Symfony 2 sharing data between controllers

强颜欢笑 提交于 2019-12-06 06:15:15

This is a common stumbling block to Symfony 2 newbies. The controller/container question has been asked hundreds of time before so you are not alone(hint).

Why doesn't your controller constructor code work?

Start by looking under vendor/symfony...FrameworkBundle/Controller/Controller.php. Hmm. No constructor there so where the heck is the container coming from? We see that Controller extends ContainerAware. That seems promising. We look at ContainerAware (the namespace helps to find where the file is) and once again, no constructor. There is however a setContainer method so we can assume that the container is injected into the controller after the constructor is called. Quite common in a dependency injection based framework.

So now we know why the constructor code fails. The container has not yet been injected. Stupid design right? Time for a different framework? Not really. Let's face it, having to have all your controllers extend a base controller just to get some twig variables set is not really the best design.

The Symfony way to execute code before the controller action is executed is to make a controller event listener. It will look something like this:

namespace Cerad\Bundle\CoreBundle\EventListener;

use Symfony\Component\DependencyInjection\ContainerAware;

use Symfony\Component\HttpKernel\HttpKernel;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class ModelEventListener extends ContainerAware implements EventSubscriberInterface
{   
    public static function getSubscribedEvents()
    {
        return array(KernelEvents::CONTROLLER => array(
            array('doTwig', 0), // 0 is just the priority
        ));
    }
    public function doTwig(FilterControllerEvent $event)
    {
        // Ignore sub requests
        if (HttpKernel::MASTER_REQUEST != $event->getRequestType()) return;

        $this->container->get('twig')->addGlobal('foo');
    }
}
// This goes in services.yml

parameters:
    cerad_core__model_event_listener__class: 
        Cerad\Bundle\CoreBundle\EventListener\ModelEventListener

services:
    cerad_core__model_event_listener:
        class:  '%cerad_core__model_event_listener__class%'
        calls:
            - [setContainer, ['@service_container']]
        tags:
            - { name: kernel.event_subscriber }

So now we have the desired functionality without the need for a base controller class.

Notice also that the controller can be accessed through the event. Since the controller has been created but the action method not yet called, you could call controller methods or inject data directly into the controller. This is seldom needed. In most cases, you would add additional information to the request object which then gets injected into the controller's action method.

It's really a nice design once you get comfortable with listeners and services.

TN888

Please read carefully that question - Symfony2 passing data between bundles & controllers, try to use code included in it.

You can use service to solve your problem, for example.

If you look at the Controller class you'll se the following:

class Controller extends ContainerAware

This means you can retrieve twig from the container as simple as this:

$twig = $this->get('twig');

But I would recommend you to use custom twig extension in your case.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!