Redirect from Plugin

Hello,

could someone please drop an example of how to make a redirect from a plugin?

What plugin do you mean? Controller plugin?

Please also describe your use case because it seems strange to want to do it that way.

I have an ExampleHelper which extends AbstractHelper and in an exceptional situation I would like to redirect the user to the route e.g. logout (in method__invoke). Is it possible?

I assume you mean Laminas\View\Helper\AbstractHelper.

Maybe but definitely wrong. A redirect in a view helper is too late, this must be done earlier.
Can you provide the code of your view helper?

You are right, it is indeed too late. I now have the logic in a plugin (ExamplePlugin extends AbstractPlugin) and the current question is, in the method __invoke can I do the redirect action?

In a controller plugin, you have access to the controller and thus also to all other plugins.

Unfortunately, I cannot say if this is a correct implementation, because your use case is still a mystery.

In the plugin, in the __invoke method, I have fetched the user’s data from the session - it returns all the necessary information about the user, but I would like to do a redirect to route logout if the session does not return the user’s data (e.g. it happens when the user has a session, but his record has been deleted from the database during his session). For example in my UserPlugin (I use this plugin in many controllers, in general this solution works, but there may be a specific situation described above):

...
if (! $this->authorizationService instanceof AuthorizationService) {
			throw new \Exception(
				'No AuthorizationService instance provided.'
			);
		}

		if (! $this->authorizationService->getIdentity()){
			return;
		}
		
		$userRow = $this->usersTable->fetchAccountById((int) $this->authorizationService->getIdentity()->getUserId());

		if (! $userRow) {
			// do redirect to logout
		} else {
			return $userRow;
		}
...

In a controller plugin, you have access to the controller…

if (! $userRow) {
    return $this->getController()->redirect()->toRoute('logout');
    // or
    return $this->getController()->plugin('redirect')->toRoute('logout');
} else {
    return $userRow;
}

Normally the identity comes from the authentication service, not authorization – these are two different things. See the related controller plugin: laminas-mvc-plugin-identity - Laminas Docs

I would suggest to use the standard authentication service from laminas-authentication and the standard identity controller plugin.
The check if the session data or user data is invalid can be done listener which listen on a MVC event. The listener can be executed automatically and always. Maybe you already have an ACL guard or something similar which does this job.

I use LmcRbacMvc\Service\AuthorizationService and I think everything is working ok.

I only have a problem with a user who was deleted during his session, and in some controllers I use this plugin to retrieve his data from the database, and he doesn’t exist anymore (he was deleted when he logged in, or in the session he still has his data, but it’s really not in the database anymore).

The check if the session data or user data is invalid can be done listener which listen on a MVC event. The listener can be executed automatically and always.

This is my solution:

public function onBootstrap($e)
    {
        $eventManager = $e->getApplication()->getEventManager();
        $eventManager->attach(MvcEvent::EVENT_DISPATCH, [$this, 'checkUser']);
    }

    public function checkUser(MvcEvent $e)
    {
        $serviceManager = $e->getApplication()->getServiceManager();
        $usersTable = $serviceManager->get(UsersTable::class);

        $authorizationService = $serviceManager->get(AuthorizationService::class);
        if ($authorizationService->getIdentity()) {
            $userRow = $usersTable->fetchAccountById((int) $authorizationService->getIdentity()->getUserId());
            
            if (! $userRow) {
                $response = $e->getResponse();
                $response->getHeaders()->addHeaderLine('Location', '/logout');
                $response->setStatusCode(302);
                $response->sendHeaders();
                return $response;   
            } else {
                return $userRow;
            }
        }
        return;
    }

Now it becomes clear.

Also there it is an authentication service:

But the identity provider is injected in role service and authorization service. Therefore my confusion.


Please have a look at the laminas-session validators, maybe this is a better solution to check if the session data is still valid. You can write a custom validator.