Routing (маршрутизация)



Содержание

Вступительный обзор

class Cake\Core\Configure

Этот раздел расскажет о наиболее распространенных способах использования CakePHP маршрутизатора. Допустим, в приложении, мы хотим отобразить какую либо страницу в качестве целевой, для этого необходимо в файл маршрутизации routes.php добавить следующий код:

use Cake\Routing\Router;

// Использование области видимости.
Router::scope('/', function ($routes) {
    $routes->connect('/', ['controller' => 'Articles', 'action' => 'index']);
});

// Использование статического метода.
Router::connect('/', ['controller' => 'Articles', 'action' => 'index']);

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

Пример выше будет выполнять индексный метод в ArticlesController при посещении главной страницы вашего сайта. Но иногда требуется создавать динамические маршруты, которые будут принимать несколько параметров, это было бы необходимо в случае, к примеру, маршрута для просмотра различных статей:

Router::connect('/articles/*', ['controller' => 'Articles', 'action' => 'view']);

Вышеуказанный маршрут будет принимать любой URL вида /articles/15 и вызывать метод view(15) в ArticlesController. Это не будет, однако, мешают людям пытается получить доступ к URL, похожим на /articles/foobar. Чтобы этого не допускать, вы можете добавить дополнительные параметры, которые будут требовать соответствия запроса определенному регулярному выражению:

$routes->connect(
    '/articles/:id',
    ['controller' => 'Articles', 'action' => 'view'],
)
->setPatterns(['id' => '\d+'])
->setPass(['id']);

// До версии 3.5 использовался массив опций
$routes->connect(
    '/articles/:id',
    ['controller' => 'Articles', 'action' => 'view'],
    ['id' => '\d+', 'pass' => ['id']]
)

В примере была заменена звездочка, которая означала, что ожидается любое значение параметра, на новый заполнитель :id. Использование таких заполнителей позволяет проверять части URL. В данном случае задействовано \d+ регулярное выражение, означающее, что в параметре допускаются только цифры. В конце, мы сказали маршрутизатору, что необходимо обрабатывать заполнитель id в качестве аргумента для функции view(), указав опцию pass. Подробнее об использовании этой опции будет рассказано немного позже.

CakePHP маршрутизатор способен так же на обратное преобразование маршрутов. Это означает, что из массива, содержащего соответствующие параметры, он способен генерировать строку URL:

use Cake\Routing\Router;

echo Router::url(['controller' => 'Articles', 'action' => 'view', 'id' => 15]);
// Будет выведено
/articles/15

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

use Cake\Routing\Router;

Router::connect(
    '/login',
    ['controller' => 'Users', 'action' => 'login'],
    ['_name' => 'login']
);

echo Router::url(['_name' => 'login']);
// Будет выведено
/login

Для того, чтобы ваш код соответствовал принципам DRY, маршрутизатор имеет концепцию ‘scopes’ (областей видимости). Область определяет общий сегмент пути. Любые маршруты, подключенные внутри этой области будут наследовать ее путь:

Router::scope('/blog', ['plugin' => 'Blog'], function ($routes) {
    $routes->connect('/', ['controller' => 'Articles']);
});

Маршрут выше будет соответствовать относительному URL адресу /blog/ и задействует индексный метод плагина Blog: Blog\Controller\ArticlesController::index().

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

Подключение маршрутов

static Cake\Routing\Router::connect($route, $defaults = [], $options = [])

Чтобы код вашего приложения соответствовал принципам DRY, вы должны использовать именно «области маршрутизации». Это позволит не только снизить количество написанного кода, но и поможет оптимизировать и ускорить работу маршрутизатора. Конечно, никто не запрещает, так же, применять и Router::connect() для подключения маршрутов, как это говорилось выше. Этот метод используется по умолчанию для области /, где каждый маршрут нужно подключать отдельно. Для того, чтобы создать область и соединить несколько маршрутов используется метод scope():

// В файле config/routes.php
use Cake\Routing\Route\DashedRoute;

Router::scope('/', function ($routes) {
    $routes->fallbacks(DashedRoute::class);
});

Метод connect() может принимать до трех параметров: URL шаблон, которому будет соответствовать маршрут; значения по умолчанию для элементов маршрута; а также дополнительные опции, которые часто включают в себя различного рода правила, в виде регулярных выражений, чтобы помочь более четкому определению элементов маршрутизации в URL строке.

Ниже приведен базовый формат для определения маршрута:

$routes->connect(
    'URL template',
    ['default' => 'defaultValue'],
    ['option' => 'matchingRegex']
);

