简体   繁体   English

扩展Twig的AppVariable

[英]Extending Twig's AppVariable

I've inherited a website that uses Symfony 2. 我继承了一个使用Symfony 2的网站。

The site was working fine until I ran composer to upgrade packages. 该网站运行正常,直到我运行composer升级包。 It upgraded Symfony 2.6 to 2.7.1 and Twig 1.18 to 1.18.2. 它将Symfony 2.6升级到2.7.1,将Twig 1.18升级到1.18.2。

I now get the following error: 我现在收到以下错误:

Method "site" for object "Symfony\\Bridge\\Twig\\AppVariable" does not exist in @Page/Page/homepage.html.twig at line 21 对象“Symfony \\ Bridge \\ Twig \\ AppVariable”的方法“site”在第21行的@ Page / Page / homepage.html.twig中不存在

The twig file in question has calls like this: 有问题的twig文件有这样的调用:

{{ app.site.name }}

Now obviously site is not a member of the AppVariable type. 现在很明显, site不是AppVariable类型的成员。 I'm having trouble figuring out how the original developers managed to extend Twig's app global with a new member. 我无法弄清楚原始开发人员是如何通过新成员扩展Twig app全局的。 I don't really know where to look. 我真的不知道在哪里看。 I'm not overly competent with Symfony. 我对Symfony不太称职。

What probably was done by the old developers was overriding the app variable. 旧开发人员可能做的是覆盖app变量。 Until Symfony @2.7 the class was called GlobalVariables and lives in the following namespace - Symfony\\Bundle\\FrameworkBundle\\Templating . 在Symfony @ 2.7之前,该类被称为GlobalVariables并且位于以下命名空间中 - Symfony\\Bundle\\FrameworkBundle\\Templating As of @2.7 it's called AppVariable and it lives in this namespace - Symfony\\Bridge\\Twig . 从@ 2.7开始,它被称为AppVariable ,它存在于这个命名空间中 - Symfony\\Bridge\\Twig What is done behind the scenes? 在幕后做了什么?

That class containing the global variables is simply added as twig global variable using the method addGlobal of Twig and for the value of app they inject the whole class as a service that's already defined. 包含全局变量的类只是使用addGlobal方法添加为addGlobal全局变量,对于app的值,它们将整个类注入已定义的服务。 GlobalVariables or AppVariables accepts the service container as an argument and defines 5 methods by default that can be used in our templates. GlobalVariablesAppVariables接受服务容器作为参数,并默认定义5个方法,可以在我们的模板中使用。 I will show you a simple way of extending that class, so you can use it to investigate. 我将向您展示一种扩展该类的简单方法,以便您可以使用它来进行调查。

Create simple class that we will define as a service: 创建我们将定义为服务的简单类:

<?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);
    }

}

Then register it: 然后注册:

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

And last but not least, override the app variable of twig: 最后但并非最不重要的是,覆盖twig的app变量:

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

Now you can define your own methods in your extended class as well as accessing the previous methods that were already here. 现在,您可以在扩展类中定义自己的方法,也可以访问此处已有的先前方法。

For symfony @2.7 is the same, just the class name is different. 对于symfony @ 2.7是相同的,只是类名不同。 Here I extend the GlobalVariables , but for @2.7 you have to extend AppVariable . 在这里我扩展了GlobalVariables ,但对于@ 2.7,你必须扩展AppVariable

Definition of the service for @2.7 located in TwigBundle Resources folder. 位于TwigBundle Resources文件夹中的@ 2.7服务的定义。

<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>

Hope this helps. 希望这可以帮助。

Refer to Artamiels answer as a starting point. 请参阅Artamiels答案作为起点。

Looks like with sf3, the AppVariable class does no longer need the container (and does not have a parent::__construct ) but the interesting vars are being set directly. 看起来像sf3, AppVariable类不再需要容器(并且没有parent::__construct ),但是直接设置了有趣的变量。

So, I did set my class MyAppExtension extends AppVariable with this setup in services.yml : 所以,我也把我的class MyAppExtension extends AppVariable与此设置在services.yml

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

This is basically xml->yml converted of the coresponding code in the Twig Bundle: https://github.com/symfony/twig-bundle/blob/master/Resources/config/twig.xml 这基本上是在Twig Bundle中对相应代码进行xml-> yml转换: 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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM