From d9cf112d48922f8e073a57a2bc5dd884c5c8f3cf Mon Sep 17 00:00:00 2001 From: aaa2000 Date: Mon, 3 Nov 2025 12:23:02 +0100 Subject: [PATCH] feat(serializer): remove pagination attributes when explicitly disabled --- src/Hal/JsonSchema/SchemaFactory.php | 68 ++-- src/Hydra/JsonSchema/SchemaFactory.php | 90 ++--- .../Tests/JsonSchema/SchemaFactoryTest.php | 25 +- src/JsonApi/JsonSchema/SchemaFactory.php | 130 ++++--- .../Tests/JsonSchema/SchemaFactoryTest.php | 29 +- .../Entity/PaginationDisabledEntity.php | 37 ++ tests/Functional/PaginationDisabledTest.php | 317 ++++++++++++++++++ 7 files changed, 559 insertions(+), 137 deletions(-) create mode 100644 tests/Fixtures/TestBundle/Entity/PaginationDisabledEntity.php create mode 100644 tests/Functional/PaginationDisabledTest.php diff --git a/src/Hal/JsonSchema/SchemaFactory.php b/src/Hal/JsonSchema/SchemaFactory.php index 8075bd40f81..d2cc4b3a0c3 100644 --- a/src/Hal/JsonSchema/SchemaFactory.php +++ b/src/Hal/JsonSchema/SchemaFactory.php @@ -35,6 +35,7 @@ final class SchemaFactory implements SchemaFactoryInterface, SchemaFactoryAwareI use SchemaUriPrefixTrait; private const COLLECTION_BASE_SCHEMA_NAME = 'HalCollectionBaseSchema'; + private const COLLECTION_BASE_SCHEMA_NAME_NO_PAGINATION = 'HalCollectionBaseSchemaNoPagination'; private const HREF_PROP = [ 'href' => [ @@ -122,10 +123,14 @@ public function buildSchema(string $className, string $format = 'jsonhal', strin } if (($schema['type'] ?? '') === 'array') { - if (!isset($definitions[self::COLLECTION_BASE_SCHEMA_NAME])) { - $definitions[self::COLLECTION_BASE_SCHEMA_NAME] = [ + if (!isset($definitions[self::COLLECTION_BASE_SCHEMA_NAME_NO_PAGINATION])) { + $definitions[self::COLLECTION_BASE_SCHEMA_NAME_NO_PAGINATION] = [ 'type' => 'object', 'properties' => [ + 'totalItems' => [ + 'type' => 'integer', + 'minimum' => 0, + ], '_embedded' => [ 'anyOf' => [ [ @@ -139,14 +144,6 @@ public function buildSchema(string $className, string $format = 'jsonhal', strin ['type' => 'object'], ], ], - 'totalItems' => [ - 'type' => 'integer', - 'minimum' => 0, - ], - 'itemsPerPage' => [ - 'type' => 'integer', - 'minimum' => 0, - ], '_links' => [ 'type' => 'object', 'properties' => [ @@ -154,26 +151,45 @@ public function buildSchema(string $className, string $format = 'jsonhal', strin 'type' => 'object', 'properties' => self::HREF_PROP, ], - 'first' => [ - 'type' => 'object', - 'properties' => self::HREF_PROP, - ], - 'last' => [ - 'type' => 'object', - 'properties' => self::HREF_PROP, - ], - 'next' => [ - 'type' => 'object', - 'properties' => self::HREF_PROP, + ], + ], + ], + 'required' => ['_links', '_embedded'], + ]; + + $definitions[self::COLLECTION_BASE_SCHEMA_NAME] = [ + 'allOf' => [ + ['$ref' => $prefix.self::COLLECTION_BASE_SCHEMA_NAME_NO_PAGINATION], + [ + 'type' => 'object', + 'properties' => [ + 'itemsPerPage' => [ + 'type' => 'integer', + 'minimum' => 0, ], - 'previous' => [ - 'type' => 'object', - 'properties' => self::HREF_PROP, + '_links' => [ + 'properties' => [ + 'first' => [ + 'type' => 'object', + 'properties' => self::HREF_PROP, + ], + 'last' => [ + 'type' => 'object', + 'properties' => self::HREF_PROP, + ], + 'next' => [ + 'type' => 'object', + 'properties' => self::HREF_PROP, + ], + 'previous' => [ + 'type' => 'object', + 'properties' => self::HREF_PROP, + ], + ], ], ], ], ], - 'required' => ['_links', '_embedded'], ]; } @@ -182,7 +198,7 @@ public function buildSchema(string $className, string $format = 'jsonhal', strin $schema['description'] = "$definitionName collection."; $schema['allOf'] = [ - ['$ref' => $prefix.self::COLLECTION_BASE_SCHEMA_NAME], + ['$ref' => $prefix.(false === $operation->getPaginationEnabled() ? self::COLLECTION_BASE_SCHEMA_NAME_NO_PAGINATION : self::COLLECTION_BASE_SCHEMA_NAME)], [ 'type' => 'object', 'properties' => [ diff --git a/src/Hydra/JsonSchema/SchemaFactory.php b/src/Hydra/JsonSchema/SchemaFactory.php index 4dd3e78047c..ae3743feafc 100644 --- a/src/Hydra/JsonSchema/SchemaFactory.php +++ b/src/Hydra/JsonSchema/SchemaFactory.php @@ -38,6 +38,7 @@ final class SchemaFactory implements SchemaFactoryInterface, SchemaFactoryAwareI private const ITEM_BASE_SCHEMA_NAME = 'HydraItemBaseSchema'; private const ITEM_WITHOUT_ID_BASE_SCHEMA_NAME = 'HydraItemBaseSchemaWithoutId'; + private const COLLECTION_BASE_SCHEMA_NAME_NO_PAGINATION = 'HydraCollectionBaseSchemaNoPagination'; private const COLLECTION_BASE_SCHEMA_NAME = 'HydraCollectionBaseSchema'; private const BASE_PROP = [ @@ -155,7 +156,7 @@ public function buildSchema(string $className, string $format = 'jsonld', string $hydraPrefix = $this->getHydraPrefix($serializerContext + $this->defaultContext); - if (!isset($definitions[self::COLLECTION_BASE_SCHEMA_NAME])) { + if (!isset($definitions[self::COLLECTION_BASE_SCHEMA_NAME_NO_PAGINATION])) { switch ($schema->getVersion()) { // JSON Schema + OpenAPI 3.1 case Schema::VERSION_OPENAPI: @@ -168,49 +169,13 @@ public function buildSchema(string $className, string $format = 'jsonld', string break; } - $definitions[self::COLLECTION_BASE_SCHEMA_NAME] = [ + $definitions[self::COLLECTION_BASE_SCHEMA_NAME_NO_PAGINATION] = [ 'type' => 'object', 'properties' => [ $hydraPrefix.'totalItems' => [ 'type' => 'integer', 'minimum' => 0, ], - $hydraPrefix.'view' => [ - 'type' => 'object', - 'properties' => [ - '@id' => [ - 'type' => 'string', - 'format' => 'iri-reference', - ], - '@type' => [ - 'type' => 'string', - ], - $hydraPrefix.'first' => [ - 'type' => 'string', - 'format' => 'iri-reference', - ], - $hydraPrefix.'last' => [ - 'type' => 'string', - 'format' => 'iri-reference', - ], - $hydraPrefix.'previous' => [ - 'type' => 'string', - 'format' => 'iri-reference', - ], - $hydraPrefix.'next' => [ - 'type' => 'string', - 'format' => 'iri-reference', - ], - ], - 'example' => [ - '@id' => 'string', - 'type' => 'string', - $hydraPrefix.'first' => 'string', - $hydraPrefix.'last' => 'string', - $hydraPrefix.'previous' => 'string', - $hydraPrefix.'next' => 'string', - ], - ], $hydraPrefix.'search' => [ 'type' => 'object', 'properties' => [ @@ -233,13 +198,60 @@ public function buildSchema(string $className, string $format = 'jsonld', string ], ], ]; + + $definitions[self::COLLECTION_BASE_SCHEMA_NAME] = [ + 'allOf' => [ + ['$ref' => $prefix.self::COLLECTION_BASE_SCHEMA_NAME_NO_PAGINATION], + [ + 'type' => 'object', + 'properties' => [ + $hydraPrefix.'view' => [ + 'type' => 'object', + 'properties' => [ + '@id' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ], + '@type' => [ + 'type' => 'string', + ], + $hydraPrefix.'first' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ], + $hydraPrefix.'last' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ], + $hydraPrefix.'previous' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ], + $hydraPrefix.'next' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ], + ], + 'example' => [ + '@id' => 'string', + 'type' => 'string', + $hydraPrefix.'first' => 'string', + $hydraPrefix.'last' => 'string', + $hydraPrefix.'previous' => 'string', + $hydraPrefix.'next' => 'string', + ], + ], + ], + ], + ], + ]; } $definitionName = $this->definitionNameFactory->create($className, $format, $inputOrOutputClass, $operation, $serializerContext); $schema['type'] = 'object'; $schema['description'] = "$definitionName collection."; $schema['allOf'] = [ - ['$ref' => $prefix.self::COLLECTION_BASE_SCHEMA_NAME], + ['$ref' => $prefix.(false === $operation->getPaginationEnabled() ? self::COLLECTION_BASE_SCHEMA_NAME_NO_PAGINATION : self::COLLECTION_BASE_SCHEMA_NAME)], [ 'type' => 'object', 'required' => [ diff --git a/src/Hydra/Tests/JsonSchema/SchemaFactoryTest.php b/src/Hydra/Tests/JsonSchema/SchemaFactoryTest.php index 149d68fa025..3a0864556d4 100644 --- a/src/Hydra/Tests/JsonSchema/SchemaFactoryTest.php +++ b/src/Hydra/Tests/JsonSchema/SchemaFactoryTest.php @@ -130,11 +130,18 @@ public function testSchemaTypeBuildSchema(): void { $resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_OUTPUT, new GetCollection()); $this->assertNull($resultSchema->getRootDefinitionKey()); - $hydraCollectionSchema = $resultSchema['definitions']['HydraCollectionBaseSchema']; - $properties = $hydraCollectionSchema['properties']; + $hydraCollectionSchemaNoPagination = $resultSchema['definitions']['HydraCollectionBaseSchemaNoPagination']; + $properties = $hydraCollectionSchemaNoPagination['properties']; $this->assertArrayHasKey('hydra:totalItems', $properties); - $this->assertArrayHasKey('hydra:view', $properties); $this->assertArrayHasKey('hydra:search', $properties); + + $hydraCollectionSchema = $resultSchema['definitions']['HydraCollectionBaseSchema']; + $this->assertArrayHasKey('allOf', $hydraCollectionSchema); + $this->assertSame([ + '$ref' => '#/definitions/HydraCollectionBaseSchemaNoPagination', + ], $hydraCollectionSchema['allOf'][0]); + $properties = $hydraCollectionSchema['allOf'][1]['properties']; + $this->assertArrayHasKey('hydra:view', $properties); $this->assertArrayNotHasKey('@context', $properties); $this->assertTrue(isset($properties['hydra:view'])); @@ -152,10 +159,16 @@ public function testSchemaTypeBuildSchemaWithoutPrefix(): void { $resultSchema = $this->schemaFactory->buildSchema(Dummy::class, 'jsonld', Schema::TYPE_OUTPUT, new GetCollection(), null, [ContextBuilder::HYDRA_CONTEXT_HAS_PREFIX => false]); $this->assertNull($resultSchema->getRootDefinitionKey()); - $hydraCollectionSchema = $resultSchema['definitions']['HydraCollectionBaseSchema']; - $properties = $hydraCollectionSchema['properties']; + $hydraCollectionSchemaNoPagination = $resultSchema['definitions']['HydraCollectionBaseSchemaNoPagination']; + $properties = $hydraCollectionSchemaNoPagination['properties']; $this->assertArrayHasKey('totalItems', $properties); - $this->assertArrayHasKey('view', $properties); $this->assertArrayHasKey('search', $properties); + + $hydraCollectionSchema = $resultSchema['definitions']['HydraCollectionBaseSchema']; + $this->assertSame([ + '$ref' => '#/definitions/HydraCollectionBaseSchemaNoPagination', + ], $hydraCollectionSchema['allOf'][0]); + $properties = $hydraCollectionSchema['allOf'][1]['properties']; + $this->assertArrayHasKey('view', $properties); } } diff --git a/src/JsonApi/JsonSchema/SchemaFactory.php b/src/JsonApi/JsonSchema/SchemaFactory.php index 1189c34888d..24a50e8e96c 100644 --- a/src/JsonApi/JsonSchema/SchemaFactory.php +++ b/src/JsonApi/JsonSchema/SchemaFactory.php @@ -49,56 +49,8 @@ final class SchemaFactory implements SchemaFactoryInterface, SchemaFactoryAwareI public const DISABLE_JSON_SCHEMA_SERIALIZER_GROUPS = 'disable_json_schema_serializer_groups'; private const COLLECTION_BASE_SCHEMA_NAME = 'JsonApiCollectionBaseSchema'; + private const COLLECTION_BASE_SCHEMA_NAME_NO_PAGINATION = 'JsonApiCollectionBaseSchemaNoPagination'; - private const LINKS_PROPS = [ - 'type' => 'object', - 'properties' => [ - 'self' => [ - 'type' => 'string', - 'format' => 'iri-reference', - ], - 'first' => [ - 'type' => 'string', - 'format' => 'iri-reference', - ], - 'prev' => [ - 'type' => 'string', - 'format' => 'iri-reference', - ], - 'next' => [ - 'type' => 'string', - 'format' => 'iri-reference', - ], - 'last' => [ - 'type' => 'string', - 'format' => 'iri-reference', - ], - ], - 'example' => [ - 'self' => 'string', - 'first' => 'string', - 'prev' => 'string', - 'next' => 'string', - 'last' => 'string', - ], - ]; - private const META_PROPS = [ - 'type' => 'object', - 'properties' => [ - 'totalItems' => [ - 'type' => 'integer', - 'minimum' => 0, - ], - 'itemsPerPage' => [ - 'type' => 'integer', - 'minimum' => 0, - ], - 'currentPage' => [ - 'type' => 'integer', - 'minimum' => 0, - ], - ], - ]; private const RELATION_PROPS = [ 'type' => 'object', 'properties' => [ @@ -217,18 +169,88 @@ public function buildSchema(string $className, string $format = 'jsonapi', strin return $schema; } - if (!isset($definitions[self::COLLECTION_BASE_SCHEMA_NAME])) { - $definitions[self::COLLECTION_BASE_SCHEMA_NAME] = [ + if (!isset($definitions[self::COLLECTION_BASE_SCHEMA_NAME_NO_PAGINATION])) { + $definitions[self::COLLECTION_BASE_SCHEMA_NAME_NO_PAGINATION] = [ 'type' => 'object', 'properties' => [ - 'links' => self::LINKS_PROPS, - 'meta' => self::META_PROPS, + 'links' => [ + 'type' => 'object', + 'properties' => [ + 'self' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ], + ], + 'example' => [ + 'self' => 'string', + ], + ], + 'meta' => [ + 'type' => 'object', + 'properties' => [ + 'totalItems' => [ + 'type' => 'integer', + 'minimum' => 0, + ], + ], + ], 'data' => [ 'type' => 'array', ], ], 'required' => ['data'], ]; + + $definitions[self::COLLECTION_BASE_SCHEMA_NAME] = [ + 'allOf' => [ + ['$ref' => $prefix.self::COLLECTION_BASE_SCHEMA_NAME_NO_PAGINATION], + [ + 'type' => 'object', + 'properties' => [ + 'links' => [ + 'type' => 'object', + 'properties' => [ + 'first' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ], + 'prev' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ], + 'next' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ], + 'last' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ], + ], + 'example' => [ + 'first' => 'string', + 'prev' => 'string', + 'next' => 'string', + 'last' => 'string', + ], + ], + 'meta' => [ + 'type' => 'object', + 'properties' => [ + 'itemsPerPage' => [ + 'type' => 'integer', + 'minimum' => 0, + ], + 'currentPage' => [ + 'type' => 'integer', + 'minimum' => 0, + ], + ], + ], + ], + ], + ], + ]; } unset($schema['items']); @@ -239,7 +261,7 @@ public function buildSchema(string $className, string $format = 'jsonapi', strin $schema['description'] = "$definitionName collection."; $schema['allOf'] = [ - ['$ref' => $prefix.self::COLLECTION_BASE_SCHEMA_NAME], + ['$ref' => $prefix.(false === $operation->getPaginationEnabled() ? self::COLLECTION_BASE_SCHEMA_NAME_NO_PAGINATION : self::COLLECTION_BASE_SCHEMA_NAME)], ['type' => 'object', 'properties' => [ 'data' => [ 'type' => 'array', diff --git a/src/JsonApi/Tests/JsonSchema/SchemaFactoryTest.php b/src/JsonApi/Tests/JsonSchema/SchemaFactoryTest.php index 28b9c3a5552..4adcb6480ce 100644 --- a/src/JsonApi/Tests/JsonSchema/SchemaFactoryTest.php +++ b/src/JsonApi/Tests/JsonSchema/SchemaFactoryTest.php @@ -129,19 +129,24 @@ public function testSchemaTypeBuildSchema(): void $this->assertTrue(isset($resultSchema['allOf'][0]['$ref'])); $this->assertEquals($resultSchema['allOf'][0]['$ref'], '#/definitions/JsonApiCollectionBaseSchema'); + $jsonApiCollectionBaseSchemaNoPagination = $resultSchema['definitions']['JsonApiCollectionBaseSchemaNoPagination']; + $this->assertTrue(isset($jsonApiCollectionBaseSchemaNoPagination['properties'])); + $this->assertArrayHasKey('links', $jsonApiCollectionBaseSchemaNoPagination['properties']); + $this->assertArrayHasKey('self', $jsonApiCollectionBaseSchemaNoPagination['properties']['links']['properties']); + $this->assertArrayHasKey('meta', $jsonApiCollectionBaseSchemaNoPagination['properties']); + $this->assertArrayHasKey('totalItems', $jsonApiCollectionBaseSchemaNoPagination['properties']['meta']['properties']); + $jsonApiCollectionBaseSchema = $resultSchema['definitions']['JsonApiCollectionBaseSchema']; - $this->assertTrue(isset($jsonApiCollectionBaseSchema['properties'])); - $this->assertArrayHasKey('links', $jsonApiCollectionBaseSchema['properties']); - $this->assertArrayHasKey('self', $jsonApiCollectionBaseSchema['properties']['links']['properties']); - $this->assertArrayHasKey('first', $jsonApiCollectionBaseSchema['properties']['links']['properties']); - $this->assertArrayHasKey('prev', $jsonApiCollectionBaseSchema['properties']['links']['properties']); - $this->assertArrayHasKey('next', $jsonApiCollectionBaseSchema['properties']['links']['properties']); - $this->assertArrayHasKey('last', $jsonApiCollectionBaseSchema['properties']['links']['properties']); - - $this->assertArrayHasKey('meta', $jsonApiCollectionBaseSchema['properties']); - $this->assertArrayHasKey('totalItems', $jsonApiCollectionBaseSchema['properties']['meta']['properties']); - $this->assertArrayHasKey('itemsPerPage', $jsonApiCollectionBaseSchema['properties']['meta']['properties']); - $this->assertArrayHasKey('currentPage', $jsonApiCollectionBaseSchema['properties']['meta']['properties']); + $this->assertArrayHasKey('allOf', $jsonApiCollectionBaseSchema); + $this->assertSame(['$ref' => '#/definitions/JsonApiCollectionBaseSchemaNoPagination'], $jsonApiCollectionBaseSchema['allOf'][0]); + $this->assertArrayHasKey('first', $jsonApiCollectionBaseSchema['allOf'][1]['properties']['links']['properties']); + $this->assertArrayHasKey('prev', $jsonApiCollectionBaseSchema['allOf'][1]['properties']['links']['properties']); + $this->assertArrayHasKey('next', $jsonApiCollectionBaseSchema['allOf'][1]['properties']['links']['properties']); + $this->assertArrayHasKey('last', $jsonApiCollectionBaseSchema['allOf'][1]['properties']['links']['properties']); + + $this->assertArrayHasKey('meta', $jsonApiCollectionBaseSchema['allOf'][1]['properties']); + $this->assertArrayHasKey('itemsPerPage', $jsonApiCollectionBaseSchema['allOf'][1]['properties']['meta']['properties']); + $this->assertArrayHasKey('currentPage', $jsonApiCollectionBaseSchema['allOf'][1]['properties']['meta']['properties']); $objectSchema = $resultSchema['allOf'][1]; $this->assertArrayHasKey('data', $objectSchema['properties']); diff --git a/tests/Fixtures/TestBundle/Entity/PaginationDisabledEntity.php b/tests/Fixtures/TestBundle/Entity/PaginationDisabledEntity.php new file mode 100644 index 00000000000..4bd93e0ad92 --- /dev/null +++ b/tests/Fixtures/TestBundle/Entity/PaginationDisabledEntity.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity; + +use ApiPlatform\Metadata\ApiResource; +use ApiPlatform\Metadata\GetCollection; +use Doctrine\ORM\Mapping as ORM; + +#[ApiResource] +#[GetCollection( + paginationEnabled: false, + paginationItemsPerPage: 3, +)] +#[ORM\Entity] +class PaginationDisabledEntity +{ + #[ORM\Column(type: 'integer', nullable: true)] + #[ORM\Id] + #[ORM\GeneratedValue(strategy: 'AUTO')] + private ?int $id = null; + + public function getId(): ?int + { + return $this->id; + } +} diff --git a/tests/Functional/PaginationDisabledTest.php b/tests/Functional/PaginationDisabledTest.php new file mode 100644 index 00000000000..53e9ed562d5 --- /dev/null +++ b/tests/Functional/PaginationDisabledTest.php @@ -0,0 +1,317 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +declare(strict_types=1); + +namespace ApiPlatform\Tests\Functional; + +use ApiPlatform\JsonSchema\SchemaFactoryInterface; +use ApiPlatform\Metadata\Operation\Factory\OperationMetadataFactory; +use ApiPlatform\Symfony\Bundle\Test\ApiTestCase; +use ApiPlatform\Tests\Fixtures\TestBundle\Entity\PaginationDisabledEntity; +use ApiPlatform\Tests\RecreateSchemaTrait; +use ApiPlatform\Tests\SetupClassResourcesTrait; +use Doctrine\ODM\MongoDB\MongoDBException; + +final class PaginationDisabledTest extends ApiTestCase +{ + use RecreateSchemaTrait; + use SetupClassResourcesTrait; + + protected SchemaFactoryInterface $schemaFactory; + private OperationMetadataFactory $operationMetadataFactory; + + protected static ?bool $alwaysBootKernel = false; + + /** + * @return class-string[] + */ + public static function getResources(): array + { + return [PaginationDisabledEntity::class]; + } + + protected function setUp(): void + { + parent::setUp(); + if ($this->isMongoDB()) { + return; + } + + $this->recreateSchema(static::getResources()); + $this->loadFixtures(); + + $this->schemaFactory = self::getContainer()->get('api_platform.json_schema.schema_factory'); + $this->operationMetadataFactory = self::getContainer()->get('api_platform.metadata.operation.metadata_factory'); + } + + /** + * @throws \Throwable + * @throws MongoDBException + */ + private function loadFixtures(): void + { + $manager = $this->getManager(); + + for ($i = 0; $i < 4; ++$i) { + $manager->persist(new PaginationDisabledEntity()); + } + + $manager->flush(); + } + + public function testCollectionJsonApi(): void + { + if ($this->isMongoDB()) { + $this->markTestSkipped('Not tested with mongodb.'); + } + + self::createClient()->request('GET', '/pagination_disabled_entities', ['headers' => ['Accept' => 'application/vnd.api+json']]); + + $this->assertResponseIsSuccessful(); + $this->assertJsonEquals([ + 'links' => [ + 'self' => '/pagination_disabled_entities', + ], + 'meta' => [ + 'totalItems' => 4, + ], + 'data' => [ + [ + 'id' => '/pagination_disabled_entities/1', + 'type' => 'PaginationDisabledEntity', + 'attributes' => [ + '_id' => 1, + ], + ], + [ + 'id' => '/pagination_disabled_entities/2', + 'type' => 'PaginationDisabledEntity', + 'attributes' => [ + '_id' => 2, + ], + ], + [ + 'id' => '/pagination_disabled_entities/3', + 'type' => 'PaginationDisabledEntity', + 'attributes' => [ + '_id' => 3, + ], + ], + [ + 'id' => '/pagination_disabled_entities/4', + 'type' => 'PaginationDisabledEntity', + 'attributes' => [ + '_id' => 4, + ], + ], + ], + ]); + + $this->assertMatchesResourceCollectionJsonSchema(PaginationDisabledEntity::class, format: 'jsonapi'); + } + + public function testSchemaCollectionJsonApi(): void + { + if ($this->isMongoDB()) { + $this->markTestSkipped('Not tested with mongodb.'); + } + + $schema = $this->schemaFactory->buildSchema(PaginationDisabledEntity::class, 'jsonapi', operation: $this->operationMetadataFactory->create('_api_/pagination_disabled_entities{._format}_get_collection')); + $this->assertArrayHasKey('definitions', $schema); + $this->assertArrayHasKey('JsonApiCollectionBaseSchemaNoPagination', $schema['definitions']); + $this->assertArrayHasKey('properties', $schema['definitions']['JsonApiCollectionBaseSchemaNoPagination']); + $this->assertArrayHasKey('links', $schema['definitions']['JsonApiCollectionBaseSchemaNoPagination']['properties']); + $this->assertSame( + [ + 'type' => 'object', + 'properties' => [ + 'self' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ], + ], + 'example' => [ + 'self' => 'string', + ], + ], + $schema['definitions']['JsonApiCollectionBaseSchemaNoPagination']['properties']['links'] + ); + $this->assertArrayHasKey('meta', $schema['definitions']['JsonApiCollectionBaseSchemaNoPagination']['properties']); + $this->assertArrayHasKey('properties', $schema['definitions']['JsonApiCollectionBaseSchemaNoPagination']['properties']['meta']); + $this->assertSame( + [ + 'totalItems' => [ + 'type' => 'integer', + 'minimum' => 0, + ], + ], + $schema['definitions']['JsonApiCollectionBaseSchemaNoPagination']['properties']['meta']['properties'] + ); + } + + public function testCollectionHal(): void + { + if ($this->isMongoDB()) { + $this->markTestSkipped('Not tested with mongodb.'); + } + + self::createClient()->request('GET', '/pagination_disabled_entities', ['headers' => ['Accept' => 'application/hal+json']]); + + $this->assertResponseIsSuccessful(); + $this->assertJsonEquals([ + '_links' => [ + 'self' => [ + 'href' => '/pagination_disabled_entities', + ], + 'item' => [ + ['href' => '/pagination_disabled_entities/1'], + ['href' => '/pagination_disabled_entities/2'], + ['href' => '/pagination_disabled_entities/3'], + ['href' => '/pagination_disabled_entities/4'], + ], + ], + 'totalItems' => 4, + '_embedded' => [ + 'item' => [ + [ + '_links' => [ + 'self' => ['href' => '/pagination_disabled_entities/1'], + ], + 'id' => 1, + ], + [ + '_links' => [ + 'self' => ['href' => '/pagination_disabled_entities/2'], + ], + 'id' => 2, + ], + [ + '_links' => [ + 'self' => ['href' => '/pagination_disabled_entities/3'], + ], + 'id' => 3, + ], + [ + '_links' => [ + 'self' => ['href' => '/pagination_disabled_entities/4'], + ], + 'id' => 4, + ], + ], + ], + ]); + + $this->assertMatchesResourceCollectionJsonSchema(PaginationDisabledEntity::class, format: 'jsonhal'); + } + + public function testSchemaCollectionHal(): void + { + if ($this->isMongoDB()) { + $this->markTestSkipped('Not tested with mongodb.'); + } + + $schema = $this->schemaFactory->buildSchema(PaginationDisabledEntity::class, 'jsonhal', operation: $this->operationMetadataFactory->create('_api_/pagination_disabled_entities{._format}_get_collection')); + + $this->assertArrayHasKey('definitions', $schema); + $this->assertArrayHasKey('HalCollectionBaseSchemaNoPagination', $schema['definitions']); + $this->assertArrayHasKey('_links', $schema['definitions']['HalCollectionBaseSchemaNoPagination']['properties']); + $this->assertSame( + [ + 'type' => 'object', + 'properties' => [ + 'self' => [ + 'type' => 'object', + 'properties' => [ + 'href' => [ + 'type' => 'string', + 'format' => 'iri-reference', + ], + ], + ], + ], + ], + $schema['definitions']['HalCollectionBaseSchemaNoPagination']['properties']['_links'] + ); + $this->assertArrayNotHasKey('itemsPerPage', $schema['definitions']['HalCollectionBaseSchemaNoPagination']['properties']); + $this->assertArrayHasKey('totalItems', $schema['definitions']['HalCollectionBaseSchemaNoPagination']['properties']); + $this->assertSame( + [ + 'type' => 'integer', + 'minimum' => 0, + ], + $schema['definitions']['HalCollectionBaseSchemaNoPagination']['properties']['totalItems'] + ); + } + + public function testCollectionJsonLd(): void + { + if ($this->isMongoDB()) { + $this->markTestSkipped('Not tested with mongodb.'); + } + + self::createClient()->request('GET', '/pagination_disabled_entities', ['headers' => ['Accept' => 'application/ld+json']]); + + $this->assertResponseIsSuccessful(); + $this->assertJsonEquals([ + '@context' => '/contexts/PaginationDisabledEntity', + '@id' => '/pagination_disabled_entities', + '@type' => 'hydra:Collection', + 'hydra:totalItems' => 4, + 'hydra:member' => [ + [ + '@id' => '/pagination_disabled_entities/1', + '@type' => 'PaginationDisabledEntity', + 'id' => 1, + ], + [ + '@id' => '/pagination_disabled_entities/2', + '@type' => 'PaginationDisabledEntity', + 'id' => 2, + ], + [ + '@id' => '/pagination_disabled_entities/3', + '@type' => 'PaginationDisabledEntity', + 'id' => 3, + ], + + [ + '@id' => '/pagination_disabled_entities/4', + '@type' => 'PaginationDisabledEntity', + 'id' => 4, + ], + ], + ]); + + $this->assertMatchesResourceCollectionJsonSchema(PaginationDisabledEntity::class, format: 'jsonld'); + } + + public function testSchemaCollectionJsonLd(): void + { + if ($this->isMongoDB()) { + $this->markTestSkipped('Not tested with mongodb.'); + } + + $schema = $this->schemaFactory->buildSchema(PaginationDisabledEntity::class, 'jsonld', operation: $this->operationMetadataFactory->create('_api_/pagination_disabled_entities{._format}_get_collection')); + + $this->assertArrayHasKey('definitions', $schema); + $this->assertArrayHasKey('HydraCollectionBaseSchemaNoPagination', $schema['definitions']); + $this->assertArrayNotHasKey('hydra:view', $schema['definitions']['HydraCollectionBaseSchemaNoPagination']['properties']); + $this->assertArrayHasKey('hydra:totalItems', $schema['definitions']['HydraCollectionBaseSchemaNoPagination']['properties']); + $this->assertSame( + [ + 'type' => 'integer', + 'minimum' => 0, + ], + $schema['definitions']['HydraCollectionBaseSchemaNoPagination']['properties']['hydra:totalItems'] + ); + } +}