【FuelPHP】Presenterのviewで共通変数をセットする

投稿日:

前にも書きましたが、最近案件で何故かfuelを使う事が多くなってきました。
バージョンは1.7.2を使っているんだけど、ちょっとPresenterを使うところで頭を悩ませた事(Presenterで共通変数をセットしてviewで見たいぃぃ)があったのでその時のメモです。
※Presenterは以下から、プレゼンターと書きます

プレゼンターって?

一応、プレゼンターって何?って話なんですが、
http://fuelphp.jp/docs/1.8/general/presenters.htmlから引用すると

プレゼンタとは?
プレゼンタはビューの生成に必要なロジックを含むクラスです。コントローラがユーザ入力を処理し、必要なアクションを処理すると、プレゼンタにビューに必要なデータを取得するように処理を引き継ぎます。プレゼンタはデータの操作を一切すべきではありませんが、データベースの呼び出しや他のデータの取得、ビューの生成に必要な準備の操作を含めます。

との事。

自分は、
プレゼンターは(データの取得/整形に関しての)ビジネスロジックをゴリゴリ書くとこ〜?
みたいな感じで捕らえています。

この辺はこちらが分かりやすかったです。
一生涯プログラマ : FuelPHPのViewModelについて
(でも、まだよくわかっていません。えへへ。)

プレゼンターはそんな感じ。

ちなみに、今までViewModelだったのが、1.7.2からPresenterに変わったようです。
でも日本語の1.7系のチュートリアル(http://fuelphp.jp/docs/1.7/)を見てもプレゼンターの事は書いていないので、プレゼンターに関しては1.8系のチュートリアル(http://fuelphp.jp/docs/1.8/)を読むことになります。
でもこれ、何も知らないでfuel始める人混乱しないかな。。
(http://fuelphp.com/docs/ を読むという手もあるけど。。)

んで、話を戻して、何で頭を悩ませたかというと、

  • プレゼンターのメインのviewで共通部品(headerとかfooter)をレンダリングする
  • メインのviewと、その共通部品のviewで一緒の値を見る必要がある
  • その値はなるべく一箇所でsetしたい
  • はて、プレゼンターでどうやんだべ

というところ。

Viewでいうset_global()をプレゼンターで使えればいいんだけど、Presenter – クラス – FuelPHP ドキュメントを見る限り、

そのため、プレゼンタは関連するビューの set()、set_safe()、bind()、auto_filter() そして render() メソッドを見えるようにしています。 関連するビューオブジェクトのプロパティにアクセスしセットするマジックゲッターおよびセッターを持っています。
プレゼンタは、静的メソッド set_global() と bind_global() をサポートしません。もし、ビューにグローバル変数が必要な場合は、 View クラスでそれらをセットしなければなりません。プレゼンタにとっては、それは透過的です。

プレゼンターから直接使えない。
もしグローバルにセットする値があるならViewクラスを使わなければいけないみたい。
で、もう少し見てみるとこんなメソッドがある事に気づく。

get_view()
get_view メソッドはプレゼンタに関連するビューのインスタンスを返します。

ピッコーン。これ使えばいいんじゃね?と閃き、強引に試してみたところ動きましたのでサンプルを載せておきます。

申し訳ありません。画面下部の追記を見てください。

強引なところ

静的メソッドをインスタンスメソッド($this->XXX())として呼んでいる

サンプル

まず、こんな構成とします。
presenterに親クラスを持たせます。

app/
    classes/
            controller/
                       sample.php
            presenter/
                      base.php
                      sample.php
    views/
          common/
                 header.php
                 footer.php
          sample.php

app/classes/controller/sample.php

<?php
class Controller_Sample extends Controller
{
    public function action_index()
    {
        return Response::forge(Presenter::forge('sample'));
    }
}

app/classes/presenter/base.php プレゼンターの親クラス

<?php
class Presenter_Base extends Presenter
{
    /**
     * 自身のView
     *
     * @var Fuel\Core\View
     */
    protected $self_view = null;

    /**
     * before
     */
    public function before()
    {
        // これでviewが取れるのでset_globalが使える
        $this->self_view = $this->get_view();

        // set_globalでsetしたものはpresenter内で
        //   $this->hello
        //   $this->self_url
        // でアクセス出来る

        // また、どのviewでも
        //   echo $hello;
        //   echo $self_url
        // の様に使える

        // 静的メソッドをインスタンスメソッドとして使う
        $this->self_view->set_global([
            'hello' => 'hello',
            'self_url' => \Uri::main()
        ]);
    }
}

app/classes/presenter/sample.php

<?php
class Presenter_Sample extends Presenter_Base
{
    /**
     * レンダリング
     */
    public function view()
    {
        $this->set('hello_world', $this->hello.' world');

        // 中身はhtmlなので第3引数はfalse
        $this->set('header', render('common/header'), false);
        $this->set('footer', render('common/footer'), false);
    }
}

app/views/sample.php

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>Sample</title>
</head>
<body>
    <?php echo $header; ?>
	<?php echo $hello_world; ?>
    <?php echo $footer; ?>
</body>
</html>

app/views/common/header.php

<header>
    <h1><a href="<?php echo $self_url; ?>"><?php echo $hello; ?></a></h1>
</header>

app/views/common/footer.php

<footer>
    <p><?php echo $hello; ?></p>
</footer>

はい。こんな感じです。
ポイントは

  • get_view()で自身のViewを参照する
  • ちょっとアレだけど静的メソッドのset_global()をインスタンスメソッドとして使う

ってところです。

まとめ

上記の様にすれば、プレゼンターで共通変数をセットする事が出来ます。
ただ、強引というかお作法に則っていない感丸出しなので、ここまで書いておいて微妙な気がしてきました。
でも共通変数をセットしたい場面って多々あると思うんだけど、どうやって解決するのがベストなんだろ。。
わざわざこうしたくないんだけどなぁぁ。

$this->set('header', render('common/header', ['self_url' => \Uri::main()]), false);

そもそも、プレゼンターの使い方間違っているんだろうか。
(こんな設計でもうやっちゃってるけど)

悩みは尽きない。お勉強を続けます。

追記

コメントにあるようにView::set_global()を使えばいいですね。。

app/classes/presenter/base.php プレゼンターの親クラス

<?php
class Presenter_Base extends Presenter
{
    /**
     * before
     */
    public function before()
    {
        // これでOK
        View::set_global([
            'hello' => 'hello',
            'self_url' => \Uri::main()
        ]);
    }
}

プレゼンタは、静的メソッド set_global() と bind_global() をサポートしません。もし、ビューにグローバル変数が必要な場合は、 View クラスでそれらをセットしなければなりません。

これってこういうことやったんか。。失礼しました。。

参考にさせて頂きました

投稿日:
カテゴリー: PHP タグ:

作成者: shimabox

Web系のプログラマをやっています。 なるべく楽しく生きていきたい。

1件のコメント

  1. Controllerを拡張して、beforeでView::set_global()を読んであげればよさそう

コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください