Detail explanation of the Eloquent relationships with Laravel 8 & 9
There are different types of relationships in Laravel. We have given a detailed explanation of the eloquent relationship with Laravel
- One to one
- One to many
- Many to many
- Has one through
- Has many through
- One-to-one (Polymorphic)
- One to many (Polymorphic)
- Many to many (polymorphic)
One To One Eloquent Relationship
An owner may have one house and that house belongs to the owner
So, we have to create two model
PHP artisan make: model owner -mc
PHP artisan make: model house -mc
Let’s add some columns in the migration
public function up() { Schema::create('owners', function (Blueprint $table) { $table->id(); $table->string('owner_name'); $table->timestamps(); }); }public function up()
{
Schema::create('houses', function (Blueprint $table) {
$table->id();
$table->foreignId('owner_id')->references('id')->on('owners');
$table->string('house_name');
$table->timestamps();
});
}
Now,we have to add hasone and belongs to method with Owner and House Class as house is belongs to owner
Owner Class
class owner extends Model { use HasFactory; public $keyType='string'; public function house() { return $this->hasOne(house::class); }
}
House Class
class house extends Model
{ use HasFactory; public function owner() {
return $this->belongsTo(house::class); } }
we can get child information from parents.
public function index()
{ $owner=owner::find(1)->house;
dd($owner);
}
and from child, we can get parent information
public function index()
{ $owner=house::find(1)->owner; dd($owner);
}
One to Many eloquent relationship
One table may have many children at another table.
One post may have many comments.
This is One to many relationship
One GD may have many Fab_Particular
Gd_Create
class Gd_Create extends Model
{
use HasFactory;
public function fab_particulars(){
return $this->hasMany(Fab_Particular::class);
}
}
Belongs to or one-to-many (inverse) eloquent relationship
Fab_Particular
class Fab_Particular extends Model
{ use HasFactory;
public function gd_creates()
{
return $this->belongsTo(Gd_Create::class);
}
}
Now if we want to get fab_particular from GD
public function gd_width(Request $request){
if (Auth::check()) {
$id=$request->gd_create_id;
$gd_widths=Gd_Create::find($id)->fab_particulars;
return response()->json($gd_widths);
}
}
Has One of Many eloquent relationship
One GD may have many Fab_Particular . But if we want to connect with only the latest or oldest we can do it.
public function gd_creates()
{
return $this->belongsTo(Gd_Create::class)->latestofMany();
}
public function gd_creates()
{
return $this->belongsTo(Gd_Create::class)->oldestofMany();
}
Has One Through eloquent relationship
When two tables or models don’t have any relation directly but are connected to each other by a common related table or model, using the third model they can communicate.
A user may have some comments which are connected to a post.
Let’s create 3 tables named User (which is automatically created by Laravel), Post, and Comments.
php artisan make:model Post -m
php artisan make:model Comments -m
Let’s create a method named userComments in the user model
public function userComments()
{
return $this-$this->hasOneThrough(Comment::class,Post::class);
}
The first argument is the final model we want to access and the second argument is the medium to access the final model.And from our controller, we can get the comments of the user
public function hasone()
{
$user=User::find(1)->userComments;
dd($user);
}
We can also use foreign key and primary key relationship
public function userComments()
{
return $this->hasOneThrough
);
}
Has many through eloquent relationship
When two tables are connected to each other by a one-to-many relationship with the third model is called “has one through”.
public function userComments()
{
return $this->hasManyThrough(Comment::class,Post::class,'user_id','comment_id','id','id');
}
Many To Many eloquent relationships
In many-to-many relationships, two tables are connected to each other by many-to-many relationship by a third table. A customer can buy from a different shop. Those shops can have many customers
So, we need three tables here.
- Customer
- Shop
- Link
php artisan make:model Shop -mc
php artisan make:model Customer -mc
php artisan make:model Link -mc
Change the migrations
Shop Table
class CreateShopsTable extends Migration
{
public function up()
{
Schema::create('shops', function (Blueprint $table) {
$table->id();
$table->string('shop_name');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('shops');
}
}
Customer Table
class CreateCustomersTable extends Migration
{
public function up()
{
Schema::create('customers', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('customers');
}
}
Link Table
class CreateLinksTable extends Migration
{
public function up()
{
Schema::create('links', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('customer_id');
$table->unsignedBigInteger('shop_id');
$table->foreign('customer_id')->references('id')->on('customers');
$table->foreign('shop_id')->references('id')->on('shops');
$table->timestamps();
});
}
public function down()
{
Schema::dropIfExists('links');
}
}
In the link table, we are creating two foreign key; one is coming from the customer and one from the shop.
Run: php artisan migrate
Then in the model, we have to add relationships
Customer Model
class Customer extends Model
{
use HasFactory;
public function shops()
{
return $this->belongsToMany(Shop::class);
}
}
Shop Model
class Shop extends Model
{
use HasFactory;
public function customers()
{
return $this->belongsToMany(Customer::class);
}
}
Now in our controller when we can access one table’s data from another table
public function hasone()
{
$shop = Shop::find(1);
foreach ($shop->customers as $sho) {
echo $sho->pivot->created_at;
}
}
But this will show an error for the default pivot table as Laravel will look for the ‘customer_shop’ table, which is not available as we define this table as links.
So, we have to change the “links” to ‘‘customer_shop’.
Customizing Pivot table
If we want to use a different table for the pivot, we have to specify it with relationsip.
class Shop extends Model
{
use HasFactory;
public function customers()
{
return $this->belongsToMany(Customer::class)
->using(Link::class)
->withTimestamps();
}
}
class Customer extends Model
{
use HasFactory;
public function shops()
{
return $this->belongsToMany(Shop::class)
->using(Link::class)
->withTimestamps()
;
}
}
Now from the controller, we can get the result below.
public function hasone()
{
$shop = Shop::find(1);
foreach ($shop->customers as $sho) {
dd($sho->pivot->shop_id);
}
}
But it will show an error. Because Link is not a pivot class.
So, we have to extend the pivot class.
use Illuminate\Database\Eloquent\Relations\Pivot;
class Link extends pivot
{
use HasFactory;
}
If the custom pivot model has a primary key with auto-incrementing we have to specify it.
public $incrementing=true;
Note: Pivot models may not use the SoftDeletes
trait. If soft delete is needed, we have to use the Eloquent model like below
Without Pivot
If we want to use the Links table as an intermediate table for many-to-many, we can do it like this also
class Shop extends Model
{
use HasFactory;
public function customers()
{
return $this->belongsToMany(Customer::class)
->as('links')
->withTimestamps();
}
}
class Customer extends Model
{
use HasFactory;
public function shops()
{
return $this->belongsToMany(Shop::class)
->as('links')
->withTimestamps()
;
}
}
Then we can get the result from the controller. We cannot use the pivot function here.
public function hasone()
{ $shop = Shop::find(1);
foreach ($shop->customers as $sho) {
dd($sho->name);
}
}
How to generate SQL of the migration table?
Php artisan migrate --pretend.
create table `test_models` (`pr_number` varchar(255) not null, `created_at` timestamp null, `updated_at` timestamp null, `created_at` timestamp null, `
updated_at` timestamp null) default character set utf8mb4 collate 'utf8mb4_unicode_ci'
Alter table `test_models` add constraint `test_models_pr_number_foreign` foreign key (`pr_number`) references `p_r_creations` (`pr_number`)
How to get data of custom primary key and foreign key with an Eloquent relationship?
Create a Route in Web.php
Route::get('barcode/{po_number}', [PdfController::class, 'barcode']);
Create two models and migration. We have shown above how to create a model and migration.
- PR Creation
- Test Model
Migration
PR Creation
Schema::create('p_r_creations', function (Blueprint $table) {
$table->string('pr_number')->primary();
$table->integer('id')->unique();
$table->date('date');
$table->string('name_of_raw_matrial');
$table->string('quantity');
$table->string('quality');
$table->string('remarks');
$table->timestamps();
});
Test Model
Schema::create('test_models', function (Blueprint $table) {
$table->string('po_number')->primary();
$table->string('pr_number');
$table->foreign('pr_number')->references('pr_number')->on('p_r_creations');
$table->timestamps();
});
Model
PR Creation
class PRCreation extends Model
{
use HasFactory;
protected $table='p_r_creations';
protected $primaryKey='pr_number';
public $incrementing = false;
protected $keyType = 'string';
public function test_models(){
return $this->hasMany(TestModel::class);
}
}
PO Creation
class TestModel extends Model
{
use HasFactory;
protected $primaryKey='po_number';
public $incrementing = false;
protected $keyType = 'string';
public function pr_creatons(){
return $this->belongsTo(PRCreation::class,'pr_number');
}
}
In pr_creations() method ‘pr_number’ is forign key.
Now in controller, if we want to get data from test model using an eloquent relationship with PR Creation it won’t work. 😉
Because Laravel adds the name of the table with foreign key by default, so we have to change the foreign key name with a table in migration.
Schema::create('test_models', function (Blueprint $table) {
$table->string('po_number')->primary();
$table->string('p_r_creation_pr_number');
$table->foreign('pr_number')->references(‘p_r_creation_pr_number')->on('p_r_creations');
$table->timestamps();
});
Now we can get data from the controller using eloquent relationship.
$pr= PRCreation::find(pr_4')->test_models;
dd($pr);