Cookbook

How Can I Implement Flash Messages?

Flash messages are used to display one-time messages to a user. A typical use case is for setting and later displaying a successful submission via a Post/Redirect/Get (PRG) workflow, where the flash message would be set during the POST request, but displayed during the GET request. (PRG is used to prevent double-submission of forms.) As such, flash messages usually are session-based; the message is set in one request, and accessed and cleared in another.

Mezzio does not provide native session facilities out-of-the-box, which means you will need:

  • Session functionality.
  • Flash message functionality, for handling message expiry from the session after first access.

A number of flash message libraries already exist that can be integrated via middleware, and these typically either use PHP's ext/session functionality or have a dependency on a session library. Two such libraries are:

  • mezzio/mezzio-flash
  • slim/flash

mezzio/mezzio-flash

mezzio-flash is a new offering from Laminas. Using it requires a session persistence engine as well, and Laminas provides that as well. Install the component using the following:

$ composer require mezzio/mezzio-flash mezzio/mezzio-session-ext

Once installed, you will need to pipe the middleware, along with the mezzio-session middleware, in your pipeline. This can be done at the application level:

$app->pipe(\Mezzio\Session\SessionMiddleware::class);
$app->pipe(\Mezzio\Flash\FlashMessageMiddleware::class);

or within a routed middleware pipeline:

$app->post('/user/login', [
    \Mezzio\Session\SessionMiddleware::class,
    \Mezzio\Flash\FlashMessageMiddleware::class,
    LoginHandler::class,
]);

Once this is in place, the flash message container will be registered as a request attribute, which you can then pull and manipulate:

$flashMessages = $request->getAttribute(FlashMessageMiddleware::FLASH_ATTRIBUTE);
// or $flashMessages = $request->getAttribute('flash');

// Create a flash message for the next request:
$flashMessages->flash($messageName, $messageValue);

// Or retrieve them:
$message = $flashMessages->getFlash($messageName);

The component has functionality for specifying the number of hops the message will be valid for, as well as accessing messages created in the current request; read more in the documentation.

slim/flash

Slim's Flash messages service provider can be used in Mezzio. It uses PHP's native session support.

First, you'll need to add it to your application:

$ composer require slim/flash

Second, create middleware that will add the flash message provider to the request:

<?php

namespace App;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
use Slim\Flash\Messages;

class SlimFlashMiddleware implements MiddlewareInterface
{
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface
    {
        // Start the session whenever we use this!
        session_start();

        return $handler->handle(
            $request->withAttribute('flash', new Messages())
        );
    }
}

Third, we will register the new middleware with our container as an invokable. Edit either the file config/autoload/dependencies.global.php or config/autoload/middleware-pipeline.global.php to add the following:

return [
    'dependencies' => [
        'invokables' => [
            App\SlimFlashMiddleware::class => App\SlimFlashMiddleware::class,
            /* ... */
        ],
        /* ... */
    ],
];

Finally, let's register it with our middleware pipeline. For programmatic pipelines, pipe the middleware somewhere, generally before the routing middleware:

$app->pipe(App\SlimFlashMiddleware::class);

Or as part of a routed middleware pipeline:

$app->post('/form/handler', [
    App\SlimFlashMiddleware::class,
    FormHandlerMiddleware::class,
]);

If using configuration-driven pipelines, edit config/autoload/middleware-pipeline.global.php to make the following additions:

return [
    'middleware_pipeline' => [
        'always' => [
            'middleware' => [
                'App\SlimFlashMiddleware',
                /* ... */
            ],
            'priority' => 10000,
        ],
        /* ... */
    ],
];

Where to register the flash middleware

Sessions can sometimes be expensive. As such, you may not want the flash middleware enabled for every request. If this is the case, add the flash middleware as part of a route-specific pipeline instead, as demonstrated in the programmatic pipelines above.

From here, you can add and read messages by accessing the request's flash attribute. As an example, middleware generating messages might read as follows:

use Psr\Http\Server\RequestHandlerInterface;
use Laminas\Diactoros\Response\RedirectResponse;

function($request, RequestHandlerInterface $handler)
{
    $flash = $request->getAttribute('flash');
    $flash->addMessage('message', 'Hello World!');

    return new RedirectResponse('/other-middleware');
}

And middleware consuming the message might read:

use Psr\Http\Server\RequestHandlerInterface;

function($request, RequestHandlerInterface $handler)
{
    $flash = $request->getAttribute('flash');
    $messages = $flash->getMessages();
    // ...
}

From there, it's a matter of providing the flash messages to your template.