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.