Using services in Doctrine repositories - symfony

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.

Related

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.

Dependency Injection - What is the best approach?

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.

Understanding Symfony2 services

I'm quite new to Symfony 2 and I'm moving to advanced topics like services. When should an object be a service?
For example, say that you have a facade object for making a call to a REST service. This class needs a username and password. Would it be correct modeling that class as a global service? Even if it's used only in a portion of the whole project?
# app/config/config.yml
parameters:
my_proxy.username: username
my_proxy.password: password
services:
my_proxy:
class: Acme\TestBundle\MyProxy
arguments: [%my_proxy.username%, %my_proxy.password%]
Definition taken from the Symfony2 glossary:
A Service is a generic term for any PHP object that performs a specific task. A service is usually used "globally", such as a database connection object or an object that delivers email messages. In Symfony2, services are often configured and retrieved from the service container. An application that has many decoupled services is said to follow a service-oriented architecture.
I think your example is a perfect candidate for a service.
You don't want to copy construction code to all places you need your API client. It's better to delegate this task to the dependency injection container.
This way it's easier to maintain (as construction happens in one place and it's configurable).
It's also more flexible as you can easily change the API client class without affecting code which uses it (as long as it implements the same interface).
I don't think there's a golden rule. But basically all classes implementing a task are good candidates for a service. Entities on the other hand are not as they're most often just data holders.
I always recommend Fabien's series of articles on the subject: http://fabien.potencier.org/article/11/what-is-dependency-injection
Yes, because this will spare you the configuration part. You're not going to fetch the username and password and give it to the constructor each time you need this class.

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.

SOA architecture for ASP.NET with Entity Framework

I am redesigning a solution's architecture to implement SOA.
After doing the design changes I have come up with:
MySolution.Client.MyProject.Web ...... //ASP.NET WebSite
MySolution.Client.MyProject.Proxy .... //Service Proxy C# Library Project *1
MySolution.Service ................... //Service.cs for Service.svc is here
MySolution.Service.DataContract ...... //IService.cs for Service.cs is here *[2]
MySolution.Service.HttpHost .......... //Service.svc is here
MySolution.Model ..................... //All custom data classes and EDMX model is here *[3]
MySolution.Repository ................ //Repository queries the DB using LINQ and ADO.NET queries
*1 MySolution.Client.MyProject.Proxy:
This project contains service proxy and contains presentation classes
*[2]MySolution.Service.DataContract:
This project contains IService and Request/Response Classes
All methods in Service.cs takes the Request classes as input and return Response classes as output
Therefore this project is referenced by the 2 Client Projects(Web and Proxy), as it contains the IService and all of the Request/Response classes that will be required to communicate with Service.cs
*[3]MySolution.Model:
This project contains the .edmx that is the Data Model of Entity Framework and some custom classes that are used in the project.
PROBLEM:
Because I only use request/response classes to communicate between service and client, the MySolution.Service.DataContract project is only used by Service.cs and Repository.cs
And due to that all responses that Repository generates I have to map them to the properties of its respective response class (which make both the original returned entity, and the response class almost identical). But I am OKAY with it...
For example:
The GetCustomer() in Repository.cs method is called by Service.cs
The GetCustomer() method in repository performs the LINQ query and returns a "Customer" object
Service.cs then maps all the properties of "Customer" object to the "CustomerResponse" object
Service.cs then returns the "CustomerResponse" to the caller.
In this case, most of the properties will repeat in both classes. If there is a solution to this, it's good, otherwise, I am fine with it.
However, when Repository.cs's method GetCustomers() (Notice it's not GetCustomer()) is called, it will return a list of Customer objects, and mapping this for return purposes would mean a "for loop" that iterates the collection and do the mapping... This is NOT OKAY...
Is there a better way of doing this, considering I do not want to return "Customer" object without "CustomerResponse" as first of all it violates the SOA architecture, and secondly I don't want my client projects to have any reference to the Model or Repository projects?
So is it just the mapping that you're having trouble with? If so, you could look at some open source mapping libraries like Mapper Extensions or AutoMapper that will automate the task.
If you don't like separate mapping between entities and DTOs expose IQueryable in your repository and use direct projections to DTOs. The disadvantage is that such solution can't be effectively unit tested. Mocking repository in such scenario doesn't make sense because query agains mock is Linq-to-objects whereas query against real repository is Linq-to-entities (different set of features where difference can be seen only at runtime).
Btw. I don't see too much SOA in your application - I see just multi tier application. It is like planting a tree in a garden and saying that you have a forest. Moreover it sounds like you are building CRUD interface (entities almost 1:1 to DTOs). I have a bad feeling that you are investing too big effort to architecture which you don't need. If your main intention is to build CRUD operations exposed as services on top of database you can expose entities directly moreover you can use tools like WCF Data services.
It sounds like your main point of grief is the tedious mapping of data objects to data transfer objects (DTOs). I haven't used this myself, but it seems like AutoMapper is made for doing automatic object-to-object mappings declaratively.
I would definitely stick to having your data objects separate from the data contracts in your services.

Resources