1

I use L8 And I have a category table ,it has parent_id for my subcategories

categories table

Category model

categoryController

SubCategoryController

categories.blade

sub_categories.blade

In my subcategory-index.blade.php I want to show categories but I just can show them with their id (parent id)

I don't know how to show categories title instead of their id.

I have this migration for categories table :

public function up()
    {

        Schema::dropIfExists('categories');
        Schema::create('categories', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('parent_id')->default(123);

            $table->string('title');
            $table->longText('description');
            $table->tinyInteger('status')->comment('status is 1 when a category is active and it is 0 otherwise.')->nullable();


            $table->rememberToken();
            $table->softDeletes();
            $table->timestamps();

        });
    }

and this is my category model :

class Category extends Model
{
    use HasFactory;

    protected $fillable = [
         'parent_id','title' , 'description', 'status',
    ];

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

    public function post(){
        return $this->hasMany(Post::class);
    }
}

And my subcategory controller :

...

public function index()
    {
        $parent_id = Category::with('parent_id')->get();
        $subcategories = Category::where('parent_id' ,'!=', 123)->get();
         return view('admin.subcategories.subcategories-index' , compact('subcategories'));
    }
...

And the part for show subcategory title in category-index.blade.php :

<table class="table table-bordered">
        <tr>
            <th>#</th>
            <th>id</th>
            <th>title</th>
            <th>category</th>
            <th>status</th>
            <th>operation</th>

        </tr>

        @foreach($subcategories as $subcategory )
        <tr>
            <td>{{ $loop->iteration }}</td>
           <td>{{ $subcategory['id'] }}</td>
           <td>{{ $subcategory['title'] }}</td>
           <td>{{ $subcategory['parent_id']}}</td>
           <td>
               @if($subcategory['status']==0 or $subcategory['status']==NULL)
                inactive
               @else
               active
               @endif
           </td>
           <td>
               <form method="POST" action="{{ route('subcategory.destroy',$subcategory->id) }}">
                   <a class="btn btn-info" href="{{ route('subcategory.show' , $subcategory->id) }}">show</a>
                   <a class="btn btn-primary" href="{{ route('subcategory.edit' , $subcategory->id) }}">edit</a>
                   @csrf
                   @method('DELETE')
                   <button type="submit" class="btn btn-danger"> delete</button>

               </form>
           </td>
        </tr>

        @endforeach

    </table>

Thanks for telling me what to do :>

calisa
  • 175
  • 1
  • 4
  • 17
  • In your subcategory controller, you're passing parent_id as a relation, and there is no such relation. And your categories are acting as subcategories, right? – MAY Mar 12 '21 at 18:37
  • my parent is category and the child is subcategory , and i have 2 ID column , one of them in primary key (main ID) and the other is parent_id , when a category has parent_id with 123 value , its a parent and when a category parent_id has other categories ID its subcategory. i hope you understand. @MAY – calisa Mar 12 '21 at 18:46
  • Ok, I get it, If parent_id exists then its a sub_category, To get all main_categories or parent_categories, simply do `$categories = Category::whereNull('parent_id')->get();` – MAY Mar 12 '21 at 18:52
  • for sub-categories, `$sub_catgories = Categories::with('childern')->whereNotNull('parent_id')->get();` you should rename your relation though, it should be parent instead of childern, because it is pointing towards the parent. – MAY Mar 12 '21 at 18:56
  • thank you but how i use in blade? because i have a subcategory foreach and show subcategory values , and in subcategory foreach i want to show category title. @MAY – calisa Mar 12 '21 at 18:59
  • Looking at the relation defined above you can have sub-categories with multiple parents, so $sub_categories collection that you'll get will have a nested collection of parents, you can loop on that collection to get the parent category name. – MAY Mar 12 '21 at 19:13
  • thank you @MAY for your help – calisa Mar 12 '21 at 20:29
  • happy to help :) – MAY Mar 12 '21 at 20:30
  • sorry for annoying you but now i put the $sub_categories_with_parent in my controller and when in my index blade i put this `{{ $subcategory->parent_id->title}}` , gives me Trying to get property 'title' of non-object error . where is my mistake? – calisa Mar 12 '21 at 20:55
  • because `parent_id` is not an object, you've to do this `$parents = $sub_categories->parent` this will give you all parents for that subcategory as from your relation single sub-category can have multiple parents. and then loop on `$parents` and access title using `$parent->title`. I hope this will help. – MAY Mar 12 '21 at 21:00
  • yeah it helped , thank ^_^ – calisa Mar 12 '21 at 21:04

2 Answers2

2

To get subcategories

$sub_categories = Category::whereNotNull('parent_id')->get();

To get sub-categories with parent

$sub_categories_with_parent = Category::with('parent')->whereNotNull('parent_id')->get();

To fetch categories

$categories = Category::whereNull('parent_id')->get();

To fetch categories with children

$categories_with_childern = Category::with('children')->whereNull('parent_id')->get();

You might have to redefine your relations as well:

public function parent()
{
    return $this->belongsTo(Category::class);
}

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

In migration define relation as well

$table->foreign('parent_id')->references('id')->on('categories')->onUpdate('cascade')->onDelete('cascade');

Make parent field nullable

$table->unsignedBigInteger('parent_id')->nullable()->default(123);
MAY
  • 667
  • 1
  • 6
  • 21
  • thank you so much .. i had not the parent relation and foreign key for parent_id , i added them and it fixed. – calisa Mar 12 '21 at 20:32
1

The line down below is incorrect. Because with() is used to get relational data and parent_id is not a relation name.

$parent_id = Category::with('parent_id')->get();

If your route contains the id or slug of the category, you can use it, but I think it doesn't, because your index function doesn't accept any route parameter. So I assume you are trying to fetch all categories and subcategories. But in this case, the second line of the index function doesn't make sense at all.

If you want to all categories:

$categories = Category::where('parent_id', null)->with('children')->get();

I see you use 123 for top-level categories, and it looks high enough. But nullable is a better practice for that purpose.

If you need a specific category and its subcategories:

// web.php
Route::get('category/{slug}', [CategoryController::class, 'index']);

// CategoryConteroller.php
public function index($slug)
{
    $category = Category::where('slug', $slug)->with('children')->get();
}
Bulent
  • 3,307
  • 1
  • 14
  • 22