symfonyのルーティング処理の内側(sfRoute)
symfonyでのルーティング処理がどのように行われているのか、ソースを読んでみました。
ルーティングの設定は、routing.yml に記述します。
routing.yml に記述した設定は、sfRoutingConfigHandler によってパースされ、キャッシュファイルとして保存されます。(cacheディレクトリ内の config/config_routing.yml.php)
例えば routing.yml に以下のように設定したとします。
routing_test1: url: /Dir1/Dir2/:param1/:param2 param: { module: modulename, action: actionname } requirements: { param1: param\d, param2: .* }
この設定は、キャッシュファイルには以下のように書き出されています。
<?php 'routing_test1' => new sfRoute('/Dir1/Dir2/:param1/:param2', array ( 'module' => 'modulename', 'action' => 'actionname', ), array ( 'param1' => 'param\\d', 'param2' => '.*', ), array ( )) ?>
ルーティングの設定が複数ある場合は、上記の sfRoute が配列になります。
次に、sfRoute クラスのコンストラクタですが、
<?php public function __construct($pattern, array $defaults = array(), array $requirements = array(), array $options = array()) ?>
となっています。
パターンのコンパイル
sfRoute クラスで、実際に URL とルーティングパターンのマッチング処理が行われる段階で、各インスタンスが保持しているパターンのコンパイルが行われ、パターンマッチ(preg_match)を行うための正規表現が生成されます。
このコンパイルでは、以下のような処理が行われます。
- コンパイル用オプションの準備(initializeOptions())
- セグメント区切り文字('/', '.')、変数のプレフィックス(':')などが設定されます。
- トークンのパース(tokenize())
- 区切り文字に従って、保持しているパターンを分解します。
- コンパイル
上で示したパターンの場合、最終的に以下のような正規表現が生成されます。
<?php #^ /Dir1 /Dir2 /(?P<param1>param\d) /(?P<param2>.*) $#x ?>
パターンのマッチング
特定の URL が呼び出されると、symfony では保持しているルーティング一覧に対して、先頭から順にマッチング処理を行っていきます。sfRoute::matchesUrl() に URL が渡されます。
matchesUrl() 内では、コンパイル処理で生成された正規表現を使って、preg_match が実行されます。
<?php if (!preg_match($this->regex, $url, $matches)) ?>
マッチすると、URL パラメータの解析などが行われます。
パターンに「*」が含まれている場合は、parseStarParameter() により URL のパターン部分以降にあるパラメータも自動的にパースされます。
また、パターンにパラメータ名(:param1など)を記述した場合は、$matches 変数から取り出します。