草庐IT

php - Laravel 5 递归函数多对多自引用模型

coder 2023-10-26 原文

我有一个名为 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');
}

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

此外,任何产品都是其他产品的组合,因为它们就像“组件”。

所以我需要根据每个 child 的可用性以及他们构建产品所需的数量来返回“可生产”产品的数量。

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

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

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

我设法像这样递归地获取 child 直到链的末尾

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 没有 Action ,但可以基于没有 Action 但也可以由子产品构建的子产品构建成许多件。

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

            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

提前致谢。 再见

最佳答案

我不知道我是否理解了这个想法,但为了测试产品是否可生产,我建议如下:

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;
    }

}

如果产品有移动那么它已经存在了,否则检查 child ,如果isProducible检查数量,如果任何失败 child 返回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.: 不要忘记四舍五入;)

关于php - Laravel 5 递归函数多对多自引用模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37709185/

有关php - Laravel 5 递归函数多对多自引用模型的更多相关文章

  1. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  2. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  3. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  4. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

  5. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

    说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

  6. ruby-on-rails - 将字符串转换为 ruby​​-on-rails 中的函数 - 2

    我需要一个通过输入字符串进行计算的方法,像这样function="(a/b)*100"a=25b=50function.something>>50有什么方法吗? 最佳答案 您可以使用instance_eval:function="(a/b)*100"a=25.0b=50instance_evalfunction#=>50.0请注意,使用eval本质上是不安全的,尤其是当您使用外部输入时,因为它可能包含注入(inject)的恶意代码。另请注意,a设置为25.0而不是25,因为如果它是整数a/b将导致0(整数)。

  7. ruby - 在 ruby​​ 中使用 .try 函数和 .map 函数 - 2

    我需要从json记录中获取一些值并像下面这样提取curr_json_doc['title']['genre'].map{|s|s['name']}.join(',')但对于某些记录,curr_json_doc['title']['genre']可以为空。所以我想对map和join()使用try函数。我试过如下curr_json_doc['title']['genre'].try(:map,{|s|s['name']}).try(:join,(','))但是没用。 最佳答案 你没有正确传递block。block被传递给参数括号外的方法

  8. ruby - 是否可以从也在该模块中的类内部调用模块函数 - 2

    在这段Ruby代码中:ModuleMClassC当我尝试运行时出现“'M:Module'的未定义方法'helper'”错误c=M::C.new("world")c.work但直接从另一个类调用M::helper("world")工作正常。类不能调用在定义它们的同一模块中定义的模块函数吗?除了将类移出模块外,还有其他解决方法吗? 最佳答案 为了调用M::helper,你需要将它定义为defself.helper;结束为了进行比较,请查看以下修改后的代码段中的helper和helper2moduleMclassC

  9. ruby - 递归地将所有数字字符串转换为 Ruby 哈希中的整数 - 2

    我有一个随机大小的散列,它可能有类似"100"的值,我想将其转换为整数。我知道我可以使用value.to_iifvalue.to_i.to_s==value来做到这一点,但我不确定我将如何在我的散列中递归地做到这一点,考虑到一个值可以是一个字符串,或一个数组(哈希或字符串),或另一个哈希。 最佳答案 这是一个非常简单的递归实现(尽管必须同时处理数组和散列会增加一些技巧)。deffixnumifyobjifobj.respond_to?:to_i#IfwecancastittoaFixnum,doit.obj.to_ielsifobj

  10. Ruby:标准递归模式 - 2

    我经常迷上ruby​​的一件事是递归模式。例如,假设我有一个数组,它可能包含无限深度的数组作为元素。所以,例如:my_array=[1,[2,3,[4,5,[6,7]]]]我想创建一个方法,可以将数组展平为[1,2,3,4,5,6,7]。我知道.flatten可以完成这项工作,但这个问题是作为我经常遇到的递归问题的一个例子-因此我试图找到一个更可重用的解决方案。简而言之-我猜这种事情有一个标准模式,但我想不出任何特别优雅的东西。任何想法表示赞赏 最佳答案 递归是一种方法,它不依赖于语言。您在编写算法时要考虑两种情况:再次调用函数的情

随机推荐