Constrain does not take effect when eager loading in laravel 5

- 1 answer

Ad

I have this function to get the results from joining relationships. However, the constraints don't seem to be taking effect. If I comment out the constraints, it still it gives the same result set as the uncommented constraints.

public function singleCategory($type, $category)
{
    $track = TrackType::with(['tracks.subgenres'], function($query, $category) {
        $query->where('name','=', $category);
    })->where('name', '=', $type)->get();

    dd($track->toArray());
}

Any help would be really appreciated :)

Ad

Answer

Ad

The constraining closure is only passed one parameter: $query. The other parameter you're trying to access ($category) needs to be made available via the use keyword:

public function singleCategory($type, $category)
{
    $track = TrackType::with(['tracks.subgenres'], function($query) use ($category) {
        $query->where('name', '=', $category);
    })->where('name', '=', $type)->get();

    dd($track->toArray());
}

Edit

The above will not affect the TrackTypes that are returned, it will only limit the related subgenres that are eager loaded. Based on the comments, it seems as if you are trying to limit the TrackTypes returned to those that contain a certain subgenre. In this case, you need to use the whereHas method:

public function singleCategory($type, $category)
{
    $track = TrackType::with('tracks.subgenres')
        ->whereHas('tracks.subgenres', function($query) use ($category) {
            $query->where('name', '=', $category);
        })
        ->where('name', '=', $type)
        ->get();

    dd($track->toArray());
}

Edit 2

It sounds like your target result set is actually the tracks, and not the track types. If so, you probably want to start by querying the tracks, and add in your filter criteria from there (I don't know your exact model and relationship names, so adjust accordingly):

public function singleCategory($type, $category)
{
    $track = Track::with(['tracktype', 'subgenres'])
        ->whereHas('tracktype', function($query) use ($type) {
            $query->where('name', '=', $type);
        })
        ->whereHas('subgenres', function($query) use ($category) {
            $query->where('name', '=', $category);
        })
        ->get();

    dd($track->toArray());
}

If you really are looking to start with the TrackType, then in addition to adding the whereHas() to find the TrackType, you need to add a whereHas() to filter down the Tracks that are eager loaded:

public function singleCategory($type, $category)
{
    $track = TrackType::with(['tracks' => function ($query) use ($category) {
            $query->whereHas('subgenres', function($query) use ($category) {
                $query->where('name', '=', $category);
            });
        }, 'tracks.subgenres'])
        ->whereHas('tracks.subgenres', function($query) use ($category) {
            $query->where('name', '=', $category);
        })
        ->where('name', '=', $type)
        ->get();

    dd($track->toArray());
}

The first example is much cleaner. In plain English, the first example would sound like "get all tracks of a type and a subgenre". The second example would sound like "get the track type, but only if it has tracks in a certain subgenre; also, only load those tracks within that subgenre".

Ad
source: stackoverflow.com
Ad