Skip to content

Commit

Permalink
Merge pull request api-platform#752 from maechler/feature/typedValues
Browse files Browse the repository at this point in the history
Adds jsonld context, Adds support for jsonld typed values
  • Loading branch information
dunglas committed Sep 30, 2016
2 parents 8963083 + dc07624 commit b555afb
Show file tree
Hide file tree
Showing 6 changed files with 222 additions and 3 deletions.
20 changes: 20 additions & 0 deletions features/jsonld/context.feature
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,23 @@ Feature: JSON-LD contexts generation
}
}
"""

Scenario: Retrieve Dummy with extended jsonld context
When I send a "GET" request to "/contexts/JsonldContextDummy"
Then the response status code should be 200
And the response should be in JSON
And the header "Content-Type" should be equal to "application/ld+json; charset=utf-8"
And the JSON should be equal to:
"""
{
"@context": {
"@vocab": "http:\/\/example.com\/doc.jsonld#",
"hydra": "http:\/\/www.w3.org\/ns\/hydra\/core#",
"person": {
"@id": "http:\/\/example.com\/id",
"@type": "@id",
"foo": "bar"
}
}
}
"""
6 changes: 6 additions & 0 deletions src/Hydra/Serializer/DocumentationNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,12 @@ private function getHydraOperation(string $resourceClass, ResourceMetadata $reso
*/
private function getRange(PropertyMetadata $propertyMetadata)
{
$jsonldContext = $propertyMetadata->getAttributes()['jsonld_context'] ?? [];

if (isset($jsonldContext['@type'])) {
return $jsonldContext['@type'];
}

if (null === $type = $propertyMetadata->getType()) {
return;
}
Expand Down
11 changes: 9 additions & 2 deletions src/JsonLd/ContextBuilder.php
Original file line number Diff line number Diff line change
Expand Up @@ -97,18 +97,25 @@ public function getResourceContext(string $resourceClass, int $referenceType = U
}

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

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

if (true !== $propertyMetadata->isReadableLink()) {
$context[$convertedName] = [
$jsonldContext = $jsonldContext + [
'@id' => $id,
'@type' => '@id',
];
} else {
}

if (empty($jsonldContext)) {
$context[$convertedName] = $id;
} else {
$context[$convertedName] = $jsonldContext + [
'@id' => $id,
];
}
}

Expand Down
66 changes: 66 additions & 0 deletions tests/Fixtures/TestBundle/Entity/JsonldContextDummy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace ApiPlatform\Core\Tests\Fixtures\TestBundle\Entity;

use ApiPlatform\Core\Annotation\ApiProperty;
use ApiPlatform\Core\Annotation\ApiResource;
use Doctrine\ORM\Mapping as ORM;

/**
* Jsonld Context Dummy.
*
*
* @ApiResource
* @ORM\Entity
*/
class JsonldContextDummy
{
/**
* @var int The id.
*
* @ApiProperty(identifier=true)
* @ORM\Column(type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
private $id;

/**
* @var string The dummy person.
*
* @ApiProperty(
* attributes={
* "jsonld_context"= {
* "@id"="http://example.com/id",
* "@type"="@id",
* "foo"="bar"
* }
* },
* )
*/
private $person;

public function getId()
{
return $this->id;
}

public function setPerson($person)
{
$this->person = $person;
}

public function getPerson()
{
return $this->person;
}
}
18 changes: 17 additions & 1 deletion tests/Hydra/Serializer/DocumentationNormalizerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,15 @@ public function testNormalize()
$documentation = new Documentation(new ResourceNameCollection(['dummy' => 'dummy']), $title, $desc, $version, []);

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

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

$propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
$propertyMetadataFactoryProphecy->create('dummy', 'name')->shouldBeCalled()->willReturn(new PropertyMetadata(new Type(Type::BUILTIN_TYPE_STRING), 'name', true, true, true, true, false, false, null, null, []));
$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']]));

$resourceClassResolverProphecy = $this->prophesize(ResourceClassResolverInterface::class);
$resourceClassResolverProphecy->isResourceClass(Argument::type('string'))->willReturn(true);
Expand Down Expand Up @@ -126,6 +127,21 @@ public function testNormalize()
'hydra:writable' => true,
'hydra:description' => 'name',
],
1 => [
'@type' => 'hydra:SupportedProperty',
'hydra:property' => [
'@id' => '#dummy/description',
'@type' => 'rdf:Property',
'rdfs:label' => 'description',
'domain' => '#dummy',
'range' => '@id',
],
'hydra:title' => 'description',
'hydra:required' => false,
'hydra:readable' => true,
'hydra:writable' => true,
'hydra:description' => 'description',
],
],
'hydra:supportedOperation' => [
0 => [
Expand Down
104 changes: 104 additions & 0 deletions tests/JsonLd/ContextBuilderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
<?php

/*
* This file is part of the API Platform project.
*
* (c) Kévin Dunglas <dunglas@gmail.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace ApiPlatform\Core\Tests\JsonLd;

use ApiPlatform\Core\Api\UrlGeneratorInterface;
use ApiPlatform\Core\JsonLd\ContextBuilder;
use ApiPlatform\Core\Metadata\Property\Factory\PropertyMetadataFactoryInterface;
use ApiPlatform\Core\Metadata\Property\Factory\PropertyNameCollectionFactoryInterface;
use ApiPlatform\Core\Metadata\Property\PropertyMetadata;
use ApiPlatform\Core\Metadata\Property\PropertyNameCollection;
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceMetadataFactoryInterface;
use ApiPlatform\Core\Metadata\Resource\Factory\ResourceNameCollectionFactoryInterface;
use ApiPlatform\Core\Metadata\Resource\ResourceMetadata;
use Symfony\Component\PropertyInfo\Type;

/**
* @author Markus Mächler <markus.maechler@bithost.ch>
*/
class ContextBuilderTest extends \PHPUnit_Framework_TestCase
{
private $entityClass;
private $resourceNameCollectionFactoryProphecy;
private $resourceMetadataFactoryProphecy;
private $propertyNameCollectionFactoryProphecy;
private $propertyMetadataFactoryProphecy;
private $urlGeneratorProphecy;

public function setUp()
{
$this->entityClass = '\Dummy\DummyEntity';
$this->resourceNameCollectionFactoryProphecy = $this->prophesize(ResourceNameCollectionFactoryInterface::class);
$this->resourceMetadataFactoryProphecy = $this->prophesize(ResourceMetadataFactoryInterface::class);
$this->propertyNameCollectionFactoryProphecy = $this->prophesize(PropertyNameCollectionFactoryInterface::class);
$this->propertyMetadataFactoryProphecy = $this->prophesize(PropertyMetadataFactoryInterface::class);
$this->urlGeneratorProphecy = $this->prophesize(UrlGeneratorInterface::class);
}

public function testResourceContext()
{
$this->resourceMetadataFactoryProphecy->create($this->entityClass)->willReturn(new ResourceMetadata('DummyEntity'));
$this->propertyNameCollectionFactoryProphecy->create($this->entityClass)->willReturn(new PropertyNameCollection(['dummyPropertyA']));
$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, []));

$contextBuilder = new ContextBuilder($this->resourceNameCollectionFactoryProphecy->reveal(), $this->resourceMetadataFactoryProphecy->reveal(), $this->propertyNameCollectionFactoryProphecy->reveal(), $this->propertyMetadataFactoryProphecy->reveal(), $this->urlGeneratorProphecy->reveal());

$expected = [
'@vocab' => '#',
'hydra' => 'http://www.w3.org/ns/hydra/core#',
'dummyPropertyA' => '#DummyEntity/dummyPropertyA',
];

$this->assertEquals($expected, $contextBuilder->getResourceContext($this->entityClass));
}

public function testResourceContextWithJsonldContext()
{
$this->resourceMetadataFactoryProphecy->create($this->entityClass)->willReturn(new ResourceMetadata('DummyEntity'));
$this->propertyNameCollectionFactoryProphecy->create($this->entityClass)->willReturn(new PropertyNameCollection(['dummyPropertyA']));
$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']]));

$contextBuilder = new ContextBuilder($this->resourceNameCollectionFactoryProphecy->reveal(), $this->resourceMetadataFactoryProphecy->reveal(), $this->propertyNameCollectionFactoryProphecy->reveal(), $this->propertyMetadataFactoryProphecy->reveal(), $this->urlGeneratorProphecy->reveal());

$expected = [
'@vocab' => '#',
'hydra' => 'http://www.w3.org/ns/hydra/core#',
'dummyPropertyA' => [
'@type' => '@id',
'@id' => 'customId',
'foo' => 'bar',
],
];

$this->assertEquals($expected, $contextBuilder->getResourceContext($this->entityClass));
}

public function testResourceContextWithReverse()
{
$this->resourceMetadataFactoryProphecy->create($this->entityClass)->willReturn(new ResourceMetadata('DummyEntity'));
$this->propertyNameCollectionFactoryProphecy->create($this->entityClass)->willReturn(new PropertyNameCollection(['dummyPropertyA']));
$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']]));

$contextBuilder = new ContextBuilder($this->resourceNameCollectionFactoryProphecy->reveal(), $this->resourceMetadataFactoryProphecy->reveal(), $this->propertyNameCollectionFactoryProphecy->reveal(), $this->propertyMetadataFactoryProphecy->reveal(), $this->urlGeneratorProphecy->reveal());

$expected = [
'@vocab' => '#',
'hydra' => 'http://www.w3.org/ns/hydra/core#',
'dummyPropertyA' => [
'@id' => '#DummyEntity/dummyPropertyA',
'@reverse' => 'parent'
],
];

$this->assertEquals($expected, $contextBuilder->getResourceContext($this->entityClass));
}
}

0 comments on commit b555afb

Please sign in to comment.