Twigでは{% include %}文を使って、外部テンプレートを読み込む事ができるのだが、この時読み込む事ができるテンプレートは、Twigをインスタンス化した際に指定するディレクトリ配下のファイルに限られる。

define('TEMPLATES_DIR', __DIR__.'/templates');

$Loader = new \Twig\Loader\FilesystemLoader(TEMPLATES_DIR);
$Twig = new \Twig\Environment($Loader, [
  'debug' => false,
]);

例えば上記の例の場合、Twigでincludeできるファイルはtemplatesディレクトリ配下のファイルに限られる。

場合によっては、別のディレクトリにあるファイルを読み込ませたい場合もあるだろう。

今回はTwigのカスタムフィルター機能を使って自作のフィルターを用意し、別のディレクトリからファイルを読み込ませる方法を紹介する。

クラスを用意する

まず、カスタムフィルターの機能を実装するため、PHPのクラスを用意する。

/**
 * Class CustomFilter
 */
class CustomFilter {
  /**
   * 自作フィルター 引数で与えられたファイルが存在したら中身を返す
   * @return string|boolean
   */
  public function twigEmbed($file) {
    if(empty($file) || !file_exists($file) || !is_file($file)) {
      return false;
    }
    return file_get_contents($file);
  }
}

カスタムフィルターの実装

次に、先ほど作成したクラスをインスタンス化し、Twigインスタンスにカスタムフィルターとして実装する。

define('TEMPLATES_DIR', __DIR__.'/templates');

$Loader = new \Twig\Loader\FilesystemLoader(TEMPLATES_DIR);
$Twig = new \Twig\Environment($Loader, [
  'debug' => false,
]);

// フィルターの追加(CustomFilterクラスは別途requireする)
$customFilter = new CustomFilter();
$filter = new \Twig\TwigFilter('embed', [$customFilter, 'twigEmbed']);
$Twig->addFilter($filter);

これでTwigのテンプレート内で「embed」フィルターが機能するようになる。

カスタムフィルターを使ってみる

それでは試しに外部ディレクトリにあるHTMLファイルを読み込んで表示させてみよう。

まず、先ほどのPHPファイルに以下を追記し、テンプレートの描画処理をおこなう。

$twigParam = array(
  'documentRootPath' => $_SERVER['DOCUMENT_ROOT'],
);

echo $Twig->render('index.twig', $twigParam);

この時、テンプレート側にサーバーのルートパスをパラメータとして渡しているところがポイント。

テンプレート側では以下のようにしてカスタムフィルターを使用する。

{{ (documentRootPath ~ '/html-templates/header.html')|embed|raw }}

この時、上記のように変数と文字列を連結させてファイルを指定する際に、丸カッコで囲む必要がある事に注意が必要だ。

これを省くと、先に文字列のみにフィルターが適用されてしまうためファイルが見つからず、思うような結果とならないのだ。

ちなみにrawフィルターはデフォルトで用意されているフィルターで、これをつけないとHTMLタグがエスケープされてしまうので、HTMLファイルを読み込ませる時は必須となる。