Следует стандартам PSR-7, PSR-15, а также PSR-1, PSR-2, PSR-4, PSR-11, PSR-16.
Использует FastRoute, вдохновлено league/route.
Основные идеи:
- возможность работать, следуя стандартам PSR-7/PSR-15, либо используя подход FastRoute
- reversed routing (генерация URL по имени роута)
- практически нативный FastRoute с возможностью использования различных стратегий обработки (CharCountBased, GroupCountBased...)
- быстрый множественный dispatch и reverse (при сохранении возможности динамического добавления роутов)
- возможность подключить свой загрузчик роутов из любых форматов
- возможность подключить кэш (PSR-16)
- возможность гибко настраивать любой из компонентов роутера (заменять обработку handler, middleware)
- Использование без PSR-7/15 совместимости
- Использование с PSR-7/15
- URL reverse - генерация URL
- Поддерживаемые виды обработчиков
- Поддерживаемые виды Middleware
- Invoker
- Container
- Loader
- Cache
- Изменение стратегий обработки FastRoute
Практически так же, как и FastRoute, но с возможностью reversed routing.
Максимально простое
$router = new Router();
Смотрите остальные разделы документации, если вам необходимо:
- применять кэш
- использовать Loader
- поменять стратегию FastRoute,
- поменять логику reverse
// Добавление роута
$router->addRoute('GET', '/test', function () {
// Это обработчик роута
}, 'test');
// Добавление роута с именем
$router->addRoute('GET', '/test/{name:[a-z]+}', function () {
// Это обработчик роута с именем
}, 'test_with_name');
// Добавление группы роутов
$router->addGroup('GET', '/api', function (Router $router) {
$router->addRoute('GET', '/users', function () {
// Тут обработчик роута с пользователями api
}, 'users');
}, 'api:');
$reversedRoute = $router->reverse('test_with_name', [
'name' => 'somename'
]);
Аналогично FastRoute, смотрите здесь: Basic usage FastRoute
$data = $router->dispatch('GET','/test');
Router имплементирует MiddlewareInterface, поэтому легко встраивается в любые Pipelines
Максимально простое
$router = new Router();
Смотрите остальные разделы документации, если вам необходимо:
- применять кэш
- использовать Loader
- поменять стратегию FastRoute,
- поменять логику reverse
- изменить стратегию Invoker
Простое добавление роутов. Виды возможных обработчиков ограничены. Поддерживаемые виды обработчиков.
$router->map('GET', '/test/{name:[a-z]+}', function () {
// Обработчик роута с именем
}, 'test_with_name');
Конечно же, можно использовать и Middleware. Поддерживаемые виды Middleware.
$router->map('POST', '/admin', function () {
// Обработчик
}, 'admin', [
AuthMiddleware::class,
CSRFValidationMiddleware::class
]);
Также поддерживаются группы, для которых можно указать Middleware.
$router->group('GET', '/api', function (Router $router) {
$router->map('GET', '/users', [UsersHandlerController::class, 'all'], 'users', [
UsersGuardMiddleware::class
]);
}, 'api:', [
ApiAuthMiddleware::class
]);
Можно указать список Middleware, которые будут применены ко всем роутам.
$router->setMiddlewares([
MyCustomMiddleware::class
]);
Так как роутер сам по себе является Middleware, то для обработки роута необходимо вызвать метод process
.
Для удобства вызова без какого-либо Pipeline предусмотрен обработчик по умолчанию \Phact\Router\NotFoundHandler
,
который выбрасывает \Phact\Router\Exception\NotFoundException
, если роут не найден.
Если роут есть, но запрашиваемый метод для него недоступен, то будет выброшено исключение
\Phact\Router\Exception\MethodNotAllowedException
.
$response = $router->process($request, new NotFoundHandler());
Если мы добавляем роут с именем, то после можно построить URL по этому имени с переданными параметрами. Например, добавим роут:
// Добавление роута с именем
$router->addRoute('GET', '/test/{name:[a-z]+}', 'someHandler', 'test_with_name');
Затем можно сгенерировать URL следующим образом:
$url = $router->reverse('test_with_name', [
'name' => 'harry'
]);
В ответе мы получим /test/harry
Передаваемые параметры могут быть простым (не ассоциативным) массивом. В этом случае подстановка параметров будет произведена по порядку. Например, добавим вот такой роут:
$router->addRoute('GET', '/test/{name:[a-z]+}/{id:[0-9]+}', 'someHandler', 'test_double');
И для генерации URL передадим не ассоциативный массив:
$url = $router->reverse('test_with_name', [
'harry',
12
]);
В ответе мы получим /test/harry/12
.
По умолчанию неиспользованные параметры будут переданы в параметры запроса.
Для примера определим роут:
$router->addRoute('GET', '/test/{name:[a-z]+}', 'someHandler', 'test_with_name');
И сгенерируем URL вот так:
$router->reverse('test_with_name', [
'name' => 'harry',
'faculty' => 'gryffindor'
]);
В ответе мы получим /test/harry?faculty=gryffindor
Вместо метода $router->reverse(...)
можно применять метод $router->url(...)
, так как они являются равнозначными.
Если вам необходимо определить своё поведение для метода reverse, то вам необходимо:
- Реализовать
\Phact\Router\ReverserFactory
, которая будет создавать\Phact\Router\Reverser
. - Реализовать
\Phact\Router\Reverser
. - Передать вашу
ReverserFactory
в конструктор Router. Например, так:
$router = new Router(null, null, new MyAmazingReverserFactory());
Актуально, только если вы используете PSR-7–совместимый метод работы. Если вы используете роутер простейшим способом, то обработчик может быть любым.
Любой из представленных ниже обработчиков должен возвращать объект \Psr\Http\Message\ResponseInterface
Пример:
$router->addRoute('GET', '/test', '\App\Handlers\MyHandler::myMethod', 'test');
Если установлен Container, то объект будет запрошен у Container. Если Container не установлен, то объект будет создан.
Пример:
$router->addRoute('GET', '/test', MyInvokableHandler::class, 'test');
Если установлен Container, то объект будет запрошен у Container. Если Container не установлен, то объект будет создан.
Пример:
$router->addRoute('GET', '/test', [MyHandler::class, 'myMethod'], 'test');
Если установлен Container, то объект будет запрошен у Container. Если Container не установлен, то объект будет создан.
Пример:
$router->addRoute('GET', '/test', [new MyHandler(), 'myMethod'], 'test');
Пример:
$router->addRoute('GET', '/test', new MyInvokableHandler(), 'test');
Пример:
$router->addRoute('GET', '/test', function(ServerRequestInterface $request, array $variables) : ResponseInterface {
// Обработка
}, 'test');
Чтобы изменить логику вызова обработчиков, просто примените свою реализацию Invoker
Пример:
$router->map('POST', '/admin', new MyInvokableHandler(), 'admin', [
ExampleMiddleware::class
]);
Если установлен Container, то объект будет запрошен у Container. Если Container не установлен, то объект будет создан.
Пример:
$router->map('POST', '/admin', new MyInvokableHandler(), 'admin', [
new ExampleMiddleware()
]);
Актуально только при использовании с Container.
Пример:
$router->map('POST', '/admin', new MyInvokableHandler(), 'admin', [
'my_some_custom_middleware_from_container'
]);
Invoker, который реализует функциональность вызова обработчиков и Middleware, является заменяемой частью роутера.
Вы можете просто заменить Invoker, реализовав интерфейс \Phact\Router\Invoker
и установив его следующим образом:
$router->setInvoker(new MyCustomInvoker());
Если вы хотите работать с вашим контейнером и он соответствует Psr\Container\ContainerInterface
,
то примените его к Router следующим образом:
$router->setContainer($myContainer);
Обратите внимание! Router передает Container в стандартную реализацию Invoker. Если вы сами реализуете Invoker, учитывайте это.
По умолчанию Router не использует никакой Loader.
Вы можете реализовать свой класс для загрузки роутов из вашего хранилища (файла, базы данных ...).
Для этого:
- опишите свой Loader, имплементируя интерфейс
\Phact\Router\Loader
- установите ваш Loader в Router следующим образом:
$router->setLoader($myCustomLoader);
Метод load
будет вызван в момент первого dispatch
или reverse
.
Метод load
может быть не вызван в случае использования Cache.
По умолчанию Router не использует никакой Cache
Вы можете использовать свою реализацию \Psr\SimpleCache\CacheInterface
(PSR-16) следующим образом:
$router->setCache($myCache);
В кэш роуты попадают в момент первого получения данных, а также после добавления роута.
Получение роутов из кэша происходит при первом dispatch
или reverse
и позволяет избежать ресурсоёмкого вызова Loader.
Есть возможность заменить любые части Router:
- DataGenerator и Dispatcher (через DispatcherFactory)
- ReverserDataGenerator и Reverser (через ReverserFactory)
- RouteParser
По умолчанию Router использует стратегию обработки GroupCountBased. Любую другую стратегию можно реализовать по аналогии со стратегий по умолчанию.
$route = new Router(
new Collector(
new MyCustomRouteParser(),
new MyCustomDataGenerator(),
new MyCustomReverserDataGenerator()
),
new MyCustomDispatcherFactory(),
new MyCustomReverserFactory()
);