扩展 Twig 的 AppVariable

Extending Twig's AppVariable

我继承了一个使用 Symfony 2 的网站。

在我 运行 composer 升级软件包之前,该站点运行良好。它将 Symfony 2.6 升级到 2.7.1,将 Twig 1.18 升级到 1.18.2。

我现在收到以下错误:

Method "site" for object "Symfony\Bridge\Twig\AppVariable" does not exist in @Page/Page/homepage.html.twig at line 21

有问题的 twig 文件有这样的调用:

{{ app.site.name }}

现在显然 site 不是 AppVariable 类型的成员。我无法弄清楚最初的开发人员如何设法通过新成员扩展 Twig 的 app 全局。我真的不知道去哪里看。我不太擅长 Symfony。

老开发人员所做的可能是覆盖 app 变量。在 Symfony @2.7 之前,class 被称为 GlobalVariables 并且存在于以下命名空间中 - Symfony\Bundle\FrameworkBundle\Templating。从 @2.7 开始,它被称为 AppVariable 并且它存在于这个命名空间中 - Symfony\Bridge\Twig。幕后做了什么?

包含全局变量的 class 使用 Twig 的方法 addGlobal 简单地添加为 twig 全局变量,并且对于 app 的值,它们注入整个 class 作为已经定义的服务。 GlobalVariablesAppVariables 接受服务容器作为参数,并默认定义了 5 个可以在我们的模板中使用的方法。我将向您展示一种扩展该 class 的简单方法,以便您可以使用它进行调查。

创建我们将定义为服务的简单 class:

<?php

namespace AppBundle\Service;

use Symfony\Bundle\FrameworkBundle\Templating\GlobalVariables,
    Symfony\Component\DependencyInjection\ContainerInterface;

class SuperGlobalsExtended extends GlobalVariables {

    /**
     * @var ContainerInterface
     **/
    protected $container = null;

    public function __construct(ContainerInterface $container) {
        $this->container = $container;

        parent::__construct($container);
    }

}

然后注册它:

services:
    app.super_globals_extended:
        class: AppBundle\Service\SuperGlobalsExtended
        arguments:
            - @service_container

最后但同样重要的是,覆盖 twig 的 app 变量:

twig:
    debug:            "%kernel.debug%"
    strict_variables: "%kernel.debug%"
    globals:
        app: @app.super_globals_extended

现在您可以在扩展 class 中定义自己的方法,也可以访问此处已有的以前的方法。

对于 symfony @2.7 是一样的,只是 class 名称不同。这里我扩展了 GlobalVariables,但是对于 @2.7 你必须扩展 AppVariable.

@2.7 的服务定义位于 TwigBundle Resources 文件夹中。

<service id="twig" class="%twig.class%">
        <argument type="service" id="twig.loader" />
        <argument /> <!-- Twig options -->
        <call method="addGlobal">
            <argument>app</argument>
            <argument type="service" id="twig.app_variable" />
        </call>
        <configurator service="twig.configurator.environment" method="configure" />
    </service>

希望这对您有所帮助。

参考作为起点。

看起来像 sf3,AppVariable class 不再需要容器(并且没有 parent::__construct)但是有趣的变量被直接设置。

因此,我在 services.yml 中使用此设置设置了我的 class MyAppExtension extends AppVariable:

extended_twig_app:
  class: AppBundle\Twig\MyAppExtension
  public: false
  calls:
    - [setEnvironment, ["%kernel.environment%"]]
    - [setDebug, ["%kernel.debug%"]]
    - [setTokenStorage, ['@security.token_storage']]
    - [setRequestStack, ['@request_stack']]

这基本上是 xml->yml 对 Twig Bundle 中相应代码的转换: https://github.com/symfony/twig-bundle/blob/master/Resources/config/twig.xml

    <service id="twig.app_variable" class="Symfony\Bridge\Twig\AppVariable" public="false">
        <call method="setEnvironment"><argument>%kernel.environment%</argument></call>
        <call method="setDebug"><argument>%kernel.debug%</argument></call>
        <call method="setTokenStorage"><argument type="service" id="security.token_storage" on-invalid="ignore" /></call>
        <call method="setRequestStack"><argument type="service" id="request_stack" on-invalid="ignore" /></call>
    </service>