[CodeIgniter] 単一メソッドで複数階層URLを処理する
URLの見た目やSEO対策を考えて、URLのディレクトリ階層を複数設定したい時に、CodeIgniterでどのように処理するのかを見ていきます。
更新日: 2018.7.17公開日: 2017.10.20
具体例
CodeIgniterの公式ドキュメントの例にそって、ファッション通販サイトの商品ページを作成しているとします。
URL的には、
example.com/products/shoes/sandals/123
つまり、
ドメイン/products/大カテゴリ/小カテゴリ/商品id
というURLになるとします。よくあるやつです。
まずは、CodeIgniterの公式ドキュメントの通りにやってみる
公式ページのドキュメントに記載されている通りに書いてみます。
vi application/controllers/Products.php
<?php
class Products extends CI_Controller {
public function shoes($sub_category, $id)
{
echo $sub_category;
echo $id;
}
}
簡単ですね。
example.com/products/shoes/sandals/123にアクセスされば、きちんとsandalsと123が表示されます。
しかし、実際に開発を進めて行くとわかりますが、このやり方はshoesというメソッドで商品ページを表示させているので、「じゃあ、ジャケットの商品ページ(example.com/products/outer/jacket/111)は処理は同じなのにjacketメソッドをまた作るの?」という疑問が湧いてくるはずです。
本来は「productsコントローラーのdetailメソッド」を呼び出すだけでいいはずです。
ルーティングを使ってURLを柔軟に変更
そこでCodeIgniterのルーティング機能を使って、商品ページのURLを複数階層にしたまま、単一メソッドで処理されるようにします。
処理の流れとしては、
「/products/カテゴリ/小カテゴリ/ID」というURLにアクセスが来たら、
- productsコントローラーのdetailメソッドに
- 変数「カテゴリ,小カテゴリ,ID」を渡す
という形にします。
実装
では、実装していきます。
まずはコントローラー側を書いていきます。
vi application/controllers/Products.php
<?php
class Products extends CI_Controller {
public function detail($category, $sub_category, $id)
{
echo $category;
echo $sub_category;
echo $id;
}
}
次に、ルーティングの設定をしていきます。
書き方は、
$route‘アクセスされたURL’ = ‘受け渡しするCodeIgniterのURI’;
という形になります。
vi application/config/routing.php
$route['products/(:any)/(:any)/(:num)'] = 'products/detail/$1/$2/$3';
簡単に解説すると、
左辺のほうで特殊なのは、「(:any)」と「(:num)」で、「(:any)」はその名の通りなんでもOK、「(:num)」のほうは数字だけを受け付けます。
右辺のほうは、CodeIgniterのURIは「コントローラー名/メソッド名」という型なので、まずは最初の2つでメソッドまでを指定します。そのあとの部分はメソッドに渡す変数になります。
メソッド側の変数は「$category, $sub_category, $id」とカンマ区切りにしますが、ルーティング側は「$1/$2/$3」とスラッシュ区切りになるので、間違いないようにしてください。
ルーティグの使い方は、ここのサイトがまとまっていてわかり易いです。
これで、シューズの時でもジャケットの時でも同じproductsコントローラーのdetaiilメソッドで処理がされます。
注意点
CodeIgniterのルーティングを使う際に注意したいのは、URLの形式がマッチすればなんでも処理してしまう点です。
上記の例の場合、「$route[‘products/(:any)/」の部分で、このままだとproductsコントローラーに作った他のメソッドにアクセスすると、すべてdetailメソッドで処理されてしまいます。
例えば、商品一覧ページとして「/prodcuts/lists/」というURLのページを作ったとしても、「$route[‘products/(:any)/」の部分が効いてdetailメソッドで処理されます。「detailメソッドにルーティングされているけど、listsメソッドがありからそちらで処理すべきだ!」みたいな気の利いたことはしてくれません。
これを回避するためには、ルーティングで他の処理を設定しておく必要があります。
vi application/config/routing.php
$route['products/lists'] = 'products/lists';
$route['products/(:any)/(:any)/(:num)'] = 'products/detail/$1/$2/$3';
ルーティングは上からマッチさせていくので、URLが固定されている方(URLの浅い階層で変数がない方)、今回の例では/products/listsを先に書くのが肝です。
一工夫入れてエラーリスクを減らす
CodeIgniterで複数階層URLを処理する場合に個人的にやっている方法なのですが、なるべくURLのどこかにメソッド名を入れるようにします。
今回の例で言えば、「example.com/products/shoes/sandals/123」ではなく、「example.com/products/shoes/sandals/detail/123」とすれば、ルーティングの処理をする際に、必ず「detail」というURLにマッチさせる必要があるので、他のメソッドとかぶる確率が低くなります。
このあたりは、サイトの特性やSEOの狙いなどにも影響するので、いろいろ試してみてください。
CodeIgniterで複数階層URL処理する方法を見てきました。
CodeIgniterは仕組みがシンプルな分カスタマイズが楽ですが、細かい設定をしていく場合は、きちんと理解して設定しないと予定外の処理が起こるので注意が必要ですね。