Skip to content

Commit ac4a097

Browse files
committed
Add HAL support for the entrypoint
1 parent b88c562 commit ac4a097

File tree

12 files changed

+237
-18
lines changed

12 files changed

+237
-18
lines changed

features/hal.feature

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ Feature: HAL support
44
I need to be able to retrieve valid HAL responses.
55

66
@createSchema
7+
Scenario: Retrieve the API entrypoint
8+
When I add "Accept" header equal to "application/hal+json"
9+
And I send a "GET" request to "/"
10+
Then the response status code should be 200
11+
And the response should be in JSON
12+
And the header "Content-Type" should be equal to "application/hal+json"
13+
And the JSON node "_links.self.href" should be equal to "/"
14+
And the JSON node "_links.dummy.href" should be equal to "/dummies"
15+
716
Scenario: Create a third level
817
When I add "Content-Type" header equal to "application/json"
918
And I send a "POST" request to "/third_levels" with body:

src/Bridge/Symfony/Bundle/Resources/config/hal.xml

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,27 @@
55
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
66

77
<services>
8-
<!-- Serializer -->
98
<service id="api_platform.hal.encoder" class="ApiPlatform\Core\Serializer\JsonEncoder" public="false">
109
<argument>jsonhal</argument>
1110

1211
<tag name="serializer.encoder" />
1312
</service>
1413

14+
<service id="api_platform.hal.normalizer.resource_name_collection" class="ApiPlatform\Core\Hal\Serializer\ResourceNameCollectionNormalizer" public="false">
15+
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
16+
<argument type="service" id="api_platform.iri_converter" />
17+
<argument type="service" id="api_platform.router" />
18+
19+
<tag name="serializer.normalizer" priority="32" />
20+
</service>
21+
22+
<service id="api_platform.hal.normalizer.collection" class="ApiPlatform\Core\Hal\Serializer\CollectionNormalizer" public="false">
23+
<argument type="service" id="api_platform.resource_class_resolver" />
24+
<argument>%api_platform.collection.pagination.page_parameter_name%</argument>
25+
26+
<tag name="serializer.normalizer" priority="16" />
27+
</service>
28+
1529
<service id="api_platform.hal.normalizer.item" class="ApiPlatform\Core\Hal\Serializer\ItemNormalizer" public="false">
1630
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
1731
<argument type="service" id="api_platform.metadata.property.name_collection_factory" />
@@ -23,13 +37,6 @@
2337

2438
<tag name="serializer.normalizer" priority="8" />
2539
</service>
26-
27-
<service id="api_platform.hal.normalizer.collection" class="ApiPlatform\Core\Hal\Serializer\CollectionNormalizer" public="false">
28-
<argument type="service" id="api_platform.resource_class_resolver" />
29-
<argument>%api_platform.collection.pagination.page_parameter_name%</argument>
30-
31-
<tag name="serializer.normalizer" priority="50" />
32-
</service>
3340
</services>
3441

3542
</container>

src/Bridge/Symfony/Bundle/Resources/config/hydra.xml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
<!-- Serializer -->
4444

4545
<service id="api_platform.hydra.normalizer.resource_name_collection" class="ApiPlatform\Core\Hydra\Serializer\ResourceNameCollectionNormalizer" public="false">
46-
<argument type="service" id="api_platform.metadata.resource.name_collection_factory" />
4746
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
4847
<argument type="service" id="api_platform.iri_converter" />
4948
<argument type="service" id="api_platform.router" />

src/EventListener/SerializeListener.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ public function onKernelView(GetResponseForControllerResultEvent $event)
5454
$attributes = RequestAttributesExtractor::extractAttributes($request);
5555
} catch (RuntimeException $e) {
5656
$this->serializeRawData($event, $request, $controllerResult);
57+
5758
return;
5859
}
5960

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the API Platform project.
5+
*
6+
* (c) Kévin Dunglas <[email protected]>
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+
namespace ApiPlatform\Core\Hal\Serializer;
13+
14+
use ApiPlatform\Core\Api\IriConverterInterface;
15+
use ApiPlatform\Core\Api\UrlGeneratorInterface;
16+
use ApiPlatform\Core\Exception\InvalidArgumentException;
17+
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
18+
use ApiPlatform\Core\Metadata\Resource\ResourceNameCollection;
19+
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
20+
21+
/**
22+
* Normalizes the API entrypoint.
23+
*
24+
* @author Kévin Dunglas <[email protected]>
25+
*/
26+
final class ResourceNameCollectionNormalizer implements NormalizerInterface
27+
{
28+
const FORMAT = 'jsonhal';
29+
30+
private $resourceMetadataFactory;
31+
private $iriConverter;
32+
private $urlGenerator;
33+
34+
public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory, IriConverterInterface $iriConverter, UrlGeneratorInterface $urlGenerator)
35+
{
36+
$this->resourceMetadataFactory = $resourceMetadataFactory;
37+
$this->iriConverter = $iriConverter;
38+
$this->urlGenerator = $urlGenerator;
39+
}
40+
41+
/**
42+
* {@inheritdoc}
43+
*/
44+
public function normalize($object, $format = null, array $context = [])
45+
{
46+
$entrypoint = ['_links' => ['self' => ['href' => $this->urlGenerator->generate('api_entrypoint')]]];
47+
48+
foreach ($object as $resourceClass) {
49+
$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
50+
51+
if (empty($resourceMetadata->getCollectionOperations())) {
52+
continue;
53+
}
54+
try {
55+
$entrypoint['_links'][lcfirst($resourceMetadata->getShortName())]['href'] = $this->iriConverter->getIriFromResourceClass($resourceClass);
56+
} catch (InvalidArgumentException $ex) {
57+
// Ignore resources without GET operations
58+
}
59+
}
60+
61+
return $entrypoint;
62+
}
63+
64+
/**
65+
* {@inheritdoc}
66+
*/
67+
public function supportsNormalization($data, $format = null)
68+
{
69+
return self::FORMAT === $format && $data instanceof ResourceNameCollection;
70+
}
71+
}

