Skip to main content

Роутинг (RouterApi)

Система роутинга (маршрутизации).

В рамках этого раздела будет показано, как устроена система роутинга, принципы работы роутинга, как создавать роуты, какие возможности настройки роутво есть. Описание программного интерфейса (API) доступного прикладным программистам при работе с RouterApi будет приведено в последнем разделе.

Всю систему роутинга можно условно разбить на следующие части:

  • Репозитарий router-плагинов
  • Программный интерфейс (API) для взаимодействия с RouterApi - включает в себя классы и функции, которые могут использовать прикладные программисты

Общее описание репозитария router-плагинов

В основе RouterApi лежит реестр плагинов типа router. Данные плагины содержат роуты модуля, в котором добавлен такой плагин. В свою очередь роут определяет связь адреса страницы и её обработчика. Кроме этого, в роутах же могут быть определены: Заголовок страницы, обработчик проверки прав доступа пользователя к странице.

Система реализована на основе PluginApi и работает в соответствии с особенностями PluginApi, реализуя плагины типа router.

router-плагины могут располагаться только в модулях.

На уровне файловой системы каждый router-плагин представляет собой папку вида:

  {module}/src/Plugins/router/{plugin-name}

router-плагины также могут быть сгруппированы и реализованы в рамках плагинного класса.

Описание файлов 'router'-плагина

В папке плагина могут быть следующие файлы:

  • {plugin-name}.inc - файл-контроллер router-плагина, в котором добавляются роуты
  • {plugin-name}.helpers.inc - в этом файле можно определить какие-то дополнительные функции, которые будут доступны в .inc файле

Переопределение ресурсов плагина

router-плагины могут быть переопределены. Это достигается с учётом принятой в PluginApi последовательности поиска и добавления плагинов в реестр. Версия плагина, добавленная в реестр позднее, получает больший приоритет перед другими версиями данного плагина и, таким образом, переопределяет его полностью или отдельные его части.

Последовательность поиска и включения виджетов (плагинов типа 'router') в реестр

  1. core-модули
  2. x- и contrib-модули
  3. app-модули

На каждом следующем уровне могут быть переопределены/дополнены ресурсы предыдущего.

Важные принципы при переопределении router-плагина

  • Файл {plugin-name}.inc по умолчанию не переопределяет родительские версии, а расширяет (дополняет)
  • Файл {plugin-name}.helpers.inc по умолчанию не переопределяет родительские версии, а расширяет (дополняет)
  • Если требуется переопределить какой-либо файл, то в начале имени файла нужно добавить '-'
  • Если требуется переопределить плагин циликом, то перед названием его папки нужно добавить '-'. В этом случае все ранее добавленные в реестр router-плагинов файлы данного плагина не будут учитываться.
  • Если в router-плагине есть какие-либо переопределния или модификации, то перед названием его папки нужно добавить '~'. Это ни на что не повлияет, но даст понимание, что в данной папке не полноценный новый плагин, а переопределение частей уже существующего плагина.

Файл {plugin-name}.inc

Файл содержит определение роутов, которые поставляет модуль.

Определение роутов добавляются в массив $routes в соответствии с форматом, описанным ниже.

.inc-файл router-плагина подключается и обрабатывается только в момент формирования реестра роутов сайта. После этого все параметры и настройки, добавленные в $routes, сохраняются в реестр, кэшируются и в дальнейшем загружаются из закэшированного реестра.

Пример определения роута:

$routes['feedback'] = [
'title' => 'Обратная связь',
'action' => [XfeedbackMainController::class, 'feedbackForm'], //Обработчик данного действия будет методовм feedbackFormAction() в классе MainController
'access arguments' => ['xfeedback send'], //Здесь перечислены права, которые разрешают пользователю доступ к данной странице
];
$routes['feedback/requests/%requestId'] = [
'title' => 'Просмотр заявки', // Заголовок страницы
'action' => [XfeedbackMainController::class, 'viewRequest'], //Обработчик данного действия будет методовм viewRequestAction() в классе XfeedbackMainController
'action arguments' => [1], //значение второго элемента пути адреса данной страницы будует передано как первый аргумент в обработчик viewRequestAction()
'access arguments' => ['xfeedback administer'], //Здесь перечислены права, которые разрешают пользователю доступ к данной странице
];

Формат пути роута

