在单独的 table 上进行自我引用 - Laravel 中的物料清单
Self Referencing on a separate table - BoM in Laravel
我很好奇是否有使用 eloquent 实现物料清单(组件)类型递归系统的简单方法?这是我正在使用的两个 table 结构:
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 |
+----+--------------+---------+----------+
这个程序集 table 应该表示“1 table 包含 1 个 table 顶部和 4 个 table 腿”。
库存型号:
class Inventory extends Eloquent
{
public function assemblies()
{
return $this->hasMany('InventoryAssembly', 'inventory_id', 'id');
}
/**
* Returns all of the assemblies items recursively.
*
* @param bool $recursive
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public function getAssemblyItems($recursive = true)
{
/*
* Grab all of the current item's assemblies not including itself
*/
$assemblies = $this->assemblies()->where('part_id', '!=', $this->id)->get();
$items = new Collection();
// We'll go through each assembly
foreach ($assemblies as $assembly)
{
// Get the assembly part
$part = $assembly->part;
if ($part)
{
// Dynamically set the quantity attribute on the item
$part->quantity = $assembly->quantity;
// Dynamically set the assembly ID attribute to the item
$part->assembly_id = $assembly->id;
// If recursive is true, we'll go through each assembly level
if($recursive)
{
if($part->is_assembly)
{
/*
* The part is an assembly, we'll create a new
* collection and store the part in it's own array key,
* as well as the assembly.
*/
$nestedCollection = new Collection([
'part' => $part,
'assembly' => $part->getAssemblyItems(),
]);
$items->add($nestedCollection);
} else
{
// The part isn't an assembly, we'll just add it to the list
$items->add($part);
}
} else
{
/*
* Looks like the dev only wants one level
* of items, we'll just add the part to the list
*/
$items->add($part);
}
}
}
return $items;
}
}
库存装配模型:
class InventoryAssembly extends BaseModel
{
public function item()
{
return $this->belongsTo('Inventory', 'inventory_id', 'id');
}
public function part()
{
return $this->belongsTo('Inventory', 'part_id', 'id');
}
}
现在这行得通了,但是如果我将一个项目添加到它自己的程序集中,它就会陷入无限循环。所以这是我的问题:
- 如何防止无限递归查询?
- 我这样做对吗?
- 有没有更简单的方法?
- BoM 模型是否更适合嵌套集设计?
我真的很难理解自引用重复查询。我非常感谢任何的帮助,在此先感谢!!
编辑: 在 user3158900 建议的库存模型上使用属于许多关系,我能够像这样执行递归装配查询:
库存模型(根据以下答案修改):
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');
}
}
检索单层程序集:
$item = Inventory::with('assemblies')->find(1);
$items = $item->assemblies;
正在检索完整的递归程序集结果:
$item = Inventory::with('assembliesRecursive')->find(1);
$items = $item->assembliesRecursive;
$nestedItems = $items->get(0)->assemblies;
$nestedNestedItems = $items->get(0)->assemblies->get(0)->assemblies;
这变得容易多了。这可能看起来不像,但它实际上属于许多,其中库存属于许多本身,inventory_assembly
是一个枢轴 table,实际上甚至不需要模型来配合它。
这里是库存模型
class Inventory extends Eloquent {
public function assemblies()
{
return $this->belongsToMany('Inventory', 'inventory_assemblies', 'inventory_id', 'part_id')
->withPivot(['quantity']);
}
}
下面是我如何获得特定库存项目的组件集。
$item = Inventory::with('assemblies')->find(1);
$assemblies = $item->assemblies;
编辑:刚刚意识到您正在使用 Laravel 4。删除命名空间。
另一个编辑: 我认为这还不算解决。例如,如果腿是需要腿和硬件的组件,硬件是需要不同 nuts/bolts/ 套工具的组件,如果工具组是需要扳手 a 和螺丝刀 b 等的组件......这种方法只会让你和腿一样深,而忽略其他一切。
在这种情况下,我们所做的一切都是错误的,而忽略了我所说的一切。这就是所谓的嵌套集模型。您可以在此处阅读更多相关信息 http://en.wikipedia.org/wiki/Nested_set_model
在这种情况下,还有一个 Laravel 包可以为您处理这种关系。它使我几次免于用头撞墙。 https://github.com/etrepat/baum#node-relations.
对于 Eloquent 中的嵌套关系,这也是可能的,您将不再需要 assemblyRecursive
函数。您可以根据需要进行深入研究。
$item = Inventory::with('assemblies.assemblies.assemblies')->find(1);
foreach($item->assemblies as $assembly) {
if($assembly->is_assembly) {
// Do things for parent items
foreach($assembly->assemblies as $nested_assembly_a) {
// Do things for 1 deep nests
if($nested_assembly_a->is_assembly) {
foreach($nested_assembly_a->assemblies as $nested_assembly_b) {
// Do things for 2 deep nests
}
} else {
// Non-assembly 1 deep child
}
}
} else {
// Non-Assembly parent
}
}
我很好奇是否有使用 eloquent 实现物料清单(组件)类型递归系统的简单方法?这是我正在使用的两个 table 结构:
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 |
+----+--------------+---------+----------+
这个程序集 table 应该表示“1 table 包含 1 个 table 顶部和 4 个 table 腿”。
库存型号:
class Inventory extends Eloquent
{
public function assemblies()
{
return $this->hasMany('InventoryAssembly', 'inventory_id', 'id');
}
/**
* Returns all of the assemblies items recursively.
*
* @param bool $recursive
*
* @return \Illuminate\Database\Eloquent\Collection
*/
public function getAssemblyItems($recursive = true)
{
/*
* Grab all of the current item's assemblies not including itself
*/
$assemblies = $this->assemblies()->where('part_id', '!=', $this->id)->get();
$items = new Collection();
// We'll go through each assembly
foreach ($assemblies as $assembly)
{
// Get the assembly part
$part = $assembly->part;
if ($part)
{
// Dynamically set the quantity attribute on the item
$part->quantity = $assembly->quantity;
// Dynamically set the assembly ID attribute to the item
$part->assembly_id = $assembly->id;
// If recursive is true, we'll go through each assembly level
if($recursive)
{
if($part->is_assembly)
{
/*
* The part is an assembly, we'll create a new
* collection and store the part in it's own array key,
* as well as the assembly.
*/
$nestedCollection = new Collection([
'part' => $part,
'assembly' => $part->getAssemblyItems(),
]);
$items->add($nestedCollection);
} else
{
// The part isn't an assembly, we'll just add it to the list
$items->add($part);
}
} else
{
/*
* Looks like the dev only wants one level
* of items, we'll just add the part to the list
*/
$items->add($part);
}
}
}
return $items;
}
}
库存装配模型:
class InventoryAssembly extends BaseModel
{
public function item()
{
return $this->belongsTo('Inventory', 'inventory_id', 'id');
}
public function part()
{
return $this->belongsTo('Inventory', 'part_id', 'id');
}
}
现在这行得通了,但是如果我将一个项目添加到它自己的程序集中,它就会陷入无限循环。所以这是我的问题:
- 如何防止无限递归查询?
- 我这样做对吗?
- 有没有更简单的方法?
- BoM 模型是否更适合嵌套集设计?
我真的很难理解自引用重复查询。我非常感谢任何的帮助,在此先感谢!!
编辑: 在 user3158900 建议的库存模型上使用属于许多关系,我能够像这样执行递归装配查询:
库存模型(根据以下答案修改):
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');
}
}
检索单层程序集:
$item = Inventory::with('assemblies')->find(1);
$items = $item->assemblies;
正在检索完整的递归程序集结果:
$item = Inventory::with('assembliesRecursive')->find(1);
$items = $item->assembliesRecursive;
$nestedItems = $items->get(0)->assemblies;
$nestedNestedItems = $items->get(0)->assemblies->get(0)->assemblies;
这变得容易多了。这可能看起来不像,但它实际上属于许多,其中库存属于许多本身,inventory_assembly
是一个枢轴 table,实际上甚至不需要模型来配合它。
这里是库存模型
class Inventory extends Eloquent {
public function assemblies()
{
return $this->belongsToMany('Inventory', 'inventory_assemblies', 'inventory_id', 'part_id')
->withPivot(['quantity']);
}
}
下面是我如何获得特定库存项目的组件集。
$item = Inventory::with('assemblies')->find(1);
$assemblies = $item->assemblies;
编辑:刚刚意识到您正在使用 Laravel 4。删除命名空间。
另一个编辑: 我认为这还不算解决。例如,如果腿是需要腿和硬件的组件,硬件是需要不同 nuts/bolts/ 套工具的组件,如果工具组是需要扳手 a 和螺丝刀 b 等的组件......这种方法只会让你和腿一样深,而忽略其他一切。
在这种情况下,我们所做的一切都是错误的,而忽略了我所说的一切。这就是所谓的嵌套集模型。您可以在此处阅读更多相关信息 http://en.wikipedia.org/wiki/Nested_set_model
在这种情况下,还有一个 Laravel 包可以为您处理这种关系。它使我几次免于用头撞墙。 https://github.com/etrepat/baum#node-relations.
对于 Eloquent 中的嵌套关系,这也是可能的,您将不再需要 assemblyRecursive
函数。您可以根据需要进行深入研究。
$item = Inventory::with('assemblies.assemblies.assemblies')->find(1);
foreach($item->assemblies as $assembly) {
if($assembly->is_assembly) {
// Do things for parent items
foreach($assembly->assemblies as $nested_assembly_a) {
// Do things for 1 deep nests
if($nested_assembly_a->is_assembly) {
foreach($nested_assembly_a->assemblies as $nested_assembly_b) {
// Do things for 2 deep nests
}
} else {
// Non-assembly 1 deep child
}
}
} else {
// Non-Assembly parent
}
}