首页 > 解决方案 > Twig 自动删除撇号和引号

问题描述

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

这两种解决方案都没有反映 twig -> php 行为的变化。(它将自动转义设置为 false,如在此处初始化 twig 环境时的 var_dump 中所示:

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 会引发错误,因为键/值没有“”或“”..

另一个编辑:我已经尝试在 twig 中修改运行时和初始化后的“转义符”扩展,包括所有策略 - 没有任何帮助

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

标签: phpsymfonytwig

解决方案


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

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

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

被解析为(读作“字符串值”-“令牌类型”):

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

当您嵌套多个 {} 时,第一个问题将展开。第二个问题是由于一个简单的事实:

类型很重要。

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

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

这将是您陈述的问题的快速“解决方案”

但是,从长远来看,忽略标记的语义会导致问题……因为您还必须以某种方式处理“coolFunctionWhichReturnsString”,即您必须将其转换为一些函数调用。从理论上讲,您应该真正构建一个 AST 并在某个时候将其编译成适当的形式......

树枝解析器使用一种方法subparse来解析东西,直到出现一些“结束”。(建立一个 AST,因为结构在某些时候也很重要)

更新:事实证明,在 twig 文档中有一个用于编写节点解析器的页面,如果您遵循https://twig.symfony.com/doc/2.x/advanced.html ,它可能会大大简化这一点#registering-a-new-tag(信息从“注册新标签”开始略高于“注册新标签”,大大简化了值的解析和使用)


推荐阅读