PHPのマイクロフレームワークでであるSlim Frameworkでは、標準ではViewに相当するコンポーネントが用意されていません。マイクロなだけに、ルーティング処理中でViewの出力まで行っても良いのですが、最低限のMVCによるViewの分離ぐらいは行いたい場合が多いです。
このような場合、slimのPhpRender(php-viewパッケージ)を利用することで、素のPHPファイルをテンプレートにしつつ、Viewを別ファイルに分離することができます。
php-viewコンポーネントのインストール
PhpRenderの機能は、slim/php-viewパッケージとして提供されており、composerでインストール出来ます。PhpRenderのパッケージはSlim Framework本体とは別で管理されているため、以下のようにそれぞれインストールします。
composer require slim/slim
composer require slim/php-view
まずは、Slim Frameworkのサンプルコードを実行
php-viewを使わないパターンでのコードを元にして、少しづつ改良を進めていきます。
こちらは、Slim Frameworkに記載されているコードです。
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require 'vendor/autoload.php';
$app = new \Slim\App;
$app->get('/hello/{name}', function (Request $request, Response $response) {
$name = $request->getAttribute('name');
$response->getBody()->write("Hello, $name");
return $response;
});
$app->run();
上記のファイルをindex.phpとして保存し、下記のコマンドで実行します。
php -S localhost:80 index.php
その後、ブラウザからhttp://localhost/hello/aliceにアクセスして、"Hello, alice"の出力されることを確認します。このコードをベースに、PhpRenderパッケージを導入します。
PhpRenderを使う
それでは、PhpRendererを使ったコードに書き換えていきます。
先ほどのコードは、PhpRendererによって以下の様に書くことができます。
// PhpRendererを使用してViewを出力(DIコンテナ未使用)
$app->get('/hello/{name}', function (Request $request, Response $response) {
$renderer = new \Slim\Views\PhpRenderer("./view");
// Viewに渡すパラメータをセット
$viewParam = [
'name' => $request->getAttribute('name'),
];
// Viewの描画
return $renderer->render($response, 'hello/index.tpl', $viewParam);
});
出力処理だった"Hello, $name"に相当する部分がなくなっており、替わりにhello/index.tplというViewの読み込み処理が追加されています。
viewに相当するファイルは、/view/hello/index.tplに別で管理します。
# view/hello/index.tpl
Hello, <?=$name?>
このプログラムを実行すると、最初のプログラムと同じく"Hello, alice."と出力されます。
PhpRendererのコンストラクタでは、viewのファイルを管理するベースディレクトリを指定します。その後、\Slim\Views\PhpRenderer::render()でresponseオブジェクトと、テンプレートを渡せば、結果のhtmlが出力されたresponseとして返されるので、returnすればよいです。
ControllerからViewに渡すパラメータがある場合は、連想配列を用意してrender()の第三引数にセットします。viewでは連想配列のキーが変数名として参照できます。
リクエストのパラメータをそのまま渡す
ルーティングで渡されるパラメータ(URL指定で記述した'/hello/{name}'のnameに該当する部分)は、クロージャーの第三引数で受け取れます。
このため、以下の様に書くとViewへの受け渡しパラメータを別途用意する必要がなくなります。これは、{name}に相当する情報が$args['name']に保存されているためです。
$app->get('/hello/{name}', function (Request $request, Response $response, $args) {
$renderer = new \Slim\Views\PhpRenderer("./view");
return $renderer->render($response, 'hello/index.tpl', $args);
});
ViewRendererをDIコンテナで管理する
Slim FrameworkのViewRendererですが、PhpRenderer以外にもSmartyやTwigをベースにした物が複数用意されています。
このため、上記のコードのようにコントローラー側で直接\Slim\Views\PhpRendererクラスを生成していると、将来Viewのレンダラーを変えたいときに、コントローラのロジックを修正する必要があります。
$renderer = new \Slim\Views\PhpRenderer("./view");
↓
$renderer = new \Slim\Views\SmartyRenderer("./view");
これを避けるためには、DIコンテナを利用するとよいです。
以下のようにDIコンテナにViewのRendererを登録したうえで...
// ViewレンダラをDIコンテナに登録
$app = new \Slim\App;
$container = $app->getContainer();
$container['renderer'] = function ($c) {
return new \Slim\Views\PhpRenderer("./view")
};
コントローラー側では、以下のように$this->rendererで、DIコンテナに登録されたRendererを取得します。
// DIコンテナに登録されたレンダラで出力する
$app->get('/hello/{name}', function (Request $request, Response $response, $args) {
return $this->renderer->render($response, 'hello/index.tpl', $args);
});
こうしておくと、将来Viewレンダラーを変更したい場合に以下のようにDIコンテナへの登録処理だけ差し替えればよくなります。
// ViewレンダラとしてPhpRendererを使用
$container['renderer'] = function ($c) {
return new \Slim\Views\PhpRenderer("./view");
};
↓
// ViewレンダラとしてSmartyを使用
$container['renderer'] = function ($c) {
return new Slim\Views\Smarty()
};