Armanhozyn's avatar

If anyone knows to bind policy to the controller in Laravel 13.

In build forum course, I am trying to do this. use Illuminate\Foundation\Auth\Access\AuthorizesRequests;

class CommentController extends Controller use AuthorizesRequests;

public function __construct() { $this->authorizeResource(Comment::class); } }

In my controller, But I am getting this error for this Call to undefined method App\Http\Controllers\CommentController::middleware().

Do you know any alternative way to bind policy with controller? I found that we do it with route middleware method. But I am not sure which is the efficient way, So that it automatically detect my controller methods to my policy method. Just like authorizeResource() method.

0 likes
3 replies
LaryAI's avatar
Level 58

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 can middleware to your routes.
  • Using authorize() in controller methods is always supported.
  • authorizeResource() works ONLY in fully-featured controllers that extend the base Controller class 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 can middleware 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!

martinbean's avatar

@armanhozyn I’ll never understand why Laravel removed this, as it was great for applying to policy methods to resourceful controller actions.

Nevertheless, you can get it back by importing the AuthorizesRequests trait in your controller:

+ use Illuminate\Foundation\Auth\Access\AuthorizesRequests;

  class CommentController extends Controller
  {
+     use AuthorizesRequests;

      public function __construct()
      {
          $this->authorizeResource(Comment::class);
      }
  }
1 like
Armanhozyn's avatar

@martinbean

I researched a lot with this, They removed it because, They want to separate policy names with controller methods, Like we need to explicitly tell which controller method should use which policy,

In this way it becomes automatic and in long run this becomes headache to understand which policy applied to which controller method.

Please or to participate in this conversation.