Skip to content

Commit a068efc

Browse files
author
Amrouche Hamza
committed
feat: Hydra - add apiDocumentationBuilder and remove deps on contextBuilder
1 parent cffda00 commit a068efc

File tree

4 files changed

+258
-9
lines changed

4 files changed

+258
-9
lines changed

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
<argument type="service" id="api_platform.metadata.resource.metadata_factory" />
1818
<argument type="service" id="api_platform.metadata.property.name_collection_factory" />
1919
<argument type="service" id="api_platform.metadata.property.metadata_factory" />
20-
<argument type="service" id="api_platform.jsonld.context_builder" />
2120
<argument type="service" id="api_platform.resource_class_resolver" />
2221
<argument type="service" id="api_platform.operation_method_resolver" />
2322
<argument type="service" id="api_platform.router" />

src/Hydra/ApiDocumentationBuilder.php

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,20 +35,18 @@ final class ApiDocumentationBuilder implements ApiDocumentationBuilderInterface
3535
private $resourceMetadataFactory;
3636
private $propertyNameCollectionFactory;
3737
private $propertyMetadataFactory;
38-
private $contextBuilder;
3938
private $resourceClassResolver;
4039
private $operationMethodResolver;
4140
private $urlGenerator;
4241
private $title;
4342
private $description;
4443

