Doctrine ORM 2.17.x Update Causes TypeError with indexBy on Doctrine Type (custom UUID) #7292

Open
opened 2026-01-22 15:49:22 +01:00 by admin · 10 comments
Owner

Originally created by @mkarolczyk on GitHub (Jan 2, 2024).

BC Break Report

Q A
BC Break yes
Version 2.17.x

Summary

After updating doctrine/orm to version 2.17.x, the index-by for doctrine type stopped working even though the object (custom UUID) has the __toString() method. Up to version 2.16.x everything worked fine.

TypeError: Doctrine\Common\Collections\ArrayCollection::set(): Argument #1 ($key) must be of type string|int, App\Common\Domain\Uuid given, called in /home/xxx/vendor/doctrine/orm/lib/Doctrine/ORM/PersistentCollection.php on line 191

Previous behavior

Until version 2.16.x, indexBy for doctrine type objects (custom UUID) with the __toString() method worked fine.

<one-to-many field="subaccountRecipients" target-entity="App\Message\Preparation\Domain\SubaccountRecipient" mapped-by="message" fetch="EAGER" orphan-removal="true" index-by="subaccountRecipientId">
            <cascade>
                <cascade-persist />
                <cascade-remove />
            </cascade>
        </one-to-many>

Current behavior

Currently, Doctrine is unable to read such an object and shows an error. Before creating an ArrayCollection, there is no cast to a simple type, in this case string.

TypeError: Doctrine\Common\Collections\ArrayCollection::set(): Argument #1 ($key) must be of type string|int, App\Common\Domain\Uuid given, called in /home/xxx/vendor/doctrine/orm/lib/Doctrine/ORM/PersistentCollection.php on line 191

How to reproduce

  • Have an existing Symfony application using Doctrine 2.17.x
  • Add in the indexBy field, which is an object mapped by doctrine type
  • Use findOneBy method
Originally created by @mkarolczyk on GitHub (Jan 2, 2024). ### BC Break Report | Q | A |------------ | ------ | BC Break | yes | Version | 2.17.x #### Summary After updating doctrine/orm to version 2.17.x, the index-by for doctrine type stopped working even though the object (custom UUID) has the __toString() method. Up to version 2.16.x everything worked fine. `TypeError: Doctrine\Common\Collections\ArrayCollection::set(): Argument #1 ($key) must be of type string|int, App\Common\Domain\Uuid given, called in /home/xxx/vendor/doctrine/orm/lib/Doctrine/ORM/PersistentCollection.php on line 191` #### Previous behavior Until version 2.16.x, indexBy for doctrine type objects (custom UUID) with the __toString() method worked fine. ```xml <one-to-many field="subaccountRecipients" target-entity="App\Message\Preparation\Domain\SubaccountRecipient" mapped-by="message" fetch="EAGER" orphan-removal="true" index-by="subaccountRecipientId"> <cascade> <cascade-persist /> <cascade-remove /> </cascade> </one-to-many> ``` #### Current behavior Currently, Doctrine is unable to read such an object and shows an error. Before creating an ArrayCollection, there is no cast to a simple type, in this case string. `TypeError: Doctrine\Common\Collections\ArrayCollection::set(): Argument #1 ($key) must be of type string|int, App\Common\Domain\Uuid given, called in /home/xxx/vendor/doctrine/orm/lib/Doctrine/ORM/PersistentCollection.php on line 191` #### How to reproduce - Have an existing Symfony application using Doctrine 2.17.x - Add in the indexBy field, which is an object mapped by doctrine type - Use findOneBy method
Author
Owner

@greg0ire commented on GitHub (Jan 4, 2024):

@mkarolczyk hey 👋

I tried finding what may have caused this, and failed, so instead, I wrote this blog post especially for you. Can you please try to apply what you read here to this issue, and let me know if anything is unclear? Thanks.

