Ahmad Baktash Hayeri
Ahmad Baktash Hayeri

Reputation: 5880

Laravel's whereHas not filtering fetched results for a relationship (one-to-many)

I have been trying to filter students belonging to a sub-class based on a filter criteria (say the last name of the student).
In my Laravel 5.0 app, I have models Subclass and Student where their relationship and class definition are as follows:

Relationship:

Subclass HasMany Student(s)

Model definitions:

class Subclass extends Eloquent {

   .
   .
   .

    public function students() {
        return $this->hasMany('App\Models\Student');
    }
}

class Student extends Eloquent {

   .
   .
   .

    public function subclass() {
       return $this->belongsTo('App\Models\Subclass');
    }

    public function scopeFilterStudents($query, $filter){
       return $query->where('last_name', 'like', '%'. $filter .'%');
    }
}


The Issue: The problem arises when I try to filter the students in a particular subclass using whereHas as such:

$students = Subclass::whereId(1)->whereHas('students', function($query){
      return $query->filterStudents(Input::get('filter'));
  })->get();

I've followed the documentation on filtering queried models and technically, it should be working, but it isn't filtering as expected (in fact, it isnt filtering at all and I don't get a students key if I cast the result into an array).


Workaround: On the other hand, if I eager load (below) the fetched models (i.e. with with method), the models are filtered with the same filter criteria (AND, I do get a students key if the returned collection is cast into an array).

  $students = Subclass::whereId(1)->with(['students' => function($query){
      return $query->filterStudents(Input::get('filter'));
  }])->get();


So, is there any problem with my implementation of the whereHas method, or else, does the whereHas itself have any issue(s) filtering models.

Any help in this regards would be appreciated.

Upvotes: 2

Views: 1924

Answers (1)

Namoshek
Namoshek

Reputation: 6544

The problem is that you're fetching objects of the wrong model. What you're doing in your first approach is fetching all SubClasses that have an ID of 1 and at least one Student record to which the given filter applies. So if you want to get Students of this SubClass, you can simply invert the query:

$students = Student::whereHas('subClass', function($q) use ($subClassId) {
    return $q->whereId($subClassId);
})->filterStudents(Input::get('filter'))->get();

Your second approach is valid as well, but you're fetching a SubClass with its Students, so if I got your explanation right, you get more than you actually want or need.


It is also possible that I missunderstood your question and you're trying to get all Students that have at least one relation to a SubClass. If so, you can use this query:

$students = Student::has('subClass')->get();

Upvotes: 2

Related Questions