ビュー

ビューとは?

ビューは、ブラウザにデータを提供するファイルです。アプリケーションのロジックとプレゼンテーションを分離することができます。ビューは典型的には html、javascript あるいは css ですが、コントローラから渡される変数を含むことがあります。

ビューを作成する

FuelPHP では、 ビューは APPPATH/views ディレクトリに置きます。サブディレクトリに置くこともできます。fuel/app/views からのディレクトリパスとファイル名から命名します。従って、fuel/app/views/user/join.php にあるビューファイルは user/join と命名されます。

例:

<html>
	<head>
		<title><?php echo $title; ?></title>
	</head>
	<body>
		Welcome, <?php echo $username; ?>.
	</body>
</html>

ビューを使用する

FuelPHP フレームワークのビューは柔軟です。単一ビューを作成し、ビューを他のビューの中に入れ子にすることができます。複数の方法で可能です。

ビューの例 (fuel/app/views/home/index.php):

<html>
	<head>
		<title><?php echo $title; ?></title>
	</head>
	<body>
		Welcome, <?php echo $username; ?>.
	</body>
</html>

方法 1 (上記ビューを使用):

class Controller_Home extends Controller
{
	public function action_index()
	{
		$data = array(); // ビューに渡す変数を格納

		$data['username'] = 'Joe14';
		$data['title'] = 'Home';

		// ブラウザに出力するビューを割り当てる
		return View::forge('home/index', $data);
	}
}

方法 2 (上記ビューを使用):

class Controller_Home extends Controller
{
	public function action_index()
	{
		// ビューを作成
		$view = View::forge('home/index');

		// ビューに渡す変数を割り当てる
		$view->username = 'Joe14';
		$view->title = 'Home';

		// ビューに渡す変数を割り当てる別の方法
		$view->set('username', 'Joe14');
		$view->set('title', 'Home');

		// ブラウザに出力するビューを割り当てる
		return $view;
	}
}

セキュリティ

ビューに渡される変数は全てサニタイズされて出力されます。デフォルトの状態では、セキュリティ関数である Security::htmlentities() が出力フィルタとして定義されています。フィルタはアプリケーションの config.php ファイルにて修正できます。 もしフィルタリングせずに変数を渡したい場合、set($name, $value, false) メソッドを使います。

class Controller_Example extends Controller
{
	public function action_index()
	{
		$view = \View::forge('example');

		// フィルタして追加する、出力: &lt;strong&gt;not bold because filtered&lt;/strong&gt;
		$view->title = '<strong>not bold because filtered</strong>';

		// フィルタせず追加する、出力: <strong> bold because unfiltered</strong>
		$view->set('title', '<strong> bold because unfiltered</strong>', false);

		// または、set_safe() メソッドを使う。これは set() メソッドと同じだが、'false' が初期値
		$view->set_safe('title', '<strong> bold because unfiltered</strong>');

		return $view;
	}
}

もしこのように View を出力させたくない場合、falseView::forge() の第三引数として渡すことで、 その View オブジェクトに追加されるものがフィルタリングされないようにできます。 その後、フィルタリングさせたい変数があれば、set($name, $value, true) を使います。
また、アプリケーションの設定値である security.auto_filter_outputfalse にすることで、 出力フィルタをグローバルに無効化することができます。しかし、セキュリティ上の理由から、この設定を行わないことを 強く推奨します。

オブジェクトについての注意: 渡されるオブジェクトが View、Presenter あるいは Closure のインスタンスでない限り、 オブジェクトは __toString() メソッドを持つことが期待され、出力フィルタリングが有効なとき文字列に強制変換されます。どうしても渡したい場合は、 set($name, $value, false) を使用する必要がありますが、 フィルタすることを決して忘れないで ください。
View と Presenter は HTML を含み、サニタイズされないものを独自にフィルタリングすることが期待されます。 Closures はサニタイズできませんので、必要ならば内部でサニタイズが確実に行われるように 注意すべきです。

遅延レンダリング

ビューオブジェクトを初期化するとき、出力を生成するのに必要な環境のみがセットアップされます。ビューファイルは読み込まれず、 変数は解釈されず、出力はレンダリングされません。

これは render() メソッドを明示的に呼び出す場合、あるいは ビューオブジェクトを文字列にキャストする(echo すると自動的にそうなります)ときのみ起きます。つまり、ビューは完全に必要になるまで処理されません。 FuelPHP はブラウザに出力する時が来るまで、レンダリングしたビューをメモリに保存しない、 ということでもあります。

