Маршрутизация (роутинг)
В JohnCMS маршрутизация построена на Johncms\Router\RouteCollection и Symfony Routing.
Эта страница описывает текущий подход: как объявлять маршруты, как подключать middleware, какие бывают обработчики и как происходит dispatch.
Где описываются маршруты
Маршруты загружаются в следующем порядке:
config/routes.php— глобальные/системные маршруты (зарезервирован для ядра)modules/{vendor}/{name}/config/routes.php— маршруты каждого модуля (подхватываются автоматически)
Каждый модуль регистрирует свои маршруты в config/routes.php внутри папки модуля. Файл подхватывается автоматически — вручную подключать его не нужно.
Базовый пример маршрута
Файл modules/{vendor}/{name}/config/routes.php должен возвращать callable:
<?php
declare(strict_types=1);
use Johncms\Router\RouteCollection;
use Mysite\Partners\Application\Controllers\PartnersController;
return static function (RouteCollection $router): void {
$router->get('/partners', PartnersController::class)->name('partners.index');
$router->map(['GET', 'POST'], '/feedback', FeedbackController::class)->name('feedback');
};Доступ к маршруту
Маршрут объявляется всегда, а ограничение доступа описывается рядом с ним.
Право на маршрут
permission() кладёт ключ права в атрибут маршрута; ядро само подключает RequirePermissionMiddleware, который его читает. Ответ посетителю без права — 403, гостю — редирект на /login. Если сам факт существования маршрута скрывать важнее, чем честно ответить, — ->permission('...', hidden: true), тогда вместо 403 будет 404.
Право должно быть объявлено провайдером модуля (класс, реализующий PermissionProviderInterface), иначе выдать его в редакторе ролей будет нечем.
То же самое можно задать сразу на группу — право получат все её маршруты, кроме тех, что назвали своё:
Маршрут только для авторизованных
Когда никакого права не нужно, а нужна только сессия:
Раздел панели администратора
Маршруты раздела в админке объявляются с ->adminArea() — на группе или на отдельном маршруте:
Это даёт странице переводы, на которых написаны макет панели и её меню, и первое звено цепочки навигации. Без adminArea() страница отрисуется, но всё меню вокруг неё останется на английском.
Именованные маршруты
Маршруту можно задать имя с помощью метода name(). Имя используется как внутренний идентификатор маршрута в системе.
Рекомендуется именовать маршруты по схеме модуль.действие (например guestbook.index, guestbook.edit, admin.contacts.save). Это соглашение используется во всех штатных модулях. name() можно комбинировать с другими методами (requirements(), addMiddleware() и т.д.) в цепочке вызовов.
Параметры и ограничения
Маршрут может содержать параметры и ограничения через requirements():
Также поддерживаются пресеты в пути:
{id:number}{article_code:slug}{category:path}
Примеры можно посмотреть в файлах modules/*/*/config/routes.php.
Middleware на маршрутах
Middleware — это промежуточный обработчик между совпавшим маршрутом и его handler. Он получает Request, может выполнить проверку/подготовку и передать управление дальше через $next($request).
Обычно middleware используют для:
проверки доступа (права, авторизация, владение ресурсом)
валидации обязательных условий перед действием
логирования и других сквозных задач
Middleware для конкретного маршрута
Добавление middleware к одному маршруту:
Можно указывать несколько middleware, они будут вызваны по порядку добавления.
Middleware для группы/коллекции маршрутов
Можно добавить middleware сразу на коллекцию (например, в группе):
Такой middleware будет применяться ко всем маршрутам внутри этой коллекции.
Допустимые типы middleware
Middleware может быть:
классом (получается из контейнера), реализующим
Johncms\Router\MiddlewareInterfacecallable
Контракт middleware для класса:
Пример класса middleware:
Пример callable middleware:
Порядок выполнения
При обработке совпавшего маршрута выполняется цепочка:
middleware коллекции/группы
middleware самого маршрута
handler маршрута
Если middleware не вызывает $next($request), цепочка останавливается и handler не будет вызван.
Кэш маршрутов
Коллекция маршрутов не зависит от посетителя, поэтому её можно собрать один раз. В config/constants.php:
При включённом кэше маршруты один раз выгружаются в data/cache/routes.php (обычный массив, который попадает в opcache), и файлы config/routes.php больше не читаются на каждый запрос. После изменения маршрутов файл нужно удалить — или выполнить php system/bin/console cache:clear.
Какие обработчики поддерживаются
В маршруте можно указать:
Invokable-контроллер (
SomeController::classс методом__invoke())Массив
[ControllerClass::class, 'method']
В обоих случаях контроллер берётся из контейнера — значит, он должен быть объявлен в config/services.php модуля. Вызовом занимаются ActionInvoker и MiddlewareDispatcher внутри Johncms\Http\Kernel.
Как работает dispatch
Запрос обрабатывает Johncms\Http\Kernel; public/index.php только собирает запрос и передаёт его ядру.
SymfonyRouteMatcher::dispatch()нормализует путь и пытается сопоставить маршрутПри
FOUND:route params кладутся в request
подключаются переводы модуля, которому принадлежит маршрут
запускается цепочка middleware
вызывается handler
При
METHOD_NOT_ALLOWEDвозвращается405 Method Not AllowedПри
NOT_FOUNDвызываетсяpageNotFound()
Типовые ошибки
404 Not Found
Причины:
путь не совпадает с шаблоном маршрута
route params не прошли
requirementsмаршрут не зарегистрирован в
modules/{vendor}/{name}/config/routes.php
405 Method Not Allowed
Причина:
URL найден, но HTTP-метод не разрешен для маршрута (например,
POSTвместоGET).
Ошибка middleware
Причины:
middleware-класс не зарегистрирован в контейнере (
config/services.phpмодуля)middleware не callable и не реализует
MiddlewareInterface
В этом случае MiddlewareDispatcher выбросит InvalidArgumentException.
См. также
Последнее обновление
Это было полезно?