Skip to content

[DependencyInjection] Enums doesn't works when they are binded #44834

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
ismail1432 opened this issue Dec 29, 2021 · 2 comments
Closed

[DependencyInjection] Enums doesn't works when they are binded #44834

ismail1432 opened this issue Dec 29, 2021 · 2 comments

Comments

@ismail1432
Copy link
Contributor

ismail1432 commented Dec 29, 2021

Symfony version(s) affected

Any version from 4.4 and PHP 8.1

Description

Use syntax !php/const with an enum as parameter doesn't work properly when you want to bind the parameter.

How to reproduce

<?php
namespace App;

enum Status: string {
    case Draft =  'draft';
    case Deleted =  'deleted';
    case Published = 'published';
}
# services.yaml
parameters:
    my_param: !php/const App\Status::Deleted
services:
    _defaults:
        autowire: true     
        autoconfigure: true
        bind:
            $myParam: '%my_param%'
dd($container->getParameter('my_param')); // is OK output the enum

but

    /**
     * @Route("/foo", name="foo")
     */
    public function index(EntityManagerInterface $entityManager, $myParam): Response

output
image

Possible Solution

No response

Additional Context

No response

@ismail1432 ismail1432 added the Bug label Dec 29, 2021
@ismail1432 ismail1432 changed the title Enums doesn't works when they are binded [DependencyInjection] Enums doesn't works when they are binded Dec 29, 2021
@ogizanagi
Copy link
Contributor

Actually enums are not supported properly in the DI parameters (yet?), while being supported in injection:

# services.yaml
services:
    _defaults:
        autowire: true     
        autoconfigure: true
        bind:
            $myParam: !php/const App\Status::Deleted

works, right?

Moreover, the ParameterBagInterface is not allowing objects, so won't accept enums:

public function get(string $name): array|bool|string|int|float|null;

public function set(string $name, array|bool|string|int|float|null $value);

@ogizanagi
Copy link
Contributor

However the following fails:

# services.yaml
services:
    _defaults:
        autowire: true     
        autoconfigure: true
        bind:
-            $myParam: !php/const App\Status::Deleted
+            App\Status $myParam: !php/const App\Status::Deleted

->

Invalid value for binding key "App\Status $myParam" for service […]: expected "Symfony\Component\DependencyInjection\Reference", "Symfony\Component\DependencyInjection\Definition", "Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument", "Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument" or null, "App\Status" given.

I tried #44838 on a 5.4 app with success.

Perhaps you could confirm this patch is working as well on 4.4 @ismail1432? 🙏🏻 (appart from the intermediate parameter which is the root of this issue)

nicolas-grekas added a commit that referenced this issue Dec 29, 2021
…(ogizanagi)

This PR was merged into the 4.4 branch.

Discussion
----------

[DependencyInjection][HttpKernel] Fix enum typed bindings

| Q             | A
| ------------- | ---
| Branch?       | 4.4 <!-- see below -->
| Bug fix?      | yes
| New feature?  | no <!-- please update src/**/CHANGELOG.md files -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tickets       | N/A <!-- prefix each issue number with "Fix #", no need to create an issue if none exist, explain below instead -->
| License       | MIT
| Doc PR        | symfony/symfony-docs#... <!-- required for new features -->

Relates to #44834

While:

```yml
# services.yaml
services:
    _defaults:
        autowire: true
        autoconfigure: true
        bind:
            $myParam: !php/const App\Status::Deleted
```

is working for me, the following isn't:

```diff
# services.yaml
services:
    _defaults:
        autowire: true
        autoconfigure: true
        bind:
-            $myParam: !php/const App\Status::Deleted
+            App\Status $myParam: !php/const App\Status::Deleted
```

->

> Invalid value for binding key "App\Status $myParam" for service […]: expected "Symfony\Component\DependencyInjection\Reference", "Symfony\Component\DependencyInjection\Definition", "Symfony\Component\DependencyInjection\Argument\TaggedIteratorArgument", "Symfony\Component\DependencyInjection\Argument\ServiceLocatorArgument" or null, "App\Status" given.

This attempts to fix it by accounting for `\UnitEnum` in the `ResolveBindingPass`,
as well as re-allowing enum types already present in bindings after #44826.

Commits
-------

c32d749 [DependencyInjection][HttpKernel] Fix enum typed bindings
nicolas-grekas added a commit that referenced this issue Feb 4, 2022
…num as parameters (ogizanagi)

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

Discussion
----------

[DependencyInjection][FrameworkBundle] Fix using PHP 8.1 enum as parameters

| Q             | A
| ------------- | ---
| Branch?       | 4.4 <!-- see below -->
| Bug fix?      | yesish
| New feature?  | no <!-- please update src/**/CHANGELOG.md files -->
| Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files -->
| Tickets       | Fix #44834  <!-- prefix each issue number with "Fix #", no need to create an issue if none exist, explain below instead -->
| License       | MIT
| Doc PR        | N/A

While #40857 allowed using enums in DI, it does not allow using these in parameters.

This would be the actual fix for #44834, which shows the error you'll get trying to use enum as DI parameters (appart from the binding issue fixed in #44838):

![image](https://user-images.githubusercontent.com/2211145/147762495-f57f1fff-f56a-4e87-bbc4-3bba97a8e81b.png)

given:

```php
namespace App;

enum Status {
    case Draft;
    case Deleted;
    case Published;
}
```

```yaml
# services.yaml
parameters:
    default_status: !php/const App\Status::Draft
```

The exception happens because the `PhpDumper` misses the leading slash:

```diff

    protected function getDefaultParameters(): array
    {
        return [
-            'default_status' => App\Status::Draft,
+            'default_status' => \App\Status::Draft,
        ];
    }
```

While this would fix using enums as DI parameters as of Symfony < 6,
the `ParameterBagInterface::get/set` and `ContainerInterface::setParameter/getParameter` are not allowing `\UnitEnum` and adding these in phpdoc is an issue since actual typehints and return types were added as of Symfony 6.
=> So this PR is a BC break, but hopefully nobody will be hit by it 🤞🏻

(poke `@ismail1432` -
https://twitter.com/SmaineDev/status/1476237072826613763?s=20)

Commits
-------

ac36617 [DependencyInjection][FrameworkBundle] Fix using PHP 8.1 enum as parameters
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants