読者です 読者をやめる 読者になる 読者になる

tanaka's Programming Memo

プログラミングについてのメモ。

Twigの勉強メモ-SlimPHPで動かす for mac

PHP 勉強メモ

SlimPHPのテンプレートエンジンとして、Twigを利用する手順をまとめておきます。

掲載したコードは Templates - Slim Framework のものを、SlimPHPのSkeletonプロジェクトで動くように書き換えたものです。

SlimPHPプロジェクトの作成

  • composerはグローバルで動くものとする
  • ターミナルを起動
  • プロジェクトフォルダーを作りたいフォルダーに移動
  • 以下でプロジェクトを作成(slim-twig-test フォルダーをプロジェクトフォルダーにする場合の例)
composer create-project slim/slim-skeleton slim-twig-test
cd slim-twig-test
composer require slim/twig-view
  • 作成したフォルダー内に出来上がる composer.jsonテキストエディタで開く
  • "require" 欄から "slim/php-view" の行は不要なので削除して、上書き保存
  • ターミナルで以下を実行して、インストール環境を更新する
composer update

設定ファイルを準備する

テンプレート用のパスと、Twigのオプションを設定します。PHPの組み込みサーバーで動作しているかどうかで、デバッグと本番設定を切り替えられるようにします。本番用は cache を利用し、デバッグ用は debug フラグをtrueにして、更新を監視するようにします。

  • /src/settings.php を開く
  • 以下のように修正
<?php
return [
    'settings' => [
        'displayErrorDetails' => true, // set to false in production

        // Twig settings
        'view' => [
            'template_path' => __DIR__ . '/../templates/',
            'options' => [
                'cache' => __DIR__ . '/../cache/'
            ]
        ],

        // Monolog settings
        'logger' => [
            'name' => 'slim-app',
            'path' => __DIR__ . '/../logs/app.log',
        ],
    ],
];
  • PHPの組み込みサーバーで起動した時のテスト用の設定として、/srcフォルダー内に settings-debug.php を作成して、以下のようにする
<?php
return [
    'settings' => [
        'displayErrorDetails' => true, // set to false in production

        // Twig settings
        'view' => [
            'template_path' => __DIR__ . '/../templates/',
            'options' => [
                'debug' => true
            ]
        ],

        // Monolog settings
        'logger' => [
            'name' => 'slim-app',
            'path' => __DIR__ . '/../logs/app.log',
        ],
    ],
];
  • 設定を読み込むために /public/index.php を開いて以下の通りにする
<?php
if (PHP_SAPI == 'cli-server') {
    // To help the built-in PHP dev server, check if the request was actually for
    // something which should probably be served as a static file
    $file = __DIR__ . $_SERVER['REQUEST_URI'];
    if (is_file($file)) {
        return false;
    }

    $settings = require __DIR__ . '/../src/settings-debug.php';
}
else {
    $settings = require __DIR__ . '/../src/settings.php';
}

require __DIR__ . '/../vendor/autoload.php';

session_start();

// Instantiate the app
$app = new \Slim\App($settings);

// Set up dependencies
require __DIR__ . '/../src/dependencies.php';

// Register middleware
require __DIR__ . '/../src/middleware.php';

// Register routes
require __DIR__ . '/../src/routes.php';

// Run app
$app->run();

コンテナにTwigを設定

SlimPHPのコンテナにTwigを追加します。

  • /src/dependencies.php を開く
  • 以下のようにする
<?php
// DIC configuration

$container = $app->getContainer();

// view renderer
$container['view'] = function ($c) {
    $settings = $c->get('settings')['view'];
    $view = new \Slim\Views\Twig(
        $settings['template_path'],
        $settings['options']
    );
    $view->addExtension(new \Slim\Views\TwigExtension(
        $c['router'],
        $c['request']->getUri()
    ));

    return $view;
};

// monolog
$container['logger'] = function ($c) {
    $settings = $c->get('settings')['logger'];
    $logger = new Monolog\Logger($settings['name']);
    $logger->pushProcessor(new Monolog\Processor\UidProcessor());
    $logger->pushHandler(new Monolog\Handler\StreamHandler($settings['path'], Monolog\Logger::DEBUG));
    return $logger;
};

ルートを設定

リクエストに応じた処理を呼び出すルートを設定します。今回は、 http://0.0.0.0:8080/hello を呼び出すと、与えられた配列のユーザー一覧を表示して、 http://0.0.0.0:8080/hello/ユーザー名 とすると、指定したユーザーのプロフィールを表示するようにします。

  • /src/routes.php を開いて、以下のようにする
