Skip to content

Commit b88c562

Browse files
committed
Refactor the entrypoint system
1 parent 4bfd44a commit b88c562

File tree

13 files changed

+94
-90
lines changed

13 files changed

+94
-90
lines changed

src/Action/EntrypointAction.php

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@
1111

1212
namespace ApiPlatform\Core\Action;
1313

14-
use ApiPlatform\Core\JsonLd\EntrypointBuilderInterface;
14+
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceNameCollectionFactoryInterface;
15+
use ApiPlatform\Core\Metadata\Resource\ResourceNameCollection;
1516

1617
/**
1718
* Generates the API entrypoint.
@@ -20,15 +21,15 @@
2021
*/
2122
final class EntrypointAction
2223
{
23-
private $entrypointBuilder;
24+
private $resourceNameCollectionFactory;
2425

25-
public function __construct(EntrypointBuilderInterface $entrypointBuilder)
26+
public function __construct(ResourceNameCollectionFactoryInterface $resourceNameCollection)
2627
{
27-
$this->entrypointBuilder = $entrypointBuilder;
28+
$this->resourceNameCollectionFactory = $resourceNameCollection;
2829
}
2930

30-
public function __invoke() : array
31+
public function __invoke() : ResourceNameCollection
3132
{
32-
return $this->entrypointBuilder->getEntrypoint();
33+
return $this->resourceNameCollectionFactory->create();
3334
}
3435
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
2626
<argument type="service" id="api_platform.naming.resource_path_naming_strategy" />
2727
<argument type="service" id="service_container" />
28+
<argument>%api_platform.formats%</argument>
29+
2830
<tag name="routing.loader" />
2931
</service>
3032

@@ -114,6 +116,10 @@
114116
<service id="api_platform.action.get_item" alias="api_platform.action.placeholder" />
115117
<service id="api_platform.action.put_item" alias="api_platform.action.placeholder" />
116118
<service id="api_platform.action.delete_item" alias="api_platform.action.placeholder" />
119+
120+
<service id="api_platform.action.entrypoint" class="ApiPlatform\Core\Action\EntrypointAction">
121+
<argument type="service" id="api_platform.metadata.resource.name_collection_factory" />
122+
</service>
117123
</services>
118124

119125
</container>

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

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

77
<services>
8-
<service id="api_platform.hydra.entrypoint_builder" class="ApiPlatform\Core\Hydra\EntrypointBuilder" public="false">
9-
<argument type="service" id="api_platform.metadata.resource.name_collection_factory" />
10-
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
11-
<argument type="service" id="api_platform.iri_converter" />
12-
<argument type="service" id="api_platform.router" />
13-
</service>
14-
158
<service id="api_platform.hydra.documentation_builder" class="ApiPlatform\Core\Hydra\ApiDocumentationBuilder" public="false">
169
<argument type="service" id="api_platform.metadata.resource.name_collection_factory" />
1710
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
@@ -49,12 +42,21 @@
4942

5043
<!-- Serializer -->
5144

45+
<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" />
47+
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
48+
<argument type="service" id="api_platform.iri_converter" />
49+
<argument type="service" id="api_platform.router" />
50+
51+
<tag name="serializer.normalizer" priority="32" />
52+
</service>
53+
5254
<service id="api_platform.hydra.normalizer.collection" class="ApiPlatform\Core\Hydra\Serializer\CollectionNormalizer" public="false">
5355
<argument type="service" id="api_platform.jsonld.context_builder" />
5456
<argument type="service" id="api_platform.resource_class_resolver" />
5557
<argument type="service" id="api_platform.iri_converter" />
5658

57-
<tag name="serializer.normalizer" priority="50" />
59+
<tag name="serializer.normalizer" priority="16" />
5860
</service>
5961

6062
<service id="api_platform.hydra.normalizer.constraint_violation_list" class="ApiPlatform\Core\Bridge\Symfony\Validator\Hydra\Serializer\ConstraintViolationListNormalizer" public="false">
@@ -82,11 +84,8 @@
8284
<argument type="service" id="api_platform.resource_class_resolver" />
8385
<argument type="service" id="api_platform.filters" />
8486
</service>
85-
<!-- Action -->
8687

87-
<service id="api_platform.action.entrypoint" class="ApiPlatform\Core\Action\EntrypointAction">
88-
<argument type="service" id="api_platform.hydra.entrypoint_builder" />
89-
</service>
88+
<!-- Action -->
9089

9190
<service id="api_platform.hydra.action.documentation" class="ApiPlatform\Core\Documentation\Action\DocumentationAction">
9291
<argument type="service" id="api_platform.hydra.documentation_builder" />

src/Bridge/Symfony/Bundle/Resources/config/routing/hal.xml renamed to src/Bridge/Symfony/Bundle/Resources/config/routing/api.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
xsi:schemaLocation="http://symfony.com/schema/routing
66
http://symfony.com/schema/routing/routing-1.0.xsd">
77

8-
<route id="api_hal_entrypoint" path="/{index}.jsonhal">
8+
<route id="api_entrypoint" path="/{index}.{_format}">
99
<default key="_controller">api_platform.action.entrypoint</default>
10+
<default key="_format" />
1011
<default key="_api_respond">1</default>
1112
<default key="index">index</default>
1213
<requirement key="index">index</requirement>

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

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,6 @@
55
xsi:schemaLocation="http://symfony.com/schema/routing
66
http://symfony.com/schema/routing/routing-1.0.xsd">
77

8-
<route id="api_hydra_entrypoint" path="/{index}.{_format}">
9-
<default key="_controller">api_platform.action.entrypoint</default>
10-
<default key="_api_respond">1</default>
11-
<default key="_format">jsonld</default>
12-
<default key="index">index</default>
13-
<requirement key="index">index</requirement>
14-
</route>
15-
168
<route id="api_hydra_doc" path="/apidoc.{_format}">
179
<default key="_controller">api_platform.hydra.action.documentation</default>
1810
<default key="_api_respond">1</default>

src/Bridge/Symfony/Bundle/Resources/config/routing/jsonld.xml

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,6 @@
55
xsi:schemaLocation="http://symfony.com/schema/routing
66
http://symfony.com/schema/routing/routing-1.0.xsd">
77

8-
<route id="api_jsonld_entrypoint" path="/{index}.{_format}">
9-
<default key="_controller">api_platform.action.entrypoint</default>
10-
<default key="_api_respond">1</default>
11-
<default key="_format">jsonld</default>
12-
<default key="index">index</default>
13-
<requirement key="index">index</requirement>
14-
</route>
15-
168
<route id="api_jsonld_context" path="/contexts/{shortName}.{_format}">
179
<default key="_controller">api_platform.jsonld.action.context</default>
1810
<default key="_api_respond">1</default>

src/Bridge/Symfony/Routing/ApiLoader.php

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,16 @@ final class ApiLoader extends Loader
4040
private $resourceMetadataFactory;
4141
private $resourcePathGenerator;
4242
private $container;
43+
private $formats;
4344

44-
public function __construct(KernelInterface $kernel, ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, ResourceMetadataFactoryInterface $resourceMetadataFactory, ResourcePathNamingStrategyInterface $resourcePathGenerator, ContainerInterface $container)
45+
public function __construct(KernelInterface $kernel, ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, ResourceMetadataFactoryInterface $resourceMetadataFactory, ResourcePathNamingStrategyInterface $resourcePathGenerator, ContainerInterface $container, array $formats)
4546
{
4647
$this->fileLoader = new XmlFileLoader(new FileLocator($kernel->locateResource('@ApiPlatformBundle/Resources/config/routing')));
4748
$this->resourceNameCollectionFactory = $resourceNameCollectionFactory;
4849
$this->resourceMetadataFactory = $resourceMetadataFactory;
4950
$this->resourcePathGenerator = $resourcePathGenerator;
5051
$this->container = $container;
52+
$this->formats = $formats;
5153
}
5254

5355
/**
@@ -57,9 +59,7 @@ public function load($data, $type = null)
5759
{
5860
$routeCollection = new RouteCollection();
5961

60-
$routeCollection->addCollection($this->fileLoader->load('hal.xml'));
61-
$routeCollection->addCollection($this->fileLoader->load('jsonld.xml'));
62-
$routeCollection->addCollection($this->fileLoader->load('hydra.xml'));
62+
$this->loadExternalFiles($routeCollection);
6363

6464
if ($this->container->getParameter('api_platform.enable_swagger')) {
6565
$routeCollection->addCollection($this->fileLoader->load('swagger.xml'));
@@ -92,6 +92,21 @@ public function supports($resource, $type = null)
9292
return 'api_platform' === $type;
9393
}
9494

95+
/**
96+
* Load external files.
97+
*
98+
* @param RouteCollection $routeCollection
99+
*/
100+
private function loadExternalFiles(RouteCollection $routeCollection)
101+
{
102+
$routeCollection->addCollection($this->fileLoader->load('api.xml'));
103+
104+
if (isset($this->formats['jsonld'])) {
105+
$routeCollection->addCollection($this->fileLoader->load('jsonld.xml'));
106+
$routeCollection->addCollection($this->fileLoader->load('hydra.xml'));
107+
}
108+
}
109+
95110
/**
96111
* Creates and adds a route for the given operation to the route collection.
97112
*

src/EventListener/SerializeListener.php

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use ApiPlatform\Core\Exception\RuntimeException;
1515
use ApiPlatform\Core\Serializer\SerializerContextBuilderInterface;
1616
use ApiPlatform\Core\Util\RequestAttributesExtractor;
17+
use Symfony\Component\HttpFoundation\Request;
1718
use Symfony\Component\HttpFoundation\Response;
1819
use Symfony\Component\HttpKernel\Event\GetResponseForControllerResultEvent;
1920
use Symfony\Component\Serializer\Encoder\EncoderInterface;
@@ -49,17 +50,10 @@ public function onKernelView(GetResponseForControllerResultEvent $event)
4950
return;
5051
}
5152

52-
if ($request->attributes->get('_api_respond') && !is_object($controllerResult)) {
53-
if (!$this->serializer instanceof EncoderInterface) {
54-
throw new RuntimeException('The serializer instance must implements the "%s" interface.', EncoderInterface::class);
55-
}
56-
57-
$event->setControllerResult($this->serializer->encode($controllerResult, $request->getRequestFormat()));
58-
}
59-
6053
try {
6154
$attributes = RequestAttributesExtractor::extractAttributes($request);
6255
} catch (RuntimeException $e) {
56+
$this->serializeRawData($event, $request, $controllerResult);
6357
return;
6458
}
6559

@@ -68,4 +62,30 @@ public function onKernelView(GetResponseForControllerResultEvent $event)
6862

6963
$event->setControllerResult($this->serializer->serialize($controllerResult, $request->getRequestFormat(), $context));
7064
}
65+
66+
/**
67+
* Tries to serialize data that are not API resources (e.g. the entrypoint or data returned by a custom controller).
68+
*
69+
* @param GetResponseForControllerResultEvent $event
70+
* @param Request $request
71+
* @param object $controllerResult
72+
*/
73+
private function serializeRawData(GetResponseForControllerResultEvent $event, Request $request, $controllerResult)
74+
{
75+
if (!$request->attributes->get('_api_respond')) {
76+
return;
77+
}
78+
79+
if (is_object($controllerResult)) {
80+
$event->setControllerResult($this->serializer->serialize($controllerResult, $request->getRequestFormat()));
81+
82+
return;
83+
}
84+
85+
if (!$this->serializer instanceof EncoderInterface) {
86+
throw new RuntimeException('The serializer instance must implements the "%s" interface.', EncoderInterface::class);
87+
}
88+
89+
$event->setControllerResult($this->serializer->encode($controllerResult, $request->getRequestFormat()));
90+
}
7191
}

