Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Сессии и разовые сообщения

Каждый запрос приложение обрабатывает с чистого листа и не помнит предыдущих. Сессия — хранилище на сервере, привязанное к одному посетителю: в неё кладут данные, которые должны пережить переход на другую страницу. В 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 ниже них — но выше посредника ошибок.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.