Skip to content

Commit abb2142

Browse files
committed
feat(serializer) Remove the pagination attributes if pagination is explicitely disabled
1 parent 07d0ef8 commit abb2142

File tree

6 files changed

+355
-0
lines changed

6 files changed

+355
-0
lines changed

src/Hal/JsonSchema/SchemaFactory.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,14 @@ public function buildSchema(string $className, string $format = 'jsonhal', strin
177177
];
178178
}
179179

180+
if (false === $operation->getPaginationEnabled()) {
181+
unset($definitions[self::COLLECTION_BASE_SCHEMA_NAME]['properties']['itemsPerPage']);
182+
unset($definitions[self::COLLECTION_BASE_SCHEMA_NAME]['properties']['_links']['properties']['first']);
183+
unset($definitions[self::COLLECTION_BASE_SCHEMA_NAME]['properties']['_links']['properties']['last']);
184+
unset($definitions[self::COLLECTION_BASE_SCHEMA_NAME]['properties']['_links']['properties']['next']);
185+
unset($definitions[self::COLLECTION_BASE_SCHEMA_NAME]['properties']['_links']['properties']['previous']);
186+
}
187+
180188
unset($schema['items']);
181189
unset($schema['type']);
182190

src/Hydra/JsonSchema/SchemaFactory.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,10 @@ public function buildSchema(string $className, string $format = 'jsonld', string
235235
];
236236
}
237237

238+
if (false === $operation->getPaginationEnabled()) {
239+
unset($definitions[self::COLLECTION_BASE_SCHEMA_NAME]['properties'][$hydraPrefix.'view']);
240+
}
241+
238242
$definitionName = $this->definitionNameFactory->create($className, $format, $inputOrOutputClass, $operation, $serializerContext);
239243
$schema['type'] = 'object';
240244
$schema['description'] = "$definitionName collection.";

