davides98's avatar

Infinitive category and subcategory

I am creating a system of categories and subcategories Infinity. For now I have managed to create two-level categories and subcategories eg.

CATEGORY_1 --SUBCATEGORY_1 CATEGORY_2 --SUBCATEGORY_2

I would like to create infinite levels. how can I do?

categories tables

    public function up()
    {
        Schema::create('categories', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->bigInteger('parent_id')->default(0);
            $table->string('name');
            $table->boolean('status')->default(1);
            $table->timestamps();
        });
    }

Models\Category

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Category extends Model
{
    use HasFactory;

    protected $fillable = [
      'name',
      'parent_id'
    ];
    
    public function children()
    {
        return $this->hasMany('App\Models\Category', 'parent_id');
    }

}

CategoryController

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Validator;
use App\Models\Category;

class CategoryController extends Controller
{
    public function index(){
      $categories = Category::with('children')->where('parent_id', '=', 0)->get();

        return view('backend.category.index')->with([
          'categories'  => $categories
        ]);

    }

    public function create(){
      $categories = Category::with('children')->where('parent_id', '=', 0)->get();

        return view('backend.category.create')->with([
          'categories'  => $categories
        ]);
    }

    public function store(Request $request)
    {
      $validatedData = $this->validate($request, [
            'name'      => 'required|min:3|max:255|string',
            'parent_id' => 'sometimes|nullable|numeric',
            'status' => 'required'
      ]);
      Category::create($validatedData);

      return redirect()->route('category.index')->withSuccess('You have successfully created a Category!');
    }




}

index.blade.php

<ul class="list-group">
                  @foreach ($categories as $category)
                    <li class="list-group-item">
                      <div class="d-flex justify-content-between">
                        {{ $category->name }}

                        <div class="button-group d-flex">
                          <button type="button" class="btn btn-sm btn-primary mr-1 edit-category" data-toggle="modal">Edit</button>

                          <form action="#" method="POST">
                            @csrf
                            @method('DELETE')

                            <button type="submit" class="btn btn-sm btn-danger">Delete</button>
                          </form>
                        </div>
                      </div>

                      @if ($category->children)
                        <ul class="list-group mt-2">
                          @foreach ($category->children as $child)
                            <li class="list-group-item">
                              <div class="d-flex justify-content-between">
                                {{ $child->name }}

                                <div class="button-group d-flex">
                                  <button type="button" class="btn btn-sm btn-primary mr-1 edit-category" data-toggle="modal">Edit</button>

                                  <form action=" #" method="POST">
                                    @csrf
                                    @method('DELETE')

                                    <button type="submit" class="btn btn-sm btn-danger">Delete</button>
                                  </form>
                                </div>
                              </div>
                            </li>
                          @endforeach
                        </ul>
                      @endif
                    </li>
                  @endforeach
                </ul>
0 likes
4 replies
tykus's avatar

This should do it as far as the relationship is concerned

    public function children()
    {
        return $this->hasMany('App\Models\Category', 'parent_id')
			->with('children');
    }

If you want to, in the view, you can reuse an extracted partial to recurse through the nested children (of children... of children...), e.g.

@each('category._children, $category->children, 'category')
1 like
davides98's avatar

Sorry, can you be more specific? If you can recreate the view

tykus's avatar
tykus
Best Answer
Level 104

Here is how I would begin to separate out the reusable view partials:

<ul class="list-group">
    @foreach ($categories as $category)
        <li class="list-group-item">
            <div class="d-flex justify-content-between">
            {{ $category->name }}

            <div class="button-group d-flex">
                <button type="button" class="btn btn-sm btn-primary mr-1 edit-category" data-toggle="modal">Edit</button>

                <form action="#" method="POST">
                @csrf
                @method('DELETE')

                <button type="submit" class="btn btn-sm btn-danger">Delete</button>
                </form>
            </div>
            </div>

			{{-- Include a partial which will determine if there are children to be rendered --}}
            @include('categories._subcategories', ['category' => $category])

        </li>
    @endforeach
</ul>
// categories/_subcategories.blade.php
@if ($category->children)
    <ul class="list-group mt-2">
		{{-- Iterate over this $category's children --}}
        @each('categories._children', $category->children, 'category')
    </ul>
@endif
// categories/_children.blade.php
<li class="list-group-item">
    <div class="d-flex justify-content-between">
        {{ $category->name }}
        <div class="button-group d-flex">
            <button type="button" class="btn btn-sm btn-primary mr-1 edit-category" data-toggle="modal">Edit</button>
            <form action=" #" method="POST">
            @csrf
            @method('DELETE')
            <button type="submit" class="btn btn-sm btn-danger">Delete</button>
            </form>
        </div>
    </div>

    {{-- Include the partial which will determine if there are children of this subcategory to be rendered --}}
    @include('categories._subcategories, ['category' => $category])
</li>
1 like
davides98's avatar

Thanks a lot,

If I want create a create.blade If you wanted to select a category or a sub-category or sub-sub-category, to do this using the classic select-option do i have to use two more blades?

Please or to participate in this conversation.