phpstan-doctrine
phpstan-doctrine copied to clipboard
Custom generator as a service produces PHPStan error
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.
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
* @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.
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)]
objectManagerLoader (see README) will AFAIK solve it.
@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.
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.
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;
As @nicolas-grekas pointed out in https://github.com/symfony/symfony-docs/pull/18427#pullrequestreview-1486527166, 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.