【CakePHP】フラッシュメッセージの動きを把握し、よくあるトラブルと戦う。
最近、ささみの燻製にはまりつつある常時減量中のfukasawaです。こんにちは。
スモークチーズみたいな味で、食べごたえもあって美味しいです。どこのスーパーにも置いているわけではないようなのですが、サラダチキンに飽きてしまった方は見かけたら是非試してみてください。
さて、CakePHPには1回限りの通知をユーザに表示するフラッシュメッセージという機能があります。例えば、ユーザがブログ記事を投稿した際に「投稿完了しました。」のようなメッセージを表示する際に便利な機能なのですが、使用していると「関係のない画面にメッセージが表示された」とか「メッセージを表示して欲しいタイミングで表示されない」といったトラブルに悩まされることがあります。
そのようなトラブルに遭遇した際、フラッシュメッセージの動きを把握していないと何処に原因があるのかを特定できず、解決するまでに時間がかかってしまったりといった状況に陥りがちです。
今回はそのようなトラブルに備えるべく、フラッシュメッセージの動きと、よくあるトラブルにどう対処したらよいかをザックリと見てみたいと思います。
※CakePHP バージョン2.6.3 を使用して検証しています。
1. フラッシュメッセージの基本的な動きについて
フラッシュメッセージは「メッセージのセット」→「セットされたメッセージの表示(&削除)」がワンセットになっています。
1. SessionComponent::setFlash()
- Controllerでメッセージをセットする
2. SessionHelper::flash()
- Viewでセットされているメッセージを取り出す
- セットされているメッセージを消す(メッセージの取り出しと同時に消してしまうので、"1回限りの通知"となります。)
サンプルを見てみましょう。
1.SessionComponent::setFlash()を使用しメッセージをセット
【Controller】
public $components = array('Session'); // SessionComponentを使用するように設定
...
$this->Session->setFlash('登録が完了しました!'); //メッセージをセット
2.セットしたメッセージを SessionHelper::flash() を使用して取り出す。
【View】
<?php echo $this->Session->flash(); //メッセージを取り出して表示 ?>
SessionHelper::flash()の役目はメッセージを取り出すところまでです。取り出したメッセージを表示するときはecho()等で出力してあげる必要があります。(バージョン1.2以前は勝手にecho()してくれていました。)
2. セットされたメッセージはどこに格納されるのか
SessionComponentとSessionHelperを使用しているのでお察しのことと思いますが、セッションに"Message.●●●"というキーで格納されます。
1. SessionComponent::setFlash()
- CakeSession::write()を使用し、セッションに"Message.flash"というキーでメッセージ(及び引数のパラメータ)を格納
※引数でキー名を指定しないと"Message.flash"というデフォルトのキー名が使用される。
2. SessionHelper::flash()
- "Message.flash"というキーがセッションに存在するか確認し、存在する場合はCakeSession::read()で読み込む
- 読み込んだメッセージをパラメータに応じて加工して返す。
- CakeSession::clear()でメッセージを削除。
フラッシュメッセージという名前で内部の処理が若干隠蔽されているように感じますが、中ではCakeSessionを使用してセッションにメッセージを書き込んだり、読み込んだりといった事をしています。
なので、例えばSessionComponent::setFlash()で設定したメッセージを2回以上使い回したい場合などは、SessionHelper::flash()で消されてしまう前にCakeSession::read()でセットしたメッセージを読み込むといった事ができなくも無いのです。(あまりしないとは思いますが。)
3. フラッシュメッセージの引数
フラッシュメッセージの引数についても簡単に見ておきます。
SessionComponent::setFlash()
$message | セットしたいメッセージ文 |
$element | どのエレメントを使用してメッセージを表示するか ("test_element"を指定すると、/app/View/Elements/test_element.ctpが使用されます。) |
$params | SessionHelper::flash()に渡すパラメータを指定します。
|
$key | メッセージのキーを設定。(デフォルトは'flash') ※例えば"regist"という値を$keyに指定すると"Message.regist"というキーでセッションにメッセージが格納されます |
SessionHelper::flash()
SessionHelper::flash(string $key = 'flash', array $params = array())
$key | メッセージのキーを指定。対になるSessionComponent::setFlash()で指定した$keyと同じ値を指定します。 |
$params | パラメータを指定
|
※SessionComponent::setFlash()の引数で
|
4. よくあるトラブルと解決の観点
ありそうなトラブルと、解決の観点についてざっくりと見てみます。
フラッシュメッセージは基本的に"Message.●●●"というキーでセッション中に格納されているので、デバッガを使用している人はデバッガで、プリントデバッグ派の人はdebug($this->session->read("Message.●●●"))等でセットされている値を追いながら対処することになると思います。
関係の無い画面でメッセージが表示されてしまう
- 使わなかったフラッシュメッセージが残ってしまっている
- 基本的にflash()を呼ばない限りメッセージがセッション中に残り続けてしまいます。適切なところでflash()して表示するか、もしくはセッションから意図的に消す必要があります。
(セットしたら必ずflash()する、みたいな流れにしておくとトラブルが少ないと思います。) - setFlash()するときのキーとflash()するときのキーが異なっている
- 引数で指定する$keyがsetFlash()とflash()で異なってしまっている可能性があります。関連するsetFlash()とflash()については、指定する$keyを合わせる必要があります。
- 必要のないsetFlash()が処理の中に存在する
- 消しましょう。
メッセージが表示されない
- flash()はしているけれど、echo()してない
- flash()はメッセージを取り出すだけなので、echo()しないと画面に出力されません。
(バージョン1.2以前は自動的にechoされていました。) - 画面でメッセージを表示する前に、既にflash()がよばれている
- 一度flash()が呼ばれるとセットされているメッセージは消えてしまうので、処理の中にリダイレクトが含まれる場合など、表示するタイミングよりも前にflash()が呼ばれていないか確認する必要があります。
- setFlash()するときのキーとflash()するときのキーが異なっている
- 関連するsetFlash()の$keyとflash()の$keyは合わせる必要があります。
- CakeSession::clear()等を使用して、セッションからメッセージを消してしまっている
- "Message.●●●"というキーのセッションを意図的に消していないか、フラッシュメッセージ以外で"Message.●●●"というキーを使っていないか等を確認します。
- 途中でセッションが切れてしまっている
- セッションに格納しているので、セッションが切れるとメッセージも消えます。
異なるエレメントを使用して出力されている
- setFlash()の第二引数($element)、flash()の第二引数($attr['element'])の2箇所で使用するエレメントを指定することができます。setFlash()時にエレメントを指定しても、flash()で再度指定すると上書きされてしまうので、両方の引数を確認し、適切なエレメントが指定されているかを確認します。
まとめ
ルールを決めて使用することで、トラブルも事前に回避できそうです。