Symfony TwigBundle 未加载任何自定义扩展
Symfony TwigBundle not loading any custom extensions
我正在努力更新 Zikula from Symfony 3 to Symfony 4 (I'm working specifically in this PR at the moment). Part of this is removing Symfony's old templating mechanism and switching entirely to Twig. In the process I am running into a very unusual problem: None of the custom Twig extensions in the included Bundles or the pseudo bundles(它们只是名为模块的捆绑包)已加载并在模板中可用。
是,扩展 class 是自动连接和自动加载的,是 它们可用 - 即它们列在 bin/console debug:container
特别是如果我做类似
me% bin/console debug:container AdminExtension
Information for Service "Zikula\AdminModule\Twig\Extension\AdminExtension"
==========================================================================
---------------- --------------------------------------------------
Option Value
---------------- --------------------------------------------------
Service ID Zikula\AdminModule\Twig\Extension\AdminExtension
Class Zikula\AdminModule\Twig\Extension\AdminExtension
Tags twig.extension
Public no
Synthetic no
Lazy no
Shared yes
Abstract no
Autowired yes
Autoconfigured yes
---------------- --------------------------------------------------
! [NOTE] The "Zikula\AdminModule\Twig\Extension\AdminExtension" service or alias has been removed or inlined when the
! container was compiled.
这清楚地表明,服务不仅正确自动装配,而且还正确标记。
如果我这样做 bin/console debug:twig
none,则会列出自定义扩展(在顶部带有函数、过滤器等)。我什至尝试逐步完成 TwigBundle Compiler 过程,我很确定那里包含可调用对象。
你知道问题出在哪里吗?我该如何解决它?
免责声明:我不是很确定,依赖注入修饰是如何工作的确切地。
依赖注入装饰器不会让您编写一个合适的装饰器(因为它无论如何都无法检查),但是,有一些迹象表明它不是装饰器。
主要指标:装饰 class 不依赖于装饰 class,如:它不需要作为 __construct()
的参数或以其他方式注入。
推理:装饰器应该以 cascading/chainable 的方式使用,本质上,装饰器应该像这样使用(在你的情况下不起作用!):
$instance = new Decorator2(new Decorator1(new DecoratedClass()));
和装饰器(方法)平均应该是这样的:
class Decorator {
protected $inner;
public function __construct(DecoratedClass $inner) {
$this->inner = $inner;
}
public function someMethod($someParam) {
// do something before, maybe change $someParam
$returnValue = $this->inner->someMethod($someParam);
// do something after, maybe change $returnValue
return $returnValue;
}
}
symfony page on decorating actually says most of this, directly or indirectly (references this wikipedia article).
据我所知,每个 class 都必须正确添加修饰的 class(烦人的 AF)的所有函数,如:在内部对象上调用它。
现在,一种方法可能是:"well, I don't really care about actually decorating, I just want my class to be used instead of the twig environment!"
在这种情况下,您应该主动将其替换为您的 class,正如我在评论 (services.yaml) 中指出的那样:
services:
Twig\Environment: Your\Class\Name
Your\Class\Name: # NO DECORATES!!!
arguments: ...
calls: ...
twig: Your\Class\Name # maybe setting it via alias is effective...
应该 导致您的 class 在需要 Twig\Environment
或 twig
或您的 class 时被使用具体来说。
但是,在修饰的情况下,您的 class 应该修饰它扩展的 class,而不是 class 具有的别名.
我问的真正问题是,"What is the correct way to override Twig\Environment
with a child class?"
正确答案是按照与原来相同的方式定义服务。 (虽然 Symfony 默认使用 xml,所以我不得不转换)。所以这是正确的定义:
# override TwigBundle's Twig\Environment definition with Zikula's own child class
# see vendor/symfony/symfony/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml
twig:
class: Zikula\ThemeModule\Bridge\Twig\EventEnabledTwigEngine
public: true
arguments:
$loader: '@twig.loader'
$options: []
calls:
- [setEventDispatcher, ['@event_dispatcher']]
- [addGlobal, ['app', '@twig.app_variable']]
- [addRuntimeLoader, ['@twig.runtime_loader']]
configurator: ['@twig.configurator.environment', 'configure']
Twig_Environment: '@twig'
Twig\Environment: '@twig'
你可以看到这是如何复制 Symfony 的:
<service id="twig" class="Twig\Environment" public="true">
<argument type="service" id="twig.loader" />
<argument /> <!-- Twig options -->
<call method="addGlobal">
<argument>app</argument>
<argument type="service" id="twig.app_variable" />
</call>
<call method="addRuntimeLoader">
<argument type="service" id="twig.runtime_loader" />
</call>
<configurator service="twig.configurator.environment" method="configure" />
</service>
<service id="Twig_Environment" alias="twig" />
<service id="Twig\Environment" alias="twig" />
并看看它与上面@Jakumi 的建议有何不同:
Twig\Environment: Your\Class\Name
Your\Class\Name: # NO DECORATES!!!
arguments: ...
calls: ...
twig: Your\Class\Name # maybe setting it via alias is effective...
非常感谢@Cerad 和@Jakumi 协助解决问题![=14=]
我正在努力更新 Zikula from Symfony 3 to Symfony 4 (I'm working specifically in this PR at the moment). Part of this is removing Symfony's old templating mechanism and switching entirely to Twig. In the process I am running into a very unusual problem: None of the custom Twig extensions in the included Bundles or the pseudo bundles(它们只是名为模块的捆绑包)已加载并在模板中可用。
是,扩展 class 是自动连接和自动加载的,是 它们可用 - 即它们列在 bin/console debug:container
特别是如果我做类似
me% bin/console debug:container AdminExtension
Information for Service "Zikula\AdminModule\Twig\Extension\AdminExtension"
==========================================================================
---------------- --------------------------------------------------
Option Value
---------------- --------------------------------------------------
Service ID Zikula\AdminModule\Twig\Extension\AdminExtension
Class Zikula\AdminModule\Twig\Extension\AdminExtension
Tags twig.extension
Public no
Synthetic no
Lazy no
Shared yes
Abstract no
Autowired yes
Autoconfigured yes
---------------- --------------------------------------------------
! [NOTE] The "Zikula\AdminModule\Twig\Extension\AdminExtension" service or alias has been removed or inlined when the
! container was compiled.
这清楚地表明,服务不仅正确自动装配,而且还正确标记。
如果我这样做 bin/console debug:twig
none,则会列出自定义扩展(在顶部带有函数、过滤器等)。我什至尝试逐步完成 TwigBundle Compiler 过程,我很确定那里包含可调用对象。
你知道问题出在哪里吗?我该如何解决它?
免责声明:我不是很确定,依赖注入修饰是如何工作的确切地。
依赖注入装饰器不会让您编写一个合适的装饰器(因为它无论如何都无法检查),但是,有一些迹象表明它不是装饰器。
主要指标:装饰 class 不依赖于装饰 class,如:它不需要作为 __construct()
的参数或以其他方式注入。
推理:装饰器应该以 cascading/chainable 的方式使用,本质上,装饰器应该像这样使用(在你的情况下不起作用!):
$instance = new Decorator2(new Decorator1(new DecoratedClass()));
和装饰器(方法)平均应该是这样的:
class Decorator {
protected $inner;
public function __construct(DecoratedClass $inner) {
$this->inner = $inner;
}
public function someMethod($someParam) {
// do something before, maybe change $someParam
$returnValue = $this->inner->someMethod($someParam);
// do something after, maybe change $returnValue
return $returnValue;
}
}
symfony page on decorating actually says most of this, directly or indirectly (references this wikipedia article).
据我所知,每个 class 都必须正确添加修饰的 class(烦人的 AF)的所有函数,如:在内部对象上调用它。
现在,一种方法可能是:"well, I don't really care about actually decorating, I just want my class to be used instead of the twig environment!"
在这种情况下,您应该主动将其替换为您的 class,正如我在评论 (services.yaml) 中指出的那样:
services:
Twig\Environment: Your\Class\Name
Your\Class\Name: # NO DECORATES!!!
arguments: ...
calls: ...
twig: Your\Class\Name # maybe setting it via alias is effective...
应该 导致您的 class 在需要 Twig\Environment
或 twig
或您的 class 时被使用具体来说。
但是,在修饰的情况下,您的 class 应该修饰它扩展的 class,而不是 class 具有的别名.
我问的真正问题是,"What is the correct way to override Twig\Environment
with a child class?"
正确答案是按照与原来相同的方式定义服务。 (虽然 Symfony 默认使用 xml,所以我不得不转换)。所以这是正确的定义:
# override TwigBundle's Twig\Environment definition with Zikula's own child class
# see vendor/symfony/symfony/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml
twig:
class: Zikula\ThemeModule\Bridge\Twig\EventEnabledTwigEngine
public: true
arguments:
$loader: '@twig.loader'
$options: []
calls:
- [setEventDispatcher, ['@event_dispatcher']]
- [addGlobal, ['app', '@twig.app_variable']]
- [addRuntimeLoader, ['@twig.runtime_loader']]
configurator: ['@twig.configurator.environment', 'configure']
Twig_Environment: '@twig'
Twig\Environment: '@twig'
你可以看到这是如何复制 Symfony 的:
<service id="twig" class="Twig\Environment" public="true">
<argument type="service" id="twig.loader" />
<argument /> <!-- Twig options -->
<call method="addGlobal">
<argument>app</argument>
<argument type="service" id="twig.app_variable" />
</call>
<call method="addRuntimeLoader">
<argument type="service" id="twig.runtime_loader" />
</call>
<configurator service="twig.configurator.environment" method="configure" />
</service>
<service id="Twig_Environment" alias="twig" />
<service id="Twig\Environment" alias="twig" />
并看看它与上面@Jakumi 的建议有何不同:
Twig\Environment: Your\Class\Name
Your\Class\Name: # NO DECORATES!!!
arguments: ...
calls: ...
twig: Your\Class\Name # maybe setting it via alias is effective...
非常感谢@Cerad 和@Jakumi 协助解决问题![=14=]