Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel Custom Pivot Table relationship and eager loading?

I am having problems with creating a schema / model for one of my projects and would like to get some help here.

I have 3 tables currently : accessories , products and a pivot table product_accessory

<?php 

Schema::create('accessories', function(Blueprint $table)
{
    $table->increments('id');
}

Schema::create('products', function(Blueprint $table) 
{
    $table->increments('id');
}

Schema::create('product_accessory', function(Blueprint $table)
{
    $table->increments('id');
    $table->integer('product_id')->unsigned();
    $table->integer('accessory_id')->unsigned();
    $table->foreign('product_id')->references('id')->on('products');
    $table->foreign('accessory_id')->references('id')->on('accessories');
}

Now problem is I need to add another product type 'adaptors' that would ultimately depend on the pivot table relation, that is, adaptors need to relate to both a product and accessory...

UPDATE Here is how my current product_accessory_adaptor table is

Schema::create('product_accessory_adaptor', function(Blueprint $table)
{
    $table->increments('id');
    $table->integer('product_accessory_id')->unsigned();
    $table->foreign('product_accessory_id')->references('id')->on('product_accessory');
}

This way, i can have many adaptors relating to a product and accessory. My question is how do i model this relation in eloquent?

Here's what i have now:

Custom pivot model :

class ProductAccessory extends Pivot {
   protected $table = 'product_accessory';

   public function product()
   {
      return $this->belongsTo('Product');
   }

   public function accessory()
   {
     return $this->belongsTo('Accessory');
   }

   public function adaptors() {
     return $this->hasMany('Adaptor', 'product_accessory_id'); 
   } 
}

Product and Accessory model

class Accessory extends Eloquent {

   public function products()
   {
      return $this->belongsToMany('Product', 'product_accessory', 'accessory_id', 'product_id')->withPivot();
   }

   public function newPivot(Eloquent $parent, array $attributes, $table, $exists) 
   {
      if ($parent instanceof Product) {
          return new ProductAccessory($parent, $attributes, $table, $exists);
      }
      return parent::newPivot($parent, $attributes, $table, $exists);
   }

   public function adaptors()
   {
      return $this->hasManyThrough('Adaptor', 'ProductAccessory', 'accessory_id', 'product_accessory_id');
   }
}

class Product extends Eloquent {

   public function accessories()
   {
      return $this->belongsToMany('Accessory', 'product_accessory', 'product_id', 'accessory_id')->withPivot();
   }

   public function newPivot(Eloquent $parent, array $attributes, $table, $exists) 
   {
      if ($parent instanceof Accessory) {
          return new ProductAccessory($parent, $attributes, $table, $exists);
      }
      return parent::newPivot($parent, $attributes, $table, $exists);
   }

   public function adaptors()
   {
      return $this->hasManyThrough('Adaptor', 'ProductAccessory', 'product_id', 'product_accessory_id');
   }
}

Adaptor model:

class Adaptor extends Eloquent {

   protected $table = 'product_accessory_adaptor';

   public function productAccessory() {
      return $this->belongsTo('ProductAccessory');
   }
}

Update Now the schema and model is setup. However there are issues with using hasManyThrough relations. In addition, any way to do eager loading in this case for the pivot relation , i.e Adaptor?

Note The error that occurs when i make a call to adaptors() on either the Product or Accessory model is Argument 1 passed to Illuminate\Database\Eloquent\Relations\Pivot::__construct() must be an instance of Illuminate\Database\Eloquent\Model, none given, called in /vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php on line 872 and defined

like image 958
yulun Avatar asked Jul 21 '14 03:07

yulun


1 Answers

That's your pivot:

<?php

use Illuminate\Database\Eloquent\Model as Eloquent;

// you don't need to call it ..Pivot, just my suggestion
class ProductAccessory extends Eloquent {

  protected $table = 'product_accessory';

  public function product()
  {
    return $this->belongsTo('Product');
  }

  public function accessory()
  {
    return $this->belongsTo('Accessory');
  }

  public function adaptors()
  {
    return $this->hasMany('Adaptor', 'product_accessory_id');
  }
}

// Product model
public function adaptors()
{
    return $this->hasManyThrough(
      'Adaptor', 'ProductAccessoryPivot', 'product_id', 'product_accessory_id'
    );
}

// Accessory model
public function adaptors()
{
    return $this->hasManyThrough(
      'Adaptor', 'ProductAccessoryPivot', 'accessory_id', 'product_accessory_id'
    );
}

Now example usage:

$product = Product::first();

$product->adaptors; // collection of all adaptors for given product

$product->adaptors->first()->accessory; // accessory for single adaptor

$product->accessories; // collection of accessories, each with your custom pivot, so:

$product->accessories->first()->adaptors; // collection of adaptors for given product-accessory pair

... and more, try it
like image 153
Jarek Tkaczyk Avatar answered Oct 18 '22 00:10

Jarek Tkaczyk