Routing

Что такое роутинг (маршрутизация)?

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

Пример маршрута.

Давайте посмотрим на простой пример того, как выглядит определение маршрута в Tanraya:

Tanraya_Controller_Router_Add::route('/users/:username/', array(
	'module'     => 'users',
	'controller' => 'users',
	'action'     => 'profile',
	':username'  => '/[-_a-z0-9]+/', // Имя пользователя должно совпадать с указанными символами
), 'username');                      // 3-й параметр (username) - это имя роута

Здесь мы видим вызов метода с тремя аргументами:

  1. Первый аргумент (обязательный) - это маска маршрута, или паттерн. Именно с ним будет сравниваться поступивший в приложение URI
  2. Второй аргумент (необязательный) - это опции маршрута. В опциях можно указать, какой модуль, контроллер или действие нужно запускать
  3. Третий аргумент (необязательный) - это имя маршрута. Имя маршрута сделано для облегчения генерации URI в шаблонах. Имя маршрута должно быть уникально

Подстрока :username в паттерне маршрута - это пользовательская макроподстановка. В опциях маршрута мы видим, что для :username
определено регулярное выражение, с которым должна совпадать подстрока из URI. Существуют так же и стандартные макроподстановки, они
нужны для облегчения написания маршрутов.

Макроподстановка должна начинаться с двоеточия и не содержать в себе пробельных символов.

Стандартные макроподстановки.

В маршрутизаторе “зашиты” стандартные макроподстановки - часто встречающиеся наборы символов. Вот какие стандартные макроподстановки есть:

Макроподстановка Рег. выражение Описание
:controller ([a-z_]+[a-z0-9_]+) Начинается с латинской буквы или подчеркивания, далее могут идти латинские буквы, цифры, подчеркивание.
:action ([a-z_]+[a-z0-9_]+)? Начинается с латинской буквы или подчеркивания, далее могут идти латинские буквы, цифры, подчеркивание.
:id (\d+)? Цифры
:any ([^/.?;*]+)? Что угодно, кроме символов-разделителей
:year (\d{4})? Четыре цифры
:month (\d{1,2})? Одна или две цифры
:day (\d{1,2})? Одна или две цифры

Все стандартные макроподстановки, кроме :controller, могут быть опущены.

Примеры маршрутов с иcпользованием стандартных макроподстановок:

  1. Tanraya_Controller_Router_Add::route('/:controller/:action/:id');
    

    Совпадет с URI: /news/show/777, /news/show, /news

  2. Tanraya_Controller_Router_Add::route('/users/:id', array(
        'controller' => 'users'
    ));
    

    Совпадет с URI: /users/555, /users/

  3. Tanraya_Controller_Router_Add::route('/news/:year/:month/:day', array(
        'controller' => 'news',
        'action'     => 'show_by_date'
    ));
    

    Совпадет с URI: /news/2009/01/28, /news/2009/01, /news/2009

Разделители в URI

Символы “/”, “.”, “?”, “;” в URI являются разделителями.

Метод запроса

По-умолчанию для всех маршрутов устанавливается метод запроса any. Это означает, что маршрут будет срабатывать
для любых запросов, переданных методами GET, POST, PUT, DELETE. Если хочется, чтобы маршрут срабатывал только для определенного
типа запроса, необходимо в опциях маршрута указать метод, вот так:

// Этот маршрут будет совпадать только тогда, когда на /users/:id приходит POST запрос.
Tanraya_Controller_Router_Add::route('/users/:id', array(
    'method' => 'post'
));

Поддержка REST

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

$blog = Tanraya_Controller_Router_Add::resource('blog');
Tanraya_Controller_Router_Add::resource('comments', $blog);

Всего эти 2 строчки сгенерируют нам 14 маршрутов:

Array
(
    [0] => Array
        (
            [0] => /blog/
            [1] => Array
                (
                    [controller] => blog
                    [method] => get
                )
            [2] => blog
            [3] => Array
                (
                )
        )
    [1] => Array
        (
            [0] => /blog/:id/
            [1] => Array
                (
                    [controller] => blog
                    [action] => show
                    [method] => get
                )
            [2] => blog_show
            [3] => Array
                (
                )
        )
    [2] => Array
        (
            [0] => /blog/new/
            [1] => Array
                (
                    [controller] => blog
                    [action] => new
                    [method] => get
                )
            [2] => blog_new
            [3] => Array
                (
                )
        )
    [3] => Array
        (
            [0] => /blog/
            [1] => Array
                (
                    [controller] => blog
                    [action] => create
                    [method] => post
                )
            [2] => blog_create
            [3] => Array
                (
                )

        )
    [4] => Array
        (
            [0] => /blog/:id/edit/
            [1] => Array
                (
                    [controller] => blog
                    [action] => edit
                    [method] => get
                )
            [2] => blog_edit
            [3] => Array
                (
                )
        )
    [5] => Array
        (
            [0] => /blog/:id/
            [1] => Array
                (
                    [controller] => blog
                    [action] => update
                    [method] => put
                )
            [2] => blog_update
            [3] => Array
                (
                )
        )
    [6] => Array
        (
            [0] => /blog/:id/
            [1] => Array
                (
                    [controller] => blog
                    [action] => destroy
                    [method] => delete
                )
            [2] => blog_destroy
            [3] => Array
                (
                )
        )
    [7] => Array
        (
            [0] => /blog/:blog_id/comments/
            [1] => Array
                (
                    [controller] => comments
                    [method] => get
                    [:blog_id] => /(\d+)/
                )
            [2] => comments
            [3] => Array
                (
                    [0] => blog
                )
        )
    [8] => Array
        (
            [0] => /blog/:blog_id/comments/:id/
            [1] => Array
                (
                    [controller] => comments
                    [action] => show
                    [method] => get
                    [:blog_id] => /(\d+)/
                )
            [2] => comments_show
            [3] => Array
                (
                    [0] => blog
                )
        )
    [9] => Array
        (
            [0] => /blog/:blog_id/comments/new/
            [1] => Array
                (
                    [controller] => comments
                    [action] => new
                    [method] => get
                    [:blog_id] => /(\d+)/
                )
            [2] => comments_new
            [3] => Array
                (
                    [0] => blog
                )
        )
    [10] => Array
        (
            [0] => /blog/:blog_id/comments/
            [1] => Array
                (
                    [controller] => comments
                    [action] => create
                    [method] => post
                    [:blog_id] => /(\d+)/
                )
            [2] => comments_create
            [3] => Array
                (
                    [0] => blog
                )
        )
    [11] => Array
        (
            [0] => /blog/:blog_id/comments/:id/edit/
            [1] => Array
                (
                    [controller] => comments
                    [action] => edit
                    [method] => get
                    [:blog_id] => /(\d+)/
                )
            [2] => comments_edit
            [3] => Array
                (
                    [0] => blog
                )
        )
    [12] => Array
        (
            [0] => /blog/:blog_id/comments/:id/
            [1] => Array
                (
                    [controller] => comments
                    [action] => update
                    [method] => put
                    [:blog_id] => /(\d+)/
                )

            [2] => comments_update
            [3] => Array
                (
                    [0] => blog
                )
        )
    [13] => Array
        (
            [0] => /blog/:blog_id/comments/:id/
            [1] => Array
                (
                    [controller] => comments
                    [action] => destroy
                    [method] => delete
                    [:blog_id] => /(\d+)/
                )

            [2] => comments_destroy
            [3] => Array
                (
                    [0] => blog
                )
        )
)

Продолжение следует.