Skip to content

Commit 61e9427

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

File tree

6 files changed

+133
-25
lines changed

6 files changed

+133
-25
lines changed

src/Hydra/Serializer/DocumentationNormalizer.php

+19-14
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ 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,
5758
) {
5859
}
5960

@@ -443,19 +444,21 @@ private function isSingleRelation(ApiProperty $propertyMetadata): bool
443444
*/
444445
private function getClasses(array $entrypointProperties, array $classes, string $hydraPrefix = ContextBuilder::HYDRA_PREFIX): array
445446
{
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-
];
447+
if ($this->entrypointEnabled) {
448+
$classes[] = [
449+
'@id' => '#Entrypoint',
450+
'@type' => $hydraPrefix.'Class',
451+
$hydraPrefix.'title' => 'Entrypoint',
452+
$hydraPrefix.'supportedProperty' => $entrypointProperties,
453+
$hydraPrefix.'supportedOperation' => [
454+
'@type' => $hydraPrefix.'Operation',
455+
$hydraPrefix.'method' => 'GET',
456+
$hydraPrefix.'title' => 'index',
457+
$hydraPrefix.'description' => 'The API Entrypoint.',
458+
$hydraPrefix.'returns' => 'Entrypoint',
459+
],
460+
];
461+
}
459462

460463
$classes[] = [
461464
'@id' => '#ConstraintViolationList',
@@ -560,7 +563,9 @@ private function computeDoc(Documentation $object, array $classes, string $hydra
560563
$doc[$hydraPrefix.'description'] = $object->getDescription();
561564
}
562565

563-
$doc[$hydraPrefix.'entrypoint'] = $this->urlGenerator->generate('api_entrypoint');
566+
if ($this->entrypointEnabled) {
567+
$doc[$hydraPrefix.'entrypoint'] = $this->urlGenerator->generate('api_entrypoint');
568+
}
564569
$doc[$hydraPrefix.'supportedClass'] = $classes;
565570

566571
return $doc;

src/Hydra/Tests/Serializer/DocumentationNormalizerTest.php

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

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

src/Laravel/ApiPlatformProvider.php

+3-1
Original file line numberDiff line numberDiff line change
@@ -731,6 +731,7 @@ 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);
734735

735736
return new HydraDocumentationNormalizer(
736737
$app->make(ResourceMetadataCollectionFactoryInterface::class),
@@ -739,7 +740,8 @@ public function register(): void
739740
$app->make(ResourceClassResolverInterface::class),
740741
$app->make(UrlGeneratorInterface::class),
741742
$app->make(NameConverterInterface::class),
742-
$defaultContext
743+
$defaultContext,
744+
$entrypointEnabled
743745
);
744746
});
745747

src/Symfony/Bundle/DependencyInjection/ApiPlatformExtension.php

+6-5
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,12 @@ public function load(array $configs, ContainerBuilder $container): void
112112
$patchFormats = $this->getFormats($config['patch_formats']);
113113
$errorFormats = $this->getFormats($config['error_formats']);
114114
$docsFormats = $this->getFormats($config['docs_formats']);
115+
if (!$config['enable_docs']) {
116+
// JSON-LD documentation format is mandatory, even if documentation is disabled.
117+
$docsFormats = isset($formats['jsonld']) ? ['jsonld' => ['application/ld+json']] : [];
118+
// If documentation is disabled, the Hydra documentation for all the resources is hidden by default.
119+
$config['defaults']['hideHydraOperation'] = true;
120+
}
115121
$jsonSchemaFormats = $config['jsonschema_formats'];
116122

117123
if (!$jsonSchemaFormats) {
@@ -538,11 +544,6 @@ private function registerJsonLdHydraConfiguration(ContainerBuilder $container, a
538544
if (!$container->has('api_platform.json_schema.schema_factory')) {
539545
$container->removeDefinition('api_platform.hydra.json_schema.schema_factory');
540546
}
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-
}
546547
}
547548

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

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

+1
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
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>
2021

2122
<tag name="serializer.normalizer" priority="-800" />
2223
</service>

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)