Laravel复杂查询



我正在重新编写一个已经编码的"制作"系统,该系统基于一组数据库"配方",其中最多有五个项目和数量(例如:item1item1qty)。以前,以正确的顺序排列配方中的物品是很重要的,这使得验证很容易,因为它只需要查看用户输入的item1item1qty等并将它们直接匹配。

我们现在想让它接受任何顺序的食材。我知道这可以通过查询功能完成,但我担心我的解决方案是错误的,因为我提出的解决方案将其标记为有效的配方,如果用户拥有配方的一部分(假设配方包含3种成分,如果他们只输入其中一种成分,即使没有其他2种适当的成分和数量,它也会有效)。我的解决方案也很长,有没有办法把它简化一点?

$recipe = DataRecipe::where(function ($query) use($request) {
        $query->where(function ($q) use($request) {
            $q->where(function($q2) use ($request) {
                $q2->where('item1', $request->item1)->where('item1qty', $request->item1qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item2', $request->item1)->where('item2qty', $request->item1qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item3', $request->item1)->where('item3qty', $request->item1qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item4', $request->item1)->where('item4qty', $request->item1qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item5', $request->item1)->where('item5qty', $request->item1qty);
            });
        })->where(function ($q) use($request) {
            $q->where(function($q2) use ($request) {
                $q2->where('item1', $request->item2)->where('item1qty', $request->item2qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item2', $request->item2)->where('item2qty', $request->item2qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item3', $request->item2)->where('item3qty', $request->item2qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item4', $request->item2)->where('item4qty', $request->item2qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item5', $request->item2)->where('item5qty', $request->item2qty);
            });
        })->where(function ($q) use($request) {
            $q->where(function($q2) use ($request) {
                $q2->where('item1', $request->item3)->where('item1qty', $request->item3qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item2', $request->item3)->where('item2qty', $request->item3qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item3', $request->item3)->where('item3qty', $request->item3qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item4', $request->item3)->where('item4qty', $request->item3qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item5', $request->item3)->where('item5qty', $request->item3qty);
            });
        })->where(function ($q) use($request) {
            $q->where(function($q2) use ($request) {
                $q2->where('item1', $request->item4)->where('item1qty', $request->item4qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item2', $request->item4)->where('item2qty', $request->item4qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item3', $request->item4)->where('item3qty', $request->item4qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item4', $request->item4)->where('item4qty', $request->item4qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item5', $request->item4)->where('item5qty', $request->item4qty);
            });
        })->where(function ($q) use($request) {
            $q->where(function($q2) use ($request) {
                $q2->where('item1', $request->item5)->where('item1qty', $request->item5qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item2', $request->item5)->where('item2qty', $request->item5qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item3', $request->item5)->where('item3qty', $request->item5qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item4', $request->item5)->where('item4qty', $request->item5qty);
            })->orWhere(function($q2) use ($request) {
                $q2->where('item5', $request->item5)->where('item5qty', $request->item5qty);
            });
        });
    })->where('tool', $request->tool)->first();

很可能有更好的方法来做到这一点,但就使您的代码更具可读性而言,您可以使用循环:

$recipe = DataRecipe::where(function ($query) use ($request) {
    foreach (range(1, 5) as $i) {
        $item = $request->{'item' . $i};
        $quantity = $request->{'item' . $i . 'qty'};
        $query->where(function ($q) use ($item, $quantity) {
            $q->where(function ($q2) use ($item, $quantity) {
                $q2->where('item1', $item)->where('item1qty', $quantity);
            })->orWhere(function ($q2) use ($item, $quantity) {
                $q2->where('item2', $item)->where('item2qty', $quantity);
            })->orWhere(function ($q2) use ($item, $quantity) {
                $q2->where('item3', $item)->where('item3qty', $quantity);
            })->orWhere(function ($q2) use ($item, $quantity) {
                $q2->where('item4', $item)->where('item4qty', $quantity);
            })->orWhere(function ($q2) use ($item, $quantity) {
                $q2->where('item5', $item)->where('item5qty', $quantity);
            });
        });
    }
})->where('tool', $request->tool)->first();

如果你的应用程序可能的话,我可能会考虑重构你的代码和数据库,这样你就可以在DataRecipe和项目之间有一个标准的1 -2-多关系。这样你就不必担心item1, item2等,如果你只能有一定数量的项目,那么你可以使用验证来确保你永远不会得到太多。

希望这对你有帮助!