Symfony Controller not extending FOSRest Bundle
Symfony Controller Best Practice by not extending a Base Controller but injecting dependencies
26 Sep 2015 by Eddie JaoudeMost examples of a Symfony Controller extend FOSRestController
. This is not ideal, it is better to have Controllers as a Service, just like any other Service. This is much easier to Unit Test with tools like PHPUnit and PHPSpec and then forces the Controllers to do less and have less dependencies - we all like Thin Controllers.
Below is a standard example of a Controller.
<?php
namespace Your\Namespace\Controller
use FOS\RestBundle\Controller\FOSRestController;
class UsersController extends FOSRestController
{
public function getUsersAction()
{
$data = ...; // get data, in this case list of users.
return $this->handleView(
$this->view($data, 200)
);
}
}
To run it as a Service is quite easy and Decouples it from Symfony FOSRest Bundle, which will look like below.
<?php
namespace Your\Namespace\Controller
class UsersController
{
/** @var Controller */
private $controller;
/**
* @param Controller $controller
*/
public function __construct(ControllerInterface $controller)
{
$this->controller = $controller;
}
public function getUsersAction()
{
$data = ...; // get data, in this case list of users.
return $this->controller->handleView(
$this->controller->view($data, 200)
);
}
}
I introduced a new class here called Controller, this will proxy through to the Symfony FOSRestController - it too will have Unit Tests.
<?php
namespace Your\Namespace\Controller
use FOS\RestBundle\View\View;
use FOS\RestBundle\View\ViewHandler;
/**
* Class Controller
*/
class Controller implements ControllerInterface
{
/** @var ViewHandler */
private $viewHandler;
/** @var View */
private $view;
/**
* @param ViewHandler $viewHandler
* @param View $view
*/
public function __construct(ViewHandler $viewHandler, View $view)
{
$this->viewHandler = $viewHandler;
$this->view = $view;
}
/**
* @param View $view
*
* @return \Symfony\Component\HttpFoundation\Response
*/
public function handle(View $view)
{
return $this->viewHandler
->handle($view);
}
/**
* @param array $data
* @return View
*/
public function setData(array $data)
{
return $this->view
->setData($data);
}
}
The services.yml
will look something like this:
services:
your_app.fos_rest.view.view:
class: FOS\RestBundle\View\View
factory: [FOS\RestBundle\View\View, create]
your_app.controller:
class: Your\Namespace\Controller\Controller
arguments: [@fos_rest.view_handler, @your_app.fos_rest.view.view]
your_app.controller.users:
class: Your\Namespace\Controller\UsersController
arguments: [@your_app.controller]
The routing.yml
will be like so:
your_app_users:
type: rest
resource: your_app.controller.users
I hope that helps. Feedback welcome.
Update: Controller Interface added.