@greg0ire commented on GitHub (Jan 4, 2024): @mkarolczyk hey :wave: I tried finding what may have caused this, and failed, so instead, I wrote [this blog post](https://dev.to/greg0ire/bisecting-vendors-12kd) especially for you. Can you please try to apply what you read here to this issue, and let me know if anything is unclear? Thanks.
Author
Owner

@gordinskiy commented on GitHub (Jan 6, 2024):

Got same error after trying to use Optimized eager fetch instead of Multi-step hydration

Doctrine\Common\Collections\ArrayCollection::set(): Argument #1 ($key) must be of type string|int, {MyCustomUlidValueObject} given, called in /opt/project/vendor/doctrine/orm/lib/Doctrine/ORM/PersistentCollection.php on line 191

@gordinskiy commented on GitHub (Jan 6, 2024): Got same error after trying to use [Optimized eager fetch](https://github.com/doctrine/orm/pull/8391) instead of [Multi-step hydration](https://ocramius.github.io/blog/doctrine-orm-optimization-hydration/) ```Doctrine\Common\Collections\ArrayCollection::set(): Argument #1 ($key) must be of type string|int, {MyCustomUlidValueObject} given, called in /opt/project/vendor/doctrine/orm/lib/Doctrine/ORM/PersistentCollection.php on line 191```
Author
Owner

@greg0ire commented on GitHub (Jan 6, 2024):

OK. @beberlei can you please look into this?

@greg0ire commented on GitHub (Jan 6, 2024): OK. @beberlei can you please look into this?
Author
Owner

@rik702 commented on GitHub (Jan 7, 2024):

Did the git bisect thing (thanks @greg0ire working link to blog post) ... was introduced in 76fd34f76607b1b96f381377c1c51df292c759aa

@rik702 commented on GitHub (Jan 7, 2024): Did the git bisect thing (thanks @greg0ire [working link to blog post](https://dev.to/greg0ire/bisecting-vendors-12kd)) ... was introduced in [76fd34f76607b1b96f381377c1c51df292c759aa](https://github.com/doctrine/orm/commit/76fd34f76607b1b96f381377c1c51df292c759aa)
Author
Owner

@greg0ire commented on GitHub (Jan 7, 2024):

Nice job! The link did change since I published the blog post 😅

@greg0ire commented on GitHub (Jan 7, 2024): Nice job! The link did change since I published the blog post :sweat_smile:
Author
Owner

@greg0ire commented on GitHub (Jan 7, 2024):

The other thing that might help would be a stack trace. Here is a documentation article (that I also authored) about that

@greg0ire commented on GitHub (Jan 7, 2024): The other thing that might help would be a stack trace. Here is a [documentation article (that I also authored) about that](https://symfony.com/doc/current/contributing/code/stack_trace.html)
Author
Owner

@rik702 commented on GitHub (Jan 8, 2024):

TypeError:
Doctrine\Common\Collections\ArrayCollection::set(): Argument #1 ($key) must be of type string|int, Symfony\Component\Uid\UuidV7 given, called in .../vendor/doctrine/orm/lib/Doctrine/ORM/PersistentCollection.php on line 191

  at vendor/doctrine/collections/src/ArrayCollection.php:311
  at Doctrine\Common\Collections\ArrayCollection->set(object(UuidV7), object(***))
     (vendor/doctrine/orm/lib/Doctrine/ORM/PersistentCollection.php:191)
  at Doctrine\ORM\PersistentCollection->hydrateSet(object(UuidV7), object(***))
     (vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:3195)
  at Doctrine\ORM\UnitOfWork->eagerLoadCollections(array('018cab11-c97b-xxxx-xxxx-cdfcb3042045' => object(PersistentCollection)), array('fieldName' => '***', 'mappedBy' => '***', 'targetEntity' => '******', 'cascade' => array('persist', 'remove'), 'indexBy' => '***Uuid', 'orphanRemoval' => true, 'fetch' => 3, 'type' => 4, 'inversedBy' => null, 'isOwningSide' => false, 'sourceEntity' => '******', 'isCascadeRemove' => true, 'isCascadePersist' => true, 'isCascadeRefresh' => false, 'isCascadeMerge' => false, 'isCascadeDetach' => false))
     (vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:3156)
  at Doctrine\ORM\UnitOfWork->triggerEagerLoads()
     (vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php:126)
  at Doctrine\ORM\Internal\Hydration\ObjectHydrator->cleanup()
     (vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php:272)
  at Doctrine\ORM\Internal\Hydration\AbstractHydrator->hydrateAll(object(Result), object(ResultSetMapping), array('deferEagerLoad' => true))
     (vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php:943)
  at Doctrine\ORM\Persisters\Entity\BasicEntityPersister->loadAll(array('User' => array(object(User))))
     (vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:3182)
  at Doctrine\ORM\UnitOfWork->eagerLoadCollections(array('018cab11-cb22-xxxx-xxxx-4b2239340e9c' => object(PersistentCollection)), array('fieldName' => '******s', 'mappedBy' => 'User', 'targetEntity' => '******', 'cascade' => array('persist', 'remove'), 'indexBy' => '***Uuid', 'orphanRemoval' => true, 'fetch' => 3, 'type' => 4, 'inversedBy' => null, 'isOwningSide' => false, 'sourceEntity' => '******', 'isCascadeRemove' => true, 'isCascadePersist' => true, 'isCascadeRefresh' => false, 'isCascadeMerge' => false, 'isCascadeDetach' => false))
     (vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:3156)
  at Doctrine\ORM\UnitOfWork->triggerEagerLoads()
     (vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php:68)
  at Doctrine\ORM\Internal\Hydration\SimpleObjectHydrator->hydrateAllData()
     (vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php:270)
  at Doctrine\ORM\Internal\Hydration\AbstractHydrator->hydrateAll(object(Result), object(ResultSetMapping), array())
     (vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php:779)
  at Doctrine\ORM\Persisters\Entity\BasicEntityPersister->load(array('UserId' => '******'), null, null, array(), null, 1, null)
     (vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php:241)
  at Doctrine\ORM\EntityRepository->findOneBy(array('UserId' => '******'))
     (vendor/symfony/doctrine-bridge/Security/User/EntityUserProvider.php:54)
  at Symfony\Bridge\Doctrine\Security\User\EntityUserProvider->loadUserByIdentifier('******')
     (vendor/symfony/security-http/Authenticator/Passport/Badge/UserBadge.php:87)
  at Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge->getUser()
     (vendor/symfony/security-http/Authenticator/Passport/Passport.php:56)
  at Symfony\Component\Security\Http\Authenticator\Passport\Passport->getUser()
     (vendor/symfony/security-http/EventListener/UserCheckerListener.php:42)
  at Symfony\Component\Security\Http\EventListener\UserCheckerListener->preCheckCredentials(object(CheckPassportEvent), 'Symfony\\Component\\Security\\Http\\Event\\CheckPassportEvent', object(TraceableEventDispatcher))
     (vendor/symfony/event-dispatcher/Debug/WrappedListener.php:116)
  at Symfony\Component\EventDispatcher\Debug\WrappedListener->__invoke(object(CheckPassportEvent), 'Symfony\\Component\\Security\\Http\\Event\\CheckPassportEvent', object(TraceableEventDispatcher))
     (vendor/symfony/event-dispatcher/EventDispatcher.php:206)
  at Symfony\Component\EventDispatcher\EventDispatcher->callListeners(array(object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener)), 'Symfony\\Component\\Security\\Http\\Event\\CheckPassportEvent', object(CheckPassportEvent))
     (vendor/symfony/event-dispatcher/EventDispatcher.php:56)
  at Symfony\Component\EventDispatcher\EventDispatcher->dispatch(object(CheckPassportEvent), 'Symfony\\Component\\Security\\Http\\Event\\CheckPassportEvent')
     (vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:127)
  at Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher->dispatch(object(CheckPassportEvent))
     (vendor/symfony/security-http/Authentication/AuthenticatorManager.php:180)
  at Symfony\Component\Security\Http\Authentication\AuthenticatorManager->executeAuthenticator(object(TraceableAuthenticator), object(Request))
     (vendor/symfony/security-http/Authentication/AuthenticatorManager.php:158)
  at Symfony\Component\Security\Http\Authentication\AuthenticatorManager->executeAuthenticators(array(object(TraceableAuthenticator)), object(Request))
     (vendor/symfony/security-http/Authentication/AuthenticatorManager.php:140)
  at Symfony\Component\Security\Http\Authentication\AuthenticatorManager->authenticateRequest(object(Request))
     (vendor/symfony/security-http/Firewall/AuthenticatorManagerListener.php:40)
  at Symfony\Component\Security\Http\Firewall\AuthenticatorManagerListener->authenticate(object(RequestEvent))
     (vendor/symfony/security-http/Authenticator/Debug/TraceableAuthenticatorManagerListener.php:68)
  at Symfony\Component\Security\Http\Authenticator\Debug\TraceableAuthenticatorManagerListener->authenticate(object(RequestEvent))
     (vendor/symfony/security-bundle/Debug/WrappedLazyListener.php:46)
  at Symfony\Bundle\SecurityBundle\Debug\WrappedLazyListener->authenticate(object(RequestEvent))
     (vendor/symfony/security-http/Firewall/AbstractListener.php:26)
  at Symfony\Component\Security\Http\Firewall\AbstractListener->__invoke(object(RequestEvent))
     (vendor/symfony/security-bundle/Security/LazyFirewallContext.php:60)
  at Symfony\Bundle\SecurityBundle\Security\LazyFirewallContext->__invoke(object(RequestEvent))
     (vendor/symfony/security-bundle/Debug/TraceableFirewallListener.php:77)
  at Symfony\Bundle\SecurityBundle\Debug\TraceableFirewallListener->callListeners(object(RequestEvent), object(Generator))
     (vendor/symfony/security-http/Firewall.php:95)
  at Symfony\Component\Security\Http\Firewall->onKernelRequest(object(RequestEvent), 'kernel.request', object(TraceableEventDispatcher))
     (vendor/symfony/event-dispatcher/Debug/WrappedListener.php:116)
  at Symfony\Component\EventDispatcher\Debug\WrappedListener->__invoke(object(RequestEvent), 'kernel.request', object(TraceableEventDispatcher))
     (vendor/symfony/event-dispatcher/EventDispatcher.php:206)
  at Symfony\Component\EventDispatcher\EventDispatcher->callListeners(array(object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener)), 'kernel.request', object(RequestEvent))
     (vendor/symfony/event-dispatcher/EventDispatcher.php:56)
  at Symfony\Component\EventDispatcher\EventDispatcher->dispatch(object(RequestEvent), 'kernel.request')
     (vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:127)
  at Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher->dispatch(object(RequestEvent), 'kernel.request')
     (vendor/symfony/http-kernel/HttpKernel.php:154)
  at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), 1)
     (vendor/symfony/http-kernel/HttpKernel.php:76)
  at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), 1, true)
     (vendor/symfony/http-kernel/Kernel.php:185)
  at Symfony\Component\HttpKernel\Kernel->handle(object(Request))
     (vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php:35)
  at Symfony\Component\Runtime\Runner\Symfony\HttpKernelRunner->run()
     (vendor/autoload_runtime.php:29)
  at require_once('.../vendor/autoload_runtime.php')
     (public/index.php:4)                

