Сессии и разовые сообщения
Каждый запрос приложение обрабатывает с чистого листа и не помнит предыдущих. Сессия — хранилище на сервере, привязанное к одному посетителю: в неё кладут данные, которые должны пережить переход на другую страницу. В Slim сессий нет — используют обычные сессии PHP, а запускает их посредник.
Посредник сессии
// 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() запускает сессию до того, как запрос попадёт в действие. Две настройки защищают cookie сессии: её не прочитает JavaScript, и она не отправится с запросами с чужих сайтов.
Подключите посредник в config/middleware.php выше трёх встроенных:
// config/middleware.php
$app->add(SessionMiddleware::class);Чтение и запись
После запуска данные сессии лежат в массиве $_SESSION. Проверим на временном маршруте:
// config/routes.php
$app->get('/visits', function (Request $request, Response $response) {
$_SESSION['visits'] = ($_SESSION['visits'] ?? 0) + 1;
$response->getBody()->write('Вы открыли эту страницу раз: ' . $_SESSION['visits']);
return $response;
});Обновите /visits несколько раз — число растёт. В другом браузере счёт начнётся заново: у него своя сессия.
Разовое сообщение
После сохранения формы браузер перенаправляется, и сообщение «Статья сохранена» нужно показать уже на следующей странице. Такое сообщение называют разовым (flash): оно кладётся в сессию и удаляется при первом чтении. Напишите для него небольшой класс:
// 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;
}
}Использование
В CreatePostAction добавьте в конструктор private Flash $flash и вызов перед перенаправлением:
// src/Action/CreatePostAction.php
$this->posts->create(trim($data['title']), trim($data['body']));
$this->flash->add('Статья сохранена');В ListPostsAction тоже добавьте Flash в конструктор и передайте сообщения в шаблон:
// 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 %}Создайте статью через форму — над списком появится «Статья сохранена». Обновите страницу, и сообщение исчезнет.
Готовый пакет с той же идеей — slim/flash.
Частая ошибка
Если обратиться к $_SESSION в коде, который выполняется до посредника сессии, PHP сообщит, что переменная не определена, а данные не сохранятся. Посредник сессии должен охватывать все слои, которым нужна сессия, то есть быть добавлен в config/middleware.php ниже них — но выше посредника ошибок.