Eloquent relationship between Hospital and Unit models in Laravel is not working as expected - php

I am trying to establish a one-to-many relationship between Hospital and Unit models in Laravel. A hospital can have many units, while a unit belongs to one hospital. However, the association doesn't seem to work as expected.
Here is my Hospital model:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Hospital extends Model
{
use HasFactory;
protected $primaryKey = 'id';
protected $keyType = 'string';
public $incrementing = false;
public function units()
{
return $this->hasMany(Unit::class);
}
}
And here is my Unit model:
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Unit extends Model
{
use HasFactory;
protected $primaryKey = 'id';
protected $keyType = 'string';
public $incrementing = false;
public function hospital()
{
return $this->belongsTo(Hospital::class);
}
public function benefits()
{
return $this->belongsToMany(Benefit::class, 'benefit_unit');
}
}
Here is the code that I use to associate a hospital with a unit:
$unit = Unit::create($unitData);
$unit->hospital()->associate($hospital)->save();
manual code works for me:
$hospitalUnitData = [
'hospital_id' => $hospital->id,
'unit_id' => $unit->id,
];
DB::table('hospital_unit')->insert($hospitalUnitData);
schemas:
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateHospitalsTable extends Migration
{
public function up()
{
Schema::create('hospitals', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('name');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('hospitals');
}
}
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateUnitsTable extends Migration
{
public function up()
{
Schema::create('units', function (Blueprint $table) {
$table->uuid('id')->primary();
$table->string('name');
$table->uuid('hospital_id');
$table->timestamps();
$table->foreign('hospital_id')->references('id')->on('hospitals');
});
}
public function down()
{
Schema::dropIfExists('units');
}
}
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateHospitalUnitTable extends Migration
{
public function up()
{
Schema::create('hospital_unit', function (Blueprint $table) {
$table->id();
$table->uuid('hospital_id');
$table->uuid('unit_id');
$table->timestamps();
$table->foreign('hospital_id')->references('id')->on('hospitals')->onDelete('cascade');
$table->foreign('unit_id')->references('id')->on('units')->onDelete('cascade');
});
}
public function down()
{
Schema::dropIfExists('hospital_unit');
}
}

Pivot table is only needed for many-to-many relationship.
For one-to-many relationship, all you need is a refernce ID on the model that belongs to a certain, model,
Simply think of them like this, you have hospital and unit model unit,
how do you get all units of hospital A? You simply query the Unit table with hostpal_id of hospital A (HasMany)
how do you determine what is the hospital of a unit? you get the hospital based on hostpal_id stored on that unit column (BelongsTo)
you see, you dont need an intermediate (pivot) table to connect hospital and unit.
when you call this $unit->hospital()->associate($hospital)->save(); its not updating your hospital_unit table because it updates the relationship of your Hospital and Unit relationship which is one-to-many,
which mean its just updating/adding the Hospital id to the hospital_id from the Unit table and not creating pivot entry in hospital_unit table as the relationship is not many-to-many

Related

Laravel: Best way to have multiple user relations on same model

I have a polling app.
Admins can create new polls. I have a belongsTo relation in my polls Model so I can later track which user created the poll.
Now I want to allow the poll admin to add users from the list of registered users so that only these users can access the poll.
Adding another hasMany relation to users to the poll model does not work because it already has the belongsTo. But what would the best way be? Simply add a field to my poll model and fill it with a list of user ids? Auth? But does that make sense for possibly hundreds of polls?
I feel like I am not seing an obvious solution here...
Thanks
Poll Model
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Poll extends Model
{
use HasFactory;
protected $guarded = [];
public function user()
{
return $this->belongsTo(User::class);
}
}
User model
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
use Spatie\Permission\Traits\HasRoles;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable, HasRoles;
...
/**
* poll relationship
*/
public function polls()
{
return $this->hasMany(Poll::class);
}
}
Poll migration
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('polls', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('user_id');
$table->string('name');
$table->timestamp('start_time')->nullable();
$table->timestamp('end_time')->nullable();
$table->timestamps();
$table->index('user_id');
});
}
}
User migration
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->string('password');
$table->rememberToken();
$table->timestamps();
});
}
}
You might want to create a a different, many to many relationship between polls and users. I call it participants.
table poll_user
poll_id
user_id
class Poll extends Model
{
public function participants()
{
return $this->belongsToMany(User::class, 'poll_user');
}
}

Laravel eloquent inserting data only in Pivot table

