3.4.5 Routesの設定
Routingは、URLをコントローラのアクションに結びつける(map) する機能です。URL の見ばえをよくし(pretty URL)、より柔軟に設定できるよう、CakePHP に備わっています。routes を使うために Apache の mod_rewrite が必ず必要というわけではありませんが、mod_rewrite を使用すると、アドレスバーに表示される URL が整ったものになります。
CakePHP 1.2 の Routes は機能が拡張され、非常にパワフルです。
3.4.5.1 デフォルトのルーティング
独自のルートを設定する前に、CakePHP のデフォルトのルートについて知っておく必要があります。CakePHP のデフォルトルーティングによって、どんなアプリケーションでもうまく動くようになっています。URL の中に、アクション名を置くことで、アクションに直接アクセスすることができます。コントローラのアクションに URL を使うことでパラメータを渡すこともできます。
デフォルトのroutesのURLパターン:
http://example.com/コントローラ名/アクション名/パラメータ1/パラメータ2/パラメータ3
/posts/view という URL は、PostsController の view() アクションにマップされます。 /products/viewClearance は、ProductsController の view_clearance() アクションにマップされます。URL でアクション名が指定されていない場合には、index() メソッドが用いられます。
デフォルトのルーティングでは、URLを使ってアクションにパラメータを渡すこともできます。例えば、/posts/view/25 というリクエストは、PostsController 上で view(25) として呼ぶのと同じことになります。
3.4.5.2 名前付きのパラメータ
CakePHP 1.2 の新機能には、パラメータに名前を付けられる、というものがあります。URL を使ってパラメータに名前を付けて、その値を渡すことができます。/posts/view/title:first+post/category:generalというリクエストでは、PostsController の view() アクションが呼ばれます。このアクションでは、title と category というパラメータの値を、それぞれ、$this->passedArgs[‘title’] と $this->passedArgs[‘category’] として受け取ることができます。
参考例としていくつか挙げてみます。
デフォルトのルーティングを使用した、URL からコントローラへのアクションマッピング:
URL: /monkeys/jump
Mapping: MonkeysController->jump();
URL: /products
Mapping: ProductsController->index();
URL: /tasks/view/45
Mapping: TasksController->view(45);
URL: /donations/view/recent/2001
Mapping: DonationsController->view('recent', '2001');
URL: /contents/view/chapter:models/section:associations
Mapping: ContentsController->view();
$this->passedArgs['chapter'] = 'models';
$this->passedArgs['section'] = 'associations';
3.4.5.3 Routes の定義
独自ルートの定義により、アプリケーションを指定した URL で動作させることができるようになります。独自のルーティングは、/app/config/routes.php ファイルの Router::connect() メソッドを使用して定義します。
connect() メソッドは3つのパラメータからなっています。対応させたい URL、カスタムルートのデフォルトの値、要素と対応させるための正規表現ルールです。
ルート定義の基本形式は次のようになります。:
Router::connect(
'URL',
array('paramName' => 'デフォルト値'),
array('paramName' => '正規表現')
)
Router::connect('URL',array('paramName' => 'デフォルト値'),array('paramName' => '正規表現'))
最初のパラメータで、制御する URL をルータ(Router)に伝えます。URL は、通常のスラッシュで分けられた文字列です。しかし、ワイルドカード(*)や、独自の route 要素(コロンで始まる URL 要素)を含むことができます。ワイルドカードで対応させたい URL を指定し、route 要素の指定で、コントローラアクションのためのパラメータを集めることができます。
URLを指定した後、connect() の次の2つのパラメータを使って、リクエストが対応した場合に何を行うのかを CakePHP に伝えます。2番目のパラメータは連想配列です。配列のキーは、URL の route 要素にちなんだものか、デフォルト要素(:controller, :action, :plugin)にしてください。配列内の値は、それらのキーに対するデフォルト値です。3番目のパラメータを考える前に基本的な例をいくつか見てみましょう。
Router::connect(
'/pages/*',
array('controller' => 'pages', 'action' => 'display')
);
Router::connect('/pages/*',array('controller' => 'pages', 'action' => 'display'));
CakePHP の routes.php ファイルの中(40行目)に、この route が書かれています。このルートは、/pages/ ではじまるすべての URL にマッチし、それを PagesController の display()メソッドに渡します。例えば、/pages/products というリクエストは、PagesController->display(‘products’) にマップされます。
Router::connect(
'/government',
array('controller' => 'products', 'action' => 'display', 5)
);
Router::connect('/government',array('controller' => 'products', 'action' => 'display', 5));
この2つ目の例は、connect() の2番目のパラメータでデフォルトパラメータを定義する方法を示しています。それぞれのお客様向けに異なる製品がある場合などに route を作成することを考えることができるでしょう。この例では、/products/display/5 としなくても、/government という URL でアクセスできるようになります。
さらに柔軟な追加機能として、カスタム route 要素を指定できます。この機能により、コントローラアクション用のパラメータが、URL のどこにあるのかを定義できるようになります。リクエストがあると、このカスタム route 要素は、コントローラの $this->params の中に入ります。これは、パラメータに名前を付けるのとは異なる仕方で扱われます。違いに注意してください。パラメータに名前を付けた(/コントローラ/アクション/名前:値)ものは、$this->passedArgs の中に入りますが、カスタム route 要素のデータは、$this->params の中に入ります。カスタム route 要素を定義する際には、正規表現によって、URL が正しく作られているか、作られていないかを CakePHP が判断できるようにします。
Router::connect(
'/:controller/:id',
array('action' => 'view'),
array('id' => '[0-9]+')
);
Router::connect('/:controller/:id',array('action' => 'view'),array('id' => '[0-9]+'));
これは、/コントローラ名/id という形で、どんなコントローラからでもモデルを表示(view)できるようにする例です。connect() に指定されている URL には2つの route 要素があります。:controller と :id です。:controller 要素は、CakePHP のデフォルト route 要素です。ルータは URL 内のコントローラ名を見つけることができます。:id 要素はカスタム route 要素なので、connect() の3番目のパラメータ内の正規表現で、どうやってマッチさせるのかを明示する必要があります。こうすることで、CakePHP はアクション名ではないと区別でき、URL 内の ID を見つけることができます。
この route が定義されると、/apples/5 というリクエストは、/apples/view/5 としたのと同じことになります。どちらも、ApplesController の view() メソッドを呼びます。view() メソッド内では、$this->params[‘id’] を使って渡された ID を知ることができます。
この例も知れば、routing の達人です。
Router::connect(
'/:controller/:year/:month/:day',
array('action' => 'index', 'day' => null),
array(
'year' => '[12][0-9]{3}',
'month' => '(0[1-9]|1[012])',
'day' => '(0[1-9]|[12][0-9]|3[01])'
)
);
Router::connect('/:controller/:year/:month/:day',array('action' => 'index', 'day' => null),array('year' => '[12][0-9]{3}','month' => '(0[1-9]|1[012])','day' => '(0[1-9]|[12][0-9]|3[01])'));
ややこしいものですが、route が非常に強力であることを示す例です。この URL では、4つの要素があります。最初のものはよく知っているもので、まずコントローラ名が来ることを CakePHP に伝えます。
次に、いくつかのデフォルト値を指定します。コントローラ名に関係なく、index() アクションが呼ばれるようにします。そして、day パラメーター(URL の4つ目の要素)のデフォルト値を null として、これがオプションであることを設定します。
最後に、年(year)、月(month)、日(day)の数値にマッチする正規表現を指定します。
設定すると、この route は、/articles/2007/02/01、/posts/2004/11/16、/products/2001/05 (day パラメータは、オプション)といった URL にマッチするようになります。対応するコントローラの index() アクションに渡し、$this->params の中にはカスタム指定した日付パラメータを入れます。
3.4.5.4 アクション(action)にパラメータを渡す
アクション(action)が次のように定義されていて、$this->params['id'] の代わりに $articleID を使用して引数を受け取りたいと仮定します。ただ、Router::connect() の第3引数に特別な配列(array)を追加するだけです。
// some_controller.php
function view($articleID = null, $slug = null) {
// ここに何かしらコードを書く
}
// routes.php
Router::connect(
// E.g. /blog/3-CakePHP_Rocks
'/blog/:id-:slug',
array('controller' => 'blog', 'action' => 'view'),
array(
// これは単にアクション(action)で ":id" を $articleID にマッピングするため、順番は重要です。
'pass' => array('id', 'slug'),
'id' => '[0-9]+'
)
)
// some_controller.phpfunction view($articleID = null, $slug = null) {// ここに何かしらコードを書く}// routes.phpRouter::connect(// E.g. /blog/3-CakePHP_Rocks'/blog/:id-:slug',array('controller' => 'blog', 'action' => 'view'),array(// これは単にアクション(action)で ":id" を $articleID にマッピングするため、順番は重要です。'pass' => array('id', 'slug'),'id' => '[0-9]+'))
これで逆のルーティング機能が追加されたので、以下のように url 配列に渡すことができます。ルートで定義されているので、 Cake は URL をどのように作成したらよいかがわかっています。
// view.ctp
// これは /blog/3-CakePHP_Rocks へのリンクを返すでしょう
<?= $html->link('CakePHP Rocks', array(
'controller' => 'blog',
'action' => 'view',
'id' => 3,
'slug' => Inflector::slug('CakePHP Rocks')
)) ?>
// view.ctp// これは /blog/3-CakePHP_Rocks へのリンクを返すでしょう<?= $html->link('CakePHP Rocks', array('controller' => 'blog','action' => 'view','id' => 3,'slug' => Inflector::slug('CakePHP Rocks'))) ?>
3.4.5.5 プリフィックスルーティング(Prefix Routing)
たいていのアプリケーションには、権限のあるユーザだけが情報を変更できる管理画面が必要です。そのために/admin/users/edit/5 のような特別な URL を準備することがよくあります。CakePHP では、コア設定ファイル内の Routing.admin に管理パスを設定して admin ルーティングを有効にできます。
Configure::write('Routing.admin', 'admin'); Configure::write('Routing.admin', 'admin');
コントローラ(controller)内では、プリフィックスとして admin_ をメソッドの前につけたすべてのアクション(action)が呼び出されます。usersを例にすると、/admin/users/edit/5というURLへのアクセスで、UsersControllerのadmin_editメソッドが、引数5で呼び出されます。
URL /admin を、pagesコントローラのadmin_index アクションにマップするには次のような route を使います。
Router::connect('/admin', array('controller' => 'pages', 'action' => 'index', 'admin' => true)); Router::connect('/admin', array('controller' => 'pages', 'action' => 'index', 'admin' => true));
Routerを使って、adminルーティングよりもより複雑な、カスタムプレフィックスを使うことも可能です。
Router::connect('/profiles/:controller/:action', array('prefix' => 'profiles', 'profiles' => true)); Router::connect('/profiles/:controller/:action', array('prefix' => 'profiles', 'profiles' => true));
profilesに対するすべての呼び出しは、profiles_プレフィックスのついたメソッドを探して呼び出します。usersを例にとると、/profiles/users/edit/5などの構造を持つURLは、UsersControllerのprofiles_editメソッドを呼び出します。また、重要な点として、HTMLヘルパーを使用してリンクを作成するなら、プレフィックスを用いた呼び出しの管理も楽になります。HTMLヘルパーを使ったリンクの例は次のようになります。
echo $html->link('Edit your profile', array('controller' => 'users', 'action' => 'profiles_edit', 'profiles' => true)); echo $html->link('Edit your profile', array('controller' => 'users', 'action' => 'profiles_edit', 'profiles' => true));
この方法を使うと、複数のプレフィックスルートを定義することができ、柔軟なURL構造を持つアプリケーションを作成できます。
