ドキュメントとコードリーディングだけであまり動作確認してないので事実と異なるかもしれない.
デフォルトルーティング
DI に何も設定しない場合, DI で Phalcon\Mvc\Router
が設定されたものをつかう.
( Router のコンストラクタで true を指定する)router.c#L238
Routerのコンストラクタに true が指定された場合には Route が二つ登録されるようになっており下記二つとなっている.
- /:controller/:action
- /:controller/:action/:params
モジュールを使っている場合( config/modules.php などで registerModules()
をしている場合)はおそらくデフォルトモジュールが設定されていないのでいろいろ方法はあると思うが下記のように対応するのが簡単だと思う.
- 設定するモジュールが一つの場合は
Router#setDefaultModule()
して使用するモジュールを固定する - 下記のように URI 自体にモジュールを必要とする設定を追加する.ちなみに第二引き数の数字は URI の正規表現のグループで一致したグループ番号.ルーティングの定義
$router->add('/:module/:controller/:action', [
'module' => 1,
'controller' => 2,
'action' => 3,
]);
ルーティング設定の追加方法
もう上で書いてしまったけど簡単には Router#add()
を使う.また Phalcon\Mvc\Router\Group#add()
でグループ毎に設定してから Router#mount()
でグループごと一気に追加する方法などもあるはず.
add()
は Phalcon\Mvc\Router\Route
を返すので後述する beforeMatch()
や convert()
などを使うメソッドチェーンなどが使える.
実行タイミング
Router#handle() で Route が一致するかの処理をするときの動きの擬似コード.
(Application 内)
application:boot
(Router 内)
remove_extra_shashes が設定されていれば除く
foreach ルートのリスト
HTTP メソッドのチェック
Hostname のチェック
パスが一致するかのチェック
beforeMatch()
converter()
Route がなければ notFound を設定
application:beforeStartModule
ここで registerAutoloaders() や registerServices() が呼ばれる
application:afterStartModule
もろもろあって Dispatcher#dispatch()
モジュールの読み込みが Router の動作後なのでおそらくモジュール単位でのルーティング設定はモジュール単位での動作に移った後にはできなさそうな雰囲気.
モジュールごとに定義したい場合は Phalcon\Mvc\Router\Group
を使ってそれぞれまとめておき,それをプロジェクト全体のところで呼び出すような形で実装するのがよい?
beforeMatch について
Palcon\Mvc\Router#add()
の返り値が Phalcon\Mvc\Router\Route
オブジェクトになるわけだが,これに beforeMatch()
でコールバックを指定すると URI によるマッチだけでなくほかにもいろいろな条件でマッチさせられるらしい.
また, Phalcon\Mvc\Router\Group
にも beforeMatch()
は設定できるが,これはそのグループに登録されている全てのルートに対してそれぞれ beforeMatch()
が設定されていることと同じと考えてよさそう.ただし Group
側に記述している場合はルート個々に設定する beforeMatch()
は Router#mount()
の時点でおそらく上書きされる. router.c#L1187
マッチング時のコールバックには第三引き数の存在は書かれていないが下記のようにコールバックを設定できる様子. Phalcon\Mvc\Router
は Phalcon\DI\InjectionAwareInterface
を実装しているため URI
によるマッチだけでなく request などを取ってきて GET パラメータによるルーティングなども可能の様子.
$uri
は現在チェック中の URI で $route
は beforeMatch()
が設定されるその Route オブジェクトで $router
はその Route
が設定されてる Router
オブジェクト.router.c#L769
/**
* Registering a router
*/
$di['router'] = function () use ($di) {
$router = new Router(true);
$router->add('/admin/index', array(
'module' => 'backend',
'controller' => 'admin',
'action' => 'index'
))->beforeMatch(function ($uri, $route, $router) {
// なんか処理する(例えば is_match パラメータが true のときだけとか)
$isMatch = $router->getDI()->get('request')->get('is_match', null, 'false');
return $isMatch === 'true';
});
beforeMatch()
ではマッチの結果として true/false しか返せ無さそうだし上記の「実行タイミング」を見てもらえればわかるが Dispacher
の処理の前なのでここで ACL 噛ませて forward()
や redirect()
は筋が悪そうな気がする.(実際には動きそう)
convert について
ルーティングパラメータの変換 に書いてある.第二引き数で指定したキーの名前に対して変換処理などを行うことができる.これは第二引き数に指定したものがコンバート対象となるだけな様子なので,例えば module をコンバート対象にした場合第二引き数に指定されていれば convert が起動するし指定せずに setDefaultModule()
で設定されたものが選択された場合は convert は起動しない.またワイルドカードなどで指定できるわけではないので一気に変換等はできなさそう.
ここを使えば例えば symfony1.4 の sfDoctrineRoute
のようなものが実現できる気がする.
参考文献
ルーティング — Phalcon 1.3.1 documentation
動作とかは大抵ソース見てた
phalcon/cphalcon