やりたいこと
Slim4のテンプレートエンジンを使ってみる
Twigがメジャーっぽいので、なんとなくTwigを使ってみようと思う
Step1.サンプル環境の構築
Step2.Twigのインストール
プロジェクトフォルダに移動後、以下のコマンドを実行
composer require slim/twig-view
Step3.Twigの依存関係を設定
dependencies.phpにTwigの依存関係を注入する
またsettings.phpでパス等の設定を切り替えられるようにしておく
app/settings.php
return function (ContainerBuilder $containerBuilder) {
// Global Settings Object
$containerBuilder->addDefinitions([
SettingsInterface::class => function () {
return new Settings([
:(略)
],
// Twig設定
,'twig' => [
'reloadCache' => time()
,'strict_variables' => true
,'cache' => __DIR__ . '/../var/cache/twig'
]
// CSS,JS,画像置き場
,'assets' =>[
'path' => '/assets'
]
]);
}
]);
app/middleware.php
use Slim\Views\Twig;
use Slim\Views\TwigMiddleware;
return function (App $app) {
$app->add(SessionMiddleware::class);
$app->add(TwigMiddleware::createFromContainer($app, Twig::class));
};
app/dependencies.php
use Slim\Views\Twig;
return function (ContainerBuilder $containerBuilder) {
$containerBuilder->addDefinitions([
LoggerInterface::class => function (ContainerInterface $c) {
:(略)
},
// Twig
Twig::class => function (ContainerInterface $container) {
// Twig設定
$settings = $container->get(SettingsInterface::class);
// テンプレートの置き場所設定
$renderTwig = Twig::create(__DIR__ . '/../templates', $settings->get('twig'));
// Css/Jsのキャッシュ読み込み (hoge.css?v=xxxx 対応)
$renderTwig->offsetSet('reloadCache', $settings->get('twig')['reloadCache']);
// CSS/JSなどのファイル格納
$renderTwig->offsetSet('assetsUrl', $settings->get('assets')['path']);
return $renderTwig;
}
]);
解説
- settings.php:twig->reloadCacheは独自定義。CSSファイルやJSファイルのキャッシュ対応。開発時にキャッシュが効きすぎてCSS/JSの更新が行えないのがだるいので、現時刻のUnix時刻を設定している。後述のテンプレートで使用する
- settings.php:twig->strict_variablesはTwigの定義。false:Twigのエラーを無視。true:Twigのエラーを検知なので、基本はtrueを設定が良い
- settings.php:twig->cacheはTwigの定義。Twigでレンダリングしたビューのファイルキャッシュ置き場を指定する
- settings.php:assets->pathは独自定義。CSSやJavaScriptファイルの置き場を指定。後述にテンプレートで使用
- middleware.php: Twigのミドルウェア追加
- dependencies.php:settingsは必ず設定。固定形式
- dependencies.php:renderTwigは必ず設定。Twigテンプレートファイルの置き場所を指定
- dependencies.php:renderTwig->offsetSetは独自定義。offsetSetメソッドで独自の設定値をTwigに渡すことが可能。後述のテンプレートで使用
Step4.Twigのテンプレートを作成する
例として以下のテンプレート構成で作成を行う
ファイル名 | 概要 |
---|---|
templates/layoutBase.html.twig | 親のテンプレート |
templates/childHoge.html.twig | 子テンプレート その1 |
templates/childFuga.html.twig | 子テンプレート その2 |
templates/layoutBase.html.twig
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<link rel="icon" href="data:,">
</head>
<body>
{# Twigコメント、共通項目 #}
<div>
{# Twig変数読み込み #}
これは{{ templateTitle }}です
{# Twigの条件判定 #}
{% if isAddComment is defined and isAddComment == true %}
{% block AddComment %}{% endblock %}
{% endif %}
</div>
{# Twigコメント、子テンプレート #}
<div>
{% block childTemplate %}{% endblock %}
</div>
<!-- 個別JavaScript -->
{% block includeJs %}{% endblock %}
</body>
</html>
templates/childHoge.html.twig
{# 基本レイアウト #}
{% extends 'layoutBase.html.twig' %}
{# JSファイル 設定 #}
{% block includeJs %}
<script type="text/javascript" src="../{{ assetsUrl }}/js/hoge.js?v={{ reloadCache }}"></script>
{% endblock %}
{# メインメニュー 設定 #}
{% block childTemplate %}
hogeファイルを読み込んだ
{% endblock %}
templates/childFuga.html.twig
{# 基本レイアウト #}
{% extends '../templates/layoutBase.html.twig' %}
{# JSファイル 設定 #}
{% block includeJs %}
<script type="text/javascript"></script>
{% endblock %}
{% set isAddComment = true %}
{% block AddComment %}
fugaの追加コメントです
{% endblock %}
{# メインメニュー 設定 #}
{% block childTemplate %}
fugaファイルを読み込んだ
{% endblock %}
解説
- layoutBase.html.twig:親テンプレートファイル。共通の画面レイアウトや共通のJavaScriptなどを設定する。画面ごとに分かれる内容を{% block xxxxxx %}{% endblock %}で、子テンプレートから取り込む
- childHoge.html.twig/childFuga.html.twig:extendsで親テンプレートを指定する
- childHoge.html.twig/childFuga.html.twig:{% block xxxxxxx %}で、子テンプレートごとの内容を記載。親テンプレートに読み込ませる。
- childFuga.html.twig:{% set xxxxxxx = true %}で、子テンプレートごとに変数定義が可能。親テンプレートで読み込ませ表示の出しわけが可能
Step5.Twigのテンプレートを読み込ませるイベントを作成
以下の設定を行い、テンプレートの読み込ませるActionイベントを作成する
ファイル名 | 概要 |
---|---|
app/routes.php | URL/Actionイベントの設定 |
src/Application/Actions/Test/HogeAction.php | 子テンプレート その1のAction |
src/Application/Actions/Test/FugaAction.php | 子テンプレート その2のAction |
app/routes.php
use Slim\Interfaces\RouteCollectorProxyInterface as Group;
use App\Application\Actions\Test\HogeAction;
use App\Application\Actions\Test\FugaAction;
return function (App $app) {
:(略)
$app->group('/twig', function (Group $group) {
$group->get('/hoge', HogeAction::class);
$group->get('/fuga', FugaAction::class);
});
};
src/Application/Actions/Test/HogeAction.php
<?php
declare(strict_types=1);
namespace App\Application\Actions\Test;
use App\Application\Actions\Action;
use Slim\Views\Twig;
use Psr\Log\LoggerInterface;
use Psr\Http\Message\ResponseInterface as Response;
use App\Application\Settings\SettingsInterface;
class HogeAction extends Action{
private $twig;
public function __construct(LoggerInterface $logger, Twig $twig, SettingsInterface $settings) {
parent::__construct($logger, $twig, $settings);
$this->twig = $twig;
}
/**
* {@inheritdoc}
*/
protected function action(): Response {
$template = './childHoge.html.twig';
$title = 'Hoge';
return $this->twig->render($this->response, $template,
[ 'templateTitle' => $title]);
}
}
src/Application/Actions/Test/FugaAction.php
<?php
declare(strict_types=1);
namespace App\Application\Actions\Test;
use App\Application\Actions\Action;
use Slim\Views\Twig;
use Psr\Log\LoggerInterface;
use Psr\Http\Message\ResponseInterface as Response;
use App\Application\Settings\SettingsInterface;
class FugaAction extends Action{
private $twig;
public function __construct(LoggerInterface $logger, Twig $twig, SettingsInterface $settings) {
parent::__construct($logger, $twig, $settings);
$this->twig = $twig;
}
/**
* {@inheritdoc}
*/
protected function action(): Response {
$template = './childFuga.html.twig';
$title = 'Fuga';
return $this->twig->render($this->response, $template,
[ 'templateTitle' => $title]);
}
}
解説
- routes.php:アクセスするURIの指定。何かしらのAction追加するときには、このファイルは編集対象となる
- HogeAction.php/FugaAction.php:useで取り込む依存関係。定型文のようなものなのでまねておく
- HogeAction.php/FugaAction.php:__constructは、Action起動時に一番はじめによばれるメソッド。依存関係の設定をしていれば、TwigのインスタンスなどがSlimから引数で渡される。Twigのレンダリングをするために、Private変数にTwigインスタンスを保存
- HogeAction.php/FugaAction.php:actionは、View処理メソッド。templete変数にActionに対応したTwigテンプレートの指定。twig->renderでテンプレートに描写を行う。[]に連想配列で値を設定すれば、Twigテンプレートにその値を渡すことが可能(サンプルでは、templateTitle変数のみを引き渡している)
Step6.Twigの表示確認
routes.phpで設定したURIにアクセスし表示を確認する。
もしこのとき、「Looks like you try to load a template outside configured directories」というエラーが画面に表示された場合、Twigのテンプレートファイルの指定/格納場所が、同一ディレクトリ内にない可能性がある。Twigの制約に引っかかっている可能性がある。
Twigテンプレートの格納位置を調整するか、以下をコメントアウトすることで制約の解除が可能
※Twigのバージョンによってはファイル名が異なる可能性がある
vendor/twig/twig/src/Loader/FilesystemLoader.php
private function validateName(string $name): void
{
:(略)
foreach ($parts as $part) {
:(略)
if ($level < 0) {
// throw new LoaderError(sprintf('Looks like you try to load a template outside configured directories (%s)(%d).', $name,$level));
}
}
}
解説
- FilesystemLoader.php:level変数でTwigテンプレートの階層をチェックしているため、ifの真条件をコメントアウトすることで、階層制限が解除できる。ただし、解除することによる弊害は不明