Laravel: Has many through not respecting whereHas

Advertisements

I am trying to construct a hasManyThrough relationship in Laravel 10.

I have 3 tables: users table (standard Laravel columns), client_assignments, and media_ad_plans

A user can be assigned to multiple clients in the client_assignments table. In the media_ad_plans table an entry belongs to one client.

In my Users model I am defining the relationship like so:

public function adPlans(): HasManyThrough
{
    return $this->hasManyThrough(
        AdPlan::class,
        ClientAssignment::class,
        'user_id',
        'client_id',
        'id',
        'client_id'
    );
}

However, when doing something like:

    $users = User::with('adPlans.client')->whereHas('adPlans', function ($query) {
        return $query->duringTodayUsing('material_deadline', false); // a custom scope
    })->get();

All of the ad plan items associated with a user are returned, not just the one’s that match the whereHas statement. I’ve tried a simple query within the whereHas closure but it does not change the output – I still get all items for the user. I suspect my relationship is malformed or perhaps I am doing something "illegal." I am not getting any errors.

Client Assignments:

Ad Plan (useful fields per the question):

>Solution :

->whereHas() has no effect on a separate ->with() clause. Your code is working exactly as expected; whereHas() is filtering which User records are returned, based on 'adPlans', function ($query) { ... }), but ->with('adPlans.client') is correctly returning ALL of each User‘s associated adPlans Records.

You either need to duplicate your logic onto your ->with() clause, like:

$users = User::with(['adPlans' => function ($query) {
  return $query->with('client')->duringTodayUsing('material_deadline', false);
}])->whereHas('adPlans', function ($query) {
  return $query->duringTodayUsing('material_deadline', false);
})->get();

Or use Laravel’s ->withWhereHas() Clause:

$users = User::withWhereHas('adPlans', function ($query) {
  return $query->with('client')->duringTodayUsing('material_deadline', false);
})->get();

Documentation:

https://laravel.com/docs/10.x/eloquent-relationships#constraining-eager-loads-with-relationship-existence

Leave a ReplyCancel reply