<?php
// Routes

// ユーザー一覧
$app->get('/hello', function($request, $response, $args) {
    // ユーザー一覧
    $users = [
        'Tama',
        'Kotta',
        'Tanaka'
    ];

    return $this->view->render($response, 'list.html', [
        'list' => $users
    ]);
})->setName('list');

// 指定のユーザーのプロフィールを表示
$app->get('/hello/{name}', function ($request, $response, $args) {
    return $this->view->render($response, 'profile.html', [
        'name' => $args['name']
    ]);
})->setName('profile');

/hello で呼び出された場合

  • list.html をテンプレートに利用
  • $users 配列に設定したデータを 'list' という名前でテンプレートエンジンに渡す
  • /hello のパスを list という名前で記録しておく

/hello/{name} で呼び出された場合

  • profile.html をテンプレートに利用
  • パスの{name}の場所のデータを、 'name' という名前でテンプレートエンジンに渡す
  • /hello/{name} のパスを profile という名前で記録しておく

テンプレートの作成

Twigのサンプルテンプレートを準備して、ルートに対応させます。

レイアウトテンプレートの作成

ユーザー一覧ページとプロフィールページのひな形となるレイアウト layout.html を作成します。

  • /templates フォルダー内に layout.html を作成
  • 以下のコードを書く
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>SlimPHP Twig Test-{% block title %}{% endblock %}</title>
</head>
<body>
    <h1>{% block pagetitle %}{% endblock %}</h1>

    <div id='content'>
        {% block content %}
        {% endblock %}
    </div>

    <hr />

    <div id='footer'>
        &copy; Copyright 2016 by YuTanaka
    </div>
</body>
</html>
  • {% block <ブロック名> %}から{% endblock %}までの箇所を、他のテンプレートで指定した内容に差し替えることが可能
  • 以下のようなブロックを定義している。list.htmlとprofile.htmlの {% block ・・・%} で囲んだ範囲が置きかわる
    • title ブロック
    • pagetitle ブロック
    • content ブロック

ユーザー一覧ページ用のテンプレートの作成

  • /templates フォルダー内に list.html を新規に作成
  • 以下のTwigテンプレートコードを入力
{% extends "layout.html" %}

{% block title %}User List{% endblock %}

{% block pagetitle %}User List{% endblock %}
{% block content %}
    <ul>
        {% for item in list %}
        <li><a href="{{ path_for('profile', {'name': item}) }}">{{item}}</a></li>
        {% endfor %}
    </ul>
{% endblock %}
  • layout.html を継承することを宣言
  • タイトルとページタイトルに User List を設定
  • content ブロックに、ulタグを作成
  • {% for item in list %} とすることで、 routes.php で list に渡した配列をループして、要素を item に入れて {% endfor %} との間をループ
  • path_for()メソッドは、 slim/twig-view による拡張メソッド。解釈は以下の通り
    • 第1引数に、ルート名を渡す。ルート名は routes.php のルート定義で->setName()したもの
    • 第2引数に、ルートのプレースホルダーに対応するデータをオブジェクトで渡す
    • この例では、クリックしたらプロファイルページを呼び出したいので、 profile のルートを指定して、'name'のプレースホルダーをループで取り出すitemに置き換える
  • {{item}}とすると、itemの中身を表示

詳細ページ用のテンプレートの作成

  • /templates フォルダー内に profie.html を新規に作成
  • 以下のTwigテンプレートコードを入力
{% extends "layout.html" %}

{% block title %}Profile{% endblock %}

{% block pagetitle %}{{name}}'s Profile{% endblock %}
{% block content %}
<p>これは「{{name}}」のプロフィールです。</p>
<p><a href="{{ path_for('list') }}">一覧へ</a></p>
{% endblock %}
  • layout.html を継承することを宣言
  • タイトルにProfileを設定
  • ページタイトルに、渡された name プロパティと、続けて 's Profile を設定
  • content ブロックでは、「name プロパティのプロフィールです。」と表示する段落と、一覧に戻るリンクを設定
  • 一覧へ戻るためのリンクは、listのルートをそのまま使う

テスト

準備ができたら、PHPの組み込みサーバーを起動して、動作を確認します。

  • サーバーを起動
php -S 0.0.0.0:8080 -t public public/index.php
  • ブラウザーhttp://0.0.0.0:8080/hello にアクセス
  • 一覧が表示されるのを確認
  • 任意の名前をクリック
  • クリックした名前のプロフィールが表示されることを確認
  • 「一覧へ」をクリックして、一覧ページに戻ることを確認