2014年6月28日土曜日

ViewModel内でPaginationが2回実行されてしまう問題的なお話(ViewModelが2回呼び出される問題)

  • このエントリーをはてなブックマークに追加

なぜかPaginationを二回呼び出してることになってるっぽい fuelphp1.7を使ってwebアプリやサービスを作ってる際に、
Controllerが汚れるのが面倒だし、可読性やらなんやらとかを考えた際に、
Modelを使うのは当然だけどModelよりもViewModelを使ってあげると色々とはかどる。

ViewModelはViewに対して諸々処理をしてあげるって感じで、
ControllerがModelからデータを引っ張って来て、そのデータをViewModelで処理してViewに表示するといった流れ。
ということでかなりいい感じで分離させることが出来るのでよかったりする。

ってことで今日はViewModelのサンプル的なものと、ViewModelを1.7で使うとバグがあるのでその対処法的なお話をば。

■ViewModelの使い方

// classes/controller/hoge.php
class Controller_Hoge extends Controller{
  public function action_detail($_uid = ""){
    $this->template->view = ViewModel::forge("hoge/detail")->set("uid",$_uid);
  }
}

// classes/view/hoge/detail.php
class View_Hoge_Detail extends ViewModel{
  protected $_view = "foo/bar/hoge/detail";

  public function view(){
    $pagination = Pagination::forge('mypagination',$config);
    $this->articles = Model_Article::get_articles($this->uid,$pagination->per_page,$pagination->offset);

    $this->_view->set_safe("pager",$pagination->render());
  }
}
まずcontrollerのhoge内でViewModel::forge()としてあげることによってViewModelを呼び出す事が出来る。
ちなみにそのあとset()とすることによって変数とかを渡す事が出来るので、ここではuidを渡している。

で、classes/viewで$_viewに代入することによってどのviewsファイルを使うかを入れる事が出来る。
本当はclass View_Hoge_Detailとクラス名がなっているので、views/hoge/detail.phpを表示するんだけど、
環境によって切り分けたいとかそういった諸々の事情があるのでこうやってテンプレートを指定している。

で、$uidの記事を引っ張ってページネーションで表示するって感じでやっている。
ページネーションは基本的にset_safe()で入れるんだけど、
Controller内で書く方法とは違って、ViewModelでは$this->_viewがset_safe()する形にしてあげる必要がある。

■1.7においてViewModelが2回実行されてしまう
こんな感じでViewModelについては用意できるんだけど、fuelphp1.7だとViewModelが2回実行されてしまうバグがあるので、
それを対処するには1.7.1とかそれ以上にアップデートするか、public/index.phpに手を加えればよい。
  {
    throw $e;
  }
}

$response->body((string) $response->body());//75行目らへん

// This will add the execution time and memory usage to the output.
75行目あたりの空いたところらへんに入れてあげればOK。
これで2回実行されることなくちゃんと1回で動作する。

って感じでViewModel使うと分離出来てかなり便利だっていう感じ。
ネットで情報調べてもみんなあまりViewModel使ってないのかな?って感じだし、
ページネーションをControllerに書くとちょっと汚れるしで見づらいしでっていうこともあるし、
けどすごく便利だから使ったらいいんじゃないかなって思った。

ただ1.7の人は本当に気をつけないといけなく、
自分はページネーションだったから全然問題なかったけど、
insertとかだったら2回挿入されるという最悪な事態が起きてしまうわけで。

ってことで出来たらViewModel使って分離して書いてみよう的な。

Adsense