src/Hydra/Serializer/ResourceNameCollectionNormalizer.php

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
use ApiPlatform\Core\Api\UrlGeneratorInterface;
1616
use ApiPlatform\Core\Exception\InvalidArgumentException;
1717
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
18-
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceNameCollectionFactoryInterface;
1918
use ApiPlatform\Core\Metadata\Resource\ResourceNameCollection;
2019
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
2120

@@ -28,14 +27,12 @@ final class ResourceNameCollectionNormalizer implements NormalizerInterface
2827
{
2928
const FORMAT = 'jsonld';
3029

31-
private $resourceNameCollectionFactory;
3230
private $resourceMetadataFactory;
3331
private $iriConverter;
3432
private $urlGenerator;
3533

36-
public function __construct(ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, ResourceMetadataFactoryInterface $resourceMetadataFactory, IriConverterInterface $iriConverter, UrlGeneratorInterface $urlGenerator)
34+
public function __construct(ResourceMetadataFactoryInterface $resourceMetadataFactory, IriConverterInterface $iriConverter, UrlGeneratorInterface $urlGenerator)
3735
{
38-
$this->resourceNameCollectionFactory = $resourceNameCollectionFactory;
3936
$this->resourceMetadataFactory = $resourceMetadataFactory;
4037
$this->iriConverter = $iriConverter;
4138
$this->urlGenerator = $urlGenerator;
@@ -44,15 +41,15 @@ public function __construct(ResourceNameCollectionFactoryInterface $resourceName
4441
/**
4542
* {@inheritdoc}
4643
*/
47-
public function normalize($object, $format = null, array $context = array())
44+
public function normalize($object, $format = null, array $context = [])
4845
{
4946
$entrypoint = [
5047
'@context' => $this->urlGenerator->generate('api_jsonld_context', ['shortName' => 'Entrypoint']),
5148
'@id' => $this->urlGenerator->generate('api_entrypoint'),
5249
'@type' => 'Entrypoint',
5350
];
5451

55-
foreach ($this->resourceNameCollectionFactory->create() as $resourceClass) {
52+
foreach ($object as $resourceClass) {
5653
$resourceMetadata = $this->resourceMetadataFactory->create($resourceClass);
5754

5855
if (empty($resourceMetadata->getCollectionOperations())) {

src/Serializer/ItemNormalizer.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,6 @@ public function denormalize($data, $class, $format = null, array $context = [])
4545
$context['object_to_populate'] = $this->iriConverter->getItemFromIri($data['id'], true);
4646
}
4747

48-
return parent::denormalize($data, $class, $format, $context); // TODO: Change the autogenerated stub
48+
return parent::denormalize($data, $class, $format, $context);
4949
}
5050
}

src/Swagger/ApiDocumentationBuilder.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,6 @@ public function getApiDocumentation() : array
180180
}
181181
}
182182

183-
184183
$resourceClassIri .= '/{id}';
185184

186185
$itemOperationsDocs[$resourceClassIri] = $operation['item'];

tests/Bridge/Symfony/Bundle/DependencyInjection/ApiPlatformExtensionTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,7 @@ private function getContainerBuilderProphecy()
289289
'api_platform.swagger.action.documentation',
290290
'api_platform.swagger.action.ui',
291291
'api_platform.hal.encoder',
292+
'api_platform.hal.normalizer.resource_name_collection',
292293
'api_platform.hal.normalizer.item',
293294
'api_platform.hal.normalizer.collection',
294295
'api_platform.hydra.action.documentation',

tests/Hal/Serializer/ItemNormalizerTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
namespace ApiPlatform\Core\Tests\Hal;
12+
namespace ApiPlatform\Core\Tests\Hal\Serializer;
1313

1414
use ApiPlatform\Core\Api\IriConverterInterface;
1515
use ApiPlatform\Core\Api\ResourceClassResolverInterface;

0 commit comments

Comments
 (0)