Laravel categories with dynamic deep paths
Author
Author

Robert Nicjoo [68]

I love Laravel & WordPress, interested to pass little knowledge that I have to others.

Qr-Code

Scan to visit on mobile

TJD STUDIO is Hiring

Photographer & Videographer

Apply now Jabodetabek

Laravel categories with dynamic deep paths

Today I'm telling you how to make deep categories and return data but mostly I will focus on how to get the correct path of each category in complete dynamic way, it will save you lots of time and results cleaner codes.

 

Let's begin

 

1. First thing first, we will need categories table so lets meke schema for it. Run command below in your terminal

        

        php artisan make:model Category -m

        
    

2- Edit your schema file as:

        

        Schema::create('categories', function (Blueprint $table) {

          $table->increments('id');

          $table->string('title');

          $table->string('slug');

          $table->integer('parent_id')->unsigned()->nullable();

          $table->timestamps();

        });

        Schema::table('categories', function (Blueprint $table) {

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

        });

        
    

 

3. Edit your category model

 

        
            protected $fillable = [
                  'title', 'slug', 'parent_id'
            ];

            public function parent() {
                  return $this->belongsTo(Category::class, 'parent_id'); //get parent category
            } 
            public function children() {
                  return $this->hasMany(Category::class, 'parent_id'); //get all subs. NOT RECURSIVE
            }
        
    

 

Now excute command below and create table in database

        

        php artisan migration

        
    

 

4. Categories are ready to use, for sake of saving time I'm not gonna trough process of making controller and CRUD you can do it later by yourself. For now:

  4.1. Open your PhpMyAdmin (or anything you use for DB)

  4.2. Add some categories

  4.3 Add child category by providing id of previous categories you've made in `parent_id` column

 

5. Now we have categories ready in our database it's time to return them in blade (front-end) where we will use slugs as link to each of them (getting close to main course)

  5.1. Add this to your view controller

        

            use App\Category;

            public function myView(){

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

               return view('myBlade', compact('categories');

           
        }

        
    

 

  5.2. Now add this to your view (blade)

        

           @foreach($categories as $category)

               {{$category->title}}

                    //getting childrens

                  @if(count($category->children) > 0 )

                          @foreach($category->children as $child)

                                 {{$child->title}}

                          @endforeach

                  @endif

           @endforeach

        
    

 

test it and first then back to reading this article :)

 

6. Well we come to the final part of this article which is main part and the reason I made this article. "Creating laravel categories with dynamic deep paths"

   6.1. First we make new folder under App foler I name it `Helpers` you can name it whatever you like.

   6.2. In that folder I make 2 files name them 'CategoryRouteService.php' and 'CategoryServiceProvider.php`

   6.3. Let's finish `CategoryRouteService.php` first, add code below and save the file

        
            namespace App\Helpers;

            use App\Category;
            use Illuminate\Database\Eloquent\Collection;

            class CategoryRouteService
            {
                private $routes = [];

                public function __construct()
                {
                    $this->determineCategoriesRoutes();
                }

                public function getRoute(Category $category)
                {
                    return $this->routes[$category->id];
                }

                private function determineCategoriesRoutes()
                {
                    $categories = Category::all()->keyBy('id');

                    foreach ($categories as $id => $category) {
                        $slugs = $this->determineCategorySlugs($category, $categories);

                        if (count($slugs) === 1) {
                            $this->routes[$id] = url('category/' . $slugs[0]);
                        }
                        else {
                            $this->routes[$id] = url('category/' . implode('/', $slugs));
                        }
                    }
                }

                private function determineCategorySlugs(Category $category, Collection $categories, array $slugs = [])
                {
                    array_unshift($slugs, $category->slug);

                    if (!is_null($category->parent_id)) {
                        $slugs = $this->determineCategorySlugs($categories[$category->parent_id], $categories, $slugs);
                    }

                    return $slugs;
                }
            }
        
    

   6.4. Add code below to `CategoryServiceProvider.php' and save the file

    

        
            namespace App\Helpers;
            use App\Helpers\CategoryRouteService;

            class CategoryServiceProvider
            {
                public function register()
                {
                    $this->app->singleton(CategoryRouteService::class, function ($app) {
                        // At this point the categories routes will be determined.
                        // It happens only one time even if you call the service multiple times through the container.
                        return new CategoryRouteService();
                    });
                }
            }
        
    

 

7.  It's time to let laravel know that we are using this custom class in our app, open Config/App.php file and add this in there

        
                App/Helpers/CategoryServiceProvider::class,
        
    

8. Open your Category model and add this:

        
                      public function getRouteAttribute()
                      {

                          $categoryRouteService = app(CategoryRouteService::class);

                          return $categoryRouteService->getRoute($this);

                      }
        
    

 

9. Go back to your blade and add `` tag to your category titles and for `href` attribute provide `{{$categoryt->route}}`

 

Test it and see if your routes come nested. Works? perfect. Now lets take care of our routes.

 

 

Populating view for categories


Note: we will use one blade for all of our categories in any deep. (awesome)

 

10. Open web.php and add following route

        
            Route::get('/category/{slug}', 'Front\[email protected]')->where('slug', '.+')->name('categoryparent');
        
    

PS: you can change namings to whatever you like and use your own controller path etc. but don't delete `{slug}` and `->where('slug', '.+')` parts. they are important.

 

11. make function for your route, open your controller and make function below (nams chan be changed)

        
                   public function parent($slug){

                         $category = Category::where('slug', $slug)->with('children')->first();

                        return view('front.categories.single', compact('category')); //make blade anyware you wish.

                   }
        
    

 

Now go and actually test the link see if it returns the right blade for you.

How do you like this article?

Back to top