0
0

【PHP/Slim4】3.軽量フレームワーク(Slim4-skeleton) Twig

Posted at

やりたいこと

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;
        }
    ]);

解説

  1. settings.php:twig->reloadCacheは独自定義。CSSファイルやJSファイルのキャッシュ対応。開発時にキャッシュが効きすぎてCSS/JSの更新が行えないのがだるいので、現時刻のUnix時刻を設定している。後述のテンプレートで使用する
  2. settings.php:twig->strict_variablesはTwigの定義。false:Twigのエラーを無視。true:Twigのエラーを検知なので、基本はtrueを設定が良い
  3. settings.php:twig->cacheはTwigの定義。Twigでレンダリングしたビューのファイルキャッシュ置き場を指定する
  4. settings.php:assets->pathは独自定義。CSSやJavaScriptファイルの置き場を指定。後述にテンプレートで使用
  5. middleware.php: Twigのミドルウェア追加
  6. dependencies.php:settingsは必ず設定。固定形式
  7. dependencies.php:renderTwigは必ず設定。Twigテンプレートファイルの置き場所を指定
  8. 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 %}

解説

  1. layoutBase.html.twig:親テンプレートファイル。共通の画面レイアウトや共通のJavaScriptなどを設定する。画面ごとに分かれる内容を{% block xxxxxx %}{% endblock %}で、子テンプレートから取り込む
  2. childHoge.html.twig/childFuga.html.twig:extendsで親テンプレートを指定する
  3. childHoge.html.twig/childFuga.html.twig:{% block xxxxxxx %}で、子テンプレートごとの内容を記載。親テンプレートに読み込ませる。
  4. 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]);
	}
}

解説

  1. routes.php:アクセスするURIの指定。何かしらのAction追加するときには、このファイルは編集対象となる
  2. HogeAction.php/FugaAction.php:useで取り込む依存関係。定型文のようなものなのでまねておく
  3. HogeAction.php/FugaAction.php:__constructは、Action起動時に一番はじめによばれるメソッド。依存関係の設定をしていれば、TwigのインスタンスなどがSlimから引数で渡される。Twigのレンダリングをするために、Private変数にTwigインスタンスを保存
  4. 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));
            }
        }
    }

解説

  1. FilesystemLoader.php:level変数でTwigテンプレートの階層をチェックしているため、ifの真条件をコメントアウトすることで、階層制限が解除できる。ただし、解除することによる弊害は不明
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0