19

I have two models which are related. I am trying to do a search in Products and only display the actual search results instead of ALL products of the category in which the product was found. I DO NOT want to search for any categories, since the categories will ALWAYS be displayed no matter what was searched for and no matter what was found.

Example. I have the following categories:

- Food
- Drinks
- Candy

My "Food" category has the following products:

- Strawberry
- Apple
- Banana

My "Drinks" category has the following products:

- Banana Cocktail
- Beer
- Cola

My "Candy" category has the following products:

- Strawberry Lollipop
- Chocolate Bar
- Banana Ice Cream

So, what I WANT to achieve is the following. I do a search for a product called "Banana". What I WANT to be displayed is:

Category Food
- Product Banana

Category Drinks
- Product Banana Cocktail

Category Candy
- Product Banana Ice Cream

But my issue is, with my code, if I perform a search for "Banana", it displays the category in which banana is found, and it returns and displays ALL products in that category instead of ONLY the products that I searched for. How can I achieve it so only the products that was searched for are displayed?

Categories Model:

class Categories extends Eloquent {

    public function products()
    {
        return $this->hasMany('Products');
    } 
}

Products Model:

class Products extends Eloquent {

    public function categories()
    {
        return $this->belongsTo('Categories');
    }
}

My Controller:

    $searchString       = Input::get('search');

    if($searchString)
    {
        $categories = Categories::with('products')->orderBy($order, $by)->whereHas('products', function ($query) use ($searchString){
            $query->where('name', 'like', '%'.$searchString.'%');
        })->get();
    }
    else {
        $categories     = Categories::with('products')->orderBy($order, $by)->get();
    }

My View:

@foreach($categories as $category)
    {{ $category->name }} // Show the category name

    @foreach($category->products as $product)
    {{ $product->name }} // Show all products in that category

    @endforeach
@endforeach
Hardist
  • 2,098
  • 11
  • 49
  • 85
  • What is your desired output? As in if "Example" belongs to "Category 1 ", "Category 2" and "Category 3", how do you want the output to appear? – Ymartin Aug 10 '15 at 13:05
  • Sorry but I didn't quite understand what do you want to get from your query, a list of Categories or a list of Products? – Juan Girini Aug 10 '15 at 13:21
  • I updated my question to explain it better :) I want to display a list of categories including the products that are linked to that category. – Hardist Aug 10 '15 at 13:48

1 Answers1

59

I don't know what how are you viewing the results, but I think if you just eager load the products on the categories you should be good.

$categories = Categories::whereHas('products', function ($query) use ($searchString){
        $query->where('name', 'like', '%'.$searchString.'%');
    })
    ->with(['products' => function($query) use ($searchString){
        $query->where('name', 'like', '%'.$searchString.'%');
    }])->get();

foreach($categories as $category){
    echo $category->name . ':' . PHP_EOL;
    foreach($category->products as $product){
        echo . '-' . $product->name . PHP_EOL;
    }
}
Pawel Bieszczad
  • 12,925
  • 3
  • 37
  • 40
  • This is what I am doing but it displays all products of a category if one search result was found, instead of displaying only the products that was searched for. – Hardist Aug 10 '15 at 13:58
  • No, because it is exactly what I am using right now, the only difference is that in your code, you also perform the search query on the categories which isn't needed. – Hardist Aug 10 '15 at 14:42
  • 1
    What your code does is fetching all categories that have a product with a search string. It doesn't filter the products. Just copy paste my solution and check the output. – Pawel Bieszczad Aug 10 '15 at 14:53
  • I tried your code and it gives me this error: syntax error, unexpected '=>' (T_DOUBLE_ARROW) So I changed the '=>' to a comma (->with('products', function ($query)) and it gave me this error: explode() expects parameter 2 to be string, object given – Hardist Aug 10 '15 at 15:06
  • I think that is why I thought I already tried that, because I couldn't see any differences from what I've done before. But this actually works, so bounty well-earned, thanks :) - Although *you may award your bounty in 19 hours* - You will get it tomorrow. – Hardist Aug 10 '15 at 15:17
  • Thanks a loooot.. you saved me :) This has been giving me a headache... – kiasaty Feb 22 '19 at 06:34
  • I thing you don't need to add the function in the with,,, – Jenuel Ganawed Jun 23 '22 at 05:56