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(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.
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.
Related
I'm relatively new to Symfony (version 4) and have put together a REST API using the framework.
I have several controllers corresponding to endpoints many of which use common services. One service is common to every controller.
Currently I am injecting these services manually into each controller.
namespace App\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use App\Services\Utilities;
use App\Services\Database;
use App\Services\Session;
use App\Services\Rest;
class Fetch extends Controller {
protected $API;
protected $DB;
protected $u;
public function init() {
$this->API = new Rest();
$this->DB = new Database();
$this->u = new Utilities();
$this->API->init();
$this->DB->init($this->DB->default_credentials);
// ....
Its kinda repetitive and not very efficient since each class needs to be instantiated every time an endpoint is requested.
There is a need for a global base controller.
Having browsed the Symfony docs & stackoverflow posts, it looks like I can create a base controller and have all my other controllers extend it like so:
class Fetch extends BaseController {
//.....
And all the methods in BaseController will be available in Fetch. Moreover, I can run hooks in BaseController that will run globally (as long as all my controllers extend BaseController.
I have also come upon this symfony docs article describing implementation of "Before and After Filters" that hook into all requests.
Which method (BaseController / Before and After Filters) would be best appropriate for what is effectively some code I want to run globally every time a request is made & why?
Before and After should better then BaseController model, here is why:
suppose, you write 10 Controller class which extends BaseController class and BaseController class initiate 5 services. the possibility very high that every controller class may not require all 5 services. that will overhead for all 10 controller classes.
So, if you implement Before/After filter, you define which controller is executing and initiate services which require for this controller.
I have made a repository pattern app, having a repo and interface:
class UserRepository extends EloquentRepository implements UserRepositoryInterface
{
public function __construct()
{
$this->model = new User();
}
...
}
The repository and interfaces as well as extended class and its interface is registered in service provider and is called on app boot.
The questions I have are:
Is there a need to watch out for the order of registering? For example, should EloquentRepository class be loaded before the
repo, or does Laravel handle that on its own?
In case I inject UserRepositoryInterface in a controller, is the constructor method called automatically even though I didn't really new-up a class?
How long does the DI injection "live"? If I inject it in a page controller which calls some other controller and needs the same dependency, does the constructor call twice then, and operate separately in each controller?
Is there a difference if I call it like App::make() instead of DI?
Is there a need to watch out for the order of registering? For example, should EloquentRepository class be loaded before the repo, or does Laravel handle that on its own?
I don't quite understand where you would load EloquentRepository as (from the code posted) it seems you're only extending it. Which shouldn't be a problem.
In case I inject UserRepositoryInterface in a controller, is the constructor method called automatically even though I didn't really new-up a class?
Yes. Most of Laravel's main classes (controllers included) are loaded with DI in mind and the dependencies will be resolved automatically.
That being said, since you are injecting an interface and an interface by default cannot be initialized as a class, since it has no implementation - you need to bind an implementation to the interface first in order to use it.
How long does the DI injection "live"? If I inject it in a page controller which calls some other controller and needs the same dependency, does the constructor call twice then, and operate separately in each controller?
My understanding is that a new instance of the class will be created when the next controller is initialized. Unless you bind a class as a singleton.
Is there a difference if I call it like App::make() instead of DI?
App::make(some::class) will automatically resolve the dependencies of class some.
For example:
namespace App;
use App\Dependancy;
class Test
{
protected $d;
public function __construct(Dependancy $d)
{
$this->d = $d;
}
}
If you call this in the controller: $a = new \App\Test() you will get an error that \App\Test constructor expects class Dependency as first parameter.
But if you initialize it like this: $a = \App::make(\App\Test::class) the Dependency will be automatically resolved.
try to make the repositories abstract in the controllers and inject these through constructor.
like this here:
public function __construct(EloquentRepository $repository)
{
$this->repository = $repository;
}
And in the AppServiceProvider you can inject repositories you will need.
public function boot()
{
// provides any Repository in SomeController
$this->app->when(SomeController::class)
->needs(EloquentRepository::class)
->give(function (Application $app) {
return $app->make(SomeRepositoryInterface::class)
});
}
I have a Controller class in which I have to use several namespaces like :
<?php
use Respect/Validation/Validator;
use Blah/blah/Foo;
class Controller {}
Now what I want that in every controller files that extends my Controller class, I do not have to write the use statements again and again.
This is something I want similar to what Laravel has done in his alias section.
How would I achieve this thing ? So for example when I do :
<?php
class HomeController extends Controller {
public function index()
{
$data = '';
Validator::arr($data); // Validator not found
}
}
This is unfortunately what you would have to do if using static methods. You could also have a Controller method (the constructor even) to inject the validator into the class, which the child classes can then use. You would the use public instance variables on the validator.
The benefit is that you do not need to specify the NS for your dependencies again and, especially so, your code is cleaner since you do not have a hard dependency on the Validator class.
for someone it might seem stupid, anyway I am new to the Symfony world and reading the documentation I came up with a doubt:
How does Symfony inject the DI Container instance inside of each Controller class which extends Controller in such a way that you can easily access a service from the container using the get($id) method??? Like here:
use Acme\HelloBundle\Newsletter\NewsletterManager;
// ...
public function sendNewsletterAction()
{
$mailer = $this->get('my_mailer');
$newsletter = new NewsletterManager($mailer);
// ...
}
I saw the source of the Controller class from GitHub, the Controller class in Symfony extends the abstract class ContainerAware which implements the ContainerAwareInterface interface, which has a method setContainer(ContainerInterface $container = null);
I can assume that the Controller itself attempts to set a reference to the Container instance calling setContainer inherited from the ContainerAware abstract class, but I am not sure whether I am right or not, but since I know that in Symfony2 every service (object with particular functionality) is under the supervision of the DI Container, who is responsible to inject the container to the Controller setContainer() setter? The Container itself? But how?
Thanks for the attention!
With controllers, Symfony2 uses the ControllerResolver class to determine if the Controller is an implementation of ContainerAwareInterface, and will inject the container that way. See this file (lines highlighted):
https://github.com/symfony/symfony/blob/master/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerResolver.php#L79-L82
As for other services, you will have to manually inject the container into them via service definitions.
I'm looking for a good example of how to correctly implement Service Layer with Zend Framework and Doctrine2
I've seen some implementations but all of them have access to the EM from the controller when instantiating the service, and I think that might be wrong or not?
Exmaple:
http://cobbweb.me/2010/11/integrate-doctrine-2-zend-framework-application/
Also I got to this project but not really sure how to implement it:
Thanks
Use a helper to act like a factory for the services:
You need to create an Action Helper and inject the EntityManager on it when you register the instance in the Front Controller.
This Action Helper receives as parameter in the direct() method the name of the service class that the factory should create.
Inside this method you should try to instantiate the service class requested, and return it (or throw an exception if the same is not found).
Let your service classes receive as parameter in the constructor the EntityManager and inject it during the construction on the factory.
The rest should already be clear to you. In your controller you only need to use something like:
SomeController extends Zend_Controller_Action {
//...
public function someAction ()
{
$myService = $this->_helper->service( 'MyService' );
$myService->doSomething();
}
}