Search code examples
laravellaravel-5eloquentlaravel-query-builderwherehas

Laravel whereHas not getting any results?


I have a Restaurant Model, each restaurant has a Contact Model, and each Contact is related to a City Model:

Restaurant.php:

public function contact()
{
  return $this->hasOne('App\Contact','rest_id');
}

Contact.php:

public function restaurant()
{
  return $this->belongsTo('App\Restaurant','rest_id','id'); 
}

public function city()
{
  return $this->belongsTo('App\City');
}

City.php:

public function contacts()
{
  return $this->hasMany('App\Contact');
}

now, what I want to do is search the restaurant names, alongside city names.
my controller code for searching is like this:

// the purpose of this condition is to keep the query empty until applying desired filters
$data = Restaurant::where('id', '=', '0');
$cityRest=$request->cityRest ;
if (!empty($cityRest)) {

  $nameFilter = Restaurant::where('name', 'like', "%$cityRest%");

  $contactFilter = Restaurant::whereHas('contact', function ($contact) use ($cityRest) {

    $contact->where('address', 'like', "%$cityRest%");

    $contact->whereHas('city', function ($city) use ($cityRest) {
      $city->where('cityName', 'like', "%$cityRest%");
    });

  });

  $data = $data->union($nameFilter);
  $data = $data->union($contactFilter);
}

$data->get();

when searching for restaurant name,the results are returned correctly,but when searching for city names nothing is returned, although there is restaurants with contact models that has a city???


Solution

  • You have to use a orWhereHas instead of a whereHas.

    With the whereHas you are searching for restaurants where the contact.address AND the city.name match your input.

    By using the orWhereHas you are searching for restaurants where the contact.address OR the city.name match your input.


    The AND and OR operators are used to filter records based on more than one condition:

    • The AND operator displays a record if all the conditions separated by AND are TRUE.
    • The OR operator displays a record if any of the conditions separated by OR is TRUE.

    source


    Try this:

    $contactFilter = Restaurant::whereHas('contact', function ($contact) use ($cityRest) {
    
        $contact->where('address', 'like', "%$cityRest%");
    
        $contact->orWhereHas('city', function ($city) use ($cityRest) {
            $city->where('cityName', 'like', "%$cityRest%");
        });
    
    });