Роуты добавляются в ассоциативный массив $routes, где в качестве ключа является путь роута.

  • Путь может содержать индексрованные плейсхолдеры вида %
  • Путь может содержать именованные плейсхолдеры вида %<name>, например, %userId
  • Путь может состоять из одного элемента или нескольких, разделённых /, например, user/%uid/edit
  • Путь не может быть пустым
  • Путь не может состоять только из плейсхолдеров, первый элемент пути не может быть плейсхолдером
  • Путь должен быть уникальным на уровен всего сайта, поэтому следуют придерживаться рекомандаций по формированию пути
  • Путь, начинающийся с admin/ всегда относится к админке, доступ к таким страницам в обязательном порядке требует наличия у пользователя как минимум права access administer pages
Рекомандаций по формированию пути
  • Путь должен быть осмысленным, по возможности коротким, учитывающим иерархию, вложенность
  • Все элементы пути должны быть в нижнем регистре, слова разделяются символом -
  • Чтобы избежать возможного пересечения пути роута с путями роутов, определённых в других модулях, рекомендуется по возможности в каждом модуле при определении путей использовать в качестве префика id модуля. В качестве id модуля может использоваться имя модуля или более красивая форма этого имени. Например, для модуля xfeedback в качестве префикса путей можно было бы использовать xfeedback или же feedback, для модуля AppUsers следует использовать либо app-users, либо users, для модуля xmsgp можно использовать msg или messages.
  • Структурно сначала в пути должен быть класс ресурсов, затем id конкретного ресурса, затем действие над ресурсом (см. ниже схему и примеры)
  • В случае, если в пути есть плейсхолдеры, рекомендуется всегда использовать именованные плейсхолдеры

Схематично общую структуру пути можно определить так:

{module-prefix}/{resources-name}[/%{resource-id}[/{action}]]

Примеры путей:

feedback
feedback/requests
feedback/requests/%requestId
feedback/requests/%requestId/edit
feedback/requests/%requestId/delete
feedback/requests/%requestId/reply-and-delete

Параметры роута

Будут рассмотрены следующие важные параметры:

Основные параметры:

  • action
  • action arguments
  • access callback
  • access arguments
  • title
  • title callback
  • title arguments
  • type
  • check_number_parts
  • constraints
  • weight

Устаревшие (deprecated) параметры:

  • access_denied forward
  • access_denied redirect
  • widget
  • widget arguments
  • page callback
  • page arguments
  • file
  • file path

'action' - настройка обработчика (действия)

С помощью action указываем, какой обработчик будет вызван в контроллере.

Пример:

Рассмотрим роут feedback/requests/%requestId.

'action' => [XfeedbackMainController::class, 'viewRequest']

В данном случае в качестве обработчика запроса к этому роуту будет вызван метод XfeedbackMainController::viewRequestAction().

ПРИМЕЧАНИЕ №1

Если в классе контроллера XfeedbackMainController определён метод viewRequestAccess(), то он будет вызван после вызова access callback, указанного в настройках роута, но до вызова обработчика viewRequestAction(). При этом метод viewRequestAccess() имеет те же входные параметры, что и viewRequestAction(). Он должен вернуть true или false. В случае возврата false вызов обработчика viewRequestAction() не будет производиться, пользователю будет возвращён код ошибки 403 Access Denied.

ПРИМЕЧАНИЕ №2

Если в классе контроллера XfeedbackMainController определён метод viewRequestActionAfter(), то он будет вызван после вызова обработчика viewRequestAction(), генерации и печати контента, определённого обработчиком. Данный метод будет вызван даже в случае, если вызов обработчика viewRequestAction() был отменён (например, из-за недостатка прав). Это делает данный метод крайне полезным для таких задач, как безусловный подсчёт обращений к роуту.

'action arguments' - настройка аргументов обработчика

С помощью action arguments настраиваем, как, какие и каким образом будут передаваться аргументы в обработчик роута. Чаще всего здесь настраивается маппинг элементов пути в соответствующие аргументы обработчика. Для этого есть несколько вариантов, которые будут рассмотрены ниже. Кроме этого есть возможность указать маппинг GET query-параметров, а также передача строковых значний.

Маппинг элементов пути в аргументы обработчика

Рассмотрим роут feedback/requests/%requestId/edit и соответствующий ему реальный путь feedback/requests/123/edit.

Для передачи значние 3-го элемента пути в качестве первого аргумента обработчика, а 4-го элемента в качестве второго аргумента обработчика указываем в action arguments их индексы в пути, начиная отсчёт с 0:

