【问题标题】:Laravel 5 recursive function many-to-many self referencing modelLaravel 5 递归函数多对多自引用模型
【发布时间】:2016-10-09 02:47:31
【问题描述】:

我有一个名为 Product 的模型,它具有以下自引用多对多关系:

// parent products based on the product_product pivot table
public function parent_products()
{
    return $this->belongsToMany('App\Product', 'product_product', 'child_id', 'parent_id')->withPivot('amount');
}

// child products based on the product_product pivot table
public function child_products()
{
    return $this->belongsToMany('App\Product', 'product_product', 'parent_id', 'child_id')->withPivot('amount');
}

// movements
public function movements()
{
    return $this->hasMany('App\Movement', 'product_id');
}

因此任何产品都可以“理想地”拥有无限的祖先和子代。

此外,任何产品都是其他产品的组合,就像“组件”一样。

因此,我需要根据每个孩子的可用性以及他们构建产品所需的数量来返还“可生产”产品的数量。

如果这是一个层次深度的东西,没有问题,但系统应该让你有许多深度层次,所以任何孩子也可以由孩子组成。

我无法控制每个产品的深度->产品->产品链。

除了性能问题,我需要一种递归方式来返回链中每个产品的“可生产”数量。

我设法像这样递归地让孩子们直到链的末端

public function child_products_recursive()
{
  return $this->child_products()->with(['child_products_recursive','movements'=>function($query){
    $query->whereDate('ready_date', '<=', date('Y-m-d'))->sum('amount');
  }]);
}

它有效。

但无法弄清楚如何从中返回值或如何导航每个模型。

涉及的表是这样“简化”的:

products
---------
id | name
---------
1  | something
2  | something
3  | something
4  | something
5  | something
6  | something
7  | something


product_product
-----------------------------
parent_id | child_id | amount (amount of children in the parent product)
-----------------------------
1         | 2        | 2
1         | 3        | 4
2         | 4        | 1.5
2         | 5        | 3
4         | 6        | 0.7
4         | 7        | 0.3


movements table
-------------------------------------
id | product_id | date       | amount
-------------------------------------
1  | 4          | 2016-01-06 | 300
2  | 5          | 2016-01-06 | 200
3  | 6          | 2016-01-06 | 125
4  | 7          | 2016-01-06 | 1000

所以产品 ID 1 没有动作,但可以基于没有动作但也可以由子产品构建的子产品构建为多个部分。

这是视觉表示(我之前没有按照表格的数据,只是为了给出想法):

            Wine box        Wine box
            6 bottles       12 bottles ---1x-- Box for
            of Wine3        of Wine4           12 Bottles
               /  \             |   \          
              /    \            |    \
            x6      x1          |     x12
            /        \          |      \
         Bottle      Box for    |     Bottle
         of Wine3    6 Bottles  |     Label
         /  |  \                |        
        /   |   \              / \    
       /    |    \            /   \
      /     |     \          /     \
    x1    x0.75    x1      x12      x9
    /       |       \      /         \
Empty       |        Bottle         Wine4
Bottle XY   |        Cork ABC
            |        
            |        
            |
            |
          Wine3
         /    \
        /      \
     x0.7      x0.3
      /          \
   Wine1        Wine2

提前致谢。 咻

【问题讨论】:

  • 是的,我想我会采用这种方法,但想知道是否有人遇到了类似的问题,并以比我的尝试更简洁、更简单的解决方案解决了

标签: php mysql laravel recursion laravel-5


【解决方案1】:

我不知道我是否明白这个想法,但为了测试产品是否isProducible,我建议如下:

public function getIsProducibleAttribute()
{
    if($this->movements > 0)
        return true;
    else{
        foreach($this->child_products_recursive as $child)
        {
            if(!$child->is_producible)
                return false;

            if($child->movements < $child->pivot->amount)
                return false;
        }

        return true;
    }

}

如果产品有 movement 所以它已经存在,否则检查孩子,如果 isProducible 检查 amount,如果任何失败孩子返回 false;

让我再试一次:

public function getProducibleQuantityAttribute()
{
    $quantity = 0;
    foreach($this->child_products_recursive as $child)
    {
        //The production expected of that child with its stock and producible take in account.
        $child_producible = ($child->movements + 
                             $child->producible_quantity)
                            / $child->pivot->amount;

        //The first value
        if($quantity == 0)
            $quantity = $child_producible;
        //Takes the lowest
        else if($child_producible < $quantity) 
            $quantity = $child_producible;
    }

    return $quantity ;
    }
}

因此,我检查了孩子的库存和可生产数量,然后除以父母需要的数量来制作一个单元。取最小值,例如:

我有 24 瓶,但只有一盒 12 瓶,所以答案是 1。

PS.:不要忘记圆,或者不;)

【讨论】:

  • 不,我需要知道这件物品可以生产多少件。
  • 好的,运动是股票吗?产品之间可以有子产品的交集吗?就像 A 是由 B 和 C 组成的,B 是由 D 组成的,C 是由 D 和 E 组成的,所以如果我用 D 来制造 B,我必须对可生产的 C 进行折扣。
  • 没错。到当前日期与产品相关的移动总和代表实际库存,但您可以避免考虑这部分并假设它已经是一个数值(我正在考虑使用附加将该查询作为值附加到产品中,所以每个孩子都会也有)。
  • 不,幸好产品不能有交集。我编辑了这个问题以图形方式表示它,所以它更清楚。让我们想想酒瓶。 0.3 升 Wine1 + 0.7 升 Wine2 = 1 升 Wine3。然后 1 升酒 3 + 1 瓶类型 23 + 1 瓶塞类型 7 + 1 标签类型 35 = 酒瓶 3。然后 6 瓶酒 3 + 1 盒 6 = 酒 3 6 盒。还有 12 瓶酒 3 + 1 盒 12 = 酒 3 12 盒和酒 21 + 1 瓶类型 23 + 1 软木类型 7 + 1 标签类型 65 = 酒瓶 21 .检查我对视觉表示的答案的编辑。
猜你喜欢
  • 1970-01-01
  • 2021-01-25
  • 2015-01-08
  • 1970-01-01
  • 2013-10-17
  • 1970-01-01
  • 2021-10-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多