Eloquent relationships

There are different types of relationships in Laravel. We have given a detailed explanation of the eloquent relationship with Laravel

  1. One to one
  2. One to many
  3. Many to many
  4. Has one through
  5. Has many through
  6. One-to-one (Polymorphic)
  7. One to many (Polymorphic)
  8. 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;
}

Incrementing IDs

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);

By Navid Anjum

Full-stack web developer and founder of Laravelaura. He makes his tutorials as simple as humanly possible and focuses on getting the students to the point where they can build projects independently. https://github.com/NavidAnjum

Leave a Reply

Your email address will not be published. Required fields are marked *