mwiby's avatar
Level 2

Access the different brands of the product collection

I need a efficent way to get the brands from the collection, I have all the Modal and relashionships right, but can't figure out how to do this, do I need a foreach loop maby?

public function show($gender,$c_slug){

    $products = Product::whereHas('categories',function($query) use ($c_slug){
        $query->where('slug',$c_slug);
    })->where('gender',$gender)->get();


    $brands = $products->brand;

    
    return ['brands' => $brands];
    
}

This is in the Product Modal

public function brand() { return $this->belongsto('App\Brand'); }

0 likes
2 replies
Snapey's avatar
$products = Product::whereHas('categories',function($query) use ($c_slug){
        $query->where('slug',$c_slug);
    })->where('gender',$gender)
    ->with('brand')->get();

then brand will be an attribute of each product

1 like
kingmaker_bgp's avatar
Level 8

You already have implemented One of a Performance factor in your Query (with/without Knowledge).

To make the Query even more performant, we can do two things (These are not Performant, see last):

1. Eager Load Brands

public function show($gender,$c_slug){
   $products = Product::whereHas('categories',function($query) use ($c_slug){
        $query->where('slug',$c_slug);
    })->where('gender',$gender)
    ->with('brand')
    ->get();

    // ........
}

2. Get the Unique Brands from the Collection

public function show($gender,$c_slug){
   $products = Product::whereHas('categories',function($query) use ($c_slug){
        $query->where('slug',$c_slug);
    })->where('gender',$gender)
    ->with("brand")
    ->get();

   $brands = $products
         ->map->brands // Mapping to get all Brands
         ->flatten() // convert Collection of Collections to flattened Collection of all Brands (repeated)
         ->unique();

   return ['brands' => $brands];
}

Performant Solution

If you only want to sent the Brands in the Response, Why don't get it alone?

public function show($gender,$c_slug){
   $brands = Brand::whereHas("products", function($productQuery) use($gender, $c_slug) {
       return $productQuery->whereHas('categories', function($query) use ($c_slug) {
              return $query->where('slug',$c_slug);
           })->where('gender',$gender);
   })
   ->get();

   return ['brands' => $brands];
}

This Solution requires an Inverse Relation on the Brand model

class Brand extends Model {
   public function products() {
       return $this->hasMany(\App\Product::class);
    }
}

By pushing the Relationship conditions into the Database layer, PHP will avoid creating numerous Collection and Model Instances. You will see the Performance Issues when you started to have 100+ Entities(Model)

2 likes

Please or to participate in this conversation.