Symfony without Request

Nicolas Moral
4 min readMay 1, 2022

--

Using Symfony controller without Request, is like riding a bike : it seems complicated at first, in the end it couldn’t be easier

Image représentant du code source

A few days ago, I read the article by Sebastian Bergmann and Stefan Priebsch entitled “Do not mock what you do not own”, an article that you should read. While reading it, I wondered : “Why do you still use Symfony Request ? What if we stop using it and control the data we use ?” This is an implementation of Sebastian Bergmann’s and Stefan Priebsh’s idea in Symfony.

State of play

The Symfony request object allows us to do a lot of things. I think most developers, including me, use it directly in their actions. Then the controller gradually becomes the border between the framework and the business. We are tempted to inject native classes of the framework as well as business services. This border area is getting very hard to test and we have to mock object that we do not own. We often end up booting the kernel in the unit tests, which makes them extremely long.

Here we found a common example found in many applications. Two of the five services are native to the framework and the use of header and request properties is making it very complicated to mock this object. This will contravene to “Do not mock what you do not own”

Create your own request:

Let’s assume that this JSON is our HTTP request body. We can split it in different sections which are at the same time a potential request and part of another request. This split allows a better reuse and harmonisation of code.

Json part explained

Let’s now see the implementation. And as code is worth better than a long speech :

I simplified the code for the example because the request does not always exist depending on the context. This code can and should be refactored to remove duplication but for our example let’s keep it as simple as possible.

MyActionRequest source code

Object : the reference

The creation of an intermediate object allowing us to iterate on our collection is interesting. In PHP, all objects are passed by reference while arrays are not. It is possible to use the “&” symbol so that the arrays are passed by reference, but this unnecessarily complicates the code.

The control of the collection also opens on other interesting optimizations such as the use of a very efficient “SplFixedArray” in reading on large volumes of data.

CheckpointCollectionRequest source code

Multiple Request: Factory !

In our example, the CheckpointRequests can be multiple. For this, it is necessary to set up a factory. Directly injecting a CheckpointRequest object would allow us to have only one Request when we potentially want several of them. The factory solves this problem.

CheckpointRequestFactory source code
ChecpointRequest source code

Use and mock the request :

Now that we have our request, we can inject it into our controller. I am personally a fan of flushing once and at the last moment. Here we can reverse the notification with the flush, which allows in case of failure of the flush, to have an operation which did not modify the database and did not notify the user.

Controller source code

In this new version of the action, it becomes very simple to mock our request and test our controller. Our business code is fully cut from the framework. Indeed, all the services injected into our controller are services that we own. The controller is no longer the place where the separation between the framework and the business code is made, but a controller that manages a request, directs it to the right services and ensures a consistent response.

UnitTest source code

Disclaimer :

If you’ve made it this far, thanks for reading. This is my very first article ever. If I am convinced of the content, I am much less so of the form. But one day you have to get started and share your ideas at the risk of being confronted with your mistakes.

--

--