Encodera

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

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

Оглавление

Посредники

Посредник (middleware) — слой, через который запрос проходит по пути к обработчику, а ответ — по пути обратно. В посредники выносят то, что повторяется от маршрута к маршруту: проверку входа, запуск сессии, служебные заголовки. В Slim это главный способ расширять приложение.

Где лежат посредники

Классы посредников кладут в src/Middleware/, а подключают в отдельном файле config/middleware.php. Обе вещи создают вручную.

Первый посредник

// src/Middleware/ResponseTimeMiddleware.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 ResponseTimeMiddleware implements MiddlewareInterface
{
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        $start = microtime(true);
 
        $response = $handler->handle($request);
 
        $ms = round((microtime(true) - $start) * 1000, 1);
 
        return $response->withHeader('X-Response-Time', $ms . ' ms');
    }
}

Главная строка — $handler->handle($request): она передаёт запрос дальше, к следующему посреднику или к действию, и возвращает готовый ответ. Код до неё выполняется перед действием, код после — когда ответ уже сформирован. Интерфейс MiddlewareInterface — часть стандарта PSR-15, поэтому в Slim работают и готовые посредники из сторонних пакетов.

Подключение

Создайте config/middleware.php:

// config/middleware.php
use App\Middleware\ResponseTimeMiddleware;
use Slim\App;
 
return function (App $app): void {
    $app->add(ResponseTimeMiddleware::class);
};

И подключите его в config/bootstrap.php перед маршрутами:

// config/bootstrap.php
(require __DIR__ . '/middleware.php')($app);
(require __DIR__ . '/routes.php')($app);

Откройте любую страницу и посмотрите заголовки ответа на вкладке «Сеть» инструментов разработчика — среди них появится X-Response-Time.

Группа и отдельный маршрут

Посредник, добавленный через $app->add(), работает для всех запросов. Его можно привязать и уже:

// config/routes.php
$app->get('/posts', ListPostsAction::class)
    ->add(ResponseTimeMiddleware::class);       // один маршрут
 
$app->group('/admin', function (RouteCollectorProxy $group) {
    // маршруты раздела
})->add(ResponseTimeMiddleware::class);         // вся группа

Остановить запрос и передать данные

Посредник не обязан вызывать $handler->handle(): он может сам вернуть ответ, например перенаправление на страницу входа. Так устроена проверка доступа — она показана в уроке об аутентификации.

Чтобы передать действию данные, посредник добавляет к запросу атрибут:

return $handler->handle($request->withAttribute('started_at', $start));

Действие прочитает значение через $request->getAttribute('started_at').

Порядок выполнения

Посредники образуют слои, как у луковицы. Добавленный последним оказывается снаружи и выполняется первым:

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

Запрос пройдёт через SecondMiddleware, затем через FirstMiddleware, затем попадёт в действие; ответ вернётся в обратном порядке. Посредники маршрута и группы всегда выполняются после посредников приложения.

Частая ошибка

Метод withAttribute(), как и все методы с with, возвращает новый запрос. Если вызвать его и передать дальше старый $request, действие не увидит атрибута. Передавайте в $handler->handle() именно тот объект, который вернул withAttribute().

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

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