Skip to content

Commit b7033a4

Browse files
committed
fix(hydra): use correctly enable_docs
1 parent c636d98 commit b7033a4

File tree

6 files changed

+134
-27
lines changed

6 files changed

+134
-27
lines changed

Diff for: src/Hydra/Serializer/DocumentationNormalizer.php

+22-15
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ public function __construct(
5454
private readonly UrlGeneratorInterface $urlGenerator,
5555
private readonly ?NameConverterInterface $nameConverter = null,
5656
private readonly ?array $defaultContext = [],
57+
private readonly ?bool $entrypointEnabled = true,
58+
private readonly ?bool $docsEnabled = true,
5759
) {
5860
}
5961

@@ -65,8 +67,9 @@ public function normalize(mixed $object, ?string $format = null, array $context
6567
$classes = [];
6668
$entrypointProperties = [];
6769
$hydraPrefix = $this->getHydraPrefix($context + $this->defaultContext);
70+
$resourceClasses = $this->docsEnabled ? $object->getResourceNameCollection() : [];
6871

69-
foreach ($object->getResourceNameCollection() as $resourceClass) {
72+
foreach ($resourceClasses as $resourceClass) {
7073
$resourceMetadataCollection = $this->resourceMetadataFactory->create($resourceClass);
7174

7275
$resourceMetadata = $resourceMetadataCollection[0];
@@ -443,19 +446,21 @@ private function isSingleRelation(ApiProperty $propertyMetadata): bool
443446
*/
444447
private function getClasses(array $entrypointProperties, array $classes, string $hydraPrefix = ContextBuilder::HYDRA_PREFIX): array
445448
{
446-
$classes[] = [
447-
'@id' => '#Entrypoint',
448-
'@type' => $hydraPrefix.'Class',
449-
$hydraPrefix.'title' => 'Entrypoint',
450-
$hydraPrefix.'supportedProperty' => $entrypointProperties,
451-
$hydraPrefix.'supportedOperation' => [
452-
'@type' => $hydraPrefix.'Operation',
453-
$hydraPrefix.'method' => 'GET',
454-
$hydraPrefix.'title' => 'index',
455-
$hydraPrefix.'description' => 'The API Entrypoint.',
456-
$hydraPrefix.'returns' => 'Entrypoint',
457-
],
458-
];
449+
if ($this->entrypointEnabled) {
450+
$classes[] = [
451+
'@id' => '#Entrypoint',
452+
'@type' => $hydraPrefix.'Class',
453+
$hydraPrefix.'title' => 'Entrypoint',
454+
$hydraPrefix.'supportedProperty' => $entrypointProperties,
455+
$hydraPrefix.'supportedOperation' => [
456+
'@type' => $hydraPrefix.'Operation',
457+
$hydraPrefix.'method' => 'GET',
458+
$hydraPrefix.'title' => 'index',
459+
$hydraPrefix.'description' => 'The API Entrypoint.',
460+
$hydraPrefix.'returns' => 'Entrypoint',
461+
],
462+
];
463+
}
459464

460465
$classes[] = [
461466
'@id' => '#ConstraintViolationList',
@@ -560,7 +565,9 @@ private function computeDoc(Documentation $object, array $classes, string $hydra
560565
$doc[$hydraPrefix.'description'] = $object->getDescription();
561566
}
562567

563-
$doc[$hydraPrefix.'entrypoint'] = $this->urlGenerator->generate('api_entrypoint');
568+
if ($this->entrypointEnabled) {
569+
$doc[$hydraPrefix.'entrypoint'] = $this->urlGenerator->generate('api_entrypoint');
570+
}
564571
$doc[$hydraPrefix.'supportedClass'] = $classes;
565572

566573
return $doc;

Diff for: src/Hydra/Tests/Serializer/DocumentationNormalizerTest.php

+98
Original file line numberDiff line numberDiff line change
@@ -824,4 +824,102 @@ public function testNormalizeWithoutPrefix(): void
824824

825825
$this->assertEquals($expected, $documentationNormalizer->normalize($documentation, null, [ContextBuilder::HYDRA_CONTEXT_HAS_PREFIX => false]));
826826
}
827+
828+
public function testNormalizeNoEntrypointNoDocs(): void
829+
{
830+
$title = 'Test Api';
831+
$desc = 'test ApiGerard';
832+
$version = '0.0.0';
833+
$documentation = new Documentation(new ResourceNameCollection(['dummy' => 'dummy']), $title, $desc, $version);
834+
835+
$resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataCollectionFactoryInterface::class);
836+
$propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
837+
$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
838+
$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
839+
$urlGenerator = $this->prophesize(UrlGeneratorInterface::class);
840+
$urlGenerator->generate('api_doc', ['_format' => 'jsonld'], Argument::any())->willReturn('/doc');
841+
842+
$documentationNormalizer = new DocumentationNormalizer(
843+
$resourceMetadataFactoryProphecy->reveal(),
844+
$propertyNameCollectionFactoryProphecy->reveal(),
845+
$propertyMetadataFactoryProphecy->reveal(),
846+
$resourceClassResolverProphecy->reveal(),
847+
$urlGenerator->reveal(),
848+
new CustomConverter(),
849+
[],
850+
false,
851+
false,
852+
);
853+
854+
$expected = [
855+
'@context' => [
856+
HYDRA_CONTEXT,
857+
[
858+
'@vocab' => '/doc#',
859+
'hydra' => 'http://www.w3.org/ns/hydra/core#',
860+
'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
861+
'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#',
862+
'xmls' => 'http://www.w3.org/2001/XMLSchema#',
863+
'owl' => 'http://www.w3.org/2002/07/owl#',
864+
'schema' => 'https://schema.org/',
865+
'domain' => [
866+
'@id' => 'rdfs:domain',
867+
'@type' => '@id',
868+
],
869+
'range' => [
870+
'@id' => 'rdfs:range',
871+
'@type' => '@id',
872+
],
873+
'subClassOf' => [
874+
'@id' => 'rdfs:subClassOf',
875+
'@type' => '@id',
876+
],
877+
],
878+
],
879+
'@id' => '/doc',
880+
'@type' => 'ApiDocumentation',
881+
'title' => 'Test Api',
882+
'description' => 'test ApiGerard',
883+
'supportedClass' => [
884+
[
885+
'@id' => '#ConstraintViolationList',
886+
'@type' => 'Class',
887+
'title' => 'ConstraintViolationList',
888+
'description' => 'A constraint violation List.',
889+
'supportedProperty' => [
890+
[
891+
'@type' => 'SupportedProperty',
892+
'property' => [
893+
'@id' => '#ConstraintViolationList/propertyPath',
894+
'@type' => 'rdf:Property',
895+
'rdfs:label' => 'propertyPath',
896+
'domain' => '#ConstraintViolationList',
897+
'range' => 'xmls:string',
898+
],
899+
'title' => 'propertyPath',
900+
'description' => 'The property path of the violation',
901+
'readable' => true,
902+
'writeable' => false,
903+
],
904+
[
905+
'@type' => 'SupportedProperty',
906+
'property' => [
907+
'@id' => '#ConstraintViolationList/message',
908+
'@type' => 'rdf:Property',
909+
'rdfs:label' => 'message',
910+
'domain' => '#ConstraintViolationList',
911+
'range' => 'xmls:string',
912+
],
913+
'title' => 'message',
914+
'description' => 'The message associated with the violation',
915+
'readable' => true,
916+
'writeable' => false,
917+
],
918+
],
919+
],
920+
],
921+
];
922+
923+
$this->assertEquals($expected, $documentationNormalizer->normalize($documentation, null, [ContextBuilder::HYDRA_CONTEXT_HAS_PREFIX => false]));
924+
}
827925
}

Diff for: src/Laravel/ApiPlatformProvider.php

+5-1
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,8 @@ public function register(): void
731731
$this->app->singleton(HydraDocumentationNormalizer::class, function (Application $app) {
732732
$config = $app['config'];
733733
$defaultContext = $config->get('api-platform.serializer', []);
734+
$entrypointEnabled = $config->get('api-platform.enable_entrypoint', true);
735+
$docsEnabled = $config->get('api-platform.enable_docs', true);
734736

735737
return new HydraDocumentationNormalizer(
736738
$app->make(ResourceMetadataCollectionFactoryInterface::class),
@@ -739,7 +741,9 @@ public function register(): void
739741
$app->make(ResourceClassResolverInterface::class),
740742
$app->make(UrlGeneratorInterface::class),
741743
$app->make(NameConverterInterface::class),
742-
$defaultContext
744+
$defaultContext,
745+
$entrypointEnabled,
746+
$docsEnabled
743747
);
744748
});
745749

Diff for: src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php

+5-6
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,11 @@ public function load(array $configs, ContainerBuilder $container): void
111111
$formats = $this->getFormats($config['formats']);
112112
$patchFormats = $this->getFormats($config['patch_formats']);
113113
$errorFormats = $this->getFormats($config['error_formats']);
114-
$docsFormats = $this->getFormats($config['docs_formats']);
114+
// JSON-LD documentation format is mandatory, even if documentation is disabled.
115+
$docsFormats = ['jsonld' => ['application/ld+json']];
116+
if ($config['enable_docs']) {
117+
$docsFormats = $this->getFormats($config['docs_formats']);
118+
}
115119
$jsonSchemaFormats = $config['jsonschema_formats'];
116120

117121
if (!$jsonSchemaFormats) {
@@ -538,11 +542,6 @@ private function registerJsonLdHydraConfiguration(ContainerBuilder $container, a
538542
if (!$container->has('api_platform.json_schema.schema_factory')) {
539543
$container->removeDefinition('api_platform.hydra.json_schema.schema_factory');
540544
}
541-
542-
if (!$config['enable_docs']) {
543-
$container->removeDefinition('api_platform.hydra.listener.response.add_link_header');
544-
$container->removeDefinition('api_platform.hydra.processor.link');
545-
}
546545
}
547546

548547
private function registerJsonHalConfiguration(array $formats, XmlFileLoader $loader): void

Diff for: src/Symfony/Bundle/Resources/config/hydra.xml

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
<argument type="service" id="api_platform.router" />
1818
<argument type="service" id="api_platform.name_converter" on-invalid="ignore" />
1919
<argument>%api_platform.serializer.default_context%</argument>
20+
<argument>%api_platform.enable_entrypoint%</argument>
21+
<argument>%api_platform.enable_docs%</argument>
2022

2123
<tag name="serializer.normalizer" priority="-800" />
2224
</service>

Diff for: src/Symfony/Routing/ApiLoader.php

+2-5
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ final class ApiLoader extends Loader
3636

3737
private readonly XmlFileLoader $fileLoader;
3838

39-
public function __construct(KernelInterface $kernel, private readonly ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, private readonly ResourceMetadataCollectionFactoryInterface $resourceMetadataFactory, private readonly ContainerInterface $container, private readonly array $formats, private readonly array $resourceClassDirectories = [], private readonly bool $graphqlEnabled = false, private readonly bool $entrypointEnabled = true, private readonly bool $docsEnabled = true, private readonly bool $graphiQlEnabled = false, private readonly bool $graphQlPlaygroundEnabled = false)
39+
public function __construct(KernelInterface $kernel, private readonly ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, private readonly ResourceMetadataCollectionFactoryInterface $resourceMetadataFactory, private readonly ContainerInterface $container, private readonly array $formats, private readonly array $resourceClassDirectories = [], private readonly bool $graphqlEnabled = false, private readonly bool $entrypointEnabled = true, readonly bool $docsEnabled = true, private readonly bool $graphiQlEnabled = false, private readonly bool $graphQlPlaygroundEnabled = false)
4040
{
4141
/** @var string[]|string $paths */
4242
$paths = $kernel->locateResource('@ApiPlatformBundle/Resources/config/routing');
@@ -124,17 +124,14 @@ public function supports(mixed $resource, ?string $type = null): bool
124124
*/
125125
private function loadExternalFiles(RouteCollection $routeCollection): void
126126
{
127+
$routeCollection->addCollection($this->fileLoader->load('docs.xml'));
127128
$routeCollection->addCollection($this->fileLoader->load('genid.xml'));
128129
$routeCollection->addCollection($this->fileLoader->load('errors.xml'));
129130

130131
if ($this->entrypointEnabled) {
131132
$routeCollection->addCollection($this->fileLoader->load('api.xml'));
132133
}
133134

134-
if ($this->docsEnabled) {
135-
$routeCollection->addCollection($this->fileLoader->load('docs.xml'));
136-
}
137-
138135
if ($this->graphqlEnabled) {
139136
$graphqlCollection = $this->fileLoader->load('graphql/graphql.xml');
140137
$graphqlCollection->addDefaults(['_graphql' => true]);

0 commit comments

Comments
 (0)