Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Laravel: Has many through not respecting whereHas

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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:

enter image description here

Ad Plan (useful fields per the question):

enter image description here

>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

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading