Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

ntn0de's avatar

Relationship query Issue

I did this query :

http://127.0.0.1:8000/api/auth/products?filter[category]=1

Result: It returns the product with no category as well and

the first one with category not matching to queried one.

{
    "data": [
 {
            "id": "51",
            "name": "test",
            
            "cats": [   ],
            "imageUrl": "17ca4da-eed-4061-e45-4bb343a8e27.jpeg"
        },
        {
            "id": "51",
            "name": "test",
            
            "cats": [
                {
                    "id": 2,
                    "name": "Cleta Roberts MD",
                    
                }
            ],
            "imageUrl": "124ca4da-ec2f-4061-b472-84bb103a8e27.jpeg"
        },
        {
            "id": "46",
            "name": "atque",
       
            "cats": [
                {
                    "id": 1,
                    "name": "Wyman Schumm",
                    
                },
                {
                    "id": 2,
                    "name": "Cleta Roberts MD",
                    
                },
                {
                    "id": 5,
                    "name": "Gay Kerluke",
                    
                }
            ],
            "imageUrl": "none"
        },
        {
            "id": "48",
            "name": "quam",
            
            "cats": [
                {
                    "id": 1,
                    "name": "Wyman Schumm",
                  
                },
                {
                    "id": 4,
                    "name": "Tremaine Walter",
                  
                },
                {
                    "id": 5,
                    "name": "Gay Kerluke",
                    
                }
            ],
            "imageUrl": "none"
        },
        {
            "id": "37",
            "name": "aliquid",
            
            "cats": [
                {
                    "id": 1,
                    "name": "Wyman Schumm",
                  
                },
                {
                    "id": 2,
                    "name": "Cleta Roberts MD",
                  
                },
                {
                    "id": 5,
                    "name": "Gay Kerluke",
                   
                }
            ],
            "imageUrl": "none"
        },
        {
            "id": "32",
            "name": "qui",
            
            "cats": [
                {
                    "id": 1,
                    "name": "Wyman Schumm",
                    
                },
                {
                    "id": 2,
                    "name": "Cleta Roberts MD",
                    
                },
                {
                    "id": 4,
                    "name": "Tremaine Walter",
                    
                }
            ],
            "imageUrl": "none"
        },
        {
            "id": "24",
            "name": "accusantium",
           
            "cats": [
                {
                    "id": 1,
                    "name": "Wyman Schumm",
                    
                },
                {
                    "id": 3,
                    "name": "Wilfred Franecki",
                   
                },
                {
                    "id": 5,
                    "name": "Gay Kerluke",
                  
                }
            ],
            "imageUrl": "none"
        },
        {
            "id": "3",
            "name": "corrupti",
       
            "cats": [
                {
                    "id": 1,
                    "name": "Wyman Schumm",
                   
                }
            ],
            "imageUrl": "none"
        },
        {
            "id": "10",
            "name": "et",
            "cats": [
                {
                    "id": 1,
                    "name": "Wyman Schumm",
                    
                }
            ],
            "imageUrl": "none"
        }
    ]
}

I have a scope in Product

public function scopeCategory($query, $filters)
    {

        return $query->with(['categories'])
            ->whereHas('categories', function ($query) use ($filters) {
                $query->where('categories.id', $filters);
            })
            ->whereDoesntHave('categories', function ($query) use ($filters) {
                $query->where('categories.id', '!=', $filters);
             })
            ;

    }

called by

$products = QueryBuilder::for(Product::class)
            ->allowedFilters(['name', 'user_id', AllowedFilter::scope('category')])
            ->allowedSorts('id')
            ->latest()
            ->whereRaw('(quantity - total_sold) > 0')
            ->orWhere('created_at', '>=', Carbon::now()->subWeek())
            ->get();
        return ProductCollection::collection($products);
0 likes
8 replies
bobbybouwmann's avatar

It's because you're using whereHas and whereDoesntHave on the same relationship. You should only pick one of them. in this case whereHas('categories') makes the most sense here ;)

bobbybouwmann's avatar

This way you can use it for one category or multiple categories in the future.

public function scopeCategory($query, $filters)
{
	$categories = is_array($filters) ? $filters : [$filters];

	return $query->with(['categories'])
		->whereHas('categories', function ($query) use ($categories) {
			$query->whereIn('id', $categories);
		});
ntn0de's avatar

@bobbybouwmann

return $query->with(['categories'])
            ->whereHas('categories', function ($query) use ($filters) {
                $query->where('categories.id', $filters);
            });

either i put this only.

the result is always same.. not as expected,

bobbybouwmann's avatar
Level 88

Yeah, @sswifto is correct here. You only now check which products have the correct categories, but then it loads all the categories of those products. Instead, you need to do this

$callback = function ($query) use ($filters) {
	$query->where('categories.id', $filters);
};

return $query->with(['categories' => $callback])
	->whereHas('categories', $callback);

Does this make sense to you? Now we're only loading the categories we're actually looking for instead of all categories of a product.

1 like

Please or to participate in this conversation.