CakePHPアプリケーションの基本的な設計指針 (1) - URL設計 -

イントロダクション

CakePHPMVCデザインパターンを採用しており、基本的にこれに従った設計が基本となります。
しかし、ある程度開発が進んだところで、やっかいな設計の問題にぶち当たることは多いですよね。
そこで、よくある問題を取り上げて、設計の指針としてまとめてみることにします。


注:とても1回で書ききれるとは思えません。連載となる可能性が高いです。

URL設計

CakePHPのURLは、最初は独特に見えたかもしれません。
http://example.com/users/view/1 などよりも、http://example.com/user/hiromi2424 などの見栄えを期待していた方も多いのではないでしょうか。
しかし、だからといって以下のようなアクション、URLの呼び出し方は、後々に響いてきます。

<?php
// Route
Router::connect(
	'/user/:nickname',
	array(
		'controller' => 'users',
		'action' => 'view'
	),
	array(
		'pass' => array('nickname'),
	)
);
?>

<?
// Controller
class UsersController extends AppController{
	function view($nickname) {
		$this->set('user', $this->User->findByNickname($nickname));
	}
}
?>

<?php
// View
echo $this->Html->link($user['User']['nickname'], '/user/' . $user['User']['nickname']);
?>

大きく3点の問題があります。

  1. URLを呼び出す時に、User.nicknameが必要(user_idしかなかったらどうする?)
  2. ニックネームの重複が許されない
  3. ルートが変更された場合、ビュー、コントローラなどの該当URL呼び出しを全て変更する必要がある

IDをURLに含めるかは要件次第ですが、たったこれだけのことで後に重大な変更になりかねません。
URLにIDが含まれていなくても、IDを元にアクションの引数、URLを扱うように設計していればその心配がなくなります。


また、CakePHP1.3からは、カスタムルートクラスが利用できます。
これを利用することにより、標準的なアクションの形で様々なURLを利用することが可能となります。

<?php
// Route

App::import('Lib', 'route' . DS . 'UserNicknameRoute');
Router::connect(
	'/user/:id/:nickname',
	array(
		'controller' => 'users',
		'action' => 'view'
	),
	array(
		'routeClass' => 'UserNicknameRoute',
		'pass' => array('id'),
	)
);
?>

<?php
//RouteClass
class UserNicknameRoute extends CakeRoute {

	function match($params) {
		// controller, actionの比較
		if (array_intersect_key($params, $this->defaults) != $this->defaults) {
			return false;
		}

		if (isset($params[0])) {
			// 実際はキャッシュするべき
			$params['id'] = $params[0];
			$params['nickname'] = rawurlencode(ClassRegistry::init('User')->field('nickname', array('id' => $params[0])));
			unset($params[0]);
		}

		return parent::match($params);
	}

}

?>

URLがニックネームが違っていてもマッチしてしまう場合は、カスタムルートクラスのparse()を実装するか、コントローラ(コンポーネント)でチェックなどをして工夫しましょう。

また、文字列でのURLの呼び出し('/user/' . $user['User']['nickname'])は極力しないようにしましょう。
ただし、例外はあります。

  • ホームページ('/'を指定)
  • 画像などアセットのパス
  • 外部URL

など。

呼び出すURLがアクションの場合、必ず標準的な配列形式で指定するようにしましょう。

最後に

これらCakePHPの機能に配慮した設計を行うことにより、変更に強く、また柔軟なルーティングが行えます。
億劫な配列地獄に見えるかもしれませんが、そこにはちゃんと規約のマジックが存在するのです。


#URL設計だけで1回終わってしまった・・・どうなることやら。


補足Togetter - 「CakePHPアプリケーションの基本的な設計指針 (1) へのツッコミなど」