Skip to content

[DependencyInjection] Unable to dump a service container when autowiring with enum default value #48178

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
guillaumesmo opened this issue Nov 9, 2022 · 1 comment
Labels
Bug DependencyInjection Help wanted Issues and PRs which are looking for volunteers to complete them. Status: Needs Review

Comments

@guillaumesmo
Copy link
Contributor

guillaumesmo commented Nov 9, 2022

Symfony version(s) affected

v6.2.0-BETA2

Description

When trying to autowire a service which contains an enum default value, the container build fails with the following error:

Error: Uncaught Symfony\Component\DependencyInjection\Exception\RuntimeException: Unable to dump a service container if a parameter is an object or a resource. in [...]/vendor/symfony/dependency-injection/Dumper/XmlDumper.php:417
Stack trace:
#0 [...]/vendor/symfony/dependency-injection/Dumper/XmlDumper.php(372): Symfony\Component\DependencyInjection\Dumper\XmlDumper::phpToXml(Object(class@anonymous))
#1 [...]/vendor/symfony/dependency-injection/Dumper/XmlDumper.php(160): Symfony\Component\DependencyInjection\Dumper\XmlDumper->convertParameters(Array, 'argument', Object(DOMElement))
#2 [...]/vendor/symfony/dependency-injection/Dumper/XmlDumper.php(257): Symfony\Component\DependencyInjection\Dumper\XmlDumper->addService(Object(Symfony\Component\DependencyInjection\Definition), 'test', Object(DOMElement))
#3 [...]/vendor/symfony/dependency-injection/Dumper/XmlDumper.php(50): Symfony\Component\DependencyInjection\Dumper\XmlDumper->addServices(Object(DOMElement))
#4 [...]/vendor/symfony/framework-bundle/DependencyInjection/Compiler/ContainerBuilderDebugDumpPass.php(32): Symfony\Component\DependencyInjection\Dumper\XmlDumper->dump()
#5 [...]/vendor/symfony/dependency-injection/Compiler/Compiler.php(73): Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ContainerBuilderDebugDumpPass->process(Object(Symfony\Component\DependencyInjection\ContainerBuilder))
#6 [...]/vendor/symfony/dependency-injection/ContainerBuilder.php(721): Symfony\Component\DependencyInjection\Compiler\Compiler->compile(Object(Symfony\Component\DependencyInjection\ContainerBuilder))
#7 [...]/vendor/symfony/http-kernel/Kernel.php(487): Symfony\Component\DependencyInjection\ContainerBuilder->compile()
#8 [...]/vendor/symfony/http-kernel/Kernel.php(709): Symfony\Component\HttpKernel\Kernel->initializeContainer()
#9 [...]/vendor/symfony/http-kernel/Kernel.php(172): Symfony\Component\HttpKernel\Kernel->preBoot()
#10 [...]/vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php(35): Symfony\Component\HttpKernel\Kernel->handle(Object(Symfony\Component\HttpFoundation\Request))
#11 [...]/vendor/autoload_runtime.php(29): Symfony\Component\Runtime\Runner\Symfony\HttpKernelRunner->run()
#12 [...]/public/index.php(5): require_once('[...]/vendo...')
#13 {main}
thrown

How to reproduce

services:
    _defaults:
        autowire: true
        autoconfigure: true

    test:
        class: App\Service\TestService
        arguments:
            $bubble: false
<?php

namespace App\Service;

use Monolog\Level;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface;

class TestService
{
    public function __construct(
        ParameterBagInterface $parameterBag,
        int|string|Level $level = Level::Debug,
        bool $test = true,
        bool $bubble = true
    ) {
    }
}

once you change $level = Level::Debug to $level = 100, the error disappear and the container build is successful

also interesting is that removing the bool $test = true, also compiles without error, so it's more complex than just "enum default values do not work"

Possible Solution

No response

Additional Context

I experience this issue when trying to migrate a logging handler from monolog v2 to v3, where the best practice is to express default levels with enums.

workaround is to add the default value in the arguments as well:

    test:
        class: App\Service\TestService
        arguments:
            $level: 100 # or !php/enum Monolog\Level:Debug
            $bubble: false
@rumman23
Copy link

rumman23 commented Apr 27, 2023

Hi, I have same issue with autowired classes. The exception is thrown in XmlDumper even for classes that will be removed at the end, because they are not injected in any service. In our situation this error occurs if an enum parameter is followed by a native php type and non native class:

    public function __construct( // fails
        private TestEnum $testEnum = TestEnum::A,
        ?string $scalar = null,
        ?Dto $dto = null,
    )
        
    public function __construct( // ok
        ?Dto $dto = null,
        private TestEnum $testEnum = TestEnum::A,
        ?string $scalar = null,
    )
    
    public function __construct( // ok
        private TestEnum $testEnum = TestEnum::A,
        ?Dto $dto = null,
        ?string $scalar = null,
    )

Main cause is probably in AutowirePass::autowireMethod call that assigns defaultArgument property with anonymous class to scalar arguments. AutowirePass object subsequently creates following constructor arguments definition:

array:2 [
  1 => class@anonymous^ {#1469
    +value: null
    +names: ArrayObject {#1472
      -storage: array:3 [
        0 => "enm"
        1 => "scalar"
        2 => "dto"
      ]
      flag::STD_PROP_LIST: false
      flag::ARRAY_AS_PROPS: false
      iteratorClass: "ArrayIterator"
    }
  }
  "dto" => Symfony\Component\DependencyInjection\TypedReference^ {#1479
    -id: "App\Dto"
    -invalidBehavior: 1
    -type: "App\Dto"
    -name: null
    -attributes: []
  }
]

@nicolas-grekas nicolas-grekas added the Help wanted Issues and PRs which are looking for volunteers to complete them. label Apr 27, 2023
nicolas-grekas added a commit that referenced this issue Aug 14, 2023
…default value (Jean-Beru)

This PR was squashed before being merged into the 5.4 branch.

Discussion
----------

[DependencyInjection] fix dump xml with array/object/enum default value

| Q             | A
| ------------- | ---
| Branch?       | 5.4
| Bug fix?      | yes
| New feature?  | no
| Deprecations? | no
| Tickets       | Fix #48178
| License       | MIT
| Doc PR        |

This PR fixes #48178 when attempting to dump the container in these conditions:
* The constructor has in its arguments a non-empty array, an object or an enum with a default value
* A second argument is placed after
* A third argument is placed after and is using configuration

Example (might be more explicit):
```php
class Foo
{
    public function __construct(
        array $array = ['a', 'b', 'c'],
        bool $firstOptional = false,
        bool $secondOptional = false
    ) {}
}
```

```yaml
services:
    Foo:
        arguments:
            secondOptional: true
```

:warning: This PR might cause Git conflicts in 6.3 and 6.4 versions. Do I have to create a dedicated PR for these versions ?

Commits
-------

ddc699a [DependencyInjection] fix dump xml with array/object/enum default value
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug DependencyInjection Help wanted Issues and PRs which are looking for volunteers to complete them. Status: Needs Review
Projects
None yet
Development

No branches or pull requests

4 participants