src/Hydra/Serializer/PartialCollectionViewNormalizer.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,10 @@ public function normalize(mixed $object, ?string $format = null, array $context
9595

9696
$partialCollectionView = $this->getPartialCollectionView($object, $context['uri'] ?? $context['request_uri'] ?? '/', $this->pageParameterName, $this->enabledParameterName, $operation?->getUrlGenerationStrategy() ?? $this->urlGenerationStrategy);
9797

98+
if (false === $operation?->getPaginationEnabled()) {
99+
return $data;
100+
}
101+
98102
$view = [
99103
'@id' => $partialCollectionView->id,
100104
'@type' => $hydraPrefix.'PartialCollectionView',

src/JsonApi/JsonSchema/SchemaFactory.php

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,19 @@ public function buildSchema(string $className, string $format = 'jsonapi', strin
231231
];
232232
}
233233

234+
if (false === $operation->getPaginationEnabled()) {
235+
unset($definitions[self::COLLECTION_BASE_SCHEMA_NAME]['properties']['links']['properties']['first']);
236+
unset($definitions[self::COLLECTION_BASE_SCHEMA_NAME]['properties']['links']['properties']['last']);
237+
unset($definitions[self::COLLECTION_BASE_SCHEMA_NAME]['properties']['links']['properties']['next']);
238+
unset($definitions[self::COLLECTION_BASE_SCHEMA_NAME]['properties']['links']['properties']['prev']);
239+
unset($definitions[self::COLLECTION_BASE_SCHEMA_NAME]['properties']['links']['example']['first']);
240+
unset($definitions[self::COLLECTION_BASE_SCHEMA_NAME]['properties']['links']['example']['last']);
241+
unset($definitions[self::COLLECTION_BASE_SCHEMA_NAME]['properties']['links']['example']['next']);
242+
unset($definitions[self::COLLECTION_BASE_SCHEMA_NAME]['properties']['links']['example']['prev']);
243+
unset($definitions[self::COLLECTION_BASE_SCHEMA_NAME]['properties']['meta']['properties']['itemsPerPage']);
244+
unset($definitions[self::COLLECTION_BASE_SCHEMA_NAME]['properties']['meta']['properties']['currentPage']);
245+
}
246+
234247
unset($schema['items']);
235248
unset($schema['type']);
236249

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <dunglas@gmail.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Tests\Fixtures\TestBundle\Entity;
15+
16+
use ApiPlatform\Metadata\ApiResource;
17+
use ApiPlatform\Metadata\GetCollection;
18+
use Doctrine\ORM\Mapping as ORM;
19+
20+
#[ApiResource]
21+
#[GetCollection(
22+
paginationEnabled: false,
23+
paginationItemsPerPage: 3,
24+
)]
25+
#[ORM\Entity]
26+
class PaginationDisabledEntity
27+
{
28+
#[ORM\Column(type: 'integer', nullable: true)]
29+
#[ORM\Id]
30+
#[ORM\GeneratedValue(strategy: 'AUTO')]
31+
private ?int $id = null;
32+
33+
public function getId(): ?int
34+
{
35+
return $this->id;
36+
}
37+
}
Lines changed: 289 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,289 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <dunglas@gmail.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
declare(strict_types=1);
13+
14+
namespace ApiPlatform\Tests\Functional;
15+
16+
use ApiPlatform\JsonSchema\SchemaFactoryInterface;
17+
use ApiPlatform\Metadata\Operation\Factory\OperationMetadataFactory;
18+
use ApiPlatform\Symfony\Bundle\Test\ApiTestCase;
19+
use ApiPlatform\Tests\Fixtures\TestBundle\Entity\PaginationDisabledEntity;
20+
use ApiPlatform\Tests\RecreateSchemaTrait;
21+
use ApiPlatform\Tests\SetupClassResourcesTrait;
22+
use Doctrine\ODM\MongoDB\MongoDBException;
23+
24+
final class PaginationDisabledTest extends ApiTestCase
25+
{
26+
use RecreateSchemaTrait;
27+
use SetupClassResourcesTrait;
28+
29+
protected SchemaFactoryInterface $schemaFactory;
30+
private OperationMetadataFactory $operationMetadataFactory;
31+
32+
protected static ?bool $alwaysBootKernel = false;
33+
34+
/**
35+
* @return class-string[]
36+
*/
37+
public static function getResources(): array
38+
{
39+
return [PaginationDisabledEntity::class];
40+
}
41+
42+
protected function setUp(): void
43+
{
44+
parent::setUp();
45+
$this->recreateSchema(static::getResources());
46+
$this->loadFixtures();
47+
48+
$this->schemaFactory = self::getContainer()->get('api_platform.json_schema.schema_factory');
49+
$this->operationMetadataFactory = self::getContainer()->get('api_platform.metadata.operation.metadata_factory');
50+
}
51+
52+
/**
53+
* @throws \Throwable
54+
* @throws MongoDBException
55+
*/
56+
private function loadFixtures(): void
57+
{
58+
$manager = $this->getManager();
59+
60+
for ($i = 0; $i < 4; ++$i) {
61+
$manager->persist(new PaginationDisabledEntity());
62+
}
63+
64+
$manager->flush();
65+
}
66+
67+
public function testCollectionJsonApi(): void
68+
{
69+
self::createClient()->request('GET', '/pagination_disabled_entities', ['headers' => ['Accept' => 'application/vnd.api+json']]);
70+
71+
$this->assertResponseIsSuccessful();
72+
$this->assertJsonEquals([
73+
'links' => [
74+
'self' => '/pagination_disabled_entities',
75+
],
76+
'meta' => [
77+
'totalItems' => 4,
78+
],
79+
'data' => [
80+
[
81+
'id' => '/pagination_disabled_entities/1',
82+
'type' => 'PaginationDisabledEntity',
83+
'attributes' => [
84+
'_id' => 1,
85+
],
86+
],
87+
[
88+
'id' => '/pagination_disabled_entities/2',
89+
'type' => 'PaginationDisabledEntity',
90+
'attributes' => [
91+
'_id' => 2,
92+
],
93+
],
94+
[
95+
'id' => '/pagination_disabled_entities/3',
96+
'type' => 'PaginationDisabledEntity',
97+
'attributes' => [
98+
'_id' => 3,
99+
],
100+
],
101+
[
102+
'id' => '/pagination_disabled_entities/4',
103+
'type' => 'PaginationDisabledEntity',
104+
'attributes' => [
105+
'_id' => 4,
106+
],
107+
],
108+
],
109+
]);
110+
111+
$this->assertMatchesResourceCollectionJsonSchema(PaginationDisabledEntity::class, format: 'jsonapi');
112+
}
113+
114+
public function testSchemaCollectionJsonApi(): void
115+
{
116+
$schema = $this->schemaFactory->buildSchema(PaginationDisabledEntity::class, 'jsonapi', operation: $this->operationMetadataFactory->create('_api_/pagination_disabled_entities{._format}_get_collection'));
117+
$this->assertArrayHasKey('definitions', $schema);
118+
$this->assertArrayHasKey('JsonApiCollectionBaseSchema', $schema['definitions']);
119+
$this->assertArrayHasKey('properties', $schema['definitions']['JsonApiCollectionBaseSchema']);
120+
$this->assertArrayHasKey('links', $schema['definitions']['JsonApiCollectionBaseSchema']['properties']);
121+
$this->assertSame(
122+
[
123+
'type' => 'object',
124+
'properties' => [
125+
'self' => [
126+
'type' => 'string',
127+
'format' => 'iri-reference',
128+
],
129+
],
130+
'example' => [
131+
'self' => 'string',
132+
],
133+
],
134+
$schema['definitions']['JsonApiCollectionBaseSchema']['properties']['links']
135+
);
136+
$this->assertArrayHasKey('meta', $schema['definitions']['JsonApiCollectionBaseSchema']['properties']);
137+
$this->assertArrayHasKey('properties', $schema['definitions']['JsonApiCollectionBaseSchema']['properties']['meta']);
138+
$this->assertSame(
139+
[
140+
'totalItems' => [
141+
'type' => 'integer',
142+
'minimum' => 0,
143+
],
144+
],
145+
$schema['definitions']['JsonApiCollectionBaseSchema']['properties']['meta']['properties']
146+
);
147+
}
148+
149+
public function testCollectionHal(): void
150+
{
151+
self::createClient()->request('GET', '/pagination_disabled_entities', ['headers' => ['Accept' => 'application/hal+json']]);
152+
153+
$this->assertResponseIsSuccessful();
154+
$this->assertJsonEquals([
155+
'_links' => [
156+
'self' => [
157+
'href' => '/pagination_disabled_entities',
158+
],
159+
'item' => [
160+
['href' => '/pagination_disabled_entities/1'],
161+
['href' => '/pagination_disabled_entities/2'],
162+
['href' => '/pagination_disabled_entities/3'],
163+
['href' => '/pagination_disabled_entities/4'],
164+
],
165+
],
166+
'totalItems' => 4,
167+
'_embedded' => [
168+
'item' => [
169+
[
170+
'_links' => [
171+
'self' => ['href' => '/pagination_disabled_entities/1'],
172+
],
173+
'id' => 1,
174+
],
175+
[
176+
'_links' => [
177+
'self' => ['href' => '/pagination_disabled_entities/2'],
178+
],
179+
'id' => 2,
180+
],
181+
[
182+
'_links' => [
183+
'self' => ['href' => '/pagination_disabled_entities/3'],
184+
],
185+
'id' => 3,
186+
],
187+
[
188+
'_links' => [
189+
'self' => ['href' => '/pagination_disabled_entities/4'],
190+
],
191+
'id' => 4,
192+
],
193+
],
194+
],
195+
]);
196+
197+
$this->assertMatchesResourceCollectionJsonSchema(PaginationDisabledEntity::class, format: 'jsonhal');
198+
}
199+
200+
public function testSchemaCollectionHal(): void
201+
{
202+
$schema = $this->schemaFactory->buildSchema(PaginationDisabledEntity::class, 'jsonhal', operation: $this->operationMetadataFactory->create('_api_/pagination_disabled_entities{._format}_get_collection'));
203+
204+
$this->assertArrayHasKey('definitions', $schema);
205+
$this->assertArrayHasKey('HalCollectionBaseSchema', $schema['definitions']);
206+
$this->assertArrayHasKey('_links', $schema['definitions']['HalCollectionBaseSchema']['properties']);
207+
$this->assertSame(
208+
[
209+
'type' => 'object',
210+
'properties' => [
211+
'self' => [
212+
'type' => 'object',
213+
'properties' => [
214+
'href' => [
215+
'type' => 'string',
216+
'format' => 'iri-reference',
217+
],
218+
],
219+
],
220+
],
221+
],
222+
$schema['definitions']['HalCollectionBaseSchema']['properties']['_links']
223+
);
224+
$this->assertArrayNotHasKey('itemsPerPage', $schema['definitions']['HalCollectionBaseSchema']['properties']);
225+
$this->assertArrayHasKey('totalItems', $schema['definitions']['HalCollectionBaseSchema']['properties']);
226+
$this->assertSame(
227+
[
228+
'type' => 'integer',
229+
'minimum' => 0,
230+
],
231+
$schema['definitions']['HalCollectionBaseSchema']['properties']['totalItems']
232+
);
233+
}
234+
235+
public function testCollectionJsonLd(): void
236+
{
237+
self::createClient()->request('GET', '/pagination_disabled_entities', ['headers' => ['Accept' => 'application/ld+json']]);
238+
239+
$this->assertResponseIsSuccessful();
240+
$this->assertJsonEquals([
241+
'@context' => '/contexts/PaginationDisabledEntity',
242+
'@id' => '/pagination_disabled_entities',
243+
'@type' => 'hydra:Collection',
244+
'hydra:totalItems' => 4,
245+
'hydra:member' => [
246+
[
247+
'@id' => '/pagination_disabled_entities/1',
248+
'@type' => 'PaginationDisabledEntity',
249+
'id' => 1,
250+
],
251+
[
252+
'@id' => '/pagination_disabled_entities/2',
253+
'@type' => 'PaginationDisabledEntity',
254+
'id' => 2,
255+
],
256+
[
257+
'@id' => '/pagination_disabled_entities/3',
258+
'@type' => 'PaginationDisabledEntity',
259+
'id' => 3,
260+
],
261+
262+
[
263+
'@id' => '/pagination_disabled_entities/4',
264+
'@type' => 'PaginationDisabledEntity',
265+
'id' => 4,
266+
],
267+
],
268+
]);
269+
270+
$this->assertMatchesResourceCollectionJsonSchema(PaginationDisabledEntity::class, format: 'jsonld');
271+
}
272+
273+
public function testSchemaCollectionJsonLd(): void
274+
{
275+
$schema = $this->schemaFactory->buildSchema(PaginationDisabledEntity::class, 'jsonld', operation: $this->operationMetadataFactory->create('_api_/pagination_disabled_entities{._format}_get_collection'));
276+
277+
$this->assertArrayHasKey('definitions', $schema);
278+
$this->assertArrayHasKey('HydraCollectionBaseSchema', $schema['definitions']);
279+
$this->assertArrayNotHasKey('hydra:view', $schema['definitions']['HydraCollectionBaseSchema']['properties']);
280+
$this->assertArrayHasKey('hydra:totalItems', $schema['definitions']['HydraCollectionBaseSchema']['properties']);
281+
$this->assertSame(
282+
[
283+
'type' => 'integer',
284+
'minimum' => 0,
285+
],
286+
$schema['definitions']['HydraCollectionBaseSchema']['properties']['hydra:totalItems']
287+
);
288+
}
289+
}

0 commit comments

Comments
 (0)