45-
public function __construct(ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, ResourceMetadataFactoryInterface $resourceMetadataFactory, PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, ContextBuilderInterface $contextBuilder, ResourceClassResolverInterface $resourceClassResolver, OperationMethodResolverInterface $operationMethodResolver, UrlGeneratorInterface $urlGenerator, string $title = '', string $description = '')
44+
public function __construct(ResourceNameCollectionFactoryInterface $resourceNameCollectionFactory, ResourceMetadataFactoryInterface $resourceMetadataFactory, PropertyNameCollectionFactoryInterface $propertyNameCollectionFactory, PropertyMetadataFactoryInterface $propertyMetadataFactory, ResourceClassResolverInterface $resourceClassResolver, OperationMethodResolverInterface $operationMethodResolver, UrlGeneratorInterface $urlGenerator, string $title = '', string $description = '')
4645
{
4746
$this->resourceNameCollectionFactory = $resourceNameCollectionFactory;
4847
$this->resourceMetadataFactory = $resourceMetadataFactory;
4948
$this->propertyNameCollectionFactory = $propertyNameCollectionFactory;
5049
$this->propertyMetadataFactory = $propertyMetadataFactory;
51-
$this->contextBuilder = $contextBuilder;
5250
$this->resourceClassResolver = $resourceClassResolver;
5351
$this->operationMethodResolver = $operationMethodResolver;
5452
$this->urlGenerator = $urlGenerator;
@@ -404,9 +402,10 @@ private function getRange(PropertyMetadata $propertyMetadata)
404402
*/
405403
private function getContext() : array
406404
{
407-
return array_merge(
408-
$this->contextBuilder->getBaseContext(UrlGeneratorInterface::ABS_URL),
405+
return
409406
[
407+
'@vocab' => $this->urlGenerator->generate('api_hydra_doc', [], UrlGeneratorInterface::ABS_URL).'#',
408+
'hydra' => ContextBuilderInterface::HYDRA_NS,
410409
'rdf' => ContextBuilderInterface::RDF_NS,
411410
'rdfs' => ContextBuilderInterface::RDFS_NS,
412411
'xmls' => ContextBuilderInterface::XML_NS,
@@ -416,7 +415,6 @@ private function getContext() : array
416415
'subClassOf' => ['@id' => 'rdfs:subClassOf', '@type' => '@id'],
417416
'expects' => ['@id' => 'hydra:expects', '@type' => '@id'],
418417
'returns' => ['@id' => 'hydra:returns', '@type' => '@id'],
419-
]
420-
);
418+
];
421419
}
422420
}
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
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\Tests\Hydra;
13+
14+
use ApiPlatform\Core\Api\OperationMethodResolverInterface;
15+
use ApiPlatform\Core\Api\ResourceClassResolverInterface;
16+
use ApiPlatform\Core\Api\UrlGeneratorInterface;
17+
use ApiPlatform\Core\Hydra\ApiDocumentationBuilder;
18+
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
19+
use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
20+
use ApiPlatform\Core\Metadata\Property\PropertyMetadata;
21+
use ApiPlatform\Core\Metadata\Property\PropertyNameCollection;
22+
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
23+
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceNameCollectionFactoryInterface;
24+
use ApiPlatform\Core\Metadata\Resource\ResourceMetadata;
25+
use ApiPlatform\Core\Metadata\Resource\ResourceNameCollection;
26+
use Prophecy\Argument;
27+
use Symfony\Component\PropertyInfo\Type;
28+
29+
/**
30+
* @author Amrouche Hamza <[email protected]>
31+
*/
32+
class ApiDocumentationBuilderTest extends \PHPUnit_Framework_TestCase /**/
33+
{
34+
public function testGetApiDocumention()
35+
{
36+
$title = 'Test Api';
37+
$desc = 'test ApiGerard';
38+
$formats = ['jsonld' => ['application/ld+json']];
39+
40+
$resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class);
41+
$resourceNameCollectionFactoryProphecy->create()->willReturn(new ResourceNameCollection(['dummy' => 'dummy']))->shouldBeCalled();
42+
43+
$propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
44+
$propertyNameCollectionFactoryProphecy->create('dummy', [])->shouldBeCalled()->willReturn(new PropertyNameCollection(['name']));
45+
46+
$dummyMetadata = new ResourceMetadata('dummy', 'dummy', '#dummy', ['get' => ['method' => 'GET'], 'put' => ['method' => 'PUT']], ['get' => ['method' => 'GET'], 'post' => ['method' => 'POST']], []);
47+
$resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
48+
$resourceMetadataFactoryProphecy->create('dummy')->shouldBeCalled()->willReturn($dummyMetadata);
49+
50+
$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
51+
$propertyMetadataFactoryProphecy->create('dummy', 'name')->shouldBeCalled()->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), 'name', true, true, true, true, false, false, null, []));
52+
53+
$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
54+
$resourceClassResolverProphecy->isResourceClass(Argument::type('string'))->willReturn(true);
55+
56+
$operationMethodResolverProphecy = $this->prophesize(OperationMethodResolverInterface::class);
57+
$operationMethodResolverProphecy->getItemOperationMethod('dummy', 'get')->shouldBeCalled()->willReturn('GET');
58+
$operationMethodResolverProphecy->getItemOperationMethod('dummy', 'put')->shouldBeCalled()->willReturn('PUT');
59+
$operationMethodResolverProphecy->getCollectionOperationMethod('dummy', 'get')->shouldBeCalled()->willReturn('GET');
60+
$operationMethodResolverProphecy->getCollectionOperationMethod('dummy', 'post')->shouldBeCalled()->willReturn('POST');
61+
62+
$urlGenerator = $this->prophesize(UrlGeneratorInterface::class);
63+
$urlGenerator->generate('api_hydra_doc')->willReturn('/doc')->shouldBeCalled(1);
64+
$urlGenerator->generate('api_hydra_entrypoint')->willReturn('/')->shouldBeCalled(1);
65+
66+
$urlGenerator->generate('api_hydra_doc', [], UrlGeneratorInterface::ABS_URL)->willReturn('/doc')->shouldBeCalled(1);
67+
68+
$apiDocumentationBuilder = new ApiDocumentationBuilder(
69+
$resourceNameCollectionFactoryProphecy->reveal(),
70+
$resourceMetadataFactoryProphecy->reveal(),
71+
$propertyNameCollectionFactoryProphecy->reveal(),
72+
$propertyMetadataFactoryProphecy->reveal(),
73+
$resourceClassResolverProphecy->reveal(),
74+
$operationMethodResolverProphecy->reveal(),
75+
$urlGenerator->reveal(),
76+
$title,
77+
$desc);
78+
79+
$expected = [
80+
'@context' => [
81+
'@vocab' => '/doc#',
82+
'hydra' => 'http://www.w3.org/ns/hydra/core#',
83+
'rdf' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
84+
'rdfs' => 'http://www.w3.org/2000/01/rdf-schema#',
85+
'xmls' => 'http://www.w3.org/2001/XMLSchema#',
86+
'owl' => 'http://www.w3.org/2002/07/owl#',
87+
'domain' => [
88+
'@id' => 'rdfs:domain',
89+
'@type' => '@id',
90+
],
91+
'range' => [
92+
'@id' => 'rdfs:range',
93+
'@type' => '@id',
94+
],
95+
'subClassOf' => [
96+
'@id' => 'rdfs:subClassOf',
97+
'@type' => '@id',
98+
],
99+
'expects' => [
100+
'@id' => 'hydra:expects',
101+
'@type' => '@id',
102+
],
103+
'returns' => [
104+
'@id' => 'hydra:returns',
105+
'@type' => '@id',
106+
],
107+
],
108+
'@id' => '/doc',
109+
'hydra:title' => 'Test Api',
110+
'hydra:description' => 'test ApiGerard',
111+
'hydra:supportedClass' => [
112+
0 => [
113+
'@id' => '#dummy',
114+
'@type' => 'hydra:Class',
115+
'rdfs:label' => 'dummy',
116+
'hydra:title' => 'dummy',
117+
'hydra:description' => 'dummy',
118+
'hydra:supportedProperty' => [0 => [
119+
'@type' => 'hydra:SupportedProperty',
120+
'hydra:property' => [
121+
'@id' => '#dummy/name',
122+
'@type' => 'rdf:Property',
123+
'rdfs:label' => 'name',
124+
'domain' => '#dummy',
125+
'range' => 'xmls:string',
126+
],
127+
'hydra:title' => 'name',
128+
'hydra:required' => false,
129+
'hydra:readable' => true,
130+
'hydra:writable' => true,
131+
'hydra:description' => 'name',
132+
]],
133+
'hydra:supportedOperation' => [
134+
0 => [
135+
'@type' => 'hydra:Operation',
136+
'hydra:method' => 'GET',
137+
'hydra:title' => 'Retrieves dummy resource.',
138+
'rdfs:label' => 'Retrieves dummy resource.',
139+
'returns' => '#dummy',
140+
],
141+
1 => [
142+
'@type' => 'hydra:ReplaceResourceOperation',
143+
'expects' => '#dummy',
144+
'hydra:method' => 'PUT',
145+
'hydra:title' => 'Replaces the dummy resource.',
146+
'rdfs:label' => 'Replaces the dummy resource.',
147+
'returns' => '#dummy',
148+
],
149+
],
150+
],
151+
1 => [
152+
'@id' => '#Entrypoint',
153+
'@type' => 'hydra:Class',
154+
'hydra:title' => 'The API entrypoint',
155+
'hydra:supportedProperty' => [0 => [
156+
'@type' => 'hydra:SupportedProperty',
157+
'hydra:property' => [
158+
'@id' => '#Entrypoint/dummy',
159+
'@type' => 'hydra:Link',
160+
'rdfs:label' => 'The collection of dummy resources',
161+
'domain' => '#Entrypoint',
162+
'range' => 'hydra:PagedCollection',
163+
'hydra:supportedOperation' => [
164+
0 => [
165+
'@type' => 'hydra:Operation',
166+
'hydra:method' => 'GET',
167+
'hydra:title' => 'Retrieves the collection of dummy resources.',
168+
'rdfs:label' => 'Retrieves the collection of dummy resources.',
169+
'returns' => 'hydra:PagedCollection',
170+
],
171+
1 => [
172+
'@type' => 'hydra:CreateResourceOperation',
173+
'expects' => '#dummy',
174+
'hydra:method' => 'POST',
175+
'hydra:title' => 'Creates a dummy resource.',
176+
'rdfs:label' => 'Creates a dummy resource.',
177+
'returns' => '#dummy',
178+
],
179+
],
180+
],
181+
'hydra:title' => 'The collection of dummy resources',
182+
'hydra:readable' => true,
183+
'hydra:writable' => false,
184+
]],
185+
'hydra:supportedOperation' => [
186+
'@type' => 'hydra:Operation',
187+
'hydra:method' => 'GET',
188+
'rdfs:label' => 'The API entrypoint.',
189+
'returns' => '#EntryPoint',
190+
],
191+
],
192+
2 => [
193+
'@id' => '#ConstraintViolation',
194+
'@type' => 'hydra:Class',
195+
'hydra:title' => 'A constraint violation',
196+
'hydra:supportedProperty' => [
197+
0 => ['@type' => 'hydra:SupportedProperty',
198+
'hydra:property' => [
199+
'@id' => '#ConstraintViolation/propertyPath',
200+
'@type' => 'rdf:Property',
201+
'rdfs:label' => 'propertyPath',
202+
'domain' => '#ConstraintViolation',
203+
'range' => 'xmls:string',
204+
],
205+
'hydra:title' => 'propertyPath',
206+
'hydra:description' => 'The property path of the violation',
207+
'hydra:readable' => true,
208+
'hydra:writable' => false,
209+
],
210+
1 => [
211+
'@type' => 'hydra:SupportedProperty',
212+
'hydra:property' => [
213+
'@id' => '#ConstraintViolation/message',
214+
'@type' => 'rdf:Property',
215+
'rdfs:label' => 'message',
216+
'domain' => '#ConstraintViolation',
217+
'range' => 'xmls:string',
218+
],
219+
'hydra:title' => 'message',
220+
'hydra:description' => 'The message associated with the violation',
221+
'hydra:readable' => true,
222+
'hydra:writable' => false,
223+
],
224+
],
225+
],
226+
3 => [
227+
'@id' => '#ConstraintViolationList',
228+
'@type' => 'hydra:Class',
229+
'subClassOf' => 'hydra:Error',
230+
'hydra:title' => 'A constraint violation list',
231+
'hydra:supportedProperty' => [0 => [
232+
'@type' => 'hydra:SupportedProperty',
233+
'hydra:property' => [
234+
'@id' => '#ConstraintViolationList/violation',
235+
'@type' => 'rdf:Property',
236+
'rdfs:label' => 'violation',
237+
'domain' => '#ConstraintViolationList',
238+
'range' => '#ConstraintViolation',
239+
],
240+
'hydra:title' => 'violation',
241+
'hydra:description' => 'The violations',
242+
'hydra:readable' => true,
243+
'hydra:writable' => false,
244+
]],
245+
],
246+
],
247+
'hydra:entrypoint' => '/',
248+
249+
];
250+
$this->assertEquals($expected, $apiDocumentationBuilder->getApiDocumentation());
251+
}
252+
}

tests/Swagger/ApiDocumentationBuilderTest.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\Swagger;
12+
namespace ApiPlatform\Core\Tests\Swagger;
1313

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

0 commit comments

Comments
 (0)