CatchAll(キャッチオール)とは、全てをキャッチするということ。メールシステムなどでよく使われる。
メールシステムでの例・・・存在しないアドレス宛にメールが来たら通常はエラーメールを返す。キャッチオールを指定すると存在しないアドレス宛てに来たメールを誰がキャッチするか定義して、全てその人が受信することができる。
ウェブサーバーでの例・・・存在しないアドレスをリクエストされると、通常はステータスコード404を返す。これはそんなものはねぇというコードで「ページを表示できません」などと表示されるそれ。キャッチオールを定義すると404の代わりに特定のページを表示させることができる。これはカスタム404とは違う。通常はページに対してではなくウェブサイト定義にないサイトがリクエストされた場合や、とりあえず全部(のホスト宛の)リクエストをデフォルトのサーバーが受け付けるという利用方法が多い。
スポンサードリンク
CakePHPの動作
CakePHPではリクエストを受けるとCakePHP本体がゴニョゴニョして、その後ユーザの作成したコントローラのアクションが実行される。もし、存在しないコントローラやページがリクエストされたら、そんなものはない、と表示する。これはルーティングに関係がある。CakePHP1.3.0のデフォルトでは次のように書かれている。
Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home')); Router::connect('/pages/*', array('controller' => 'pages', 'action' => 'display'));
foo.bar.comにアクセスされたらfoo.bar.com/に転送する。foo.bar.com/は/がリクエストされたということなので、上段の定義によってpagesコントローラのdisplayアクションに引数homeで渡される。これはトップページをリクエストされたときにhome.ctpが表示されるかwebrootが表示されるかを決めているところ。
下段はpages/*とある。*がキャッチオール的なもので「全て」を意味し、/pages/hogeや/pages/fooなど全てが当てはまる。foo.bar.com/pages/hogeがリクエストされたとすれば、定義によってpagesコントローラのdisplayアクションに引数hogeで渡される。pagesコントローラはデフォルトで存在するコントローラでページを表示する機能を持っている。この場合、指定された場所にあるhoge.ctpが取り込まれCakePHPがゴニョゴニョ(ヘッダなどを付加)してページが表示される。hoge.ctpがなければそんなものはない、と表示される。
実装してみる
ここまでが基本的なCakePHPの動作。いよいよキャッチオールを作成してみる。リクエストされたものによってコントローラが呼び出され、ゴニョゴニョして結果を出す。なければCakePHPによって存在しないという表示が行われる。ある意味でこれもキャッチオールだ。今回は存在しないものをわざわざ呼び出す必要があるのでキャッチオールの必要性がでてきた。
つまり、呼び出したい形式は foo.bar.com/hoge や foo.bar.com/g0fd80s など。通常であればhogeコントローラやg0fd80sコントローラ(のindex())が呼ばれるのだが、それは存在しない。1つのコントローラがあって、そこにhogeやg0fd80sがリクエストされたぞ、ということが知りたいのだ。たぶんもっとスマートなやり方があるのだろうけど、参考文献を参考にしつつ以下のように実装してみることにする。
ルーティングに追加する
routs.phpの下部に以下の定義を追加する(例)
Router::connect('/*', array('controller' => 'urls', 'action' => 'transfer'));
(参考)ルーティングした場合としない場合の違い
ここで、ルーティングを定義した場合としない場合の違いを参考に記載しておく。
ルーティングした場合
- /hoge でアクセスした場合、 args は 1 で、 [0] => hoge となる。
- /urls/transfer/hoge/foo (コントローラとアクションを直接指定) でアクセスした場合、 args は 4 で、 [0] => urls, [1] => transfer, [2] => hoge, [3] => foo となる。つまり、直接指定してもルーティングが定義されている場合、argsに増減が生じない。
ルーティングしない場合
- /urls/transfer/hoge/foo でアクセスした場合、 args は 2 で、 [0] => hoge, [1] => foo となる。
- /urls/transfer/hoge でアクセスした場合、 args は 1 で、 [0] => hoge となる。
- /urls/transfer/ または /urls/transfer でアクセスした場合、 args は未定義となる。
コントローラを作成する
今回のコントローラは pages_controller.php をコピーして使うのが簡単。ここでは次のように作成した:
- pages_controller.php → urls_controller.php
- PagesController → UrlsController
- function display() → function transfer()
今回のテストは次のように定義している:
- /* でアクセスされたら呼ばれる
- argsは1(=args[0])に限る(=/hoge は良いが、 /hoge/foo 等は許可しない)
- args[0] を取り出す(=今回の目的=/hogeならhogeを取り出す)
- argsが1でないなら/に転送する
- Modelを使わない
- Viewを使わない
参考コード
function transfer() { $path = func_get_args(); $count = count($path); if ($count != 1) { $this->redirect('/'); } $target = $path[0]; debug($target); }
参考文献
- Custom URLs from the Site Root (Articles) | The Bakery, Everything CakePHP :
301 Moved Permanently - CakePHP’s routing explained (Articles) | The Bakery, Everything CakePHP :
301 Moved Permanently
コメント