5

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

yulun
  • 260
  • 1
  • 6
  • 21
  • 1
    You need this: **1** custom pivot model `ProductAccessory`, **2** 2 `belongsTo` relations on this model (with `Product` and `Accessory`) + `hasMany` relation with `Adaptor`, **3** Adaptor model with `belongsTo` relation to that pivot model, **4** `hasManyThrough` relations with `Adaptor` on both `Product` and `Accessory`. It may seem pretty complex, but give it a try. – Jarek Tkaczyk Jul 21 '14 at 07:40
  • hey @deczo thanks for the reply. i am trying to figure out how to do write the custom pivot model but can't seem to quite find examples on it. the documentation here http://laravel.com/docs/eloquent#working-with-pivot-tables doesn't really provide an example on how to do it. would you mind giving me some directions? – yulun Jul 22 '14 at 04:39

1 Answers1

10

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
Jarek Tkaczyk
  • 78,987
  • 25
  • 159
  • 157
  • hey @deczo i can now access the adaptors data via `$product->accessories()->first()->pivot->adaptors()` but not through `Product::first()->adaptors or $product->accessories->first()->adaptors.` whenever i do that, this error occurs : `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` also, on a side note, is there anyway i can eager load the adaptors data? – yulun Jul 23 '14 at 04:13
  • Right, I forgot about it. In fact you don't need to extend `Pivot` but ordinary `Model`/`Eloquent`, and no need to use custom `newPivot`. Check the edit and it wil work. – Jarek Tkaczyk Jul 23 '14 at 06:38
  • great that finally worked! thanks alot. and i was able to use eager loading for the adaptor, essentially halving the speed of the queries. – yulun Jul 23 '14 at 07:38
  • sorry after changing to this method, my save for adaptor doesn't work now... how should i add an adaptor to the pivot table? – yulun Jul 23 '14 at 09:07
  • paste the code you execute and error to bin.laravel.io – Jarek Tkaczyk Jul 23 '14 at 09:09
  • 1
    OK, you still need custom pivot in order to use it the way you want: http://laravel.io/bin/eybn6 – Jarek Tkaczyk Jul 23 '14 at 10:00
  • thanks for the suggesstion. got to say its quite brilliant. however, say if i don't need to save it this way (through the pivot), wat would be the correct way to save adaptors? retrieve product_accessory_id and use Adaptor::create? p.s thanks for the patience so far – yulun Jul 23 '14 at 10:54
  • Yes, you could simply do it manually `$adaptor = new Adaptor([your data here, 'product_accessory_id => $product_accessory->pivot->id]);` but then you need `withPivot(['id']);` on the `Product`-`Accessory` relations – Jarek Tkaczyk Jul 23 '14 at 11:35
  • hey deczo, sorry my requirements kind of change and i have no idea if should create a new question or ask u here on this. is there any way i can eager load the pivot relations with constraints? Something like this http://laravel.io/bin/Qk8BV. its possible to eager load with this but i can't figure out how to pass in the pivot id – yulun Jul 28 '14 at 10:45
  • Please ask a new question with appropriate code and description, what you'd like to query – Jarek Tkaczyk Jul 28 '14 at 11:01
  • sorry @deczo, here's the new question :http://stackoverflow.com/questions/24995629/eager-loading-nested-relationships-using-pivot – yulun Jul 28 '14 at 12:49
  • I really need to see `laravel.io/bin/eybn6`. Unfortunately it just takes me to `laravel.io/bin` when I click the link. :( I am pretty sure it is a problem on their side because I can't load any pastebin stuff on their site. – Dustin Griffith Nov 03 '14 at 17:08
  • Yes, it seems laravel.io broke something. Ask your question and I'll try to help you. – Jarek Tkaczyk Nov 03 '14 at 17:17
  • @JarekTkaczyk I actually think I am starting to understand it a little more. I was mixing code from too many difference examples. Once I get a better grasp on how this is supposed to work I will make a tutorial and link to it in another comment. – Dustin Griffith Nov 03 '14 at 19:00