# Zend_Controller_Router_Route_Regex

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

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

    $route = new Zend_Controller_Router_Route_Regex(
        'archive/(\d+)',
        array(
            'controller' => 'archive',
            'action'     => 'show'
        )
    );
    $router->addRoute('archive', $route);

Каждый определенный подшаблон регулярного выражения будет внедрен в объект запроса. В нашем примере после успешного сопоставления с `http://domain.com/archive/2006` результирующий массив значений может выглядеть следующим образом:

    $values = array(
        1            => '2006',
        'controller' => 'archive',
        'action'     => 'show'
    );

Ведущая и замыкающая косые черты удаляются из URL в маршрутизаторе до сопоставления. Поэтому URL-у `http://domain.com/foo/bar/` будет соответствовать регулярное выражение `foo/bar`, но не `/foo/bar`.

Указатели начала и конца строки ('^' и '$' соответственно) автоматически добавляются в начало и конец всех выражений. Поэтому вы не должны использовать их в своих регулярных выражениях, кроме этого, следует передавать строку выражения целиком.

Этот класс маршрута использует символ `#` в качестве ограничителя. Это означает, что нужно экранировать символы хэша ('#'), но не прямой косой черты ('/') в своем определении маршрута. Поскольку символ '#' (называемый анкером) редко передается веб-серверу, вам нечасто придется использовать этот символ в своем регулярном выражении.

Вы можете получать содержимое заданного подшаблона обычным способом:

    public function showAction()
    {
        $request = $this->getRequest();
        $year    = $request->getParam(1); // $year = '2006';
    }

Обратите внимание, что ключ является целым числом (1), а не строкой ('1').

Этот маршрут не будет работать в точности так же, как и аналогичный ему стандартный маршрут, потому что еще не определено значение по умолчанию для 'year'. Есть еще неочевидная проблема с замыкающей косой чертой, которая остается даже в том случае, если мы объявим значение по умолчанию для 'year' и сделаем подшаблон опциональным. Решение состоит в том, чтобы сделать часть 'year' опциональной вместе с косой чертой, но отлавливать только число:

    $route = new Zend_Controller_Router_Route_Regex(
        'archive(?:/(\d+))?',
        array(
            1            => '2006',
            'controller' => 'archive',
            'action'     => 'show'
        )
    );
    $router->addRoute('archive', $route);

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

    $route = new Zend_Controller_Router_Route_Regex(
        'archive/(\d+)',
        array(
            'controller' => 'archive',
            'action' => 'show'
        ),
        array(
            1 => 'year'
        )
    );
    $router->addRoute('archive', $route);

Это приведет к тому, что в объект запроса будут добавлены следующие значения:

    $values = array(
        'year'       => '2006',
        'controller' => 'archive',
        'action'     => 'show'
    );

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

    $route = new Zend_Controller_Router_Route_Regex(
        'archive/(\d+)',
        array( ... ),
        array(1 => 'year')
    );

    // ИЛИ

    $route = new Zend_Controller_Router_Route_Regex(
        'archive/(\d+)',
        array( ... ),
        array('year' => 1)
    );

Ключи подшаблонов должны быть представлены целыми числами.

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

    $route = new Zend_Controller_Router_Route_Regex(
        'archive/(\d+)/page/(\d+)',
        array( ... ),
        array('year' => 1)
    );

Это приведет к тому, что в объекте запроса будут значения с разными ключами. Например, при URL `http://domain.com/archive/2006/page/10` результатом будут следующие значения:

    $values = array(
        'year'       => '2006',
        2            => 10,
        'controller' => 'archive',
        'action'     => 'show'
    );

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

    $route = new Zend_Controller_Router_Route_Regex(
        'archive/(\d+)',
        array( ... ),
        array('year' => 1),
        'archive/%s'
    );

Все это можно реализовать через объект стандартного маршрута, поэтому вы спросите - какие преимущества дает использование маршрута Regex? Главным образом, он позволяет описывать любые типы URL без всяких ограничений. Предположим, у вас есть свой блог, вы хотите создавать URL вида `http://domain.com/blog/archive/01-Using_the_Regex_Router.html` и должны разлагать последний элемент пути `01-Using_the_Regex_Router.html` на ID статьи и ее заголовок/описание. Это невозможно реализовать с помощью стандартного маршрута. С маршрутом Regex вы можете сделать нечто подобное для решения этой задачи:

    $route = new Zend_Controller_Router_Route_Regex(
        'blog/archive/(\d+)-(.+)\.html',
        array(
            'controller' => 'blog',
            'action'     => 'view'
        ),
        array(
            1 => 'id',
            2 => 'description'
        ),
        'blog/archive/%d-%s.html'
    );
    $router->addRoute('blogArchive', $route);

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