Hi, I have started to create a project using Symfony 2. I need to share data between all controllers.
I have added a base controller which extends symfony\controller and each of my controllers extends this base controller
class BaseController extends Controller
class HomeController extends BaseController
This base controller will be used for things like assigning global twig variables ( I know I can do this in the config but some of the variables will be gotten from other config files and database ).
So I thought I could reference container since Controller is container aware, however it isn’t at the point I am using the functions (from constructor).
public function __construct ()
I have seen people mention passing the container in as a parameter and mention services but I have had a look and cannot figure it out. All I want to achieve is this:
public function __construct (Container $container) {
$container->get('twig').addGlobal('foo');
}
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.
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.
+1 for a great answer. 
I’ll also leave this documentation page here.
Adding globals into our templates is common enough that Symfony made it even easier.
Awesome post @ahundiak, thanks. I have since decided to stick to Silex since I am more comfortable with it and it seems it would take a while to migrate the whole project over. I would like to start using Symfony for it but not sure it is the best option at this stage. I will, however, implement your code in a test project to learn more about how Symfony works.
Consider accepting my answer on the site that just over flows with questions. Cerad
Didn’t see that answer. Accepted.