Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 361
Petr Avatar asked Nov 10 '12 08:11

Petr


2 Answers

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.

like image 199
Wouter J Avatar answered Oct 23 '22 15:10

Wouter J


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.

like image 38
Dave Marshall Avatar answered Oct 23 '22 15:10

Dave Marshall