Skip to content

Commit

Permalink
Use ContextGenerator for JSON serializer (#23)
Browse files Browse the repository at this point in the history
* Use ContextGenerator for JSON serializer

* EntityReference needs context too.

Also update tests

* Check the field_context exists before using it.

* Initialize values_clean as array.

* Oops reset an array.

* Remove @type for entity references
  • Loading branch information
whikloj authored and DiegoPino committed Sep 19, 2017
1 parent 9ae1d2e commit 36f37cb
Show file tree
Hide file tree
Showing 7 changed files with 131 additions and 42 deletions.
3 changes: 2 additions & 1 deletion jsonld.services.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
services:
serializer.normalizer.entity_reference_item.jsonld:
class: Drupal\jsonld\Normalizer\EntityReferenceItemNormalizer
arguments: ['@hal.link_manager', '@serializer.entity_resolver']
arguments: ['@hal.link_manager', '@serializer.entity_resolver', '@jsonld.contextgenerator']
tags:
- { name: normalizer, priority: 10 }
serializer.normalizer.field_item.jsonld:
class: Drupal\jsonld\Normalizer\FieldItemNormalizer
arguments: ['@jsonld.contextgenerator']
tags:
- { name: normalizer, priority: 10 }
serializer.normalizer.field.jsonld:
Expand Down
16 changes: 2 additions & 14 deletions src/ContextGenerator/JsonldContextGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -180,21 +180,9 @@ public function generateContext(RdfMappingInterface $rdfMapping) {
}

/**
* Gets the correct piece of @context for a given entity field.
*
* @param \Drupal\rdf\RdfMappingInterface $rdfMapping
* Rdf mapping object.
* @param string $field_name
* The name of the field.
* @param \Drupal\Core\Field\FieldDefinitionInterface $fieldDefinition
* The definition of the field.
* @param array $allRdfNameSpaces
* Every RDF prefixed namespace in this Drupal.
*
* @return array
* Piece of JSON-LD context that supports this field
* {@inheritdoc}
*/
private function getFieldsRdf(RdfMappingInterface $rdfMapping, $field_name, FieldDefinitionInterface $fieldDefinition, array $allRdfNameSpaces) {
public function getFieldsRdf(RdfMappingInterface $rdfMapping, $field_name, FieldDefinitionInterface $fieldDefinition, array $allRdfNameSpaces) {
$termDefinition = [];
$fieldContextFragment = [];
$fieldRDFMapping = $rdfMapping->getPreparedFieldMapping($field_name);
Expand Down
18 changes: 18 additions & 0 deletions src/ContextGenerator/JsonldContextGeneratorInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace Drupal\jsonld\ContextGenerator;

use Drupal\Core\Field\FieldDefinitionInterface;
use Drupal\rdf\RdfMappingInterface;

/**
Expand Down Expand Up @@ -41,4 +42,21 @@ public function generateContext(RdfMappingInterface $mapping);
*/
public function getContext($ids);

/**
* Gets the correct piece of @context for a given entity field.
*
* @param \Drupal\rdf\RdfMappingInterface $rdfMapping
* Rdf mapping object.
* @param string $field_name
* The name of the field.
* @param \Drupal\Core\Field\FieldDefinitionInterface $fieldDefinition
* The definition of the field.
* @param array $allRdfNameSpaces
* Every RDF prefixed namespace in this Drupal.
*
* @return array
* Piece of JSON-LD context that supports this field
*/
public function getFieldsRdf(RdfMappingInterface $rdfMapping, $field_name, FieldDefinitionInterface $fieldDefinition, array $allRdfNameSpaces);

}
21 changes: 18 additions & 3 deletions src/Normalizer/EntityReferenceItemNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Drupal\Core\Entity\FieldableEntityInterface;
use Drupal\hal\LinkManager\LinkManagerInterface;
use Drupal\jsonld\ContextGenerator\JsonldContextGeneratorInterface;
use Drupal\serialization\EntityResolver\EntityResolverInterface;
use Drupal\serialization\EntityResolver\UuidReferenceInterface;

Expand Down Expand Up @@ -38,11 +39,15 @@ class EntityReferenceItemNormalizer extends FieldItemNormalizer implements UuidR
*
* @param \Drupal\hal\LinkManager\LinkManagerInterface $link_manager
* The hypermedia link manager.
* @param \Drupal\hal\EntityResolver\EntityResolverInterface $entity_Resolver
* @param \Drupal\serialization\EntityResolver\EntityResolverInterface $entity_Resolver
* The entity resolver.
* @param \Drupal\jsonld\ContextGenerator\JsonldContextGeneratorInterface $jsonld_context
* The Json-Ld context service.
*/
public function __construct(LinkManagerInterface $link_manager, EntityResolverInterface $entity_Resolver) {

public function __construct(LinkManagerInterface $link_manager,
EntityResolverInterface $entity_Resolver,
JsonldContextGeneratorInterface $jsonld_context) {
parent::__construct($jsonld_context);
$this->linkManager = $link_manager;
$this->entityResolver = $entity_Resolver;
}
Expand Down Expand Up @@ -76,6 +81,7 @@ public function normalize($field_item, $format = NULL, array $context = []) {
$embedded = $this->serializer->normalize($target_entity, $format, $context);

if (isset($context['current_entity_rdf_mapping'])) {
$values_clean = [];
// So why i am passing the whole rdf mapping object and not
// only the predicate? Well because i hope i will be able
// to MAP to RDF also sub fields of a complex field someday
Expand All @@ -102,13 +108,22 @@ public function normalize($field_item, $format = NULL, array $context = []) {
// expensive and would require an helper method
// i could just borrow it from the $embed result.
$values_clean['@id'] = key($embedded['@graph']);
// Because having a @type for a reference causes problems, we strip that.
// This could be removed using headers in future.
if (isset($values_clean['@type'])) {
unset($values_clean['@type']);
}

// The returned structure will be recursively merged into the normalized
// JSON-LD @Graph.
foreach ($field_keys as $field_name) {
// If there's no context, we need full predicates, not shortened ones.
if (!$context['needs_jsonldcontext']) {
$field_name = $this->escapePrefix($field_name, $context['namespaces']);
foreach ($values_clean as $key => $val) {
// Expand values in the array, ie. @type values xsd:string.
$values_clean[$key] = $this->escapePrefix($val, $context['namespaces']);
}
}
$normalized_prop[$field_name] = [$values_clean];
}
Expand Down
36 changes: 34 additions & 2 deletions src/Normalizer/FieldItemNormalizer.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace Drupal\jsonld\Normalizer;

use Drupal\Core\Field\FieldItemInterface;
use Drupal\jsonld\ContextGenerator\JsonldContextGeneratorInterface;
use Symfony\Component\Serializer\Exception\InvalidArgumentException;

/**
Expand All @@ -17,6 +18,23 @@ class FieldItemNormalizer extends NormalizerBase {
*/
protected $supportedInterfaceOrClass = 'Drupal\Core\Field\FieldItemInterface';

/**
* Json-Ld context generator service.
*
* @var \Drupal\jsonld\ContextGenerator\JsonldContextGeneratorInterface
*/
protected $jsonldContextgenerator;

/**
* FieldItemNormalizer constructor.
*
* @param \Drupal\jsonld\ContextGenerator\JsonldContextGeneratorInterface $jsonld_context
* Json-Ld context generator service.
*/
public function __construct(JsonldContextGeneratorInterface $jsonld_context) {
$this->jsonldContextgenerator = $jsonld_context;
}

/**
* {@inheritdoc}
*/
Expand Down Expand Up @@ -58,12 +76,22 @@ public function normalize($field_item, $format = NULL, array $context = []) {
$arguments = isset($field_mappings['datatype_callback']['arguments']) ? $field_mappings['datatype_callback']['arguments'] : NULL;
$values_clean['@value'] = call_user_func($callback, $values, $arguments);
}
$field_context = $this->jsonldContextgenerator->getFieldsRdf(
$context['current_entity_rdf_mapping'],
$field->getName(),
$field->getFieldDefinition(),
$context['namespaces']
);
if (isset($field_context[$field_keys[0]])) {
$values_clean = $values_clean + $field_context[$field_keys[0]];
}

}
else {
$field_keys = [$field->getName()];
}

if (isset($context['langcode'])) {
// JSON-LD Spec says you can't have an @language for a typed values.
if (isset($context['langcode']) && !isset($values_clean['@type'])) {
$values_clean['@language'] = $context['langcode'];
}
array_filter($values_clean);
Expand All @@ -74,6 +102,10 @@ public function normalize($field_item, $format = NULL, array $context = []) {
// If there's no context, we need full predicates, not shortened ones.
if (!$context['needs_jsonldcontext']) {
$field_name = $this->escapePrefix($field_name, $context['namespaces']);
foreach ($values_clean as $key => $val) {
// Expand values in the array, ie. @type values xsd:string.
$values_clean[$key] = $this->escapePrefix($val, $context['namespaces']);
}
}
$normalized[$field_name] = [$values_clean];
}
Expand Down
6 changes: 4 additions & 2 deletions tests/src/Kernel/JsonldKernelTestBase.php
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,13 @@ protected function setUp() {

$chain_resolver = new ChainEntityResolver([new UuidResolver($entity_manager), new TargetIdResolver()]);

$jsonld_context_generator = $this->container->get('jsonld.contextgenerator');

// Set up the mock serializer.
$normalizers = [
new ContentEntityNormalizer($link_manager, $entity_manager, \Drupal::moduleHandler()),
new EntityReferenceItemNormalizer($link_manager, $chain_resolver),
new FieldItemNormalizer(),
new EntityReferenceItemNormalizer($link_manager, $chain_resolver, $jsonld_context_generator),
new FieldItemNormalizer($jsonld_context_generator),
new FieldNormalizer(),
];

Expand Down
73 changes: 53 additions & 20 deletions tests/src/Kernel/Normalizer/ContentEntityNormalizerTests.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

use Drupal\entity_test\Entity\EntityTest;
use Drupal\Tests\jsonld\Kernel\JsonldKernelTestBase;
use Drupal\user\Entity\User;

/**
* Class ContentEntityTests.
Expand Down Expand Up @@ -32,23 +33,45 @@ protected function setUp() {
* @covers \Drupal\jsonld\Normalizer\EntityReferenceItemNormalizer::normalize
*/
public function testSimpleNormalizeJsonld() {

$target_entity = EntityTest::create([
'name' => $this->randomMachineName(),
'langcode' => 'en',
'field_test_entity_reference' => NULL,
]);
$target_entity->save();

$target_user = User::create([
'name' => $this->randomMachineName(),
'langcode' => 'en',
]);
$target_user->save();

rdf_get_mapping('entity_test', 'entity_test')->setBundleMapping(
[
'types' => [
"schema:ImageObject",
],
])->setFieldMapping('field_test_text', [
'properties' => ['dc:description'],
])->setFieldMapping('user_id', [
'properties' => ['schema:author'],
])->setFieldMapping('modified', [
'properties' => ['schema:dateModified'],
'datatype' => 'xsd:dateTime',
])->save();

$tz = new \DateTimeZone('UTC');
$dt = new \DateTime(NULL, $tz);
$created = $dt->format("U");
$iso = $dt->format(\DateTime::W3C);
$created_iso = $dt->format(\DateTime::W3C);
// Create an entity.
$values = [
'langcode' => 'en',
'name' => $this->randomMachineName(),
'type' => 'entity_test',
'bundle' => 'entity_test',
'user_id' => $target_user->id(),
'created' => [
'value' => $created,
],
Expand All @@ -65,40 +88,50 @@ public function testSimpleNormalizeJsonld() {
$entity->save();

$expected = [
'@graph' => [
"@graph" => [
[
'@id' => $this->getEntityUri($entity),
'@type' => ['http://schema.org/Thing'],
'http://purl.org/dc/terms/title' => [
"@id" => $this->getEntityUri($entity),
"@type" => [
'http://schema.org/ImageObject',
],
"http://purl.org/dc/terms/references" => [
[
"@id" => $this->getEntityUri($target_entity),
],
],
"http://purl.org/dc/terms/description" => [
[
'@value' => $values['name'],
'@type' => 'xsd:string',
'@language' => 'en',
"@type" => "http://www.w3.org/2001/XMLSchema#string",
"@value" => $values['field_test_text']['value'],
],
],
'http://schema.org/dateCreated' => [
"http://purl.org/dc/terms/title" => [
[
'@value' => $iso,
'@type' => 'xsd:dateTime',
'@language' => 'en',
"@type" => "http://www.w3.org/2001/XMLSchema#string",
"@value" => $values['name'],
],
],
'http://purl.org/dc/terms/abstract' => [
"http://schema.org/author" => [
[
'@value' => $values['field_test_text']['value'],
'@type' => 'xsd:string',
"@id" => $this->getEntityUri($target_user),
],
],
'http://purl.org/dc/terms/references' => [
"http://schema.org/dateCreated" => [
[
'@id' => $this->getEntityUri($target_entity),
'@type' => 'xsd:nonNegativeInteger',
"@type" => "http://www.w3.org/2001/XMLSchema#dateTime",
"@value" => $created_iso,
],
],
],
[
'@id' => $this->getEntityUri($target_entity),
'@type' => ['http://schema.org/Thing'],
"@id" => $this->getEntityUri($target_user),
"@type" => "http://localhost/rest/type/user/user",
],
[
"@id" => $this->getEntityUri($target_entity),
"@type" => [
"http://schema.org/ImageObject",
],
],
],
];
Expand Down

0 comments on commit 36f37cb

Please sign in to comment.