Twig 自动去除撇号和引号

Twig automatically removes apostrophe and quotation marks

为了学习,我创建了自己的 TransTokenParser(解析 {% trans %}{% trans with %})-> 解析器本身工作良好,除了后一个变体:trans with.

解析器读出分配的变量,但自动转义 "' 因此它们不会显示(变量出来时没有 '" 直接来自解析器)。

例如,我们在树枝中有这个块:

{% trans with {'{test}': coolFunctionWhichReturnsString('testParameter')} %}
UNIQUE_TRANS_ID
{% endtrans %}

这个块用 trans 和诸如此类的东西解析得很好,但是把 'with' 之后的部分变成了这个:{{test}: coolFunctionWhichReturnsString(testParameter)}

我试过在 Twig_Environment

中设置一个参数
new Twig_Environment(..., ['autoescape' => false])

我试过在 config.yml 下的树枝下设置全局:

autoescape: false

None 的两个解决方案反映了 twig -> php 行为的变化。 (它将 autoescape 设置为 false,如 var_dump 在此处初始化 twig 环境时所见:

array (size=13)
  'debug' => boolean true
  'charset' => string 'UTF-8' (length=5)
  'base_template_class' => string 'Twig_Template' (length=13)
  'strict_variables' => boolean true
  'autoescape' => boolean false

这是我的代码:

/**
 * @return array
 * @throws \Twig_Error_Syntax
 */
private function parseVariant(): array
{
    $stream = $this->parser->getStream();
    $trans = null;
    $json = null;
    //SIMPLE VARIANT trans
    $stream->nextIf(\Twig_Token::PUNCTUATION_TYPE, '');
    if (null !== $stream->nextIf(\Twig_Token::BLOCK_END_TYPE)) { //%} TRANS_LITERAL
        $stream->nextIf(\Twig_Token::PUNCTUATION_TYPE, '');
        $trans = $stream->expect(\Twig_Token::TEXT_TYPE)->getValue();
    } elseif (null !== $stream->nextIf(\Twig_Token::NAME_TYPE, 'with')) { // {% trans with {} %} TRANS_LITERAL
        $stream->next();
        $json = implode($this->getInlineParams());
        $stream->nextIf(\Twig_Token::PUNCTUATION_TYPE);
        $stream->nextIf(\Twig_Token::BLOCK_END_TYPE);
        $stream->nextIf(\Twig_Token::PUNCTUATION_TYPE);
        $trans = $stream->expect(\Twig_Token::TEXT_TYPE)->getValue();
        //die();
    }
    // {% endtrans %}
    $stream->nextIf(\Twig_Token::PUNCTUATION_TYPE);
    $stream->expect(\Twig_Token::BLOCK_START_TYPE);
    $stream->nextIf(\Twig_Token::PUNCTUATION_TYPE);
    $stream->expect(\Twig_Token::NAME_TYPE);
    $stream->nextIf(\Twig_Token::PUNCTUATION_TYPE);
    $endLine = $stream->expect(\Twig_Token::BLOCK_END_TYPE)->getLine();

    return [$json, $trans, $endLine];
}

问题出在 $json,在这种情况下指的是:

$json = implode($this->getInlineParams());

获取内联参数:

protected function getInlineParams(): array
{
    $stream = $this->parser->getStream();
    $params = [];
    while (!$stream->test(\Twig_Token::BLOCK_END_TYPE)) {
        $params[] = $this->parser->getStream()->next()->getValue();
    }
    $stream->expect(\Twig_Token::BLOCK_END_TYPE);

    return $params;
}

编辑:使用 ExpressionParser 会引发错误,因为 key/values 没有 "" 或 ''..

另一个编辑:我已经尝试在运行时和 post 中修改 "escaper" 扩展 - 在 twig 中初始化包括所有策略 - 没有任何帮助

有什么建议吗? 提前致谢。

这是一个双重问题:第一个是 getInlineParams 函数中简单逻辑的可能方式,对于这些简单的情况可能没有问题,但对于更复杂的情况可能会很可怕.

第二个问题是对类型的完全无知。

{'{test}': coolFunctionWhichReturnsString('testParameter')}

被解析为(读作 "string value" - "token type"):

  • { - 块开始
  • {test} - 一个字符串
  • : - 标点符号
  • coolFunctionWhichReturnsString - 一个名字
  • ( - (不确定是哪种类型)
  • testParameter - 一个字符串
  • ) -(再次)
  • } - 区块结束

当您嵌套多个 {} 时,第一个问题就会出现。 第二个问题是由于一个简单的事实:

类型很重要。

词法分析器有一个非常重要的任务,它删除用户可能选择的所有不同变体来表达字符串、注释,它删除不相关的空格(因为它只是混乱),等等。现在,如果您将每个 Token(具有值和类型)视为只是一些包含您想要的字符串的奇怪对象,那么您就有问题了 - 显然。

因此,如果您想重新创建类似于原始输入的内容,则必须查看类型并在类型为字符串时添加引号。 (文本可能是块之外的所有内容)

(这将是快速 "solution" 解决您提出的问题)

但是,忽略标记的语义会导致长 运行... 中的问题,因为您还必须以某种方式处理 "coolFunctionWhichReturnsString",即,您必须将其转换为某个函数称呼。理论上,你真的应该构建一个 AST 并在某个时候将它编译成合适的形式...

twig 解析器使用一种方法 subparse 来解析内容,直到 "end" 出现。 (构建 AST,因为在某些时候结构也很重要)

更新:事实证明,在 twig 文档中有一个用于编写节点解析器的页面,如果您遵循 https://twig.symfony.com/doc/2.x/advanced.html#registering-a-new-tag(信息略高于 "Registering a new tag" 并且大大简化了值的解析和使用)