I'm trying to inject a dependency into my Silex Controller, because I need an object of type user in my controller and handle some stuff with it.
$app->mount("/users", new \MyApp\Controller\Provider\User($user));
And I implemented the controller by implementing the ControllerProviderInterface:
class User implements ControllerProviderInterface{
protected $user;
public function __construct($user){
//...
}
public function connect(Application $app)
{
//...
}
}
The routes and the methods are all set up in the controller. Without the dependency injection everything works fine. But as long as I edit the code and add the injection I get the following error:
Missing argument 1 for ...::__construct()
When I create the object, I send that parameter to it, but somehow Silex creates an instance before with a constructor without passing any argument.
Another approach is to use a ServiceController
instead of a ControllerProvider
. You can achieve a more familiar dependency injection feel this way.
$app->register(new Silex\Provider\ServiceControllerServiceProvider());
$app["user"] = function () {
return new User();
};
$app["user.controller"] = function () use ($app) {
return new UserController($app["user"]);
};
$app->get("/users/{id}", "user.controller:get");
...
class User implements UserInterface
{
// ...
}
...
class UserController
{
protected $user;
public function __construct(UserInterface $user)
{
$this->user = $user;
}
public function get(Request $request, $id)
{
$this->user;
// Do stuff
}
}
Reference: http://silex.sensiolabs.org/doc/providers/service_controller.html
Silex takes a different approach to dependency injection than you might be used to or might expect. Silex\Application
is the dependency injection container that is available in almost any context in a Silex application. You register your dependencies with the $app
and those dependencies are injected via the $app
in any context you might need it. Here is an example of something you might do in your situation.
$app["user"] = function () {
return new \MyApp\Service\User();
};
$app->mount("/users", new \MyApp\Controller\Provider\User());
...
class User implements ControllerProviderInterface
{
public function connect(Application $app)
{
$controller = $app["controller_factory"];
$controller->get("/{id}", array($this, "get"));
return $controller;
}
public function get(Application $app, Request $request, $id)
{
$user = $app["user"];
// Do stuff
}
}
Dependency injection in Silex is different and it takes a little getting used to, but once you are comfortable with it, it's a pleasure to work with and it's very efficient.
This accepted answer is not the answer to the question. And the thing described in the answer is not dependency injection either, or a realy crude form of it. Its more like Hardcoding $app into your controllers.
The code in the question should work without changes. The code in the connect function and the constructor might be helpful to figure out, where your problem sits. Its not the call to mount, im sure.