Silex, el manual oficial

A.9. ServiceControllerServiceProvider

Si tu aplicación Silex crece mucho, es posible que quieras organizar tus controladores de una manera más formal. Silex soporta la definición de controladores como métodos de clases PHP, pero con un poco más de trabajo, puedes convertir tus controladores en servicios, lo que te permite aprovechar todo el potencial de la inyección de dependencias.

Las dos principales ventajas de definir los controladores como servicios son las siguientes:

  1. Inyección de dependencias en vez búsqueda de servicios. Si utilizas este método puedes inyectar directamente las dependencias que necesitan tus controladores, por lo que puedes aprovechar al máximo las ventajas del patrón de diseño "inversion of control". Además, como las dependencias están claramente definidas, puedes crear mocks fácilmente y por tanto, los tests funcionales se simplifican.

  2. Independencia respecto al framework. Siguiendo esta filosofía puedes independizar tus controladores respecto a Silex. De hecho, si eres un poco cuidadoso puedes hacer que tus controladores se puedan utilizar con varios frameworks diferentes. Controla cuidadosamente las dependencias y así tus controladores serán compatibles por ejemplo con Silex, Symfony y con Drupal.

A.9.1. Parámetros de configuración

Este proveedor no define ningún parámetro de configuración.

A.9.2. Servicios proporcionados

Este proveedor no proporciona ningún servicio propio.

A.9.3. Cómo se registra el proveedor

El siguiente código muestra un ejemplo de cómo registrar este proveedor:

$app->register(new Silex\Provider\ServiceControllerServiceProvider());

A.9.4. Ejemplos de uso

A continuación se presenta un ejemplo sencillo de una API para un blog. En concreto, se va a modificar la ruta /posts.json para que utilice un controlador definido como un servicio.

use Silex\Application;
use Demo\Repository\PostRepository;

$app = new Application();

$app['posts.repository'] = $app->share(function() {
    return new PostRepository;
});

$app->get('/posts.json', function() use ($app) {
    return $app->json($app['posts.repository']->findAll());
});

Reescribir este controlador como servicio es muy sencillo, ya que sólo hay que crear un objeto PHP simple que contenga una dependencia con la clase PostRepository y un método llamado indexJsonAction que sea capaz de procesar la petición. Aunqe no se muestra en el código del ejemplo anterior, puedes utilizar el truco de indicar la clase delante del parámetro (lo que se conoce como type hinting) tal y como harías en cualquier otra ruta normal de Silex.

Si además sigues la filosofía TDD o BDD, habrás notado que este controladores bastante fácil de testear porque sus responsabilidades y sus dependencias están muy bien definidas. También te habrás dado cuenta de que su única dependencia externa es sobre la clase JsonResponse de Symfony, lo que significa que este controlador se puede utilizar fácilmente tanto en Silex como en Symfony.

namespace Demo\Controller;

use Demo\Repository\PostRepository;
use Symfony\Component\HttpFoundation\JsonResponse;

class PostController
{
    protected $repo;

    public function __construct(PostRepository $repo)
    {
        $this->repo = $repo;
    }

    public function indexJsonAction()
    {
        return new JsonResponse($this->repo->findAll());
    }
}

Por último, define el controlador como un servicio de la aplicación y utilízalo en alguna ruta. La sintaxis que se utiliza en las rutas consiste en indicar el nombre del servicio seguido del nombre del método y separados por dos puntos (:), tal y como se muestra en el siguiente ejemplo:

$app['posts.controller'] = $app->share(function() use ($app) {
    return new PostController($app['posts.repository']);
});

$app->get('/posts.json', "posts.controller:indexJsonAction");