繁体   English   中英

Laravel 从关系中过滤模型

[英]Laravel filtering models from relations

我在 Laravel (8.0) 中有两个相关模型

Products
+---------+-----------+-----------------+-----+
| item_id |   group   | show_in_website | ... |
+---------+-----------+-----------------+-----+
|     147 | Keyboards |               1 | ... |
|     158 | Keyboards |               1 | ... |
|     003 | Mouse     |               1 | ... |
+---------+-----------+-----------------+-----+

Attributes
+----+---------+-------------+------------+
| id | item_id |    name     |   value    |
+----+---------+-------------+------------+
|  1 |     147 | Color       | Black      |
|  2 |     147 | Sensitivity | 1800 DPI   |
|  3 |     158 | Color       | White      |
|  4 |     158 | Sensitivity | 1800 DPI   |
|  5 |     003 | Color       | White      |
|  6 |     003 | Type        | Mechanical |
|  7 |     003 | Size        | 108 Keys   |
+----+---------+-------------+------------+

我有使用 hasMany() 关系的与属性相关的产品,我希望用户根据一个或多个属性过滤产品。 我能想出的唯一解决方案是

$group = 'Mouse';
$names = ['Color', 'Sensitivity'];
$values = ['Black', 'White', 'Red', '1800 DPI', '2100 DPI']

// OR

$group = 'Keyboard';
$names = ['Type'];
$values = ['Mechanical']

/* These parameters are user controlled, user can only filter one group at a time, 
but might choose one or more names/values pairs for filters. 
I.E the first case would return all Mice which has Black,White or Red color and 1800 or 2100 DPI
*/


$products = Product::where(['show_in_website', 1], ['group', $group])
            ->whereHas('attributes', 
                function ($query) use ($names, $values){
                    $query
                        ->whereIn('name', $names)
                        ->whereIn('values', $values);
                })->paginate(20);

此查询的问题是,如果用户选择颜色:黑色和灵敏度:1800DPI,它会返回所有具有黑色(以及任何灵敏度)的产品和所有具有 1800 DPI (以及任何颜色)的产品,而不是同时具有这两种属性的产品。

如何编写 eloquent 查询来实现所需的 function? 如果没有,是否有更好的方法来做到这一点? (更好的建模/代码结构)?

您需要以另一种格式进行输入

$group = 'Mouse';
$attributes = ['Color' => ['black'], 'Sensitivity' => ['1800 DPI', '2100 DPI']];

然后使用 whereHas 循环属性

$query = Product::where(['show_in_website', 1], ['group', $group]);
foreach ($attributes as $name => $values) {
    $query->whereHas('attributes', function ($attributeQuery) use ($name, $values){
        $attributeQuery->where('name', $name)
            ->whereIn('values', $values);
}
$products = $query->paginate(20);

我这样做的方式如下:

$products = Product::where('show_in_website', 1)->where('group', $group);
foreach($names as $name){
    $products->whereHas('attributes', function ($query) use($name, $values){
        $query->where('name', $name)
              ->whereIn('value', $values);
        });
}

感谢Laravel Discord 社区帮我找到这个!

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM