0

I have the following relations in my Laravel application

class Item extends Model 
{
    public function category()
    {
        return $this->belongsTo('App\Category');
    }
}

and

class Category extends Model
{
    public function item()
    {
        return $this->hasMany('App\Item');
    }
}

I want to implement search functionality so I have created the following Eloquent query:

$items = Item::where('item_type', '=', 'type1')
         ->where(function($query) use ($q) {
            $query->where('item_name','LIKE','%'.$q.'%')
                  ->orWhere('item_description','LIKE','%'.$q.'%');
         })
         ->paginate(10);

This is working as expected and returns the search results for 'q' based on the name and the description of the item.

As a next step, I would like to also search for the category_name. Because of the relation, I have the category_id stored in the Items table, but I would like to use the category_name in my Eloquent query.

Anyone could provide some help?


Based on feedback received, I tried:

Suggestion 1:

$items = Item::where('item_type', '=', 'type1')
         ->where(function($query) use ($q) {
           $query
             ->where('item_name', 'LIKE' ,'%'.$q.'%')
             ->orWhere('item_description', 'LIKE' ,'%'.$q.'%');
           })
           ->whereHas('category', function (Category $query) use ($q) {
              $query->where('category_name', $q);
           })

=> this gives following error message:

Argument 1 passed to App\Http\Controllers\ItemController::App\Http\Controllers{closure}() must be an instance of App\Http\Controllers\App\Category, instance of Illuminate\Database\Eloquent\Builder given

Suggestion 2:

$items = Item::where('item_type', '=', 'type1')
         ->where(function($query) use ($q) {
           $query
             ->where('item_name', 'LIKE' ,'%'.$q.'%')
             ->orWhere('item_description', 'LIKE' ,'%'.$q.'%');
           })
           ->whereHas('category', function ($query) use ($q) {
              $query->where('category_name', $q);
           })

=> this does not result any search result anymore (also not for item_name and item_description).

Solution

  $items = Item::where('item_type', '=', 'type1')
            ->where(function($query) use ($q) {
                $query
                 ->where('item_name', 'LIKE' ,'%'.$q.'%')
                 ->orWhere('item_description', 'LIKE' ,'%'.$q.'%');
              })
            ->orWhereHas('category', function ($query) use ($q) {
                 $query->where('category_name', $q);
              })
            ->sortable(['id' => 'desc'])
            ->paginate(10);
4
  • What you tried is not what I suggested though. I did not typehint Category in the whereHas closure. Commented Feb 4, 2019 at 9:26
  • Have you tried "orWhereHas" instead of "whereHas" in suggestion 2? As you don't want the result where both are equal to $q, rather than where one of them is equal to $q Commented Feb 4, 2019 at 9:27
  • Suggestion 2 in the original post is the variant which is not typehinted. But that also does not work. Commented Feb 4, 2019 at 9:27
  • So you want to search items that have a Category with a specific name. Is that right? Commented Feb 4, 2019 at 9:30

2 Answers 2

3

As you already described relation to Category in your Item model, you have to use just whereHas method:

$items = Item::where('item_type', '=', 'type1')
         ->where(function($query) use ($q) {
            $query->where('item_name','LIKE','%'.$q.'%')
                  ->orWhere('item_description','LIKE','%'.$q.'%');
         })
         ->orWhereHas('category', function ($query) use ($q) {
            $query->where('category_name', 'LIKE', "%$q%");
         })
         ->paginate(10);
Sign up to request clarification or add additional context in comments.

5 Comments

Hi, thanks for your answer. Your suggestion does not seem to work. I edited the original post with error messages
Sorry, then just delete Category type-hinting from the query. I'll change my answer right now
@wiwa1978, I also updated my answer using orWhereHas method to save first condition
This works indeed, thanks. I'll accept this answer and update original post
Great! Was glad to help you
3

You could add a whereHas and constrain it. For example:

$items = Item::where('item_type', '=', 'type1')
    ->where(function($query) use ($q) {
        $query->where('item_name','LIKE','%'.$q.'%')
            ->orWhere('item_description','LIKE','%'.$q.'%');
    })
    ->whereHas('category', function($query) {
        $query->where('category_name', 'name');
    })
    ->paginate(10);

1 Comment

Thanks Mozammil. This seems correct also. Similar to @Sergey answer. Note: I just used the orWhereHas instead of whereHas. Thanks for your help!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.