接近完成 - 只需要完成 Twig 扩展来渲染 ESI - Symfony2 [英] Nearly completed - just need to finish Twig extension to render ESI - Symfony2

查看:28
本文介绍了接近完成 - 只需要完成 Twig 扩展来渲染 ESI - Symfony2的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想创建一个 Twig 扩展并使用它:

I want to create a Twig extension and use this:

{{ new_func(route-name) }}

做同样的事情:

{{ render_esi(url(route-name)) }}

...但有一些调整

快完成了,但需要更改的是这一行,但我看不到如何从这段代码中调用 ESI(在 Twig 之外):

It's nearly done but it's this line that needs to be changed, but I can't see how I can call an ESI from this code (outside of Twig):

return $environment->render($route);   /// needs to receive route and render an ESI

-

namespace Acme\Bundle\MyBundle\Twig;

class NewTwigFunction extends \Twig_Extension
{

    private $request;

    public function __construct($container)
    {
        $this->request = $container->get('request');
    }

    public function getFunctions() {

        return array(
            'new_func' => new \Twig_Function_Method($this, 'newFunction', array('needs_environment' => true) )
        );

    }

    public function newFunction(\Twig_Environment $environment, $route) {

        $r = $this->request;

        return $environment->render($route);

    }

    public function getName() {

        return "new_func";

    }

 }

推荐答案

我不知道为什么你需要这个,但我认为这是一个很好的抽象问题的例子:

I'm not sure I follow why would you need this, but I think it's great as an example of an abstract question:

您似乎无法找到这个 render_esi 在哪里执行,所以让我们解决这个问题!

Seems that you're having trouble finding where is this render_esi executed, so let's tackle that!

这看起来不像是标准的 Twig 功能,所以它必须是一个扩展,就像你正在创建的那样.

This doesn't seem like a standard Twig feature, so it must be an extension, just like the one you're creating.

它应该位于 Symfony2 核心文件的某个地方,所以我们开始查看 vendor/symfony/src 文件夹.由于我们已经知道我们正在处理 Twig 的扩展,因此 Component 文件夹是不可能的(因为 Twig 是一个独立于 Symfony2 核心组件的库).

It should be located somewhere in Symfony2 core files, so we start looking into vendor/symfony/src folder. Since we already know that we're dealing with an extension of Twig, Component folder is out of the question (because Twig is a separate library from Symfony2 core components).

所以我们将范围缩小到BridgeBundle.如果我们查看它们的内部,就会看到 Bundle/TwigBundleBridge/Twig.我们也知道 Symfony2 开发人员遵循严格的代码/架构风格,所以我们确切地知道要查找哪个文件夹 - Extension.现在只需检查它们.

So we've narrowed it down to Bridge and Bundle. If we look inside them then we see Bundle/TwigBundle or Bridge/Twig. We also know that Symfony2 developers follow a strict code/architecture style, so we know exactly which folder to look for - Extension. Now it's just a matter of checking them both.

长话短说,我们在 vendor/symfony/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension 中找到了我们正在寻找的东西,在那里我们看到了一个 render_* 功能.头奖!

Long story short we find what we're looking for in vendor/symfony/src/Symfony/Bridge/Twig/Extension/HttpKernelExtension, where we see a render_* function. Jackpot!

在改变任何东西之前,我们需要先模拟已经存在的东西,所以我们创建了这样的东西:

Before changing anything, we need to first emulate what's already there, so we create something like this:

use Symfony\Component\HttpKernel\Fragment\FragmentHandler;

class NewTwigFunction extends \Twig_Extension
{
    private $handler;

    public function __construct(FragmentHandler $handler)
    {
        $this->handler = $handler;
    }

    public function getFunctions() 
    {
        return array(
            'new_func' => new \Twig_Function_Method($this, 'newFunction', array('is_safe' => array('html')) )
        );
    }

    public function newFunction($uri, $options = array()) 
    {
        return $this->handler->render($uri, 'esi', $options);
    }

    public function getName() 
    {
        return "new_func";
    }

 }

现在当你打电话

{{ new_func(url(route-name)) }}

您应该看到与

{{ render_esi(url(route-name)) }}

但是我们仍然需要去掉 url 部分.就像馅饼一样简单,我们只需将 router 服务添加到我们的扩展中即可!现在我们的扩展看起来像这样:

But we still need to get rid of the url part. Easy as pie, we just add the router service to our extension! Now our extension could look like this:

use Symfony\Component\Routing\Router;
use Symfony\Component\HttpKernel\Fragment\FragmentHandler;

class NewTwigFunction extends \Twig_Extension
{
    private $handler;
    private $router;

    public function __construct(FragmentHandler $handler, Router $router)
    {
        $this->handler = $handler;
        $this->router  = $router;
    }

    public function getFunctions() 
    {
        return array(
            'new_func' => new \Twig_Function_Method($this, 'newFunction', array('is_safe' => array('html')) )
        );
    }

    public function newFunction($routeName, $options = array()) 
    {
        $uri = $this->router->generate($routeName);

        return $this->handler->render($uri, 'esi', $options);
    }

    public function getName() 
    {
        return "new_func";
    }

 }

{{ new_func(route-name) }} 应该按预期工作.

and {{ new_func(route-name) }} should work as expected.

按照我的理解,您需要与 render_esi 几乎相同的功能,但对输出略有改动.所以这意味着我们需要在 return$this->handler->render($uri, $strategy, $options); 之间的某个地方挂钩.

The way I understood it, you want almost the same functionality as render_esi, but with slight changes to output. So that means that we need to hook somewhere in-between return and $this->handler->render($uri, $strategy, $options);.

我们需要深入到兔子洞的深处取决于变化.

How deep down the rabbit hole we need to go depends on the change.

例如,如果您想在将 Response 对象转换为实际的 html string 之前对其进行更改,则需要首先找到它转换的位置.一个不错的选择是查看 FragmentHandler:

For example, if you want to alter Response object before it's turned into actual html string, you need to find the spot where it's turned in the first place. A good bet would be to look into FragmentHandler:

protected function deliver(Response $response)
{
    if (!$response->isSuccessful()) {
        throw new \RuntimeException(sprintf('Error when rendering "%s" (Status code is %s).', $this->request->getUri(), $response->getStatusCode()));
    }

    if (!$response instanceof StreamedResponse) {
        return $response->getContent();
    }

    $response->sendContent();
}

明白了!现在你只需要扩展 FragmentHandler::deliver() 并将你的实现传递到你的树枝扩展中.

Got it! Now you just need to extend FragmentHandler::deliver() and pass your implementation of it into your twig extenion.

你要明白Symfony2的核心代码和你在日常生活中写的并没有什么不同,它仍然遵守自己的规则.

You have to understand that Symfony2 core code is not that different from what you write in your everyday life, it still abides by its own rules.

比如,通常在Symfony2中创建Twig扩展时,您需要将其配置为服务,对吗?嗯,Symfony2 核心扩展的配置方式相同.您只需要找到配置文件所在的位置即可.

For example, when normally creating a Twig extension in Symfony2 you need to configure it as a service, right? Well, Symfony2 core extensions are configured in the same way. You just need to find where the configuration files are located.

遵循扩展功能的逻辑,我们确信它们不在Component中.Bridge 实际上是一个设计模式的名称——而不是一个地方你会放置你的服务配置:)

Following the logic from Extending the functionality we know for sure that they're not located in Component. Bridge is actually a name for a design pattern - not a place where you'd place your service configuration :)

所以我们只剩下 Bundle - 显然,我们可以在这里找到我们需要的所有信息:vendor/symfony/src/Bundle/TwigBundle/Resources/config/twig.xml

So we're left with Bundle - and obviously that's where we find all the information we need: vendor/symfony/src/Bundle/TwigBundle/Resources/config/twig.xml

现在我们只需查看原始 HttpKernelExtension 的配置方式并遵循其引导:

Now we simply look up how original HttpKernelExtension is configured and follow its lead:

    <service id="twig.extension.httpkernel" class="%twig.extension.httpkernel.class%" public="false">
        <argument type="service" id="fragment.handler" />
    </service>

将其转换为更常用的 .yml 格式,我们的扩展配置可能如下所示:

Transforming it into a more commonly used .yml format, our extension config could look like this:

new_func:
    class: Acme\Bundle\MyBundle\Twig\NewTwigFunction
    arguments:
        - "@fragment.handler"
        # Uncomment when implementing code from 2nd example
        # - "@router"
    tags:
        - { name: twig.extension }
    public: false

这篇关于接近完成 - 只需要完成 Twig 扩展来渲染 ESI - Symfony2的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