src/Hydra/ApiDocumentationBuilder.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ public function getApiDocumentation() : array
248248
$doc['hydra:description'] = $this->description;
249249
}
250250

251-
$doc['hydra:entrypoint'] = $this->urlGenerator->generate('api_hydra_entrypoint');
251+
$doc['hydra:entrypoint'] = $this->urlGenerator->generate('api_entrypoint');
252252
$doc['hydra:supportedClass'] = $classes;
253253

254254
return $doc;

src/Hydra/EntrypointBuilder.php renamed to src/Hydra/Serializer/ResourceNameCollectionNormalizer.php

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,25 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
namespace ApiPlatform\Core\Hydra;
12+
namespace ApiPlatform\Core\Hydra\Serializer;
1313

1414
use ApiPlatform\Core\Api\IriConverterInterface;
1515
use ApiPlatform\Core\Api\UrlGeneratorInterface;
1616
use ApiPlatform\Core\Exception\InvalidArgumentException;
17-
use ApiPlatform\Core\JsonLd\EntrypointBuilderInterface;
1817
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
1918
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceNameCollectionFactoryInterface;
19+
use ApiPlatform\Core\Metadata\Resource\ResourceNameCollection;
20+
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
2021

2122
/**
22-
* {@inheritdoc}
23+
* Normalizes the API entrypoint.
2324
*
2425
* @author Kévin Dunglas <[email protected]>
2526
*/
26-
final class EntrypointBuilder implements EntrypointBuilderInterface
27+
final class ResourceNameCollectionNormalizer implements NormalizerInterface
2728
{
29+
const FORMAT = 'jsonld';
30+
2831
private $resourceNameCollectionFactory;
2932
private $resourceMetadataFactory;
3033
private $iriConverter;
@@ -41,11 +44,11 @@ public function __construct(ResourceNameCollectionFactoryInterface $resourceName
4144
/**
4245
* {@inheritdoc}
4346
*/
44-
public function getEntrypoint(string $referenceType = UrlGeneratorInterface::ABS_PATH) : array
47+
public function normalize($object, $format = null, array $context = array())
4548
{
4649
$entrypoint = [
47-
'@context' => $this->urlGenerator->generate('api_jsonld_context', ['shortName' => 'Entrypoint'], $referenceType),
48-
'@id' => $this->urlGenerator->generate('api_hydra_entrypoint', [], $referenceType),
50+
'@context' => $this->urlGenerator->generate('api_jsonld_context', ['shortName' => 'Entrypoint']),
51+
'@id' => $this->urlGenerator->generate('api_entrypoint'),
4952
'@type' => 'Entrypoint',
5053
];
5154

@@ -64,4 +67,12 @@ public function getEntrypoint(string $referenceType = UrlGeneratorInterface::ABS
6467

6568
return $entrypoint;
6669
}
70+
71+
/**
72+
* {@inheritdoc}
73+
*/
74+
public function supportsNormalization($data, $format = null)
75+
{
76+
return self::FORMAT === $format && $data instanceof ResourceNameCollection;
77+
}
6778
}

0 commit comments

Comments
 (0)