'action arguments' => [2, 3]

В данном случае на вход обработчика данного роута будут переданы 2 аргумента: 123 и 'edit', т.е. фактически будет следующий вызов метода:

  $response = xlib(XfeedbackMainController::class)->viewRequestAction(123, 'edit');

Поскольку в данном примере у нас именованный плейсхолдер мы можем использовать имя этого плейсхолдера в action arguments, вместо указания его индекса. Это делает роут более понятным и позволяет избежать ошибок:

'action arguments' => ['%requestId', 3]

Результат передачи аргументов в обработчик будет таким же, как в примере выше.

Маппинг query-параметров URL-запроса в аргументы обработчика

Иногда возникает необходимость передать нескоторые query-параметры запроса в качестве аргументов обработчика. Это легко сделать с помощью следующего маппинга query:{param-name}

Рассмотрим роут feedback/requests/%requestId/edit и соответствующий ему реальный запрос feedback/requests/123/edit?sendNotify=1.

Для передачи значние 3-го элемента пути в качестве первого аргумента обработчика, а 4-го элемента в качестве второго аргумента обработчика указываем в action arguments их индексы в пути, начиная отсчёт с 0:

'action arguments' => ['%requestId', 3, 'query:sendNotify']

В данном случае на вход обработчика данного роута будут переданы 3 аргумента: 123, 'edit' и 1, т.е. фактически будет следующий вызов метода:

  $response = xlib(XfeedbackMainController::class)->viewRequestAction(123, 'edit', 1);
Передача простых строковых значений в аргументы обработчика

В качестве аргументов обработчика можно передавать простые строки, для которых не будет выполняться никакого маппинга:

'action arguments' => ['%requestId', 'edit']

В данном случае второй аргумент будет всегда равен 'edit'. В реальных условиях это используется редко и со временем, возможно, будет удалено.

'check_number_parts' и 'constraints' - настройка валидации роута

Перед тем как начнётся фаза проверки прав пользователя на роут, выполняется валидация роута. Это важная фаза, поскольку она позволяет предотвратить обработку заведомо некорректных запросов и передачу неподходящих данных в обработчики роута. Если валидация не пройдена, то роут считается неподходящим для обработки запроса, а значит пользователь получит ошибку 404 Not Found.

Валидация роута проходит в 3 этапа:

  1. Проверка соответвествия числа элементов в пути роута и в пути текущего запроса
  2. Проверка ограничений на значения переменных параметров роута
  3. Запуск валидации на уровне контроллера, указанного в action

Рассмотрим подробнее каждый этап.

Этапа 1: Проверка соответвествия числа элементов в пути роута и в пути текущего запроса

На данном этапе проверяется простое соответствие числа элементов в пути роута и в пути текущего запроса. Данная валидация активируются, когда значение настройки роута check_number_parts установлено в true (по умолчанию). Чтобы отключить данную валидацию нужно установить check_number_parts в false.

Пример:

Пусть путь роута 'clubs/%clubId'
`check_number_parts` установлено в `true` (или не установлено)
Чилсо элементов равно 2
В этом случае валидация следующих реальных запросов даст такие результаты:

clubs/regional -> true (т.к. число элементов этого пути также равно 2)
clubs/regional/unpublished -> false (т.к. число элементов этого пути также равно 3)

Иногда (редко) требуется разрешить передачу дополнительных элементов в путь роута. В этом случае необходимо установить check_number_parts в false.

Пример:

Пусть путь роута 'clubs/%clubId'
`check_number_parts` установлено в `false`
Чилсо элементов равно 2
В этом случае валидация следующих реальных запросов даст такие результаты:

clubs/regional -> true (т.к. число элементов этого пути также равно 2)
clubs/regional/unpublished -> true (т.к. число элементов этого пути равно 3, но в данном случае это будет допустимо)
Этапа 2: Проверка ограничений на значения переменных параметров роута

С помощью constraints можно легко добавить правила валидации динамических параметров адреса роута. Это позволяет не допустить возможную передачу неподходящих данных в обработчики роута через адрес запроса. Также это позволяет исключить выполнение заведомо некорректных запросов.

Пример использования:

    // Пусть путь роута 'user/%uid/edit
// Пусть реальный допустимый адрес будет такой 'user/123/edit?status=published'
// Добавим ограничения для переменных параметров
'constraints' => [
[1, 'TYPE', 'int'],
['%uid', 'TYPE', 'int'], //можно и так
['query:status', 'IN', ['blocked', 'published']],
],

Подддерживаются следующие типы проверок:

    [paramIndex, $regexpPattern],                       // пример: [1, '/\d/']
[paramIndex, 'ENTITY_EXISTS', $entityTypeName], // пример: [1, 'ENTITY_EXISTS', 'User']
[paramIndex, 'OBJECT_EXISTS', $entityTypeName], // пример: [1, 'OBJECT_EXISTS', 'user_load']
[paramIndex, 'CHECK', 'is_int'], // пример: [1, 'CHECK_TRUE', 'is_int']
[paramIndex, 'TYPE', 'int'], // пример: [1, 'TYPE', 'int']
[paramIndex, 'IN', [...]], // пример: ['query:status', 'IN', ['publish','unpublish']]
[paramIndex, 'BETWEEN', [...]], // пример: ['%userId', 'BETWEEN', [1, 12]]
Этапа 3: Запуск валидации на уровне контроллера, указанного в 'action'

Если проверка constraints для текущего запроса успешно пройдена, то RouterApi проверит, есть ли у контроллера специальный метод __validateAction(). Если такой метод есть, то он будет также вызван для дополнительной валидации роута. Если этот метод также вернёт true, то валидация роута считается пройденной и далее начнётся следующая фаза обработки роута - проверка прав доступа пользователя к этому роуту.

Если же роут на каком-либо этапе не прошёл валидацию, то RouterApi вернёт ошибку route_not_found и установит access для такого роуту в false. Это приведёт к том, что пользователь увидит ошибку 404 Page Not Found, а в лог будет добавлена запись о том, что проверка constraints не прошла для текущего запроса.

'access callback' и 'access arguments' - настройка доступа к роуту

Для настройки доступа к роуту можно использовать access callback и access arguments. Рекомендуется всегда настраивать параметры доступа к каждому роуту. Если access callback не указан, то в зависимости от настройки access arguments будет использован один из следующих методов:

  • User::checkPerm()
  • User::checkOwnerPerm()
  • User::checkPerms()
'access callback'

Если этих возможностей недостаточно, то можно указать свой access callback. В качестве access callback можно передать либо название функции, либо callable-массив.

Пример:

//Файл user_common.inc
$routes['user/%user'] = [
'title' => 'My account',
'title callback' => 'user_page_title',
'title arguments' => [1],
'page callback' => 'user_view',
'page arguments' => [1],
'access callback' => 'user_view_access',
'access arguments' => [1],
];

//Файл user.module
function user_view_access($account)
{
return xlib(UserApi::class)->view_access($account);
}
'access arguments'

С помощью access arguments настраиваем, как, какие и каким образом будут передаваться аргументы в access callback.

Чаще всего здесь будут передаваться аргументы для User::check*-функций, а это один или несколько прав доступа, и иногда маппинг uid из пути роута. Правила маппинга такие же, как описано в разделе про action arguments.

Далее в этом разделе рассмотрим случаи, когда в настройках роута не указан access callback. В этом случае access callback будет выбран автоматически в RouterApi на основе содержимого access arguments.

Вариант 1 - выбор User::checkPerm()

Если в access arguments первый и единственный элемент массива простая строка, то в качестве access callback будет выбран User::checkPerm().

Пример:

'access arguments' => ['access content'],

В этом случае при проверке доступа пользователя к роуту RouterApi фактически выполнит следующий код:

$access = User::checkPerm('access content')

Вариант 2 - выбор User::checkOwnerPerm()

Если в access arguments первый элемент массива простая строка и есть второй простой (не объект и не массив) элемент массива, то в качестве access callback будет выбран User::checkOwnerPerm(). При этом второй элемент массива будет рассматриваться как параметр $ownerUid метода User::checkOwnerPerm().

Пример:

// Пусть путь роута 'user/%uid/edit'
'access arguments' => ['edit own profile', 1],

В этом случае при проверке доступа пользователя к роуту RouterApi фактически выполнит следующий код:

// Пусть реальный путь запроса будет 'user/123/edit'
$access = User::checkOwnerPerm('edit own profile', 123);

Вариант 3 - выбор User::checkPerms()

Если в access arguments первый элемент массива является массиовом, то в качестве access callback будет выбран User::checkPerms(). При этом, если также передан вотрой элемент, то он будет рассматриваться как параметр $ownerUid метода User::checkPerms().

Пример:

// Пусть путь роута 'user/%uid/edit'
'access arguments' => [
[
'edit own profile'
'edit any profile'
],
1
],

В этом случае при проверке доступа пользователя к роуту RouterApi фактически выполнит следующий код:

// Пусть реальный путь запроса будет 'user/123/edit'
$currentUid = $currentUser->uid;
$access = User::checkPerms(['edit own profile', 'edit any profile'], $currentUid, 123);

'title' - заголовок страницы

С помощью title указываем заголовок страницы. В качестве значения можно передать обычную строку, а также строку, содержащую плейсхолдеры.

Использование плейсхолдеров позволяет строить заголовок страниц динамиески с учётом параметров адреса страницы.
В качестве плейсхолдеров можно использовать:

  • {%<index>} - Прямой индексированный плейсхолдер параметра из пути.
  • {%<name>} - Прямой именованный плейсхолдер параметра из пути.
  • {@<name>} - Вычисляемый плейсхолдер (такой плейсхолдер передаётся в специальном методе контроллера __mapTitleArgs() или путём вызова Page::setPageTitleArg()).
  • {query:<param-name>} - Значение (заэскейпченное) из query-параметра.

ВАЖНО: Значение плейсхолдера всегда безопасно, поскольку проходит через escapeHtml().

Примеры:

//Простой заголовок в виде строки
'title' => 'Редактор заявки'

//Заголовок в виде строки, включающий прямой индексированный плейсхолдер параметра из пути
'title' => 'Редактор заявки #{%2}'

//Заголовок в виде строки, включающий прямой именованный плейсхолдер параметра из пути
'title' => 'Редактор заявки #{%requestId}'

//Заголовок в виде строки, включающий вычисляемый плейсхолдер
'title' => 'Редактор заявки #{%requestId} от {@requesterName}'

//Заголовок в виде строки, включающий вычисляемый плейсхолдер и параметр из query
'title' => 'Редактор заявки #{%requestId} от {@requesterName} ({query:})'

'title callback' и 'title arguments' - установка нестандартного обработчика заголовка

Если по каким-то причинам возможностей установки заголовка страницы с помощью свойства title недостаточно, то можно установить свой обработчик заголовка с помощью свойств роута title callback и title arguments.

В качестве title callback можно передать либо название функции, либо callable-массив.

ВАЖНО!

Это не рекомендуемый способ генерации заголовка страницы и в будущих версиях скорее всего его поддержка будет удалена.

Пример использования:

//Файл user_common.inc
$routes['user/%user'] = [
'title' => 'My account',
'title callback' => 'user_page_title',
'title arguments' => [1],
'page callback' => 'user_view',
'page arguments' => [1],
'access callback' => 'user_view_access',
'access arguments' => [1],
];

//Файл user.module
function user_page_title($account)
{
if ($account->uid == $GLOBALS['user']->uid) {
return t('My account');
}

return $account->name;
}

'widget' и 'widget arguments' - настройка виджета как обработчика роута

В качестве обработчика роута можно использовать виджет. В этом случае вместо action и action arguments используем соответственно widget и widget arguments. Такой подход позволяет немного упростить код, избавившись от необходимости в создании контроллера и метода-обработчка, но экономия эта несущественная, а недостатков такой подход имеет довольно много.

ВАЖНО!

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

Пример:

$routes["node/%/photo/%/info"] = [
'title' => 'File quick info',
'widget' => 'xalbum-quick-card',
'page arguments' => [1, 3],
'access arguments' => ['access content'],
];

type и weight - настройка виджета как обработчика роута

Параметр type наряду с title и weight влияет на отображение данного роута в таких элементах навигации по странице как: заголовок, табы и хлебные крошки. С параметром title заголовком страницы разобрались выше. В этом разделе рассмотрим как настроить отображение навигации по подразделам в виде табов.

Для начала рассмотрим возможные значния параметра type:

  • MENU_CALLBACK - значение type по умолчанию. Такой роут не является подразделом (табом).
  • MENU_DEFAULT_LOCAL_TASK - Такой роут будет подразделом (табом) по умолчанию.
  • MENU_LOCAL_TASK - Такой роут будет подразделом (табом)

Параметр weight имеет смысл для роутов, являющихся подразделами (табами). В этом случае weight позволяет изменить порядок отображения табов по умолчанию.