Here's a stack trace, It's happening at logon, with a chain of fetch='EAGER' relationships on OneToMany, ManytoOne then another OneToMany. Each entity has Symfony UUID PKs as below:

  #[ORM\Column(type: 'uuid')]
  #[ORM\GeneratedValue(strategy: 'CUSTOM')]
  #[ORM\CustomIdGenerator('doctrine.uuid_generator')]
  #[ORM\Id]
  private ?Uuid $uuid = null;
@rik702 commented on GitHub (Jan 8, 2024): ``` TypeError: Doctrine\Common\Collections\ArrayCollection::set(): Argument #1 ($key) must be of type string|int, Symfony\Component\Uid\UuidV7 given, called in .../vendor/doctrine/orm/lib/Doctrine/ORM/PersistentCollection.php on line 191 at vendor/doctrine/collections/src/ArrayCollection.php:311 at Doctrine\Common\Collections\ArrayCollection->set(object(UuidV7), object(***)) (vendor/doctrine/orm/lib/Doctrine/ORM/PersistentCollection.php:191) at Doctrine\ORM\PersistentCollection->hydrateSet(object(UuidV7), object(***)) (vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:3195) at Doctrine\ORM\UnitOfWork->eagerLoadCollections(array('018cab11-c97b-xxxx-xxxx-cdfcb3042045' => object(PersistentCollection)), array('fieldName' => '***', 'mappedBy' => '***', 'targetEntity' => '******', 'cascade' => array('persist', 'remove'), 'indexBy' => '***Uuid', 'orphanRemoval' => true, 'fetch' => 3, 'type' => 4, 'inversedBy' => null, 'isOwningSide' => false, 'sourceEntity' => '******', 'isCascadeRemove' => true, 'isCascadePersist' => true, 'isCascadeRefresh' => false, 'isCascadeMerge' => false, 'isCascadeDetach' => false)) (vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:3156) at Doctrine\ORM\UnitOfWork->triggerEagerLoads() (vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/ObjectHydrator.php:126) at Doctrine\ORM\Internal\Hydration\ObjectHydrator->cleanup() (vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php:272) at Doctrine\ORM\Internal\Hydration\AbstractHydrator->hydrateAll(object(Result), object(ResultSetMapping), array('deferEagerLoad' => true)) (vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php:943) at Doctrine\ORM\Persisters\Entity\BasicEntityPersister->loadAll(array('User' => array(object(User)))) (vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:3182) at Doctrine\ORM\UnitOfWork->eagerLoadCollections(array('018cab11-cb22-xxxx-xxxx-4b2239340e9c' => object(PersistentCollection)), array('fieldName' => '******s', 'mappedBy' => 'User', 'targetEntity' => '******', 'cascade' => array('persist', 'remove'), 'indexBy' => '***Uuid', 'orphanRemoval' => true, 'fetch' => 3, 'type' => 4, 'inversedBy' => null, 'isOwningSide' => false, 'sourceEntity' => '******', 'isCascadeRemove' => true, 'isCascadePersist' => true, 'isCascadeRefresh' => false, 'isCascadeMerge' => false, 'isCascadeDetach' => false)) (vendor/doctrine/orm/lib/Doctrine/ORM/UnitOfWork.php:3156) at Doctrine\ORM\UnitOfWork->triggerEagerLoads() (vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/SimpleObjectHydrator.php:68) at Doctrine\ORM\Internal\Hydration\SimpleObjectHydrator->hydrateAllData() (vendor/doctrine/orm/lib/Doctrine/ORM/Internal/Hydration/AbstractHydrator.php:270) at Doctrine\ORM\Internal\Hydration\AbstractHydrator->hydrateAll(object(Result), object(ResultSetMapping), array()) (vendor/doctrine/orm/lib/Doctrine/ORM/Persisters/Entity/BasicEntityPersister.php:779) at Doctrine\ORM\Persisters\Entity\BasicEntityPersister->load(array('UserId' => '******'), null, null, array(), null, 1, null) (vendor/doctrine/orm/lib/Doctrine/ORM/EntityRepository.php:241) at Doctrine\ORM\EntityRepository->findOneBy(array('UserId' => '******')) (vendor/symfony/doctrine-bridge/Security/User/EntityUserProvider.php:54) at Symfony\Bridge\Doctrine\Security\User\EntityUserProvider->loadUserByIdentifier('******') (vendor/symfony/security-http/Authenticator/Passport/Badge/UserBadge.php:87) at Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge->getUser() (vendor/symfony/security-http/Authenticator/Passport/Passport.php:56) at Symfony\Component\Security\Http\Authenticator\Passport\Passport->getUser() (vendor/symfony/security-http/EventListener/UserCheckerListener.php:42) at Symfony\Component\Security\Http\EventListener\UserCheckerListener->preCheckCredentials(object(CheckPassportEvent), 'Symfony\\Component\\Security\\Http\\Event\\CheckPassportEvent', object(TraceableEventDispatcher)) (vendor/symfony/event-dispatcher/Debug/WrappedListener.php:116) at Symfony\Component\EventDispatcher\Debug\WrappedListener->__invoke(object(CheckPassportEvent), 'Symfony\\Component\\Security\\Http\\Event\\CheckPassportEvent', object(TraceableEventDispatcher)) (vendor/symfony/event-dispatcher/EventDispatcher.php:206) at Symfony\Component\EventDispatcher\EventDispatcher->callListeners(array(object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener)), 'Symfony\\Component\\Security\\Http\\Event\\CheckPassportEvent', object(CheckPassportEvent)) (vendor/symfony/event-dispatcher/EventDispatcher.php:56) at Symfony\Component\EventDispatcher\EventDispatcher->dispatch(object(CheckPassportEvent), 'Symfony\\Component\\Security\\Http\\Event\\CheckPassportEvent') (vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:127) at Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher->dispatch(object(CheckPassportEvent)) (vendor/symfony/security-http/Authentication/AuthenticatorManager.php:180) at Symfony\Component\Security\Http\Authentication\AuthenticatorManager->executeAuthenticator(object(TraceableAuthenticator), object(Request)) (vendor/symfony/security-http/Authentication/AuthenticatorManager.php:158) at Symfony\Component\Security\Http\Authentication\AuthenticatorManager->executeAuthenticators(array(object(TraceableAuthenticator)), object(Request)) (vendor/symfony/security-http/Authentication/AuthenticatorManager.php:140) at Symfony\Component\Security\Http\Authentication\AuthenticatorManager->authenticateRequest(object(Request)) (vendor/symfony/security-http/Firewall/AuthenticatorManagerListener.php:40) at Symfony\Component\Security\Http\Firewall\AuthenticatorManagerListener->authenticate(object(RequestEvent)) (vendor/symfony/security-http/Authenticator/Debug/TraceableAuthenticatorManagerListener.php:68) at Symfony\Component\Security\Http\Authenticator\Debug\TraceableAuthenticatorManagerListener->authenticate(object(RequestEvent)) (vendor/symfony/security-bundle/Debug/WrappedLazyListener.php:46) at Symfony\Bundle\SecurityBundle\Debug\WrappedLazyListener->authenticate(object(RequestEvent)) (vendor/symfony/security-http/Firewall/AbstractListener.php:26) at Symfony\Component\Security\Http\Firewall\AbstractListener->__invoke(object(RequestEvent)) (vendor/symfony/security-bundle/Security/LazyFirewallContext.php:60) at Symfony\Bundle\SecurityBundle\Security\LazyFirewallContext->__invoke(object(RequestEvent)) (vendor/symfony/security-bundle/Debug/TraceableFirewallListener.php:77) at Symfony\Bundle\SecurityBundle\Debug\TraceableFirewallListener->callListeners(object(RequestEvent), object(Generator)) (vendor/symfony/security-http/Firewall.php:95) at Symfony\Component\Security\Http\Firewall->onKernelRequest(object(RequestEvent), 'kernel.request', object(TraceableEventDispatcher)) (vendor/symfony/event-dispatcher/Debug/WrappedListener.php:116) at Symfony\Component\EventDispatcher\Debug\WrappedListener->__invoke(object(RequestEvent), 'kernel.request', object(TraceableEventDispatcher)) (vendor/symfony/event-dispatcher/EventDispatcher.php:206) at Symfony\Component\EventDispatcher\EventDispatcher->callListeners(array(object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener), object(WrappedListener)), 'kernel.request', object(RequestEvent)) (vendor/symfony/event-dispatcher/EventDispatcher.php:56) at Symfony\Component\EventDispatcher\EventDispatcher->dispatch(object(RequestEvent), 'kernel.request') (vendor/symfony/event-dispatcher/Debug/TraceableEventDispatcher.php:127) at Symfony\Component\EventDispatcher\Debug\TraceableEventDispatcher->dispatch(object(RequestEvent), 'kernel.request') (vendor/symfony/http-kernel/HttpKernel.php:154) at Symfony\Component\HttpKernel\HttpKernel->handleRaw(object(Request), 1) (vendor/symfony/http-kernel/HttpKernel.php:76) at Symfony\Component\HttpKernel\HttpKernel->handle(object(Request), 1, true) (vendor/symfony/http-kernel/Kernel.php:185) at Symfony\Component\HttpKernel\Kernel->handle(object(Request)) (vendor/symfony/runtime/Runner/Symfony/HttpKernelRunner.php:35) at Symfony\Component\Runtime\Runner\Symfony\HttpKernelRunner->run() (vendor/autoload_runtime.php:29) at require_once('.../vendor/autoload_runtime.php') (public/index.php:4) ``` Here's a stack trace, It's happening at logon, with a chain of fetch='EAGER' relationships on OneToMany, ManytoOne then another OneToMany. Each entity has Symfony UUID PKs as below: ```php #[ORM\Column(type: 'uuid')] #[ORM\GeneratedValue(strategy: 'CUSTOM')] #[ORM\CustomIdGenerator('doctrine.uuid_generator')] #[ORM\Id] private ?Uuid $uuid = null; ```
Author
Owner

