我具有以下表结构:
| products | product_options | product_option_values | product_option_to_product |
+----------+-----------------+-----------------------+---------------------------+
| id | id | id | id |
| | | | product_id |
| | | | product_option_id |
| | | | product_option_value_id |
我的关系如下所示:
// Product.php
public function options()
{
return $this->belongsToMany('App\ProductOption', 'product_option_to_product', 'product_id', 'product_option_id')->withPivot('product_option_value_id', 'product_id');
}
// ProductOption.php
public function values()
{
return $this->belongsToMany('App\ProductOptionValue', 'product_option_to_product', 'product_option_id', 'product_option_value_id')->withPivot('product_id');
}
现在,当我尝试这个:
$products = Product::with('options')->with('options.values')->first();
要么
$products = Product::with('options.values')->first();
我获得所有可能的选项值,因为它不使用产品ID来加载选项值。
有谁知道我如何确保它仅加载属于该产品的值?
我可以直接在产品上与选项值建立联系,但是我确实需要将它们附加到它们所属的选项上。
编辑:
我用这样的联接尝试了它:
$products = Product::with(['options.values' => function($q) {
$q->join('products', 'products.id', '=', 'product_option_to_product.product_id');
}])->first();
但这给出了相同的结果。
我目前已经实施了一个非常讨厌的修复程序,在我看来,我进行了一些检查:
@if($value->pivot->product_id == $product->id)
<div class="checkbox">
<label>
<input type="checkbox" name="{{ $option->id }}" value="{{ $value->id }}"> {{ $value->language->name }}
</label>
</div>
@endif
但是,这对我来说不合适。
您的问题在于表中的记录product_options
不知道您要检索的产品。
基于您在问题中提到的数据库结构,我编写了以下几行:
$product = App\Product::with('options')->with('options.values')->first();
foreach ($product->options as $option) {
foreach ($option->values as $value) {
printf(
"Product: %s, Option: %d, Value: %d\n",
$product->id,
$option->id,
$value->id
);
}
}
上面的代码仅打印特定产品的选项和值的可能组合。我使用的是您在应用程序中创建的相同关系。
当我加载该代码时,Eloquent(Laravel的ORM)在数据库中运行以下查询:
-- Retrieves the first product
select * from `products` limit 1;
-- Retrieves all options using the product_id as condition
select `product_options`.*, `product_option_to_product`.`product_id` as `pivot_product_id`, `product_option_to_product`.`product_option_id` as `pivot_product_option_id`, `product_option_to_product`.`product_option_value_id` as `pivot_product_option_value_id`
from `product_options` inner join `product_option_to_product` on `product_options`.`id` = `product_option_to_product`.`product_option_id`
where `product_option_to_product`.`product_id` in ('1')
-- Retrieves all values using the option_id as condition
select `product_option_values`.*, `product_option_to_product`.`product_option_id` as `pivot_product_option_id`, `product_option_to_product`.`product_option_value_id` as `pivot_product_option_value_id`, `product_option_to_product`.`product_id` as `pivot_product_id`
from `product_option_values` inner join `product_option_to_product` on `product_option_values`.`id` = `product_option_to_product`.`product_option_value_id`
where `product_option_to_product`.`product_option_id` in ('1', '2')
如您所见,最后一个查询不使用product_id
条件作为检索值的条件,因为product_options
table不保存对products
table的引用。
最后,我取得了与您相同的结果。尽管我正在搜索产品,但所有值都与一个选项相关。
最简单的解决方法是在调用关系时添加查询约束。像这样:
$product = App\Product::with('options')->with('options.values')->first();
foreach ($product->options as $option) {
foreach ($option->values()->where('product_id', $product->id)->get() as $value) {
printf("PRO: %s, OPT: %d, VAL: %d<br>\n", $product->id, $option->id, $value->id);
}
}
请注意$option->values
,我没有使用属性作为调用,而是使用了$option->values()
作为方法。调用关系方法时,可以像使用查询构建器一样使用它。
如果您不想使用此解决方法,则可能需要更改数据库结构和模型类。
-
一种替代解决方案是使用查询生成器来获取特定产品的所有值。
您可以在控制器中执行以下操作:
$values = ProductOptionValue::select([
'product_option_values.*',
'product_option_to_product.option_id',
])
->join('product_option_to_product', 'product_option_to_product.product_option_value_id', '=', 'product_option_values.id')
->where('product_id', $product->id)
->get();
这样,您将获得特定产品的所有值(由其提供$product->id
)及其相应的option_id
。
要在模板中使用上面查询的结果,您只需在复选框名称中做一个小改动:
<div class="checkbox">
<label>
<input type="checkbox" name="{{ $value->option_id }}" value="{{ $value->id }}"> {{ $value->language->name }}
</label>
</div>
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句