Symfony2 在没有服务的情况下调用 twig-extension 中的控制器操作

Symfony2 call controller-action in twig-extension without service

我正在编写一个具有以下功能的系统:普通用户(非程序员或管理员)可以创建可以插入“占位符”的内容。呈现页面时,这些占位符将被替换为不同的内容类型(例如十六进制颜色代码、滑块、图像……)。占位符的替换有点复杂,并且有一些额外的功能(例如定义默认值,用正确语言的内容替换占位符,......)。因此,我创建了一个带有“占位符过滤器”的树枝扩展。此函数应获取正确的内容以替换占位符并处理附加功能。

因为内容类型如此不同,所以对于包含在控制器中呈现内容的逻辑的每种内容类型,都有一些 - 称之为“插件”。

现在我的问题是:

插件的控制器操作return呈现的内容。因为我用 twig 扩展中的内容替换了占位符,所以我需要一种方法来调用此 twig 扩展中的控制器操作。

到目前为止我的想法:

我知道我可以通过这种方式在模板中调用控制器操作(来源:http://symfony.com/doc/current/book/templating.html):

{{ render(controller(
        'AppBundle:Article:recentArticles',
        { 'max': 3 }
    )) }}

所以在twig中调用controller-action似乎是没有问题的。但是我需要在 twig-extension 中调用这个函数。

我还知道,当我将控制器实现为服务时,我可以调用控制器动作。但是我不能将所有的插件控制器都定义为服务,因为插件是动态包含在系统中的。在安装新插件时动态处理服务也很“困难”(我想我必须用脚本编辑 service.yml - 或者我错了吗?)。这就是为什么我不能将控制器用作服务的原因。 - 但如果您能告诉我如何动态实施服务,我愿意接受其他解决方案。

我已经尝试过的是结合这两个页面的解决方案: http://symfony.com/doc/current/book/templating.html

echo $view['actions']->render(
    new \Symfony\Component\HttpKernel\Controller\ControllerReference(
        'AppBundle:Article:recentArticles',
        array('max' => 3)
    )
)

https://www.robinvdvleuten.nl/blog/rendering-templates-in-a-twig-extension/

我现在可以访问我的 twig-extension 中占位符过滤器中的 Twig_Environment,但以下代码不起作用:

$twig->render( new \Symfony\Component\HttpKernel\Controller\ControllerReference(
                            'Extensions'.$namespace.'Bundle:Index:getContent',
                            array('content'=>$contentObject)
                        ), array() );

我收到无法将 ControllerReference 转换为字符串的错误(这是有道理的,因为 ControllerReference 是一个对象...)。

那么有没有办法在不将控制器定义为服务的情况下调用 twig-extension 中的控制器动作?还是我应该重新考虑整个解决方案?

也许您可以定义一个 ViewListener 并让您的控制器 return 您想要的 html 而不是由 $this->render 在控制器上 return 编辑的响应。

您需要在控制器上使用 $this->renderView 并将结果return发送到您的扩展。

老实说,我觉得像这样设置的整个系统会非常 hacky 并且难以长期维护,所以我建议重新考虑它

几个小时后 "thinking about the problem" 我找到了主要问题的简单答案。当我在我的过滤器函数中包含 Twig_environment 时(请参阅 https://www.robinvdvleuten.nl/blog/rendering-templates-in-a-twig-extension/),我可以访问 twig render() 函数。该函数适用于模板和字符串。因此,在没有服务的情况下在 twig-extension 中调用控制器操作的最简单方法是使用普通的 twig-template-syntax:

// $twig is the Twig_Environment in my filter-function
$myRenderedContent = $twig->render(
    "{{ render(controller( 'Extensions".$namespace."Bundle:Index:getContent', { 'content': content })) }}", 
    array('content'=>$contentObject)
);

补充想法:

正如您在 http://symfony.com/doc/current/book/templating.html 中看到的那样,在 symfony 中调用这样的控制器似乎完全没问题。所以我认为在 twig-extension 中使用这个功能也是可以的(因为 twig-extension 为模板渲染定义了额外的辅助函数,这就是我想用我的过滤器函数做的,用特殊的占位符替换特殊的占位符内容)。

也许不将我的插件控制器作为服务包括在内不是最佳做法,但直到现在我还没有看到像这样处理插件控制器的缺点 - 当你知道一个时:请告诉我因为我愿意学习 "how to make it better" ;-)