Search code examples
phplaravellaravel-5eloquenteager-loading

Laravel: Where selection for Eloquent Eager Loading relationship


I got two DB tables:

Posts

$table->increments('id');
$table->integer('country_id')->unsigned();
$table->foreign('country_id')->references('id')->on('countries');

Countries

$table->increments('id');
$table->string('name', 70);

I use laravel as back-end. Now I want to implement filtering data for my front-end. So the user can select a country name and laravel should answer the request only with posts that have a country with the specified name.

How could I add this condition to my existing pagination query? I tried this:

$query = app(Post::class)->with('country')->newQuery(); 
// ...
if ($request->exists('country')) {
        $query->where('country.name', $request->country);
}
// ...

... resulting in the following error:

Column not found: 1054 Unknown column 'country.name' in 'where clause' (SQL: select count(*) as aggregate from `posts` where `country`.`name` = Albania)

Solution

  • whereHas method accepts parameter as per Laravel code base,

     /**
     * Add a relationship count / exists condition to the query with where clauses.
     *
     * @param  string  $relation
     * @param  \Closure|null  $callback
     * @param  string  $operator
     * @param  int     $count
     * @return \Illuminate\Database\Eloquent\Builder|static
     */
    public function whereHas($relation, Closure $callback = null, $operator = '>=', $count = 1)
    {
        return $this->has($relation, $operator, $count, 'and', $callback);
    }
    

    so Changing the code a little as,

    $query = ""    
    
    if ($request->has('country'){
    $query = Post::with("country")->whereHas("country",function($q) use($request){
        $q->where("name","=",$request->country);
    })->get()
    }else{
        $query = Post::with("country")->get();
    }
    

    By the way above code can be a little simplified as follow;

    $query = ""    
    
    if ($request->has('country'){
      $query = Post::with(["country" => function($q) use($request){
      $q->where("name","=",$request->country);
    }])->first()
    }else{
      $query = Post::with("country")->get();
    

    }