Doctrine 2 with Symfony DI Container - symfony

I am working on a Zend Framework project that leverages Doctrine 2. I'm trying to get Symfony's DI container working with the project as well, but I'm having trouble. Suppose I have a class "Foo" that needs two instances injected. I can set up a Symfony DI container no problem to fetch me a new "Foo" with the dependencies injected. Great! But now what if I want to make "Foo" a Doctrine entity? All is well when I insert the entity to the DB because I can grab a new one from the DI container and simply persist the entity. However, when I query the entity from the DB Doctrine is instantiating my "Foo" instances and they will not have the proper dependencies injected. How do I get Doctrine to use my DI container so that the entity will have the appropriate dependencies? I know that Doctrine offers a "postLoad" hook in that I could use to inject dependencies on my entity, but that kind of defeats the purpose and benefit of the DI container.

A Doctrine Entity is a newable, not an injectable. Entities are not supposed to be created through a DIC. See this following blog post on the difference between newable and injectable:
http://misko.hevery.com/2008/09/30/to-new-or-not-to-new/

Its a bit tricky, but it can be done. There exists a patch for symfony di container which allows you to pass a already existing object to the container builder instance and let the di container configure it for you (e. g. inject dependencies based on interfaces). The patch is implemented in this repository on github: https://github.com/lstrojny/symfony but didn´t make it upstream to symfony master repository.
You use it like this:
$user = new User();
$container->configure('someId', $user);
Then you could register a PostLoad event handler with Doctrine´s EventManager (see here for more details: http://www.doctrine-project.org/docs/orm/2.0/en/reference/events.html ). In this event handler you configure the loaded entity via the aforementioned method. It´s obvious but you cant use constructor injection in this case, only setter.
This is a bit tricky to set up, but can be very powerful especially in conjunction with the ability of symfony di container to inject dependencies based on interfaces.

Related

Symfony2: Creating entity table conditionally

I have a bundle with entity defined in it. I want to be able to configure this bundle in such a way, that this entity will or won't be relevant. So if bundle is configured properly entity table shouldn't be created with app/console doctrine:schema:update etc, or should be - it should depend on configuration.
How to conditionally "disable" entity so its table won't be created by app/console doctrine:schema:update?
Your scenario requires you to disable the auto_mapping, but it seems to be set to false by default. http://symfony.com/doc/current/reference/configuration/doctrine.html
Next thing to do is make sure the build function of your bundle conditionally adds the wanted DoctrineOrmMappingPass as also is explained here: https://stackoverflow.com/a/26975083/1794894
As you can see in the source, build only is executed once the cache is empty so this is the place where you can do this. You can also take a look at how to add compiler passes there.
I think that although maybe you could find a way, you are complicating your self. If the back-end bundle is independent then always could be optional to install it and by consequence it's entities created or not.
You can find an example in Sonata bundles, you can manage the users as you want, but if you are using FOSUserBundle, the you have the option to install SonataUserBundle, then tell to fos_user configuration that the new class belong to the Sonata User and as consequence the new entity will be persisted with a lot of new attributes thanks to class inheritance, and all the crud operations for user will be already configured in sonata views. SonataUser also have it's own user entity for using in a standalone way.
I know that this is not what you asking for but may be you just need manage to follow a model like this.

ASP.NET 5 dependency injection outside of Controllers and Views

Each tutorial or example that I've found for using DI in ASP.NET 5 only shows how it works with Controllers and Razor Views. I need to use DI for other classes but don't know the proper way to resolve types and provide an instance. Right now I have an instance of a HackyDependencyResolver that everything must reference in order to get the proper instances. I want to either access ASP.NET's service resolver or follow some other best-practice for resolving dependencies.
For example if I have
public class SomeClass
{
public SomeClass(IUseMe useMe)
{
}
}
which is not an ASP.NET MVC Controller. I need a pattern for resolving a correct instance for IUseMe when SomeClass is created. Certainly I can make my own global factory, but is that the best way?
DI has nothing to do with asp.net, controllers or views. In the end all are classes. Considering that an action is an entrypoint in your app, any service you need there should be injected, The service itself has some dependencies and those will be injected automatically by the DI Container when it instantiates the controller.
All you have to do is to define your services (not every object needs injected deps) then register those services into the Di Container.
How do I resolve IUseMe so that I'm not dependent on a particular implementation?
You don't. The Di Container does that based on configuration, when the controller is instantiated. Everything has a flow, you don't just pick classes out of thin air and say "I want this created by the Di container". OK you could, but it would be the wrong approach.
The whole point of using a DI Container is not to care about instantiating services. The framework takes care of integrating with the container, your only job is to define the classes properly and to configure the container .

Doctrine DQL with interface

I have an entity in one of my portable bundles with MappedSuperClass set. I extend it to the real entity for each separate project / website and implement the additional properties in a main project bundle. I'm using the interface and the ResolveTargetEntities to relate the entities using the interfaces. This part works flawlessly so far.
The problem comes with my DQL queries, which need to address that particular implemented entity class, the one that extends the mapped superclass. If I use the interface or the mapped superclass, I get the Symfony errors. But I don't want to use my implementation of the superclass name because that would mean I have to change my portable bundle's repository code for each project, which is unacceptable.
One of the ideas was to get the orm mappings from config in the repository and inject the correct class there. But I can't find the way to extract that info from the config file.
The other, better, one was to create some sort of a listener, which would replace the interface with the real thing for me.
So my questions: Does anyone know if this is the usual behavior for the DQL not to be resolved? Does anyone have any ideas how I would implement the code to achieve the resolution by myself?
Any info is appreciated.
I assume you have your concrete class set as a parameter that you are accessing later in your parent bundle. If so you can create a repository for that class (half copied from Sylius).
parameters:
acme.repository.something.class: Doctrine\ORM\EntityRepository
// Or your custom repository
services:
acme.manager.something:
alias: doctrine.orm.entity_manager
acme.metadata.something:
class: Doctrine\ORM\Mapping\ClassMetadata
factory_service: acme.manager.something
factory_method: getClassMetadata
arguments:
- %acme.model.something.class%
acme.repository.something:
class: %acme.repository.something.class%
arguments:
- #acme.manager.something
- #acme.metadata.something
Then you can just call the repository using $this->container->get('acme.repository.something)`
Andrej, I had a similiar situation. You can make a setter method in your custom repository that sets the class name to be used in the dql. You can then have that setter method called with the call tag in your service declaration.
This is what I did in my post repo service declaration. I hope it helps. Good luck.
<service id="cfs_blog.post_repository"
class="%cfs_blog.post_repository.class%"
factory-service="doctrine.orm.entity_manager"
factory-method="getRepository">
<argument>%cfs_blog.post.class%</argument>
<call method="setUserEntityClass">
<argument>%user_class%</argument>
</call>
</service>

Silex - real DI vs injecting $app which looks like ServiceLocator?

I read the article yesterday: https://igor.io/2012/11/09/scaling-silex.html
And another one http://davedevelopment.co.uk/2012/10/03/Silex-Controllers-As-Services.html
So a conceptual question rised in my head:
Currently I do have a lot of controllers in separate classes. I overwrite controller_resolver to create a controller class instance and inject $app into contoller's constructor.
I define routes like this $app->get('/hello', 'HelloController::indexAction') <- my controller resolver will create new HelloController($app); - so far so good.
But to be honest it became a ServiceLocator pattern, not a DependencyInjection, because I do inject whe whole $app which looks like ServiceLocator usage.
Now I am in doubt: should I leave it as is (because it works well) or try "controllers as services" to inject only those sevices on which my controller really depends on? May be my SeviceLocator approach will hit me some day? (people say that DI is better for tests).
I have also looked into Symfony Framework Bundle: class Controller extends abstract class ContainerAware which also have the whole $container injected! ServiceLocator approach in full stack framework?
Any recomendation? Pros/cons?
The symfony2 full-stack framework
The framework uses the Dependency Injection pattern and not the Service Locator pattern.
All controllers aren't services by default. The ContainerAware class includes methods to get access to the service container, so you can call Services inside the Controller.
If you are going to use a Controller as a Service you need to remove the Controller extend. All dependencies you want to use inside the controller needs to be injected by the Service Container.
Read more about this in a blogpost by richard miller, one of the core contributors of Symfony2.
The Silex micro-framework
The Silex micro-framework provides the bare bones of a framework, it's up to you how the architecture looks and which patterns you use.
The Silex documentation uses Controllers that aren't Services. It injects the complete Service Container inside very Controller:
$app->post('/post/{id}-{slug}', function($id, $slug) use ($app) {
// ...
});
If you want to use controllers as service, you should only inject the services you want to use inside the controller.
EDIT: The Controller::action syntax refers also to a Controller that isn't a Service. The Controller:action notation is used to refer to Controllers as Services.
There's lot's of personal preference involved here. What you've done already is a good (enough) step to organising your code base. Some people like myself take things a step further and move our controllers to the container, rather than injecting it in to some kind of BaseController. This happens in both Silex and the full stack Symfony framework.
My advice would be to leave everything you have as is, then try defining your next controller as a service, by practising BDD.
For example, the behaviour of a UserController view action:
It should retrieve the user from a database
It should render the user with a template
Not once does it mention retrieving the database or the template renderer from a container. I'm comfortable not injecting the container, so I'll only inject what I'm led to believe I need by BDD.

Lazy loading dependencies with symfony DI

Currently I've got a Symfony2 DI container instance ready with a service and all it's dependencies. Lets say for example I have a Car class and it has Engine and Lights as dependencies.
In my current setup both these dependencies are automatically created through setter injection when the Car object is created, but it might very well be that my Car object won't need it's lights this time around thus it doesn't explicitly need to create an instance of this dependency.
Is there a way to achieve this in Symfony DI? Thus only creating an instance of the Lights object when needed? My guess is it'll be some sort of Proxy implementation like Doctrine has but as far as i've seen it doesn't exist in Symfony DI.
Inject the dedendencies that are mandatory through the Constructor via your services.yml, automatically.
If you have optional dependencies inject them through a setter in your Controller when you need them.
$this->container->get('cars')->setLights(new \Namespace\Lights());
Of course your Cars class must be designed like so and you have to direct the injections yourself in your controller, or whereever needed, code.
Question is already answered, but for who needs this functionality, lazy services are implemented in Symfony 2.3.
You need to install the ProxyManager bridge.
You can find official documentation here.
A very interesting question, but I don't think it's possible within Symfony2's Dependency Injection Container. The container is only aware of what you tell it - in this case, you have a dependency that's conditional on a specific use-case. Plus, the registration of services happens early on in the app's life, so I don't see how you could get this to work.
Maybe you should use the Factory pattern. Register a CarFactory as a service, and then when fetching a Car instance, you can specify that it should include a Light dependency.
Can I ask why you want to achieve this? There may be a simpler solution.
It's not a pretty workaround, but you can try injecting the whole DIC, then getting the Light and Engine services when neccessary.
I was thinking about something like this method in the Car class:
protected function getLightService()
{
if (!$this->light) { //so we reuse the first instance
$this->light = $this->dic->get("car.light");
}
return $this->light;
}

Resources