ルーティングはどのフレームでも似ていますが、やはり違いがあるものです。ちょっとした所ではまりがちですね。
高度なルーティングは、まだ試していませんが、今回使っている機能で、理解した内容を残しておきます。
まず、うまく行かない時のデバックのコツですが、ズバリ、echo Debug::dump($this);、これに限ります。情報をたっぷり出してくれるので、自分の考え違いに、直ぐ気が付きます。お試しください。
それでは内容です。
デフォルトの_root_と、ルーティングが見つからない時の_404_は簡単に理解できますね。
上記の2つ以外は、定義した順番に一致するか検査され、一致するものが見つかったら、それが実行され、以降のルーティング条件は検査されません。
つまり、場合によっては/で区切られているセグメントの数とかを、考慮しなくてはならないということです。これはセグメントの最後が名前付きパラメータを付ける場合に、特に重要です。
名前付きパラメーターとは、自分の好きな名前をルーティングの定義に指定しておき、ルーティングされたアクションの中で、引き出せるというものです。名前付きパラメーターの先頭は、':'、コロンで始まります。
':year/:month' => 'calendar/show'と定義したばあい、calendarコントローラークラスのなかのaction_show()関数中に飛ばされますが、その時に$this->param('year')と$this->param('month')で、セグメントの中身が参照できます。
名前付きパラメーターは、とても欲張りです。可能な限り長くマッチしてしまいます。
もし、セグメントの数によって、動作を変えたい場合、次のように設定しても、動きません。
':year' => 'calendar/yearly',
':year/:month' => 'calendar/monthly',
':year/:month/:day => 'calendar/daily',
実は、一つ以上のセグメントを付けた場合、最初の':year'が全セグメントと一致してしまいます。つまり、calendarクラスのaction_yearlyが実行され、$this->param('year')が付けたセグメント全部を指し示します。
ですから、指定する順番を逆にするのが正解です。
':year/:month/:day => 'calendar/daily',
':year/:month' => 'calendar/monthly',
':year' => 'calendar/yearly',
更に、問題が続きます。この例では3つのセグメントを取り扱っていますが、4つ以上セグメントを付けられた場合、通常は404のアクションが実行されることを期待しますが、そうなりません。上記の例の場合、最初の3つのセグメントのアクション、calendarクラスの、dailyアクションが実行され、$this->param('day')に3つ目以降のセグメント全部が入ってしまいます。ですから、名前付きパラメーターを利用し、かつ指定した数以上のパラメーター指定で、404のアクションを取りたいときは、次のようになります。
':arga/:argb/:argc/:argd' => 'errorpage/404' // 明示的にエラーページへ
':year/:month/:day => 'calendar/daily',
':year/:month' => 'calendar/monthly',
':year' => 'calendar/yearly',
こうすれば、4つ以上のパラメーターで、404のアクションがおこなわれます。
私が今回行ったのは、セグメントの数が1,2,3の時は、それぞれ別のアクションを取り、4つ指定される場合は、それは数字の場合のみ特定のアクションを行い、4つでも4つ目が数字でなければ、404にしました。
この例を含め、一般的にはこんな感じに定義することになるでしょう。
'_root' => 'home/index', // パラメーターが無い、デフォルトのルーティング
'_404_' => 'error/404', // ルーティングに一致しない、404状態のルーティング
'login' => 'auth/login', // セグメント1つ指定の呼び出し
'logout' => 'auth/logout', // ただし、名前付きパラメーターは
'signup' => 'auth/register', // あとでまとめて指定する
'home' => 'home/index', // こうした、名前付きパラメーターや
'about' => 'home/about', // :anyを使わない限り、順番は適当に
'update/(:num)' => 'post/update/$1', // パラメーター2つ
'userdate/(:alnum)' => 'user/show/$1', // :numや:alnumは名前付きパラメータではない'(\d{2})/about' => 'site/about/$1', // 正規表現も使えます
// これ以降は名前付きパラメーター
':areaa/:areab/:areac/(:num)', 'map/check/$1',
':dmya/:dmyb/:dmyc/:dmyd', => 'error/404', // 明示的にエラー処理へ
':year/:month/:day => 'calendar/daily',
':year/:month' => 'calendar/monthly',
':year' => 'calendar/yearly',
:numや:alnumは名前付きパラメーターではありません。:numが数字、:alphaは英文字、:alnumは英数字へ一致します。どんな文字にでも一致させたいときは:segment、それ以降、全部のセグメント=パラメーターと一致させたいときは、:anyを使います。(たしかkohanaと同じ設計ですね)ですから、必然的に:anyは一番最後のセグメントに指定します。(追記::anyが最後に来ると書きましたが、間違いでした。Kohanaと同一視していました。例えば、'abc/(:any)/xyz'と書くことで、セグメントの最初がabcで最後がxyzに一致させることが可能です。ただし、2つの間には、一つ以上のセグメントが必要です。'abc/xyz'には一致しません。)
実は、:segmentと:anyはまだ確かめていません。たぶん、:anyを使用する場合、名前付きパラメーターと同じ問題が起きます。対処しましょう。
迷ったときは最初に書いたとおり、echo Debug::dump($this);がとても役に立ちますよ。
表示される内容中、単数形の'path'はどのパターンに一致したか、つまり各条件の左側のキーの文字列を示しています。そのpath以降に表示される行も、見てもらえれば、何を意味しているか、理解できるでしょう。
ルーティングを試すために小さなコードを書くという手もあります。
class Controller_Routetest extend Controller {
function action_index() {
Debug::dump($this->request->route);
}
}
あとは、routes.phpでアクション/コントローラーの指定を全部一時的に'routetest/index'を指定すれば、どのパスが適用されたのか、一目瞭然です。
追記:本家フォーラムに問題を上げて見ました。時間がある方は、チャレンジしてみてください。How to learn fuelphp routing
追記:名前付きパラメータには数字が使えませんでした。修正しました。
追記:名前付きパラメータ使用時に、throw new HttpNotFoundException;で404へ転送されず、名前付きパラメーターで指定した個所にマッチしてしまうバグがありました。フォーラムには投稿しておきました。
| Fuelphp、大文字URIのバグ< 前 | 次 >Fuelphp、コードテスターに保存機能をつけて見ました |
|---|
| < 前 | 次 > |
|---|