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

### **Для чего нужен роутер в JohnCMS?**

Как и в других CMS и фреймворках роутер в JohnCMS обрабатывает запрошенный URL адрес и определяет какой модуль запустить для обработки этого запроса.\
В свою очередь модуль может получить от роутера различные параметры в зависимости от настроек маршрута и использовать для реализации своего функционала.

Перейдем к практической части.

### Где хранятся настройки маршрутизации?

Все описания маршрутов хранятся в модулях по следующему пути: **config/routes.php**

Пример файла **routes.php**

{% code title="config/routes.local.php" %}

```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');
};
```

{% endcode %}

Давайте теперь рассмотрим детально как работать с роутером и как использовать его в своих модулях?

Возьмём простой пример из кода выше.\
Маршрут у нас в нем задается такой строкой:

<pre class="language-php"><code class="lang-php"><strong>$router->get('/contacts/', [ContactseController::class, 'index'])->setName('contacts');
</strong></code></pre>

Эта строка говорит роутеру следующее:\
Если запрос пришел методом GET и он поступил на страницу site.ru/contacts/, то необходимо вызвать метод **index** в контроллере **Johncms\Contacts\Controllers\ContactseController**\
Таким образом, когда пользователь переходит по адресу site.ru/contacts/ он видит те данные, которые вернул метод index.

Давайте рассмотрим более сложные примеры маршрутизации.\
Для этого давайте изменим наш простой модуль контактов, который мы создавали в предыдущей статье: [Создание модуля](/10.0/moduli/sozdanie-modulya.md)

Откроем файл /config/routes.local.php

Изменим нашу строку маршрута следующим образом:

```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 вставим следующий код

{% code title="ContactsController.php" %}

```php
<?php

declare(strict_types=1);

namespace Johncms\Contacts\Controllers;

class ContactsController
{
    public function index(string $action = '')
    {
        // Получаем массив параметров, которые вернул нам роутер
        $route = di('route');
        // Выведем их на экран
        dd($route);
    }
}
```

{% endcode %}

Перейдем по адресу: **site.ru/contacts/moscow/**

В браузере у вас отобразится следующий текст:

```
Array
(
    [action] => moscow
)
```

Как мы видим, параметр, который мы назвали в настройках маршрута action, появился у нас в массиве и содержит слово moscow.

В модуле мы можем обратиться к этому параметру и в зависимости от его содержимого управлять логикой работы модуля.\
Получить этот параметр можно, как вы наверное уже догадались, следующим образом:\
&#x20;$route\['action']

Также в методе контроллера можно указывать одноименные переменные и в таком случае в этих переменных будет содержаться то, что вы указали в параметрах марщрута.

В нашем случае в переменной $action будет содержаться слово moscow.

{% hint style="info" %}
При автоматическом внедрении переменных в методы контроллеров происходит приведение типов к указанному в сигнатуре метода. Преобразование выполняется только для типов int, float, string, bool. \
Оригинальные типы можно получить из массива $route = di('route');
{% endhint %}

### Прочие примеры использования

Указание регулярного выражения для сопоставления маршрута

```php
$router->get('/contacts/{page<\d+>}', [ContactseController::class, 'index']);
```

В примере выше регулярное выражение ограничивает тип параметра page до числа. Если после строки /contacts/ будут буквы - маршрут не будет сопоставлен и отобразится 404 страница.

#### Установка метода запроса

Роутер позволяет задавать методы для которых будет доступен маршрут.

```php
// 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 существуют заготовленные регулярные выражения которые можно указать следующим образом:

<pre class="language-php"><code class="lang-php">// Число. /contacts/1234
$router->get('/contacts/{page:number}', [ContactseController::class, 'index']);
<strong>
</strong><strong>// Буквы, цифры и некоторые знаки. /contacts/my-page_1-2-3
</strong>$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']);
</code></pre>

#### Группы маршрутов

Поддерживается возможность объединения маршрутов в группу

```php
$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').\
Далее это имя можно использовать для генерации ссылок:

```php
echo route('admin.login'); // /admin/login/
echo route('admin.authorize'); // /admin/login/authorize/
```

Можно так же генерировать маршруты с параметрами:

```php
$router->get('/contacts/{action?}', [ContactseController::class, 'index'])->setName('contacts');
echo route('contacts', ['action' => 'action-name']); // /contacts/action-name
```

#### Установка приоритета

Бывают случаи когда один адрес может попадать под одно и то же регулярное выражение. Например если у вас есть маршрут с динамическим параметром, но для конкретной страницы которая попадает под этот маршрут вам нужно сделать отдельный контроллер.

```php
$router->get('/path/{action}', ['class', 'method'])->setPriority(20);
$router->get('/path/test-action', ['class2', 'method'])->setPriority(100);
```

В этом примере URL **/path/test-action** попадает под шаблон первого маршрута, но т.к. мы указали приоритет второго маршрута выше чем первого, второй маршрут отработает раньше.

#### Добавление middleware

```php
// Для одного маршрута
$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 будут выполняться в следующем порядке:

1. Глобальные для всех маршрутов (из конфигов)
2. Для группы
3. Для конкретных маршрутов

Мы рассмотрели наиболее частые варианты использования маршрутизации и надеемся дальше вы сможете самостоятельно строить ещё более сложные маршруты.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.johncms.com/10.0/moduli/marshrutizaciya-routing.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
