ZendFramework2ガイド

入門編

ルーティングを知る

URLとコントローラークラスの関係

多くのMVCフレームワークでは全てのアクセスはindex.phpにリライトする事を前提に動作するようになっています。
これはZend2でも同じです。そしてリクエストされたURLのパスをもとにして実行させるコントローラークラスを決定する仕組みになっています。
これをルーティングと呼んでいますが、Zend2の場合は、ルーティング方法をmodule.config.phpに記載し、その設定にしたがってルーティングが行われる仕組みになっています。
この設定とはURLとクラスのマッピングであり、単純にリクエストURLのパスと実行するクラスメソッドの組合せを配列の形式で定義するというものです。

パスセグメントのワイルドカードマッチングによるルーティング(Segment)

実際のアプリケーションでは、膨大な数のページ全てについていちいちルーティング設定を記述していくのは大変です。
そこで、デフォルトの設定でもそうなっているように、URLのパスセグメントがそのままルーティング先のクラスを表すような設定が可能です。

ルーティングの設定はmodule/Ec/config/module.config.phpの中の以下の部分です。

module/Ec/config/module.config.php
    'router' => array(
        'routes' => array(
            'home' => array(
                'type' => 'Zend\Mvc\Router\Http\Literal',
                'options' => array(
                    'route'    => '/',
                    'defaults' => array(
                        'controller' => 'Ec\Controller\Index',
                        'action'     => 'index',
                    ),
                ),
            ),
            'application' => array(
                'type'    => 'Literal',
                'options' => array(
                    'route'    => '/ec',
                    'defaults' => array(
                        '__NAMESPACE__' => 'Ec\Controller',
                        'controller'    => 'Index',
                        'action'        => 'index',
                    ),
                ),
                'may_terminate' => true,
                'child_routes' => array(
                    'default' => array(
                        'type'    => 'Segment',
                        'options' => array(
                            'route'    => '/[:controller[/:action]]',
                            'constraints' => array(
                                'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
                                'action'     => '[a-zA-Z][a-zA-Z0-9_-]*',
                            ),
                            'defaults' => array(
                            ),
                        ),
                    ),
                ),
            ),
        ),
    ),

この中の以下の部分はドメインのルート、つまりパスが/へのアクセスの場合のルーティング設定です。

            'home' => array(
                'type' => 'Zend\Mvc\Router\Http\Literal',
                'options' => array(
                    'route'    => '/',
                    'defaults' => array(
                        'controller' => 'Ec\Controller\Index',
                        'action'     => 'index',
                    ),
                ),
            ),

'route'の部分が、'/'となっているので、URLのパスとして'/'にアクセスされた場合に適用される設定ということになります。
この場合、Ec\Controller\IndexControllerがルーティング先のコントローラークラスで、
その中のindexActionメソッドが呼び出される、という事になります。
試しにブラウザからドメインルートへアクセスしてみてください。
「Welcome to Zend Framework 2」
のページが表示されます。

次に、 'application' => array(
以下の部分です。
ここではまず、'route'が'/ec'となっているため、URLのパスが'/ec'にアクセスされた時のルーティング設定ということになります。

ルーティング先の設定は、

                    'defaults' => array(
                        '__NAMESPACE__' => 'Ec\Controller',
                        'controller'    => 'Index',
                        'action'        => 'index',
                    ),

となっていますが、これは先ほどの、

                    'defaults' => array(
                        'controller'    => 'Ec\ControllerIndex',
                        'action'        => 'index',
                    ),

と同じ意味であると考えてください。
'Ec\Controller\Index'というのは、'Ec\Controller'名前空間の中のIndexという意味なので、結果的には同じなわけです。
次に、

                'child_routes' => array(
                    'default' => array(
                        'type'    => 'Segment',
                        'options' => array(
                            'route'    => '/[:controller[/:action]]',
                            'constraints' => array(
                                'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
                                'action'     => '[a-zA-Z][a-zA-Z0-9_-]*',
                            ),
                            'defaults' => array(
                            ),
                        ),
                    ),
                ),

の部分ですが、
child_routesと言う名の通り、
URLのパスが'/ec’で始まる場合の、'/ec’以下のパスセグメントの扱いの定義です。

'route'が'/[:controller[/:action]]'となっているのは、
[]で囲われている部分のセグメントはパスとして存在していても存在していなくてもマッチする事を表します。
つまり、
/ecはマッチするし、/ec/aaaもマッチします。
更に[]の中に[]が存在しているため、/ec/aaaでも/ec/aaa/bbbでもマッチすることになります。

そして:controllerとなっているのは、パスのそのセグメント部分(この設定の場合はパスの第2セグメントに当たります)が、
コントローラークラスを表すキーであるということになります。
同じように、第3セグメントはアクションメソッドを表すキーとなります。
つまり、/ec/aaa/bbbへアクセスされた場合、
Ec\Controller\AaaControllerクラスのbbbActionメソッドへルーティングされます。

                            'constraints' => array(
                                'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
                                'action'     => '[a-zA-Z][a-zA-Z0-9_-]*',
                            ),

の部分は、:controllerと:actionの部分のそれぞれ指定可能な文字種を指定しています。
これに適合しない場合はnot foundとなります。

全てのルーティング設定を個別に設定する(Literal)

Segmentを利用したルーティングは、一つ定義しておくだけで、全てのURLパスに対応でき、非常に楽です。
しかしこの場合、URLとクラス名やメソッド名が直結し、URLがそのままクラス名メソッド名を表すことになってしまい、密な関係になってしまいます。

そこで、やはり一つ一つを設定する方法について解説します。
ルーティングの設定としては最も単純であるとも言えます。

実は、デフォルトの設定の以下の部分はそれにあたります。

            'home' => array(
                'type' => 'Zend\Mvc\Router\Http\Literal',
                'options' => array(
                    'route'    => '/',
                    'defaults' => array(
                        'controller' => 'Ec\Controller\Index',
                        'action'     => 'index',
                    ),
                ),
            ),

これは、'/'に汗クスされた時にはEc\Controller\Indexコントローラーのindexアクションへルーティング、という設定ですが、
同様にあらゆるアクセスパスに対しての設定を追加していく感じです。

例えばこうです。

            'literal1' => array(
                'type' => 'Zend\Mvc\Router\Http\Literal',
                'options' => array(
                    'route'    => '/aaa/bbb',
                    'defaults' => array(
                        'controller' => 'Ec\Controller\Aaa',
                        'action'     => 'bbb',
                    ),
                ),
            ),
            'literal2' => array(
                'type' => 'Zend\Mvc\Router\Http\Literal',
                'options' => array(
                    'route'    => '/ccc/ddd',
                    'defaults' => array(
                        'controller' => 'Ec\Controller\Xxx',
                        'action'     => 'yyy',
                    ),
                ),
            ),

2つのルーティング設定例を記述しましたが、
一つ目は'/aaa/bbb'へのアクセスはEc\Controller\Aaaコントローラーのbbbアクションへルーティングという設定で、
URLパスとルーティング先のクラス、メソッド名が一致しています。
ですが2つ目は'/ccc/ddd'へのアクセスはEc\Controller\Xxxコントローラーのyyyアクションへルーティングとなっています。
URLパスとクラス、メソッド名が全く一致していません。

これらはどちらも正しいルーティング設定です。
前者はたまたま一致するような設定にした、後者はそうはしなかった、というだけのことで、
リクエストURLとルーティング先のクラス名メソッド名が直結しません。
そのため、柔軟なルーティング設定が可能になります。

実際は全ての想定されるリクエストURLに対して設定を記述すると膨大な設定量となるため、
基本はSegmentで、場合により、Literalを利用するという使い方が現実的かもしれません。