繁体   English   中英

如何从symfony2中的事件监听器发送var来查看?

[英]How to send var to view from event listener in symfony2?

我试图从symfony2中的事件监听器发送var来查看,但我已经堆叠了。

1)这可能吗?

2)使用什么内核事件(kernel.view或kernel.request)?

3)最后如何发送一些var来查看?

我最好的猜测是,我必须从控制器延长返回,然后让控制器完成他的工作。

我需要发送一些对象(实体)。

我看到了几种处理这个问题的方法。

kernel.request侦听器添加全局变量

我们的想法是在kernel.request事件之后直接添加一个全局变量。

services.yml

services:
    class: Acme\FooBundle\Listener\MyListener
    arguments:
        - @twig
    tags:
        -
            name: kernel.event_listener
            event: kernel.request
            method: onKernelRequest

myListener的

class MyListener
{
    protected $twig;

    public function __construct(\Twig_Environment $twig)
    {
        $this->twig = $twig;
    }

    public function onKernelRequest(GetResponseEvent $event)
    {
        $myVar = 'foo'; // Process data

        $this->twig->addGlobal('myvar', $myVar);
    }
}

您现在可以随时使用它

{{ myvar }}

来自kernel.view监听器

首先,您需要了解何时kernel.view 仅当控制器的返回不是Response对象的实例时才会调用它。
那说,做

// Acme/FooBundle/FooController#fooAction

return $this->render();

返回一个Response对象 ,因此不调用kernel.view

定义控制器

我们的想法是让所有控制器返回一个数据数组,就像@Template要求一样。

// Acme/FooBundle/FooController#fooAction

return array(
    'template' => 'AcmeFooBundle:Foo:foo.html.twig',
    'data' => array(
        'entity' => $entity
    )
);

定义服务

由于您已经拥有服务定义,因此您只需在服务声明中添加一些要求即可。
您需要@templating服务来呈现数据。
您需要将自己设置为kernel.view侦听器

// Acme/FooBundle/Resources/config/services.yml

services:
    acme_foo.my_listener:
        class: Acme\FooBundle\Listener\MyListener
        arguments:
            - @templating
        tags:
            -
                name: kernel.event_listener
                event: kernel.request
                method: onKernelRequest
            -
                name: kernel.event_listener
                event: kernel.view
                method: onKernelView

创建服务

// Acme/FooBundle/Listener/MyListener.php

use Symfony\Component\Templating\EngineInterface;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;

class MyListener
{
    protected $templating;
    protected $myVar;

    public function __construct(EngineInterface $templating)
    {
        $this->templating = $templating;
    }

    public function getMyVar()
    {
        return $this->myVar;
    }

    public function onKernelRequest(GetResponseEvent $event)
    {
        $this->myVar = ""; // Process MyVar data
    }

    public function onKernelView(GetResponseForControllerResultEvent $event)
    {
        $result = $event->getControllerResult();

        if (null === $this->myVar || !isset($result['template']) || !isset($result['data'])) {
            return;
        }

        $data = array_merge($result['data'], array('myvar' => $this->myVar));
        $rendered = $this->templating->render($result['template'], $data);

        $event->setResponse(new Response($rendered));
    }
}

你有。 监听器正在创建一个新的响应,将myvar的自定义定义添加到他呈现的任何模板中。


来自TWIG扩展

另一种方法是创建TWIG扩展 在下面的示例中,我假设MyListener定义与上面相同。

定义服务

根据上面给出的文档,您只需创建一个简单的扩展类。

// Acme/FooBundle/Resources/config/services.yml

services:
    acme_foo.my_listener:
        class: Acme\FooBundle\Listener\MyListener
        tags:
            - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
    acme_foo.my_extension:
        class: Acme\FooBundle\Extension\MyExtension
        arguments:
            - @acme_foo.my_listener
        tags:
            - { name: twig.extension }

定义服务

就像在文档中一样,我们将创建一个简单的函数。

// Acme/FooBundle/Extension/MyExtension.php

use Acme\FooBundle\Listener\MyListener;

class MyExtension extends \Twig_Extension
{
    protected $listener;

    public function __construct(MyListener $listener)
    {
        $this->listener = $listener;
    }

    public function getName()
    {
        return 'my_extension';
    }

    public function getFunctions()
    {
        return array(
            'myvar' => new \Twig_Function_Method($this, 'getMyVar')
        );
    }

    public function getMyVar()
    {
        return $this->listener->getMyVar();
    }
}

用法

然后你可以在任何视图中使用它

{{ myvar() }}

从一个普通的控制器

我不喜欢这个想法,但这是另一种选择。 您只需创建一个BaseController ,它将覆盖默认的render方法。

// Acme/FooBundle/Controller/BaseController.php

abstract class BaseController extends Controller
{
    public function render($view, array $parameters = array(), Response $response = null)
    {
        $parameters = array_merge(
            $parameters,
            array(
                'myvar' => $this->get('my_listener')->getMyVar()
            )
        );

        return parent::render($view, $parameters, $response);
    }
}

这里有一种替代方法,我必须这样做。 我想获取一些数据,通过json_encode()运行它,然后其作为JavaScript变量添加到响应中。 这就是我最终做的事情。

我正在订阅kernel.response

public static function getSubscribedEvents()
{
    return [
        KernelEvents::RESPONSE => 'onKernelResponse'
    ];
}

public function onKernelResponse(FilterResponseEvent $event)
{
    /** -- SNIP -- Cutting out how I get my serialised data **/
    $serialized = json_encode($data);

    /** Shove it into the response as some JS at the bottom **/
    $dom = new \DOMDocument;

    libxml_use_internal_errors(true);
    $dom->loadHTML($event->getResponse()->getContent());
    libxml_use_internal_errors(false);

    $node = $dom->createElement('script', "var data = $serialized;");

    $dom->getElementsByTagName('body')->item(0)->appendChild($node);

    $event->getResponse()->setContent($dom->saveHTML());
}

这是一种方法。 老实说,我不喜欢这个页面上描述的任何方法。 应该有更好的方法,但没有。 这就是我正在使用的,它运作良好。 只要确保你没有调用你的变量“数据”; 使用其他地方不会占用的东西,最好将它推入自己的(function() { } JS命名空间。

我不知道如何直接将变量传递给视图,但您可以使用kernel.response事件侦听器更改响应对象。 看看symfony调试工具栏如何注入底栏,你可以使用类似的技术。

https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/WebProfilerBundle/EventListener/WebDebugToolbarListener.php#L106

暂无
暂无

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

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