あっぽログ
← 記事一覧に戻る

SymfonyのTwig入門:テンプレート構文・継承・フィルタを使いこなす

Twigとは

TwigはSymfonyで標準採用されているPHP用のテンプレートエンジンです。HTMLとロジックを分離し、読みやすく保守しやすいテンプレートを記述できます。PHPそのものをテンプレートに書くのではなく、Twig独自のシンプルな構文を使います。

主な特徴は以下のとおりです。

  • シンプルな構文{{ }} で変数を出力、{% %} で制御構文を書く
  • テンプレート継承:共通レイアウトを親テンプレートとして定義し、子テンプレートで拡張できる
  • 自動エスケープ:XSS対策としてデフォルトでHTMLエスケープが有効
  • 豊富なフィルタと関数:文字列・配列・日付などの操作が組み込み済み

基本的な構文

変数の出力

{{ 変数名 }} で変数をHTMLに出力します。

{# templates/greeting.html.twig #}
<h1>こんにちは、{{ name }} さん!</h1>
<p>今日は {{ today }} です。</p>

Symfonyのコントローラからテンプレートに値を渡すには、render() メソッドで配列を渡します。

// src/Controller/GreetingController.php
namespace App\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Attribute\Route;

class GreetingController extends AbstractController
{
    #[Route('/greeting', name: 'app_greeting')]
    public function index(): Response
    {
        return $this->render('greeting.html.twig', [
            'name'  => '太郎',
            'today' => (new \DateTime())->format('Y年m月d日'),
        ]);
    }
}

制御構文(if・for)

{% if %} で条件分岐、{% for %} でループ処理を記述します。

{# 条件分岐 #}
{% if user.isAdmin %}
  <p>管理者としてログイン中です。</p>
{% elseif user.isLoggedIn %}
  <p>ようこそ、{{ user.name }} さん。</p>
{% else %}
  <p>ログインしてください。</p>
{% endif %}

{# ループ #}
<ul>
  {% for item in items %}
    <li>{{ loop.index }}. {{ item.name }}({{ item.price }}円)</li>
  {% else %}
    <li>商品がありません。</li>
  {% endfor %}
</ul>

loop.index はループの現在のインデックス(1始まり)を返す特別な変数です。loop.firstloop.last で最初・最後の判定もできます。

テンプレートの継承

Twigの最も強力な機能のひとつがテンプレート継承です。サイト共通のレイアウトを親テンプレートに定義し、ページごとに変わる部分だけを子テンプレートで上書きできます。

親テンプレート(base.html.twig)

{# templates/base.html.twig #}
<!DOCTYPE html>
<html lang="ja">
<head>
  <meta charset="UTF-8">
  <title>{% block title %}マイサイト{% endblock %}</title>
  {% block stylesheets %}{% endblock %}
</head>
<body>
  <header>
    <nav>共通ナビゲーション</nav>
  </header>

  <main>
    {% block body %}{% endblock %}
  </main>

  <footer>
    <p>&copy; 2026 マイサイト</p>
  </footer>

  {% block javascripts %}{% endblock %}
</body>
</html>

{% block ブロック名 %}{% endblock %} で子テンプレートが上書きできる領域を定義します。

子テンプレート

{# templates/product/list.html.twig #}
{% extends 'base.html.twig' %}

{% block title %}商品一覧 - マイサイト{% endblock %}

{% block body %}
  <h1>商品一覧</h1>
  <ul>
    {% for product in products %}
      <li>
        <a href="{{ path('app_product_show', { id: product.id }) }}">
          {{ product.name }}
        </a>
        - {{ product.price|number_format(0, '.', ',') }}円
      </li>
    {% endfor %}
  </ul>
{% endblock %}

{% extends %} で親テンプレートを指定し、各 {% block %} セクションを子テンプレートで上書きします。

フィルタと関数

よく使うフィルタ

フィルタは {{ 値|フィルタ名 }} の形式で使います。

{# 文字列の操作 #}
{{ 'hello world'|upper }}        {# HELLO WORLD #}
{{ 'HELLO WORLD'|lower }}        {# hello world #}
{{ '  spaces  '|trim }}          {# spaces #}
{{ 'long text here'|truncate(8) }} {# long tex... #}

{# 数値のフォーマット #}
{{ 1234567|number_format(0, '.', ',') }}  {# 1,234,567 #}

{# 日付のフォーマット #}
{{ post.createdAt|date('Y年m月d日') }}

{# デフォルト値 #}
{{ user.nickname|default('名無し') }}

{# 配列の操作 #}
{{ items|length }}          {# 要素数 #}
{{ items|join(', ') }}      {# カンマ区切りで結合 #}
{{ items|sort }}            {# ソート #}

raw フィルタと自動エスケープ

TwigはデフォルトでHTML特殊文字をエスケープします。HTMLタグを含む文字列をそのまま出力したい場合は |raw フィルタを使いますが、ユーザー入力に対して使うのは危険です。信頼できるデータにのみ使用してください。

{# エスケープあり(デフォルト) #}
{{ '<b>太字</b>' }}   {# &lt;b&gt;太字&lt;/b&gt; として出力 #}

{# エスケープなし(信頼できるデータのみ) #}
{{ article.htmlContent|raw }}

マクロで再利用可能なコンポーネントを作る

Twigのマクロは、再利用可能なテンプレート部品を定義する機能です。

{# templates/macros/form.html.twig #}
{% macro input(name, value, type = 'text', label = '') %}
  <div class="form-group">
    {% if label %}
      <label for="{{ name }}">{{ label }}</label>
    {% endif %}
    <input type="{{ type }}" id="{{ name }}" name="{{ name }}" value="{{ value }}">
  </div>
{% endmacro %}
{# 別テンプレートから使う #}
{% import 'macros/form.html.twig' as forms %}

<form method="post">
  {{ forms.input('username', '', 'text', 'ユーザー名') }}
  {{ forms.input('password', '', 'password', 'パスワード') }}
  <button type="submit">ログイン</button>
</form>

まとめ

Twigの主要な機能をまとめると以下のとおりです。

機能構文用途
変数出力{{ 変数 }}値の表示
制御構文{% if %} {% for %}条件分岐・ループ
テンプレート継承{% extends %} {% block %}レイアウト共通化
フィルタ値|フィルタ名値の変換・整形
マクロ{% macro %}再利用可能な部品
コメント{# コメント #}テンプレート内注釈

Twigを使いこなすことで、PHPのロジックとHTMLの見た目を明確に分離でき、チーム開発でのメンテナンス性が大幅に向上します。Symfonyプロジェクトではまずテンプレート継承とフィルタをしっかりと押さえておきましょう。

← 記事一覧に戻る