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);
此查询的问题是,如果用户选择颜色:黑色和 Senstivity:1800DPI,它 returns 所有颜色为黑色 的产品(以及任何敏感度) 和 所有具有 1800 DPI 的产品(以及任何颜色),不是同时具有这两种属性的产品。
如何编写 eloquent 查询以 实现所需的功能?
如果没有,是否有 更好的方法来做到这一点?(更好的 modeling/code 结构)?
您需要采用另一种格式输入
$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 Community 帮我找到这个!
我在 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);
此查询的问题是,如果用户选择颜色:黑色和 Senstivity:1800DPI,它 returns 所有颜色为黑色 的产品(以及任何敏感度) 和 所有具有 1800 DPI 的产品(以及任何颜色),不是同时具有这两种属性的产品。
如何编写 eloquent 查询以 实现所需的功能? 如果没有,是否有 更好的方法来做到这一点?(更好的 modeling/code 结构)?
您需要采用另一种格式输入
$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 Community 帮我找到这个!