Skip to content

Commit e122925

Browse files
authored
Merge pull request #752 from maechler/feature/typedValues
Adds jsonld context, Adds support for jsonld typed values
2 parents a958d71 + ab6c0d8 commit e122925

File tree

6 files changed

+222
-3
lines changed

6 files changed

+222
-3
lines changed

features/jsonld/context.feature

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,3 +64,23 @@ Feature: JSON-LD contexts generation
6464
}
6565
}
6666
"""
67+
68+
Scenario: Retrieve Dummy with extended jsonld context
69+
When I send a "GET" request to "/contexts/JsonldContextDummy"
70+
Then the response status code should be 200
71+
And the response should be in JSON
72+
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
73+
And the JSON should be equal to:
74+
"""
75+
{
76+
"@context": {
77+
"@vocab": "http:\/\/example.com\/doc.jsonld#",
78+
"hydra": "http:\/\/www.w3.org\/ns\/hydra\/core#",
79+
"person": {
80+
"@id": "http:\/\/example.com\/id",
81+
"@type": "@id",
82+
"foo": "bar"
83+
}
84+
}
85+
}
86+
"""

src/Hydra/Serializer/DocumentationNormalizer.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,12 @@ private function getHydraOperation(string $resourceClass, ResourceMetadata $reso
281281
*/
282282
private function getRange(PropertyMetadata $propertyMetadata)
283283
{
284+
$jsonldContext = $propertyMetadata->getAttributes()['jsonld_context'] ?? [];
285+
286+
if (isset($jsonldContext['@type'])) {
287+
return $jsonldContext['@type'];
288+
}
289+
284290
if (null === $type = $propertyMetadata->getType()) {
285291
return;
286292
}

src/JsonLd/ContextBuilder.php

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,18 +97,25 @@ public function getResourceContext(string $resourceClass, int $referenceType = U
9797
}
9898

9999
$convertedName = $this->nameConverter ? $this->nameConverter->normalize($propertyName) : $propertyName;
100+
$jsonldContext = $propertyMetadata->getAttributes()['jsonld_context'] ?? [];
100101

101102
if (!$id = $propertyMetadata->getIri()) {
102103
$id = sprintf('%s/%s', $prefixedShortName, $convertedName);
103104
}
104105

105106
if (true !== $propertyMetadata->isReadableLink()) {
106-
$context[$convertedName] = [
107+
$jsonldContext = $jsonldContext + [
107108
'@id' => $id,
108109
'@type' => '@id',
109110
];
110-
} else {
111+
}
112+
113+
if (empty($jsonldContext)) {
111114
$context[$convertedName] = $id;
115+
} else {
116+
$context[$convertedName] = $jsonldContext + [
117+
'@id' => $id,
118+
];
112119
}
113120
}
114121

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
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\Fixtures\TestBundle\Entity;
13+
14+
use ApiPlatform\Core\Annotation\ApiProperty;
15+
use ApiPlatform\Core\Annotation\ApiResource;
16+
use Doctrine\ORM\Mapping as ORM;
17+
18+
/**
19+
* Jsonld Context Dummy.
20+
*
21+
*
22+
* @ApiResource
23+
* @ORM\Entity
24+
*/
25+
class JsonldContextDummy
26+
{
27+
/**
28+
* @var int The id.
29+
*
30+
* @ApiProperty(identifier=true)
31+
* @ORM\Column(type="integer")
32+
* @ORM\Id
33+
* @ORM\GeneratedValue(strategy="AUTO")
34+
*/
35+
private $id;
36+
37+
/**
38+
* @var string The dummy person.
39+
*
40+
* @ApiProperty(
41+
* attributes={
42+
* "jsonld_context"= {
43+
* "@id"="http://example.com/id",
44+
* "@type"="@id",
45+
* "foo"="bar"
46+
* }
47+
* },
48+
* )
49+
*/
50+
private $person;
51+
52+
public function getId()
53+
{
54+
return $this->id;
55+
}
56+
57+
public function setPerson($person)
58+
{
59+
$this->person = $person;
60+
}
61+
62+
public function getPerson()
63+
{
64+
return $this->person;
65+
}
66+
}

tests/Hydra/Serializer/DocumentationNormalizerTest.php

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,15 @@ public function testNormalize()
3939
$documentation = new Documentation(new ResourceNameCollection(['dummy' => 'dummy']), $title, $desc, $version, []);
4040

4141
$propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
42-
$propertyNameCollectionFactoryProphecy->create('dummy', [])->shouldBeCalled()->willReturn(new PropertyNameCollection(['name']));
42+
$propertyNameCollectionFactoryProphecy->create('dummy', [])->shouldBeCalled()->willReturn(new PropertyNameCollection(['name', 'description']));
4343

4444
$dummyMetadata = new ResourceMetadata('dummy', 'dummy', '#dummy', ['get' => ['method' => 'GET'], 'put' => ['method' => 'PUT']], ['get' => ['method' => 'GET'], 'post' => ['method' => 'POST']], []);
4545
$resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
4646
$resourceMetadataFactoryProphecy->create('dummy')->shouldBeCalled()->willReturn($dummyMetadata);
4747

4848
$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
4949
$propertyMetadataFactoryProphecy->create('dummy', 'name')->shouldBeCalled()->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), 'name', true, true, true, true, false, false, null, null, []));
50+
$propertyMetadataFactoryProphecy->create('dummy', 'description')->shouldBeCalled()->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), 'description', true, true, true, true, false, false, null, null, ['jsonld_context' => ['@type' => '@id']]));
5051

5152
$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
5253
$resourceClassResolverProphecy->isResourceClass(Argument::type('string'))->willReturn(true);
@@ -126,6 +127,21 @@ public function testNormalize()
126127
'hydra:writable' => true,
127128
'hydra:description' => 'name',
128129
],
130+
1 => [
131+
'@type' => 'hydra:SupportedProperty',
132+
'hydra:property' => [
133+
'@id' => '#dummy/description',
134+
'@type' => 'rdf:Property',
135+
'rdfs:label' => 'description',
136+
'domain' => '#dummy',
137+
'range' => '@id',
138+
],
139+
'hydra:title' => 'description',
140+
'hydra:required' => false,
141+
'hydra:readable' => true,
142+
'hydra:writable' => true,
143+
'hydra:description' => 'description',
144+
],
129145
],
130146
'hydra:supportedOperation' => [
131147
0 => [
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
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\JsonLd;
13+
14+
use ApiPlatform\Core\Api\UrlGeneratorInterface;
15+
use ApiPlatform\Core\JsonLd\ContextBuilder;
16+
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
17+
use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
18+
use ApiPlatform\Core\Metadata\Property\PropertyMetadata;
19+
use ApiPlatform\Core\Metadata\Property\PropertyNameCollection;
20+
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
21+
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceNameCollectionFactoryInterface;
22+
use ApiPlatform\Core\Metadata\Resource\ResourceMetadata;
23+
use Symfony\Component\PropertyInfo\Type;
24+
25+
/**
26+
* @author Markus Mächler <[email protected]>
27+
*/
28+
class ContextBuilderTest extends \PHPUnit_Framework_TestCase
29+
{
30+
private $entityClass;
31+
private $resourceNameCollectionFactoryProphecy;
32+
private $resourceMetadataFactoryProphecy;
33+
private $propertyNameCollectionFactoryProphecy;
34+
private $propertyMetadataFactoryProphecy;
35+
private $urlGeneratorProphecy;
36+
37+
public function setUp()
38+
{
39+
$this->entityClass = '\Dummy\DummyEntity';
40+
$this->resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class);
41+
$this->resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
42+
$this->propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
43+
$this->propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
44+
$this->urlGeneratorProphecy = $this->prophesize(UrlGeneratorInterface::class);
45+
}
46+
47+
public function testResourceContext()
48+
{
49+
$this->resourceMetadataFactoryProphecy->create($this->entityClass)->willReturn(new ResourceMetadata('DummyEntity'));
50+
$this->propertyNameCollectionFactoryProphecy->create($this->entityClass)->willReturn(new PropertyNameCollection(['dummyPropertyA']));
51+
$this->propertyMetadataFactoryProphecy->create($this->entityClass, 'dummyPropertyA')->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), 'Dummy property A', true, true, true, true, false, false, null, null, []));
52+
53+
$contextBuilder = new ContextBuilder($this->resourceNameCollectionFactoryProphecy->reveal(), $this->resourceMetadataFactoryProphecy->reveal(), $this->propertyNameCollectionFactoryProphecy->reveal(), $this->propertyMetadataFactoryProphecy->reveal(), $this->urlGeneratorProphecy->reveal());
54+
55+
$expected = [
56+
'@vocab' => '#',
57+
'hydra' => 'http://www.w3.org/ns/hydra/core#',
58+
'dummyPropertyA' => '#DummyEntity/dummyPropertyA',
59+
];
60+
61+
$this->assertEquals($expected, $contextBuilder->getResourceContext($this->entityClass));
62+
}
63+
64+
public function testResourceContextWithJsonldContext()
65+
{
66+
$this->resourceMetadataFactoryProphecy->create($this->entityClass)->willReturn(new ResourceMetadata('DummyEntity'));
67+
$this->propertyNameCollectionFactoryProphecy->create($this->entityClass)->willReturn(new PropertyNameCollection(['dummyPropertyA']));
68+
$this->propertyMetadataFactoryProphecy->create($this->entityClass, 'dummyPropertyA')->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), 'Dummy property A', true, true, true, true, false, false, null, null, ['jsonld_context' => ['@type' => '@id', '@id' => 'customId', 'foo' => 'bar']]));
69+
70+
$contextBuilder = new ContextBuilder($this->resourceNameCollectionFactoryProphecy->reveal(), $this->resourceMetadataFactoryProphecy->reveal(), $this->propertyNameCollectionFactoryProphecy->reveal(), $this->propertyMetadataFactoryProphecy->reveal(), $this->urlGeneratorProphecy->reveal());
71+
72+
$expected = [
73+
'@vocab' => '#',
74+
'hydra' => 'http://www.w3.org/ns/hydra/core#',
75+
'dummyPropertyA' => [
76+
'@type' => '@id',
77+
'@id' => 'customId',
78+
'foo' => 'bar',
79+
],
80+
];
81+
82+
$this->assertEquals($expected, $contextBuilder->getResourceContext($this->entityClass));
83+
}
84+
85+
public function testResourceContextWithReverse()
86+
{
87+
$this->resourceMetadataFactoryProphecy->create($this->entityClass)->willReturn(new ResourceMetadata('DummyEntity'));
88+
$this->propertyNameCollectionFactoryProphecy->create($this->entityClass)->willReturn(new PropertyNameCollection(['dummyPropertyA']));
89+
$this->propertyMetadataFactoryProphecy->create($this->entityClass, 'dummyPropertyA')->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), 'Dummy property A', true, true, true, true, false, false, null, null, ['jsonld_context' => ['@reverse' => 'parent']]));
90+
91+
$contextBuilder = new ContextBuilder($this->resourceNameCollectionFactoryProphecy->reveal(), $this->resourceMetadataFactoryProphecy->reveal(), $this->propertyNameCollectionFactoryProphecy->reveal(), $this->propertyMetadataFactoryProphecy->reveal(), $this->urlGeneratorProphecy->reveal());
92+
93+
$expected = [
94+
'@vocab' => '#',
95+
'hydra' => 'http://www.w3.org/ns/hydra/core#',
96+
'dummyPropertyA' => [
97+
'@id' => '#DummyEntity/dummyPropertyA',
98+
'@reverse' => 'parent'
99+
],
100+
];
101+
102+
$this->assertEquals($expected, $contextBuilder->getResourceContext($this->entityClass));
103+
}
104+
}

0 commit comments

Comments
 (0)