Маршрутизация в Kohana 3.2

Kohana 3 это один из не многих фреймворков который может по хвастаться  очень мощной и гибкой системой маршрутизации. По своей сути маршруты в системе устанавливают соответствие между URL и действиями ваших контроллеров. При правильном использовании системы маршрутизации фреймворка Kohana 3 вы можете сделать практически любую схему URL для вашего сайта соответствующую практически любому расположению контроллеров.

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

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

Если вы посмотрите файл APPPATH/bootstrap.php, то вы увидите что маршрут используемый системой по умолчанию выглядит следующим образом:

Route::set('default', '(<controller>(/<action>(/<id>)))')
->defaults(array(
    'controller' => 'welcome',
    'action'     => 'index',
));

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

Код описывающий маршрут по умолчанию создает в системе маршрут с именем default соответствующий URL в формате: (<controller>(/<action>(/<id>)))

Давайте подробнее рассмотрим каждый из параметров name, uri и дополнительный массив regex метода создания маршрутов Route::set.

Name

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

URI

Параметр URI задается строкой, которая представляет собой шаблон формата URL. Как правило шаблон состоит и параметров имена которых заключены между символами <>, так же  эти параметры могут быть заключены в символы (), что в сою очередь означает что эти параметры являются необязательными в URI. В шаблоне маршрутов Kohana можно использовать любые символы кроме ()<>, такие символы будут трактоваться как литералы (использоваться как есть).  Обычно / используется в качестве разделителя статических частей URL. Kohana не накладывает ни каких ограничений на форматирование ваших маршрутов.

Давайте посмотрим на шаблон маршрута по умолчанию еще раз, (<controller>(/<action>(/<id>))). В этом шаблоне у нас есть три параметра: controller, action и id. Так как все параметры шаблона находятся между символами () то этому шаблону так же будет удовлетворять и пустой адрес, а так же пустому адресу будут соответствовать значения параметров controller и action заданные по умолчанию (параметры устанавливаются методом defaults()).

Вы можете использовать любые имена для ваших параметров в запросе, кроме перечисленных ниже, эти параметры имеют специальное значение для объекта Request:

Directory — подкаталог в директории classes/controller для поиска контроллера.

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

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

Regex

Маршрут Kohana в процессе проверки использует синтаксис Perl-совместимых регулярных выражений. По умолчанию каждый параметр (имя которого обрамлено символами <> ) будет соответствовать регулярному выражению [^/.,;?\n]++ (или на простом языке: всем символам кроме косой черты, точки, запятой, точки с запятой, вопросительного знака или символа новой строки). Вы можете определить свои собственные регулярные выражения для проверки ваших параметров передав как дополнительный третий аргумент в метод создания маршрута Route::set ассоциативный массив содержащий в качестве ключей имена ваших параметров, а в качестве значений регулярные выражения для их проверки.

В представленном ниже примере маршрута контроллеры располагаются в двух каталогах: admin и affiliate. Этому маршруту будут соответствовать адреса которые начинаются с имени каталога admin или affiliate.

Route::set('sections', '<directory>(/<controller>(/<action>(/<id>)))',
    array(
        'directory' => '(admin|affiliate)'
    ))
    ->defaults(array(
        'controller' => 'home',
        'action'     => 'index',
    ));

Вы можете также использовать менее строгие регулярные выражения для проверки ваших параметров и тем самым игнорировать переполнение в маршруте. В представленном ниже примере URL «foobar/baz/and-anything/else_that/is-on-the/url» будет соответствовать контроллеру Controller_Foobar, действию action_baz(), а параметр «stuff» будет содержать «and-anything/else_that/is-on-the/url» .

Route::set('default', '(<controller>(/<action>(/<stuff>)))', array('stuff' => '.*'))
    ->defaults(array(
        'controller' => 'welcome',
        'action' => 'index',
  ));

Значения по умолчанию

Если параметр в маршрут не является обязательным, вы можете задать для него значение по умолчанию, передав ассоциативный массив с ключами которые являются именами параметров и значений по умолчанию в метод Route::defaults, вызванный после метода Route::set. Значения параметров по умолчанию могуть содержать значения параметров для контроллера и действия используемых по умолчанию.

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

Давайте посмотрим на шаблон маршрута по умолчанию еще раз, в нем все параметры являются необязательными, а значения для параметров  controller и action заданы по умолчанию. В случае если мы откроем URL http://mysite.com, то данный маршрут по умолчанию выполнит действе action_index контроллера Controller_Welcome. Если мы откроем URL http://mysite.com/foobar то будет использоваться только параметр action по умолчанию и маршрут выполнит действие action_index контроллера Controller_Foobar, и наконец, если мы откроем URL http://mysite.com/foobar/baz то значения по умолчанию для параметров не будут использоваться, и в этом случае маршрут выполнит действие action_baz контроллера Controller_Foobar.

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

Маршруты с анонимными функциями или функциями обратного вызова

Начиная с версии Kohana 3.1, вы можете задать дополнительные схемы маршрутизации с помощью лямбда-маршрутов. Вместо шаблона передаваемого в аргументе URI, вы можете использовать анонимную функцию или функцию обратного вызова заданного стандартными правилами для PHP, которая будет обрабатывать ваши маршруты. Ниже представлен небольшой пример.

Если вы хотите использовать методы создания URL на основе маршрута лямбда-маршрутов, вам необходимо передать третий параметр:

Route::set('testing', function($uri)
    {
        if ($uri == 'foo/bar')
            return array(
                'controller' => 'welcome',
                'action'     => 'foobar',
            );
    },
    'foo/bar'
);

 