ビューを入れ子にする

ビューは入れ子にすることができます。複数の方法が可能です。

ビューの例

fuel/app/views/layout.php

<html>
	<head>
		<?php echo $head; ?>
	</head>
	<body>
		<?php echo $header; ?>
		<?php echo $content; ?>
		<?php echo $footer; ?>
	</body>
</html>

fuel/app/views/head.php

<title><?php echo $title; ?></title>

fuel/app/views/header.php

<div class="logo"></div>
<div class="logo_text"><?php echo $site_title; ?></div>

fuel/app/views/content.php

<h1><?php echo $title; ?></h1>
<div class="welcome_user">Welcome <?php echo $username; ?></div>

fuel/app/views/footer.php

<div class="footer">
	&copy; Copyright <?php echo date('Y');?> <?php echo $site_title; ?>
</div>

方法 1 (上記の例と遅延レンダリングを使用):

class Controller_Home extends Controller
{
	public function action_index()
	{
		// レイアウトビューを作成する
		$view = View::forge('layout');

		// グローバル変数(すべてのビューがアクセスできる)を割り当てる
		$view->set_global('username', 'Joe14');
		$view->set_global('title', 'Home');
		$view->set_global('site_title', 'My Website');

		//変数としてビューを割り当てる、遅延レンダリング
		$view->head = View::forge('head');
		$view->header = View::forge('header');
		$view->content = View::forge('content');
		$view->footer = View::forge('footer');

		// ビューオブジェクトをリクエストに返す
		return $view;
	}
}

方法 2 (上記の例と強制レンダリングを使用):

class Controller_Home extends Controller
{
	public function action_index()
	{
		//変数を割り当てる
		$data = array();
		$data['title'] = 'Home';
		$data['site_title'] = 'My Website';
		$data['username'] = 'Joe14';

		//変数としてビューを割り当てる、強制レンダリング
		$views = array();
		$views['head'] = View::forge('head', $data)->render();
		$views['header'] = View::forge('header', $data)->render();
		$views['content'] = View::forge('content', $data)->render();
		$views['footer'] = View::forge('footer', $data)->render();

		// レンダリングした HTML をリクエストに返す
		return View::forge('layout', $views)->render();
	}
}

方法 3 (上記の例と遅延レンダリングを使用、グローバルデータなし):

class Controller_Home extends Controller
{
	public function action_index()
	{
		// レイアウトビューを生成
		$view = View::forge('layout');

		// ローカルなビュー内の変数(遅延ロード)
		$view->head = View::forge('head', array('title' => 'Home'));
		$view->header = View::forge('header', array('site_title' => 'My Website'));
		$view->content = View::forge('content', array('username' => 'Joe14', 'title' => 'Home'));
		$view->footer = View::forge('footer', array('site_title' => 'My Website'));

		// リクエストに対し view オブジェクトを返す
		return $view;
	}
}

View の関数についての説明は、「クラス」の項の View クラスを参照して下さい。

ビューに関数を渡す

ビューにコードからビュー特定の関数を渡すには、匿名関数や クロージャ を使用します:

// コントローラアクション
public function action_index()
{
	// view オブジェクトを作成
	$view = \View::forge('page/index');

	// 値を返すクロージャを設定
	$view->somevar = function() { return "somevalue"; };

	// これは同じ動作
	$view->set('othervar', function() { return "othervalue"; });

	// 引数を持つクロージャのために、set_safe を利用しエンコーディングを防ぐ
	$view->set_safe('echo_upper', function($string) { echo strtoupper($string); });
}

// その後、ビューで使用できます:
echo $somevar, $othervar;   // 出力: "somevalue" "othervalue"
$echo_upper('this string'); // 出力: "THIS STRING"

クロージャはフィルタリングに関して値と同様に扱われます。 値を返すクロージャの場合、set() メソッドを使えば、 その値はフィルタリングの設定に従ってエンコードされます。 もし、上記の例のような修飾子の場合や、 返される値がエンコードされるべきでないクロージャの場合は、 set_safe() メソッドを使うか、 set() メソッドの第 3 引数に false を指定して下さい。

クロージャがフィルタされないことを期待しているレガシーアプリケーションでは、 アプリケーションの設定ファイル config.php を編集し、次のキーを追加します:

/**
 * クロージャをフィルタするかどうか
 */
'filter_closures'  => false,