Первый параметр используется, чтобы сообщить маршрутизатору, какой URL вы пытаетесь контролировать. Обычный URL является строкой разделенной слэшами (например: /articles), но может также содержать и знаки подстановки (*) или элементы маршрута. Использование знаков подстановки (например: /articles/*) говорит маршрутизатору, что вы готовы принять любые дополнительные аргументы. Маршруты без * должны точно соответствовать прилагаемому шаблону.

После указания URL, прописываются второй и третий параметры метода Connect(). Они необходимы для того, чтобы CakePHP понимал как следует обрабатывать полученный запрос. Второй параметр является ассоциативным массивом. Ключи массива указывают на элементы маршрута, которые будут представлять URL шаблон (например контроллер и экшен), а их значения это названия элементов используемые по умолчанию. Далее мы рассмотрим некоторые основные примеры, прежде чем начнем разговор об использовании третьего параметра Connect():

$routes->connect(
    '/pages/*',
    ['controller' => 'Pages', 'action' => 'display']
);

Этот маршрут, прописанный в файле routes.php папки config, будет соответствовать любому URL, начинающимся с /pages/. Обработчиком маршрута будет экшен display() контроллера PagesController. Запрос по адресу /pages/products, так же обратиться к экшену PagesController->display('products'), который воспримет products как входной параметр.

В дополнении к жадной звезде /*, также существует /**. Используя завершающую двойную звезду, вы будете захватывать весь остаток от URL в качестве единственного передаваемого в экшен аргумента. Это будет полезно, когда возникнет необходимость использовать аргумент, который включал бы в себя слеш (/):

$routes->connect(
    '/pages/**',
    ['controller' => 'Pages', 'action' => 'show']
);

Входящий URL /pages/the-example-/-and-proof приведет к тому, что в экшен будет передан аргумент the-example-/-and-proof. В противном же случае, если использовать одну звезду (/*), аргумент обрежется по слешу и будет равен строке the-example-.

Так же, вы можете использовать второй параметр метода Connect(), чтобы передавать любые параметры маршрутизации, которые состоят из значений по умолчанию для указанного маршрута:

$routes->connect(
    '/government',
    ['controller' => 'Pages', 'action' => 'display', 5]
);

Если у вас на сайте, например, показываются продукты для разных категорий клиентов, то можно рассмотреть вопрос о создании такого маршрута. Это позволяет использовать просто /government, вместо /pages/display/5.

Другим часто используемым приемом является определение «псевдонима» для контроллера. Давайте предположим, что вместо того, чтобы получить доступ к нашему постоянному URL /users/some_action/5, мы хотели бы, чтобы имелась возможность обращаться к /cooks/some_action/5. Следующий маршрут позаботится именно об этом:

$routes->connect(
    '/cooks/:action/*', ['controller' => 'Users']
);

Запись говорит маршрутизатору, что любые URL, начинающиеся с /cooks/ должны быть направлены к контроллеру Users. Название экшена будет зависеть от значения параметра :action. Используя элементы маршрута, вы можете создавать переменные маршруты, которые принимают пользовательский ввод или переменные. В вышеуказанном примере, также, используется жадная звезда. Она указывает маршрутизатору, что этот маршрут должен принимать какие-либо дополнительные аргументы. Эти аргументы будут доступны в массиве Передаваемые Аргументы.

При генерации URL-адреса, маршруты тоже используются. Указав ['controller' => 'Users', 'action' => 'some_action', 5], в качестве URL-будет выводиться /cooks/some_action/5, если указанный выше маршрут будет найден.

Маршруты, которые мы до сих пор рассматривали, будут соответствовать любому HTTP методу (post, get и др.). Хотя, например, при разработке REST API может потребоваться, в зависимости от метода HTTP, обратиться к определенному экшену контроллера. Для этого, RouteBuilder предоставляет вспомогательные инструменты, которые будут определять маршруты для разных HTTP методов:

// Создает маршрут, который будет отвечает только на запросы GET
$routes->get(
    '/cooks/:id',
    ['controller' => 'Users', 'action' => 'view'],
    'users:view'
);

// Создаст маршрут, который будет реагировать только на PUT запросы
$routes->put(
    '/cooks/:id',
    ['controller' => 'Users', 'action' => 'update'],
    'users:update'
);

Вышеуказанные маршруты будут распределять один и тот же URL на различные действия (экшены) контроллера исходя из используемого HTTP метода. GET запросы будут идти на экшен «view», в то время как запросы PUT направятся на экшен «update». Маршрутизатором определяются следующие HTTP методы:

  • GET;
  • POST;
  • PUT;
  • PATCH;
  • DELETE;
  • OPTIONS;
  • HEAD.

Все эти методы возвращают экземпляр маршрута, позволяющий вам использовать быстрые настройки для его дальнейшей конфигурации.

Новое в версии 3.5.0: Добавлены вспомогательные методы HTTP глагола в 3.5.0

Элементы маршрута

Через маршрутизатор вы можете указывать свои собственные элементы маршрута. Это дает вам возможность определить места в URL, где будут находиться параметры действия (экшена) контроллера. При выполнении запроса, значения этих элементов маршрута можно найти в $this->request->getParam() контроллера (например: echo $this->request->getParam('controller');, выведет название текущего контроллера). При определении пользовательского элемента маршрута, вы можете дополнительно указать регулярное выражение - это поможет CakePHP узнать - правильно сформирован URL или нет. Если используется регулярное выражение, то любой символ, отличный от / будет рассматриваться как часть параметра и прогоняться через это выражение:

$routes->connect(
    '/:controller/:id',
    ['action' => 'view']
)->setPatterns(['id' => '[0-9]+']);

// До версии 3.5 использовался массив опций
$routes->connect(
    '/:controller/:id',
    ['action' => 'view'],
    ['id' => '[0-9]+']
);

Приведенный выше пример показывает, как создать быстрый способ для просмотра моделей из любого контроллера по запрашиваемому URL, который выглядит как /controllername/:id. URL предоставляет для connect() два элемента маршрута: :controller и :id. Элемент :controller является элементом маршрута CakePHP по умолчанию, так что маршрутизатор знает, как определить имя контроллера который будет соответствовать запрашиваемому URL. А :id является пользовательским элементом маршрута, и необходимо дополнительно уточнить, что мы ожидаем увидеть, указав соответствующее регулярное выражение в третьем параметре Connect().

CakePHP не выполняет автоматически написание URLов строчными буквами или через дефис при использовании параметра :controller

use Cake\Routing\Route\DashedRoute;

$routes->scope('/', function ($routes) {
    $routes->setRouteClass(DashedRoute::class);
    $routes->connect('/:controller/:id', ['action' => 'view'])
        ->setPatterns(['id' => '[0-9]+']);

// До версии 3.5 использовался массив опций
$routes->connect(
    '/:controller/:id',
    ['action' => 'view'],
    ['id' => '[0-9]+', 'routeClass' => DashedRoute::class]
);

Класс DashedRoute будет следить за тем, чтобы параметры :controller и :plagin писались корректно, строчными буквами и через дефис.

Если вам нужны строчные или разделенные подчеркиванием URL, при переносе приложения из CakePHP 2.x, можете вместо вышеуказанного класса использовать класс InflectedRoute.

Внимание! Шаблоны, используемые для элементов маршрутизации не должны содержать какие-либо объединенные группы. Иначе маршрутизатор будет работать не корректно.

После того, как маршрут был определен (см. пример выше), запрос /apples/5 будет вызывать метод view() в ApplesController. Внутри метода view(), можно будет получить доступ к переданному параметру ID через запись $this->request->getParam('id').

Если у вас есть определенный контроллер в создаваемом приложении, и вы не хотите, чтобы его имя фигурировало в URL, то можно через URLы ссылаться только на экшены в этом контроллере. Например, для home контроллера, можно прописывать URL, как /demo вместо /home/demo. Для этого необходимо прописать в маршрутизаторе следующее:

$routes->connect('/:action', ['controller' => 'Home']);

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

$routes->connect(
    '/:userShortcut',
    ['controller' => 'Teachers', 'action' => 'profile', 1],
)->setPatterns(['userShortcut' => '(?i:principal)']);

// До версии 3.5 использовался массив опций
$routes->connect(
    '/:userShortcut',
    ['controller' => 'Teachers', 'action' => 'profile', 1],
    ['userShortcut' => '(?i:principal)']
);

Еще один пример маршрутизации:

$routes->connect(
    '/:controller/:year/:month/:day',
    ['action' => 'index']
)->setPatterns([
    'year' => '[12][0-9]{3}',
    'month' => '0[1-9]|1[012]',
    'day' => '0[1-9]|[12][0-9]|3[01]'
]);

// До версии 3.5 использовался массив опций
$routes->connect(
    '/:controller/:year/:month/:day',
    ['action' => 'index'],
    [
        'year' => '[12][0-9]{3}',
        'month' => '0[1-9]|1[012]',
        'day' => '0[1-9]|[12][0-9]|3[01]'
    ]
);

Это достаточно сложный пример, но он показывает, какие разнообразные маршруты можно создавать. URL в примере состоит из четырёх элементов маршрута. Первый нам уже знаком и является элементом по умолчанию, который говорит CakePHP ожидать имя контроллера.

Далее мы задаем некоторое значение, согласно которому, независимо от контроллера, будет выполняться экшен index().

Наконец, мы указываем регулярные выражения, которым соответствуют годы, месяцы и дни в числовой форме. Обратите внимание, что круглые скобки (группировка) не поддерживается в регулярных выражениях. В качестве альтернативы используйте чередование, как указано выше, без группирования круглыми скобками.

После определения, указанный в примере выше маршрут, будет соответствовать таким URL, как /articles/2007/02/01 или /articles/2004/11/16, передавая запросы в экшен index() соответствующих контроллеров, с параметрами даты, которые можно получить из $this->request->getParam() (например: $this->request->getParam('day')).

Есть несколько элементов маршрутов, которые имеют особое значение в CakePHP, и не должны использоваться в других целях.

  • controller Используется, чтобы назвать контроллер для маршрута;
  • action Используется, чтобы назвать действие контроллера для маршрута;
  • plugin Используется, чтобы назвать плагин, в котором располагается контроллер
  • prefix Используется для префиксов маршрутизации
  • _ext Применяется при использовании файловых расширений в маршрутизации;
  • _base Установите false, чтобы удалить основной путь из сформированного URL. Если ваше приложение находится не в корневом каталоге, это может быть использовано для создания относительных URL-адресов;
  • _scheme Установите для создания ссылок на различные схемы, такие как WebCal или FTP. По умолчанию используется текущая схема.
  • _host Установив хост, можно формировать в его пределах относительные ссылки. По умолчанию используется текущий хост;
  • _port Установите порт, если вам необходимо создать ссылки на нестандартные поры;
  • _full Если true, то FULL_BASE_URL константа будет предшествовать в генерируемых URL;
  • # Позволяет установить URL хэш-фрагменты;
  • _ssl Установите true для преобразования сгенерированного URL в https или false, чтобы заставить использовать http;
  • _method Определяет какой HTTP - глагол/метод используется. Полезно при создании маршрутов для RESTful;
  • _name Название маршрута. Если у вас есть именованные маршруты, то для их указания, вы можете использовать данный ключ.

Настройка параметров маршрута

Есть несколько вариантов маршрутизации, которые могут быть установлены на каждом маршруте. Для этого, после подключения маршрута, вы можете использовать соответствующие методы, выполняющие его дальнейшую настройку. Такие настройки заменяют многие из ключей в параметрах $options метода Connect():

$routes->connect(
    '/:lang/articles/:slug',
    ['controller' => 'Articles', 'action' => 'view'],
)
// Разрешить GET и POST запросы
->setMethods(['GET', 'POST'])

// Использовать только для поддомена
->setHost('blog.example.com')

// Устанавливает элементы маршрута, которые будут преобразованы 
// в аргументы, передаваемые в экшен
->setPass(['slug'])

// Устанавливает требования для элементов маршрута
->setPatterns([
    'slug' => '[a-z0-9-_]+',
    'lang' => 'en|fr|es',
])

// Разрешает использование в запросе расширения JSON
->setExtenions(['json'])

// Устанавливает 'lang' постоянным параметром 
->setPersist(['lang']);

Новое в версии 3.5.0: Добавлены вспомогательные методы настройки маршрутов в 3.5.0

Передача параметров в экшены

При подключении маршрутов с использованием элементов маршрута, вы можете захотеть получить отправленный элемент в виде передаваемого в экшен аргумента. Опция pass создает whitelists (белый список), согласно которому элементы маршрута, также, должны быть доступны в качестве аргументов, передаваемых в функцию контроллера:

// файл src/Controller/BlogsController.php
public function view($articleId = null, $slug = null)
{
    // Код экшена...
}

// файл routes.php
Router::scope('/', function ($routes) {
    $routes->connect(
        '/blog/:id-:slug', // Например: /blog/3-CakePHP_Rocks
        ['controller' => 'Blogs', 'action' => 'view']
    )
     ->setPatterns([
            // Определяем элементы маршрута в шаблоне маршрута 
            // для передачи в качестве аргументов функции. 
            // ":id" шаблона будет соответствовать переменной $articleId в вашем экшене
            'pass' => ['id', 'slug'],
            // Определяем шаблон (регулярное выражение), 
            // которому `id` должен соответствовать.
            'id' => '[0-9]+'
        ]);
});

Теперь благодаря возможности обратной маршрутизации, вы можете передать в URL массив, как показано ниже, и CakePHP будет знать, как сформировать URL, исходя из определенных в routes.php маршрутах:

// view.ctp
// Вернет ссылку вида: /blog/3-CakePHP_Rocks
echo $this->Html->link('CakePHP Rocks', [
    'controller' => 'Blog',
    'action' => 'view',
    'id' => 3,
    'slug' => 'CakePHP_Rocks'
]);

// Так же, можно указывать сразу значения параметров, 
// соблюдая последовательность.
echo $this->Html->link('CakePHP Rocks', [
    'controller' => 'Blog',
    'action' => 'view',
    3,
    'CakePHP_Rocks'
]);

Использование именных маршрутов

Иногда, прописывание всех параметров URL для определенного маршрута (особенно, если это приходиться делать не один раз) отнимает много времени и способствует дополнительному разрастанию кода, что, в свою очередь приводит к снижению быстродействия в работе приложения. Чтобы этого не происходило, вы можете воспользоваться именными маршрутами, при подключении которых, помимо всего прочего, задается параметр _name. Эта опция может быть использована в обратной маршрутизации, чтобы определить маршрут, который Вы хотите использовать:

// Подключение маршрута с именем.
$routes->connect(
    '/login',
    ['controller' => 'Users', 'action' => 'login'],
    ['_name' => 'login']
);

// Можно указать для маршрута метод  (3.5.0+)
$routes->post(
    '/logout',
    ['controller' => 'Users', 'action' => 'logout'],
    'logout'
);

// Формируем URL с помощью именного маршрута.
$url = Router::url(['_name' => 'login']);

// Формируем URL с помощью именного маршрута,
// с некоторым, передаваемым в запросе аргументом.
$url = Router::url(['_name' => 'login', 'username' => 'jimmy']);

Если шаблон содержит такие элементы маршрута, как например :controller, в обязательном порядке необходимо указывать их в качестве опции при формировании Router::url():

echo $url = Router::url(['_name' => 'myUrl', 'controller' => 'PagesHome', 3, 'CakePHP_Rocks']);

Внимание! Имена маршрутов должны быть уникальными во всем приложении. Один и тот же _name не может быть использован дважды, даже если это происходит внутри другой области маршрутизации.

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

Router::scope('/api', ['_namePrefix' => 'api:'], function ($routes) {
    // Название маршрута ниже будет `api:ping`
    $routes->get('/ping', ['controller' => 'Pings'], 'ping');
});
// Сгенерирует URL для маршрута 'ping' 
Router::url(['_name' => 'api:ping']);

// Использование namePrefix с plugin():
Router::plugin('Contacts', ['_namePrefix' => 'contacts:'], function ($routes) {
    // Подключаемый маршрут.
});

// Или с prefix()
Router::prefix('Admin', ['_namePrefix' => 'admin:'], function ($routes) {
    // Подключаемый маршрут.
});

Вы также можете использовать опцию _namePrefix внутри вложенных областей, и она так же будет корректно работать:

Router::plugin('Contacts', ['_namePrefix' => 'contacts:'], function ($routes) {
    $routes->scope('/api', ['_namePrefix' => 'api:'], function ($routes) {
        // Название маршрута ниже будет `contacts:api:ping`
        $routes->get('/ping', ['controller' => 'Pings'], 'ping');
    });
});

// Сгенерирует URL для маршрута 'ping' 
echo $url = Router::url(['_name' => 'contacts:api:ping']);

Маршрутам, подключаемым в именованных областях, будут присвоены имена с использованием префикса, если они были так же именованны. К безымянным маршрутам _namePrefix применяться не будет.

Новое в версии 3.1: Опция _namePrefix была добавлена ​​в версии 3.1

Использование префиксов в маршрутизации

static Cake\Routing\Router::prefix($name, $callback)

Часто, во многих приложениях используется раздел администрирования, где привилегированные пользователи могут вносить определенные изменения. В основном это делается через специальный URL, такой как /admin/users/edit/5. В CakePHP, префикс маршрутизация может быть включена с помощью метода prefix области видимости:

use Cake\Routing\Route\DashedRoute;

Router::prefix('admin', function ($routes) {
    // Все маршруты, подключаемые  в этой области 
    // будут иметь префикс `/admin`
    // при обратной маршрутизации необходимо 
    // добавлять элемент маршрута 'prefix' => 'admin'.
    $routes->fallbacks(DashedRoute::class);
});

Префиксы сопоставляются с подпространством имен, организованном в пространстве имен контроллеров вашего приложения. Таким образом, мы получаем префиксы в виде уменьшенных и более простых отдельных контроллеров. Поведение, которое является общим для префиксных и не префиксных контроллеров, может быть реализовано через наследование, компоненты контроллеров или черты. Учитывая пример выше, получится, что при обращении пользователя по адресу /admin/users/edit/5 будет вызван метод edit() в контроллере src/Controller/Admin/UsersController.php и в этот метод будет передан параметр 5 в виде аргумента функции. Используемый в этом случае файл вида будет искаться по пути src/Template/Admin/Users/edit.ctp

Вы можете прописать, что по умолчанию для URL /admin будет происходить обращение к экшену index() контроллера страницы:

Router::prefix('admin', function ($routes) {
    // Поскольку вы находитесь в области администрирования ('admin'), 
    // вам не нужно указывать префикс /admin или элемент маршрута admin.
    $routes->connect('/', ['controller' => 'Pages', 'action' => 'index']);
});

При создании префиксов маршрутов, вы можете установить дополнительные параметры маршрута с помощью аргумента $options:

Router::prefix('admin', ['param' => 'value'], function ($routes) {
    // Маршруты, связанные областью, имеют префикс '/admin' 
    // и общие параметры «param».
    $routes->connect('/:controller');
});

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

Router::plugin('DebugKit', function ($routes) {
    $routes->prefix('admin', function ($routes) {
        $routes->connect('/:controller');
    });
});

Запись выше создаст такой шаблон маршрута, как /debug_kit/admin/:controller. Здесь plugin и prefix будут установлены как элементы подключаемого маршрута.

При определении префиксов, если это необходимо, вы можете организовывать вложенность:

Router::prefix('manager', function ($routes) {
    $routes->prefix('admin', function ($routes) {
        $routes->connect('/:controller');
    });
});

Запись выше создаст такой шаблон маршрута, как /manager/admin/:controller. Здесь prefix будет установленным элементом маршрута со значением manager/admin.

Текущий префикс можно получить через метод контроллера $this->request->getParam('prefix')

При использовании префиксов маршрутов, важно устанавливать опцию префикса. Вот как построить такую ссылку с помощью HTML помощника:

// Ссылка с использованием префикса.
echo $this->Html->link(
    'Управление статьями',
    ['prefix' => 'manager', 'controller' => 'Articles', 'action' => 'add']
);

// Не использовать префикс
echo $this->Html->link(
    'View Post',
    ['prefix' => false, 'controller' => 'Articles', 'action' => 'view', 5]
);

Внимание! Вы должны подключить префиксы маршрутов до того, как начнете использовать обратную маршрутизацию.

Маршрутизация при использовании плагинов

static Cake\Routing\Router::plugin($name, $options = [], $callback)

Маршруты для плагинов должны создаваться с помощью метода plugin(). Для этих маршрутов методом будет создана новая область маршрутизации:

Router::plugin('DebugKit', function ($routes) {
    // Подключенные здесь маршруты будут иметь префикс '/debug_kit' и
    // элемент маршрута plugin со значением 'DebugKit'.
    $routes->connect('/:controller');
});

При создании областей методом plugin(), в параметрах вы можете настроить элемент пути path:

Router::plugin('DebugKit', ['path' => '/debugger'], function ($routes) {
    // Подключенные здесь маршруты будут иметь префикс '/debugger' и
    // элемент маршрута plugin со значением 'DebugKit'.
    $routes->connect('/:controller');
});

Так же, вы можете определить область плагина внутри области префикса:

Router::prefix('admin', function ($routes) {
    $routes->plugin('DebugKit', function ($routes) {
        $routes->connect('/:controller');
    });
});

Запись выше создаст такой шаблон маршрута, как /admin/debug_kit/:controller. Этот маршрут будет иметь prefix и элемент маршрута plugin со значением 'DebugKit'. Более подробную информацию о построении маршрутов для подключаемых плагинов вы можете найти в разделе Plugin Routes официального сайта кейка.

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

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

echo $this->Html->link(
    'New todo',
    ['plugin' => 'Todo', 'controller' => 'TodoItems', 'action' => 'create']
);

И наоборот, если активный запрос является запросом плагина и вы хотите создать ссылку, которая не входит в его область, то выполните следующее:

echo $this->Html->link(
    'New todo',
    ['plugin' => null, 'controller' => 'Users', 'action' => 'profile']
);

Устанавливая 'plugin' => null вы говорите маршрутизатору, что хотите создать ссылку, которая не является частью плагина.

SEO-Friendly маршруты

Некоторые разработчики, чтобы достичь более высокого рейтинга в поисковых системах, предпочитают использовать дефис в URL-адресах. Для этого в CakePHP применяют класс DashedRoute, который помогает организовывать в приложении маршрутизацию плагинов, контроллеров, и camelized имен для экшенов с дефисами в URL-адресах.

Например, если мы используем ToDo плагин, с контроллером TodoItems и showItems() экшеном, то чтобы получить URL адрес /to-do/todo-items/show-items, необходимо подключить следующий маршрут:

use Cake\Routing\Route\DashedRoute;

Router::plugin('ToDo', ['path' => 'to-do'], function ($routes) {
    $routes->fallbacks(DashedRoute::class);
});

Сопоставление маршрутов с определенными HTTP методами

Маршруты могут соответствовать конкретным HTTP методам (глаголам), для этого используются вспомогательные HTTP методы маршрутизации:

Router::scope('/', function($routes) {
    // Этот маршрут будет соответствовать только запросам POST.
    $routes->post(
        '/reviews/start',
        ['controller' => 'Reviews', 'action' => 'start']
    );

    // Для нескольких глаголов
    // До версии 3.5 используйте $options['_method'] для установки метода
    $routes->connect(
        '/reviews/start',
        [
            'controller' => 'Reviews',
            'action' => 'start',
        ]
    )->setMethods(['POST', 'PUT']);
});

Можно указать несколько методов HTTP с помощью массива. И помните, что параметр _method является ключом маршрута, участвующим в прямой и обратной маршрутизации, поэтому не забывайте использовать его при генерации URL:

$url = Router::url([
    'controller' => 'Reviews',
    'action' => 'start',
    '_method' => 'POST',
]);

Сопоставление маршрутов с именем хоста

При создании маршрутов можно использовать опцию _host, чтобы они соответствовали только определенным хостам. Так же, допускается использование подстановочной конструкции *. , чтобы маршрут соответствовал любому субдомену:

Router::scope('/', function($routes) {
    // Этот маршрут будет сопоставлен только с http://images.example.com
    // До версии 3.5 используйте опцию _host
    $routes->connect(
        '/images/default-logo.png',
        ['controller' => 'Images', 'action' => 'default']
    )->setHost('images.example.com');

    // Этот маршрут будет сопоставлен с 
    // любым субдоменом http://*.example.com
    $routes->connect(
        '/images/old-log.png',
        ['controller' => 'Images', 'action' => 'oldLogo']
    )->setHost('images.example.com');
});

Параметр _host также используется в генерации URL. Если _host параметр определяет точный домен, этот домен будет включен в созданном URL. Однако, если вы используете подстановочную конструкцию, то необходимо будет предоставить маршрутизатору параметр _host при создании URL-адреса:

// Если вы определяли следующий маршрут:
$routes->connect(
    '/images/old-log.png',
    ['controller' => 'Images', 'action' => 'oldLogo']
)->setHost('images.example.com');

// Вам нужно прописать следующий код, 
// чтобы создать URL:
echo Router::url([
    'controller' => 'Images',
    'action' => 'oldLogo',
    '_host' => 'images.example.com',
]);

Новое в версии 3.4.0: _host опция была добавлена ​​в 3.4.0

Маршрутизация файловых расширений

static Cake\Routing\Router::extensions(string|array|null $extensions, $merge = true)

Обработку различных файловых расширений при маршрутизации, можно осуществлять на глобальном уровне или уровне области видимости. Глобальное определение расширений может быть достигнуто с помощью статического метода Router::extensions():

Router::extensions(['json', 'xml']);
// ...

Запись выше повлияет на все маршруты, подключаемые strong>после, независимо от их области видимости.

Для того, чтобы ограничить расширения для конкретных областей, применяется метод Cake\Routing\RouteBuilder::setExtensions():

Router::scope('/', function ($routes) {
    // До версии 3.5.0 используйте `extensions()`
    $routes->setExtensions(['json', 'xml']);
});

Это позволит использовать указанные расширения для всех маршрутов, которые относятся к данной области маршрутизации (в том числе и маршрутов, подключенных во вложенных областях) и прописаны после вызова метода setExtensions(). Указанный принцип действия похож на глобальный метод Router::extensions(), в котором любые маршруты, подключенные до его вызова не будут наследовать указываемые расширения.

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

Если вы хотите создать URL, похожие на /page/title-of-page.html, то необходимо создать следующий маршрут:

Router::scope('/page', function ($routes) {
    // До версии 3.5.0 используйте `extensions()`
    $routes->setExtensions(['json', 'xml', 'html']);
    $routes->connect(
        '/:title',
        ['controller' => 'Pages', 'action' => 'view']
    )->setPass(['title']);
});

Затем, чтобы создать ссылку с использованием обратной маршрутизации, необходимо прописать следующий код:

$this->Html->link(
    'Link title',
    ['controller' => 'Pages', 'action' => 'view', 'title' => 'super-article', '_ext' => 'html']
);

Расширения файлов используются в Request Handling (обработчике запросов) для автоматического переключения вида на основе типов контента.

Подключение областей промежуточного ПО (далее Middleware)

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

Прежде чем Middleware может быть применено к соответствующей области, его необходимо зарегистрировать в коллекции маршрута:

// в файле config/routes.php
use Cake\Http\Middleware\CsrfProtectionMiddleware;
use Cake\Http\Middleware\EncryptedCookieMiddleware;

Router::scope('/', function ($routes) {
    $routes->registerMiddleware('csrf', new CsrfProtectionMiddleware());
    $routes->registerMiddleware('cookies', new EncryptedCookieMiddleware());
});

После регистрации, промежуточное ПО может применяться к конкретным областям:

$routes->scope('/cms', function ($routes) {
    // Включаем промежуточное ПО: CSRF и cookies
    $routes->applyMiddleware('csrf', 'cookies');
    $routes->get('/articles/:action/*', ['controller' => 'Articles'])
});

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

$routes->scope('/api', function ($routes) {
    $routes->applyMiddleware('ratelimit', 'auth.api');
    $routes->scope('/v1', function ($routes) {
        $routes->applyMiddleware('v1compat');
        // Здесь определяем маршруты.
    });
});

В приведенном выше примере маршруты, определенные в /v1, будут использовать промежуточное ПО «ratelimit», «auth.api» и «v1compat». Если вы повторно откроете область, промежуточное ПО, применяемое к маршрутам в каждой области, будет изолировано:

$routes->scope('/blog', function ($routes) {
    $routes->applyMiddleware('auth');
    // Здесь подключаем экшены, требующие аутентификации
});
$routes->scope('/blog', function ($routes) {
    // Здесь подключаем экшены, доступные всем
});

В приведенном выше примере два использования области /blog не имеют общего Middleware. Однако обе эти области будут наследовать промежуточное программное обеспечение родительской области, если их в нее вложить.

Группировка Middleware

Для того, чтобы ваш код соответствовал принципам DRY, промежуточное ПО может быть объединено в группы.

$routes->registerMiddleware('cookie', new EncryptedCookieMiddleware());
$routes->registerMiddleware('auth', new AuthenticationMiddleware());
$routes->registerMiddleware('csrf', new CsrfProtectionMiddleware());
$routes->middlewareGroup('web', ['cookie', 'auth', 'csrf']);

// Применить группу
$routes->applyMiddleware('web');

Новое в версии 3.5.0: Области видимости с Middleware и группировка Middleware добавлены в 3.5.0

Создание RESTful маршрутов

Маршрутизатор позволяет легко генерировать RESTful маршруты для контроллеров. RESTful маршруты полезны при создании API-endpoints для вашего приложения. Если мы хотим организовать REST доступ к контроллеру Recipes, то необходимо выполнить следующее:

// В файле config/routes.php...

Router::scope('/', function ($routes) {
    // До версии 3.5.0 используйте `extensions()`
    $routes->setExtensions(['json']);
    $routes->resources('Recipes');
});

Первая строка выполняет настройку для маршрутов области с целью легкого доступа REST, определяя желаемый формат результата (например, XML, JSON, RSS). Эти маршруты чувствительны к HTTP-методу запроса.

В CakePHP класс маршрутизатора Routes использует целый ряд различных индикаторов для определения того, какой метод HTTP используется. Эти индикаторы приведены ниже в порядке предпочтения (format - используемое расширение):

HTTP формат URL.format Какой экшен вызывается
GET /recipes.format RecipesController::index()
GET /recipes/123.format RecipesController::view(123)
POST /recipes.format RecipesController::add()
PUT /recipes/123.format RecipesController::edit(123)
PATCH /recipes/123.format RecipesController::edit(123)
DELETE /recipes/123.format RecipesController::delete(123)

Класс маршрутизатора Router в CakePHP использует целый ряд различных способов для определения используемого HTTP метода. Ниже они приведены в порядке предпочтения:

  1. Переменная метода POST (_method POST);
  2. X_HTTP_METHOD_OVERRIDE;
  3. Заголовок REQUEST_METHOD.

Переменная _method POST полезна при использование браузера в качестве клиента REST (или что-нибудь еще, что может сделать POST). Просто установите значение имени _method запроса HTTP, который вы хотите принимать.

Создание маршрутов с вложенными ресурсами (Nested Resource)

После того, как вы подключили ресурсы в области, вы также можете подключить маршруты для подресурсов. Маршруты подресурсов будут добавлены к исходному имени ресурса и параметру id. Например:

Router::scope('/api', function ($routes) {
    $routes->resources('Articles', function ($routes) {
        $routes->resources('Comments');
    });
});

Будет генерировать маршруты ресурсов для статей и комментариев

Маршруты для комментариев будут выглядеть следующим образом:

/api/articles/:article_id/comments
/api/articles/:article_id/comments/:id

Вы можете получить article_id в CommentsController следующим образом:

$this->request->getParam('article_id');

По умолчанию маршруты ресурсов сопоставляются с префиксом его области. Если у вас есть как вложенные, так и не вложенные контроллеры ресурсов, то можете использовать свой контроллер в каждом контексте, применяя префиксы:

Router::scope('/api', function ($routes) {
    $routes->resources('Articles', function ($routes) {
        $routes->resources('Comments', ['prefix' => 'articles']);
    });
});

Пример выше говорит о том, что ресурс 'Comments' располагается в App\Controller\Articles\CommentsController. Наличие отдельных (вспомогательных) контроллеров позволяет упростить логику в контроллерах основных. Префиксы, созданные таким образом, совместимы с основной префикс маршрутизацией.

Внимание! Несмотря на то, что вы можете вкладывать ресурсы так глубоко, как вам требуется, не рекомендуется этим увлекаться и объединять более двух ресурсов.

Новое в версии 3.3: Префиксы в метод resources() были добавлены ​​в версии 3.3

Ограничение созданных маршрутов

По умолчанию CakePHP соединит 5 маршрутов для каждого ресурса. Если необходимо подключить только определенные маршруты ресурсов, то можете использовать опцию only:

$routes->resources('Articles', [
    'only' => ['index', 'view']
]);

Создадутся маршруты только для чтения. Имена возможных маршрутов: create, update, view, index, and delete.

Изменение используемых в контроллере экшенов

Вам, возможно, потребуется изменить имена действий контроллера, которые используются при подключении маршрутов. Например: если ваш экшен edit() будет называться put(), то можно использовать опцию actions для такого переименования:

$routes->resources('Articles', [
    'actions' => ['update' => 'put', 'create' => 'add']
]);

Запись выше будет использовать put() для экшена edit(), и add() вместо create().

Отображение дополнительных маршрутов ресурса

Вы можете отобразить дополнительные методы ресурсов используя опцию map:

$routes->resources('Articles', [
   'map' => [
       'deleteAll' => [
           'action' => 'deleteAll',
           'method' => 'DELETE'
       ]
   ]
]);
// Это соединит с /articles/deleteAll

Помимо маршрутов по умолчанию, это также подключить маршрут /articles/delete_all. По умолчанию путь маршрута будет соответствовать имени ключа. Вы можете использовать ключ path внутри массива определяющего ресурс, чтобы настроить путь вручную:

$routes->resources('Articles', [
    'map' => [
        'updateAll' => [
            'action' => 'updateAll',
            'method' => 'DELETE',
            'path' => '/update_many'
        ],
    ]
]);
// Это соединит с /articles/update_many

Если вы определили ‘only’ и ‘map’, убедитесь, что ваши преобразованные методы также фигурируют в списке ‘only’.

Пользовательские классы для маршрутов ресурса

Вы можете использовать ключ connectOptions в массиве $options для resources(), чтобы обеспечить пользовательскую настройку подключения:

Router::scope('/', function ($routes) {
    $routes->resources('Books', [
        'connectOptions' => [
            'routeClass' => 'ApiRoute',
        ]
    ];
});

Модификация URL для маршрутов ресурса

По умолчанию URL формируется исходя из имени соответствующего контроллера и разделяется нижним подчеркиванием. Например, фрагмент URL для контроллера BlogPostsController будет /blog_posts.

Вы можете указать альтернативный тип модификации URLа с помощью опции Inflect:

Router::scope('/', function ($routes) {
    $routes->resources('BlogPosts', [
        'inflect' => 'dasherize' // Будет использоваться "Inflector::dasherize()"
    ]);
});

Запись выше будет генерировать следующий URL: /blog-posts.

Внимание! По состоянию на CakePHP 3.1 скелет приложения использует DashedRoute в классе маршрута по умолчанию. Использование 'inflect' => 'dasherize' при подключении маршрутов ресурсов рекомендуется для согласованности URL.

Изменение пути элемента

По умолчанию маршруты ресурсов используют измененную форму имени ресурса для сегмента URL. Вы можете установить пользовательский сегмент URL при помощи опции path:

Router::scope('/', function ($routes) {
    $routes->resources('BlogPosts', ['path' => 'posts']);
});

Новое в версии 3.5.0: Опция path была добавлена ​​в версии 3.5.0

Передаваемые аргументы

Передаваемые аргументы являются дополнительными аргументами или сегментами пути, которые используются при создании запроса. Они часто передаются как параметры методов (экшенов) контроллера.

http://localhost/calendars/view/recent/mark

В приведенном выше примере, recent и mark являются передаваемыми аргументами для метода CalendarsController::view(). Аргументы передаются в контроллеры тремя способами. Во первых в качестве аргументов вызываемого экшена, а во-вторых, они доступны в $this -> request-> getParam ('pass') в виде массива с числовой индексацией. При использовании настраиваемых маршрутов вы также можете принудительно ввести определенные параметры в переданные аргументы.

Если бы вы использовали ранее упомянутый URL, то действие контроллера должно выглядеть следующим образом:

class CalendarsController extends AppController
{
    public function view($arg1, $arg2)
    {
        debug(func_get_args());
    }
}

Вы получите следующий результат:

Array
(
    [0] => recent
    [1] => mark
)

Эти же данные доступны в $this->request->getParam('pass') в ваших контроллерах (controllers), представлениях (views) и хелперах (helpers). Значения в массиве индексируются числами в зависимости от порядкового их расположения в вызываемом URL:

debug($this->request->getParam('pass'));

В каждом случае вы получите:

Array
(
    [0] => recent
    [1] => mark
)

При создании URL-адресов, используя массив маршрутизации, передаваемые аргументы добавляются в массив в виде значений без строковых ключей:

['controller' => 'Articles', 'action' => 'view', 5]

Поскольку цифра 5 имеет числовой ключ в массиве, она рассматривается как переданный аргумент.

Создание URL-адресов

static Cake\Routing\Router::url($url = null, $full = false)

Создание URL-адресов или обратная маршрутизация - это функция CakePHP, которая позволяет изменять структуру URL-адресов без изменения всего кода. Используя массивы маршрутизации для определения URL-адресов, вы можете в дальнейшем перенастроить маршруты, а сгенерированные URL-адреса будут автоматически обновляться.

Если вы создадите URL-адрес как показано ниже:

$this->Html->link('View', '/articles/view/' . $id);

И затем позже решите, что вместо /articles будете использовать 'posts', то вам придется пройти и исправить все соответствующие URL-адреса приложения. Однако, если вы определили свою ссылку как:

$this->Html->link(
    'View',
    ['controller' => 'Articles', 'action' => 'view', $id]
);

То, в последствии вы можете изменить URL-адрес просто переопределив маршрут. Это изменит как входящее сопоставление URL-адресов, так и сгенерированные URL-адреса.

При использовании массива URL-адресов вы можете определить как параметры строки запроса, так и фрагменты документа с помощью специальных ключей:

Router::url([
    'controller' => 'Articles',
    'action' => 'index',
    '?' => ['page' => 1],
    '#' => 'top'
]);

// Сгенерирует следующий URL:
/articles/index?page=1#top

Маршрутизатор также преобразует любые неизвестные параметры в массиве маршрутизации в параметры запроса. Вопросительный знак предлагается использовать для обратной совместимости со старыми версиями CakePHP.

Вы также можете использовать любой из специальных элементов маршрута при создании URL-адресов:

  • _ext Используется для маршрутизации файловых расширений;
  • _base Установите значение false, чтобы удалить базовый путь из сгенерированного URL. Если ваше приложение не находится в корневом каталоге, это может быть использовано для создания URL-адресов, которые являются 'относительными';
  • _base Установите для создания ссылок на различные схемы, такие как WebCal или FTP. По умолчанию используется текущая схема;
  • _host Установив хост, можно формировать в его пределах относительные ссылки. По умолчанию используется текущий хост;
  • _port Установите порт, если вам необходимо создать ссылки на нестандартные поры;
  • _method Определяет какой HTTP - глагол/метод используется;
  • _full Если true, то FULL_BASE_URL константа будет предшествовать в генерируемых URL;
  • _ssl Установите true для преобразования сгенерированного URL в https или false, чтобы заставить использовать http;
  • _name Название маршрута. Если у вас есть именованные маршруты, то для их указания, вы можете использовать данный ключ.

Перенаправление в маршрутизации

Перенаправление в маршрутизации позволяет вам отправлять HTTP-статус 30x для входящих маршрутов и перенаправлять их на разные URL-адреса. Это полезно, если вы хотите сообщить клиентским приложениям, что ресурс перемещен, и вы не хотите показывать два URL-адреса для одного и того же контента.

Маршруты перенаправления отличаются от обычных маршрутов, поскольку они выполняют фактическое перенаправление заголовка, если совпадение найдено. Перенаправление может выполняться для адресата в вашем приложении или в совершенно другое место:

Router::scope('/', function ($routes) {
    $routes->redirect(
        '/home/*',
        ['controller' => 'Articles', 'action' => 'view'],
        ['persist' => true]
        // Или ['persist'=>['id']] для маршрутизации по умолчанию, где
        // view экшен ожидает $id в виде аргумента.
    );
})

Перенаправление с /home/* на /articles/view и передача параметров в /articles/view. Использование массива в качестве адресата перенаправления позволяет вам использовать другие маршруты, чтобы определить, куда должна быть перенаправлена строка URL. Вы так же можете перенаправлять на внешние ресурсы, используя строковые URL-адреса в качестве адресата:

Router::scope('/', function ($routes) {
    $routes->redirect('/articles/*', 'http://google.com', ['status' => 302]);
});

Запись выше выполнит редирект с /articles/* на http://google.com с HTTP статусом - 302.

Пользовательские классы маршрутов

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

  • Ожидается, что классы маршрутов будут найдены в пространстве имен Routing\\Route вашего приложения или плагина;
  • Классы маршрутов должны расширять Cake\Routing\Route;
  • Классы маршрутов должны реализовывать один или оба метода match() и/или parse().

Метод parse() используется для анализа входящего URL-адреса. Он должен генерировать массив параметров запроса, которые могут быть использованы в контроллере и экшене. Возвращайте false из этого метода, чтобы указать неудачу совпадения.

Метод match() используется для сопоставления массива параметров и создания строки URL-адреса. Если параметры URL не соответствуют маршруту, то должен быть возвращен false.

Вы можете использовать собственный класс маршрута с помощью опции routeClass:

$routes->connect(
     '/:slug',
     ['controller' => 'Articles', 'action' => 'view'],
     ['routeClass' => 'SlugRoute']
);

// Или установив routeClass в своей области.
$routes->scope('/', function ($routes) {
    //До версии 3.5.0 используйте 'routeClass()'
    $routes->setRouteClass('SlugRoute');
    $routes->connect(
         '/:slug',
         ['controller' => 'Articles', 'action' => 'view']
    );
});

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

Класс маршрута по умолчанию

static Cake\Routing\Router::defaultRouteClass($routeClass = null)

Если вы хотите использовать альтернативный класс маршрута для всех своих маршрутов, помимо маршрута по умолчанию, вы можете сделать это, вызывая Router::defaultRouteClass() перед общей настройкой маршрутов и не указывая опцию routeClass для каждого маршрута. Например:

use Cake\Routing\Route\InflectedRoute;

Router::defaultRouteClass(InflectedRoute::class);

приведет к тому, что все маршруты, подключенные после этого, будут использовать класс маршрута InflectedRoute. Вызов метода без аргумента возвращает текущий класс маршрута по умолчанию.

Метод fallbacks

Cake\Routing\Router::fallbacks($routeClass = null)

Метод fallbacks - это простой ярлык для определения маршрутов по умолчанию. Метод использует пройденный класс маршрутизации для определенных правил или, если класс не предоставлен, класс, возвращаемый методом Router::defaultRouteClass().

fallbacks вызывается следующим образом:

use Cake\Routing\Route\DashedRoute;

$routes->fallbacks(DashedRoute::class);

Запись выше является эквивалентом следующих явных вызовов:

use Cake\Routing\Route\DashedRoute;

$routes->connect('/:controller', ['action' => 'index'], ['routeClass' => DashedRoute::class]);
$routes->connect('/:controller/:action/*', [], ['routeClass' => DashedRoute::class]);

Внимание! Использование класса маршрута по умолчанию (Route) с fallbacks или любого маршрута с элементами маршрута :plugin и/или :controller, приведет к несогласованному URL-адресу.

Создание постоянных URL параметров

Вы можете подключиться к процессу генерации URL-адресов, используя функции их фильтрации. Функции вызываются до того, как URL- адреса будут сопоставлены с маршрутами, что позволяет подготовить URL-адреса до маршрутизации.

Фильтрационные функции обратного вызова должны ожидать следующие параметры:

  • $params Обрабатываемые параметры URL адреса;
  • $request Текущий запрос.

Функция фильтра URL всегда должна возвращать параметры, даже если они не изменены.

Фильтры URL позволяют реализовать такие функции, как постоянные параметры:

Router::addUrlFilter(function ($params, $request) {
    if ($request->getParam('lang') && !isset($params['lang'])) {
        $params['lang'] = $request->getParam('lang');
    }
    return $params;
});

Функции фильтра применяются в том порядке, в котором они подключены.

Другим вариантом использования является изменение определенного маршрута во время выполнения (например, маршруты плагинов):

Router::addUrlFilter(function ($params, $request) {
    if (empty($params['plugin']) || $params['plugin'] !== 'MyPlugin' || empty($params['controller'])) {
        return $params;
    }
    if ($params['controller'] === 'Languages' && $params['action'] === 'view') {
        $params['controller'] = 'Locations';
        $params['action'] = 'index';
        $params['language'] = $params[0];
        unset($params[0]);
    }
    return $params;
});

Это изменит следующий маршрут:

Router::url(['plugin' => 'MyPlugin', 'controller' => 'Languages', 'action' => 'view', 'es']);

на

Router::url(['plugin' => 'MyPlugin', 'controller' => 'Locations', 'action' => 'index', 'language' => 'es']);

Обработка именованных параметров в URL-адресах

Хотя именованные параметры были удалены в CakePHP 3.0, приложения могут иметь опубликованные URL-адреса, содержащие их. Вы можете продолжать принимать URL-адреса, содержащие именованные параметры.

В методе beforeFilter() вашего контроллера вы можете вызвать parseNamedParams() для извлечения любых именованных параметров из переданных аргументов:

public function beforeFilter(Event $event)
{
    parent::beforeFilter($event);
    Router::parseNamedParams($this->request);
}

Это будет заполнять $this->request->getParam ('named') с любыми именованными параметрами, найденными в переданных аргументах. Любой переданный аргумент, который интерпретируется как именованный параметр, будет удален из списка переданных аргументов.