Классы-действия
Пока обработчики — функции внутри config/routes.php, файл растёт с каждым маршрутом. Обработчик выносят в отдельный класс — действие (action). Один класс отвечает за один маршрут, а в файле маршрутов остаётся одна строка.
Где лежат действия
Действия кладут в папку src/Action/. Команды для создания в Slim нет: создайте папку и файл вручную.
Первое действие
// src/Action/HomeAction.php
namespace App\Action;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
final class HomeAction
{
public function __invoke(Request $request, Response $response): Response
{
$response->getBody()->write('Главная страница блога');
return $response;
}
}__invoke — особый метод PHP: объект с таким методом можно вызвать как функцию. Аргументы те же, что у функции-обработчика.
Подключение в маршруте
В config/routes.php вместо функции указывают имя класса:
// config/routes.php
use App\Action\HomeAction;
use Slim\App;
return function (App $app): void {
$app->get('/', HomeAction::class)->setName('home');
};Откройте http://localhost:8080 — страница та же, но код обработчика теперь в своём файле. Slim сам создаёт объект класса, когда приходит запрос.
Действие с параметром адреса
Параметры адреса приходят третьим аргументом, как и в функции:
// src/Action/ShowPostAction.php
namespace App\Action;
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
final class ShowPostAction
{
public function __invoke(Request $request, Response $response, array $args): Response
{
$response->getBody()->write('Статья №' . (int) $args['id']);
return $response;
}
}// config/routes.php
$app->get('/posts/{id:[0-9]+}', ShowPostAction::class)->setName('posts.show');Адрес /posts/5 выведет «Статья №5». Не забудьте добавить use App\Action\ShowPostAction; в начало файла маршрутов.
Как называть
Имя действия отвечает на вопрос «что делает маршрут»:
| Маршрут | Класс |
|---|---|
GET /posts | ListPostsAction |
GET /posts/{id} | ShowPostAction |
POST /posts | CreatePostAction |
Контроллер вместо действий
Если привычнее контроллер — один класс с несколькими методами, — маршрут записывают массивом из имени класса и имени метода:
// config/routes.php
$app->get('/posts', [PostController::class, 'index']);
$app->get('/posts/{id:[0-9]+}', [PostController::class, 'show']);Методы index и show принимают те же аргументы, что __invoke. В курсе используются действия: каждый класс короткий и получает только то, что нужно его маршруту.
Частая ошибка
Действие, которое само разбирает запрос, выполняет запросы к базе и собирает HTML, превращается в «толстый» класс. Оставляйте в действии три шага: достать данные из запроса, вызвать другой класс, который делает работу, и сформировать ответ. Как передавать такие классы в действие, показано в следующем уроке.