0

I have defined categories in three level. Primary, Secondary, and Product Category.

I have Two categories under primary_categories table which is Women's Fashion and Men's Fashion.

Under secondary_categories I have categories like traditional wear(for women), Footwear(for women), western(for women), western wear(for men), footwear(for men), pants(for men) and so on.

And finally under product_categories I have categories like pants, t-shirts, kurta, sandals and so on.

While saving category for the product, I have used products table in the column category_id.

Now I want to get products that comes under Women's fashion. How can I do that?

Primary Category

public function up()
{
    Schema::create('primary_categories', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->string('name');
        $table->timestamps();
    });
}

Secondary Category

public function up()
{
    Schema::create('secondary_categories', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->string('name');
        $table->string('slug');
        $table->unsignedBigInteger('primary_category_id')->nullable();
        $table->foreign('primary_category_id')->references('id')->on('primary_categories')->onDelete('SET NULL');
        $table->timestamps();
    });
}

Final Category

public function up()
{
    Schema::create('product_categories', function (Blueprint $table) {
        $table->bigIncrements('id');
        $table->string('name');
        $table->string('slug')->unique();
        $table->unsignedBigInteger('secondary_category_id')->nullable(); 
        $table->foreign('secondary_category_id')->references('id')->on('secondary_categories')->onDelete('SET NULL');
        $table->timestamps();
    });
}

While adding product, category_id of product_categories goes inside the product table.

Aashish gaba
  • 1,726
  • 1
  • 5
  • 14
Gaurav
  • 149
  • 12

1 Answers1

2

PrimaryCategory Model

public function secondaryCategories(){
   return $this->hasMany(App\SecondaryCategory::class, 'primary_category_id', 'id');
}

SecondaryCategory Model

public function primaryCategory(){
    return $this->belongsTo(App\PrimaryCategory::class, 'primary_category_id', 'id');
}

public function productCategories(){
   return $this->hasMany(App\ProductCategory::class, 'secondary_category_id', 'id');
}

ProductCategory Model

public function secondaryCategory(){
   return $this->belongsTo(App\SecondaryCategory::class, 'secondary_category_id', 'id');
}

public function products(){
    return $this->hasMany(App\Product::class, 'category_id', 'id');
}

Product Model

public function productCategory(){
      return $this->belongsTo(App\ProductCategory, 'category_id', 'id');
}

Controller

To get all products with a given PrimaryCategory

Option 1: DB query, several collection methods.

$name = "Women's Fashion";

$pc = PrimaryCategory::with(
        'secondaryCategories.productCategories.products')
        ->where('name', $name)->first();

$products = $pc->secondaryCategories->pluck('productCategories')
               ->collapse()->pluck('products')->collapse();

 

OR

[NESTED EAGER LOADING WITH CONSTRAINTS]

Option 2: DB query

$name = "Women's Fashion";

$products = Product::whereHas('productCategory', function($query) 
    use($name) {
         $query->whereHas('secondaryCategory', function($query) 
         use($name)  { 
             $query->whereHas('primaryCategory', function($query) 
             use($name){
                 $query->where('name', $name);
             });
         });
   })
   ->with([
    'productCategory' => function($query) use($name) {
         $query->whereHas('secondaryCategory', function($query) use($name)
          { 
             $query->whereHas('primaryCategory', function($query) 
               use($name){
                   $query->where('name', $name);
               });
          });
     },
    'productCategory.secondaryCategory'=> function($query) use($name)
     { 
             $query->whereHas('primaryCategory', function($query) 
               use($name){
                   $query->where('name', $name);
               });
     },
    'productCategory.secondaryCategory.primaryCategory' =>                   
      function($query) use($name) {
            $query->where('name', $name);
     }])->get();
Aashish gaba
  • 1,726
  • 1
  • 5
  • 14
  • It says Trying to get property 'productCategories' of non-object – Gaurav Jul 26 '20 at 07:50
  • Can you paste the model codes here? And make sure you add the name in the where statement correct, I mean add whatever's there in your database for the category 'for women' – Aashish gaba Jul 26 '20 at 08:09
  • Also dd($sc_women) to see if you're getting the correct SecondCategory instance. – Aashish gaba Jul 26 '20 at 08:10
  • I was only getting one category `$sc_women` because there is `first()` method instead of 'get()'. Now I am getting data. Now I am getting data. But in some `secondary_categories` there is not `product_categories` maybe that's why I am getting Property [productCategories] does not exist on this collection instance. – Gaurav Jul 26 '20 at 08:21
  • I created it considering that there exists a mapping between every type of category. And you didn't mention anything regarding the type of category_id being stored in the product. So I assumed that the category_id in the product is of the productCategory, and then there exists a mapping to the point of PrimaryCategory. Let me know if I misinterpreted anything. – Aashish gaba Jul 26 '20 at 08:27
  • While adding product the category_id is set inside `category_id` column and that will be of `product_categories`. I think we are near to the answer because I am getting all the `sub_categories` and under that I am also getting all the `product_categories` on the relation instance. Now we need to fetch all the product from `category_id` coming in `sub_categories` instance. Is is possible? – Gaurav Jul 26 '20 at 08:39
  • That is exactly we're doing. The 'for women' category is from SecondaryCategory, right ?. We get that instance and then we get its product categories, and then the products which belong to those product categories. And as you said, the category_id is of productcategory, so if you want to get product on the basis of secondaryCategory, you need to have mapping of every productCategory to Secondary Category. – Aashish gaba Jul 26 '20 at 09:52
  • You're storing productCategory id in the category_id of the product table. As far as the question post was concerned, the solution was supposed to get the products which fall under given SecondaryCategory, given the structure that we store productCategory's id in the product_id column of the product table. And that is what the answer does. If this is not something that you wanted, please rephrase the question and let me know. – Aashish gaba Jul 26 '20 at 09:56
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/218614/discussion-between-gaurav-and-aashish-gaba). – Gaurav Jul 26 '20 at 10:04
  • I also think that making it a function would be great. We can use same code again and again. Isn't it? – Gaurav Jul 26 '20 at 11:36
  • Yes, we can for sure :) I just didn't want too many function names in the code, and wanted to keep it clear so it's easier for reader to understand that we need to go to the deepest level from every relation possible. – Aashish gaba Jul 26 '20 at 11:38