CakePHPでセションメッセージ、フラッシュメッセージを二度以上使いたかった

CakePHPでセションメッセージを二度以上使いたかった。

CakePHPでセションを使ってメッセージを表示することができる。通常はエラーメッセージを表示させたりするためにeditやaddなどでエラーメッセージを収めておき、リダイレクト先のviewでflush()を呼んで表示している。

便利な機能なのだけれど、setFlashという名前の通り、このメッセージは一度限り設定できる。コントローラが大きくなってくるとセションメッセージの設定位置が散らばったりするため、意図せずしてセションメッセージを後から上書きしてしまうことになってしまう。今回はこの問題を調べてなんとかしてみた。

1. やりたいこと
下のようなコードがあったとする。

Class HogeController extends AppController {
public function action() {
$this->Session->setFlash('hoge');
$this->Session->setFlash('fuga');
}
}

このとき、actionのviewでflush()でセションのメッセージを呼び出したとき、hogeは無くなってしまってfugaが表示される。
今回はここで何とかして hogefuga という風に連結したメッセージを表示させてみる。

$this->Session->setFlash('hoge');
$flashMessage = $this->Session->read('Message.flash');
$this->Session->setFlash($flashMessage['message'] .= 'fuga');

これでセションのフラッシュメッセージを追加できる。この場合だと hogefuga が表示される。

こうすると動かせるようになるのは以下の理由。
SessionComponent.phpにあるsetFlashのメソッドの定義を見てみる。

public function setFlash($message, $element = 'default', $params = array(), $key = 'flash') {
CakeSession::write('Message.' . $key, compact('message', 'element', 'params'));
}

setFlashというのはCakeSessionのwriteメソッドを呼んでいる。このメソッドの定義はCakeSession.phpにある。このクラスにはwriteの他にreadもある。このreadを使って上記のように取り出して追記している。

public static function read($name = null) {
if (!self::started() && !self::start()) {
return false;
}
if (is_null($name)) {
return self::_returnSessionVars();
}
if (empty($name)) {
return false;
}
$result = Hash::get($_SESSION, $name);

if (isset($result)) {
return $result;
}
self::_setError(2, "$name doesn't exist");
return null;
}
public static function write($name, $value = null) {
if (!self::started() && !self::start()) {
return false;
}
if (empty($name)) {
return false;
}
$write = $name;
if (!is_array($name)) {
$write = array($name => $value);
}
foreach ($write as $key => $val) {
self::_overwrite($_SESSION, Hash::insert($_SESSION, $key, $val));
if (Hash::get($_SESSION, $key) !== $val) {
return false;
}
}
return true;
}

readとwriteするときにはキーによって制御している。このキーはsetFlashを使ったときには ‘Message.flash’ が用いられている。なのでこれを手動でreadして改めて連結してsetFlashしている。

これでセションのメッセージを追記することができる。
なにか別名を与えてsetFlashの代わりにこれを全部使っても良いかなと思うのだけど、しばらく様子をみてからにしよう。

コメントを残す