Backround information
Using Laravel I'm building an application where I want to link a Company profile to a Station.
Company.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Company extends Model
{
protected $guarded = [];
protected $table = 'companies';
public function user()
{
return $this->hasMany('App\User');
}
public function station()
{
return $this->belongsToMany('App\Station')->withPivot('company_stations');
}
public function line()
{
return $this->belongsToMany('App\Line');
}
}
Station.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Station extends Model
{
protected $guarded = [];
protected $table = 'stations';
public function lines()
{
return $this->belongsToMany('App\Line');
}
public function company()
{
return $this->belongsToMany('App\Company')->withPivot('company_stations');
}
}
company_stations migration
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateCompanyStationsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('company_stations', function (Blueprint $table) {
$table->id();
$table->integer('company_id')->unsigned();
$table->integer('station_id')->unsigned();
$table->boolean('following')->default(false);
$table->boolean('completed')->default(false);
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('company_stations');
}
}
I also have a migration company_stations, but no Model for it.
The question
I want to create a checkbox on the station view where the currently logged in Company ID is linked to the Station ID in the pivot table to keep track of which stations the company is following and wether the company has completed that station or not.
What would be the easiest and most clean approach to this? Do I make a new Model CompanyStation + controller or can this be filled in from the Company or Station controller?
You can use sync method of belongsTomany relationship.
$station = Station::find($stationid);
$station->company()->sync([1,2,3]); //1,2,3 is the company ids which you're selection through checkbox.
//this will drop all the existing companies except the companies with id 1,2,3. If these ids don't exist it will attach them (still dropping the existing ones).
if you add a column to your piviot table company_stations example: 'completed' you can access it with
foreach ($company->stations as $station) {
dd($station->pivot->completed);
}
you can add that data via
$company->stations()->attach($station->id, ['completed' => true]);
Query it
//only show me completed company stations. (from piviot)
Company::whereHas('stations', function($q) {
$q->where('company_stations.completed', true);
})
->get();

Issue with Laravel model relationships

I'm trying to retrieve all product categories with all their respective products, one product belongs to one product category and one product category can have many products.
When I retrieve productCategories I get the following error:
Illuminate \ Database \ QueryException (42S22)
SQLSTATE[42S22]: Column not found: 1054 Unknown column 'products.product_category_id' in 'where clause' (SQL: select * from `products` where `products`.`product_category_id` in (1, 2, 3))
This is my migrations file for product and categories:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class ProductsAndCategories extends Migration
{
public function up()
{
//CREATE PRODUCT CATEGORIES TABLE
Schema::create('productcategories', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->string('description')->nullable();
$table->string('image')->nullable();
$table->timestamps();
});
// CREATE PRODUCTS TABLE
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('productcategory_id')->index();
$table->foreign('productcategory_id')->references('id')->on('productcategories');
$table->string('title');
$table->string('description')->nullable();
$table->string('body')->default('');
$table->string('image')->nullable()->default(config('globals.dummy_image'));
$table->boolean('isVisible')->default(true);
$table->integer('stockLeft')->default(0);
$table->decimal('halfPrice', 5,2)->default(0.00);
$table->decimal('fullPrice', 5,2)->default(0.00);
$table->decimal('finalPrice', 5,2)->default(0.00);
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('products');
Schema::dropIfExists('productcategories');
}
}
And my two related models:
Product:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $table = 'products';
public function productcategory()
{
return $this->belongsTo('App\Models\ProductCategory', 'productcategory_id');
}
}
ProductCategory:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ProductCategory extends Model
{
protected $table = 'productcategories';
public function products()
{
return $this->HasMany('App\Models\Product');
}
}
First of all you need to define right keyword for hasMany relation. Change HasMany to hasMany();
and Model look like this:-
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class Product extends Model
{
protected $table = 'products';
protected $primary_key = 'product_id';
public function productcategory()
{
return $this->belongsTo('App\Models\ProductCategory', 'productcategory_id');
}
}
and second model look like this: -
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class ProductCategory extends Model
{
protected $table = 'productcategories';
protected $primary_key = 'id';
public function products()
{
return $this->HasMany('App\Models\Product', 'id');
}
}
and Query will be look like this: -
$product_list = Product::with('productcategory')->get();
this query will give you all records and category of particular record.

Undefined table: 7 ERROR: relation "expenses" does not exist

