【第5回】 Twig関数の拡張

DrupalのUnmanaged Files(パート5):Twig関数の拡張
目次

カスタムTwig関数を拡張して、テーマ開発者がテンプレート内で直接URLまたは完全な画像タグを選択できるようにします。画像スタイルの適用方法や、安全なHTML出力の実装方法を学べます。

編集者注:この記事は、Jeff Greenbergによる「DrupalのUnmanaged Files」チュートリアルシリーズの第5弾です。各記事は前回の内容を基に構築され、データベースのオーバーヘッドなしでファイルを管理およびレンダリングするさまざまな方法を探ります。このパートでは、以前に導入したTwig関数を拡張し、Drupalテンプレート内で開発者とテーマ作成者により多くの柔軟性を提供します。

パート4では、モジュールで定義されたTwigテンプレートを通じて非管理ファイルをレンダリングしました。このパートでは、以前に導入したTwig関数をアップグレードすることで、その柔軟性を拡張します。これにより、テーマ作成者はTwigから直接、URLまたは完全にレンダリングされた画像タグのどちらを使用するかを決定できます。これにより、構文がシンプルに保たれ、別のヘルパー関数が不要になり、Drupalのis_safeオプションを使用してカスタムTwig関数から安全にHTMLを返す方法を実証します。

更新されたTwig拡張機能

Twig拡張クラスを更新して、2つのオプション引数$format$styleを追加します。{{ random_unmanaged_file('url') }}として呼び出す(または引数なしで呼び出す)と、ファイルURLを返します。{{ random_unmanaged_file('img') }}として呼び出すと、レンダリング可能な<img>タグを返します。また、2番目の引数としてオプションの画像スタイル名を渡すこともできます。例えば、{{ random_unmanaged_file('img', 'thumbnail') }}とすることで、Twigから直接DrupalのImage Stylesをプログラム的に適用できます。

<?php
namespace Drupal\unmanaged_files\Twig;

use Drupal\unmanaged_files\Service\FileHandler;
use Drupal\Core\File\FileUrlGeneratorInterface;
use Twig\Extension\AbstractExtension;
use Twig\TwigFunction;
use Drupal\image\Entity\ImageStyle;
use Drupal\Component\Utility\Html;

/**
 * テンプレートに非管理ファイルヘルパーを公開するTwig拡張機能。
 */
final class UnmanagedFilesExtension extends AbstractExtension {

  public function __construct(
    private FileHandler $handler,
    private FileUrlGeneratorInterface $urlGen,
  ) {}

  /**
   * {@inheritdoc}
   */
  public function getFunctions(): array {
    return [
      new TwigFunction('random_unmanaged_file', [$this, 'getRandomFile'], ['is_safe' => ['html']]),
    ];
  }

  /**
   * ランダムな非管理ファイルのファイルURLまたは<img>タグを返します。
   *
   * @param string $format
   *   'url'(デフォルト)でファイルURLを返すか、'img'で<img>タグを返します。
   * @param string|null $style
   *   (オプション)画像スタイルのマシン名、$format = 'img'の場合のみ使用されます。
   *
   * @return string|null
   *   URLまたはHTML文字列、ファイルが見つからない場合はNULL。
   */
  public function getRandomFile(string $format = 'url', ?string $style = NULL): ?string {
    $uri = $this->handler->getRandomFile();
    if (!$uri) {
      return NULL;
    }

    // 絶対ファイルURLから始めます。
    $url = $this->urlGen->generateAbsoluteString($uri);

    // 要求された場合は画像スタイルを適用します。
    if ($format === 'img' && $style) {
      if ($image_style = ImageStyle::load($style)) {
        $url = $image_style->buildUrl($uri);
      }
    }

    if ($format === 'img') {
      $safeUrl = Html::escape($url);
      return '<img src="' . $safeUrl . '" alt="ランダムな非管理ファイル">';
    }

    return $url;
  }
}
図1. 拡張されたTwig拡張クラス

関数の使用方法

更新された関数を配置したら、キャッシュをクリア(ddev drush crまたはdrush cr)し、任意のTwigテンプレートで直接いずれかの形式を使用できます:

{# 例1: URLのみ #}
<p>ファイルURL: {{ random_unmanaged_file() }}</p>

{# 例2: レンダリングされた画像 #}
{{ random_unmanaged_file('img') }}

{# 例3: 特定のスタイルを使用したレンダリングされた画像 #}
{{ random_unmanaged_file('img', 'thumbnail') }}
図2. Twigテンプレートでの使用例

「is_safe」について

通常、Drupalは安全でないHTMLを防ぐために、Twig関数からのすべての出力をエスケープします。関数宣言のis_safeフラグは、返される文字列が意図的にHTMLとしてレンダリングしても安全であることをTwigに伝えます。これは、出力を制御およびサニタイズする場合にのみ使用することが重要です。この場合、DrupalのFile APIによって構築された内部URLです。

セキュリティ上の注意:is_safeフラグを使用する際は、出力が完全に制御されており、適切にサニタイズされていることを確認してください。この例では、Html::escape()を使用してURLをエスケープし、XSS攻撃を防いでいます。

なぜこのアプローチなのか?

この小さな拡張により、テーマ開発者に最大限の利便性が提供されます:

  • URL形式:背景画像、CSS変数、またはリンクに便利です
  • 画像タグ形式:インライン表示、バナー、または装飾画像に最適です
  • 画像スタイル対応:Drupalの画像スタイルを直接適用できます

この進化は、現実世界の柔軟性を反映しています。固定されたレンダリングから、テーマやモジュール間で再利用できる動的なヘルパーへと発展します。

以前のパートとの比較

パート アプローチ 適用対象
パート3 Block Plugin サイトビルダー向けの設定可能な配置
パート4 Twigテンプレート デザイナー向けの固定出力構造
パート5 Twig関数 開発者とテーマ作成者向けのドロップイン型再利用可能ヘルパー

次のステップ

パート6では、ハンドラー内のロジックを拡張して、複数のランダムファイルを選択し、同じカテゴリから2つの選択が行われないようにします。

この記事は 「Unmanaged Files in Drupal (Part 5): Enhancing the Twig Function」の翻訳記事です。

カテゴリ

タグ