skip to Main Content

I have a model Product, and the same product can be sold by multiple supermarkets and outlets, so I define two BelongsToMany relationships for them:

class Product extends Model
{
    public function supermarkets(): BelongsToMany
    {
        return $this->belongsToMany(
            Supermarket::class,
            'product_supermarket',
            'product_id',
            'supermarket_id'
        );
    }

    public function outlets(): BelongsToMany
    {
        return $this->belongsToMany(
            Outlet::class,
            'outlet_product',
            'product_id',
            'outlet_id'
        );
    }
}

Then in the Supermarket model I define a BelongsToMany relastionship to Products model, since one supermarket can sell many different products.

class Supermarket extends Model
{
    public function products(): BelongsToMany
    {
        return $this->belongsToMany(
            Product::class,
            'product_supermarket',
            'supermarket_id',
            'product_id'
        );
    }
}

If I want to access the intermediate table product_supermarket, I can:

foreach ($supermarket->products as $product) {
    echo $product->pivot->created_at;
}

However, we see that Product model has two BelongsToMany defined in its class. So what will property pivot be like in such a case? How can I access the intermediate table product_supermarket or outlet_product specifically?

I read the official documentation of Laravel but found nothing about it metioned in it: https://laravel.com/docs/11.x/eloquent-relationships

2

Answers


  1. Chosen as BEST ANSWER

    I've figured it out. So if you want to return a specific intermediate table by 'pivot', you need to get the related model instances from the model that this intermediate table is bounded to. For example:

    $outlet = AppModelsOutlet::find(1);
    foreach($outlet->products as $product) 
    { 
       echo $product->pivot; // access the outlet_product table
    }
    
    $supermarket = AppModelsSupermarket::find(1);
    foreach($supermarket->products as $product) 
    { 
       echo $product->pivot; // access the product_supermarket table
    }
    
    

  2. You can use https://laravel.com/docs/11.x/eloquent-relationships#customizing-the-pivot-attribute-name to alias the pivot attribute name for each relationship you have.

    class Supermarket extends Model
    {
        public function products(): BelongsToMany
        {
            return $this->belongsToMany(
                Product::class,
                'product_supermarket',
                'supermarket_id',
                'product_id'
            )->as('supermarkets_pivot');
        }
    }
    

    and the reverse if you need it.

    class Product extends Model
    {
        public function supermarkets(): BelongsToMany
        {
            return $this->belongsToMany(
                Supermarket::class,
                'product_supermarket',
                'product_id',
                'supermarket_id'
            )->as('supermarkets_pivot');
        }
    
        public function outlets(): BelongsToMany
        {
            return $this->belongsToMany(
                Outlet::class,
                'outlet_product',
                'product_id',
                'outlet_id'
            )->as('outlets_pivot');
        }
    }
    

    Then you can access each one by it’s pivot alias outlets_pivot or supermarkets_pivot I also recommend to eager load those relationships since you are already looping through all of them to avoid n+1 query if you are querying multiple supermarkets.

    Also note that

    foreach ($supermarket->products as $product) {
        echo $product->pivot->created_at;
    }
    

    the pivot here will always be the pivot related to the product and supermarket.

    foreach ($outlet->products as $product) {
        echo $product->pivot->created_at;
    }
    

    and here it will always be for the outlets and products.
    So you might not need the alias in most cases.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search