Page Contents

Маршрутизация

class Cake\Routing\Router

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

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

Быстрый тур

В этом разделе вам расскажут о наиболее распространённых применениях CakePHP Router. Как правило, вы хотите отображать что-то в качестве целевой страницы, поэтому вы добавляете это в свой файл routes.php:

use Cake\Routing\Router;

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

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

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

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

$routes->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+, чтобы сопоставлялись только цифры. Наконец, мы сказали Router обработать id в качестве аргумента функции view(), указав опцию pass. Подробнее об использовании этого параметра расскажем попозже.

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

use Cake\Routing\Router;

echo Router::url(['controller' => 'Articles', 'action' => 'view', 'id' => 15]);
// Выйдет
/articles/15

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

// В routes.php
$routes->connect(
    '/login',
    ['controller' => 'Users', 'action' => 'login'],
    ['_name' => 'login']
);

use Cake\Routing\Router;

echo Router::url(['_name' => 'login']);
// Выйдет
/login

Чтобы сохранить код маршрутизации DRY, маршрутизатор имеет концепцию „scopes“ (области). Область определяет общий сегмент пути и, при необходимости, маршрутизирует значения по умолчанию. Любые маршруты, связанные внутри области, наследуют пути/значения по умолчанию из обёртки их областей:

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

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

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

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

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

Чтобы сохранить код DRY вы должны использовать „области маршрутизации“. Области маршрутизации не только позволяют сохранить код DRY, но и помогают маршрутизатору оптимизировать его работу. Этот метод по умолчанию использует область /. Чтобы создать область и подключить некоторые маршруты, мы будем использовать метод 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-адрес - это строка с нормальным символом слэша, но может также содержать подстановочный знак (*) или Элементы маршрута. Использование подстановочного знака указывает маршрутизатору, что вы готовы принять любые дополнительные аргументы. Маршруты без символа * соответствуют только указанному патерну шаблона.

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

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

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

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

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

Входящий URL-адрес /pages/the-example-/-and-proof приведёт к передаче одного аргумента the-example-/-and-proof.

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

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

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

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

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

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

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

Маршруты, которые мы подключали до сих пор, будут соответствовать любому HTTP-глаголу. Если вы создаёте 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

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

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

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

Вы можете указать свои собственные элементы маршрута, и это даёт вам возможность определять места в URL-адресе, где должны находиться параметры для действий контроллера. Когда запрос сделан, значения для этих элементов маршрута находятся в $this->request->getParam() в контроллере. Когда вы определяете настраиваемый элемент маршрута, вы можете дополнительно указать регулярное выражение - это говорит 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 использовать опцию array
    $routes->connect(
        '/:controller/:id',
        ['action' => 'view'],
        ['id' => '[0-9]+']
    );
});

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

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

Примечание

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

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

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

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

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

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

Еще один пример, и вы будете профессионалом маршрутизации:

// До 3.5 используовался массив параметров вместо setPatterns()
$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]'
]);

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

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

Затем мы укажем некоторые значения по умолчанию. Независимо от контроллера, мы хотим вызвать экшен index().

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

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

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

  • controller Используется для обозначения контроллера для маршрута.

  • action Используется для обозначения действия(экшена) контроллера для маршрута.

  • plugin Используется для обозначения плагина, в котором находится контроллер.

  • prefix Используется для Префиксная маршрутизация

  • _ext Используется для File extentions routing.

  • _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
->setExtensions(['json'])

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

Добавлено в версии 3.5.0: Свободные методы построения были добавлены в 3.5.0

Передача параметров в действие(экшен)

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

// src/Controller/BlogsController.php
public function view($articleId = null, $slug = null)
{
    // Здесь код экшена
}

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

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

// 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' => 'logout']);

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

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

Примечание

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

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

Router::scope('/api', ['_namePrefix' => 'api:'], function ($routes) {
    // Имя этого маршрута будет `api:ping`
    $routes->get('/ping', ['controller' => 'Pings'], 'ping');
});
// Создайте URL-адрес для маршрута пинга
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-адрес для маршрута пинга
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() области видимости, в config/routes.php:

use Cake\Routing\Route\DashedRoute;

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

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

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

