CakePHP携帯用ビューのRoute設定

携帯ビュー向けRoutingが一部アクションでうまく作動しない件について、解決。。


携帯向けビューのprefixをroute.phpで設定する場合、
URLで変数が渡されるケースがあるなら、そのパターンや変数名を明確に定義しなくてはならないようです。


このブログには書いてませんが*1CakePHPによる携帯対応サイトの定法に乗っ取り、以下を参考に http://example.com/m/* にアクセスすると携帯ビューとなるように実装しています。
CakePHP 1.2で携帯用ビューを表示する - Shin x blog
http://www.multiburst.net/ElectricBrain/2009/02/cakephp-mobile-site


今までindex, view, add, delete, login, logout, listview*2などのアクションを実装して不具合がなかったのですが、
users情報のうち、パスワードだけを更新するアクションchange_passwordを実装したところ、$form->createで生成されるFROMタグのactionに、/m/が自動挿入されませんでした。*3

view記載
echo $form->create('User', array('action' => 'change_password'));
↓
出力
<form id="UserChangePasswordForm" method="post" action="/rootDir/users/change_password/1">


addなどだと、自然に/m/が入ります。

<?php echo $form->create('User'); ?>
↓
<form id="UserAddForm" method="post" action="/rootDir/m/users/add">


cake/libs以下を、FormヘルパーからRouter.phpまで辿って調査の結果。


原因は、app/config/route.phpの指定不足でした。
prefix=mobileとなるRouteingのルールに、変数名=idのパラメータが含まれる場合を追加しなくてはなりませんでした。

修正前*4

if (preg_match("/^".str_replace("/", "\/", $this->webroot)."m\//", $_SERVER['REQUEST_URI'])) {
	Router::connect('/m/:controller/:action/*', array('prefix' => 'mobile'));
}

修正後

if (preg_match("/^".str_replace("/", "\/", $this->webroot)."m\//", $_SERVER['REQUEST_URI'])) {
	Router::connect('/m/:controller/:action/*', array('prefix' => 'mobile'));
	Router::connect('/m/:controller/:action/:id', array('prefix' => 'mobile'));
}


パラメータに$idが入ってきますよ、という情報がroute.phpの設定にないと、以下のチェックを通過できないのです。


cake/libs/router.php*5

	function mapRouteElements($route, $url) {
(中略)
		$paramsKeys = array_keys($params);
		$defaultsKeys = array_keys($defaults);

		if (!empty($params)) {
			if (array_diff($paramsKeys, $routeParams) != array()) {  <=ここ。
				return false;
			}
(後略)

$paramsKeys = array('controller', 'action', 'id');
でしたが、修正前の状態では
$defaultsKeys = array('controller', 'action'); *6
array_diffを取ると、array("id")が残るのでreturn falseで捕まってしまう。

route.phpに /m/:controller/:action/:id のケースを明示することで、$defaultsKeysにidが追加されてパスできるようになりました。


今までhtmlヘルパーによるlink作成などで、なんとなく不具合なさそうに動いていたのは、

Router::connect('/m/:controller/:action/*', array('prefix' => 'mobile'));

でキャプチャしていたあたりと関係ありそうです・・・

参考URLでは

Router::connect('/m/:controller/:action', array('prefix' => 'mobile'));

とあるのですが、idがはいるURLが変換できないために
「ではアスタリスクいれてみよう。おお、うまく行った」
・・・・と対応したような気がします*7


アスタリスクで対応するのも、route.phpのサンプルケースをみるとありかと思いますが、
それではうまく行かない場合もある、というケースでした・・・・

*1:ブログ開設前だったと思われます

*2:listにするとPHPの関数と同じ名前になってエラー ^^;

*3:本来edit辺りで気付くケースぽいですが・・・イレギュラに、editを棚あげ放置してました;;

*4:if文は、PCビュー時のリンク書き換えを防ぐためのもの http://d.hatena.ne.jp/cake67/20091015/1255593212

*5:mapRouteElementsはRouterのlink()内でコール

*6:他に,pluginなどのキーもありましたが、value=nullなら問題なし

*7:メモ残ってないので曖昧