88use Doctrine \DBAL \Types \Type ;
99use Doctrine \ORM \EntityManagerInterface ;
1010use Doctrine \ORM \Mapping \ClassMetadata ;
11+ use Doctrine \ORM \Mapping \PropertyAccessors \PropertyAccessor ;
1112use Doctrine \ORM \PersistentCollection ;
1213use Doctrine \ORM \QueryBuilder ;
1314use LogicException ;
1718use function count ;
1819use function get_parent_class ;
1920use function is_a ;
21+ use function method_exists ;
2022
2123/**
2224 * @template E of object
@@ -123,18 +125,18 @@ private function loadProxies(
123125 int $ maxFetchJoinSameFieldCount ,
124126 ): array
125127 {
126- $ identifierReflection = $ classMetadata -> getSingleIdReflectionProperty ( ); // e.g. Order::$id reflection
128+ $ identifierAccessor = $ this -> getSingleIdPropertyAccessor ( $ classMetadata ); // e.g. Order::$id reflection
127129 $ identifierName = $ classMetadata ->getSingleIdentifierFieldName (); // e.g. 'id'
128130
129- if ($ identifierReflection === null ) {
131+ if ($ identifierAccessor === null ) {
130132 throw new LogicException ('Doctrine should use RuntimeReflectionService which never returns null. ' );
131133 }
132134
133135 $ uniqueEntities = [];
134136 $ uninitializedIds = [];
135137
136138 foreach ($ entities as $ entity ) {
137- $ entityId = $ identifierReflection ->getValue ($ entity );
139+ $ entityId = $ identifierAccessor ->getValue ($ entity );
138140 $ entityKey = (string ) $ entityId ;
139141 $ uniqueEntities [$ entityKey ] = $ entity ;
140142
@@ -170,11 +172,11 @@ private function preloadToMany(
170172 int $ maxFetchJoinSameFieldCount ,
171173 ): array
172174 {
173- $ sourceIdentifierReflection = $ sourceClassMetadata -> getSingleIdReflectionProperty ( ); // e.g. Order::$id reflection
174- $ sourcePropertyReflection = $ sourceClassMetadata -> getReflectionProperty ( $ sourcePropertyName ); // e.g. Order::$items reflection
175- $ targetIdentifierReflection = $ targetClassMetadata -> getSingleIdReflectionProperty ( );
175+ $ sourceIdentifierAccessor = $ this -> getSingleIdPropertyAccessor ( $ sourceClassMetadata ); // e.g. Order::$id reflection
176+ $ sourcePropertyAccessor = $ this -> getPropertyAccessor ( $ sourceClassMetadata , $ sourcePropertyName ); // e.g. Order::$items reflection
177+ $ targetIdentifierAccessor = $ this -> getSingleIdPropertyAccessor ( $ targetClassMetadata );
176178
177- if ($ sourceIdentifierReflection === null || $ sourcePropertyReflection === null || $ targetIdentifierReflection === null ) {
179+ if ($ sourceIdentifierAccessor === null || $ sourcePropertyAccessor === null || $ targetIdentifierAccessor === null ) {
178180 throw new LogicException ('Doctrine should use RuntimeReflectionService which never returns null. ' );
179181 }
180182
@@ -184,9 +186,9 @@ private function preloadToMany(
184186 $ uninitializedCollections = [];
185187
186188 foreach ($ sourceEntities as $ sourceEntity ) {
187- $ sourceEntityId = $ sourceIdentifierReflection ->getValue ($ sourceEntity );
189+ $ sourceEntityId = $ sourceIdentifierAccessor ->getValue ($ sourceEntity );
188190 $ sourceEntityKey = (string ) $ sourceEntityId ;
189- $ sourceEntityCollection = $ sourcePropertyReflection ->getValue ($ sourceEntity );
191+ $ sourceEntityCollection = $ sourcePropertyAccessor ->getValue ($ sourceEntity );
190192
191193 if (
192194 $ sourceEntityCollection instanceof PersistentCollection
@@ -199,7 +201,7 @@ private function preloadToMany(
199201 }
200202
201203 foreach ($ sourceEntityCollection as $ targetEntity ) {
202- $ targetEntityKey = (string ) $ targetIdentifierReflection ->getValue ($ targetEntity );
204+ $ targetEntityKey = (string ) $ targetIdentifierAccessor ->getValue ($ targetEntity );
203205 $ targetEntities [$ targetEntityKey ] = $ targetEntity ;
204206 }
205207 }
@@ -216,10 +218,10 @@ private function preloadToMany(
216218 $ targetEntitiesChunk = $ innerLoader (
217219 associationMapping: $ associationMapping ,
218220 sourceClassMetadata: $ sourceClassMetadata ,
219- sourceIdentifierReflection : $ sourceIdentifierReflection ,
221+ sourceIdentifierAccessor : $ sourceIdentifierAccessor ,
220222 sourcePropertyName: $ sourcePropertyName ,
221223 targetClassMetadata: $ targetClassMetadata ,
222- targetIdentifierReflection : $ targetIdentifierReflection ,
224+ targetIdentifierAccessor : $ targetIdentifierAccessor ,
223225 uninitializedSourceEntityIdsChunk: array_values ($ uninitializedSourceEntityIdsChunk ),
224226 uninitializedCollections: $ uninitializedCollections ,
225227 maxFetchJoinSameFieldCount: $ maxFetchJoinSameFieldCount ,
@@ -253,20 +255,20 @@ private function preloadToMany(
253255 private function preloadOneToManyInner (
254256 array |ArrayAccess $ associationMapping ,
255257 ClassMetadata $ sourceClassMetadata ,
256- ReflectionProperty $ sourceIdentifierReflection ,
258+ PropertyAccessor | ReflectionProperty $ sourceIdentifierAccessor ,
257259 string $ sourcePropertyName ,
258260 ClassMetadata $ targetClassMetadata ,
259- ReflectionProperty $ targetIdentifierReflection ,
261+ PropertyAccessor | ReflectionProperty $ targetIdentifierAccessor ,
260262 array $ uninitializedSourceEntityIdsChunk ,
261263 array $ uninitializedCollections ,
262264 int $ maxFetchJoinSameFieldCount ,
263265 ): array
264266 {
265267 $ targetPropertyName = $ sourceClassMetadata ->getAssociationMappedByTargetField ($ sourcePropertyName ); // e.g. 'order'
266- $ targetPropertyReflection = $ targetClassMetadata -> getReflectionProperty ( $ targetPropertyName ); // e.g. Item::$order reflection
268+ $ targetPropertyAccessor = $ this -> getPropertyAccessor ( $ targetClassMetadata , $ targetPropertyName ); // e.g. Item::$order reflection
267269 $ targetEntities = [];
268270
269- if ($ targetPropertyReflection === null ) {
271+ if ($ targetPropertyAccessor === null ) {
270272 throw new LogicException ('Doctrine should use RuntimeReflectionService which never returns null. ' );
271273 }
272274
@@ -280,11 +282,11 @@ private function preloadOneToManyInner(
280282 );
281283
282284 foreach ($ targetEntitiesList as $ targetEntity ) {
283- $ sourceEntity = $ targetPropertyReflection ->getValue ($ targetEntity );
284- $ sourceEntityKey = (string ) $ sourceIdentifierReflection ->getValue ($ sourceEntity );
285+ $ sourceEntity = $ targetPropertyAccessor ->getValue ($ targetEntity );
286+ $ sourceEntityKey = (string ) $ sourceIdentifierAccessor ->getValue ($ sourceEntity );
285287 $ uninitializedCollections [$ sourceEntityKey ]->add ($ targetEntity );
286288
287- $ targetEntityKey = (string ) $ targetIdentifierReflection ->getValue ($ targetEntity );
289+ $ targetEntityKey = (string ) $ targetIdentifierAccessor ->getValue ($ targetEntity );
288290 $ targetEntities [$ targetEntityKey ] = $ targetEntity ;
289291 }
290292
@@ -306,10 +308,10 @@ private function preloadOneToManyInner(
306308 private function preloadManyToManyInner (
307309 array |ArrayAccess $ associationMapping ,
308310 ClassMetadata $ sourceClassMetadata ,
309- ReflectionProperty $ sourceIdentifierReflection ,
311+ PropertyAccessor | ReflectionProperty $ sourceIdentifierAccessor ,
310312 string $ sourcePropertyName ,
311313 ClassMetadata $ targetClassMetadata ,
312- ReflectionProperty $ targetIdentifierReflection ,
314+ PropertyAccessor | ReflectionProperty $ targetIdentifierAccessor ,
313315 array $ uninitializedSourceEntityIdsChunk ,
314316 array $ uninitializedCollections ,
315317 int $ maxFetchJoinSameFieldCount ,
@@ -356,7 +358,7 @@ private function preloadManyToManyInner(
356358 }
357359
358360 foreach ($ this ->loadEntitiesBy ($ targetClassMetadata , $ targetIdentifierName , $ sourceClassMetadata , array_values ($ uninitializedTargetEntityIds ), $ maxFetchJoinSameFieldCount ) as $ targetEntity ) {
359- $ targetEntityKey = (string ) $ targetIdentifierReflection ->getValue ($ targetEntity );
361+ $ targetEntityKey = (string ) $ targetIdentifierAccessor ->getValue ($ targetEntity );
360362 $ targetEntities [$ targetEntityKey ] = $ targetEntity ;
361363 }
362364
@@ -389,17 +391,17 @@ private function preloadToOne(
389391 int $ maxFetchJoinSameFieldCount ,
390392 ): array
391393 {
392- $ sourcePropertyReflection = $ sourceClassMetadata -> getReflectionProperty ( $ sourcePropertyName ); // e.g. Item::$order reflection
394+ $ sourcePropertyAccessor = $ this -> getPropertyAccessor ( $ sourceClassMetadata , $ sourcePropertyName ); // e.g. Item::$order reflection
393395
394- if ($ sourcePropertyReflection === null ) {
396+ if ($ sourcePropertyAccessor === null ) {
395397 throw new LogicException ('Doctrine should use RuntimeReflectionService which never returns null. ' );
396398 }
397399
398400 $ batchSize ??= self ::PRELOAD_ENTITY_DEFAULT_BATCH_SIZE ;
399401 $ targetEntities = [];
400402
401403 foreach ($ sourceEntities as $ sourceEntity ) {
402- $ targetEntity = $ sourcePropertyReflection ->getValue ($ sourceEntity );
404+ $ targetEntity = $ sourcePropertyAccessor ->getValue ($ sourceEntity );
403405
404406 if ($ targetEntity === null ) {
405407 continue ;
@@ -549,4 +551,31 @@ private function addFetchJoinsToPreventFetchDuringHydration(
549551 }
550552 }
551553
554+ /**
555+ * @param ClassMetadata<object> $classMetadata
556+ */
557+ private function getSingleIdPropertyAccessor (ClassMetadata $ classMetadata ): PropertyAccessor |ReflectionProperty |null
558+ {
559+ if (method_exists ($ classMetadata , 'getSingleIdPropertyAccessor ' )) {
560+ return $ classMetadata ->getSingleIdPropertyAccessor ();
561+ }
562+
563+ return $ classMetadata ->getSingleIdReflectionProperty ();
564+ }
565+
566+ /**
567+ * @param ClassMetadata<object> $classMetadata
568+ */
569+ private function getPropertyAccessor (
570+ ClassMetadata $ classMetadata ,
571+ string $ property ,
572+ ): PropertyAccessor |ReflectionProperty |null
573+ {
574+ if (method_exists ($ classMetadata , 'getPropertyAccessor ' )) {
575+ return $ classMetadata ->getPropertyAccessor ($ property );
576+ }
577+
578+ return $ classMetadata ->getReflectionProperty ($ property );
579+ }
580+
552581}
0 commit comments