# Zend_Controller_Router_Route_Regex

デフォルトのルートや静的なルートに加えて、正規表現によるルートも使用可能です。 このルートは他のものに比べてより強力で柔軟なものですが、 多少複雑になってしまいます。そして、より高速になります。

標準のルートと同様、このルートを初期化する際にはルートの定義とデフォルトを指定する必要があります。 サンプルとして、archive ルートを作成してみましょう。 これは先ほど定義したものとほぼ同じですが、今回は 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'
    );

関連付けは両方の方法で定義でき、任意の環境 (例. Zend_Config) で動作します。 キーには変数名あるいはサブパターン番号のいずれかを含めることができます。

    $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 を制約なしに定義することができます。 仮に、あなたが blog を持っており `http://domain.com/blog/archive/01-Using_the_Regex_Router.html` のような URL を作成したいと考えたとしましょう。 このパスの最後の要素 `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 ルートは標準のルートよりはるかに柔軟性があるということが、 ここからもわかります。