@wmouwen commented on GitHub (Jan 25, 2024):

Related to #11097.

The changes in this commit started injecting entities and backed enumerations as keys for collections.

76fd34f766/lib/Doctrine/ORM/UnitOfWork.php (L3199-L3204)

In the example of #11097, it expects the scalar value behind the database column language_id, but gets the Language entity instead.

In the example by @rik702 above, it expects the scalar value behind the Uuid class, but gets the Uuid class/entity instead.

In my beliefs the mapper in UnitOfWork should cast the result of $indexByProperty->getValue($targetValue) to the primary identifier of the object if an object is returned. Note that it should also cast BackedEnums to their scalar value to maintain the behavior of 2.16.x.

@greg0ire any thoughts on this?

@wmouwen commented on GitHub (Jan 25, 2024): Related to #11097. The changes in [this](https://github.com/doctrine/orm/commit/76fd34f76607b1b96f381377c1c51df292c759aa#diff-55a900494fc8033ab498c53929716caf0aa39d6bdd7058e7d256787a24412ee4R3199-R3204) commit started injecting entities and backed enumerations as keys for collections. https://github.com/doctrine/orm/blob/76fd34f76607b1b96f381377c1c51df292c759aa/lib/Doctrine/ORM/UnitOfWork.php#L3199-L3204 In the example of #11097, it expects the scalar value behind the database column `language_id`, but gets the Language entity instead. In the example by @rik702 above, it expects the scalar value behind the Uuid class, but gets the Uuid class/entity instead. In my beliefs the mapper in UnitOfWork should cast the result of `$indexByProperty->getValue($targetValue)` to the primary identifier of the object if an object is returned. Note that it should also cast BackedEnums to their scalar value to maintain the behavior of 2.16.x. @greg0ire any thoughts on this?
Author
Owner

