Skip to content

Commit 78a3d6d

Browse files
authored
Merge pull request #1455 from meyerbaptiste/refactor_collection_normalizers
Create a base collection normalizer
2 parents 5439c36 + 9c17299 commit 78a3d6d

File tree

5 files changed

+184
-137
lines changed

5 files changed

+184
-137
lines changed

features/hal/hal.feature

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -192,6 +192,8 @@ Feature: HAL support
192192
}
193193
]
194194
},
195+
"totalItems": 1,
196+
"itemsPerPage": 3,
195197
"_embedded": {
196198
"item": [
197199
{
@@ -221,8 +223,6 @@ Feature: HAL support
221223
"alias": null
222224
}
223225
]
224-
},
225-
"totalItems": 1,
226-
"itemsPerPage": 3
226+
}
227227
}
228228
"""

src/Hal/Serializer/CollectionNormalizer.php

Lines changed: 22 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -13,75 +13,27 @@
1313

1414
namespace ApiPlatform\Core\Hal\Serializer;
1515

16-
use ApiPlatform\Core\Api\ResourceClassResolverInterface;
17-
use ApiPlatform\Core\DataProvider\PaginatorInterface;
18-
use ApiPlatform\Core\DataProvider\PartialPaginatorInterface;
19-
use ApiPlatform\Core\Serializer\ContextTrait;
16+
use ApiPlatform\Core\Serializer\AbstractCollectionNormalizer;
2017
use ApiPlatform\Core\Util\IriHelper;
21-
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
22-
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
23-
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
2418

2519
/**
2620
* Normalizes collections in the HAL format.
2721
*
2822
* @author Kevin Dunglas <dunglas@gmail.com>
2923
* @author Hamza Amrouche <hamza@les-tilleuls.coop>
3024
*/
31-
final class CollectionNormalizer implements NormalizerInterface, NormalizerAwareInterface
25+
final class CollectionNormalizer extends AbstractCollectionNormalizer
3226
{
33-
use ContextTrait;
34-
use NormalizerAwareTrait;
35-
3627
const FORMAT = 'jsonhal';
3728

38-
private $resourceClassResolver;
39-
private $pageParameterName;
40-
41-
public function __construct(ResourceClassResolverInterface $resourceClassResolver, string $pageParameterName)
42-
{
43-
$this->resourceClassResolver = $resourceClassResolver;
44-
$this->pageParameterName = $pageParameterName;
45-
}
46-
47-
/**
48-
* {@inheritdoc}
49-
*/
50-
public function supportsNormalization($data, $format = null)
51-
{
52-
return self::FORMAT === $format && (is_array($data) || ($data instanceof \Traversable));
53-
}
54-
5529
/**
5630
* {@inheritdoc}
5731
*/
58-
public function normalize($object, $format = null, array $context = [])
32+
protected function getPaginationData($object, array $context = []): array
5933
{
60-
$data = [];
61-
if (isset($context['api_sub_level'])) {
62-
foreach ($object as $index => $obj) {
63-
$data[$index] = $this->normalizer->normalize($obj, $format, $context);
64-
}
65-
66-
return $data;
67-
}
68-
69-
$resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, true);
70-
$context = $this->initContext($resourceClass, $context);
34+
list($paginator, $paginated, $currentPage, $itemsPerPage, $lastPage, $pageTotalItems, $totalItems) = $this->getPaginationConfig($object, $context);
7135
$parsed = IriHelper::parseIri($context['request_uri'] ?? '/', $this->pageParameterName);
7236

73-
$currentPage = $lastPage = $itemsPerPage = $pageTotalItems = null;
74-
if ($paginated = $isPaginator = $object instanceof PartialPaginatorInterface) {
75-
if ($object instanceof PaginatorInterface) {
76-
$paginated = 1. !== $lastPage = $object->getLastPage();
77-
} else {
78-
$pageTotalItems = (float) count($object);
79-
}
80-
81-
$currentPage = $object->getCurrentPage();
82-
$itemsPerPage = $object->getItemsPerPage();
83-
}
84-
8537
$data = [
8638
'_links' => [
8739
'self' => IriHelper::createIri($parsed['parts'], $parsed['parameters'], $this->pageParameterName, $paginated ? $currentPage : null),
@@ -103,26 +55,31 @@ public function normalize($object, $format = null, array $context = [])
10355
}
10456
}
10557

58+
if (null !== $totalItems) {
59+
$data['totalItems'] = $totalItems;
60+
}
61+
62+
if ($paginator) {
63+
$data['itemsPerPage'] = (int) $itemsPerPage;
64+
}
65+
66+
return $data;
67+
}
68+
69+
/**
70+
* {@inheritdoc}
71+
*/
72+
protected function getItemsData($object, string $format = null, array $context = []): array
73+
{
74+
$data = [];
75+
10676
foreach ($object as $obj) {
10777
$item = $this->normalizer->normalize($obj, $format, $context);
10878

10979
$data['_embedded']['item'][] = $item;
11080
$data['_links']['item'][] = $item['_links']['self'];
11181
}
11282

113-
$paginated = null;
114-
if (
115-
is_array($object) ||
116-
($paginated = $object instanceof PaginatorInterface) ||
117-
$object instanceof \Countable && !$object instanceof PartialPaginatorInterface
118-
) {
119-
$data['totalItems'] = $paginated ? (int) $object->getTotalItems() : count($object);
120-
}
121-
122-
if ($isPaginator) {
123-
$data['itemsPerPage'] = (int) $itemsPerPage;
124-
}
125-
12683
return $data;
12784
}
12885
}

src/JsonApi/Serializer/CollectionNormalizer.php

Lines changed: 29 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,9 @@
1313

1414
namespace ApiPlatform\Core\JsonApi\Serializer;
1515

16-
use ApiPlatform\Core\Api\ResourceClassResolverInterface;
17-
use ApiPlatform\Core\DataProvider\PaginatorInterface;
18-
use ApiPlatform\Core\DataProvider\PartialPaginatorInterface;
19-
use ApiPlatform\Core\Exception\RuntimeException;
20-
use ApiPlatform\Core\Serializer\ContextTrait;
16+
use ApiPlatform\Core\Exception\InvalidArgumentException;
17+
use ApiPlatform\Core\Serializer\AbstractCollectionNormalizer;
2118
use ApiPlatform\Core\Util\IriHelper;
22-
use Symfony\Component\Serializer\Normalizer\NormalizerAwareInterface;
23-
use Symfony\Component\Serializer\Normalizer\NormalizerAwareTrait;
24-
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
2519

2620
/**
2721
* Normalizes collections in the JSON API format.
@@ -30,62 +24,19 @@
3024
* @author Hamza Amrouche <hamza@les-tilleuls.coop>
3125
* @author Baptiste Meyer <baptiste.meyer@gmail.com>
3226
*/
33-
final class CollectionNormalizer implements NormalizerInterface, NormalizerAwareInterface
27+
final class CollectionNormalizer extends AbstractCollectionNormalizer
3428
{
35-
use ContextTrait;
36-
use NormalizerAwareTrait;
37-
3829
const FORMAT = 'jsonapi';
3930

40-
private $resourceClassResolver;
41-
private $pageParameterName;
42-
43-
public function __construct(ResourceClassResolverInterface $resourceClassResolver, string $pageParameterName)
44-
{
45-
$this->resourceClassResolver = $resourceClassResolver;
46-
$this->pageParameterName = $pageParameterName;
47-
}
48-
49-
/**
50-
* {@inheritdoc}
51-
*/
52-
public function supportsNormalization($data, $format = null)
53-
{
54-
return self::FORMAT === $format && (is_array($data) || ($data instanceof \Traversable));
55-
}
56-
5731
/**
5832
* {@inheritdoc}
5933
*/
60-
public function normalize($object, $format = null, array $context = [])
34+
protected function getPaginationData($object, array $context = []): array
6135
{
62-
$data = [];
63-
if (isset($context['api_sub_level'])) {
64-
foreach ($object as $index => $obj) {
65-
$data[$index] = $this->normalizer->normalize($obj, $format, $context);
66-
}
67-
68-
return $data;
69-
}
70-
71-
$resourceClass = $this->resourceClassResolver->getResourceClass($object, $context['resource_class'] ?? null, true);
72-
$context = $this->initContext($resourceClass, $context);
36+
list($paginator, $paginated, $currentPage, $itemsPerPage, $lastPage, $pageTotalItems, $totalItems) = $this->getPaginationConfig($object, $context);
7337
$parsed = IriHelper::parseIri($context['request_uri'] ?? '/', $this->pageParameterName);
7438

75-
$currentPage = $lastPage = $itemsPerPage = $pageTotalItems = null;
76-
if ($paginated = $isPaginator = $object instanceof PartialPaginatorInterface) {
77-
if ($object instanceof PaginatorInterface) {
78-
$paginated = 1. !== $lastPage = $object->getLastPage();
79-
} else {
80-
$pageTotalItems = (float) count($object);
81-
}
82-
83-
$currentPage = $object->getCurrentPage();
84-
$itemsPerPage = $object->getItemsPerPage();
85-
}
86-
8739
$data = [
88-
'data' => [],
8940
'links' => [
9041
'self' => IriHelper::createIri($parsed['parts'], $parsed['parameters'], $this->pageParameterName, $paginated ? $currentPage : null),
9142
],
@@ -106,29 +57,39 @@ public function normalize($object, $format = null, array $context = [])
10657
}
10758
}
10859

60+
if (null !== $totalItems) {
61+
$data['meta']['totalItems'] = $totalItems;
62+
}
63+
64+
if ($paginator) {
65+
$data['meta']['itemsPerPage'] = (int) $itemsPerPage;
66+
$data['meta']['currentPage'] = (int) $currentPage;
67+
}
68+
69+
return $data;
70+
}
71+
72+
/**
73+
* {@inheritdoc}
74+
*
75+
* @throws InvalidArgumentException
76+
*/
77+
protected function getItemsData($object, string $format = null, array $context = []): array
78+
{
79+
$data = [
80+
'data' => [],
81+
];
82+
10983
foreach ($object as $obj) {
11084
$item = $this->normalizer->normalize($obj, $format, $context);
11185

11286
if (!isset($item['data'])) {
113-
throw new RuntimeException('The JSON API document must contain a "data" key.');
87+
throw new InvalidArgumentException('The JSON API document must contain a "data" key.');
11488
}
11589

11690
$data['data'][] = $item['data'];
11791
}
11892

119-
if (
120-
is_array($object) ||
121-
($paginated = $object instanceof PaginatorInterface) ||
122-
$object instanceof \Countable && !$object instanceof PartialPaginatorInterface
123-
) {
124-
$data['meta']['totalItems'] = $paginated ? (int) $object->getTotalItems() : count($object);
125-
}
126-
127-
if ($isPaginator) {
128-
$data['meta']['itemsPerPage'] = (int) $itemsPerPage;
129-
$data['meta']['currentPage'] = (int) $currentPage;
130-
}
131-
13293
return $data;
13394
}
13495
}

0 commit comments

Comments
 (0)