For the complete documentation index, see llms.txt. This page is also available as Markdown.

Маршрутизация (роутинг)

В JohnCMS маршрутизация построена на Johncms\Router\RouteCollection и Symfony Routing.

Эта страница описывает текущий подход: как объявлять маршруты, как подключать middleware, какие бывают обработчики и как происходит dispatch.

Где описываются маршруты

Маршруты загружаются в следующем порядке:

  1. config/routes.php — глобальные/системные маршруты (зарезервирован для ядра)

  2. 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() страница отрисуется, но всё меню вокруг неё останется на английском.

Конвенция завершающего слэша. Маршруты принято регистрировать без завершающего слэша (/partners), а в ссылках (в шаблонах и контроллерах) — использовать слэш (/partners/). Перед сопоставлением путь запроса нормализуется (Johncms\Http\RequestPathNormalizer): декодируется и лишается завершающего слэша, поэтому оба варианта работают.

Именованные маршруты

Маршруту можно задать имя с помощью метода 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\MiddlewareInterface

  • callable

Контракт middleware для класса:

Пример класса middleware:

Пример callable middleware:

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

При обработке совпавшего маршрута выполняется цепочка:

  1. middleware коллекции/группы

  2. middleware самого маршрута

  3. handler маршрута

Если middleware не вызывает $next($request), цепочка останавливается и handler не будет вызван.

Кэш маршрутов

Коллекция маршрутов не зависит от посетителя, поэтому её можно собрать один раз. В config/constants.php:

При включённом кэше маршруты один раз выгружаются в data/cache/routes.php (обычный массив, который попадает в opcache), и файлы config/routes.php больше не читаются на каждый запрос. После изменения маршрутов файл нужно удалить — или выполнить php system/bin/console cache:clear.

Обработчик и middleware маршрута при этом должны быть данными: строкой с именем класса или массивом [Класс::class, 'метод']. Замыкание выгрузить нельзя — такой маршрут ломает кэш, о чём в лог попадёт предупреждение, а сайт продолжит работать без кэша.

Какие обработчики поддерживаются

В маршруте можно указать:

  1. Invokable-контроллер (SomeController::class с методом __invoke())

  2. Массив [ControllerClass::class, 'method']

В обоих случаях контроллер берётся из контейнера — значит, он должен быть объявлен в config/services.php модуля. Вызовом занимаются ActionInvoker и MiddlewareDispatcher внутри Johncms\Http\Kernel.

Как работает dispatch

Запрос обрабатывает Johncms\Http\Kernel; public/index.php только собирает запрос и передаёт его ядру.

  1. SymfonyRouteMatcher::dispatch() нормализует путь и пытается сопоставить маршрут

  2. При FOUND:

    • route params кладутся в request

    • подключаются переводы модуля, которому принадлежит маршрут

    • запускается цепочка middleware

    • вызывается handler

  3. При METHOD_NOT_ALLOWED возвращается 405 Method Not Allowed

  4. При 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.

См. также

Последнее обновление

Это было полезно?