Skip to content

Commit

Permalink
fix(doctrine): doctrine/orm:^3.0 support (#6193)
Browse files Browse the repository at this point in the history
* feat: add compatibility with doctrine/orm 3.0

* attempt to fix lowest

---------

Co-authored-by: David de Boer <david@ddeboer.nl>
  • Loading branch information
soyuka and ddeboer authored Mar 5, 2024
1 parent f891f16 commit d8e2d0c
Show file tree
Hide file tree
Showing 23 changed files with 450 additions and 302 deletions.
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"doctrine/doctrine-bundle": "^1.12 || ^2.0",
"doctrine/mongodb-odm": "^2.2",
"doctrine/mongodb-odm-bundle": "^4.0 || ^5.0",
"doctrine/orm": "^2.14",
"doctrine/orm": "^2.14 || ^3.0",
"elasticsearch/elasticsearch": "^7.11 || ^8.4",
"friends-of-behat/mink-browserkit-driver": "^1.3.1",
"friends-of-behat/mink-extension": "^2.2",
Expand Down
12 changes: 6 additions & 6 deletions src/Doctrine/Common/Tests/State/PersistProcessorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
use ApiPlatform\Metadata\Get;
use ApiPlatform\State\ProcessorInterface;
use Doctrine\ODM\MongoDB\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Mapping\ClassMetadata as ORMClassMetadata;
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\Persistence\ObjectManager;
use PHPUnit\Framework\TestCase;
Expand Down Expand Up @@ -84,8 +84,8 @@ public function testPersistWithNullManager(): void
public static function getTrackingPolicyParameters(): array
{
return [
'deferred explicit ORM' => [ClassMetadataInfo::class, true, true],
'deferred implicit ORM' => [ClassMetadataInfo::class, false, false],
'deferred explicit ORM' => [ORMClassMetadata::class, true, true],
'deferred implicit ORM' => [ORMClassMetadata::class, false, false],
'deferred explicit ODM' => [ClassMetadata::class, true, true],
'deferred implicit ODM' => [ClassMetadata::class, false, false],
];
Expand All @@ -98,15 +98,15 @@ public function testTrackingPolicy(string $metadataClass, bool $deferredExplicit
{
$dummy = new Dummy();

$classMetadataInfo = $this->prophesize($metadataClass);
$classMetadata = $this->prophesize($metadataClass);
if (method_exists($metadataClass, 'isChangeTrackingDeferredExplicit')) {
$classMetadataInfo->isChangeTrackingDeferredExplicit()->willReturn($deferredExplicit)->shouldBeCalled();
$classMetadata->isChangeTrackingDeferredExplicit()->willReturn($deferredExplicit)->shouldBeCalled();
} else {
$persisted = false;
}

$objectManagerProphecy = $this->prophesize(ObjectManager::class);
$objectManagerProphecy->getClassMetadata(Dummy::class)->willReturn($classMetadataInfo)->shouldBeCalled();
$objectManagerProphecy->getClassMetadata(Dummy::class)->willReturn($classMetadata)->shouldBeCalled();
$objectManagerProphecy->contains($dummy)->willReturn(true);
$objectManagerProphecy->persist($dummy)->should($persisted ? new CallPrediction() : new NoCallsPrediction());
$objectManagerProphecy->flush()->shouldBeCalled();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ public function __construct(LegacyResourceClassResolverInterface|ResourceClassRe
public function onFlush(EventArgs $eventArgs): void
{
if ($eventArgs instanceof OrmOnFlushEventArgs) {
// @phpstan-ignore-next-line
$uow = method_exists($eventArgs, 'getObjectManager') ? $eventArgs->getObjectManager()->getUnitOfWork() : $eventArgs->getEntityManager()->getUnitOfWork();
} elseif ($eventArgs instanceof MongoDbOdmOnFlushEventArgs) {
$uow = $eventArgs->getDocumentManager()->getUnitOfWork();
Expand Down
16 changes: 13 additions & 3 deletions src/Doctrine/EventListener/PurgeHttpCacheListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Event\OnFlushEventArgs;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Doctrine\ORM\Mapping\AssociationMapping;
use Doctrine\ORM\PersistentCollection;
use Symfony\Component\PropertyAccess\PropertyAccess;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
Expand Down Expand Up @@ -57,6 +58,7 @@ public function preUpdate(PreUpdateEventArgs $eventArgs): void
$this->gatherResourceAndItemTags($object, true);

$changeSet = $eventArgs->getEntityChangeSet();
// @phpstan-ignore-next-line
$objectManager = method_exists($eventArgs, 'getObjectManager') ? $eventArgs->getObjectManager() : $eventArgs->getEntityManager();
$associationMappings = $objectManager->getClassMetadata(ClassUtils::getClass($eventArgs->getObject()))->getAssociationMappings();

Expand All @@ -75,6 +77,7 @@ public function preUpdate(PreUpdateEventArgs $eventArgs): void
*/
public function onFlush(OnFlushEventArgs $eventArgs): void
{
// @phpstan-ignore-next-line
$em = method_exists($eventArgs, 'getObjectManager') ? $eventArgs->getObjectManager() : $eventArgs->getEntityManager();
$uow = $em->getUnitOfWork();

Expand Down Expand Up @@ -125,12 +128,19 @@ private function gatherResourceAndItemTags(object $entity, bool $purgeItem): voi
private function gatherRelationTags(EntityManagerInterface $em, object $entity): void
{
$associationMappings = $em->getClassMetadata(ClassUtils::getClass($entity))->getAssociationMappings();
foreach (array_keys($associationMappings) as $property) {
/** @var array|AssociationMapping $associationMapping according to the version of doctrine orm */
foreach ($associationMappings as $property => $associationMapping) {
if ($associationMapping instanceof AssociationMapping && ($associationMapping->targetEntity ?? null) && !$this->resourceClassResolver->isResourceClass($associationMapping->targetEntity)) {
return;
}

if (
\array_key_exists('targetEntity', $associationMappings[$property])
&& !$this->resourceClassResolver->isResourceClass($associationMappings[$property]['targetEntity'])) {
\is_array($associationMapping)
&& \array_key_exists('targetEntity', $associationMapping)
&& !$this->resourceClassResolver->isResourceClass($associationMapping['targetEntity'])) {
return;
}

if ($this->propertyAccessor->isReadable($entity, $property)) {
$this->addTagsFor($this->propertyAccessor->getValue($entity, $property));
}
Expand Down
2 changes: 1 addition & 1 deletion src/Doctrine/Orm/AbstractPaginator.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ public function __construct(DoctrinePaginator $paginator)
{
$query = $paginator->getQuery();

if (null === ($firstResult = $query->getFirstResult()) || null === $maxResults = $query->getMaxResults()) { // @phpstan-ignore-line
if (null === ($firstResult = $query->getFirstResult()) || $firstResult < 0 || null === $maxResults = $query->getMaxResults()) { // @phpstan-ignore-line
throw new InvalidArgumentException(sprintf('"%1$s::setFirstResult()" or/and "%1$s::setMaxResults()" was/were not applied to the query.', Query::class));
}

Expand Down
5 changes: 2 additions & 3 deletions src/Doctrine/Orm/Extension/EagerLoadingExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
use ApiPlatform\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\Query\Expr\Select;
use Doctrine\ORM\QueryBuilder;
Expand Down Expand Up @@ -137,9 +136,9 @@ private function joinRelations(QueryBuilder $queryBuilder, QueryNameGeneratorInt

if (
// Always skip extra lazy associations
ClassMetadataInfo::FETCH_EXTRA_LAZY === $mapping['fetch']
ClassMetadata::FETCH_EXTRA_LAZY === $mapping['fetch']
// We don't want to interfere with doctrine on this association
|| (false === $forceEager && ClassMetadataInfo::FETCH_EAGER !== $mapping['fetch'])
|| (false === $forceEager && ClassMetadata::FETCH_EAGER !== $mapping['fetch'])
) {
continue;
}
Expand Down
6 changes: 3 additions & 3 deletions src/Doctrine/Orm/Extension/FilterEagerLoadingExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
use ApiPlatform\Metadata\Operation;
use ApiPlatform\Metadata\ResourceClassResolverInterface;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;

Expand Down Expand Up @@ -111,12 +111,12 @@ public function applyToCollection(QueryBuilder $queryBuilder, QueryNameGenerator
*
* @param array $checked array cache of tested metadata classes
*/
private function hasFetchEagerAssociation(EntityManagerInterface $em, ClassMetadataInfo $classMetadata, array &$checked = []): bool
private function hasFetchEagerAssociation(EntityManagerInterface $em, ClassMetadata $classMetadata, array &$checked = []): bool
{
$checked[] = $classMetadata->name;

foreach ($classMetadata->getAssociationMappings() as $mapping) {
if (ClassMetadataInfo::FETCH_EAGER === $mapping['fetch']) {
if (ClassMetadata::FETCH_EAGER === $mapping['fetch']) {
return true;
}

Expand Down
29 changes: 25 additions & 4 deletions src/Doctrine/Orm/Filter/ExistsFilter.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@
use ApiPlatform\Doctrine\Orm\Util\QueryBuilderHelper;
use ApiPlatform\Doctrine\Orm\Util\QueryNameGeneratorInterface;
use ApiPlatform\Metadata\Operation;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Mapping\AssociationMapping;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ManyToManyOwningSideMapping;
use Doctrine\ORM\Mapping\ToOneOwningSideMapping;
use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;
Expand Down Expand Up @@ -199,7 +202,7 @@ protected function isNullableField(string $property, string $resourceClass): boo

if ($metadata->hasAssociation($field)) {
if ($metadata->isSingleValuedAssociation($field)) {
if (!($metadata instanceof ClassMetadataInfo)) {
if (!($metadata instanceof ClassMetadata)) {
return false;
}

Expand All @@ -211,7 +214,7 @@ protected function isNullableField(string $property, string $resourceClass): boo
return true;
}

if ($metadata instanceof ClassMetadataInfo && $metadata->hasField($field)) {
if ($metadata instanceof ClassMetadata && $metadata->hasField($field)) {
return $metadata->isNullable($field);
}

Expand All @@ -223,8 +226,26 @@ protected function isNullableField(string $property, string $resourceClass): boo
*
* @see https://github.com/doctrine/doctrine2/blob/v2.5.4/lib/Doctrine/ORM/Tools/EntityGenerator.php#L1221-L1246
*/
private function isAssociationNullable(array $associationMapping): bool
private function isAssociationNullable(AssociationMapping|array $associationMapping): bool
{
if ($associationMapping instanceof AssociationMapping) {
if (!empty($associationMapping->id)) {
return false;
}

if ($associationMapping instanceof ToOneOwningSideMapping || $associationMapping instanceof ManyToManyOwningSideMapping) {
foreach ($associationMapping->joinColumns as $joinColumn) {
if (false === $joinColumn->nullable) {
return false;
}
}

return true;
}

return true;
}

if (!empty($associationMapping['id'])) {
return false;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@

use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\FieldMapping;
use Doctrine\Persistence\ManagerRegistry;

/**
Expand Down Expand Up @@ -55,7 +56,7 @@ public function create(string $resourceClass, string $property, array $options =
break;
}

if ($doctrineClassMetadata instanceof ClassMetadataInfo) {
if ($doctrineClassMetadata instanceof ClassMetadata) {
$writable = $doctrineClassMetadata->isIdentifierNatural();
} else {
$writable = false;
Expand All @@ -67,10 +68,13 @@ public function create(string $resourceClass, string $property, array $options =
}
}

if ($doctrineClassMetadata instanceof ClassMetadataInfo && \in_array($property, $doctrineClassMetadata->getFieldNames(), true)) {
/** @var mixed[] */
if ($doctrineClassMetadata instanceof ClassMetadata && \in_array($property, $doctrineClassMetadata->getFieldNames(), true)) {
$fieldMapping = $doctrineClassMetadata->getFieldMapping($property);
$propertyMetadata = $propertyMetadata->withDefault($fieldMapping['options']['default'] ?? $propertyMetadata->getDefault());
if (class_exists(FieldMapping::class) && $fieldMapping instanceof FieldMapping) {
$propertyMetadata = $propertyMetadata->withDefault($fieldMapping->default ?? $propertyMetadata->getDefault());
} else {
$propertyMetadata = $propertyMetadata->withDefault($fieldMapping['options']['default'] ?? $propertyMetadata->getDefault());
}
}

return $propertyMetadata;
Expand Down
6 changes: 3 additions & 3 deletions src/Doctrine/Orm/State/LinksHandlerTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
use ApiPlatform\Doctrine\Orm\Util\QueryNameGenerator;
use ApiPlatform\Metadata\Link;
use ApiPlatform\Metadata\Operation;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\QueryBuilder;

/**
Expand Down Expand Up @@ -83,7 +83,7 @@ private function handleLinks(QueryBuilder $queryBuilder, array $identifiers, Que
$associationMapping = $fromClassMetadata->getAssociationMapping($link->getFromProperty()); // @phpstan-ignore-line
$relationType = $associationMapping['type'];

if ($relationType & ClassMetadataInfo::TO_MANY) {
if ($relationType & ClassMetadata::TO_MANY) {
$nextAlias = $queryNameGenerator->generateJoinAlias($alias);
$whereClause = [];
foreach ($identifierProperties as $identifierProperty) {
Expand All @@ -100,7 +100,7 @@ private function handleLinks(QueryBuilder $queryBuilder, array $identifiers, Que
}

// A single-valued association path expression to an inverse side is not supported in DQL queries.
if ($relationType & ClassMetadataInfo::TO_ONE && !($associationMapping['isOwningSide'] ?? true)) {
if ($relationType & ClassMetadata::TO_ONE && !($associationMapping['isOwningSide'] ?? true)) {
$queryBuilder->innerJoin("$previousAlias.".$associationMapping['mappedBy'], $joinAlias);
} else {
$queryBuilder->join(
Expand Down
Loading

0 comments on commit d8e2d0c

Please sign in to comment.