Reputation: 305
How do I inject dependency in some of the object methods instead of the constructor?
The example below works fine for __constructor injection
How do I inject the DateTime object in indexAction?
app.php
$app['index.controller'] = $app->share(function() use ($app) {
return new Controllers\IndexController(new \DateTime());
});
IndexController.php
namespace Moo\Controllers;
class IndexController
{
private $date;
public function __construct(\DateTime $date)
{
$this->date = $date;
}
public function indexAction()
{
return $this->date->format('y-m-d');
}
}
Upvotes: 2
Views: 291
Reputation: 3590
Just for the record, as you won't probably want to do this, its is, indeed, possible to do method injection in Silex (in fact it is the Pimple container the one responsible to do it) by using the extend method:
<?php
$app['some_service'] = $app->share(function() use ($app) {
return SomeClass($app['some_dependency']);
});
$app['some_service'] = $app->extend('some_service', function($instance, $app) {
$instance->setSomeDependency($app['another_dependency']);
return $instance;
});
Having said that you should take into account what @JakubZalas is explaining as you will not want to call your controller action inside the extend method (you want to be called by the dispatcher).
Upvotes: 1
Reputation: 36201
If your class has different dependencies depending on which method is called, than these methods should probably be defined in separate classes.
In case of controllers I think the rules are simple. Dependencies your action methods need should be passed via the constructor. Anything coming with a request should come as a method argument.
I'm not sure what kind of dependencies you're trying to inject. If they're just services, than you should split your controller to multiple classes. Big number of constructor arguments is a code smell. It's good you're concerned by it, but you're trying to solve it in a wrong way.
If the dependency is coming with a request, you should inject it into your controller method (action). A controller method should accept a request and return a response.
All route placeholders are automatically registered as a Request attribute. So if your date comes from a request:
$app->get('/my/path/{date}', 'index.controller:indexAction');
It will be available as a request attribute:
public function indexAction(Request $request)
{
$request->attributes->get('date');
}
Any request attributes can be directly injected into the controller:
public function indexAction($date)
{
}
This also means, that if you manually set a request attribute, it will be possible to inject it to your controller. It's matched by name:
// somewhere in your code (event perhaps)
$request->attributes->set('myDate', new \DateTime());
// in your controller
public function indexAction(\DateTime $myDate)
{
}
Finally you can convert simple types coming with the request, to more complex ones with route variable converters.
$callback = function ($post, Request $request) {
return new Post($request->attributes->get('slug'));
};
$app->get('/blog/{id}/{slug}', 'your.controller:indexAction')
->convert('post', $callback);
Read the docs for more.
Upvotes: 2