From 5e15094e8fb7232e0d1f154f12782666036ecb13 Mon Sep 17 00:00:00 2001 From: soyuka Date: Mon, 26 Apr 2021 08:40:47 +0200 Subject: [PATCH 1/8] fix(MongoDB): Handle deprecated setMetadataCacheImpl --- src/Test/DoctrineMongoDbOdmSetup.php | 6 +++++- src/Test/DoctrineMongoDbOdmTestCase.php | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/Test/DoctrineMongoDbOdmSetup.php b/src/Test/DoctrineMongoDbOdmSetup.php index 8e81982f1d2..6084576271e 100644 --- a/src/Test/DoctrineMongoDbOdmSetup.php +++ b/src/Test/DoctrineMongoDbOdmSetup.php @@ -62,7 +62,11 @@ public static function createConfiguration(bool $isDevMode = false, string $prox $cache = self::createCacheConfiguration($isDevMode, $proxyDir, $hydratorDir, $cache); $config = new Configuration(); - $config->setMetadataCacheImpl($cache); + if (method_exists($config, 'setMetadataCache')) { + $config->setMetadataCache($cache); + } else { + $config->setMetadataCacheImpl($cache); + } $config->setProxyDir($proxyDir); $config->setHydratorDir($hydratorDir); $config->setProxyNamespace('DoctrineProxies'); diff --git a/src/Test/DoctrineMongoDbOdmTestCase.php b/src/Test/DoctrineMongoDbOdmTestCase.php index 36907e29a27..59f23c30e20 100644 --- a/src/Test/DoctrineMongoDbOdmTestCase.php +++ b/src/Test/DoctrineMongoDbOdmTestCase.php @@ -39,7 +39,11 @@ public static function createTestDocumentManager($paths = []) $config->setProxyNamespace('SymfonyTests\Doctrine'); $config->setHydratorNamespace('SymfonyTests\Doctrine'); $config->setMetadataDriverImpl(new AnnotationDriver(new AnnotationReader(), $paths)); - $config->setMetadataCacheImpl(new ArrayCache()); + if (method_exists($config, 'setMetadataCache')) { + $config->setMetadataCache(new ArrayCache()); + } else { + $config->setMetadataCacheImpl(new ArrayCache()); + } return DocumentManager::create(null, $config); } From 3c797c1262fd59bdda85df9c1108c0ccf839e0f0 Mon Sep 17 00:00:00 2001 From: Sullivan SENECHAL Date: Mon, 26 Apr 2021 11:20:37 +0200 Subject: [PATCH 2/8] chore(open-api-factory): unused variable removal (#4245) --- src/OpenApi/Factory/OpenApiFactory.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/OpenApi/Factory/OpenApiFactory.php b/src/OpenApi/Factory/OpenApiFactory.php index 7edebffd5ea..e126e094b0e 100644 --- a/src/OpenApi/Factory/OpenApiFactory.php +++ b/src/OpenApi/Factory/OpenApiFactory.php @@ -90,7 +90,6 @@ public function __invoke(array $context = []): OpenApi foreach ($this->resourceNameCollectionFactory->create() as $resourceClass) { $resourceMetadata = $this->resourceMetadataFactory->create($resourceClass); - $resourceShortName = $resourceMetadata->getShortName(); // Items needs to be parsed first to be able to reference the lines from the collection operation $this->collectPaths($resourceMetadata, $resourceClass, OperationType::ITEM, $context, $paths, $links, $schemas); From 8aba012e7a8c8a2cad2e6ffd4381d2dfc3c3e51b Mon Sep 17 00:00:00 2001 From: Guilliam Xavier Date: Mon, 26 Apr 2021 12:01:00 +0200 Subject: [PATCH 3/8] Fix undefined steps in Swagger Behat tests (#4246) --- features/swagger/docs.feature | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/features/swagger/docs.feature b/features/swagger/docs.feature index c9e0111fee7..9b14c8353c6 100644 --- a/features/swagger/docs.feature +++ b/features/swagger/docs.feature @@ -57,8 +57,8 @@ Feature: Documentation support And the JSON node "paths./api/custom-call/{id}.get" should exist And the JSON node "paths./api/custom-call/{id}.put" should exist # Properties - And "id" property exists for the Swagger class "Dummy" - And "name" property is required for Swagger class "Dummy" + And the "id" property exists for the Swagger class "Dummy" + And the "name" property is required for the Swagger class "Dummy" # Filters And the JSON node "paths./dummies.get.parameters[0].name" should be equal to "dummyBoolean" And the JSON node "paths./dummies.get.parameters[0].in" should be equal to "query" From 13112d3537de023cd8fce402eb447c9de9186d84 Mon Sep 17 00:00:00 2001 From: llupa <41073314+llupa@users.noreply.github.com> Date: Tue, 27 Apr 2021 15:20:02 +0200 Subject: [PATCH 4/8] Update Hydra JsonSchema context property possible types (#4223) --- CHANGELOG.md | 1 + src/Hydra/JsonSchema/SchemaFactory.php | 22 +++++++++- .../Symfony/Bundle/Test/ApiTestCaseTest.php | 42 ++++++++++++++----- tests/Hydra/JsonSchema/SchemaFactoryTest.php | 24 +++++++++++ 4 files changed, 77 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2b89af2652..440b5515c98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## 2.6.5 +* JsonSchema: Update Hydra `@context` property possible types * Filter validation: Fix issue in Required filter validator with dot notation (#4221) * OpenAPI: Fix notice/warning for `response` without `content` in the `openapi_context` (#4210) * OpenAPI: Do not use output for request body (#4213) diff --git a/src/Hydra/JsonSchema/SchemaFactory.php b/src/Hydra/JsonSchema/SchemaFactory.php index c3f82538df2..a3c95897509 100644 --- a/src/Hydra/JsonSchema/SchemaFactory.php +++ b/src/Hydra/JsonSchema/SchemaFactory.php @@ -13,6 +13,7 @@ namespace ApiPlatform\Core\Hydra\JsonSchema; +use ApiPlatform\Core\JsonLd\ContextBuilder; use ApiPlatform\Core\JsonSchema\Schema; use ApiPlatform\Core\JsonSchema\SchemaFactory as BaseSchemaFactory; use ApiPlatform\Core\JsonSchema\SchemaFactoryInterface; @@ -35,7 +36,26 @@ final class SchemaFactory implements SchemaFactoryInterface '@type' => self::BASE_PROP, ]; private const BASE_ROOT_PROPS = [ - '@context' => self::BASE_PROP, + '@context' => [ + 'readOnly' => true, + 'oneOf' => [ + ['type' => 'string'], + [ + 'type' => 'object', + 'properties' => [ + '@vocab' => [ + 'type' => 'string', + ], + 'hydra' => [ + 'type' => 'string', + 'enum' => [ContextBuilder::HYDRA_NS], + ], + ], + 'required' => ['@vocab', 'hydra'], + 'additionalProperties' => true, + ], + ], + ], ] + self::BASE_PROPS; private $schemaFactory; diff --git a/tests/Bridge/Symfony/Bundle/Test/ApiTestCaseTest.php b/tests/Bridge/Symfony/Bundle/Test/ApiTestCaseTest.php index 7d8e3c37ecb..12fa9c00296 100644 --- a/tests/Bridge/Symfony/Bundle/Test/ApiTestCaseTest.php +++ b/tests/Bridge/Symfony/Bundle/Test/ApiTestCaseTest.php @@ -16,6 +16,7 @@ use ApiPlatform\Core\Bridge\Symfony\Bundle\Test\ApiTestCase; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\Dummy as DummyDocument; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\Dummy; +use ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity\DummyDtoInputOutput; use ApiPlatform\Core\Tests\Fixtures\TestBundle\Model\ResourceInterface; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Tools\SchemaTool; @@ -137,6 +138,21 @@ public function testAssertMatchesResourceItemJsonSchema(): void $this->assertMatchesResourceItemJsonSchema(ResourceInterface::class); } + public function testAssertMatchesResourceItemJsonSchemaOutput(): void + { + $this->recreateSchema(); + + /** @var EntityManagerInterface $manager */ + $manager = self::$container->get('doctrine')->getManager(); + $dummyDtoInputOutput = new DummyDtoInputOutput(); + $dummyDtoInputOutput->str = 'lorem'; + $dummyDtoInputOutput->num = 54; + $manager->persist($dummyDtoInputOutput); + $manager->flush(); + self::createClient()->request('GET', '/dummy_dto_input_outputs/1'); + $this->assertMatchesResourceItemJsonSchema(DummyDtoInputOutput::class); + } + // Next tests have been imported from dms/phpunit-arraysubset-asserts, because the original constraint has been deprecated. public function testAssertArraySubsetPassesStrictConfig(): void @@ -160,17 +176,7 @@ public function testAssertArraySubsetDoesNothingForValidScenario(): void public function testFindIriBy(): void { - self::bootKernel(); - /** - * @var EntityManagerInterface - */ - $manager = self::$container->get('doctrine')->getManager(); - /** @var \Doctrine\ORM\Mapping\ClassMetadata[] $classes */ - $classes = $manager->getMetadataFactory()->getAllMetadata(); - $schemaTool = new SchemaTool($manager); - - $schemaTool->dropSchema($classes); - $schemaTool->createSchema($classes); + $this->recreateSchema(); self::createClient()->request('POST', '/dummies', [ 'headers' => [ @@ -185,4 +191,18 @@ public function testFindIriBy(): void $this->assertMatchesRegularExpression('~^/dummies/\d+~', self::findIriBy($resource, ['name' => 'Kevin'])); $this->assertNull(self::findIriBy($resource, ['name' => 'not-exist'])); } + + private function recreateSchema(): void + { + self::bootKernel(); + + /** @var EntityManagerInterface $manager */ + $manager = self::$container->get('doctrine')->getManager(); + /** @var \Doctrine\ORM\Mapping\ClassMetadata[] $classes */ + $classes = $manager->getMetadataFactory()->getAllMetadata(); + $schemaTool = new SchemaTool($manager); + + $schemaTool->dropSchema($classes); + $schemaTool->createSchema($classes); + } } diff --git a/tests/Hydra/JsonSchema/SchemaFactoryTest.php b/tests/Hydra/JsonSchema/SchemaFactoryTest.php index 5c29c60ae6b..598776381d5 100644 --- a/tests/Hydra/JsonSchema/SchemaFactoryTest.php +++ b/tests/Hydra/JsonSchema/SchemaFactoryTest.php @@ -15,6 +15,7 @@ use ApiPlatform\Core\Api\OperationType; use ApiPlatform\Core\Hydra\JsonSchema\SchemaFactory; +use ApiPlatform\Core\JsonLd\ContextBuilder; use ApiPlatform\Core\JsonSchema\Schema; use ApiPlatform\Core\JsonSchema\SchemaFactory as BaseSchemaFactory; use ApiPlatform\Core\JsonSchema\TypeFactoryInterface; @@ -79,6 +80,29 @@ public function testHasRootDefinitionKeyBuildSchema(): void $this->assertArrayHasKey('properties', $definitions[$rootDefinitionKey]); $properties = $resultSchema['definitions'][$rootDefinitionKey]['properties']; $this->assertArrayHasKey('@context', $properties); + $this->assertSame( + [ + 'readOnly' => true, + 'oneOf' => [ + ['type' => 'string'], + [ + 'type' => 'object', + 'properties' => [ + '@vocab' => [ + 'type' => 'string', + ], + 'hydra' => [ + 'type' => 'string', + 'enum' => [ContextBuilder::HYDRA_NS], + ], + ], + 'required' => ['@vocab', 'hydra'], + 'additionalProperties' => true, + ], + ], + ], + $properties['@context'] + ); $this->assertArrayHasKey('@type', $properties); $this->assertArrayHasKey('@id', $properties); } From 1be4676e322310779217bfe789cba9fe2b2e1bcb Mon Sep 17 00:00:00 2001 From: David Bennett Date: Tue, 27 Apr 2021 14:37:08 +0100 Subject: [PATCH 5/8] [GraphQL] Fix `FieldsBuilder` not always fully unwrapping a type before deciding if a resolver is needed. (#4251) --- CHANGELOG.md | 1 + src/GraphQl/Type/FieldsBuilder.php | 2 +- tests/GraphQl/Type/FieldsBuilderTest.php | 19 +++++++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 440b5515c98..6a756f7c07a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ * Serializer: Convert internal error to HTTP 400 in Ramsey uuid denormalization from invalid body string (#4200) * Symfony: Add tests with Symfony Uuid (#4230) * OpenAPI: Allow to set extensionProperties with YAML schema definition (#4228) +* GraphQL: Fix `FieldsBuilder` not fully unwrapping nested types before deciding if a resolver is needed (#4251) ## 2.6.4 diff --git a/src/GraphQl/Type/FieldsBuilder.php b/src/GraphQl/Type/FieldsBuilder.php index aa462454c73..a082bdf27c5 100644 --- a/src/GraphQl/Type/FieldsBuilder.php +++ b/src/GraphQl/Type/FieldsBuilder.php @@ -276,7 +276,7 @@ private function getResourceFieldConfiguration(?string $property, ?string $field return null; } - $graphqlWrappedType = $graphqlType instanceof WrappingType ? $graphqlType->getWrappedType() : $graphqlType; + $graphqlWrappedType = $graphqlType instanceof WrappingType ? $graphqlType->getWrappedType(true) : $graphqlType; $isStandardGraphqlType = \in_array($graphqlWrappedType, GraphQLType::getStandardTypes(), true); if ($isStandardGraphqlType) { $resourceClass = ''; diff --git a/tests/GraphQl/Type/FieldsBuilderTest.php b/tests/GraphQl/Type/FieldsBuilderTest.php index df2f13f055a..82561bf2039 100644 --- a/tests/GraphQl/Type/FieldsBuilderTest.php +++ b/tests/GraphQl/Type/FieldsBuilderTest.php @@ -505,6 +505,7 @@ public function testGetResourceObjectTypeFields(string $resourceClass, ResourceM $this->typeConverterProphecy->convertType(Argument::type(Type::class), Argument::type('bool'), null, $mutationName, null, '', $resourceClass, $propertyName, 1)->willReturn(GraphQLType::string()); $this->typeConverterProphecy->convertType(Argument::type(Type::class), Argument::type('bool'), null, null, $subscriptionName, '', $resourceClass, $propertyName, 1)->willReturn(GraphQLType::string()); $this->typeConverterProphecy->convertType(Argument::type(Type::class), true, null, $mutationName, null, 'subresourceClass', $propertyName, 1)->willReturn(GraphQLType::string()); + $this->typeConverterProphecy->convertType(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING)), Argument::type('bool'), $queryName, null, null, '', $resourceClass, $propertyName, 1)->willReturn(GraphQLType::nonNull(GraphQLType::listOf(GraphQLType::nonNull(GraphQLType::string())))); } $this->typesContainerProphecy->has('NotRegisteredType')->willReturn(false); $this->typesContainerProphecy->all()->willReturn([]); @@ -592,6 +593,24 @@ public function resourceObjectTypeFieldsProvider(): array ], ], ], + 'query with simple non-null string array property' => ['resourceClass', new ResourceMetadata(), + [ + 'property' => new PropertyMetadata(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING)), null, true, false), + ], + false, 'item_query', null, null, null, + [ + 'id' => [ + 'type' => GraphQLType::nonNull(GraphQLType::id()), + ], + 'property' => [ + 'type' => GraphQLType::nonNull(GraphQLType::listOf(GraphQLType::nonNull(GraphQLType::string()))), + 'description' => null, + 'args' => [], + 'resolve' => null, + 'deprecationReason' => null, + ], + ], + ], 'mutation non input' => ['resourceClass', new ResourceMetadata(), [ 'property' => new PropertyMetadata(), From dca12db195b27de84450a2a289807b1f86a0d66c Mon Sep 17 00:00:00 2001 From: Antoine Bluchet Date: Fri, 30 Apr 2021 11:11:00 +0200 Subject: [PATCH 6/8] chore(phpunit): migrate phpunit.xml schema (#4255) --- phpunit.xml.dist | 32 +++++++++++++------------------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/phpunit.xml.dist b/phpunit.xml.dist index 7b52597293e..24793a48189 100644 --- a/phpunit.xml.dist +++ b/phpunit.xml.dist @@ -1,12 +1,6 @@ - - + @@ -25,19 +19,19 @@ - - + + . - - features - tests - vendor - src/Bridge/NelmioApiDoc - src/Bridge/FosUser - src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php - - - + + + features + tests + vendor + src/Bridge/NelmioApiDoc + src/Bridge/FosUser + src/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php + + From f1f3ba9cd9206ac6931ec9869b10ead75648c0e0 Mon Sep 17 00:00:00 2001 From: Antoine Bluchet Date: Fri, 30 Apr 2021 11:21:38 +0200 Subject: [PATCH 7/8] test(mongodb): use MatchStage instead of Match (conflicts with php8) (#4253) --- .github/workflows/ci.yml | 2 +- composer.json | 4 ++-- .../Doctrine/MongoDbOdm/Extension/PaginationExtensionTest.php | 2 +- tests/Bridge/Doctrine/MongoDbOdm/ItemDataProviderTest.php | 2 +- .../Doctrine/MongoDbOdm/SubresourceDataProviderTest.php | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b2be7812e4f..1b3c4a40621 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -129,7 +129,7 @@ jobs: if: matrix.coverage run: echo "COVERAGE=1" >> $GITHUB_ENV - name: Remove Doctrine MongoDB ODM - if: (startsWith(matrix.php, '7.1') || startsWith(matrix.php, '8.0')) + if: (startsWith(matrix.php, '7.1')) run: | composer remove --dev --no-interaction --no-progress --no-update --ansi \ doctrine/mongodb-odm \ diff --git a/composer.json b/composer.json index 97df41a39bf..0f2fa18a40b 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,7 @@ "doctrine/common": "^2.11 || ^3.0", "doctrine/data-fixtures": "^1.2.2", "doctrine/doctrine-bundle": "^1.12 || ^2.0", - "doctrine/mongodb-odm": "^2.0", + "doctrine/mongodb-odm": "^2.2", "doctrine/mongodb-odm-bundle": "^4.0", "doctrine/orm": "^2.6.4 || ^3.0", "elasticsearch/elasticsearch": "^6.0 || ^7.0", @@ -86,7 +86,7 @@ }, "conflict": { "doctrine/common": "<2.7", - "doctrine/mongodb-odm": "<2.0", + "doctrine/mongodb-odm": "<2.2", "doctrine/persistence": "<1.3" }, "suggest": { diff --git a/tests/Bridge/Doctrine/MongoDbOdm/Extension/PaginationExtensionTest.php b/tests/Bridge/Doctrine/MongoDbOdm/Extension/PaginationExtensionTest.php index bf020e09db5..c45c6eaa893 100644 --- a/tests/Bridge/Doctrine/MongoDbOdm/Extension/PaginationExtensionTest.php +++ b/tests/Bridge/Doctrine/MongoDbOdm/Extension/PaginationExtensionTest.php @@ -27,7 +27,7 @@ use Doctrine\ODM\MongoDB\Aggregation\Builder; use Doctrine\ODM\MongoDB\Aggregation\Stage\Count; use Doctrine\ODM\MongoDB\Aggregation\Stage\Facet; -use Doctrine\ODM\MongoDB\Aggregation\Stage\Match as AggregationMatch; +use Doctrine\ODM\MongoDB\Aggregation\Stage\MatchStage as AggregationMatch; use Doctrine\ODM\MongoDB\Aggregation\Stage\Skip; use Doctrine\ODM\MongoDB\DocumentManager; use Doctrine\ODM\MongoDB\Iterator\Iterator; diff --git a/tests/Bridge/Doctrine/MongoDbOdm/ItemDataProviderTest.php b/tests/Bridge/Doctrine/MongoDbOdm/ItemDataProviderTest.php index b38d3cd1073..264301871b8 100644 --- a/tests/Bridge/Doctrine/MongoDbOdm/ItemDataProviderTest.php +++ b/tests/Bridge/Doctrine/MongoDbOdm/ItemDataProviderTest.php @@ -28,7 +28,7 @@ use ApiPlatform\Core\Tests\Fixtures\TestBundle\Document\Dummy; use ApiPlatform\Core\Tests\ProphecyTrait; use Doctrine\ODM\MongoDB\Aggregation\Builder; -use Doctrine\ODM\MongoDB\Aggregation\Stage\Match as AggregationMatch; +use Doctrine\ODM\MongoDB\Aggregation\Stage\MatchStage as AggregationMatch; use Doctrine\ODM\MongoDB\Iterator\Iterator; use Doctrine\ODM\MongoDB\Mapping\ClassMetadata; use Doctrine\ODM\MongoDB\Repository\DocumentRepository; diff --git a/tests/Bridge/Doctrine/MongoDbOdm/SubresourceDataProviderTest.php b/tests/Bridge/Doctrine/MongoDbOdm/SubresourceDataProviderTest.php index 879a630431c..cda11a88882 100644 --- a/tests/Bridge/Doctrine/MongoDbOdm/SubresourceDataProviderTest.php +++ b/tests/Bridge/Doctrine/MongoDbOdm/SubresourceDataProviderTest.php @@ -31,7 +31,7 @@ use ApiPlatform\Core\Tests\ProphecyTrait; use Doctrine\ODM\MongoDB\Aggregation\Builder; use Doctrine\ODM\MongoDB\Aggregation\Stage\Lookup; -use Doctrine\ODM\MongoDB\Aggregation\Stage\Match as AggregationMatch; +use Doctrine\ODM\MongoDB\Aggregation\Stage\MatchStage as AggregationMatch; use Doctrine\ODM\MongoDB\DocumentManager; use Doctrine\ODM\MongoDB\Iterator\Iterator; use Doctrine\ODM\MongoDB\Mapping\ClassMetadata; From 166f05a9a4c7b4522f43ca9323d1df9906da7cc5 Mon Sep 17 00:00:00 2001 From: Antoine Bluchet Date: Fri, 30 Apr 2021 12:38:22 +0200 Subject: [PATCH 8/8] docs: use conventional commits (#4256) --- CONTRIBUTING.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 88533097f08..4ec00f91b66 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -77,6 +77,32 @@ When you send a PR, just make sure that: that you did not make in your PR, you're doing it wrong. * Also don't forget to add a comment when you update a PR with a ping to [the maintainers](https://github.com/orgs/api-platform/people), so he/she will get a notification. +The commit messages must follow the [Conventional Commits specification](https://www.conventionalcommits.org/). +The following types are allowed: + +* `fix`: bug fix +* `feat`: new feature +* `docs`: change in the documentation +* `spec`: spec change +* `test`: test-related change +* `perf`: performance optimization +* `ci`: CI-related change +* `chore`: updating dependencies and related changes + +Examples: + + fix(metadata): resource identifiers from properties + + feat(validation): introduce a number constraint + + feat(metadata)!: new resource metadata system, BC break + + docs(doctrine): search filter on uuids + + test(doctrine): mongodb disambiguation + +We strongly recommend the use of a scope on API Platform core. + ### Tests On `api-platform/core` there are two kinds of tests: unit (`phpunit` through `simple-phpunit`) and integration tests (`behat`).