Skip to content
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

Custom generator as a service produces PHPStan error #297

Open
javaDeveloperKid opened this issue Mar 5, 2022 · 8 comments
Open

Custom generator as a service produces PHPStan error #297

javaDeveloperKid opened this issue Mar 5, 2022 · 8 comments

Comments

@javaDeveloperKid
Copy link

javaDeveloperKid commented Mar 5, 2022

Since Doctrine Bundle 2.3 we can pass a service id to the CustomIdGenerator annotation. However this causes Internal error: Internal error: Can't instantiate custom generator : app.doctrine.user_id_generator in file /app/src/Entity/User.php.

BTW. Can this even be fixed? It would require phpstan/phpstan-doctrine to have access to the Symfony's DI container.

@ondrejmirtes
Copy link
Member

we can pass a service id to the CustomIdGenerator annotation

How does an annotation like that look like? I need something to reproduce that.

Also you might solve that by providing objectManagerLoader: https://github.com/phpstan/phpstan-doctrine#configuration

@javaDeveloperKid
Copy link
Author

javaDeveloperKid commented Mar 6, 2022

* @ORM\CustomIdGenerator("<service_id_here>")
https://www.doctrine-project.org/projects/doctrine-bundle/en/2.4/custom-id-generators.html

Will take a look at this objectManagerLoader feature.

@NMe84
Copy link

NMe84 commented Aug 11, 2022

I just ran into the same issue, but there seems to be a solution that is cleaner anyway.

This will trigger the error:
#[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]

...and this will not:

use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
[...]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]

@ondrejmirtes
Copy link
Member

objectManagerLoader (see README) will AFAIK solve it.

@javaDeveloperKid
Copy link
Author

javaDeveloperKid commented Aug 11, 2022

@NMe84 it works because UuidGenerator::class is a service id as well as a FQCN. You can do new $fqcn() but you can't do new 'doctrine.uuid_generator' as such class does nor exist. What's more, the former won't work also when a constructor has non-optional patameter.
That's why doctrine bundle integrates with Symfony container but PHPStan does not understand that out of the box and some configuration is required.

@NMe84
Copy link

NMe84 commented Aug 11, 2022

I know, I'm just pointing out that this would be a solution and, let's be honest, much cleaner code than using magic strings.

@kkevindev
Copy link

I just ran into the same issue, but there seems to be a solution that is cleaner anyway.

This will trigger the error: #[ORM\CustomIdGenerator(class: 'doctrine.uuid_generator')]

...and this will not:

use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;
[...]
#[ORM\CustomIdGenerator(class: UuidGenerator::class)]

Thanks this worked!

use Symfony\Component\Uid\Uuid;
use Symfony\Bridge\Doctrine\IdGenerator\UuidGenerator;

    /**
     * @ORM\Id
     * @ORM\Column(type="uuid", unique=true)
     * @ORM\GeneratedValue(strategy="CUSTOM")
     * @ORM\CustomIdGenerator(class=UuidGenerator::class)
     */
    private Uuid $uuid;

@xelaris
Copy link

xelaris commented Jun 25, 2023

As @nicolas-grekas pointed out in symfony/symfony-docs#18427 (review), UuidGenerator::class is currently not a service id.

In many cases, UuidGenerator::class will work as expected, but one should be aware, that, in fact, in regard of the property, it replaces the doctrine.uuid_generator service by a new instance, created by doctrine ORM itself. The service might use a custom uuid factory, while the instance, created by doctrine for the particular property, will always use the default factory.

If you don't want to change your application code, to solve the Can't instantiate custom generator issue, and want to keep using the service, I can confirm that using the objectManagerLoader feature, as suggested by @ondrejmirtes, works:

# phpstan.neon
parameters:
	doctrine:
		objectManagerLoader: tests/object-manager.php # needs to be created according to README.md

Maybe the README.md could be extended by something like:

If you are using this extension in a Symfony project with Doctrine bundle and you are using a CustomIdGenerator, you might want to set up the objectManagerLoader, to allow service ids to be resolved.

Currently it sounds as the objectManagerLoader is relevant for "more advanced analysis" and "DQL validation" only. What do you think?

After all, this seems not to be an issue with phpstan-doctrine to me. Instead the issue seems to be caused by Doctrine bundle, by intentionally using the class attribute of the ORM's CustomIdGenerator attribute/annotation in a way which is not supported/expected by ORM. Doctrine ORM expects "name of the class…", while the Doctrine Bundle allows a service id to be used. This seems to cause issues for tools like phpstan-doctrine, which try to gather information about entities without Doctrine bundle. Maybe I will raise this topic in doctrine/DoctrineBundle, after further research.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants