# Check access to controller method

**URL:** https://discourse.laminas.dev/t/check-access-to-controller-method/2570
**Category:** Components & MVC
**Tags:** laminas-eventmanager, laminas-mvc
**Created:** [October 31, 2021, 8:53pm UTC](https://discourse.laminas.dev/t/check-access-to-controller-method/2570 "2021-10-31T20:53:36Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![Kriss\_Kals](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/kriss_kals/32/1295_2.png) [@Kriss\_Kals](https://discourse.laminas.dev/u/Kriss_Kals)
#### Post date: [October 31, 2021, 8:53pm UTC](https://discourse.laminas.dev/t/check-access-to-controller-method/2570/1 "2021-10-31T20:53:36Z")

</div>

Hello,

I have several controllers with different actions. Let’s assume that in a few cases I would like for the whole controller to check if the user, based on the passed parameter (let’s assume category\_id), can perform actions in it. What is the best method to not duplicate the code in each action, but to check based on the parameter from routing and let’s say a database query, if the user has access to this controller and the actions in it?

---

<div class="post-metadata">

### Author: ![makxk](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/makxk/32/1266_2.png) [@makxk](https://discourse.laminas.dev/u/makxk)
#### Post date: [November 3, 2021, 8:28am UTC](https://discourse.laminas.dev/t/check-access-to-controller-method/2570/2 "2021-11-03T08:28:10Z")

</div>

Hi!  
Well, I am doing exactly what you mentioned (manually querying the ACL at the beginning of each action), but I think that can be replaced with an MvcEvent-Listener for the event ‘route’. ([Using the EventManager - tutorials - Laminas Docs](https://docs.laminas.dev/tutorials/event-manager/))

**Laminas\Mvc\Application L307:**

```auto
// Trigger route event
        $event->setName(MvcEvent::EVENT_ROUTE);
        $event->stopPropagation(false); // Clear before triggering
        $result = $events->triggerEventUntil($shortCircuit, $event);
        if ($result->stopped()) {
            $response = $result->last();
            if ($response instanceof ResponseInterface) {
                $event->setName(MvcEvent::EVENT_FINISH);
                $event->setTarget($this);
                $event->setResponse($response);
                $event->stopPropagation(false); // Clear before triggering
                $events->triggerEvent($event);
                $this->response = $response;
                return $this;
            }
        }

```

Hope this helps 🙂

---

<div class="post-metadata">

### Author: ![froschdesign](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/froschdesign/32/38_2.png) [@froschdesign](https://discourse.laminas.dev/u/froschdesign)
#### Post date: [November 3, 2021, 11:31am UTC](https://discourse.laminas.dev/t/check-access-to-controller-method/2570/3 "2021-11-03T11:31:40Z")

</div>

> [@makxk](#):
>
> …but I think that can be replaced with an MvcEvent-Listener for the event ‘route’

Correct, this is the recommended way.

An example of a listener can be found in the documentation of laminas-view:

[https://docs.laminas.dev/laminas-view/cookbook/setting-module-specific-layouts/](https://docs.laminas.dev/laminas-view/cookbook/setting-module-specific-layouts/)

The registration of listener can be simplified, `module/MyModule/config/module.config.php`:

```php
return [
    'listeners' => [
        MyModule\Listener\MyListener::class,
    ],
    'service_manager' => [
        'factories' => [
             MyModule\Listener\MyListener::class => Laminas\ServiceManager\Factory\InvokableFactory::class,
        ],
    ],
];

```

---

<div class="post-metadata">

### Author: ![makxk](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/makxk/32/1266_2.png) [@makxk](https://discourse.laminas.dev/u/makxk)
#### Post date: [November 3, 2021, 12:35pm UTC](https://discourse.laminas.dev/t/check-access-to-controller-method/2570/4 "2021-11-03T12:35:29Z")

</div>

Thanks for confirming 😃

> ```auto
> 'service_manager' => [
> MyModule\Listener\MyListener::class => Laminas\ServiceManager\Factory\InvokableFactory::class,
> ],
> 
> ```

Should there be a “factories” key?

```auto
'service_manager' => [
 'factories' => [ //here?
    MyModule\Listener\MyListener::class => Laminas\ServiceManager\Factory\InvokableFactory::class,
 ]
]

```

---

<div class="post-metadata">

### Author: ![froschdesign](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/froschdesign/32/38_2.png) [@froschdesign](https://discourse.laminas.dev/u/froschdesign)
#### Post date: [November 3, 2021, 12:38pm UTC](https://discourse.laminas.dev/t/check-access-to-controller-method/2570/5 "2021-11-03T12:38:37Z")

</div>

Right, I have updated the code example! 👍🏼

---

<div class="post-metadata">

### Author: ![Kriss\_Kals](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/kriss_kals/32/1295_2.png) [@Kriss\_Kals](https://discourse.laminas.dev/u/Kriss_Kals)
#### Post date: [November 4, 2021, 10:34pm UTC](https://discourse.laminas.dev/t/check-access-to-controller-method/2570/6 "2021-11-04T22:34:14Z")

</div>

Thank you for all your suggestions. Everyone has been helpful.

By the way, there was a question: if I check whether the user is the owner of the category, should I return the category object retrieved in the listener under some variable, so that in the controller in the methods I do not duplicate the query?  
I suspect the listener is not a good place. Once because of the role, twice because the function has too much responsibility. But on the other hand it’s always fewer database queries.

---

<div class="post-metadata">

### Author: ![froschdesign](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/froschdesign/32/38_2.png) [@froschdesign](https://discourse.laminas.dev/u/froschdesign)
#### Post date: [November 5, 2021, 6:38am UTC](https://discourse.laminas.dev/t/check-access-to-controller-method/2570/7 "2021-11-05T06:38:42Z")

</div>

> [@Kriss\_Kals](#):
>
> By the way, there was a question: if I check whether the user is the owner of the category, should I return the category object retrieved in the listener under some variable, so that in the controller in the methods I do not duplicate the query?

I’m sorry but your question was to check something based on some parameter from routing and not to retrieve something.  
Please provide a code example of your controller to illustrate what you need so we can better understand your use case.

---

<div class="post-metadata">

### Author: ![Kriss\_Kals](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/kriss_kals/32/1295_2.png) [@Kriss\_Kals](https://discourse.laminas.dev/u/Kriss_Kals)
#### Post date: [November 5, 2021, 8:06pm UTC](https://discourse.laminas.dev/t/check-access-to-controller-method/2570/8 "2021-11-05T20:06:43Z")

</div>

First, thank you for your help and guidance.

Let me describe my problem in detail.

Users, who have accounts in the portal, have access to the content management panel. Due to the nature of the site there are several hundred of them. In the content management panel of their pages there are several controllers. Among them there is a group of say 10 controllers, which are used to manage the content created by the user’s own web pages. And here at the outset in each controller and each method I have a call to a class say websiteBuilder, which currently does two things: it checks access to the method based on the passed routing parameter and if the user has access to it also sets a parameter with the site object - it has to fetch it anyway to check access, so it returns it by the way.

I would like to do the checking in one place - here the listener is perfect. There is still the issue of calling the object retrieval controller in one place. In zend framework 1 there was init() method and here it would be perfect.

```auto
class WebsiteController extends AbstractController
{

	protected $websiteBuilder;
	...

	public function __construct(
		WebsiteBuilderInterface $websiteBuilder,
		...
	)
	{
		$this->websiteBuilder = $websiteBuilder;
		...
	}

	public function indexAction()
	{
		$websiteBuilder = $this->websiteBuilder;
		$websiteBuilder->setWebsiteId((int) $this->params()->fromRoute('website_id'));
		$websiteBuilder->run();
		$resultWebsiteBuilder = $websiteBuilder->getParams();

		if (! $resultWebsiteBuilder->isValid()) {
			// set message
			$this->flashMessenger()->addErrorMessage($resultWebsiteBuilder->getErrorMessage());
			// redirect
			return $this->redirect()->toRoute($resultWebsiteBuilder->getRedirect(), $params = $resultSiteBuilder->getRedirectAction());
		}
		
		$websiteRow = $resultWebsiteBuilder->getWebsiteObject();

		...
		[other code]
	}

	public function otherAction()
	{
		$websiteBuilder = $this->websiteBuilder;
		$websiteBuilder->setWebsiteId((int) $this->params()->fromRoute('website_id'));
		$websiteBuilder->run();
		$resultWebsiteBuilder = $websiteBuilder->getParams();

		if (! $resultWebsiteBuilder->isValid()) {
			// set message
			$this->flashMessenger()->addErrorMessage($resultWebsiteBuilder->getErrorMessage());
			// redirect
			return $this->redirect()->toRoute($resultWebsiteBuilder->getRedirect(), $params = $resultSiteBuilder->getRedirectAction());
		}
		
		$websiteRow = $resultWebsiteBuilder->getWebsiteObject();
		
		...
		[other code]
	}
	
	...

```

The WebsiteController uses a WebsiteControllerFactory to inject dependencies.

There is probably a very simple solution to this case… that I don’t know 😃

---

<div class="post-metadata">

### Author: ![froschdesign](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/froschdesign/32/38_2.png) [@froschdesign](https://discourse.laminas.dev/u/froschdesign)
#### Post date: [November 6, 2021, 2:08pm UTC](https://discourse.laminas.dev/t/check-access-to-controller-method/2570/12 "2021-11-06T14:08:57Z")

</div>

> [@Kriss\_Kals](#):
>
> In zend framework 1 there was init() method and here it would be perfect.

In the `Laminas\Mvc\Controller\AbstractActionController` you can find the `onDispatch` method:

> <https://github.com/laminas/laminas-mvc/blob/9510e9fdcfd2a76eb852d4ba831e0a50cb6178a2/src/Controller/AbstractActionController.php#L52-L68>

This method can be overridden in own controllers and is executed with every request of the controller:

```php
public function onDispatch(MvcEvent $e)
{
    $action = $e->getRouteMatch()->getParam('action');

    // …

    return parent::onDispatch($e);
}

```

Maybe this will already help you.

* * *

I will look at the rest of your example later and give you feedback.

---

<div class="post-metadata">

### Author: ![Kriss\_Kals](https://yyz2.discourse-cdn.com/flex032/user_avatar/discourse.laminas.dev/kriss_kals/32/1295_2.png) [@Kriss\_Kals](https://discourse.laminas.dev/u/Kriss_Kals)
#### Post date: [November 8, 2021, 7:41am UTC](https://discourse.laminas.dev/t/check-access-to-controller-method/2570/14 "2021-11-08T07:41:07Z")

</div>

Thank You @froschdesign.

Your hint was very helpful and I was able to solve the problem.
