Skip to content

Commit 15421c1

Browse files
authored
Eliminate Doctrine deprecations (#21)
* Eliminate Doctrine deprecations * Add backward compatibility with old Doctrine
1 parent 3dfc855 commit 15421c1

File tree

4 files changed

+79
-26
lines changed

4 files changed

+79
-26
lines changed

phpstan.neon.dist

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,20 @@ parameters:
3232
identifier: 'identical.alwaysFalse'
3333
reportUnmatched: false
3434
path: 'src/EntityPreloader.php'
35+
-
36+
message: '#internal interface Doctrine\\ORM\\Mapping\\PropertyAccessors\\PropertyAccessor#' # internal, although returned from public ClassMetadata::getPropertyAccessor
37+
reportUnmatched: false # only new Doctrine
38+
path: 'src/EntityPreloader.php'
39+
-
40+
message: '#Doctrine\\ORM\\Mapping\\PropertyAccessors\\PropertyAccessor#'
41+
reportUnmatched: false # only old Doctrine
42+
identifier: class.notFound
43+
path: 'src/EntityPreloader.php'
44+
-
45+
message: '#Call to function method_exists#'
46+
reportUnmatched: false # only new Doctrine
47+
identifier: function.alreadyNarrowedType
48+
path: 'src/EntityPreloader.php'
3549
-
3650
identifier: shipmonk.defaultMatchArmWithEnum
3751
reportUnmatched: false # only new dbal issue

phpunit.xml.dist

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,21 @@
1313
displayDetailsOnTestsThatTriggerErrors="true"
1414
displayDetailsOnTestsThatTriggerWarnings="true"
1515
displayDetailsOnTestsThatTriggerNotices="true"
16+
displayDetailsOnTestsThatTriggerDeprecations="true"
1617
cacheDirectory="cache/phpunit"
1718
>
19+
<php>
20+
<ini name="error_reporting" value="-1"/>
21+
<env name="DOCTRINE_DEPRECATIONS" value="trigger"/>
22+
</php>
23+
1824
<testsuites>
1925
<testsuite name="default">
2026
<directory>tests</directory>
2127
</testsuite>
2228
</testsuites>
2329

24-
<source>
30+
<source ignoreSuppressionOfDeprecations="true">
2531
<include>
2632
<directory>src</directory>
2733
</include>

src/EntityPreloader.php

Lines changed: 54 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Doctrine\DBAL\Types\Type;
99
use Doctrine\ORM\EntityManagerInterface;
1010
use Doctrine\ORM\Mapping\ClassMetadata;
11+
use Doctrine\ORM\Mapping\PropertyAccessors\PropertyAccessor;
1112
use Doctrine\ORM\PersistentCollection;
1213
use Doctrine\ORM\QueryBuilder;
1314
use LogicException;
@@ -17,6 +18,7 @@
1718
use function count;
1819
use function get_parent_class;
1920
use 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
}

tests/Fixtures/Blog/Article.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
use Doctrine\Common\Collections\ReadableCollection;
88
use Doctrine\ORM\Mapping\Column;
99
use Doctrine\ORM\Mapping\Entity;
10+
use Doctrine\ORM\Mapping\InverseJoinColumn;
11+
use Doctrine\ORM\Mapping\JoinColumn;
1012
use Doctrine\ORM\Mapping\ManyToMany;
1113
use Doctrine\ORM\Mapping\ManyToOne;
1214
use Doctrine\ORM\Mapping\OneToMany;
@@ -29,6 +31,8 @@ class Article extends TestEntityWithCustomPrimaryKey
2931
* @var Collection<int, Tag>
3032
*/
3133
#[ManyToMany(targetEntity: Tag::class, inversedBy: 'articles')]
34+
#[JoinColumn(nullable: false)]
35+
#[InverseJoinColumn(nullable: false)]
3236
private Collection $tags;
3337

3438
/**

0 commit comments

Comments
 (0)