Encodera

Thanks for reading!

Donate to the site — we work hard for you.

Contents

Sessions and flash messages

The application handles every request from a clean slate and does not remember earlier ones. A session is server-side storage tied to one visitor: it holds data that must survive a move to another page. Slim has no sessions — ordinary PHP sessions are used, and a middleware starts them.

The session middleware

// src/Middleware/SessionMiddleware.php
namespace App\Middleware;
 
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;
 
final class SessionMiddleware implements MiddlewareInterface
{
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        if (session_status() !== PHP_SESSION_ACTIVE) {
            session_start([
                'cookie_httponly' => true,
                'cookie_samesite' => 'Lax',
            ]);
        }
 
        return $handler->handle($request);
    }
}

session_start() starts the session before the request reaches the action. The two options protect the session cookie: JavaScript cannot read it, and it is not sent with requests from other sites.

Attach the middleware in config/middleware.php above the three built-in ones:

// config/middleware.php
$app->add(SessionMiddleware::class);

Reading and writing

Once started, session data lives in the $_SESSION array. Try it on a temporary route:

// config/routes.php
$app->get('/visits', function (Request $request, Response $response) {
    $_SESSION['visits'] = ($_SESSION['visits'] ?? 0) + 1;
 
    $response->getBody()->write('Times you opened this page: ' . $_SESSION['visits']);
 
    return $response;
});

Reload /visits a few times — the number grows. In another browser the count starts over: it has its own session.

A flash message

After a form is saved the browser is redirected, and the "Post saved" message has to be shown on the next page. Such a message is called a flash message: it is put into the session and removed on first read. Write a small class for it:

// src/Support/Flash.php
namespace App\Support;
 
final class Flash
{
    public function add(string $message): void
    {
        $_SESSION['flash'][] = $message;
    }
 
    public function pull(): array
    {
        $messages = $_SESSION['flash'] ?? [];
        unset($_SESSION['flash']);
 
        return $messages;
    }
}

Using it

In CreatePostAction add private Flash $flash to the constructor and a call before the redirect:

// src/Action/CreatePostAction.php
$this->posts->create(trim($data['title']), trim($data['body']));
 
$this->flash->add('Post saved');

In ListPostsAction add Flash to the constructor too and pass the messages to the template:

// src/Action/ListPostsAction.php
return $this->twig->render($response, 'posts/index.twig', [
    'posts' => $this->posts->all(),
    'messages' => $this->flash->pull(),
]);
{# templates/posts/index.twig #}
{% for message in messages %}
    <p class="notice">{{ message }}</p>
{% endfor %}

Create a post through the form — "Post saved" appears above the list. Reload the page and the message is gone.

A ready-made package built on the same idea is slim/flash.

Common mistake

If code that runs before the session middleware touches $_SESSION, PHP reports an undefined variable and the data is not saved. The session middleware must wrap every layer that needs the session, which means it is added in config/middleware.php below them — but above the error middleware.

Thanks for reading!

Donate to the site — we work hard for you.