我正在尝试将var发送到symfony2中的事件侦听器进行查看,但我已经堆叠了。
1)这可能吗?
2)使用什么内核事件(kernel.view或kernel.request)?
3)最后如何发送一些var来查看?
我最好的猜测是我必须从控制器延伸返回,然后让控制器完成他的工作。
我需要发送一些对象(实体)数组。
答案 0 :(得分:42)
我看到了几种处理这个问题的方法。
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
。只有在控制器is not an instance of Response object返回时才会调用它
那说,做
// Acme/FooBundle/FooController#fooAction
return $this->render();
返回Response object,因此不会调用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
定义添加到他呈现的任何模板中。
另一种选择是create a TWIG extension。在下面的示例中,我假设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);
}
}
答案 1 :(得分:1)
这里有一种替代方法,我必须这样做。我想获取一些数据,通过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());
}
这是一种方式。老实说,我不喜欢本页描述的任何方法。应该有更好的方法,但是没有。这就是我正在使用的,而且效果很好。只要确保你没有调用你的变量"数据&#34 ;;使用不会被其他地方占用的东西,最好把它塞进自己的(function() { }
JS命名空间。
答案 2 :(得分:0)
我不知道如何直接将变量传递给视图,但您可以使用kernel.response
事件侦听器更改响应对象。看看symfony调试工具栏如何注入底栏,你可以使用类似的技术。