Latteの拡張
Latteは拡張性を考慮して設計されています。標準のタグ、フィルタ、関数のセットは多くのユースケースをカバーしていますが、独自の特定のロジックやヘルパーツールを追加する必要があることがよくあります。このページでは、単純なヘルパーから複雑な新しい構文まで、プロジェクトの要件に完全に一致するようにLatteを拡張する方法の概要を説明します。
Latteを拡張する方法
Latteをカスタマイズおよび拡張するための主な方法の概要を以下に示します。
- カスタムフィルタ:
テンプレートの出力で直接データをフォーマットまたは変換するため(例:
{$var|myFilter}
)。日付のフォーマット、テキストの編集、特定のエスケープの適用などのタスクに最適です。コンテンツを匿名の{block}
でラップし、カスタムフィルタを適用することで、より大きなHTMLコンテンツのブロックを編集するためにも使用できます。 - カスタム関数:
テンプレート内の式で呼び出すことができる再利用可能なロジックを追加するため(例:
{myFunction($arg1, $arg2)}
)。計算、アプリケーションヘルパー関数へのアクセス、またはコンテンツの小さな部分の生成に役立ちます。 - カスタムタグ:
全く新しい言語構造を作成するため(
{mytag}...{/mytag}
またはn:mytag
)。タグは最も多くの可能性を提供し、独自の構造を定義し、テンプレートのパースを制御し、複雑なレンダリングロジックを実装できます。 - コンパイルパス: パース後、PHPコード生成前にテンプレートの抽象構文木(AST)を変更する関数。高度な最適化、セキュリティチェック(Sandboxなど)、または自動コード変更に使用されます。
- カスタムローダー: Latteがテンプレートファイルを検索して読み込む方法を変更するため(例:データベース、暗号化されたストレージなどからの読み込み)。
適切な拡張方法を選択することが重要です。複雑なタグを作成する前に、より単純なフィルタや関数で十分かどうかを検討してください。例として、生成する単語数を引数として受け取る*Lorem ipsum*ジェネレータの実装を考えてみましょう。
- タグとして?
{lipsum 40}
– 可能ですが、タグは制御構造や複雑なマークアップの生成により適しています。タグは式で直接使用することはできません。 - フィルタとして?
{=40|lipsum}
– 技術的には機能しますが、フィルタは入力値を変換することを目的としています。ここでは、40
は変換される値ではなく引数です。これは意味的に間違っているように感じられます。 - 関数として?
{lipsum(40)}
– これが最も自然な解決策です!関数は引数を受け取り、値を返します。これは、任意の式で使用するのに理想的です:{var $text = lipsum(40)}
。
一般的な推奨事項: 計算/生成には関数を、変換にはフィルタを、新しい言語構造や複雑なマークアップにはタグを使用してください。ASTの操作にはパスを、テンプレートの取得にはローダーを使用してください。
直接登録
プロジェクト固有のヘルパーツールや迅速な拡張のために、LatteはLatte\Engine
オブジェクトへのフィルタと関数の直接登録を許可します。
フィルタを登録するには、addFilter()
メソッドを使用します。フィルタ関数の最初の引数は|
文字の前の値になり、後続の引数はコロン:
の後に渡されるものです。
$latte = new Latte\Engine;
// フィルタ定義(呼び出し可能なオブジェクト:関数、静的メソッドなど)
$myTruncate = fn(string $s, int $length = 50) => mb_substr($s, 0, $length);
// 登録
$latte->addFilter('truncate', $myTruncate);
// テンプレートでの使用:{$text|truncate} または {$text|truncate:100}
フィルタローダーを登録することもできます。これは、要求された名前に基づいてフィルタの呼び出し可能なオブジェクトを動的に提供する関数です。
$latte->addFilterLoader(fn(string $name) => /* 呼び出し可能なオブジェクトまたはnullを返す */);
テンプレート式で使用可能な関数を登録するには、addFunction()
を使用します。
$latte = new Latte\Engine;
// 関数定義
$isWeekend = fn(DateTimeInterface $date) => $date->format('N') >= 6;
// 登録
$latte->addFunction('isWeekend', $isWeekend);
// テンプレートでの使用:{if isWeekend($myDate)}週末!{/if}
詳細については、カスタムフィルタの作成および関数セクションを参照してください。
堅牢な方法:Latte Extension
直接登録は簡単ですが、Latte拡張機能をパッケージ化して配布するための標準的で推奨される方法は、Extensionクラスを使用することです。Extensionは、複数のタグ、フィルタ、関数、コンパイルパス、およびその他の要素を登録するための中心的な設定ポイントとして機能します。
なぜExtensionsを使用するのですか?
- 整理: 関連する拡張機能(特定の機能のためのタグ、フィルタなど)を1つのクラスにまとめます。
- 再利用性と共有: 他のプロジェクトで使用したり、コミュニティと共有したりするために拡張機能を簡単にパッケージ化できます(例:Composer経由)。
- フルパワー: カスタムタグとコンパイルパスは、Extensionsを介してのみ登録できます。
Extensionの登録
Extensionは、addExtension()
メソッドを使用してLatteに登録されます(または設定ファイルを介して):
$latte = new Latte\Engine;
$latte->addExtension(new MyProjectExtension);
複数の拡張機能を登録し、それらが同じ名前のタグ、フィルタ、または関数を定義する場合、最後に追加された拡張機能が優先されます。これは、拡張機能がネイティブのタグ/フィルタ/関数を上書きできることも意味します。
クラスに変更を加え、自動更新が無効になっていない場合、Latteは自動的にテンプレートを再コンパイルします。
Extensionの作成
カスタム拡張機能を作成するには、Latte\Extensionを継承するクラスを作成する必要があります。そのような拡張機能がどのように見えるかを知るには、組み込みのCoreExtension
実装できるメソッドを見てみましょう:
beforeCompile (Latte\Engine $engine): void
テンプレートのコンパイル前に呼び出されます。このメソッドは、例えばコンパイルに関連する初期化に使用できます。
getTags(): array
テンプレートのコンパイル時に呼び出されます。*タグ名 ⇒ 呼び出し可能なオブジェクト*の連想配列を返します。これらはタグをパースするための関数です。詳細情報。
public function getTags(): array
{
return [
'foo' => FooNode::create(...),
'bar' => BarNode::create(...),
'n:baz' => NBazNode::create(...),
// ...
];
}
タグn:baz
は、純粋なn:属性、つまり属性としてのみ記述できるタグを表します。
タグfoo
とbar
については、Latteはそれらがペアタグであるかどうかを自動的に認識し、そうであれば、n:inner-foo
やn:tag-foo
といったプレフィックス付きのバリアントを含むn:属性を使用して自動的に記述できます。
このようなn:属性の実行順序は、getTags()
メソッドによって返される配列内の順序によって決定されます。したがって、HTMLタグ内で属性が<div n:bar="..." n:foo="...">
のように逆の順序でリストされていても、n:foo
は常にn:bar
の前に実行されます。
複数の拡張機能にわたるn:属性の順序を指定する必要がある場合は、ヘルパーメソッドorder()
を使用します。ここで、パラメータbefore
xor
after
は、どのタグが指定されたタグの前または後にソートされるかを指定します。
public function getTags(): array
{
return [
'foo' => self::order(FooNode::create(...), before: 'bar')]
'bar' => self::order(BarNode::create(...), after: ['block', 'snippet'])]
];
}
getPasses(): array
テンプレートのコンパイル時に呼び出されます。*パス名 ⇒ 呼び出し可能なオブジェクト*の連想配列を返します。これらは、ASTを走査して変更する、いわゆるコンパイルパスを表す関数です。
ここでもヘルパーメソッドorder()
を使用できます。パラメータbefore
またはafter
の値は、すべてより前/後を意味する*
にすることができます。
public function getPasses(): array
{
return [
'optimize' => Passes::optimizePass(...),
'sandbox' => self::order($this->sandboxPass(...), before: '*'),
// ...
];
}
beforeRender (Latte\Engine $engine): void
各テンプレートのレンダリング前に呼び出されます。このメソッドは、例えばレンダリング中に使用される変数の初期化に使用できます。
getFilters(): array
テンプレートのレンダリング前に呼び出されます。フィルタを*フィルタ名 ⇒ 呼び出し可能なオブジェクト*の連想配列として返します。詳細情報。
public function getFilters(): array
{
return [
'batch' => $this->batchFilter(...),
'trim' => $this->trimFilter(...),
// ...
];
}
getFunctions(): array
テンプレートのレンダリング前に呼び出されます。関数を*関数名 ⇒ 呼び出し可能なオブジェクト*の連想配列として返します。詳細情報。
public function getFunctions(): array
{
return [
'clamp' => $this->clampFunction(...),
'divisibleBy' => $this->divisibleByFunction(...),
// ...
];
}
getProviders(): array
テンプレートのレンダリング前に呼び出されます。プロバイダーの配列を返します。これらは通常、実行時にタグによって使用されるオブジェクトです。それらは$this->global->...
を介してアクセスされます。詳細情報。
public function getProviders(): array
{
return [
'myFoo' => $this->foo,
'myBar' => $this->bar,
// ...
];
}
getCacheKey (Latte\Engine $engine): mixed
テンプレートのレンダリング前に呼び出されます。戻り値は、コンパイルされたテンプレートのファイル名に含まれるハッシュのキーの一部になります。したがって、異なる戻り値に対して、Latteは異なるキャッシュファイルを生成します。