扩展 Symfony 以自动转义 .tex.twig 文件的乳胶字符

Extend Symfony to automatically escape latex characters for .tex.twig files

我正在使用 .tex.twig 文件在我的项目中生成一些 PDF。默认情况下,我所有的 twig 文件都使用 html 策略自动转义。为了阻止意外转义,我不得不将所有 .tex.twig 文件包装在一个 autoescape false 块中。
我想为 .html.twig 文件保留默认的 html 转义,但在渲染 .tex.twig 文件时使用我自己的乳胶转义方法。我找到了一种使用以下代码扩展树枝环境的方法:

//LatexEscapeSetter.php
public function __invoke(Environment $twig)
{
    $twig->getExtension('Twig_Extension_Core')
        ->setEscaper('latex',
                     function ($twig, $string, $charset) {
                         // Escaping logic here....
                     }
        );

    return $twig;
}

为了调用此方法,我在 services.yml 中创建了以下定义:

Twig_Environment:
    class: Twig_Environment
    factory: ['LatexEscapeSetter.php', '__invoke']
    arguments: ['@twig']

重新启动服务器后,我使用了 var_dump($twig->getExtensions()),实际上注意到核心扩展确实包含一个 latex 条目。但是在我的 html 页面之一中使用 {% autoescape 'latex' %} 作为测试没有任何影响。
我错过了什么?

这就是你的做法:

首先需要在twig命名空间下配置autoescape_service和autoescape_service_method配置

twig:
    autoescape_service: 'App\Twig\EscapeStrategy'
    autoescape_service_method: guess

转义策略服务必须在 config/services.yaml 或您的自定义服务定义文件中注册:

services:
    App\Twig\EscapeStrategy: ~

在您的用例中,EscapeStrategy 可能如下所示:

<?php

namespace App\Twig;
use Twig\FileExtensionEscapingStrategy;

class EscapeStrategy
{

    const STRATEGY_NAME = 'latex';

    public function guess($name)
    {
        if ('.tex.twig' === substr($name, -9)) {
            return self::STRATEGY_NAME;
        }

        return FileExtensionEscapingStrategy::guess($name);
    }
}

symfony 默认使用 FileExtensionEscapingStrategy,因此退回到其默认猜测器是个好主意。

如果您尝试呈现名称以“.tex.twig”结尾的模板,您将得到一个异常,因为该 'latex' 策略的处理程序不存在。

要为新的转义策略注册一个处理程序,您需要装饰一个树枝服务。 在 services.yaml:

services:
    App\Twig\Configurator:
        decorates: 'twig.configurator.environment'

实现可能是这样的:

<?php

namespace App\Twig;

use Symfony\Bundle\TwigBundle\DependencyInjection\Configurator\EnvironmentConfigurator;
use Twig\Environment;
use Twig\Extension\EscaperExtension;

class Configurator
{

    /**
     * @var EnvironmentConfigurator
     */
    private $configurator;

    public function __construct(EnvironmentConfigurator $configurator)
    {
        $this->configurator = $configurator;
    }

    public function configure(Environment $environment)
    {
        $environment->getExtension(EscaperExtension::class)->setEscaper(EscapeStrategy::STRATEGY_NAME, [$this, 'escape']);

        $this->configurator->configure($environment);
    }

    public function escape($twig, $string, $charset)
    {
        //implement escape here
        return $string;
    }
}

如果您没有使用自动装配,请查看文档 https://symfony.com/doc/current/service_container/service_decoration.html

同时确保清除缓存,无论开发环境还是生产环境。

好吧,我找到了一个更简单的解决方案。

实际上有一个助手 class(一项服务)使用了这个奇异的逃逸器。它使用依赖注入来获取树枝环境。

有一个可以设置逃逸器:

class TexHelper
{
    /**
     * @var Environment
     */
    private $twig;
    
    public function __construct(Environment $twig)
    {
        $this->twig->getExtension(EscaperExtension::class)->setEscaper('latex',
            function (Environment $env, string $string, $charset)
            {
                // str_replace(['%', '&'], ['\%', '\&'], $string);
                return AppFilters::escapeTexInner($env, $string, $charset);
            });
    }

现在可以使用例如{% autoescape 'latex' %}{{ myVar|e('latex') }}