I'm trying to use the orWhereHas
method in Laravel with nested relations, but I am not getting the result I expect. Am I misunderstanding how to use this method?
My relationships are set up as follows:
Product
-> hasOne uniqueItem
-> hasMany fulfillmentCenterUniqueItems
-> hasMany skus
-> hasOne uniqueItem
-> hasMany fulfillmentCenterUniqueItems
I'm trying to test out the whereHas
and orWhereHas
methods by retrieving products from the database that contain uniqueItems
that have a uniqueItemFulfillmentCenter
with id = 7089
OR products that contain a sku
, that contains a uniqueItem
, that has a uniqueItemFulfillmentCenter
with id = 7412
.
Based on the data in my database, the result of this query should be two products. Product IDs 105 and 239.
Here's the Eloquent code I'm using:
$product = Spire_models\Product
::whereHas('uniqueItem.fulfillmentCenterUniqueItems', function ($query)
{
$query->where('id', 7089);
})
->orWhereHas('skus.uniqueItem.fulfillmentCenterUniqueItems', function ($query)
{
$query->where('id', 7412);
})
->get()->toArray();
For some reason, this is only returning product ID 105, instead of 105 and 239. The generated sql from this function is:
select * from `products` where `products`.`deleted_at` is null and (select count(*) from `unique_items` where `products`.`unique_item_id` = `unique_items`.`id` and (select count(*) from `fulfillment_center_unique_items` where `fulfillment_center_unique_items`.`unique_item_id` = `unique_items`.`id` and `id` = 7089 and `fulfillment_center_unique_items`.`deleted_at` is null) >= 1 and `unique_items`.`deleted_at` is null) >= 1 and (select count(*) from `skus` where `skus`.`product_id` = `products`.`id` and (select count(*) from `unique_items` where `skus`.`unique_item_id` = `unique_items`.`id` or (select count(*) from `fulfillment_center_unique_items` where `fulfillment_center_unique_items`.`unique_item_id` = `unique_items`.`id` and `id` = 7412 and `fulfillment_center_unique_items`.`deleted_at` is null) >= 1 and `unique_items`.`deleted_at` is null) >= 1 and `skus`.`deleted_at` is null) >= 1
Is this sql being generated incorrectly, or am I misusing the orWhereHas
method? To me it does not look like the OR
statement is being placed correctly in the sql.
If I remove the orWhereHas
method, things works as expected. For example, if I run this:
$product = Spire_models\Product
::whereHas('uniqueItem.fulfillmentCenterUniqueItems', function ($query)
{
$query->where('id', 7089);
})
->get()->toArray();
I correctly get back product ID 105. If I run this:
$product = Spire_models\Product
::whereHas('skus.uniqueItem.fulfillmentCenterUniqueItems', function ($query)
{
$query->where('id', 7412);
})
->get()->toArray();
I correctly get back product ID 239. So the individual pieces of the query work correctly, but it seems when I try to combine these with an orWhereHas
, I get unexpected results. Any idea why?
EDIT
As per the comments, it looks like this is a bug. I was able to temporarily work around it by rewriting the code to use where
and orWhere
. Here's the temporary solution:
$product = Spire_models\Product
::where(function ($query)
{
$query->whereHas('uniqueItem.fulfillmentCenterUniqueItems', function ($query)
{
$query->where('id', 7089);
});
})
->orWhere(function ($query)
{
$query->whereHas('skus.uniqueItem.fulfillmentCenterUniqueItems', function ($query)
{
$query->where('id', 7412);
});
})
->get()->toArray();
It was a bug and is fixed by now with this PR https://github.com/laravel/framework/pull/8171
It's been OK since version 5.0.21
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With