Browse Source

Use Context to allow altering the normalized JSON-LD (#77)

* Use Context to allow altering the normalized JSON-LD

* Implement jsonld hook and do context work in islandora

* Add functional test

* Namespace ContextReaction ID

* Fix reaction id in test
pull/756/head
Jared Whiklo 7 years ago committed by dannylamb
parent
commit
21124f317d
  1. 10
      islandora.module
  2. 29
      src/ContextReaction/NormalizerAlterReaction.php
  3. 126
      src/Plugin/ContextReaction/MappingUriPredicateReaction.php
  4. 156
      tests/src/Functional/MappingUriPredicateReactionTest.php

10
islandora.module

@ -181,3 +181,13 @@ function islandora_entity_delete(EntityInterface $entity) {
}
}
}
/**
* Implements hook_jsonld_alter_normalized_array().
*/
function islandora_jsonld_alter_normalized_array(EntityInterface $entity, array &$normalized, array $context) {
$context_manager = \Drupal::service('context.manager');
foreach ($context_manager->getActiveReactions('\Drupal\islandora\ContextReaction\NormalizerAlterReaction') as $reaction) {
$reaction->execute($entity, $normalized, $context);
}
}

29
src/ContextReaction/NormalizerAlterReaction.php

@ -0,0 +1,29 @@
<?php
namespace Drupal\islandora\ContextReaction;
use Drupal\context\ContextReactionPluginBase;
use Drupal\Core\Entity\EntityInterface;
/**
* Base class to alter the normalizes Json-ld.
*
* Plugins must extend this class to be considered for execution.
*
* @package Drupal\islandora\ContextReaction
*/
abstract class NormalizerAlterReaction extends ContextReactionPluginBase {
/**
* This reaction takes can alter the array of json-ld built from the entity.
*
* @param \Drupal\Core\Entity\EntityInterface|null $entity
* The entity we are normalizing.
* @param array|null $normalized
* The normalized json-ld before encoding.
* @param array|null $context
* The context used in the normalizer.
*/
abstract public function execute(EntityInterface $entity = NULL, array &$normalized = NULL, array $context = NULL);
}

126
src/Plugin/ContextReaction/MappingUriPredicateReaction.php

@ -0,0 +1,126 @@
<?php
namespace Drupal\islandora\Plugin\ContextReaction;
use Drupal\Core\Entity\EntityInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\islandora\ContextReaction\NormalizerAlterReaction;
use Drupal\jsonld\Normalizer\NormalizerBase;
/**
* Map URI to predicate context reaction.
*
* @ContextReaction(
* id = "islandora_map_uri_predicate",
* label = @Translation("Map URI to predicate")
* )
*/
class MappingUriPredicateReaction extends NormalizerAlterReaction {
const URI_PREDICATE = 'drupal_uri_predicate';
/**
* {@inheritdoc}
*/
public function summary() {
return $this->t('Map Drupal URI to configured predicate.');
}
/**
* {@inheritdoc}
*/
public function execute(EntityInterface $entity = NULL, array &$normalized = NULL, array $context = NULL) {
$config = $this->getConfiguration();
$drupal_predicate = $config[self::URI_PREDICATE];
if (!is_null($drupal_predicate) && !empty($drupal_predicate)) {
$url = $entity
->toUrl('canonical', ['absolute' => TRUE])
->setRouteParameter('_format', 'jsonld')
->toString();
if ($context['needs_jsonldcontext'] === FALSE) {
$drupal_predicate = NormalizerBase::escapePrefix($drupal_predicate, $context['namespaces']);
}
if (isset($normalized['@graph']) && is_array($normalized['@graph'])) {
foreach ($normalized['@graph'] as &$graph) {
if (isset($graph['@id']) && $graph['@id'] == $url) {
if (isset($graph[$drupal_predicate])) {
if (!is_array($graph[$drupal_predicate])) {
if ($graph[$drupal_predicate] == $url) {
// Don't add it if it already exists.
return;
}
$tmp = $graph[$drupal_predicate];
$graph[$drupal_predicate] = [$tmp];
}
elseif (array_search($url, array_column($graph[$drupal_predicate], '@value'))) {
// Don't add it if it already exists.
return;
}
}
else {
$graph[$drupal_predicate] = [];
}
$graph[$drupal_predicate][] = ["@value" => $url];
return;
}
}
}
}
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$config = $this->getConfiguration();
$form[self::URI_PREDICATE] = [
'#type' => 'textfield',
'#title' => $this->t('Drupal URI predicate'),
'#description' => $this->t("The Drupal object's URI will be added to the resource with this predicate. Must use a defined prefix."),
'#default_value' => isset($config[self::URI_PREDICATE]) ? $config[self::URI_PREDICATE] : '',
'#size' => 35,
];
return $form;
}
/**
* {@inheritdoc}
*/
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
$drupal_predicate = $form_state->getValue(self::URI_PREDICATE);
if (!is_null($drupal_predicate) and !empty($drupal_predicate)) {
if (preg_match('/^https?:\/\//', $drupal_predicate)) {
// Can't validate all URIs so we have to trust them.
return;
}
elseif (preg_match('/^([^\s:]+):/', $drupal_predicate, $matches)) {
$predicate_prefix = $matches[1];
$rdf = rdf_get_namespaces();
$rdf_prefixes = array_keys($rdf);
if (!in_array($predicate_prefix, $rdf_prefixes)) {
$form_state->setErrorByName(
self::URI_PREDICATE,
$this->t('Namespace prefix @prefix is not registered.',
['@prefix' => $predicate_prefix]
)
);
}
}
else {
$form_state->setErrorByName(
self::URI_PREDICATE,
$this->t('Predicate must use a defined prefix or be a full URI')
);
}
}
parent::validateConfigurationForm($form, $form_state);
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$this->setConfiguration([self::URI_PREDICATE => $form_state->getValue(self::URI_PREDICATE)]);
}
}

