I just followed the http://fabien.potencier.org/article/50/create-your-own-framework-on-top-of-the-symfony2-components-part-1 articles, and have some questions about the DI container.
Let's say I want to fire an event inside my controller, how would i get the dispatcher inside my controller?
I'm starting my test framework through
$c->get('app')->handle($request);
where 'app' is the Symfony\HttpKernel. How can i set the dependencies to the container? Let's say I have a view engine, defined in the container
$c->register('view.engine', 'Core\ViewEngine');
and I want to give that object, or resolve that object, inside my Controller to render some views. It's the same problem with the event fire, I don't have access to those values inside my controller ... How is a DI container supposed to work in situations like this?
Thanks!
There are different approaches. You might want to read through the silex documentation as a next step. In silex, the application itself is a DI container. You might also read through the introduction to Symfony 2 documentation.
The most straight forward approach (and the one used by S2 as a default) is to inject the DI container itself into your controller. The controller can then pull out services such as the dispatcher as needed.
A "better" approach is to inject the dispatcher along with whatever else the controller needs directly into the controller. It's "better" because the controller itself does not need access to the container. But it's more difficult since a controller often needs a number of services just to it's job.
==============================================
How would I inject the container in the controller though?
That is where looking at existing frameworks starts to come in handy. Remember that HTTPKernel is a component and not a framework. How you use it is up to you.
In Symfony 2 the app object is actually derived from Kernel and not HTTPKernel. The Kernel in turn contains an instance of HTTPKernel as well as an instance of the container.
There are several approaches you might take. There is no single "correct" one.
If you look into HTTPKernel::handleRaw you will find:
$controller = $this->resolver->getController($request))
You might make your own controller resolver object which would inject the container after creating the controller. Just one possibility.
Related
Update 2020 (this should have been much sooner). There can be a new class for each controller action. Each controller can be named by the action it is going to do, with an Invoke() method. Consider "Action Domain Responder" (ADR).
Why do I want to do this? Controllers do not necessarily adhere to SRP, and I'm not about to go creating a new class for each of, what is effectively, a controller 'action'. Therefore, a controller should not have everything injected via constructor, but the relevant method being called should be able to state explicitly "I require these objects" and another method "these other objects".
As of Symfony 2.8, the Dependency Injection component now provides auto-wiring for your services if you provide autowire: true in services.yml.
I'm defining my controller as a service, like so:
test_controller:
class: AppBundle\Controller\TestController
autowire: true
My controller looks as follows:
class TestController
{
public function indexAction(TestClass1 $tc1, $id)
{
return new Response('The slug is: ' . $id);
}
}
You will notice I'm typehinting for TestClass, which is just an empty class. However, the following error appears when I refresh the page:
What do I need to change in my services.yml file to have auto wiring dependency injection in my controller method? Just a note, the issue isn't because I have an $id 'slug' afterwards. Removing it does nothing.
Edit: I've created a bundle allowing to do more or less what you want called DunglasActionBundle.
Disclaimer: I'm the author of the Symfony autowiring system.
The Symfony Dependency Injection Component (and the autowiring system is part of it) doesn't work that way. It only allows to automatically inject dependencies in the class constructor of services and knows nothing about controller classes, actions and other parts of the HttpKernel Component.
It's not currently possible to do what you want to do. Initially, the autowiring system has been designed for domain services, not for controllers.
It should be possible to bridge the autowiring system with controller parameters using a custom param converter. However, I'll suggest you take another way I've first described here:
There is another approach I want to discuss since several time but I
did not have the time to blog about it.
It's a derivate of/similar to the ADR pattern, applied to Symfony.
An action is a single class with a __invoke() method containing all it's
logic (should be only some lines of glue code to call the domain and
the responder).
Actions are registered as a service (it can be
automated using a compiler pass and some conventions, similar to how
we discover controllers right now, with the ability to override the
definition if needed)
On such action services, autowiring is enabled.
It means that almost as easy as current controllers to use for the
developper, but with an explicit dependency graph and a better
reusability. Only things that are really necessary are injected. In
fact, it's already doable to use such system with Symfony. We do it in
API Platform master. Here is one action for instance:
https://github.com/dunglas/DunglasApiBundle/blob/master/Action/PostCollectionAction.php
In this implementation I also rely a lof on kernel events to be able
to plug and play some sort of logic (persistence, validation...) in a
decoupled manner but it's out of scope.
I am looking for a php implementation or a design pattern something like this (just a very basic skeleton example):
namespace Contract {
interface Application {...}
interface EntryPoint {...}
}
namespace RestApi {
class Module {
/** #return Contract\EntryPoint */
public function getEntryPoint(Contract\Application $application){...}
}
class EntryPoint implements Contract\EntryPoint {...}
}
namespace BusinessLogic {
class Module {
/** #return Contract\Application */
public function getApplication(){...}
}
class Application implements Contract\Application {...}
}
$dependencyResolver = new DependencyResolver();
$dependencyResolver->parse(new RestApi\Module());
$dependencyResolver->parse(new BusinessLogic\Module());
$dependencyResolver->invoke(function (Contract\EntryPoint $entryPoint){
$entrypoint->handleRequest();
});
I want to loose couple every modules I am using in my application, so I intend to design interfaces, maybe abstract classes with validation to make a well defined interface for every module type. I haven't found a solution for this problem, ppl usually inject things with IoC container, which does not tell anything about the common interface between two modules...
Do you know a design pattern which solves this problem, or a de factor standard php implementation/framework for this?
note: IoC container is not a solution, I want to inject the dependencies with well defined interfaces, not to pull them from a DI container or service locator... I don't want my modules to know anything about how they get their dependencies...
edit:
I updated my question because I don't think my code was obvious for everyone. A created a class diagram to ease the understanding of it:
Okay, so this diagram contains a description of a single environment. We usually use different environments for example: test, development, production, etc... Each of these environment contains different modules, for example by testing and developing we usually turn off email sending, so one of the modules contains a mock php mailer in those environments... As you see by cross-module dependency the classes depend on contracts, not directly on each other. This way the code of the modules is loose coupled...
I intend to describe this dependencies (for example with annotations) and inject them on an automated way somehow. This is a difficult task, because by PHP I have to load only the classes which are necessary to handle the request. For example:
So I have to use lazy load somehow, for example I could inject factories, but I don't like that idea, I want to inject the dependency itself, not a factory...
Be aware that the contract interface does not know anything about its implementations, so I have to publish somehow those implementations by every module and find them from the other modules... Most of the DI container implementations solve that problem, but I don't want to inject factories or DI containers into my modules. I want them to depend on the contracts only and nothing else...
Matthieu Napoli recommended to use just a single IoC container with different config by each of the environments, but I don't see how this would solve my problem. That DI container would instantiate every class with cross-module dependency, so I would move the whole config of every modules into a huge main config file. Even by a simple project I'd have about 20 classes (languages, users, identification-factors, user-identification-factors, contacts, user-contacts, roles, user-roles, permissions, role-permissions, articles, comments, etc...) and at least 3 modules (presentation layer, business logic layer, data access layer). So that main config would contain the instantiation of at least 60 classes from different modules... That would be pretty hard to maintain and I am almost certain that it would result a lot of code repetition by configs of different environments... Yes maybe splitting the config files can reduce the pain, but I guess I wont know the advantages and drawbacks of this solution until I start to use it on a complicated project. Another problem with this approach that how should I implement the lazy load without injecting the IoC container itself into every class with cross-module dependency? I think I need proof or example code, that this approach really works well by this problem domain...
Currently I am thinking on something similar than require.js does with AMD javascript modules, but that injects the IoC container as well by lazy load. You have to use the require("moduleName") from inside the modules if you want to load a dependency which you don't want to use in your code, just in case when it's really necessary. Ofc that require is just a sugar syntax of container.get("moduleName")... Currently I don't see how to solve that problem. I think every of my modules should have one or more DI containers, call them module containers. Those module containers can handle the cross-module dependencies. By lazy load the module containers would pull down the cross-module dependencies of each class from a main container, which would automatically register every module container and every class instantiated by them. In this scenario only the module containers would know about the main container if I cannot solve lazy load without injecting a factory or a DI container or a service locator... Ofc this is the last resort, I think I can do the lazy load somehow without injecting the main container into the module containers. Or at least I can do it somehow with a sugar syntax, for example:
class ModuleContainer {
public function setCrossDomainDependency(Contract\Dep $crossDomainDependency){
//...
}
/** #return Contract\Dep */
public function getCrossDomainDependency(){
//...
}
}
My purpose to use the same ModuleContainer instance regardless of having a MainContainer. I'll check the reflection api, maybe I am able to override the getCrossDomainDependency somehow at runtime. If not then I think the only solution to inject factories or the main container... Nah but this is my solution...
How would you solve this problem?
A IoC container is exactly the solution.
I want to inject the dependencies with well defined interfaces, not to pull them from a DI container or service locator
Then don't use the container as a service locator. That's exactly what a DI container is meant for.
Here is your example using PHP-DI:
$containerBuilder = new ContainerBuilder();
$container = containerBuilder->build();
// Configure RestApi\EntryPoint to use for Contract\EntryPoint
$container->set(Contract\EntryPoint::class, \DI\link(RestApi\EntryPoint::class));
// Configure BusinessLogic\Application to use for Contract\Application
$container->set(Contract\Application::class, \DI\link(BusinessLogic\Application::class));
// Run
$entryPoint = $container->get(Contract\EntryPoint::class);
$entryPoint->handleRequest();
Of course my example here is not perfect. I would suggest to separate the configuration part from the execution part. I would put the configuration in a configuration file (look here for how).
Important: Yes, in that example I fetch something from the container. That is exceptional. That should happen only once or twice in your application.
You have to use the container at some point, at the root of your application (i.e. the entry point of the app), to construct the object graph (or dependency graph).
I am not suggesting that you call get() on the container everytime you need a dependency. I am suggesting that you use dependency injection instead, and that you call get() only at the entry point of the application.
Example of defining with a factory:
$container->set(Contract\EntryPoint::class, \DI\factory(function (Container $c) {
return new RestApi\EntryPoint($c->get('some.parameter'));
}));
I have build a in-house MVC PHP framework and now I am struggling on implementing DI Container. I've adopted the Pimple as a DiC, I have read the book by Chris Hartjes "The Grumpy Programmer's Guide To Building Testable PHP Applications" (which I find a very good and inspiring read, will recommend it highly!), which talks eased me to understand more about TDD. Anyway, If I get a DI in the core of the framework, how should I populate the definitions and ho should I pass it along.
Injecting the container(Injecting in the application object all the way to the user created controller). - WRONG
Forcing the dev-user to 'populate' it in the Bootstrap - WRONG
Singleton - VERY WRONG
Observer Pattern (DiC attached to the observer. Observer as a front end to DiC) - ?(Probably the worst idea :D )
Then how to make the core DiC available in the whole framework (for, lets say, injecting the Configuration Object), without creating any dependencies, unnecessary forcing the user to code it or adding the overhead of creating XML/JSON or any other.
PS:
** I do believe that I will see a lot of answers about the Inversion-of-Control (IoC) and Service Locator. Which I cant seem to get exactly how to implement them.. Reference me to a simple/basic guide.
(disclaimer, I'm the developer of PHP-DI)
I don't really understand your question, it seems to me that if you have full control over the MVC framework, then using DI and a DIC should be pretty easy. Here is a copy of the introduction to DI on PHP-DI homepage:
Application needs FooController so:
Application gets FooController from the Container, so:
Container creates SomeRepository
Container creates BarService and gives it SomeRepository
Container creates FooController and gives it BarService
Application calls FooController
FooController calls BarService
BarService calls SomeDependency
SomeRepository does something
The Container is in charge of creating all the objects (the object graph), and then the non-framework code (controllers, services, …) works without EVER calling the Container.
Then how to make the core DiC available in the whole framework?
Do not make it available in the whole framework.
Each component (object) should have its dependencies injected (for example in the constructor). The container will inject them (because the container creates all the objects), and the container should be called at the root of your application (the front controller).
Example: you want to inject the Configuration object in a controller:
class MyController {
private $configuration;
public function __construct(Configuration $configuration) {
$this->configuration = $configuration;
}
}
Since that the role of the DIC to create that controller, it will inject the configuration object.
Also, I don't think you should inject the whole configuration object, but just the values you are interested in (but that's another debate).
And also, if you have questions about how to write your controllers, maybe you should read this: Controllers as services?.
You may access the (let's say) Doctrine service inside the controller, using:
$d = $this->getDoctrine()
now I want my controller to call another function (in another class) and I want that class to have access to all services. Is that possible without passing the services as variable?
You have to inject dependent services to your class or method. If you were thinking about some global object you might access everywhere than it's not the right way to go (and you can't actually access the container this way). You'd miss the whole point of dependency injection.
You can inject the services to your class two ways:
Manually
Let DIC do it
First solution requires you to pass the dependency yourself either way (constructor, setter, method).
The later solution means you define your class as a service and let container construct it and inject the dependencies. It can only be done if you can delegate object creation to DIC. It cannot be done with Entities for example.
Be careful with injecting whole container. It's not the best practice. You'd introduce dependency on a whole container which might have different services depending on the configuration. Dependencies wouldn't be clear.
I'm trying to pass the entity manager to a service but havent find a correct way yet. I want to complete remove the em from the controller so thats why I'm finding another way.
I was thinking of this options:
1. I could save it in the registry and then try to access it from the service object. can I access the registry from there?
2. Inject the em to a static variable of a base class for the services in the bootstrap.
What is the correct way yo do it?
thanks
I think generally the best way to do it is to pass the entitymanager as an argument to the constructor.
This allows you to easily replace the entitymanager for example when doing unit tests, and unlike your approaches of 1 and 2, it does not depend on behavior in a base class or global data (the registry is a lot like a global variable)
What you could do to avoid touching the EM in your controllers is using a dependency injection container, such as the one in Symfony2 or the one in ZF2 (not sure if that component is very stable yet).
Another perhaps slightly simpler approach would be to have a sort of a "service locator" object, which you would use in the controller to get instances of your services. You could initialize the locator in your bootstrap with the services, or perhaps with a factory class which creates them.
In any case you will probably require at least some kind of an intermediate object in the controller. Personally I don't really see an issue with simply using the EM itself, unless you have some other reasons besides just not wanting to.
There's nothing wrong, IMO, with letting your controllers know about the EM. I typically use a Zend_Application_Resource to bootstrap Doctrine. That resource facilitates a bootstrap resource called "doctrine" which has an EM available. The abstract controller implements and em() method, which returns the EM.
When instantiating service classes, the constructor simply injects the EM via a call to $this->em() at constructor time.
This is nice, as many times, simple controller actions don't need any special service class, but can instead get away with doing $entity = $this->em()->getRepository('Some\Entity')->find(1); In those cases, I don't see any reason for additional redirection via a service class.