Dependency Injection - What is the best approach? - symfony

Scenario
Talk about Symfony2. I have an entity with his setters and getters. One of this setter is a bit particular, because have to retrieve some related object, do something and write back ralationship.
What came in my mind, for retrieve those objects, is to use the entity manager and repository related to my entity.
Problem
I haven't the possibility to access Entity Manager directly from entity. One possible solution is to inject the E.M. into this entity but, as far I know, dependency injection is not recommended for entity.
Possible solution
Write a service, inject into it E.M., use service into entity.
Please pay attention to this: I can't instantiate my entity elsewhere because a Bundle (SonataAdmin) is responsible for doin' that.
Is this a good way to do it, or exists a better method?

Let's say you're working with the Entity 1. You need to get entity 2.
I would create a service, with a function which get Entity 1 as a parameter. Give E.M. to this service, and get Entity 2.
Entity file isn't made to such a thing, services are here to help you.

Related

How to get self links of embeddedItems from Resources from Spring Data Rest and FeignClient

I have an application where I am using Spring Data Rest to expose my entities in one service, and then use FeignClient from another service to access and update those resources.
In examples I've seen POSTing a #OneToMany sub-resource association in Spring Data REST, the way to establish these relationships is as follows:
Create the entity
Get the "self" href of the newly created entity
Create a list of existing entities of the owning entity for that type and then add that newly created link to the list
Do a "PUT" with the list of URIs to the association URI (with a Content-Type of "text/uri-list") to create the association.
I have done this using AngularJs and it works fine. However, I really do not want my javascript controller to have such an intimate knowledge of my domain objects, I would prefer to have Spring HATEOAS do that work for me.
So what I've done is to create a service in my client application that uses the Spring Cloud FeignClient access those endpoints and do the work that the Angular is presently doing.
The problem that I am running into is that when I get my reference to my associations (e.g. "http://myapp/myobjects/3/myassociation") and then do a "GET" to that URI, it returns "Resources<MyAssociation>" which has no way of getting at the list of URIs of the association objects. All I get for "Links" is the reference to the associations from the owning entity (e.g. "http://myapp/myobjects/3/myassociation").
Is there a way that I can find that list of associations without having to make several other GETs so that I can add the newly added one to it?
Thanks in advance,
CS
URI.create(Resource.getId().getHref()).getPath()
U can try this.

Dependency Injection or Service Locator - Symfony

I have started to go through Symfony2 code, studied a little bit small classes like Pimple and after few hours of examination have come to strange idea. The best start for this is to explain how I understand few terms, so:
Dependency
Something which is needed for another thing to work, like "engine" in "car"
Container
Object or class which is able to store a lot of another objects, like "engine","gearbox" or even "car"
Dependency Injection
Process in which every dependency is injected to object, so if I need "car" I know that I have to inject "engine","gearbox" and a lot of another stuff. Important is, that "car" don't create "engine", but "engine" is put inside "car"
Service Locator
Process in which object asks for another object, for example into the car there is inserted our container, and when car need to start it require from container "engine", so container return him "engine"
When i studied Symphony code, they start with dependency injection, but after some time I realize that when Controller is created, there is injected whole container and then you can use $this->get('serviceName') to get it, so it more looks like service locator, which according to few articles is anti-pattern.
Sow how is it? Is that line between DI and SL so small that it is sometimes broken? Or did I misunderstood something? If I use DI, do I need to insert every service into controller, so I know from outside what I use? Or can controller become in some cases container?
Your understanding of DI is pretty good. And yes, Symfony Controller does implement ContainerAwareInterface, and as you said, has a service locator role. But service locator isn't an anti-pattern. Each pattern has it's proper and improper uses.
Furthermore, Symfony doesn't enforce you in any way to use it's Controller. Your Controller can be a service. Hell, it can even be a function!
Here is one of the reasons why Controllers are implemented as service locators: Performance.
Let's drop car analogy and focus on real case that you'll encounter in 99% of projects: you need CRUD for a resource. Let's say you're building a Todo app and you need a RESTfulish controller to handle CRUD operations for Task Resource.
The least you need to have is a way to read all tasks and a way to add a new task, for that you need two actions: index (commonly named list too), and store (commonly named create too).
Common flow in Symfony would be this, in pseudo code:
indexAction -> getDoctrine -> getTaskRepository -> getAllTasks
storeAction -> getFormFactory -> createForm -> bindRequestDataToForm -> getDoctrine -> saveData
If Controller was a service locator
Index Action
When index action is executed, only service that will be resolved from the container will be ManagerRegistry (in this case Doctrine service). We will then ask it to give us task repository, and we'll do our operation with it.
Store Action
When store action is executed, we will do a bit more work: ask container to give us FormFactory, do some operations with it, and then ask it to give us Doctrine and do some operations with it too.
So summary: when index action is executed, only one service has to be constructed by service container, when update is executed, two will have to be constructed.
If Controller was a regular service
Let's see what our Controller needs. From the section above, we see that it needs FormFactory and Doctrine.
Now, when you just want to call index action to read all tasks from data storage, your controller will have to get instantiated by container. Before it can be instantiated, container needs to instantiate it's dependencies: FormFactory and Doctrine. Then instantiate controller while injecting those two into it.
So, you are calling index action which doesn't need FormFactory at all, but you still have overhead of creating it because it is needed for an action that will not be called at all in that request.
Lazy Services
To reduce this overhead, there is a thing called lazy service. It works by actually injecting a Proxy of your service into the controller. So, as far as controller is concerned, it got FormFactory. What it doesn't know is that isn't real FormFactory but instead a fake object which will delegate calls to real FormFactory code when you call some method on it.
Wrapping it up
Controller doesn't have to be a service locator, but can be. Making it a service locator can be a bit more performant and easier to bootstrap, but hides dependencies. Furthermore, it's a bit harder to test, since you'll need to mock dependency container. Whether you want to make your controllers services, functions or service locators is your choice and Symfony won't enforce you to use any of those ways.
In my experience, extending default Symfony Controller and having controllers be service locators is just fine as long as you don't write your business logic in them, but instead delegate all that work to services, which you get from container. That way, it's really unlikely that you'll have bugs in controller code (as methods will usually consist of 2-3 lines of code) and can get away without testing it.

Symfony2 Accessing a service from a non-service class

I want to access a service I've created (ServiceClass) from another class that I've created (ClassA). I've read a lot that the proper way to do this is to make ClassA a service and then inject ServiceClass, but class ClassA is not really a service in terms of functionality, it doesn't provide any global functionality, for me it's an Entity, so making it a service just so I can have access to other services doesn't seem right. Can anyone help me understand?
If it is an entity than it shouldn't need to know about any service. In ideal cases entities are just used to store data. You should rethink your class structure probably.
If you still want to go that way anyway, your only option is to declare it as a service or inject/set services when instantiating your class.
And yes, please provide code so we can suggest you what to do. This is just blind guessing because you provided very little info.

Using services in Doctrine repositories

How would I inject services in Doctrine repositories? Is it a good idea to do so? Should I make a doctrine repository container aware or should I pass services in the function arguments?
For example: I want to use a service called "knp_pager" that paginates queries. I want to have it available in the getArticleList() function of my Article repository so that I can return a paged result.
IMHO, inject the knp_pager service into your repository is not a good idea. It's not the responsability of the repository to paginate your query.
For limiting your query, I would pass an optional offset & an optional length to the repository method which can be generated by the knp_pager. Like that, the repository responsability is respected and you are able to limit your query easily.
You can define services from your repository, there is a cookbook recipe on symfony 2 website about that. Then you can inject other services using setters and wiring them in the container configuration.
Anyway I would try to keep repository classes as simple as possible (let's say that they should only provide generic data access) and inject them in other services if I need more abstraction on complex operations.

How to access 'templating' service not in controller

Ok, so the problem is:
I've got some 'order' entity, and it has 'status' property. On changing status, i wanted some other objects to be informed of this event, so i've decided to use Observer pattern. One of the observers notifies clients via email. Now i want to render Email text's from some of the twig templates. As i get from the Book, rendering templates in controllers are done with 'templating' service.
So the question as it follows: How can i access 'templating' service in my Observer class?
Specification:
I was advised, to implement my Observer as a service, but i'm not sure 'bout that. I've tried to solve this problem, and here is my options:
Use Registry. Solution that is straight and hard as rail. I guess it misses the whole point of DI and Service Container. Huge plus of this solution, is that i can access all common services from any point of my application.
To pass needed services from the context via constructor, or via setters. This is more like in Sf2 spirit. There comes another list of problems, which are not related to this question field.
Use observers as a service. I'm not really sure 'bout this option 'cos, in the book it is written, that service is a common functionality, and i don't think that observing entity with number of discrete properties is a common task.
I'm looking for a Sf2 spirit solution, which will be spread over whole project, so all answers with an explanation are appreciated.
As with any other service in a Symfony2 project, you can access it from within other classes through the dependency injector container. Basically what you would do is register your observer class as a service, and then inject the templating service into your observer service. See the docs for injecting services.
If you're not familiar with how Symfony handles dependency injection, I'd suggest reading that entire chapter of the documentation - it's very helpful. Also, if you want to find all the services that are registered for application, you can use the console command container:debug. You can also append a service name after that to see detailed info about the service.
Edit
I read your changes to the question, but still recommend going down the DI route. That is the Symfony2 spirit :) You're worried that your observer isn't common enough to be used as a service, but there's no hard rule saying "You must use this piece of code in X locations in order for it to be 'common'".
Using the DIC comes with another huge benefit - it handles other dependencies for you. Let's say the templating service has 3 services injected into itself. When using the DIC, you don't need to worry about the templating service's dependencies - they are handled for you. All you care about is telling it "inject the templating service into this other service" and Symfony takes care of all the heavy lifting.
If you're really opposed to defining your observer as a service, you can use constructor or setter injection as long as you're within a container-aware context.

Resources