Since i am a spanish speaker, i wrote the controllers and models of income and expense in spanish; while all the rest were on english..
I renamed and changed manually Routes, Controllers, Migrations and even Models.
And when i run php artisan migrate:reset this is my error.
Undefined table: 7 ERROR: relation "expenses" does not exist (SQL: alter table "expenses" drop column "location_id")**
I use psgql and laravel 5.3
This is my code:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Expense extends Model
{
protected $fillable = ['id', 'description', 'quantity'];
public function locations()
{
return $this->hasMany('App\Location');
}
public function icons()
{
return $this->hasMany('App\Icon');
}
public function types()
{
return $this->hasMany('App\Type');
}
public function stores()
{
return $this->hasMany('App\Store');
}
}
Migration:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateExpensesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('expenses', function (Blueprint $table) {
$table->increments('id');
$table->float('quantity');
$table->string('description');
$table->integer('location_id')->unsigned();
$table->integer('icon_id')->unsigned();
$table->integer('type_id')->unsigned();
$table->integer('store_id')->unsigned();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('expenses');
}
}
Location Migration:
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateLocationsTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('locations', function (Blueprint $table) {
$table->increments('id');
$table->string('address');
$table->float('lat');
$table->float('long');
$table->integer('store_id')->unsigned();
$table->timestamps();
$table->foreign('store_id')->references('id')->on('stores')->onDelete('cascade');
});
Schema::table('expenses', function (Blueprint $table) {
$table->foreign('location_id')->references('id')->on('locations')->onDelete('cascade');
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::table('expenses', function (Blueprint $table) {
$table->dropColumn('location_id');
});
Schema::dropIfExists('locations');
}
}
Model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Location extends Model
{
protected $fillable = ['id', 'address', 'lat', 'long'];
public function expenses()
{
return $this->belongsTo('App\Expense');
}
public function stores()
{
return $this->hasOne('App\Store');
}
}
Hope you can help me.
When it says
relation "expenses" does not exist
It usually happens when your expenses table must have been dropped before migration:reset rolled back CreateLocationsTable.
Check the order of execution of your migrations.
As you were trying to reset, to fix it now, open your database, drop all tables manually and execute migrate again.
Schema::table('expenses', function (Blueprint $table) {
$table->foreign('location_id')->references('id')->on('locations')->onDelete('cascade');
});
change this to
Schema::alter('expenses', function (Blueprint $table) {
$table->foreign('location_id')->references('id')->on('locations')->onDelete('cascade');
});
I had this error. I had to resolve it by adding the prefix of the database to my model. There is a way to change this in the database, and it is supposed to be changed. it's something, like $user, public. It's the schema profile. Mine is changed when I login, but for some reason the model is not binding to schema. So I had to specify it in the model. Instead of
protected $table = 'table_name';
I had to do
protected $table = 'schema_name.table_name';
Note: By schema_name or table_name, I'm not referring for you to put schema_ then the name. That is just so it's easier to read.
The model is located in the model folder under the App/Models folder depending on which version of Laravel you using and how your Models are organized. If your model name is not the same as the table name, then you will need to put the protected $table. But if the schema is not there, then you will need to add that.
I do have this set in my DB_DATABASE_SECOND= in .env file. But it somehow still doesn't pick up the prefix.
But yeah. Pretty much I couldn't find the answer anywhere, but I
Solution found in:
Laravel assumes the database table is the plural form of the model name
https://laravel.com/docs/8.x/eloquent#table-names
you need to declare the singularity name of your table.
add this line
protected $table = 'expense'
at the end of your model file
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Expense extends Model
{
protected $fillable = ['id', 'description', 'quantity'];
public function locations()
{
return $this->hasMany('App\Location');
}
public function icons()
{
return $this->hasMany('App\Icon');
}
public function types()
{
return $this->hasMany('App\Type');
}
public function stores()
{
return $this->hasMany('App\Store');
}
protected $table = 'expense';
}

How to make one to many relationship in laravel

I'm trying to make a one to many relationship using eloquent model and want to show the products in the specified category
that is my product model :
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\softDeletes;
class Product extends Model
{
use softDeletes;
protected $table='products';
public function category(){
return $this->belongsTo('App\Category');
}
}
And that is my category model :
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\softDeletes;
class Category extends Model
{
use softDeletes;
protected $table='category';
public function product(){
return $this->hasMany('App\Product','category_id','id');
}
}
And that's the product controller :
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Product;
use App\Category;
class productsController extends Controller
{
public function getShow($id,Request $request){
$in=$request->get('id');
$category=Category::all();
$product=Product::find($id);
$products=$product->category()->where('category_id','=',$in);
return view ('contents.products')->with('products',$products)
->with('category',$category);
}
}
And this is the product table :
public function up()
{
Schema::create('products', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->string('category_id');
$table->string('describtion');
$table->string('image_name');
$table->timestamps();
$table->softDeletes();
});
}
And that is the category table :
public function up()
{
Schema::create('category', function (Blueprint $table) {
$table->increments('id');
$table->string('name');
$table->timestamps();
$table->softDeletes();
});
}
And it gives me this error : Call to a member function category() on a non-object
So how can i solve it ?
As far i understand your question :
In your controller:
$category = Category::find($id);
$products = $category->product;
Better yet you could use eager loading and forget about assigning products manually:
Controller:
$category = Category::with('product')->where('id', 1)->first();
Hope this help you .

Categories