Remove all services arguments from Symfony config with a script

| 2 min read

I'm helping a team migrate from Symfony 3.4 to a newer version of the framework. One of our objectives is to move away from using the container to get access to services and use dependency injection instead. Our first step was enabling auto wiring, which should simplify the rest of the work because the framework will automagically inject every new service we add to the constructor directly into the service—no need to edit any configuration.

The next step we plan is to use Rector to transform every call to Container::get to dependency injection.

Rector will save us tremendous time by refactoring the code but will not touch the configuration. In the configuration, when a service definition declares the service arguments, it takes precedence over the auto wiring. We need to clean all the configuration files by removing the arguments declaration.

I decided to see if I could use awk to script that and avoid the manual work requested on many different config files, and I managed to do so in less time than expected. Practicing some awk katas was worth it, after all.

Here is the script. It looks for arguments: and sets a variable indicating that we are in an argument block. Once in that block, we look for the first line not starting with - to say we are out of the argument block. The script prints every line outside arguments blocks, when ARGUMENT_BLOCK == 0.

ARGUMENT_BLOCK == 1 && !/[[:blank:]]*-/ {  
/arguments:/ {  
ARGUMENT_BLOCK == 0 {print $0}

Here is an example of a diff once the script was used on a services.yaml file. Note that the script deals with the single and multiline YAML array format.

@@ -2,29 +2,12 @@
         class: XXX\ListsRepository
         factory: [ '@doctrine.orm.default_entity_manager', 'getRepository' ]
-        arguments:
-            - 'SDKListBundle:Lists'
         class: XXX\ListBundle\Services\Lists
-        arguments:
-            - '@service_container'
-            - '@event_dispatcher'
-            - '@sdk.entity.list'
         class: XXX\Repository\ListAccessSetRepository
         factory: [ '@doctrine.orm.default_entity_manager', 'getRepository' ]
-        arguments: ['SDKListBundle:ListAccessSet']
           class: XXX\Services\ListAccessSet
-          arguments:
-              - '@sdk.entity.list_access_set'
-              - '@sdk.entity.mapping_list_access_set'
-              - '@logger'
\ No newline at end of file

To run the script on a single file you can use awk -i inplace -f script file.

And if you have a lot of services.yaml files to edit at once, you can use a combination of find, xargs and awk:
find ./src -name services.yml | xargs awk -i inplace -f script.

That step is now automated; we don't need to edit hundreds or more service definitions manually. A few minutes of work and a lot of time saved.

Do you speak French and want to stop hating your tests ?

I've created a course to help developers to improve their automated tests.

I share ideas and technics to improve slow, flaky, failing for unexpected reason and hard to understand tests until they become tests we take joy to work with !

But you'll need to understand French...