Reputation: 315
I have an issue with one of my Laravel 5.2 routes/controllers, specifically I get the error of Controller method not found.
Route:
Route::get( 'guest/shop/{product}', 'GuestShopController@show' )->name( 'guest.shop.show' );
Controller and method:
class GuestShopController extends ShopController {
public function __construct( ) {
$this->middleware( 'guest' );
}
}
abstract class ShopController extends Controller {
protected function singularProductData( $product ) {
$thumbnails = $product->thumbnails();
return [
'product' => $product,
'thumbnails' => $thumbnails,
'main_thumbnail' => head( $thumbnails ),
];
}
protected function getProducts() {
return Cache::remember(
'products',
3600,
function () {
return Product::active()->get();
}
);
}
/**
* Display a listing of the resource.
*
* @return \Illuminate\Http\Response
*/
public function index() {
return view( 'pages.shop.index' )->with(
[
'products' => $this->getProducts(),
'organisation' => request()->attributes->get( 'organisation' ),
]
);
}
/**
* Display the specified product.
*
* @param string $slug
* @param null $product
*
* @return \Illuminate\Http\Response
*/
public function show( $slug, $product = null ) {
if( ! is_a( $product, Product::class ) ) {
$product = Product::active()->where( 'slug', $slug )->firstOrFail();
}
return view( 'pages.shop.product' )->with( $this->singularProductData( $product ) );
}
/**
* Display the specified product modal.
*
* @param int $id
*
* @return \Illuminate\Http\Response
*/
public function modal( $id ) {
$product = Product::active()->findOrFail( $id );
if( request()->ajax() ) {
return view( '_partials.shop.modal-content' )->with( $this->singularProductData( $product ) );
}
return $this->show( $product->slug, $product );
}
}
Things I've already done when debugging:
php artisan route:list
and confirmed route, controller and middleware all match up
composer dumpautoload
Upvotes: 1
Views: 1106
Reputation: 385
What url are you putting in the browser to be exact? You have
Route::get('guest/shop/{product}', 'GuestShopController@show')->name('guest.shop.show');
but show method expects 2 parameters $slug and an optional $product so the route should be
Route::get('guest/shop/{slug}/{product?}', 'GuestShopController@show')->name('guest.shop.show');
Otherwise if you only need the product the method and route should be as below:
Route::get('guest/shop/{product?}', 'GuestShopController@show')->name('guest.shop.show');
public function show($product = null)
{
}
Upvotes: 2
Reputation: 315
@chikurubhi's answer was mostly correct. It led me to change the url structure and slightly re-jig the controller methods.
Route::get( 'guest/shop/modal/{productId}', 'GuestShopController@modal' )->name( 'guest.shop.modal' );
Route::get( 'guest/shop/{slug}', 'GuestShopController@show' )->name( 'guest.shop.show' );
And on abstract ShopController:
/**
* Display the specified product.
*
* @param string $slug
* @param null $product
*
* @return \Illuminate\Http\Response
*/
public function show( $slug ) {
$product = Product::active()->where( 'slug', $slug )->firstOrFail();
return view( 'pages.shop.product' )->with( $this->singularProductData( $product ) );
}
/**
* Display the specified product modal.
*
* @param int $id
*
* @return \Illuminate\Http\Response
*/
public function modal( $productId ) {
$product = Product::active()->findOrFail( $productId );
if( request()->ajax() ) {
return view( '_partials.shop.modal-content' )->with( $this->singularProductData( $product ) );
}
return redirect()->action( "{$this}@show", [ $product->slug ] );
}
I've now changed this to {slug}
as the route parameter. After recently upgrading from 5.1 to 5.2, this may be a change in the framework that I wasn't aware of, that parameter names in the controller methods and routes must match? Anyway, fixed now and happy.
Because I have a route for modals that uses the same path, appended with modal, I've also changed this around so Laravel can't get confused by it. The modal route is now /guest/shop/modal/{productId}
. The modal controller method now only looks up the product via the $productId
parameter and if the request does not come via ajax, it redirects the user to the show method via the redirect()->action()
helper.
Because of the similar structure of the modal and show routes, I ensured I placed the modal route first, otherwise it would always return a 404.
Upvotes: 0