開発メモや日ごろ思ったことなどを書きためるサイトです。サイト管理者は、SE、Web開発者。最近はiPhone、Android開発に興味が出てきてすこしずつ勉強中。
複雑なフォームのパラメータを持ちまわりたかったので、cakephperの日記(CakePHP, MongoDB, Lithium)さんのよくある確認画面でのhiddenデータの持ち回り ver2を改造させていただき無制限でネストしてパラメータに押し込む用にしてみた。
class FormhiddenHelper extends AppHelper {
var $helpers = array('Form');
function hiddenVars() {
$ret = "";
$keyStack = array();
$this->_hiddenVarsNestParse($this->data, $keyStack, $ret);
return $ret;
}
function _hiddenVarsNestParse($data, &$keyStack, &$ret) {
if (is_array($data)) {
foreach ($data as $key => $val) {
array_push($keyStack, $key);
$this->_hiddenVarsNestParse($val, $keyStack, $ret);
array_pop($keyStack);
}
} else {
$ret .= $this->Form->hidden(implode('.' ,$keyStack)) . "\n";
}
}
}
CakePHPの動作が難解なのでめも。
1.同一モデルの複数レコードの保存
※insertしたいのでidは指定しない
$data = array(
'Article' => array(
'0' => array(
'name' => 'a',
'price' => 1000),
'1' => array(
'name' => 'b',
'price' => 5000)));
$this->Article->saveAll($data);
2.単一レコードに結びつく複数モデルの保存
Categoryに結びつくArticleを作成
$data = array(
'Category' => array(
'id' => 1),
'Article' => array(
'0' => array(
'name' => 'a',
'price' => 1000),
'1' => array(
'name' => 'b',
'price' => 5000)));
$this->Article->saveAll($data);
ここで一つ問題が発生
Articleモデルのarticle.phpのvalidateに下記のような記述をした。
$validate = array(
'category_id' => array(
コントローラーの応答にリダイレクトが含まれるとtestActionを実行したときにテストケースが終了してしまうという落とし穴がある。対処方法がリンク先にいろいろ書いてあるが、とりあえず簡単な対処方法が見つかった。
testActionで呼ぶURL部分でcake bakeで作成されたテストケースのTest◯◯Controllerクラスを呼ぶように書き換える。
変更前: $result = $this->testAction('/admin/categories/xxxx');
変更後: $result = $this->testAction('/admin/test_categories/xxxx');
#categories_controller.test.php
class TestCategoriesController extends CategoriesController {
var $autoRender = false;
function redirect($url, $status = null, $exit = true) {
$this->redirectUrl = $url;
}
}
class CategoriesControllerTestCase extends CakeTestCase {
<省略>
function testSomeCase() {
$result = $this->testAction('/admin/test_categories/xxxx');
}
リダイレクトを前提とするテストケースでtestActionに'return' => 'var'を設定するとエラーになる。ビューが呼ばれないのにビューの変数を読み込もうとしてしまったのが原因みたい。
CakePHPのコアをいじらないでブラウザ終了時にセッション終了する方法がわかったので記載する。
CakePHPはSecurity.level lowまたはmediumだとブラウザを閉じても、セッションが終了しない。これは、PHPの"session.cookie_lifetimeがセキュリティレベルがmediumの時は7日間、lowの時は25年間ぐらいに設定されるためだ。
散々悩んだ挙句にCakePHPのコアのソースを読んでみて、cake/libs/session.phpでいろいろやっていることが分かったので解決方法をここで書きたいと思う。
CakePHPのconfig/core.phpでSession.saveをcakeに設定すると下記の通りセッションの設定がされる。
ini_set('session.use_trans_sid', 0);
ini_set('url_rewriter.tags', '');
ini_set('session.serialize_handler', 'php');
ini_set('session.use_cookies', 1);
ini_set('session.name', Configure::read('Session.cookie'));
ini_set('session.cookie_lifetime', $this->cookieLifeTime);
ini_set('session.cookie_path', $this->path);
ini_set('session.auto_start', 0);
ini_set('session.save_path', TMP . 'sessions');
この設定のsession.cookie_lifetimeの部分だけ入れ替えたいので"config/myapp_session.php"というファイルを準備し上の記述を丸々コピーしてsession.cookie_lifetimeの部分のみ書き換える。
config/myapp_session.phpの内容
------------------------------------------------------
ini_set('session.use_trans_sid', 0);
ini_set('url_rewriter.tags', '');
ini_set('session.serialize_handler', 'php');
ini_set('session.use_cookies', 1);
ini_set('session.name', Configure::read('Session.cookie'));
ini_set('session.cookie_lifetime', 0); // ← この部分を0にした
ini_set('session.cookie_path', $this->path);
ini_set('session.auto_start', 0);
ini_set('session.save_path', TMP . 'sessions');
------------------------------------------------------------
次に/config/core.phpを開き下記の通り変更する
変更前: Configure::write('Session.save', 'cake');
変更後: Configure::write('Session.save', 'myapp_session');
これでmyapp_session.phpの内容を読み込んでくれて、ブラウザを閉じるとセッションも終了するようになる。
以下蛇足
myapp_session.phpが読み込まれる仕組み。
CakePHPコアのsession.phpではSession.saveで不明なタイプが設定されている場合に
下記のプログラムが実行され、"Session.saveで設定された名称" + .phpが読み込まれる
cake/libs/session.php __initSession()の最後のほう
if (empty($_SESSION)) {
$config = CONFIGS . Configure::read('Session.save') . '.php';
if (is_file($config)) {
require_once ($config);
}
}
# 2009/10/3 わかりにくかったので、多少文章変更