Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Controller plugins

A controller plugin is a small class with code needed in many actions. The familiar params(), redirect(), layout() and flashMessenger() are exactly such plugins. A plugin of your own saves you from copying the same lines from controller to controller.

Built-in plugins

Call in an actionWhat it does
$this->params()Reads request parameters
$this->redirect()Redirects
$this->url()->fromRoute('blog')Builds an address from a route name
$this->layout()Controls the layout
$this->forward()->dispatch(...)Calls an action of another controller

Your own plugin

The page number from the address is needed in every list, and each time it must be turned into a number not less than one. Let us move that into a plugin. Create the folder module/Blog/src/Controller/Plugin and a file in it:

// module/Blog/src/Controller/Plugin/PageNumber.php
namespace Blog\Controller\Plugin;
 
use Laminas\Mvc\Controller\Plugin\AbstractPlugin;
 
class PageNumber extends AbstractPlugin
{
    public function __invoke(): int
    {
        $page = (int) $this->getController()->params()->fromQuery('page', 1);
 
        return max(1, $page);
    }
}

The class extends AbstractPlugin. The __invoke() method runs when the plugin is called, and getController() returns the controller it was called from.

Registration

Plugins are described in the controller_plugins section of module/Blog/config/module.config.php:

// module/Blog/config/module.config.php
'controller_plugins' => [
    'factories' => [
        Controller\Plugin\PageNumber::class => InvokableFactory::class,
    ],
    'aliases' => [
        'pageNumber' => Controller\Plugin\PageNumber::class,
    ],
],

factories says how to create the class, and aliases sets the short name under which the plugin is called in actions.

Calling it in an action

// module/Blog/src/Controller/PostController.php
public function indexAction()
{
    $page = $this->pageNumber();
 
    return new ViewModel(['page' => $page]);
}

For /blog?page=3 the $page variable holds 3; for /blog?page=-5 and /blog?page=abc it holds 1. The plugin is available in every controller of the application, not only in the Blog module.

A plugin with dependencies

A plugin can receive services through its constructor. For example, this plugin returns the logged-in user:

// module/Blog/src/Controller/Plugin/CurrentUser.php
namespace Blog\Controller\Plugin;
 
use Laminas\Authentication\AuthenticationService;
use Laminas\Mvc\Controller\Plugin\AbstractPlugin;
 
class CurrentUser extends AbstractPlugin
{
    public function __construct(private AuthenticationService $auth) {}
 
    public function __invoke(): ?array
    {
        return $this->auth->hasIdentity() ? $this->auth->getIdentity() : null;
    }
}

In the configuration use ReflectionBasedAbstractFactory::class instead of InvokableFactory and add the alias currentUser. In an action $this->currentUser() returns an array with id and email, or null for a guest.

Common mistake

If you register a plugin in factories but forget the line in aliases, calling $this->pageNumber() ends with an exception saying a plugin with that name was not found. The short name is not derived from the class name — it is always set by an alias.

Thanks for reading!

Donate to the site — we work hard for you.