Route::set('testing', function($uri)
    {
        if ($uri == '</language regex/>(.+)')
        {
            Cookie::set('language', $match[1]);
            return array(
                'controller' => 'welcome',
                'action'     => 'foobar'
            );
        }
    },
    '<language>/<rest_of_uri>
);

В случае если вы используете PHP 5.2, то вы так же можете использовать лямбда-маршруты:

Route::set('testing', array('Class', 'method_to_process_my_uri'));

Примеры

/*
 * Маршрут для проверки авторизации пользователя
 */
Route::set('auth', '<action>',
  array(
    'action' => '(login|logout)'
  ))
  ->defaults(array(
    'controller' => 'auth'
  ));

/*
 * Маршрут лент новостей в нескольких форматах
 *   452346/comments.rss
 *   5373.json
 */
Route::set('feeds', '<user_id>(/<action>).<format>',
  array(
    'user_id' => '\d+',
    'format' => '(rss|atom|json)',
  ))
  ->defaults(array(
    'controller' => 'feeds',
    'action' => 'status',
  ));

/*
 * Статические страницы
 */
Route::set('static', '<path>.html',
  array(
    'path' => '[a-zA-Z0-9_/]+',
  ))
  ->defaults(array(
    'controller' => 'static',
    'action' => 'index',
  ));

/*
 * Вы не любите слеши в адресе?
 *   EditGallery:bahamas
 *   Watch:wakeboarding
 */
Route::set('gallery', '<action>(<controller>):<id>',
  array(
    'controller' => '[A-Z][a-z]++',
    'action'     => '[A-Z][a-z]++',
  ))
  ->defaults(array(
    'controller' => 'Slideshow',
  ));

/*
 * Быстрый поиск
 */
Route::set('search', ':<query>', array('query' => '.*'))
  ->defaults(array(
    'controller' => 'search',
    'action' => 'index',
  ));

Параметры запроса

Для того что бы получить значение параметров directory , controller и action из объекта вы можете использовать методы объекта Request:

// получение доступа из метода контроллера
$this->request->action();
$this->request->controller();
$this->request->directory();

// получение доступа из любого места приложения
Request::current()->action();
Request::current()->controller();
Request::current()->directory();

Все остальные параметры перечисленные в маршруте доступны через Request::param():

// получение доступа из метода контроллера
$this->request->param('key_name');

// получение доступа из любого места приложения
Request::current()->param('key_name');

Метод Request::param() принимает второй необязательный аргумент для того что бы определить значение по умолчанию для параметра в случае, если данный параметр не установлен текущим маршрутом. Если для метода Request::param() не задан ни один аргумент, то метод возвращает все ключи параметры в виде ассоциативного массива.

Важно. Параметры action, controller и directory не доступены через метод Request::param().

Например, следующий маршрут:

Route::set('ads','ad/<ad>(/<affiliate>)')
->defaults(array(
    'controller' => 'ads',
    'action'     => 'index',
));

Если URL соответствует маршруту, то будет вызвано действие action_index контроллера Controller_Ads. И вы сможете получить доступ к параметрам с помощью метода param() объяекта Request контроллера, при получении параметра не забудьте определить значение по умолчанию (через второй необязательный параметр Request::param()), это стоит делать в том случае если вы не определили значение для параметра по умолчанию через метод Route::defaults.

class Controller_Ads extends Controller {
    public function action_index()
    {
        $ad = $this->request->param('ad');
        $affiliate = $this->request->param('affiliate',NULL);
    }
}

Где должны быть определены маршруты?

Созданные вами маршруты вы можете разместить в файлах инициализации модулей MODPATH/<module>/init.php, в случае если ваши маршруты принадлежать модулю, или просто вставить их в APPPATH/bootstrap.php файл (не забудьте добавить их перед маршрутом по умолчанию), в случае если маршруты являются специфическими для приложения. Конечно ничто не мешает вам загружать из нонешнего файла, или даже генерировать их динамически.

Генерация URL и ссылок на основе маршрутов

В месте с мощной маршрутизацией Kohana 3, в фремворк включены методы для генерации URI на основе ваших маршрутов, и так же вы всегда можете создать URI на основе строки используя URL::site для абсолютной ссылки примерно так:

URL::site('admin/edit/user/'.$user_id);

Так же Kohana предоставляет средства для создания URI на основе маршрута. Это очень полезно, если ваши маршруты могут когда-либо измениться, эта возможность избавить вас от необходимости в дальнейшем изменять формат URL во всем приложении, созданный на основе строки. Вот пример динамической генерации, которая соответствует маршруту feeds которй был описан ранее:

Route::get('feeds')->uri(array(
  'user_id' => $user_id,
  'action' => 'comments',
  'format' => 'rss'
));

Допустим вы решили позже сделать этот путь более подробным  изменив его на feeds/<user_id>(/<action>).<format> . Если вы в вашем приложении для создания ссылок использовали код указанный выше, то вам не придется менять больше ни строчки! В случае если часть URI заключается в круглые скобки и она содержит определение параметра, для которого не определено значение переданное для генерации URI и нет значения по умолчанию указанного в маршруте, то эта часть URL будет удалена. Примером этого является часть маршрута по умолчанию (/<id>).

5 комментариев

  1. Tomich:

    А как сделать на Kohana настроить маршрутизацию так, чтобы адреса страниц имели вид http://page1.site.com , page2.site.com (т.е. имитация домена 3-го уровня), а не http://site.com/page1
    И возможно ли это?

    • Radik:

      Для этого нужно соответствующим образом настроить ваш web сервер (nginx, apache) и в kohana генерировать абсолютные ссылки (ссылки с доменным именем).

  2. Sergey:

    Спасибо за статью, мне она помогла.

  3. Денис:

    Спасибо, доходчиво, но по сравнению с роутами в CI намного сложнее ИМХО

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *