Search code examples
laraveleloquenteager-loadingrelationsubquery

Eloquent "super-eager" nested query possible?


Mates, my first post, searching and trying different solutions and approaches - and finally ended here asking.

I have a database with several related tables. A customer has a location, which has several settings (lifecycle eg. plan, build, run) and each setting has different circuits. Basically:

customers->locations->settings->circuits

Now I want a list of locations with setting and circuit information, where the supplier of the circuit is selected.

How would I write this query with eloquent? Here is what I tried so far, but it seems to ignore the "where supplier" clause...

$locations = Locations::with(
    ['settings' => function($query) use ($request)
        {
            $query->with(
                ['circuits' =>function($query2) use ($request)
                    {
                        $query2->where('supplier', $request->supplier);
                    }
                ]
            );                  
        }
    ])
    ->where('customer_id', $customers_id)
    ->orderBy('country')
    ->orderBy('city')
    ->get(); 

I'm sure, that all the "hasMany" and "belongsTo" extensions are available. Thanks for reading & answering udowsky

Update: Working Code, based on Enver's hint:

$locations = Locations::with('settings')
    ->whereHas('settings.circuits', function($query) use ($request)
        {
            $query->where('supplier', $request->supplier);
        }
        )
    ->where('customer_id', $report->customers_id)
    ->orderBy('country')
    ->orderBy('city')
    ->get();

HasManyThrough approach also works smooth:

Extending the Locations model:

public function circuits()
{
    return $this->hasManyThrough('App\Circuits', '\App\Settings');
}

and then use this query:

$locations = Locations::with('circuits')
    ->whereHas('circuits', function($query) use ($request)
        {
            $query->where('supplier', $request->supplier);
        }
    )
    ->where('customer_id', $report->customers_id)
    ->orderBy('country')
    ->orderBy('city')
    ->get();

Thank you all!


Solution

  • You can use nested relation query with eager loading.

    Example:

    $relation_sort = 'asc';
    $nested_sort = 'desc';
    
    $result = Model::with([
       'relation' => function($query) use($relation_sort){
          $query->orderBy('relation_column', $relation_sort);
       },
       'relation.nested' => function($query) use($nested_sort){
          $query->orderBy('nested_relation_column', $nested_sort);
       }
    ])->whereHas('relation', function($query){
        //Relation exists check.
        $query->where('price', '>', 100);
    })->whereHas('relation.nested', function($query) use($search_param){
        //Nested Relation search.
        $query->where('search_column', 'LIKE', $search_param);
    })->get();