Router::prefix('admin', function (RouteBuilder $routes) {
    // Поскольку вы находитесь в области администрирования,
    // вам не нужно включать префикс /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(
    'Manage articles',
    ['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' и
    // имеют элемент маршрута плагина, установленный в 'DebugKit'.
    $routes->connect('/:controller');
});

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

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

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

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

Вышеизложенное создало бы маршрут, который выглядит как /admin/debug_kit/:controller. Он будет иметь элементы prefix и 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

Некоторые разработчики предпочитают использовать тире в URL-адресах, так как они воспринимаются как лучший рейтинг в поисковых системах. Класс DashedRoute может использоваться в вашем приложении с возможностью маршрутизации плагинов, контроллеров „верблюжьих“ имён в пунктирный URL.

Например, если у вас есть плагин ToDo, с контроллером TodoItems и экшеном showItems(), его можно получить в разделе /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. Чтобы генерировать URL-адреса для маршрутов, специфичных для метода, вам нужно включить ключ _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('*.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']);
// ...

Это повлияет на все маршруты, которые подключаются после этого, независимо от их объема.

Чтобы ограничить расширения конкретными областями, вы можете определить их, используя метод 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']
);

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

Соединение с областью 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 middleware
    $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 не используют промежуточное ПО. Однако обе эти области будут наследовать промежуточное ПО, определённое в их областях видимости.

Группировка промежуточного ПО

Чтобы сохранить код маршрута 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: Промежуточное ПО и группы промежуточного ПО были добавлены в 3.5.0

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

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

// В config/routes.php...

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

Первая строка устанавливает несколько маршрутов по умолчанию для простого доступа REST, где метод определяет желаемый формат результата (например, xml, json, rss). Эти маршруты чувствительны к методу HTTP запросов.

HTTP format

URL.format

Controller action invoked

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. The _method POST variable

  2. The X_HTTP_METHOD_OVERRIDE

  3. The REQUEST_METHOD header

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

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

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

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

Будет генерировать маршруты ресурсов для articles и comments. Маршруты комментариев будут выглядеть так:

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

Вы можете получить article_id в CommentController:

$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: Опция prefix была добавлена в resources() в 3.3.

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

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

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

Создал бы маршруты ресурсов только для чтения. Имена маршрутов: create, update, view, index, и 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() для предоставления настраиваемых параметров, используемых connect():

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

URL-инфлексия для ресурсных маршрутов

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

Вы можете указать альтернативный тип инфлексии, используя опцию `` 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') в ваших контроллерах, представлениях и помощниках(хелперах). Значения в массиве pass численно индексируются в зависимости от порядка их появления в вызываемом URL:

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

Любой из приведённых выше:

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

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

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

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

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

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

Создание URL-адресов или обратная маршрутизация - это функция CakePHP, которая позволяет изменять структуру URL-адресов без изменения всего вашего кода. Используя routing arrays для определения ваших 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-адреса.

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

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

// Будет генерировать URL-адрес, похожий на
/articles/index?page=1#top

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

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

  • _ext Используется для Расширения файлов маршрутизации маршрутизации.

  • _base Установите false, чтобы удалить базовый путь из сгенерированного URL. Если ваше приложение не находится в корневом каталоге, это может быть использовано для создания URL-адресов, которые являются „относительными кексами“.

  • _scheme Установите для создания ссылок на разные схемы, такие как webcal или ftp. По умолчанию используется текущая схема.

  • _host Установите хост для связи. По умолчанию используется текущий хост.

  • _port Установите порт, если вам нужно создать ссылки на нестандартных портах.

  • _method Определите HTTP-глагол для URL-адреса.

  • _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/*', 'https://google.com', ['status' => 302]);
});

Это перенаправит /articles/* на hat can be resolved i с HTTP-статусом 302.

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

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

  • Ожидается, что классы маршрутов будут найдены в пространстве имён Routing\\Route вашего приложения или плагина.

  • Маршрутные классы должны расширять Cake\Routing\Route.

  • Классы маршрутов должны реализовывать один или оба из match() и/или parse().

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

Метод match() используется для сопоставления массива параметров URL и создания строкового 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 и позволит вам реализовать обработку настраиваемых параметров. Вы можете использовать классы маршрутов плагинов, используя стандартный plugin syntax.

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

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

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

use Cake\Routing\Route\InflectedRoute;

Router::defaultRouteClass(InflectedRoute::class);

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

Метод откатов

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

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

Вызов таких резервов:

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) по умолчанию с резервными ошибками или любого маршрута с элементами маршрута :plugin и/или :controller приведёт к несогласованному URL адресу.

Создание постоянных параметров 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') любыми иными параметрами, найденными в переданных аргументах. Любой переданный аргумент, который интерпретируется как именованный параметр, будет удалён из списка переданных аргументов.