読者です 読者をやめる 読者になる 読者になる

ITの隊長のブログ

ITの隊長のブログです。CakePHPとPlayFrameworkを使って仕事しています。最近はAngular2をさわりはじめたお(^ω^ = ^ω^)

【CakePHP3.x】FlashComponentのメッセージが表示されない

スポンサードリンク

タイトルだけではよくわかんないね。

<?php
// ...
    public function cakeAction($id = null)
    {
        $function = function ($post) {
            // ...
        };
        $this->_something($id, $function);
        $this->render('edit');
    }

    private function _something($id, $function)
    {
        // ...
        $this->Flash->success(__('success!'));
        // ...
    }
// ...

とあるControllerの中に↑のようなアクションとメソッドがあるとする。

/controller/cake-action/1へアクセスすると、cakeAction($id = null)が呼ばれて、その中の処理で、_something($id, $function)メソッドが呼ばれるような感じです。

_something($id, $function)は、処理の途中で$this->Flash->success(__('success!'))を実行しています。これでPHPでよく見る$_SESSIONにメッセージが書き込まれたはずです。

このメッセージを取り出して使うのはView(template)のほうで、この場合だと、edit.ctpなんてテンプレートを呼び出してブラウザでレンダリングするようになっています。

が、何度検証しても、何故かメッセージがでてこない。

色々調べた所、わかりました。

理由としては、セッションに書き込んだ後、$this->render()を呼び出すと、中の処理でセッションがクリアされてることがわかりました。何故ー!?

  1. Cake\Controller\Controller->render()
  2. Cake\View\View->render()
  3. Cake\View\View->renderLayout()
  4. Cake\View\View->_render()
  5. Cake\View\View->_evaluate()

↑の5番目の箇所でセッションがクリアされていました。

ただ、根本な理由はわかりませんでした。。。(´・ω・`)

なんか、何度も実行されるんだよね、このCake\View\View->_evaluate()ってメソッド。

呼ばれたセッションが消えるわけではなくて、その何度も実行されているときに何かのタイミングで削除されてるん感じ。なのでよくわからん。

とりあえず、このアクションはレンダリングするテンプレートファイルは決まっているので、処理の最初で決めるように修正しました。

<?php
// ...
    public function cakeAction($id = null)
    {
        $this->render('edit');
        $function = function ($post) {
            // ...
        };
        $this->_something($id, $function);
    }

    private function _something($id, $function)
    {
        // ...
        $this->Flash->success(__('success!'));
        // ...
    }
// ...

これでよし。

しかし、処理の結果でテンプレートファイルをswitchさせたい場合はメッセージをどうすればいいんだろ?

・・・・

きになったので、やっぱりもう少し調べてみることにした。

<?php

// ...
    /**
     * Sandbox method to evaluate a template / view script in.
     *
     * @param string $viewFile Filename of the view
     * @param array $dataForView Data to include in rendered view.
     *    If empty the current View::$viewVars will be used.
     * @return string Rendered output
     */
    protected function _evaluate($viewFile, $dataForView)
    {
        $this->__viewFile = $viewFile;
        extract($dataForView);
        ob_start();

        include $this->__viewFile;

        unset($this->__viewFile);

        return ob_get_clean();
    }
// ...

_evaluate()メソッドの中身の全部です。ob_get_clean()が怪しいと思っています。

これが呼ばれたら、$_SESSIONの中身が空になるのか調べてみました。

<?php

require_once('./a.php');
require_once('./b.php');

ob_start();

include './index.php';

ob_get_clean();

require_once('./b.php');

echo $_SESSION['test'] . PHP_EOL;
<?php
@session_start();
$_SESSION['test'] = 'test';
<?php
@session_start();
if (isset($_SESSION['test'])) {
  echo $_SESSION['test'].PHP_EOL;
} else {
  echo 'testは見つかりませんでした'.PHP_EOL;
}

a.phpでセッションをセットして、b.phpを最初に呼ぶ。

んで、次にob_start()してob_get_clean()を実行する。

そのあとに、b.phpを呼び出して、セッションから値が読めるかチェックします。

はたして結果は…

$ php ob_get_clean-session-delete.php
test # 最初のrequire_onceでよんだやつ
test # ob_get_clean()のあとによんだやつ

ダメでした。うーん。これが原因じゃないのかな。