0

I'm trying to create a route with three slugs, which include category, brand name and product name.

web.php

Route::get('/shop/{category:slug}/{brand:slug}/{product:slug}', [ProductController::class, 'index']);

Controller

<?php

namespace App\Http\Controllers;

use App\Brand;
use App\Category;
use App\Product;
use Illuminate\Http\Request;

class ProductController extends Controller
{
    public function index(Category $category, Brand $brand, Product $product)
    {
        $product = Product::where('id', $product->id)->with('related', function($q) {
            $q->with('brand')->with('categories');
        })->with('brand')->first();

        return view('product', compact('product', 'category'));
    }
}

For some reason i get this error, which i don't understand why.

BadMethodCallException Call to undefined method App\Category::brands()

3
  • 2
    Odd, I don't see brands() in your code here. Please post the stacktrace so we can see where the error lies. It might be in one of your models. Commented Dec 1, 2021 at 13:13
  • Are you calling $category->brands in your blade file by chance? Commented Dec 1, 2021 at 17:34
  • No i'm not, if i remove Brand $brand from the function it works fine. Commented Dec 1, 2021 at 20:45

1 Answer 1

1

The route resolver is assuming the parameters are all related to each other. From the documentation:

When using a custom keyed implicit binding as a nested route parameter, Laravel will automatically scope the query to retrieve the nested model by its parent using conventions to guess the relationship name on the parent.

So you should have a brands() relationship set up in your Category model, as well as a products() relationship in your Brand model.

If it's not possible to set up a relationship, simply stop using the route model binding and do it manually:

Route::get('/shop/{category}/{brand}/{product}', [ProductController::class, 'index']);
<?php

namespace App\Http\Controllers;

use App\Brand;
use App\Category;
use App\Product;
use Illuminate\Http\Request;

class ProductController extends Controller
{
    public function index(string $category, string $brand, string $product)
    {
        $category = Category::where('slug', $category);

        $product = Product::where('slug', $product)
            ->with(['category', 'brand'])->first();

        return view('product', compact('product', 'category'));
    }
}
Sign up to request clarification or add additional context in comments.

4 Comments

I understand, but brands do not have a relationship with the categories, only products. So to fix this issue i should just use the slug and find the brand with a query inside the function.
Understood, one brand will have many products of different categories. Unfortunately the way the URL is set up, Laravel assumes a relationship. The docs don't mention any way to override or disable that behaviour.
Yes you could get rid of the route model binding altogether and do the lookups manually if you need the slugs in the URL instead of the ID. Although looking at your controller, you don't even use the $category or $brand variable.
I use $category in the compact function, i was just really confused with the error. Thanks for pointing it out!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.