diff --git a/.github/workflows/continuous-integration-optional.yml b/.github/workflows/continuous-integration-optional.yml index d7c2a47573..1d02ca95b7 100644 --- a/.github/workflows/continuous-integration-optional.yml +++ b/.github/workflows/continuous-integration-optional.yml @@ -136,5 +136,5 @@ jobs: - run: php bin/console doctrine:migrations:migrate --no-interaction -e test working-directory: api - - run: php bin/console doctrine:schema:validate -v -e test + - run: php bin/console doctrine:schema:validate --skip-sync -e test && php bin/console doctrine:migrations:up-to-date -e test && ! php bin/console doctrine:migrations:diff -e test --namespace DoctrineMigrations working-directory: api diff --git a/api/composer.json b/api/composer.json index 054e6b861d..aaaeaf15cf 100644 --- a/api/composer.json +++ b/api/composer.json @@ -10,7 +10,7 @@ "cweagans/composer-patches": "1.7.3", "doctrine/doctrine-bundle": "2.13.1", "doctrine/doctrine-migrations-bundle": "3.3.1", - "doctrine/orm": "2.20.0", + "doctrine/orm": "3.2.0", "exercise/htmlpurifier-bundle": "5.0", "friendsofsymfony/http-cache": "3.1.0", "friendsofsymfony/http-cache-bundle": "3.0.2", @@ -53,7 +53,7 @@ "require-dev": { "brianium/paratest": "v7.7.0", "friendsofphp/php-cs-fixer": "3.66.0", - "hautelook/alice-bundle": "2.13.0", + "hautelook/alice-bundle": "2.14.0", "justinrainbow/json-schema": "6.0.0", "php-coveralls/php-coveralls": "2.7.0", "phpspec/prophecy-phpunit": "2.3.0", diff --git a/api/composer.lock b/api/composer.lock index a5b7a52d45..9d20ea3af9 100644 --- a/api/composer.lock +++ b/api/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "6b7f9d4db93fd999e267f770dea212cd", + "content-hash": "d0769c8f36806e8dd3ffa8702685234f", "packages": [ { "name": "api-platform/core", @@ -795,47 +795,42 @@ }, { "name": "doctrine/dbal", - "version": "3.9.3", + "version": "4.2.1", "source": { "type": "git", "url": "https://github.com/doctrine/dbal.git", - "reference": "61446f07fcb522414d6cfd8b1c3e5f9e18c579ba" + "reference": "dadd35300837a3a2184bd47d403333b15d0a9bd0" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/dbal/zipball/61446f07fcb522414d6cfd8b1c3e5f9e18c579ba", - "reference": "61446f07fcb522414d6cfd8b1c3e5f9e18c579ba", + "url": "https://api.github.com/repos/doctrine/dbal/zipball/dadd35300837a3a2184bd47d403333b15d0a9bd0", + "reference": "dadd35300837a3a2184bd47d403333b15d0a9bd0", "shasum": "" }, "require": { - "composer-runtime-api": "^2", - "doctrine/cache": "^1.11|^2.0", "doctrine/deprecations": "^0.5.3|^1", - "doctrine/event-manager": "^1|^2", - "php": "^7.4 || ^8.0", + "php": "^8.1", "psr/cache": "^1|^2|^3", "psr/log": "^1|^2|^3" }, "require-dev": { "doctrine/coding-standard": "12.0.0", "fig/log-test": "^1", - "jetbrains/phpstorm-stubs": "2023.1", + "jetbrains/phpstorm-stubs": "2023.2", "phpstan/phpstan": "1.12.6", + "phpstan/phpstan-phpunit": "1.4.0", "phpstan/phpstan-strict-rules": "^1.6", - "phpunit/phpunit": "9.6.20", - "psalm/plugin-phpunit": "0.18.4", + "phpunit/phpunit": "10.5.30", + "psalm/plugin-phpunit": "0.19.0", "slevomat/coding-standard": "8.13.1", "squizlabs/php_codesniffer": "3.10.2", - "symfony/cache": "^5.4|^6.0|^7.0", - "symfony/console": "^4.4|^5.4|^6.0|^7.0", - "vimeo/psalm": "4.30.0" + "symfony/cache": "^6.3.8|^7.0", + "symfony/console": "^5.4|^6.3|^7.0", + "vimeo/psalm": "5.25.0" }, "suggest": { "symfony/console": "For helpful console commands such as SQL execution and import of files." }, - "bin": [ - "bin/doctrine-dbal" - ], "type": "library", "autoload": { "psr-4": { @@ -888,7 +883,7 @@ ], "support": { "issues": "https://github.com/doctrine/dbal/issues", - "source": "https://github.com/doctrine/dbal/tree/3.9.3" + "source": "https://github.com/doctrine/dbal/tree/4.2.1" }, "funding": [ { @@ -904,7 +899,7 @@ "type": "tidelift" } ], - "time": "2024-10-10T17:56:43+00:00" + "time": "2024-10-10T18:01:27+00:00" }, { "name": "doctrine/deprecations", @@ -1597,63 +1592,48 @@ }, { "name": "doctrine/orm", - "version": "2.20.0", + "version": "3.2.0", "source": { "type": "git", "url": "https://github.com/doctrine/orm.git", - "reference": "8ed6c2234aba019f9737a6bcc9516438e62da27c" + "reference": "37946d3a21ddf837c0d84f8156ee60a92102e332" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/doctrine/orm/zipball/8ed6c2234aba019f9737a6bcc9516438e62da27c", - "reference": "8ed6c2234aba019f9737a6bcc9516438e62da27c", + "url": "https://api.github.com/repos/doctrine/orm/zipball/37946d3a21ddf837c0d84f8156ee60a92102e332", + "reference": "37946d3a21ddf837c0d84f8156ee60a92102e332", "shasum": "" }, "require": { "composer-runtime-api": "^2", - "doctrine/cache": "^1.12.1 || ^2.1.1", - "doctrine/collections": "^1.5 || ^2.1", - "doctrine/common": "^3.0.3", - "doctrine/dbal": "^2.13.1 || ^3.2", + "doctrine/collections": "^2.2", + "doctrine/dbal": "^3.8.2 || ^4", "doctrine/deprecations": "^0.5.3 || ^1", "doctrine/event-manager": "^1.2 || ^2", "doctrine/inflector": "^1.4 || ^2.0", "doctrine/instantiator": "^1.3 || ^2", - "doctrine/lexer": "^2 || ^3", - "doctrine/persistence": "^2.4 || ^3", + "doctrine/lexer": "^3", + "doctrine/persistence": "^3.3.1", "ext-ctype": "*", - "php": "^7.1 || ^8.0", + "php": "^8.1", "psr/cache": "^1 || ^2 || ^3", - "symfony/console": "^4.2 || ^5.0 || ^6.0 || ^7.0", - "symfony/polyfill-php72": "^1.23", - "symfony/polyfill-php80": "^1.16" - }, - "conflict": { - "doctrine/annotations": "<1.13 || >= 3.0" + "symfony/console": "^5.4 || ^6.0 || ^7.0", + "symfony/var-exporter": "^6.3.9 || ^7.0" }, "require-dev": { - "doctrine/annotations": "^1.13 || ^2", - "doctrine/coding-standard": "^9.0.2 || ^12.0", - "phpbench/phpbench": "^0.16.10 || ^1.0", - "phpstan/extension-installer": "~1.1.0 || ^1.4", - "phpstan/phpstan": "~1.4.10 || 1.12.6", - "phpstan/phpstan-deprecation-rules": "^1", - "phpunit/phpunit": "^7.5 || ^8.5 || ^9.6", + "doctrine/coding-standard": "^12.0", + "phpbench/phpbench": "^1.0", + "phpstan/phpstan": "1.11.1", + "phpunit/phpunit": "^10.4.0", "psr/log": "^1 || ^2 || ^3", "squizlabs/php_codesniffer": "3.7.2", - "symfony/cache": "^4.4 || ^5.4 || ^6.4 || ^7.0", - "symfony/var-exporter": "^4.4 || ^5.4 || ^6.2 || ^7.0", - "symfony/yaml": "^3.4 || ^4.0 || ^5.0 || ^6.0 || ^7.0", - "vimeo/psalm": "4.30.0 || 5.24.0" + "symfony/cache": "^5.4 || ^6.2 || ^7.0", + "vimeo/psalm": "5.24.0" }, "suggest": { "ext-dom": "Provides support for XSD validation for XML mapping files", - "symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0", - "symfony/yaml": "If you want to use YAML Metadata Mapping Driver" + "symfony/cache": "Provides cache support for Setup Tool with doctrine/cache 2.0" }, - "bin": [ - "bin/doctrine" - ], "type": "library", "autoload": { "psr-4": { @@ -1694,9 +1674,9 @@ ], "support": { "issues": "https://github.com/doctrine/orm/issues", - "source": "https://github.com/doctrine/orm/tree/2.20.0" + "source": "https://github.com/doctrine/orm/tree/3.2.0" }, - "time": "2024-10-11T11:47:24+00:00" + "time": "2024-05-23T14:27:52+00:00" }, { "name": "doctrine/persistence", @@ -10931,35 +10911,35 @@ }, { "name": "hautelook/alice-bundle", - "version": "2.13.0", + "version": "2.14.0", "source": { "type": "git", "url": "https://github.com/theofidry/AliceBundle.git", - "reference": "7b8cf62973853ec406ecb27f3b90b91a1b525a05" + "reference": "9b648956ffe4c39318dc61cbe8c2a7e209e9ab58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/theofidry/AliceBundle/zipball/7b8cf62973853ec406ecb27f3b90b91a1b525a05", - "reference": "7b8cf62973853ec406ecb27f3b90b91a1b525a05", + "url": "https://api.github.com/repos/theofidry/AliceBundle/zipball/9b648956ffe4c39318dc61cbe8c2a7e209e9ab58", + "reference": "9b648956ffe4c39318dc61cbe8c2a7e209e9ab58", "shasum": "" }, "require": { - "doctrine/data-fixtures": "^1.5", - "doctrine/doctrine-bundle": "^2.5", - "doctrine/orm": "^2.10.0", - "doctrine/persistence": "^2.2 || ^3.0", + "doctrine/data-fixtures": "^1.7", + "doctrine/doctrine-bundle": "^2.11.3", + "doctrine/orm": "^3.1", + "doctrine/persistence": "^3.3.1", "php": "^8.2", "psr/log": "^1.0 || ^2.0 || ^3.0", "symfony/finder": "^6.4 || ^7.0", "symfony/framework-bundle": "^6.4 || ^7.0", - "theofidry/alice-data-fixtures": "^1.5" + "theofidry/alice-data-fixtures": "^1.7" }, "require-dev": { "monolog/monolog": "^3.5", - "phpspec/prophecy": "^1.7", + "phpspec/prophecy": "^1.14.0", "phpspec/prophecy-phpunit": "^2.0", - "phpunit/phpunit": "^9.5", - "symfony/phpunit-bridge": "^6.4 || ^7.0" + "phpunit/phpunit": "^9.6.17", + "symfony/phpunit-bridge": "^6.4.4 || ^7.0" }, "type": "symfony-bundle", "extra": { @@ -10999,9 +10979,9 @@ ], "support": { "issues": "https://github.com/theofidry/AliceBundle/issues", - "source": "https://github.com/theofidry/AliceBundle/tree/2.13.0" + "source": "https://github.com/theofidry/AliceBundle/tree/2.14.0" }, - "time": "2023-12-03T23:53:29+00:00" + "time": "2024-03-08T19:55:04+00:00" }, { "name": "icecave/parity", diff --git a/api/src/HttpCache/PurgeHttpCacheListener.php b/api/src/HttpCache/PurgeHttpCacheListener.php index 94793afd1f..c3f5b8c989 100644 --- a/api/src/HttpCache/PurgeHttpCacheListener.php +++ b/api/src/HttpCache/PurgeHttpCacheListener.php @@ -33,7 +33,7 @@ use Doctrine\ORM\Event\OnFlushEventArgs; use Doctrine\ORM\Event\PreUpdateEventArgs; use Doctrine\ORM\Mapping\AssociationMapping; -use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\PersistentCollection; use FOS\HttpCacheBundle\CacheManager; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; @@ -53,7 +53,7 @@ public function __construct(private readonly IriConverterInterface|LegacyIriConv */ public function preUpdate(PreUpdateEventArgs $eventArgs): void { $changeSet = $eventArgs->getEntityChangeSet(); - $objectManager = method_exists($eventArgs, 'getObjectManager') ? $eventArgs->getObjectManager() : $eventArgs->getEntityManager(); + $objectManager = $eventArgs->getObjectManager(); $associationMappings = $objectManager->getClassMetadata(ClassUtils::getClass($eventArgs->getObject()))->getAssociationMappings(); foreach ($changeSet as $key => $value) { @@ -76,7 +76,12 @@ public function preUpdate(PreUpdateEventArgs $eventArgs): void { */ public function onFlush(OnFlushEventArgs $eventArgs): void { /** @var EntityManagerInterface */ - $em = method_exists($eventArgs, 'getObjectManager') ? $eventArgs->getObjectManager() : $eventArgs->getEntityManager(); + $em = $eventArgs->getObjectManager(); + + if (!$em instanceof EntityManagerInterface) { + return; + } + $uow = $em->getUnitOfWork(); foreach ($uow->getScheduledEntityInsertions() as $entity) { @@ -118,7 +123,7 @@ public function postFlush(): void { private function addTagsForManyToManyRelations($collection, $entities) { $associationMapping = $collection->getMapping(); - if (ClassMetadataInfo::MANY_TO_MANY !== $associationMapping['type']) { + if (ClassMetadata::MANY_TO_MANY !== $associationMapping['type']) { return; } @@ -222,15 +227,7 @@ private function gatherRelationTags(EntityManagerInterface $em, object $entity): $associationMappings = $em->getClassMetadata(ClassUtils::getClass($entity))->getAssociationMappings(); foreach ($associationMappings as $property => $associationMapping) { - // @phpstan-ignore-next-line - if (class_exists(AssociationMapping::class) && $associationMapping instanceof AssociationMapping && ($associationMapping->targetEntity ?? null) && !$this->resourceClassResolver->isResourceClass($associationMapping->targetEntity)) { - return; - } - - // @phpstan-ignore-next-line - if (\is_array($associationMapping) - && \array_key_exists('targetEntity', $associationMapping) - && !$this->resourceClassResolver->isResourceClass($associationMapping['targetEntity'])) { + if ($associationMapping instanceof AssociationMapping && ($associationMapping->targetEntity ?? null) && !$this->resourceClassResolver->isResourceClass($associationMapping->targetEntity)) { return; } diff --git a/api/src/Repository/UserRepository.php b/api/src/Repository/UserRepository.php index 6be84d88e1..0829c2a014 100644 --- a/api/src/Repository/UserRepository.php +++ b/api/src/Repository/UserRepository.php @@ -32,8 +32,8 @@ public function upgradePassword(PasswordAuthenticatedUserInterface $user, string } $user->password = $newHashedPassword; - $this->_em->persist($user); - $this->_em->flush(); + $this->getEntityManager()->persist($user); + $this->getEntityManager()->flush(); } /** @@ -41,7 +41,7 @@ public function upgradePassword(PasswordAuthenticatedUserInterface $user, string * @throws NoResultException */ public function loadUserByIdentifier(string $identifier): ?User { - $queryBuilder = $this->_em->createQueryBuilder(); + $queryBuilder = $this->getEntityManager()->createQueryBuilder(); $queryBuilder->select('user'); $queryBuilder->from(User::class, 'user'); $queryBuilder->join('user.profile', 'profile'); diff --git a/api/src/Serializer/Normalizer/RelatedCollectionLinkNormalizer.php b/api/src/Serializer/Normalizer/RelatedCollectionLinkNormalizer.php index fe57060406..af6b5690e9 100644 --- a/api/src/Serializer/Normalizer/RelatedCollectionLinkNormalizer.php +++ b/api/src/Serializer/Normalizer/RelatedCollectionLinkNormalizer.php @@ -16,9 +16,11 @@ use App\Metadata\Resource\OperationHelper; use App\Util\ClassInfoTrait; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\AssociationMapping; +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\Mapping\InverseSideMapping; use Doctrine\ORM\Mapping\MappingException; -use Doctrine\Persistence\Mapping\ClassMetadata; +use Doctrine\ORM\Mapping\OwningSideMapping; use Rize\UriTemplate; use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\PropertyAccess\PropertyAccessorInterface; @@ -168,8 +170,8 @@ protected function getRelatedCollectionHref($object, $rel, array $context, &$hre try { $classMetadata = $this->getClassMetadata($resourceClass); - if (!$classMetadata instanceof ClassMetadataInfo) { - throw new \RuntimeException("The class metadata for {$resourceClass} must be an instance of ClassMetadataInfo."); + if (!$classMetadata instanceof ClassMetadata) { + throw new \RuntimeException("The class metadata for {$resourceClass} must be an instance of ClassMetadata."); } $relationMetadata = $classMetadata->getAssociationMapping($rel); @@ -178,10 +180,8 @@ protected function getRelatedCollectionHref($object, $rel, array $context, &$hre return false; } - $relatedResourceClass = $relationMetadata['targetEntity']; - - $relatedFilterName = $relationMetadata['mappedBy']; - $relatedFilterName ??= $relationMetadata['inversedBy']; + $relatedResourceClass = $relationMetadata->targetEntity; + $relatedFilterName = $this->getRelatedProperty($relationMetadata); if (empty($relatedResourceClass) || empty($relatedFilterName)) { // The $resourceClass # $rel relation does not have both a targetEntity and a mappedBy or inversedBy property @@ -282,4 +282,16 @@ private function exactSearchFilterExists(string $resourceClass, mixed $propertyN && 'exact' === $filterDescription[$propertyName]['strategy']; })); } + + private function getRelatedProperty(AssociationMapping $mapping): ?string { + if ($mapping instanceof InverseSideMapping) { + return $mapping->mappedBy ?? null; + } + + if ($mapping instanceof OwningSideMapping) { + return $mapping->inversedBy ?? null; + } + + return null; + } } diff --git a/api/src/Types/Doctrine/UTCDateTimeType.php b/api/src/Types/Doctrine/UTCDateTimeType.php index ad59ea1bdd..f7fbe7a38f 100644 --- a/api/src/Types/Doctrine/UTCDateTimeType.php +++ b/api/src/Types/Doctrine/UTCDateTimeType.php @@ -2,10 +2,13 @@ namespace App\Types\Doctrine; +use DateTime; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\ConversionException; use Doctrine\DBAL\Types\DateTimeImmutableType; use Doctrine\DBAL\Types\DateTimeType; +use Doctrine\DBAL\Types\Exception\InvalidFormat; +use Doctrine\DBAL\Types\Exception\InvalidType; /** * Replacement for Doctrine's DateTime Type. @@ -31,7 +34,7 @@ class UTCDateTimeType extends DateTimeType { * * @template T */ - public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string { + public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): ?string { if (null === $value) { return null; } @@ -46,7 +49,11 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform): ?str return parent::convertToDatabaseValue($value, $platform); } - throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'DateTime']); + throw InvalidType::new( + $value, + static::class, + ['null', \DateTime::class], + ); } /** @@ -54,28 +61,33 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform): ?str * * @param T $value * - * @return (T is null ? null : \DateTimeInterface) + * @return (T is null ? null : \DateTime) * * @throws ConversionException * * @template T */ - public function convertToPHPValue($value, AbstractPlatform $platform): ?\DateTimeInterface { - if (null === $value || $value instanceof \DateTimeInterface) { + public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?\DateTime { + if (null === $value || $value instanceof \DateTime) { return $value; } - $val = \DateTime::createFromFormat($platform->getDateTimeFormatString(), $value, self::getUtc()); + $dateTime = \DateTime::createFromFormat($platform->getDateTimeFormatString(), $value, self::getUtc()); - if (!$val) { - throw ConversionException::conversionFailedFormat( + if (false !== $dateTime) { + return $dateTime; + } + + try { + return new \DateTime($value); + } catch (\Exception $e) { + throw InvalidFormat::new( $value, - $this->getName(), - $platform->getDateTimeFormatString() + static::class, + $platform->getDateTimeFormatString(), + $e, ); } - - return $val; } private static function getUtc(): \DateTimeZone { diff --git a/api/src/Types/Doctrine/UTCDateType.php b/api/src/Types/Doctrine/UTCDateType.php index 49fe9a38b5..a3b6054ccd 100644 --- a/api/src/Types/Doctrine/UTCDateType.php +++ b/api/src/Types/Doctrine/UTCDateType.php @@ -6,6 +6,7 @@ use Doctrine\DBAL\Types\ConversionException; use Doctrine\DBAL\Types\DateImmutableType; use Doctrine\DBAL\Types\DateType; +use Doctrine\DBAL\Types\Exception\InvalidFormat; class UTCDateType extends DateType { private static ?\DateTimeZone $utc = null; @@ -19,7 +20,7 @@ class UTCDateType extends DateType { * * @template T */ - public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string { + public function convertToDatabaseValue(mixed $value, AbstractPlatform $platform): ?string { if ($value instanceof \DateTime || $value instanceof \DateTimeImmutable) { $value = $value->setTimezone(self::getUtc()); } @@ -36,27 +37,27 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform): ?str * * @param T $value * - * @return (T is null ? null : \DateTimeInterface) + * @return (T is null ? null : \DateTime) * * @throws ConversionException * * @template T */ - public function convertToPHPValue($value, AbstractPlatform $platform): ?\DateTimeInterface { - if (null === $value || $value instanceof \DateTimeInterface) { + public function convertToPHPValue(mixed $value, AbstractPlatform $platform): ?\DateTime { + if (null === $value || $value instanceof \DateTime) { return $value; } - $val = \DateTime::createFromFormat('!'.$platform->getDateFormatString(), $value, self::getUtc()); - if (!$val) { - throw ConversionException::conversionFailedFormat( - $value, - $this->getName(), - $platform->getDateFormatString() - ); + $dateTime = \DateTime::createFromFormat('!'.$platform->getDateFormatString(), $value, self::getUtc()); + if (false !== $dateTime) { + return $dateTime; } - return $val; + throw InvalidFormat::new( + $value, + static::class, + $platform->getDateFormatString(), + ); } private static function getUtc(): \DateTimeZone { diff --git a/api/src/Util/IdGenerator.php b/api/src/Util/IdGenerator.php index a45db9d0e2..8ae71587ed 100644 --- a/api/src/Util/IdGenerator.php +++ b/api/src/Util/IdGenerator.php @@ -2,7 +2,7 @@ namespace App\Util; -use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Id\AbstractIdGenerator; class IdGenerator extends AbstractIdGenerator { @@ -10,7 +10,7 @@ public static function generateRandomHexString(int $length): string { return bin2hex(random_bytes($length / 2)); } - public function generate(EntityManager $em, $entity): string { + public function generateId(EntityManagerInterface $em, ?object $entity): mixed { return IdGenerator::generateRandomHexString(12); } } diff --git a/api/tests/Metadata/Resource/Factory/UriTemplateFactoryTest.php b/api/tests/Metadata/Resource/Factory/UriTemplateFactoryTest.php index b250fef235..9379bd627f 100644 --- a/api/tests/Metadata/Resource/Factory/UriTemplateFactoryTest.php +++ b/api/tests/Metadata/Resource/Factory/UriTemplateFactoryTest.php @@ -2,8 +2,8 @@ namespace App\Tests\Metadata\Resource\Factory; -use ApiPlatform\Api\FilterInterface; use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\FilterInterface; use ApiPlatform\Metadata\Get; use ApiPlatform\Metadata\GetCollection; use ApiPlatform\Metadata\IriConverterInterface; diff --git a/api/tests/Serializer/Normalizer/RelatedCollectionLinkNormalizerTest.php b/api/tests/Serializer/Normalizer/RelatedCollectionLinkNormalizerTest.php index 6cedb30333..d7f8ff12df 100644 --- a/api/tests/Serializer/Normalizer/RelatedCollectionLinkNormalizerTest.php +++ b/api/tests/Serializer/Normalizer/RelatedCollectionLinkNormalizerTest.php @@ -18,6 +18,7 @@ use Doctrine\Common\Collections\Collection; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping as ORM; +use Doctrine\ORM\Mapping\OneToManyAssociationMapping; use Doctrine\Persistence\ManagerRegistry; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; @@ -159,7 +160,13 @@ public function testNormalizeReplacesLinkArrayWithSingleFilteredCollectionLink() $resource = new ParentEntity(); $this->mockDecoratedNormalizer(); $this->mockNameConverter(); - $this->mockAssociationMetadata(['targetEntity' => Child::class, 'mappedBy' => 'parent']); + $this->mockAssociationMetadata(OneToManyAssociationMapping::fromMappingArray([ + 'targetEntity' => Child::class, + 'mappedBy' => 'parent', + 'fieldName' => 'children', + 'sourceEntity' => ParentEntity::class, + ])); + $this->mockRelatedResourceMetadata(['filters' => ['attribute_filter_something_something']]); $this->mockRelatedFilterDescription(['parent' => ['strategy' => 'exact']]); $this->mockGeneratedRoute(); @@ -231,7 +238,12 @@ public function testNormalizeReplacesSerializedNameLinkArray() { $this->mockRelatedResourceMetadata(['filters' => ['attribute_filter_something_something']]); $this->mockRelatedFilterDescription(['parent' => ['strategy' => 'exact']]); - $this->mockAssociationMetadata(['targetEntity' => Child::class, 'mappedBy' => 'parent']); + $this->mockAssociationMetadata(OneToManyAssociationMapping::fromMappingArray([ + 'targetEntity' => Child::class, + 'mappedBy' => 'parent', + 'fieldName' => 'children', + 'sourceEntity' => ParentEntity::class, + ])); $this->mockGeneratedRoute(); // when @@ -252,7 +264,12 @@ public function testNormalizeDoesntReplaceWhenFilterDoesntApplyToMappedProperty( $resource = new ParentEntity(); $this->mockDecoratedNormalizer(); $this->mockNameConverter(); - $this->mockAssociationMetadata(['targetEntity' => Child::class, 'mappedBy' => 'parent']); + $this->mockAssociationMetadata(OneToManyAssociationMapping::fromMappingArray([ + 'targetEntity' => Child::class, + 'mappedBy' => 'parent', + 'fieldName' => 'children', + 'sourceEntity' => ParentEntity::class, + ])); $this->mockRelatedResourceMetadata(['filters' => ['attribute_filter_something_something']]); $this->mockRelatedFilterDescription(['some_other_property' => ['strategy' => 'exact']]); $this->mockGeneratedRoute(); @@ -269,7 +286,12 @@ public function testNormalizeDoesntReplaceWhenEmptyFiltersArray() { $resource = new ParentEntity(); $this->mockDecoratedNormalizer(); $this->mockNameConverter(); - $this->mockAssociationMetadata(['targetEntity' => Child::class, 'mappedBy' => 'parent']); + $this->mockAssociationMetadata(OneToManyAssociationMapping::fromMappingArray([ + 'targetEntity' => Child::class, + 'mappedBy' => 'parent', + 'fieldName' => 'children', + 'sourceEntity' => ParentEntity::class, + ])); $this->mockRelatedResourceMetadata(['filters' => []]); $this->mockRelatedFilterDescription(['parent' => ['strategy' => 'exact']]); $this->mockGeneratedRoute(); @@ -286,7 +308,12 @@ public function testNormalizeDoesntReplaceWhenNoFilters() { $resource = new ParentEntity(); $this->mockDecoratedNormalizer(); $this->mockNameConverter(); - $this->mockAssociationMetadata(['targetEntity' => Child::class, 'mappedBy' => 'parent']); + $this->mockAssociationMetadata(OneToManyAssociationMapping::fromMappingArray([ + 'targetEntity' => Child::class, + 'mappedBy' => 'parent', + 'fieldName' => 'children', + 'sourceEntity' => ParentEntity::class, + ])); $this->mockRelatedResourceMetadata([]); $this->mockRelatedFilterDescription(['parent' => ['strategy' => 'exact']]); $this->mockGeneratedRoute(); @@ -303,7 +330,12 @@ public function testNormalizeDoesntReplaceWhenTargetEntityIsMissing() { $resource = new ParentEntity(); $this->mockDecoratedNormalizer(); $this->mockNameConverter(); - $this->mockAssociationMetadata(['targetEntity' => null, 'mappedBy' => 'parent']); + $this->mockAssociationMetadata(OneToManyAssociationMapping::fromMappingArray([ + 'targetEntity' => '', + 'mappedBy' => 'parent', + 'fieldName' => 'children', + 'sourceEntity' => ParentEntity::class, + ])); $this->mockRelatedResourceMetadata(['filters' => ['attribute_filter_something_something']]); $this->mockRelatedFilterDescription(['parent' => ['strategy' => 'exact']]); $this->mockGeneratedRoute(); @@ -342,7 +374,11 @@ public function testNormalizeDoesntReplaceWhenMappedByIsMissing() { $resource = new ParentEntity(); $this->mockDecoratedNormalizer(); $this->mockNameConverter(); - $this->mockAssociationMetadata(['targetEntity' => Child::class, 'mappedBy' => null, 'inversedBy' => null]); + $this->mockAssociationMetadata(OneToManyAssociationMapping::fromMappingArray([ + 'targetEntity' => Child::class, + 'fieldName' => 'children', + 'sourceEntity' => ParentEntity::class, + ])); $this->mockRelatedResourceMetadata(['filters' => ['attribute_filter_something_something']]); $this->mockRelatedFilterDescription(['parent' => ['strategy' => 'exact']]); $this->mockGeneratedRoute(); @@ -359,7 +395,12 @@ public function testNormalizeDoesntReplaceWhenFilterDoesntExistInContainer() { $resource = new ParentEntity(); $this->mockDecoratedNormalizer(); $this->mockNameConverter(); - $this->mockAssociationMetadata(['targetEntity' => Child::class, 'mappedBy' => 'parent']); + $this->mockAssociationMetadata(OneToManyAssociationMapping::fromMappingArray([ + 'targetEntity' => Child::class, + 'mappedBy' => 'parent', + 'fieldName' => 'children', + 'sourceEntity' => ParentEntity::class, + ])); $this->mockRelatedResourceMetadata(['filters' => ['attribute_filter_something_something']]); $this->filterInstance = null; $this->mockGeneratedRoute(); @@ -376,7 +417,12 @@ public function testNormalizeDoesntReplaceWhenFilterIsNotSearchFilter() { $resource = new ParentEntity(); $this->mockDecoratedNormalizer(); $this->mockNameConverter(); - $this->mockAssociationMetadata(['targetEntity' => Child::class, 'mappedBy' => 'parent']); + $this->mockAssociationMetadata(OneToManyAssociationMapping::fromMappingArray([ + 'targetEntity' => Child::class, + 'mappedBy' => 'parent', + 'fieldName' => 'children', + 'sourceEntity' => ParentEntity::class, + ])); $this->mockRelatedResourceMetadata(['filters' => ['attribute_filter_something_something']]); $this->filterInstance = new DateFilter($this->managerRegistryMock, null, ['filters' => ['attribute_filter_something_something']]); $this->mockGeneratedRoute(); @@ -393,7 +439,12 @@ public function testNormalizeDoesntReplaceWhenMissingGetCollectionOperation() { $resource = new ParentEntity(); $this->mockDecoratedNormalizer(); $this->mockNameConverter(); - $this->mockAssociationMetadata(['targetEntity' => Child::class, 'mappedBy' => 'parent']); + $this->mockAssociationMetadata(OneToManyAssociationMapping::fromMappingArray([ + 'targetEntity' => Child::class, + 'mappedBy' => 'parent', + 'fieldName' => 'children', + 'sourceEntity' => ParentEntity::class, + ])); $metadataCollection = new ResourceMetadataCollection('Dummy'); $metadataCollection->append((new ApiResource())->withOperations(new Operations([new Get()]))); diff --git a/api/tests/Types/Doctrine/BaseDateTypeTestCase.php b/api/tests/Types/Doctrine/BaseDateTypeTestCase.php index 1e47d9a9a5..0e2152468d 100644 --- a/api/tests/Types/Doctrine/BaseDateTypeTestCase.php +++ b/api/tests/Types/Doctrine/BaseDateTypeTestCase.php @@ -1,7 +1,7 @@ platform = $this->getMockForAbstractClass(AbstractPlatform::class); $this->currentTimezone = \date_default_timezone_get(); - - self::assertInstanceOf(Type::class, $this->type); } protected function tearDown(): void { @@ -55,29 +50,7 @@ public function testConvertDateTimeToPHPValue(): void { self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); } - /** - * Note that while \@see \DateTimeImmutable is supposed to be handled - * by @see \Doctrine\DBAL\Types\DateTimeImmutableType, previous DBAL versions handled it just fine. - * This test is just in place to prevent further regressions, even if the type is being misused. - */ - public function testConvertDateTimeImmutableToPHPValue(): void { - $date = new \DateTimeImmutable('now'); - - self::assertSame($date, $this->type->convertToPHPValue($date, $this->platform)); - } - - /** - * Note that while \@see \DateTimeImmutable is supposed to be handled - * by @see \Doctrine\DBAL\Types\DateTimeImmutableType, previous DBAL versions handled it just fine. - * This test is just in place to prevent further regressions, even if the type is being misused. - */ - public function testDateTimeImmutableConvertsToDatabaseValue(): void { - self::assertIsString($this->type->convertToDatabaseValue(new \DateTimeImmutable(), $this->platform)); - } - - /** - * @return mixed[][] - */ + /** @return mixed[][] */ public static function invalidPHPValuesProvider(): iterable { return [ [0], diff --git a/api/tests/Util/CamelPascalNamingStrategyTest.php b/api/tests/Util/CamelPascalNamingStrategyTest.php index 84cb01a92c..f5b58c8ab1 100644 --- a/api/tests/Util/CamelPascalNamingStrategyTest.php +++ b/api/tests/Util/CamelPascalNamingStrategyTest.php @@ -41,7 +41,7 @@ public function testPropertyToColumnName(string $input, string $output) { $strategy = new CamelPascalNamingStrategy(); // when - $result = $strategy->propertyToColumnName($input); + $result = $strategy->propertyToColumnName($input, ''); // then $this->assertEquals($output, $result);