@greg0ire commented on GitHub (Jan 25, 2024):

No thoughts, this sounds good.
Possible next steps for anybody willing to work on this:

  • build a failing test case from the examples above
  • try the solution proposed by @wmouwen , see if it breaks any tests in the test suite
@greg0ire commented on GitHub (Jan 25, 2024): No thoughts, this sounds good. Possible next steps for anybody willing to work on this: - build a failing test case from the examples above - try the solution proposed by @wmouwen , see if it breaks any tests in the test suite
Author
Owner

@pajon commented on GitHub (Feb 27, 2024):

Hi everyone,

I've been debugging, and I believe I've identified the issue. It appears that Doctrine ORM does not support arrays with custom types.

You can find more information about this in the Doctrine ORM source code here: https://github.com/doctrine/orm/blob/b187bc85881cc85d36b28e7ed9dbe2071d472e30/src/Persisters/Entity/BasicEntityPersister.php#L1891

While the input contains the correct type, the output always seems to be translated to DBAL ArrayParameterType[STRING|INTEGER|ASCII].

In my case, the custom type (UuidType) is being translated to ArrayParameterType::STRING, which invokes Uuid::__toString() instead of using UuidType::convertToDatabaseValue()

@pajon commented on GitHub (Feb 27, 2024): Hi everyone, I've been debugging, and I believe I've identified the issue. It appears that Doctrine ORM does not support arrays with custom types. You can find more information about this in the Doctrine ORM source code here: [https://github.com/doctrine/orm/blob/b187bc85881cc85d36b28e7ed9dbe2071d472e30/src/Persisters/Entity/BasicEntityPersister.php#L1891](url) While the input contains the correct type, the output always seems to be translated to DBAL ArrayParameterType[STRING|INTEGER|ASCII]. In my case, the custom type (UuidType) is being translated to ArrayParameterType::STRING, which invokes Uuid::__toString() instead of using UuidType::convertToDatabaseValue()
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#7292