Рассмотрим пример настройки роутов для подразделов:

$routes['admin/xfeedback'] = [
'title' => 'Обратная связь',
//Обработчик данного действия будет методовм feedbackSummaryAction() в классе XfeedbackAdminController
'action' => [XfeedbackAdminController::class, 'feedbackSummary'],
'access arguments' => ['xfeedback edit'],
];
$routes['admin/xfeedback/summary'] = [
'title' => 'Сводка',
'access arguments' => ['xfeedback edit'],
//У данного типа нет обработчика.
//Он используется только для отрисовки дефолтного таба.
//Обработчик такого таба задаётся в родительском табе - в данном случае это будет 'admin/xfeedback'
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -1,
];
$routes['admin/xfeedback/list'] = [
'title' => 'Список заявок',
//Обработчик данного действия будет методовм feedbackListAction() в классе XfeedbackAdminController
'action' => [XfeedbackAdminController::class, 'feedbackList'],
'access arguments' => ['xfeedback edit'],
'type' => MENU_LOCAL_TASK,
];

Каждый подраздел (таб) может также иметь дочерние подразделы (табы). Всего разрешается иметь не более 2-х уровней табов.

Рассмотрим пример определения 2-уровневых табов:

$routes['admin/xpay'] = [
'title' => 'Платные услуги и финансы',
'action' => [AdminController::class, 'summary'],
'access arguments' => ['administer payments'],
'file' => 'xpay.admin.inc',
'weight' => -10,
];

$routes['admin/xpay/summary'] = [
'title' => 'Сводка',
'weight' => -10,
'type' => MENU_DEFAULT_LOCAL_TASK,
'access arguments' => ['administer payments'],
];

$routes['admin/xpay/transactions'] = [
'title' => 'Все транзакции',
'action' => [AdminController::class, 'transactionsList'],
'access arguments' => ['administer payments'],
'type' => MENU_LOCAL_TASK,
];

$routes['admin/xpay/balance-increase'] = [
'title' => 'Пополнение балансов',
'action' => [AdminController::class, 'refillList'],
'access arguments' => ['administer payments'],
'weight' => -9,
'type' => MENU_LOCAL_TASK,
];

//второй уровень вложенности табов
$routes['admin/xpay/balance-increase/balance'] = [
'title' => 'Все методы пополнения',
'type' => MENU_DEFAULT_LOCAL_TASK,
'access arguments' => ['administer payments'],
];
//второй уровень вложенности табов
$routes['admin/xpay/balance-increase/balance/robokassa'] = [
'title' => 'Robokassa',
'action' => [AdminController::class, 'robokassaRefillList'],
'access arguments' => ['administer payments'],
'type' => MENU_LOCAL_TASK,
];

RouterApi

В рамках данного раздела рассмотрим наиболее важные программные средства, которые доступны прикладным программистам при работе с RouterApi.

  • API-функции системы роутинга
  • API-методы класса RouterApi и его фасада Router
  • API-методы класса RouterPluginRegistry
  • API-методы класса Url
  • Базовый класс для создания контроллеров ActionControllerBase

API-функции системы роутинга

К таким функциям относятся те, которые лежат в основе роутинга:

  • Функция формирования URL url(...)
  • Функция формирования ссылок l(...)

Функция url(...)

Функция url() формирует внутренний или внешний URL-адрес на основе переданных в неё параметров.

Есть 2 варианта использования данной функции:

1) Без проверки прав доступа пользователя к соответвующему запросу 2) С проверкой прав доступа пользователя к соответвующему запросу

Вариант 1 - без проверки прав доступа

В первом случае используем простой формат передачи параметра $path в функцию - в виде строки.

Пример:

$url = url("user/$uid/edit");

В данном случае url будет сформирован и возвращён в виде строки независимо от прав доступа пользователя к этой странице.

Вариант 2 - с проверкой прав доступа

Второй вариант подразумевает перед тем как начать формирования URL сначала проверить права доступа пользователя к этой странице. И если прав доступа у пользователя недостаточно, то прервать формирование URL и вернуть null.

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

Чтобы использовать данный вариант вместо в качестве первого параметра $path функции url() передаем индексированный массив, где первым элементом является path роута с плейсхолдерами, а последующими - значения всех плейсхолдеров. Преобразование такого массива в реальный $path будет прозведён с помощью RouterApi.

Пример:

