Общие сведения
С помощью маршрутов система узнает какому фронт-контроллеру нужно передать управление для обработки запроса.
Общий порядок работы маршрутов в системе выглядит так:
- Скрипт index.php получает запрос
- Система генерирует событие getroute
- Все модули возвращают системе свои маршруты
- Система перебирает маршруты, вызывая у каждого метод match. Метод возвращает true, если текущий URL подходит для маршрута
- Если какой-либо маршрут вернул true, у него вызываются методы getController() и getAction()
- Запускается фронт-контроллер
- Если ни один маршрут не откликнулся на URL, возвращается ошибка 404
Классы для работы с маршутами описаны в пространстве имен RS::Router. Чтобы сообщить системе маршруты модуля, необходимо вернуть их объекты с помощью обработчика события getroute.
namespace ModuleName\Config;
{
function init()
{
$this->bind('getroute');
}
public static function getRoute($routes)
{
$routes[] = new \RS\Router\Route('modulename-front-controller', array(
'/section1/{id}/{page}/',
'/section3/{id}/'
), null, 'Страница демонстрационного модуля');
return $routes;
}
}
Рассмотрим класс маршрута RS::Router::Route подробнее. Он принимает следующие аргументы:
- string $id - идентификатор URI.
- string |array $masks - Маска для URI в формате ReadyScript. В случае, если передан array, маска, имеющая бОльшую длину должна располагаться в списке выше.
- array | null $defaults - Значения по умолчанию для переменных из URI
- string $description - Текстовое описание страницы по данному URI
- boolean hide - Скрывать из списков в административной панели?
- string $wrap_pattern - Обрамляющий шаблон для регулярного выражения. Стандартный обрамляющий шаблон: ^{pattern}
Допустимые варианты спользования маски ReadyScript:
/product/{alias}/ - запишет вторую секцию в переменную alias
/product/{alias:[\d]+}/ - маршрут сработает, только если alias будет числом
Чтобы маршрут сработал, должно произойти соответствие по левой части маски (если используется стандартный $wrap_pattern).
Например, для url: http://domain.ru/product/phone-360gs/comments/
- маршрут с маской /product/ - сработает
- маршрут с маской /comments/ - НЕ сработает
В маске можно указать переменные, которые должны быть извлечены из URL. Если таких переменных в URL не будет найдено значения будут взяты из аргумента $default.
Опционально, в маске можно использовать регулярное выражение для проверки значения параметров. Для этого используется следующая конструкция: {ИМЯ_ПЕРЕМЕННОЙ[:PCRE_РЕГУЛЯРНОЕ ВЫРАЖЕНИЕ]} Например, можно составить маску /product/{alias:(one|two|three)}/, в этом случае маршрут сработает только для следующих URL адресов:
- /product/one/
- /product/two/
- /product/three/
Связь маршрута и фронт-контроллера задается либо заданием в $defaults пары:
array(
'controller' => 'сокращенное имя контроллера'
)
либо указанием сокращенного имени контроллера в качестве $id маршрута.
- Заметки
- Сокращенное имя контроллера формируется из имени класса контроллера включая namesapce, путем замены обратных слешей на минусы, и исключения секции -controller. Минусы по краям удаляются. Вся строка приводится к нижнему регистру. Например, если имя контроллера: \Catalog\Controller\Front\ProductList, то его сокращенное имя будет: catalog-front-productlist
Чтобы направить маршут на определенное действие контроллера, необходимо задать строку в массиве $default с ключем Act:
namespace ModuleName\Config;
{
function init()
{
$this->bind('getroute');
}
public static function getRoute($routes)
{
$routes[] = new \RS\Router\Route('modulename-front-controller', array(
'/viewitem/{id}/'
), array(
'Act' => 'view'
), 'Страница просмотра объекта');
return $routes;
}
}
Переменную Act можно также указать в маске URI маршрута, в этом случае от URL будет зависеть, какое действие контроллера будет вызвано.
...
public static function getRoute($routes)
{
$routes[] = new \RS\Router\Route('modulename-front-controller', array(
'/item/{Act}/{id}/'
), null, 'Страница просмотра объекта');
return $routes;
}
...
В случае, если необходимо создать несколько различных URL, ведущих на различные действия одного контроллера следует помнить, что имя маршрута должно быть уникальным и имя контроллера следует задавать с помощью параметра controller, через параметры $defaults.
namespace ModuleName\Config;
{
function init()
{
$this->bind('getroute');
}
public static function getRoute($routes)
{
$routes[] = new \RS\Router\Route('modulename-front-controller-list', array(
'/items/'
), array(
'controller' => 'modulename-front-controller'
'Act' => 'index'
), 'Страница со списком объектов');
$routes[] = new \RS\Router\Route('modulename-front-controller-view', array(
'/items/{id}/'
), array(
'controller' => 'modulename-front-controller'
'Act' => 'view'
), 'Страница просмотра объекта');
return $routes;
}
}
Формирование URL с помощью маршрутов
Маршрут способен не только извлекать параметры из URL, но и формировать URL по заданным параметрам. Благодаря этой возможности в шаблонах можно абстрагироваться от конкретных URL, что дает возможность программистам и специалистам SEO, полностью изменять карту URL-адресов интернет-магазинов. Это также может быть полезно для сохранения адресации, при переносе другого сайта на платформу ReadyScript.
Итак, для формирования URL служит метод RS::Router::Route::buildUrl. Метод ожидает 3 параметра:
- array $params - параметры для uri
- bool $absolute - если true, то вернет абсолютный путь
- mixed $mask_key - индекс маски по которой будет строиться url, если не задан, то будет определен автоматически
Пример:
$route = new \RS\Router\Route('modulename-front-controller', array(
0 => '/section1/{id}/{page}/',
1 => '/section3/{id}/'
), null, 'Страница демонстрационного модуля');
echo $route->buildUrl(array( 'id' => 35 ));
echo $route->buildUrl(array( 'id' => 35, 'page' => 2));
echo $route->buildUrl(array( 'id' => 35, 'param1' => 'value1' ));
echo $route->buildUrl(array( 'id' => 35, 'page' => 2, 'param2' => 'value2' ));
echo $route->buildUrl(array( 'id' => 35, 'page' => 2), false, 1);
Во всех marty шаблонах присутствует переменная $router, в которой находится объект RS::Router::Manager. Рассмотрим пример, как получить готовый URL в шаблоне.
Ссылка: {$router->getUrl('modulename-front-controller', ['id' => 35])}
Абсолютная ссылка: {$router->getUrl('modulename-front-controller', ['id' => 35, 'page' => 2], true)}
Получение текущего маршрута
Для получения текущего маршрута в любой части кода, можно воспользоваться статическим методом RS::Router::Manager::getCurrentRoute
Очень удобно использовать объект текущего маршрута передачи сведений от фронт-контроллера к блок-контроллерам. Например, фронт-контроллер карточки товара, записывает объект просматриваемого товара в произвольное свойство product текущего маршрута.
namespace Catalog\Controller\Front;
{
function actionIndex()
{
$this->router->getCurrentRoute()->addExtra(self::ROUTE_EXTRA_PRODUCT, $product_orm);
}
}
Далее, в любом блок контроллере можно получить объект товара, который просматривается в данный момент.
namespace ModuleName\Controller\Block;
{
function actionIndex()
{
$route = $this->router->getCurrentRoute();
if ($route->getId() == 'catalog-front-product') {
$product = $route->getExtra(\Catalog\Controller\Front\Product::ROUTE_EXTRA_PRODUCT);
if ($product && $product['title'] == 'Планшет Samsung') {
}
}
}
}
Проверка маршрутов из административной панели
Чтобы проверить, как маршрут откликается на на URL, в административной панели есть вспомогательный раздел. В меню Управление → Настройка системы в правой части стрницы нужно выбрать пункт Маршруты в системе.
Маршруты в системе
В данном разделе можно набрать произвольный URL и увидеть какой маршрут откликается на него.
Маршрут административной части
Все запросы административной части обрабатываются одним маршрутом, который объявлен следующим образом:
new Route(self::ADMIN_ROUTE,
array(
"/{$admin}/{mod_controller}/",
"/{$admin}/",
), array(
'controller' => 'main-admin-index',
'mod_controller' => 'main-widgets'
),
t('Панель Администратора'),
true
);
Рассмотрим подробнее данный маршрут:
Все запросы, с начальной секцией /{$admin}/ обрабатываются фронт-контроллером main-admin-index, т.е. классом Main::Controller::Admin::Index. Второй секцией определена переменная $mod_controller, в которой ожидается сокращенное название контроллера модуля административной части, которому будет передано управление. Если $mod_controller явно не задана в URL, то будет использоваться значение по-умолчанию, т.е. main-widgets.
- Заметки
- Сокращенное имя контроллера, ожидаемое в параметре $mod_controller, формируется из имени класса контроллера включая namesapce, путем замены обратных слешей на минусы, и исключения секции -controller-admin. Минусы по краям удаляются. Вся строка приводится к нижнему регистру. Например, если имя контроллера: \Catalog\Controller\Admin\Ctrl, то его сокращенное имя будет: catalog-ctrl