I'm moving my old codebase to the Symfony 2.2 framework.
In my old code, my Article entity has had a method getUrl(), which was returning a URL for current article.
In Symfony i have to use Router service to generate such an URLs.
I can't access Router from inside the Entity, cause it's a bad practice and not really supported by the framework.
I can call the router from the Twig template itself using Twig helper path() and provide all the arguments (from the Article instance) needed to construct the URL. But this approach is not very good, cause if i'll decide to change URL formatting rules - i will have to find all this calls and rewrite them (not very DRY).
I really want to save the business-logic encapsulation here and not to pull all the guts to the view layer.
How should i proceed in this situation?
Create an ArticleManager class in your service layer, and handle any business logic there. You can pass the router to it through dependency injection.
For your example, ArticleManager would have a getUrl(Article $article) method which would use the router instance (that you either injected through __construct or a separate setter method) to generate the Url based on properties of $article, and return it.
This method will ensure that your business logic doesn't pollute the view or controller layers.
Be sure to read up on the Service Container docs.
Related
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.
I have a small app (Win Forms) where I have two different repositories (SQL Server and Redis) both implementing a interface IFilterRepo.
I also have a service class that depends on the IFilterRepo. The client (the Win Form) call the service to access filter data.
I want the client to have two radio buttons where a user can choose which repo to use. And here comes my dilemma. How should I tell the service which concrete class to instantiate as IFilterRepo? I mean, ALL Unity registrations and references to it shall be done in the composition root. Is that "rule" really possible in this case?
This is a common question, and the answer is generally to use an Abstract Factory.
Here is a good article on the subject (I link this all the time, but I didn't write it):
http://blog.ploeh.dk/2012/03/15/ImplementinganAbstractFactory/
As noted in the article, you can make the factory part of the composition root, so that calling container.Resolve() inside the factory doesn't violate that rule.
Edit
You would register different implementations of the service using a name (string):
http://msdn.microsoft.com/en-us/library/ff648211.aspx
myContainer.RegisterType<IMyService, CustomerService>("Customers");
And then your factory would resolve by that name:
public IFilterRepo Create(string myName)
{
return myContainer.Resolve<IFilterRepo>(myName);
}
Edit 2
The question you asked in your last comment is a bit much to answer here, but in brief: your factory itself would implement an interface, and would be resolved and registered via the container.
As a general matter, I would not recommend accessing a repository directly from the code behind--I would at least look at having a layered architecture (or better, an Onion architecture, which works very well with DI).
Finally, I have not done WinForms development in years, but I don't think it fits perfectly with using a container/Composition Root, since you don't have full control over the lifecycle of your objects (you can't inject services into your form constructors). The same is true of ASP.Net Webforms. So you may have to use property injection for your factory and other services needed in your form, or just resolve the factory directly via calling a static instance of the container (container.Resolve()). This is imperfect, and goes against the idea of having a Composition Root, and more toward service location.
You might google keywords "Unity WinForms" and/or "[OtherDIFramework] Winforms" to get some ideas of how to structure your code.
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.
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.
I have a solution with several projects (MyApp.Data, MyApp.BLL, MyApp.Web). I register types in Global.asax file in MyApp.Web (main web application):
builder.RegisterType<SomeService1>().As<ISomeService1>().InstancePerHttpRequest();
builder.RegisterType<SomeService2>().As<ISomeService2>().InstancePerHttpRequest();
//...etc
And I wonder whether it's a bad practice to register types and their scope using attributes in the other assemblies (for example, in MyApp.BLL). See below:
[Dependency(typeof(ISomeService1), ComponentLifeStyle.Transient)]
public class SomeService1 : ISomeService1
{
//methods and properties go here
}
Using local attributes or other ways to indicate wiring for a DI Container tightly couples the service to the DI Container, so I don't think that's a good idea.
Additionally, it may constrain your future options. If, for example, you specify the lifestyle scope, you can't reuse the service with a different scope.
In general, you should compose the application in a Composition Root (global.asax), which gives you a single location with a clearly defined responsibility where all classes are composed.
That would be much more manageable and maintainable that spreading the configuration data all over your classes.
As your question implies, it makes some sense to delegate responsibility for registration to the assembly that knows what needs to be registered. For example, if you
use the SolrNet library, it provides a method that performs component registration, to encapsulate the knowledge of what needs to be registered and to spare the library's consumer from having to learn all about the library before getting started.
However, there is a potential issue with this approach. Would your registration requirements change if you used the dependent assemblies in other applications? For example, would it make sense to register something as ComponentLifeStyle.HttpRequestScoped and then use it in a non-Web application? By delegating registration to the dependency, you are coupling the dependency to its consumer's registration requirements (and to its choice of IoC container).
Autofac (I can't speak for other IoC containers) provides a way round this. It enables you to override registrations so that the most recently registered component is used when a service is resolved. This means that you can call a library's registration method and then register your own services to override the defaults.
There is another problem with your proposed attribute-based registration - it doesn't enable you to specify a lambda expression as a component creator. How would you implement a registration like this with attributes?
builder.Register(c => new A(c.Resolve<B>()));
It might be preferable to define an IRegistrar interface, and then use reflection to search all loaded assemblies for implementations and invoke them. Perhaps something like this:
public interface IRegistrar
{
void RegisterComponents();
}