Skip to content

Commit

Permalink
Merge pull request #6201 from soyuka/merge-main
Browse files Browse the repository at this point in the history
Merge 3.2
  • Loading branch information
soyuka committed Mar 5, 2024
2 parents 6d6f856 + 655c4cf commit 1cf3827
Show file tree
Hide file tree
Showing 31 changed files with 532 additions and 325 deletions.
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,18 @@ These namespaces are deprecated:

Most of the classes have moved to `ApiPlatform\Metadata`.

## v3.2.15

### Bug fixes

* [09aacf98a](https://github.com/api-platform/core/commit/09aacf98a2e4d0ffa00fbefa59cb2b31f35fbb54) fix(symfony): revert breaking change on attributes extractor (#6170)
* [4138cb7c0](https://github.com/api-platform/core/commit/4138cb7c031b38731162d99b3d43754251fc5913) fix(openapi): resource name parameter description (#6178)
* [5e4b6312a](https://github.com/api-platform/core/commit/5e4b6312a057ba4d1f45c395c7a215dc393acd80) fix(jsonschema): multiple type support (draft4) (#6171)
* [8535f9def](https://github.com/api-platform/core/commit/8535f9def6fbd2baff9cedc79c34103940eb4fca) fix(doctrine): read parent class properties on PUT (#6176)
* [a188c9473](https://github.com/api-platform/core/commit/a188c947396e0400ba6e1aadaa262d2e785fd941) fix(symfony): autoconfigure legacy alias fixes #6177 (#6181)
* [e7b442149](https://github.com/api-platform/core/commit/e7b4421496b58f7c3db414d11dd357a8dc759323) fix(validator): stop considering properties marked with NotBlank(allowNull=true) as required (#6184)
>>>>>>> upstream/3.2
## v3.2.14

### Bug fixes
Expand Down
2 changes: 1 addition & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,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
2 changes: 1 addition & 1 deletion src/Doctrine/Common/composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
},
"require-dev": {
"doctrine/mongodb-odm": "^2.6",
"doctrine/orm": "^2.17",
"doctrine/orm": "^2.17 || ^3.0",
"phpspec/prophecy-phpunit": "^2.0",
"phpunit/phpunit": "^10.0",
"symfony/phpunit-bridge": "^6.4 || ^7.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,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
10 changes: 9 additions & 1 deletion src/Doctrine/Orm/Metadata/Resource/DoctrineOrmLinkFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,16 @@ public function createLinksFromRelations(Metadata $operation): array
continue;
}

if (!$doctrineMetadata->isAssociationInverseSide($property)) {
continue;
}

if (!($mappedBy = $doctrineMetadata->getAssociationMappedByTargetField($property))) {
continue;
}

$relationClass = $doctrineMetadata->getAssociationTargetClass($property);
if (!($mappedBy = $doctrineMetadata->getAssociationMappedByTargetField($property)) || !$this->resourceClassResolver->isResourceClass($relationClass)) {
if (!$this->resourceClassResolver->isResourceClass($relationClass)) {
continue;
}

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\QueryNameGeneratorInterface;
use ApiPlatform\Metadata\Link;
use ApiPlatform\Metadata\Operation;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\QueryBuilder;
use Doctrine\Persistence\ManagerRegistry;

Expand Down Expand Up @@ -86,7 +86,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 @@ -103,7 +103,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 1cf3827

Please sign in to comment.