# Настройка маршрутов
За маршрутизацию отвечает пакет HttpSoft\Router, а экземпляр приложения проксирует методы сборщика маршрутов.
По умолчанию настройка маршрутов производится в файле config/routes.php. Предоставляется несколько методов добавления маршрутов для наиболее популярных HTTP-методов. Каждый из этих методов создает, добавляет в коллекцию и возвращает экземпляр HttpSoft\Router\Route.
/**
* @var HttpSoft\Basis\Application $app
* @var Psr\Container\ContainerInterface $container
* @var mixed $handler
*/
$app = $container->get(HttpSoft\Basis\Application::class);
// Только для метода "GET":
$app->get('post.view', '/posts/{id}', $handler)->tokens(['id' => '\d+']);
// Только для метода "POST":
$app->post('post.create', '/posts', $handler);
// Только для метода "PUT":
$app->post('post.update', '/posts/{id}', $handler)->tokens(['id' => '\d+']);
// Только для метода "PATCH":
$app->patch('post.change', '/posts/{id}', $handler)->tokens(['id' => '\d+']);
// Только для метода "DELETE":
$app->delete('post.delete', '/posts/{id}', $handler)->tokens(['id' => '\d+']);
// Только для метода "HEAD":
$app->delete('post.headers', '/posts', $handler);
// Только для метода "OPTIONS":
$app->options('post.options', '/posts', $handler);
// Для любых методов:
$app->any('posts', '/posts{[id]}', $handler)->tokens(['id' => '\d+']);
// Для пользовательских методов:
$app->add('posts.edit', '/posts/(create|update)/{id}', $handler, ['GET', 'POST'])
->tokens(['id' => '\d+'])
;
# Группы маршрутов
Можно указать маршруты внутри группы. Все маршруты, определенные внутри группы, будут иметь общий префикс пути.
use HttpSoft\Router\RouteCollector;
$app->group('/posts', static function (RouteCollector $router) use ($handler): void {
$router->get('post.view', '/{slug}', $handler)->tokens(['slug' => '[\w-]+']);
$router->get('post.list', '{[page]}', $handler)->tokens(['page' => '\d+']);
});
Результат будет эквивалентен:
$app->get('post.view', '/posts/{slug}', $handler)->tokens(['slug' => '[\w-]+']);
$app->get('post.list', '/posts{[page]}', $handler)->tokens(['page' => '\d+']);
# Плейсхолдеры и токены
При добавлении параметра-плейсхолдера {token}
в путь по умолчанию будет использоваться регулярное выражение [^/]+
, которое соответствует любым символам, кроме слэша, указывающего на следующий сегмент пути. Чтобы указать пользовательские регулярные выражения для плейсхолдеров, используйте метод HttpSoft\Router\Route::tokens()
.
$app->delete('post.delete', '/posts/{id}', $handler)->tokens(['id' => '\d+']);
$app->get('post.view', '/posts/{slug}{format}', $handler)
->tokens(['slug' => '[\w\-]+', 'format' => '\.[a-zA-z]{3,}'])
;
Вы можете установить для токена значение по умолчанию, используя метод HttpSoft\Router\Route::defaults()
.
$app->get('post.view', '/posts/{slug}{format}', $handler)
->tokens(['slug' => '[\w\-]+', 'format' => '\.[a-zA-z]{3,}'])
->defaults(['format' => '.html'])
;
Плейсхолдеры, заключенные в [...]
, считаются необязательными.
$app->get('post.list', '/posts{[page]}', $handler)
->tokens(['page' => '\d+'])
;
// `{[year/month/day]}` эквивалентно `{[/year/month/day]}`
$app->get('post.archive', '/posts/archive{[year/month/day]}', $handler)
->tokens(['year' => '\d{4}', 'month' => '\d{2}', 'day' => '\d{2}'])
;
Необязательные параметры ДОЛЖНЫ находиться только в самом конце маршрута и перед ними НЕ ДОЛЖНО быть ведущего слэша.
Читайте подробнее о добавлении маршрутов, установке хоста для каждого маршрута, токенах и т.д.
# Сопоставление маршрутов
Процесс сопоставления маршрутов происходит в два этапа при помощи посредников (смотрите описание).
- HttpSoft\Router\Middleware\RouteMatchMiddleware — сопоставляет входящий запрос с добавленными маршрутами. При совпадении регистрирует экземпляр HttpSoft\Router\Route как атрибут запроса, используя имя класса
HttpSoft\Router\Route
в качестве имени атрибута, и передает запрос следующему посреднику. - HttpSoft\Router\Middleware\RouteDispatchMiddleware — проверяет наличие совпадающего маршрута (экземпляра HttpSoft\Router\Route) в качестве атрибута в запросе. Если он существует, то используется обработчик этого маршрута, иначе обработка запроса делегируется обработчику, который передается аргументом в метод
process()
.
Посредники регистрируются в конвейере config/pipeline.php. Между этими двумя посредниками может быть расположено любое количество других посредников. При этом HttpSoft\Router\Middleware\RouteDispatchMiddleware
ДОЛЖЕН находиться в конце конвейера.
Читайте подробнее о конвейере посредников.
# Обработка маршрутов
Для примера добавим два простых маршрута.
$app->get('home', '/', HomeAction::class);
$app->get('data', '/data', DataAction::class);
В качестве обработчиков используются вымышленные имена классов (HomeAction
, DataAction
и т.д.). Такой подход позволяет организовывать обработку каждого маршрута в отдельном классе. Эти классы реализуют Psr\Http\Server\RequestHandlerInterface.
use HttpSoft\Response\JsonResponse;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
final class HomeAction implements RequestHandlerInterface
{
public function handle(ServerRequestInterface $request): ResponseInterface
{
return new JsonResponse(['name' => 'HomeAction']);
}
}
Объекты обработчиков будут созданы через контейнер, поэтому они могут принимать зависимости в конструкторе.
use HttpSoft\Basis\Response\PrepareJsonDataTrait;
use HttpSoft\Response\JsonResponse;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
final class DataAction implements RequestHandlerInterface
{
use PrepareJsonDataTrait;
private Repository $repository;
public function __construct(Repository $repository)
{
$this->repository = $repository;
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
return new JsonResponse($this->prepareJsonData($this->repository->getAll()));
}
}
После запуска приложения и сопоставления маршрута с запросом отработает обработчик совпавшего маршрута и вернет экземпляр ответа для отправки клиенту.
Также обработчиком может быть:
- Строка (имя класса или идентификатор определения контейнера) или экземпляр, реализующий Psr\Http\Server\MiddlewareInterface или Psr\Http\Server\RequestHandlerInterface.
- Любой вариант типа
callable
без аргументов, возвращающий экземпляр Psr\Http\Message\ResponseInterface. - Любой вариант типа
callable
, соответствующий сигнатуре Psr\Http\Server\MiddlewareInterface::process(). - Массив ранее перечисленных обработчиков.
Подробнее об обработчиках смотрите в HttpSoft\Runner\MiddlewareResolver.
# Генерация URI
Чаще всего генерация URI используется в экшенах или шаблонах представлений. Чтобы получить доступ к маршрутам, нужно принять экземпляр сборщика маршрутов в конструкторе экшена.
use HttpSoft\Response\RedirectResponse;
use HttpSoft\Router\RouteCollector;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\RequestHandlerInterface;
final class PageAction implements RequestHandlerInterface
{
private RouteCollector $router;
public function __construct(RouteCollector $router)
{
$this->router = $router;
}
public function handle(ServerRequestInterface $request): ResponseInterface
{
return new RedirectResponse($this->router->routes()->path('home'));
}
}
Для генерации путей используйте метод HttpSoft\Router\RouteCollection::path()
.
/**
* @var HttpSoft\Router\RouteCollector $router
* @var mixed $handler
*/
$router->get('home', '/', $handler);
$router->routes()->path('home'); // '/'
$router->get('page', '/{slug}', $handler)->tokens(['slug' => '[\w\-]+']);
$router->routes()->path('page', ['slug' => 'page-slug']); // '/page-slug'
Для генерации URL используйте метод HttpSoft\Router\RouteCollection::url()
.
/**
* @var HttpSoft\Router\RouteCollector $router
* @var mixed $handler
*/
$router->get('home', '/', $handler)->host('(shop|blog).example.com');
$router->routes()->url('home', []); // '/'
$router->routes()->url('home', [], 'blog.example.com'); // '//blog.example.com'
$router->routes()->url('home', [], 'blog.example.com', true); // 'https://blog.example.com'
$router->routes()->url('home', [], 'blog.example.com', false); // 'http://blog.example.com'
$router->get('page', '/{slug}', $handler)->tokens(['slug' => '[\w\-]+']);
$router->routes()->url('page', ['slug' => 'page-slug']); // '/page-slug'
$router->routes()->url('page', ['slug' => 'page-slug'], 'any-host.com'); // '//any-host.com/page-slug'
Подробнее о генерации URI смотрите в HttpSoft\Router\RouteCollection.