Description
Symfony version(s) affected
5.4.43
Description
Inside the development environment we want to replace specific services with logbook variant to prevent accidentally calling remote api's. For the service configuration we mainly use the XML format, in which we tried the following:
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="Vendor\RemoteApiCaller" alias="Vendor\LogbookRemoteApiCaller"/>
<service id="Vendor\HttpRemoteApiCaller" class="Vendor\HttpRemoteApiCaller"/>
<service id="Vendor\LogbookRemoteApiCaller" class="Vendor\LogbookRemoteApiCaller"/>
</services>
<when env="prod">
<services>
<service id="Vendor\RemoteApiCaller" alias="Vendor\HttpRemoteApiCaller"/>
</services>
</when>
</container>
But we discovered that the Dependency Injection still want's to use the HttpRemoteApiCaller
for non-prod environments which isn't expected.
After some additional debugging we discovered that the XmlFileLoader::class
doesn't ignore the <services />
elements that are part of the <when env="..." />
element. Resulting in applying all service definition in order, and thus overwriting the defined value in the base <services />
element.
To make sure this isn't expected behaviour i've rewrote the same service config in Yaml to see what happens inside the YamlFileLoader::class
. And as expected this loader only load the services defined in the when@prod:
statement when the application environment is set to it.
services:
Vendor\RemoteApiCaller:
alias: Vendor\LogbookRemoteApiCaller
Vendor\LogbookRemoteApiCaller:
class: Vendor\LogbookRemoteApiCaller
Vendor\HttpRemoteApiCaller:
class: Vendor\HttpRemoteApiCaller
when@prod:
services:
Vendor\RemoteApiCaller:
alias: Vendor\HttpRemoteApiCaller
I'm not that familiar with xPath but it seems like the query used here https://github.com/symfony/dependency-injection/blob/7.1/Loader/XmlFileLoader.php#L137 isn't excluding elements that are inside a <when />
element. Which also happens when passing it along inside http://xpather.com/ .
How to reproduce
See https://github.com/CipherdevNL/di-symfony-xml-yaml with an example, run the bug.php
script with php bug.php
to see the difference in processing.
Possible Solution
Make the xpath check more stricter to ignore the when statements. Haven't tested it with the latest Symfony 7.1 but based on the code diff I don't see any changes in the XmlFileLoader that resolves this issue.
When fixing this we should handle it as a BC as this inconsistency is already present in SF 5.4. So projects can (unintentionally) depend on this behaviour for their XML configs.
Additional Context
Output of the bug.php
:
[XML] Expects 'logbook' got 'http'
[YAML] Expects 'logbook' got 'logbook'
[ALL] Different file loaders don't have the same result D: