Going far, then Too Far with the ViewResponseListener [FOSRESTBundle]
This next step is optional, but I like how it cuts down my controller method code even further. We're going to enable and configure the ViewResponseListener
. This will allow us to simply return a View
instance from our controller methods:
// current implementation
public function postAction(
Request $request
) {
// ... etc
return $this->handleView(
$this->view(
[
'status' => 'ok',
],
);
);
}
Can simplify to:
// current implementation
public function postAction(
Request $request
) {
// ... etc
return $this->view(
[
'status' => 'ok',
],
);
}
In order for this to work, we need composer require sensio/framework-extra-bundle
.
Please note that in the Symfony 4 API with FOSRESTBundle the SensioFrameworkExtraBundle was listed as an optional dependency. It is mandatory if you want this feature.
Let's enable the view_response_listener
:
# config/packages/fos_rest.yaml
fos_rest:
routing_loader:
include_format: true
format_listener:
rules:
- { path: ^/, prefer_extension: true, fallback_format: json, priorities: [ xml, json ] }
view:
view_response_listener:
enabled: true
And that's it. We can now just return either calls to $this->view(...)
, or new View(...)
objects directly.
You can take this one step further. It is possible to simply return data:
# config/packages/fos_rest.yaml
fos_rest:
routing_loader:
include_format: true
format_listener:
rules:
- { path: ^/, prefer_extension: true, fallback_format: json, priorities: [ xml, json ] }
view:
view_response_listener:
enabled: true
+ force: true
Which allows you to e.g:
// current implementation
public function postAction(
Request $request
) {
// ... etc
return [
'status' => 'ok',
];
}
Or more interestingly:
// current implementation
public function postAction(
Request $request
) {
// ... etc
if (false === $form->isValid()) {
return $form;
}
}
I used to do this a lot.
The reason I now prefer the $this->view(...)
approach is that the view
method call takes optional second and third arguments:
/**
* Creates a view.
*
* Convenience method to allow for a fluent interface.
*
* @param mixed $data
* @param int $statusCode
* @param array $headers
*
* @return View
*/
protected function view($data = null, $statusCode = null, array $headers = [])
{
return View::create($data, $statusCode, $headers);
}
Simply put, it makes it easier to set the status code for a given request.
If we returned a $form
when our form submission failed, and a new JsonResponse
if everything went to plan, then we're returning two different types. For me, this feels weird, and is not a practice that has served me well over the years. Returning a single type - a View
- standardises this, and leads to code that's easier to reason about.
Now admittedly on this last issue is moot point, as nothing should be directly consuming our controller methods. We return JSON. Our front end consumers work with that JSON. They would never directly call the postAction
. But generally, as far as programming practices go, this approach of returning a single type is something I prefer, if at all possible.