しばらくの間、小さな問題が静かに私の人生を台無しにし、そのために怠が時間を浪費していました。 最近、私はまだ自分自身を強制しており、それに対する解決策はTwigのプラグインに関する小さな記事に適していると思います。
問題自体は、テンプレート内の定数にあります。 テンプレート内のいくつかの識別子をステッチする必要がある場合、そのようなタスクがあります。 それらを数字で表すのはあまり良くありませんが、それらに定数がある場合、
constant
関数を使用しないのは罪です。 しかし、実際には、テンプレートからコンパイルした後、実行時に計算されます。
そして、私たちは何ができますか? リファクタリングの結果、定数を削除または名前変更し、テンプレートを忘れます。 そして、IDEは、自慢のPHPStormでさえも忘れています。 大量のテンプレートをデプロイする前にコンパイルを成功させ、サーバーに分散させます。 何も落ちず、すべてがうまく機能せず、同一のVoringsの巨大なシートが頭に落ちます。 悪い? うんざり!
解決策? テンプレートをコンパイルする過程で定数を解決します。不在の場合-誓います。
Twigに精通していないか、あまり知らない人のために、各テンプレートはプラグインによって解析され(基本的な機能はプラグインを使用してテンプレートエンジンに実装されます)、処理されてphpクラスにコンパイルされ、
display
メソッドが
display
されることを(非常に簡単に)伝えます。 たとえば、次の定数を使用して、次のテンプレートコードを取得します。
{% if usertype == constant('Users::TYPE_TROLL') %} , ! {% else %} ! {% endif %}
パターンは、比較的大きなオブジェクトのツリーに分類されます。
ここに、テンプレートの表現のわずかに短縮されたが、それでも素晴らしいprint_r出力があります
[body] => Twig_Node_Body Object ( [nodes:protected] => Array ( [0] => Twig_Node_If Object ( [nodes:protected] => Array ( [tests] => Twig_Node Object ( [nodes:protected] => Array ( [0] => Twig_Node_Expression_Binary_Equal Object ( [nodes:protected] => Array ( [left] => Twig_Node_Expression_Name Object ( [attributes:protected] => Array ( [name] => usertype ) ) [right] => Twig_Node_Expression_Function Object ( [nodes:protected] => Array ( [arguments] => Twig_Node Object ( [nodes:protected] => Array ( [0] => Twig_Node_Expression_Constant Object ( [attributes:protected] => Array ( [value] => Users::TYPE_TROLL ) ) ) ) ) [attributes:protected] => Array ( [name] => constant ) ) ) ) [1] => Twig_Node_Text Object ( [attributes:protected] => Array ( [data] => , ! ) ) ) ) [else] => Twig_Node_Text Object ( [attributes:protected] => Array ( [data] => ! ) ) ) ) ) )
さらに処理され(ここでくさびを入れる必要があります)、その結果、そのようなファイルにコンパイルされます(わずかに短縮されたバージョンでもあります)。
class __TwigTemplate_long_long_hash extends Twig_Template { protected function doDisplay(array $context, array $blocks = array()) { if (((isset($context["usertype"]) ? $context["usertype"] : null) == twig_constant("Users::TYPE_TROLL"))) { echo ", !"; } else { echo "!"; } } }
ここでの
$context
は、このテンプレートへの入力のための変数の束に入ったものです。 すべてが明確で、何も説明する必要がないことを願っています。
twig_constant
関数は、実際には標準の
constant
と変わらず、実行時に解決されます。
私たち自身の目で問題を見るために、コードから定数を削除し、レンダリングをキャッチします。
PHP Warning: constant(): Couldn't find constant Users::TYPE_TROLL in vendor/twig/twig/lib/Twig/Extension/Core.php on line 1387
コンパイルされたバージョンでは、定数値で置き換える必要がある
twig_constant
呼び出しです。
拡張機能の場合、テンプレートエンジンは拡張機能を継承する
Twig_Extension
クラスを提供します。 この拡張機能は、
Twig_ExtensionInterface
インターフェースで見つけることができる特別なメソッドを介して考えることができる関数、フィルター、およびその他のナンセンスのセットをテンプレートエンジンに提供できます。
getNodeVisitors
メソッドに興味があります。このメソッドは、解析されるテンプレートツリーのすべての要素がコンパイルされる前に渡されるオブジェクトの配列を返します。
class Template_Extensions_ConstEvaluator extends Twig_Extension { public function getNodeVisitors() { return [ new Template_Extensions_NodeVisitor_ConstEvaluator() ]; } public function getName() { return 'const_evaluator'; } }
コンパイルする前に、すべてのノードを調べて、通常のテキスト引数が含まれている定数関数を見つけて値に変更するか、そのような定数がないことを誓うだけです。
これが、ノードビジターの結果です。
class Template_Extensions_NodeVisitor_ConstEvaluator implements Twig_NodeVisitorInterface { public function enterNode(Twig_NodeInterface $node, Twig_Environment $env) { // - constant 1 if ($node instanceof Twig_Node_Expression_Function && 'constant' === $node->getAttribute('name') && 1 === $node->count() ) { // $args = $node->getNode('arguments'); if ($args instanceof Twig_Node && 1 === $args->count() ) { $constNode = $args->getNode(0); // 1 if ($constNode instanceof Twig_Node_Expression_Constant && null !== $value = $constNode->getAttribute('value') ) { if (null === $constantEvaluated = constant($value)) { // - throw new Twig_Error( sprintf( "Can't evaluate constant('%s')", $value ) ); } // , // :] return new Twig_Node_Expression_Constant($constantEvaluated, $node->getLine()); } } } // , , , return $node; } public function leaveNode(Twig_NodeInterface $node, Twig_Environment $env) { return $node; } }
これが、テンプレートツリーのほぼ3分の1を通常の値に置き換える方法です。
念のため、コンパイルされたバージョンで何が起こったのかを示します
class __TwigTemplate_long_long_hash extends Twig_Template { protected function doDisplay(array $context, array $blocks = array()) { if (((isset($context["usertype"]) ? $context["usertype"] : null) == 2)) { echo ", !"; } else { echo "!"; } } }
シンプルで、面白く、便利です。
うまくいけば、これによって誰かがTwigを掘り下げ、関数やフィルター以外の何かでTwigを拡張しようとすることを願っています。 どんな批判にも耳を傾け、午前中に質問に答える準備ができています。 Discas!