Self Referencing on a separate table - BoM in Laravel -


i'm curious if there's easy way of implementing bill of materials (assemblies) type recursive system using eloquent? here 2 table structures i'm working with:

inventory table:

+----+------------+-------------+ | id | name | is_assembly | +----+------------+-------------+ | 1 | table | 1 | +----+------------+-------------+ | 2 | table top | 0 | +----+------------+-------------+ | 3 | table legs | 0 | +----+------------+-------------+

inventory_assemblies table:

+----+--------------+---------+----------+ | id | inventory_id | part_id | quantity | +----+--------------+---------+----------+ | 1 | 1 | 1 | 1 | +----+--------------+---------+----------+ | 2 | 1 | 2 | 1 | +----+--------------+---------+----------+ | 3 | 1 | 3 | 4 | +----+--------------+---------+----------+

this assembly table should mean '1 table contains 1 table top , 4 table legs'.

inventory model:

class inventory extends eloquent {     public function assemblies()     {         return $this->hasmany('inventoryassembly', 'inventory_id', 'id');     }      /**      * returns of assemblies items recursively.      *      * @param bool $recursive      *      * @return \illuminate\database\eloquent\collection      */     public function getassemblyitems($recursive = true)     {         /*          * grab of current item's assemblies not including          */         $assemblies = $this->assemblies()->where('part_id', '!=', $this->id)->get();          $items = new collection();          // we'll go through each assembly         foreach ($assemblies $assembly)         {             // assembly part             $part = $assembly->part;              if ($part)             {                 // dynamically set quantity attribute on item                 $part->quantity = $assembly->quantity;                  // dynamically set assembly id attribute item                 $part->assembly_id = $assembly->id;                  // if recursive true, we'll go through each assembly level                 if($recursive)                 {                     if($part->is_assembly)                     {                         /*                          * part assembly, we'll create new                          * collection , store part in it's own array key,                          * assembly.                          */                         $nestedcollection = new collection([                             'part' => $part,                             'assembly' => $part->getassemblyitems(),                         ]);                          $items->add($nestedcollection);                      } else                     {                         // part isn't assembly, we'll add list                         $items->add($part);                     }                 } else                 {                     /*                      * looks dev wants 1 level                      * of items, we'll add part list                      */                     $items->add($part);                 }             }         }          return $items;     } } 

inventoryassembly model:

class inventoryassembly extends basemodel {     public function item()     {         return $this->belongsto('inventory', 'inventory_id', 'id');     }      public function part()     {         return $this->belongsto('inventory', 'part_id', 'id');     } } 

now works, if add item assembly of itself, infinite loop. here questions:

  • how can prevent infinite recursive queries?
  • am doing right?
  • is there easier way?
  • would bom model better suited towards nested set design?

i'm having trouble understanding self-referencing recurring queries. really appreciate any help, in advance!!

edit: using belongs many relationship on inventory model suggested user3158900, i'm able perform recursive assembly query so:

the inventory model (modified below answer):

class inventory extends eloquent {      public function assemblies()     {         return $this->belongstomany('inventory', 'inventory_assemblies', 'inventory_id', 'part_id')             ->withpivot(['quantity']);     }      public function assembliesrecursive()     {         return $this->assemblies()->with('assembliesrecursive');     }  } 

retrieving single level of assemblies:

$item = inventory::with('assemblies')->find(1);  $items = $item->assemblies; 

retrieving complete recursive assemblies results:

$item = inventory::with('assembliesrecursive')->find(1);  $items = $item->assembliesrecursive;  $nesteditems = $items->get(0)->assemblies;  $nestednesteditems = $items->get(0)->assemblies->get(0)->assemblies; 

this gets lot easier. may not it, it's belongs-to-many inventory belongs many , inventory_assembly pivot table , doesn't require model go along it.

here inventory model

class inventory extends eloquent {      public function assemblies()     {         return $this->belongstomany('inventory', 'inventory_assemblies', 'inventory_id', 'part_id')             ->withpivot(['quantity']);     }  } 

and here how got collection of assemblies inventory item.

$item = inventory::with('assemblies')->find(1);  $assemblies = $item->assemblies; 

edit: realized using laravel 4. removed namespaces.

another edit: wouldn't count solved yet. if example legs assembly requires leg , hardware, hardware assembly requires different nuts/bolts/ sets of tools, if sets of tools assembly requires wrench , screwdriver b, etc... method deep leg , ignore else.

in case, going wrong , ignore i've said. what's known nested set model. can read more here http://en.wikipedia.org/wiki/nested_set_model

in case, there laravel package should handle relationship you. it's saved me few times smacking head against wall. https://github.com/etrepat/baum#node-relations.

for nested relationships in eloquent, possible , no longer need assemblyrecursive function. can go deep need to.

$item = inventory::with('assemblies.assemblies.assemblies')->find(1);  foreach($item->assemblies $assembly) {     if($assembly->is_assembly) {         // things parent items         foreach($assembly->assemblies $nested_assembly_a) {             // things 1 deep nests              if($nested_assembly_a->is_assembly) {                 foreach($nested_assembly_a->assemblies $nested_assembly_b) {                     // things 2 deep nests                  }             } else {                 // non-assembly 1 deep child             }         }     } else {         // non-assembly parent     } } 

Comments

Popular posts from this blog

c++ - Difference between pre and post decrement in recursive function argument -

php - Nothing but 'run(); ' when browsing to my local project, how do I fix this? -

php - How can I echo out this array? -