Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Synchro's avatar

Invokable controllers, api resources, and policies

I have a set of invokable single action controllers for an API resource. I also have a policy for the underlying model. The controllers have a base class that tells it to authorize requests in its constructor:

$this->authorizeResource(Product::class, 'product');

The problem seems to be that these policy methods are never triggered. Do invokable controllers and policies not get on? Does the lack of an action name (because it's always __invoke) mean that the action to policy name mapping (e.g. index -> viewAny) doesn't work?

To be clear, I'm also calling:

$this->authorize('viewAny', Product::class);

from within the __invoke method of the index controller, but I'm wondering if that fails to make the connection to the policy for the product model, since that method is never called.

0 likes
7 replies
SilenceBringer's avatar

@synchro of course authorizeResource will not works for invokable controller, because it doesn't have resource actions.

Now about policy: Did you register it correctly? Which methods you have in policy? Can you show your policy?

Synchro's avatar

I didn't register it because I'm relying on autodiscovery.

The policy contains the usual resource methods: viewAny, view, create, update, delete, restore, and forceDelete, plus a couple of extra ones.

Is there a way to get a before policy method to trigger across multiple invokable controllers (e.g. for admin access to all)?

This wasn't my design – Given that this is a bunch of methods relating to a single resource type, I suspect it might be better to migrate it to a single controller.

martinbean's avatar

@synchro If you have a single-action controller, then what methods exactly are you expecting the policy to apply to? The authoriseResource method is meant to be used in resource controllers:

class ProductController extends Controller
{
    public function __construct()
    {
        $this->authorizeResource(Product::class);
    }
}
Synchro's avatar

As i said, this is a set of single action controllers that acts like a single resource controller, and I'm trying to understand why it was built this way. I think the answer here will be to move it into a regular resource controller, however, it might be easier to call the methods in the policy manually, though I'm not sure what the right way to do that might be since the authorize call I'm using (as above) doesn't seem to provide that.

SilenceBringer's avatar

@synchro try this:

in your controller:

$this->authorize('viewAny', Product::class);

in your Product policy


    public function viewAny(User $user)
    {
        dd("I'm here");
    }

if you'll see the dump - you are ready to go. If not - possible you have some mistakes in your auto-discover policy name. Try to declare it directly

1 like
Synchro's avatar
Synchro
OP
Best Answer
Level 2

Yes, that's what I was trying. It was very odd - I could get it to trigger some policy calls but not others.

I've now solved it by moving all the invokables into a single resource controller, and now the policy works fine.

martinbean's avatar

@synchro All authorizeResource does is register policy methods against controller actions en masse. So it calls the viewAny policy method when the index action is called, and so on.

If you have single-action controllers then you’ll just need to call the appropriate, corresponding policy method in either the constructor or in your __invoke method:

class ProductIndexController extends Controller
{
    public function __construct()
    {
        $this->middleware('can:viewAny,App\Models\Product');
    }
}

Or:

class ProductIndexController extends Controller
{
    public function __invoke()
    {
        $this->authorize('viewAny', Product::class);
    }
}

Please or to participate in this conversation.