l_stankov01's avatar

Big problem , with Category and SubCategory models, please help!

Hello Guys, i have a problem to make Categories and SubCategories!

I want to get all products who belongs to SubCategory and if doesn't have product who belongs to sub to get all products from parent category i mean:

/category/{category} and if have subcategory in navbar /category/{category}/{sub}

Here is my code

Category.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;
use Cviebrock\EloquentSluggable\Sluggable;

class Category extends Model
{
    use Sluggable;
    protected $fillable = ['name','icon','subcategory_id','slug'];

    /**
     * @return array
     */
    public function sluggable(){
        return [
            'slug' => [
                'source' => 'name'
            ]
        ];
    }

    /**
     * @return string
     */
    public function getRouteKeyName(){
        return 'slug';
    }


    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function products() {
       return $this->belongsToMany(Product::class);
    }
}

SubCategory.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class SubCategory extends Model
{
    protected $fillable = ['name','slug'];

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function category() {
        return $this->belongsTo(Category::class);
    }
}

Product.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Product extends Model
{
    protected $fillable = [];

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function categories() {
       return $this->belongsToMany(Category::class);
    }
}

My Database structure:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateCategoriesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('categories', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('parent_id')->nullable()->default(null);
            $table->string('name');
            $table->string('slug');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('categories');
    }
}

SubCategory:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateSubcategoriesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('subcategories', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('slug')->unique();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('subcategories');
    }
}


Products:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateProductsTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('products', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->text('description');
            $table->double('price');
            $table->text('image');
            $table->text('onlyOnce');
            $table->integer('discount')->nullable(true);
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('products');
    }
}


Please help thanks!

0 likes
4 replies
taNgo's avatar

I think you don't need 2 different tables, you can have 1 table for categories and subcategories. You even prepare field 'parent_id' in categories table so you can drop subcategories.

To get product first query (simple)

Product::whereHas(['categories' => function($query) use ($subcategoryId){
            $query->whereId($subcategoryId);
        }])->get();

If you don't have any products then second query

Product::whereHas(['categories' => function($query) use ($category){
            $query->whereId($category->id);
        }])->orWhereHas(['categories' => function($query) use ($category){
            $query->whereIn('id', $category->subcategories->pluck('id'));   
        }])->get();

Maybe not so optimal but should work.

taNgo's avatar

Soo in your category model define relation to subcategories

public function subcategories(){
    return $this->hasMany(static::class, 'parent_id');
}

You didn't create table where will be multi-relations between products and categories. When you do that define in Product model relation to categories using belongsToMany.

Start from reading documentation about that kind of relations and everything will be much simpler :) Link

Please or to participate in this conversation.