Маршрутизация (роутинг)
Для чего нужен роутер в JohnCMS?
Как и в других CMS и фреймворках роутер в JohnCMS обрабатывает запрошенный URL адрес и определяет какой модуль запустить для обработки этого запроса. В свою очередь модуль может получить от роутера различные параметры в зависимости от настроек маршрута и использовать для реализации своего функционала.
Перейдем к практической части.
Где хранятся настройки маршрутизации?
Все описания маршрутов хранятся в модулях по следующему пути: config/routes.php
Пример файла routes.php
<?php
declare(strict_types=1);
use Johncms\Contacts\Controllers\ContactseController;
use Johncms\Router\RouteCollection;
return function (RouteCollection $router) {
$router->get('/contacts/', [ContactseController::class, 'index'])->setName('contacts');
};
Давайте теперь рассмотрим детально как работать с роутером и как использовать его в своих модулях?
Возьмём простой пример из кода выше. Маршрут у нас в нем задается такой строкой:
$router->get('/contacts/', [ContactseController::class, 'index'])->setName('contacts');
Эта строка говорит роутеру следующее: Если запрос пришел методом GET и он поступил на страницу site.ru/contacts/, то необходимо вызвать метод index в контроллере Johncms\Contacts\Controllers\ContactseController Таким образом, когда пользователь переходит по адресу site.ru/contacts/ он видит те данные, которые вернул метод index.
Давайте рассмотрим более сложные примеры маршрутизации. Для этого давайте изменим наш простой модуль контактов, который мы создавали в предыдущей статье: Создание модуля
Откроем файл /config/routes.local.php
Изменим нашу строку маршрута следующим образом:
$router->get('/contacts/{action?}', [ContactseController::class, 'index'])->setName('contacts');
Мы добавили в неё дополнительный параметр {action?} Что это значит? Вопросительный знак сообщает роутеру, что этот параметр не обязателен (он может быть, а может отсутствовать). В фигурных скобках задается название параметра, чтобы модуль смог с ним работать. По умолчанию выбираться будет та часть адреса, которая расположена между /contacts/ и следующим слэшем.
Чтобы было понятнее, давайте разберем на примерах. 1. site.ru/contacts/ - В таком варианте у нас параметр action будет игнорироваться т.к. роутер считает его необязательным и откроет нашу страницу контактов. 2. site.ru/contacts/moscow - Такой вариант откроет нашу страницу контактов и в модуле будет доступен параметр action. В этом параметре будет содержаться слово "moscow". 3. site.ru/contacts/new_york - Тоже самое что и в варианте 3, только в параметре action будет "new_york" 4. site.ru/contacts/new_york/test1/ - Выдаст ошибку 404 т.к. роутер видит, что маршрут не подходит нам (содержит больше данных чем нужно для нашего маршрута).
Получение параметров маршрута в контроллере
Давайте теперь разберемся как в модуле нам получить параметры, которые мы указываем в роутере. Откроем файл контроллера Controllers/ContactsController.php В методе index вставим следующий код
<?php
declare(strict_types=1);
namespace Johncms\Contacts\Controllers;
class ContactsController
{
public function index(string $action = '')
{
// Получаем массив параметров, которые вернул нам роутер
$route = di('route');
// Выведем их на экран
dd($route);
}
}
Перейдем по адресу: site.ru/contacts/moscow/
В браузере у вас отобразится следующий текст:
Array
(
[action] => moscow
)
Как мы видим, параметр, который мы назвали в настройках маршрута action, появился у нас в массиве и содержит слово moscow.
В модуле мы можем обратиться к этому параметру и в зависимости от его содержимого управлять логикой работы модуля. Получить этот параметр можно, как вы наверное уже догадались, следующим образом: $route['action']
Также в методе контроллера можно указывать одноименные переменные и в таком случае в этих переменных будет содержаться то, что вы указали в параметрах марщрута.
В нашем случае в переменной $action будет содержаться слово moscow.
Прочие примеры использования
Указание регулярного выражения для сопоставления маршрута
$router->get('/contacts/{page<\d+>}', [ContactseController::class, 'index']);
В примере выше регулярное выражение ограничивает тип параметра page до числа. Если после строки /contacts/ будут буквы - маршрут не будет сопоставлен и отобразится 404 страница.
Установка метода запроса
Роутер позволяет задавать методы для которых будет доступен маршрут.
// GET
$router->get('/', ['class', 'method']);
// POST
$router->post('/', ['class', 'method']);
// DELETE
$router->delete('/', ['class', 'method']);
// HEAD
$router->head('/', ['class', 'method']);
// OPTIONS
$router->options('/', ['class', 'method']);
// PATCH
$router->patch('/', ['class', 'method']);
// PUT
$router->put('/', ['class', 'method']);
// Несколько методов сразу
$router->map(['GET', 'POST', 'DELETE'], '/', ['class', 'method']);
Шаблоны популярных выражений
Для упрощения ограничений типов параметров в JohnCMS существуют заготовленные регулярные выражения которые можно указать следующим образом:
// Число. /contacts/1234
$router->get('/contacts/{page:number}', [ContactseController::class, 'index']);
// Буквы, цифры и некоторые знаки. /contacts/my-page_1-2-3
$router->get('/contacts/{page:slug}', [ContactseController::class, 'index']);
// Буквы латинского алфафита. /contacts/word
$router->get('/contacts/{page:word}', [ContactseController::class, 'index']);
// Путь. /contacts/path/level2/level3/level4/any-level
$router->get('/contacts/{page:path}', [ContactseController::class, 'index']);
// Опциональный параметр. /contacts/1 или /contacts
$router->get('/contacts/{page:number?}', [ContactseController::class, 'index']);
Группы маршрутов
Поддерживается возможность объединения маршрутов в группу
$router->group('/admin/', function (RouteCollection $routeGroup) {
$routeGroup->get('/login/', [AuthController::class, 'index'])->setName('login');
$routeGroup->post('/login/authorize/', [AuthController::class, 'authorize'])->setName('authorize');
})->setNamePrefix('admin.');
В примере описанном выше будут обрабатываться следующие ссылки: /admin/login/ /admin/login/authorize/
Имена маршрутов так же будут иметь префикс admin. (admin.login, admin.authorize)
Генерация URL по имени маршрута
При объявлении маршрута можно указывать его имя с помощью метода ->setName('routeName'). Далее это имя можно использовать для генерации ссылок:
echo route('admin.login'); // /admin/login/
echo route('admin.authorize'); // /admin/login/authorize/
Можно так же генерировать маршруты с параметрами:
$router->get('/contacts/{action?}', [ContactseController::class, 'index'])->setName('contacts');
echo route('contacts', ['action' => 'action-name']); // /contacts/action-name
Установка приоритета
Бывают случаи когда один адрес может попадать под одно и то же регулярное выражение. Например если у вас есть маршрут с динамическим параметром, но для конкретной страницы которая попадает под этот маршрут вам нужно сделать отдельный контроллер.
$router->get('/path/{action}', ['class', 'method'])->setPriority(20);
$router->get('/path/test-action', ['class2', 'method'])->setPriority(100);
В этом примере URL /path/test-action попадает под шаблон первого маршрута, но т.к. мы указали приоритет второго маршрута выше чем первого, второй маршрут отработает раньше.
Добавление middleware
// Для одного маршрута
$router->get('/admin/', [DashboardController::class, 'index'])
->setName('admin.dashboard')
->addMiddleware(AdminAuthorizedUserMiddleware::class)
->addMiddleware(HasAnyRoleMiddleware::class);
// Для группы
$router->group('/admin/', function (RouteCollection $routeGroup) {
$routeGroup->get('/login/', [AuthController::class, 'index'])->setName('admin.login');
$routeGroup->post('/login/authorize/', [AuthController::class, 'authorize'])->setName('admin.authorize');
})->addMiddleware(AdminUnauthorizedUserMiddleware::class);
Middleware будут выполняться в следующем порядке:
Глобальные для всех маршрутов (из конфигов)
Для группы
Для конкретных маршрутов
Мы рассмотрели наиболее частые варианты использования маршрутизации и надеемся дальше вы сможете самостоятельно строить ещё более сложные маршруты.
Last updated
Was this helpful?