Controllerの肥大化は嫌いです

とりあえずFuelPHP使って何かアプリケーションを作ろうとしたのだけど、 Viewを作る時にページ全体をそれぞれのViewファイルに定義するのは非効率&保守性悪い&バグの元。

なので、普通はページのベースとなる部分を共通のTemplateとか定義して、Controllerで処理した後のViewをTemplateに定義したコンテンツ部分に当てはめるのが一般的だと思う。

FuelPHPにもその辺の事は考慮されていて、Viewの中にViewを入れ子にしたり、標準のTemplateを作っておいてそこに色々当てはめていけるController_Templateクラス何かが用意されている。

しかし、このController_Templateクラス、使い方としては公式ドキュメントにある通りこんなコードになってしまう。

class Controller_Example extends Controller_Template
{
    public function action_index()
    {
        $this->template->title = 'Example Page';
        $this->template->content = View::forge('exsample/index', $data);
    }
}
何が嫌かって、titleを設定しているところ。
ここではtitleとcontentの設定のみだけど、実際にはページ独自のcss読み込ませたり、ScriptをTemplateで宣言した共通Script読み込む前と後でそれぞれにScript読み込ませたかったりと細かく色々設定したくなる場合が多々ある。
その場合にController内にどんどんViewに関するコードが増えてしまいControllerが厚くなるのが好みでない。というか、ViewとControllerの分離が甘いと感じる。

という訳で

Controllerクラスを拡張するよりもViewクラスを拡張した方がしっくりくる気がするのもあってTemplateViewというクラスを作成してみた。
使い方はこんな感じ

class Controller_Example extends Controller
{
    public function action_index()
    {
        return Response::forge(TemplateView::forge('exsample/index', $data));
    }
}
これでControllerの中身がシンプルになった。
Viewの中身はTemplate、Contentとそれぞれこんな感じ

app/classes/view/template.php(style部省略)

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
        <!-- titleを子Viewより取得 -->
	<title><?php echo $container->get_item('title'); ?></title>
        <!-- Assetを使用してcssやjsをロード。子Viewではパスだけ記述すればよい。 -->
        <?php echo Asset::css($container->get_item('css')); ?>
        <?php echo Asset::js($container->get_item('js')); ?>
	<?php echo Asset::css('bootstrap.css'); ?>

</head>
<body>
    <header>
        <div class="container">
                <div id="logo"></div>
        </div>
    </header>
    <div class="container">
        <h1><?php echo $container->get_item('subTitle'); ?></h1>
        <?php echo $container->content; ?>        
    </div>
</body>
</html>


app/classes/view/exsample/index.php
<?php
    $container->title = "タイトル";
    $container->subTitle = "サブタイトル";
    $container->css = "exsample/test.css";
?>

Indexメソッドが呼び出されました!

実行結果
スクリーンショット 2014 05 12 1 48 07
こんな感じでindex.phpの中で$containerを使ってtemplate.phpに表示したい内容をセットしていけばOK。
template.phpで指定している$containerのitemが無くてもちゃんと処理してくれる。

ただ、思いついたままに書いたコードなので孫Viewがある場合とかはまだ考慮していない。
とりあえずGitHubに置いといたので、もし使いたいという人が居ればどうぞ。
PullRequest大歓迎です。
TamplateView