In Silex, the most common way to define the controller of a route is with a
closure. But when your project gets bigger, you want to organize your code in
classes. You can use the syntax ClassName::methodName
in your route
definition instead of a function () { ... }
but you have to inject the
Silex\Application $app
as a parameter on each method of your controller
class, which can become quite boring.
In order to avoid these repetitive injections, you need to create your own
ControllerResolver
which extends the Silex\ControllerResolver
(inspired by the one in the Symfony2 framework bundle) :
namespace MyProject\Controller;
use Silex\ControllerResolver as SilexControllerResolver;
class ControllerResolver extends SilexControllerResolver
{
/**
* Returns a callable for the given controller.
*
* @param string $controller A Controller string
*
* @return mixed A PHP callable
*/
protected function createController($controller)
{
if (false === strpos($controller, '::')) {
throw new \InvalidArgumentException(sprintf('Unable to find controller "%s".', $controller));
}
list($class, $method) = explode('::', $controller, 2);
if (!class_exists($class)) {
throw new \InvalidArgumentException(sprintf('Class "%s" does not exist.', $class));
}
$controller = new $class();
if ($controller instanceof AbstractController) {
$controller->setContainer($this->app);
}
return array($controller, $method);
}
}
The code is pretty straightforward : you create a new $class()
and if it is
an instance of AbstractController
you inject the Silex Application
.
Now the AbstractController
is easy to create :
namespace MyProject\Controller;
use Silex\Application;
abstract class AbstractController
{
/**
* @var Application;
*/
protected $app = null;
/**
* @param Application $app
*/
public function setContainer(Application $app)
{
$this->app = $app;
}
}
Finally, you replace the Silex\ControllerResolver
by your own in your
bootstrap file :
$app['resolver'] = $app->share(function () use ($app) {
return new \MyProject\ControllerResolver($app);
});
And that's all. You only have to make all your controller's class extend
AbstractController
.