156
tests/src/Functional/MappingUriPredicateReactionTest.php

@ -0,0 +1,156 @@
<?php
namespace Drupal\Tests\islandora\Functional;
/**
* Class MappingUriPredicateReactionTest.
*
* @package Drupal\Tests\islandora\Functional
* @group islandora
*/
class MappingUriPredicateReactionTest extends IslandoraFunctionalTestBase {
/**
* {@inheritdoc}
*/
public function setUp() {
parent::setUp();
$types = ['schema:Thing'];
$created_mapping = [
'properties' => ['schema:dateCreated'],
'datatype' => 'xsd:dateTime',
'datatype_callback' => ['callable' => 'Drupal\rdf\CommonDataConverter::dateIso8601Value'],
];
// Save bundle mapping config.
$this->rdfMapping = rdf_get_mapping('node', 'test_type')
->setBundleMapping(['types' => $types])
->setFieldMapping('created', $created_mapping)
->setFieldMapping('title', [
'properties' => ['dc:title'],
'datatype' => 'xsd:string',
])
->save();
$resourceConfigStorage = $this->container
->get('entity_type.manager')
->getStorage('rest_resource_config');
// There is already a setting for entity.node, so delete it.
$resourceConfigStorage
->delete($resourceConfigStorage
->loadMultiple(['entity.node']));
// Create it new.
$resourceConfigStorage->create([
'id' => 'entity.node',
'granularity' => 'resource',
'configuration' => [
'methods' => ['GET'],
'authentication' => ['basic_auth', 'cookie'],
'formats' => ['jsonld'],
],
'status' => TRUE,
])->save(TRUE);
$this->container->get('router.builder')->rebuildIfNeeded();
}
/**
* @covers \Drupal\islandora\Plugin\ContextReaction\MappingUriPredicateReaction
*/
public function testMappingReaction() {
$account = $this->drupalCreateUser([
'bypass node access',
'administer contexts',
]);
$this->drupalLogin($account);
$context_name = 'test';
$reaction_id = 'islandora_map_uri_predicate';
$this->postNodeAddForm('test_type',
['title[0][value]' => 'Test Node'],
t('Save'));
$this->assertSession()->pageTextContains("Test Node");
$url = $this->getUrl();
// Make sure the node exists.
$this->drupalGet($url);
$this->assertSession()->statusCodeEquals(200);
$contents = $this->drupalGet($url . '?_format=jsonld');
$this->assertSession()->statusCodeEquals(200);
$json = \GuzzleHttp\json_decode($contents, TRUE);
$this->assertArrayHasKey('http://purl.org/dc/terms/title',
$json['@graph'][0], 'Missing dcterms:title key');
$this->assertEquals(
'Test Node',
$json['@graph'][0]['http://purl.org/dc/terms/title'][0]['@value'],
'Missing title value'
);
$this->assertArrayNotHasKey('http://www.w3.org/2002/07/owl#sameAs',
$json['@graph'][0], 'Has predicate when not configured');
$this->createContext('Test', $context_name);
$this->drupalGet("admin/structure/context/$context_name/reaction/add/$reaction_id");
$this->assertSession()->statusCodeEquals(200);
$this->drupalGet("admin/structure/context/$context_name");
// Can't use an undefined prefix.
$this->getSession()->getPage()
->fillField("Drupal URI predicate", "bob:smith");
$this->getSession()->getPage()->pressButton("Save and continue");
$this->assertSession()
->pageTextContains("Namespace prefix bob is not registered");
// Can't use a straight string.
$this->getSession()->getPage()
->fillField("Drupal URI predicate", "woohoo");
$this->getSession()->getPage()->pressButton("Save and continue");
$this->assertSession()
->pageTextContains("Predicate must use a defined prefix or be a full URI");
// Use an existing prefix.
$this->getSession()->getPage()
->fillField("Drupal URI predicate", "owl:sameAs");
$this->getSession()->getPage()->pressButton("Save and continue");
$this->assertSession()
->pageTextContains("The context $context_name has been saved");
$new_contents = $this->drupalGet($url . '?_format=jsonld');
$json = \GuzzleHttp\json_decode($new_contents, TRUE);
$this->assertEquals(
'Test Node',
$json['@graph'][0]['http://purl.org/dc/terms/title'][0]['@value'],
'Missing title value'
);
$this->assertEquals(
"$url?_format=jsonld",
$json['@graph'][0]['http://www.w3.org/2002/07/owl#sameAs'][0]['@value'],
'Missing alter added predicate.'
);
$this->drupalGet("admin/structure/context/$context_name");
// Change to a random URL.
$this->getSession()->getPage()
->fillField("Drupal URI predicate", "http://example.org/first/second");
$this->getSession()->getPage()->pressButton("Save and continue");
$this->assertSession()
->pageTextContains("The context $context_name has been saved");
$new_contents = $this->drupalGet($url . '?_format=jsonld');
$json = \GuzzleHttp\json_decode($new_contents, TRUE);
$this->assertEquals(
'Test Node',
$json['@graph'][0]['http://purl.org/dc/terms/title'][0]['@value'],
'Missing title value'
);
$this->assertArrayNotHasKey('http://www.w3.org/2002/07/owl#sameAs',
$json['@graph'][0], 'Still has old predicate');
$this->assertEquals(
"$url?_format=jsonld",
$json['@graph'][0]['http://example.org/first/second'][0]['@value'],
'Missing alter added predicate.'
);
}
}
Loading…
Cancel
Save