【第3回】Block Pluginで画像を動的に表示する実装ガイド

【第2回】ブロック内での非管理ファイルのレンダリング
目次

Block Pluginを使用して非管理ファイルをサイトに表示する方法を解説します。前回作成したファイルハンドラーサービスをブロックとして実装し、サイトビルダーがUI経由で自由に配置できるようにします。

パート2では、非管理ファイルを検索してランダムに1つを返すサービスを構築しました。このパートでは、その機能をBlock Pluginとして公開します。ブロックを使用することで、カスタムロジックを再利用可能な形で実装できます。サイトビルダーは、Drupalのブロックレイアウトインターフェイスを通じて、コードを変更することなく、任意の場所に配置できます。

Block Pluginクラスの基本構造と実装

クラスはBlockBaseを継承し、ContainerFactoryPluginInterfaceを実装します。これにより、DrupalのサービスコンテナからファイルハンドラーとURL生成サービスを注入できます。

<?php
namespace Drupal\unmanaged_files\Plugin\Block;

use Drupal\Core\Block\BlockBase;
use Drupal\Core\File\FileUrlGeneratorInterface;
use Drupal\unmanaged_files\Service\FileHandler;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;

/**
 * ランダムな非管理ファイルを表示するブロックを提供します。
 *
 * @Block(
 *   id = "unmanaged_files_block",
 *   admin_label = @Translation("Unmanaged Files Block"),
 * )
 */
final class UnmanagedFilesBlock extends BlockBase implements ContainerFactoryPluginInterface {
図1. Block Pluginクラスの定義

依存性注入を活用したコンストラクターの実装

コンストラクターは、通常のプラグインパラメーターに加えて、2つの注入されたサービスを受け取ります。カスタムFileHandlerとDrupalのFileUrlGeneratorInterfaceです。これらは、後で使用するためにプライベートプロパティとして保存されます。

  /**
   * 新しいUnmanagedFilesBlockインスタンスを構築します。
   *
   * @param array $configuration
   *   プラグインインスタンスに関する情報を含む設定配列。
   * @param string $plugin_id
   *   ブロックのプラグインID。
   * @param mixed $plugin_definition
   *   プラグイン実装の定義。
   * @param \Drupal\unmanaged_files\Service\FileHandler $handler
   *   非管理ファイル用のファイルハンドラーサービス。
   * @param \Drupal\Core\File\FileUrlGeneratorInterface $urlGen
   *   ファイルURL生成サービス。
   */
  public function __construct(
    array $configuration,
    $plugin_id,
    $plugin_definition,
    private FileHandler $handler,
    private FileUrlGeneratorInterface $urlGen,
  ) {
    parent::__construct($configuration, $plugin_id, $plugin_definition);
  }
図2. 依存性注入を行うコンストラクター

コンテナファクトリパターンによるサービス注入

コンストラクターがサービスを必要とするため、ContainerFactoryPluginInterfaceからcreate()も実装します。これは、コンテナからサービスを取得し、コンストラクターに渡します。@varアノテーションは、IDEが型を理解し、誤った警告を回避するのに役立ちます。

  /**
   * UnmanagedFilesBlockのインスタンスを作成します。
   *
   * このファクトリーメソッドは、コンテナから必要なサービスを注入します。
   *
   * @param \Symfony\Component\DependencyInjection\ContainerInterface $c
   *   サービスコンテナ。
   * @param array $configuration
   *   プラグインインスタンスに関する情報を含む設定配列。
   * @param string $plugin_id
   *   ブロックのプラグインID。
   * @param mixed $plugin_definition
   *   プラグイン実装の定義。
   *
   * @return static
   *   新しいUnmanagedFilesBlockインスタンスを返します。
   */
  public static function create(ContainerInterface $c, array $configuration, $plugin_id, $plugin_definition): self {
    /** @var \Drupal\unmanaged_files\Service\FileHandler $handler */
    $handler = $c->get('unmanaged_files.handler');

    /** @var \Drupal\Core\File\FileUrlGeneratorInterface $urlGen */
    $urlGen = $c->get('file_url_generator');

    return new self(
      $configuration,
      $plugin_id,
      $plugin_definition,
      $handler,
      $urlGen,
    );
  }
図3. 依存性注入のためのファクトリーメソッド

レンダー配列を生成するbuildメソッドの実装

build()メソッドは、Drupalがブロックをレンダリングするために呼び出すものです。ファイルハンドラーにランダムな非管理ファイルを要求します。ファイルが見つかった場合は、imageテーマを使用してレンダー配列を返します。ファイルが見つからない場合は、シンプルなメッセージを返します。max-ageキャッシュメタデータは1秒に設定されているため、ページをリフレッシュすると画像が素早くローテーションします。

  /**
   * ブロックのレンダー配列を構築します。
   *
   * ファイルハンドラーを使用してランダムな非管理ファイルを取得し、
   * それを画像レンダー配列として返します。非管理ファイルが見つからない場合は、
   * 代わりにシンプルなメッセージを返します。
   *
   * @return array
   *   ブロックコンテンツのレンダー配列。
   */
  public function build(): array {
    $uri = $this->handler->getRandomFile();

    if (!$uri) {
      return [
        '#markup' => '<p>非管理ファイルが見つかりません。</p>',
      ];
    }

    return [
      '#theme' => 'image',
      '#uri' => $uri,
      '#alt' => $this->t('ランダムな非管理ファイル'),
      '#cache' => [
        'max-age' => 1,
      ],
    ];
  }
図4. ブロックのbuildメソッド

管理画面でのブロック配置手順

キャッシュをクリアしてから、「構造」→「ブロックレイアウト」に移動します。「カスタム」カテゴリに「Unmanaged Files Block」がリストされているのがわかるはずです。サイドバーまたはフッター領域に配置し、保存してページをリフレッシュしてください。リロードするたびに、異なる非管理ファイル画像が表示されるはずです。

管理画面での操作手順:

  1. 管理メニューから「構造」→「ブロックレイアウト」にアクセス
  2. 配置したい領域(サイドバー、フッターなど)の「ブロックを配置」をクリック
  3. 「カスタム」カテゴリから「Unmanaged Files Block」を選択
  4. 設定を確認して「ブロックを配置」ボタンをクリック
  5. レイアウトを保存

次のステップ

パート4では、Twigテンプレート内で非管理ファイルを直接レンダリングする方法を探ります。これにより、開発者はテーマレイヤー内でハンドラーを使用するより柔軟な方法が得られます。

この記事は 「Unmanaged Files in Drupal (Part 3): Rendering an Unmanaged File in a Block」の翻訳記事です。

カテゴリ