Skip to content

[Dependency Injection] XmlFileLoader treats when@env differently than YamlFileLoader #58293

Closed
@CipherdevNL

Description

@CipherdevNL

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:

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions