0

How to explicitly say to route model binding to fetch only related categories? I have my web.php file as follows:

Route::get('/catalog/{category}', [CategoryController::class, 'index'])->name('category.index');
Route::get('/catalog/{category}/{subcategory}', [SubcategoryController::class, 'index'])->name('subcategory.index');
Route::get('/catalog/{category}/{subcategory}/{subsubcategory}', [SubsubcategoryController::class, 'index'])->name('subsubcategory.index');

Subsubcategory controller:

public function index(Category $category, Subcategory $subcategory, Subsubcategory $subsubcategory)
{
    $subsubcategory->load('product')->loadCount('product');
    $products = Product::where('subsubcategory_id', $subsubcategory->id)->orderByRaw('product_order = 0, product_order')->get();
 return view('subsubcategory.index', compact('subsubcategory', 'products'));
}

And model in question:

public function subcategory()
{
    return $this->belongsTo(Subcategory::class);
}

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

public function getRouteKeyName()
{
    return 'slug';
}

It works partially ok. It loads all the slugs, but the problem is, let's say I have Samsung Subsubcategory with it's parent categories like:

catalog/mobile-phones/android/samsung

Whenever I modify url from catalog/mobile-phones/android/samsung to catalog/mobile-phones/ios/samsung it works, where in fact it should not. How to handle this second scenario?

PS: it also applies if I open subcategory and change category slug. But, obviously, if upper level category does not exists, it's going to throw 404.

Coverdale101
  • 7
  • 1
  • 2
  • Try reversing the routes listed, changed to this order instead ``` Route::get('/catalog/{category}/{subcategory}/{subsubcategory}', [SubsubcategoryController::class, 'index'])->name('subsubcategory.index'); Route::get('/catalog/{category}/{subcategory}', [SubcategoryController::class, 'index'])->name('subcategory.index'); Route::get('/catalog/{category}', [CategoryController::class, 'index'])->name('category.index'); ``` – Tanner May 25 '21 at 03:14
  • Thank you for your reply, but it still functions the same way – Coverdale101 May 25 '21 at 15:07

1 Answers1

0

You may want to explore the docs a bit in regard to explicit route model binding and customizing the resolution logic to get some ideas.
https://laravel.com/docs/8.x/routing#customizing-the-resolution-logic

The following is untested and I'm making some guesses about your table structures, but I think this should give you a basic concept of how you can alter route model binding to fit your needs. The same concept could also be applied to the {subcategory} binding, but with one less relationship check.

App/Providers/RouteServiceProvider.php

public function boot()
{
    // ...default code...

    // add custom resolution for binding 'subsubcategory'
    Route::bind('subsubcategory', function($slug, $route) {

        // check to see if category exists
        if ($category = Category::where('slug',$route->parameter('category'))->first()) {

            // check to see if subcategory exists under category
            if ($subcategory = $category->subcategories()->where('slug',$route->parameter('subcategory'))->first()) {

                // check to see if subsubcategory exists under subcategory
                if ($subsubcategory = $subcategory->subsubcategories()->where('slug',$slug)->first()) {

                    // success, proper relationship exists
                    return $subsubcategory;
                }
            }
        }

        // fail (404) if we get here
        throw new ModelNotFoundException();
    });
}

I will note, however, that this makes a number of separate database calls. There may be more efficient ways to achieve the same goal through other methods if optimization is a concern.

matticustard
  • 4,850
  • 1
  • 13
  • 18