$url = url(["user/%uid/edit", $uid]); //можно использовать именованный параметр
$url = url(["user/%uid/edit", ['%uid' => $uid]]); //можно использовать именованный параметр
$url = url(["user/%/edit", $uid]); //можно использовать индексированный параметр

В данном случае будет сгенерирован реальный url к странице, но проверка прав доступа производится не будет. Чтобы была проведена проверка прав доступа необходимо в начале пути роута добавить знак !.

Пример:

$url = url(["!user/%uid/edit", $uid]); //можно использовать именованный параметр
$url = url(["!user/%uid/edit", ['%uid' => $uid]]); //можно использовать именованный параметр
$url = url(["!user/%/edit", $uid]); //можно использовать индексированный параметр
if($url) {
$btn = "<a href='$url'>редактировать профиль</a>";
}

Функция l(...)

Функция l() на основе переданных в неё параметров формирует html-код ссылки. Второй параметр функции $path - это путь адреса ссылки. В отношении него действуют те же правила, что и для $path в функции url().

Примеры:

$link = l('Редактировать', "user/$uid/edit"); //без проверки прав доступа
$link = l('Редактировать', ["user/%uid/edit", $uid]); //без проверки прав доступа
$link = l('Редактировать', ["!user/%uid/edit", $uid]); //с проверкой прав доступа
if($link) {
$vars['editLink'] = $link;
}

Класс RouterApi и его фасад Router

Класс RouterApi - это 'главный контроллер' системы роутинга. Именно отсюда начинается и завершается обработка любого запроса. Кроме обработки запросов данный класс также содержит ряд публичных методов, которые могут быть полезны прикладным программистам. Для удобства работы с этими методами создан фасад Router. Поскольку для доступа к этим методам рекомендуется использовать фасад, то во всех примерах этого раздела будем использовать именно методы фасада.

Класс Router предоставляет следующие публичные методы:

  • buildUrl()
  • buildPath()
  • checkAccess()
  • getRouteData()
  • getRouteItem()
  • setActiveRoute()
  • getRoutes()
  • rebuildRoutes()

Метод buildUrl($pathPattern, $pathParams = null, $options = []): ?string

Данный метод работает аналогично функции url().

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

$url = Request::buildUrl(["!user/%uid", 123]); // -> '<base_url>/user/123' или null, если недостаточно прав

Метод buildPath($pathPattern, $pathParams = null): ?string

Строит реальный путь запроса на основе переданного шаблона пути (путь роута) и параметров.

Правила передачи данных для формирования реального пути запроса аналогичны функции url().

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

$path = Request::buildPath(["!user/%uid", 123]); // -> 'user/123' или null, если недостаточно прав

Метод checkAccess($pathPattern, $pathParams = null): bool

Проверяет есть ли у текущего пользователя права на доступ к странице с роутом $pathPattern и параметрами переменных роута $pathParams.

ВАЖНО!

В отличии от фукнций url(), l(), методов Router::buildPath() и Router::buildUrl() перед путём роута не нужно ставить !.

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

$url = Request::checkAccess(["user/%uid", 123]); // -> true, если есть права, иначе - false

Метод getRouteData(string $pathPattern): array

Если роут, соответствующий $pathPattern найден, то будет возвращён ассоциативный массив с параметрами данного роута. Иначе будет возвращён пустой массив.

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

$routeData = Router::getRouteData($pathPattern); 

Метод getRouteItem(?string $path = null, $routerItem = null): array

Находит роут, подходящий для пути $path, формирует все роута данные для передачи на выполнение и возвращает результирующие данные в виде массива. Если $path пустой, то будет использован $_GET['q'].

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

$processedRouteData = Router::getRouteItem("user/123");

Метод getRouteItem(?string $path = null, $routerItem = null): array

Находит роут, подходящий для пути $path, формирует все роута данные для передачи на выполнение и возвращает результирующие данные в виде массива.

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

$processedRouteData = Router::getRouteItem("user/123");

Метод setActiveRoute(string $path): void

Программно устанавливает активный путь в $path, что определяет, какая страница загружается.

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

Router::setActiveRoute("user/123");

Метод getRoutes(): array

Возвращает массив всех роутов.

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

$allRoutes = Router::getRoutes();

Метод rebuildRoutes(): bool

Очищает кэш роутов и запускает процедуру заполнения реестра роутов. Именно в этот момент выполняются router-плагины. После того как реестр роутов построен он кэшируется.

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

Router::rebuildRoutes();