atijust's blog

技術的なこととか。

Laravelでテンプレート用のロジックを整理する方法

Laravel Advent Calendar 2013の15日目です。 robclancy/presenterでテンプレート用のロジックを整理する方法を紹介します。

テンプレート用ロジックの置き場所の問題

Laravelに限らずですが、Webアプリを開発していてぶち当たる問題として、テンプレート用のロジックをどこに置くかというのがあります。

例えばモデルの作成日時をテンプレートで表示するというのはよくありますよね。

{{{$article->created_at->format('M d, Y')}}}

何も考えずに書くとこんな感じかな。テンプレート内でフォーマットを指定して表示しています。 うん問題ない。でも、日付の表示がここ1箇所だけならいいのですが、他に何箇所も表示しなければならないとしたら、ちょっと嫌ですよね。DRYじゃない。表示のフォーマットを変えたくなった場合、すべての箇所を1つずつ修正しなければなりません。

そこで、日付をフォーマットしてくれるヘルパーを用意してみます。

<?php
function article_date($date)
{
    return $date->format('M d, Y');
}
{{{article_date($article->created_at)}}}

これなら、フォーマットを変えたくなった時もヘルパーを修正するだけで大丈夫。やったね! …でも、ArticleだけならまだしもCommentやらなんやらの日時も表示するとなると、それに対応するヘルパーが際限なく増えていくわけで、なんか嫌かも。グローバル関数がいっぱいとかゾッとしますよね。

であれば、モデルに書いちゃえ!

<?php
class Article extends Eloquent
{
    public function formatDate()
    {
        return $this->created_at->format('M d, Y');
    }
}
{{{$article->formatDate()}}}

いやいやいやモデルにテンプレート用のロジックとかあり得ないだろjk

…このように、テンプレート用のロジックの置き場所というのは悩ましいものです。

それrobclancy/presenterで上手くできるよ!

少し前の自分なら、もやもやした気分のままヘルパーをひたすら増やすか、えいやでモデルにメソッドを追加していたでしょうが、最近いいパッケージを知りました。robclancy/presenterです。このパッケージを使えば、Decoratorパターンでモデルにメソッドを追加できます。

<?php
class ArticlePresenter extends Robbo\Presenter\Presenter
{
    public function formatDate()
    {
        return $this->created_at->format('M d, Y');
    }
}

// …

$article = new ArticlePresenter($article);
{{{$article->formatDate()}}}

このようにテンプレート用のロジックを実装したPresenterを用意し、モデルをラップすることで、モデルのクラスを変更することなくメソッドを追加することができます。Presenterは自身にないメソッドやプロパティへのアクセスは、モデルに自動的に移譲してくれるので、元々のモデルのメソッドも問題なく使えます。

<?php
class Article extends Eloquent implements Robbo\Presenter\PresentableInterface
{
    public function getPresenter()
    {
        return new ArticlePresenter($this);
    }
}

また、モデルにPresentableInterfaceを実装することで、テンプレートにモデルを渡すときに自動的にPresenterでラップしたものに差し替えることもできます。Controllerで手動でちまちまラップする必要がなくて便利です。

これで、テンプレート用のロジックをキレイに実装できるようになって、気持よくプログラミングに励むことができますね!

最後になりましたが導入方法です。 composer.jsonrobclancy/presenterを追加します。

 "robclancy/presenter": "1.1.*"

app/config/app.phpでServiceProviderを登録します。 このとき必ず Illuminate\View\ViewServiceProviderより後になるようにしましょう。

<?php
 'Illuminate\View\ViewServiceProvider',
 // …
 'Robbo\Presenter\PresenterServiceProvider'

robclancy/presenter自体はLaravel以外でも使える汎用的なライブラリですので、Laravel以外のフレームワークと組み合わせてみるのもいいかもしれませんね。

以上、Laravel Advent Calendar 2013の15日目でした。 明日の担当はHiroKwsさんです。よろしくお願いします!