Certainly! If you're getting the error:
Call to undefined method App\Http\Controllers\CommentController::middleware()
It's likely because in Laravel 11 and up (including Laravel 13), the controller middleware registration is handled differently due to the introduction of invokable controllers by default and changes in the middleware handling.
What Happened to authorizeResource()?
authorizeResource and even the middleware() method for controllers are not available by default in new Laravel versions unless you use the classic controller style (with the base Controller class and not invokable controllers).
Recommended Solution
Approach 1: Use Route Middleware
The most robust and up-to-date way in Laravel 13+ is to use the can middleware directly on your resource routes. Here’s how you can do it in your routes file:
Route::resource('comments', CommentController::class)
->middleware(['can:viewAny,App\Models\Comment']); // Example for `index` action
If you want to automatically bind all policy methods to the resource routes, Laravel provides a shortcut. Pass the action-to-ability mapping to the resource declaration:
use App\Models\Comment;
Route::resource('comments', CommentController::class)->middleware([
'index' => 'can:viewAny,' . Comment::class,
'create' => 'can:create,' . Comment::class,
'store' => 'can:create,' . Comment::class,
'show' => 'can:view,comment',
'edit' => 'can:update,comment',
'update' => 'can:update,comment',
'destroy' => 'can:delete,comment',
]);
But, since ->middleware() is not supported for resource routes this way, you should apply the can middleware directly in the route definition for each action if needed.
Approach 2: Manually Authorize in Actions
You can always authorize within each controller method:
use Illuminate\Support\Facades\Gate;
public function update(Comment $comment)
{
$this->authorize('update', $comment);
// ...
}
Approach 3: Use Classic Controller Style
If you want to use authorizeResource() as before, make sure your controller extends the base Controller and is not an invokable or single-action controller. Then, do:
use App\Models\Comment;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
class CommentController extends Controller
{
use AuthorizesRequests;
public function __construct()
{
$this->authorizeResource(Comment::class, 'comment');
}
}
BUT: This may still not work if your app is using the new slim controller style. In that case, stick with route can middleware or per-method authorization.
Summary (Efficient Way)
- Most "automatic" way now: Attach the
canmiddleware to your routes. - Using
authorize()in controller methods is always supported. authorizeResource()works ONLY in fully-featured controllers that extend the baseControllerclass and not in slim/invokable controllers.
Example Route with can middleware for resource routes:
Route::resource('comments', CommentController::class)->middleware('can:viewAny,App\Models\Comment');
Or, for individual routes:
Route::get('comments/{comment}', [CommentController::class, 'show'])
->middleware('can:view,comment');
TL;DR
- Laravel 13+ prefers route
canmiddleware for policy binding. authorizeResource()requires classic controller, not available in new slim/invokable controller style.- Authorize in each method if needed.
Let me know if you want examples for a specific controller or policy!