diff --git a/core/modules/jsonld/jsonld.info b/core/modules/jsonld/jsonld.info index 70d5d40..110b881 100644 --- a/core/modules/jsonld/jsonld.info +++ b/core/modules/jsonld/jsonld.info @@ -2,3 +2,4 @@ name = JSON-LD description = Serializes entities using JSON-LD format. package = Core core = 8.x +dependencies[] = rdf diff --git a/core/modules/jsonld/lib/Drupal/jsonld/JsonldBundle.php b/core/modules/jsonld/lib/Drupal/jsonld/JsonldBundle.php index 4d086d1..5b8c28e 100644 --- a/core/modules/jsonld/lib/Drupal/jsonld/JsonldBundle.php +++ b/core/modules/jsonld/lib/Drupal/jsonld/JsonldBundle.php @@ -38,6 +38,10 @@ public function build(ContainerBuilder $container) { 'entity' => array( 'jsonld' => 'Drupal\jsonld\JsonldEntityNormalizer', ), + // RDF Schema. + 'bundle_rdf_schema' => array( + 'jsonld' => 'Drupal\jsonld\RdfBundleSchemaNormalizer', + ), ); // Encoders can only specify which format they support in // Encoder::supportsEncoding(). diff --git a/core/modules/jsonld/lib/Drupal/jsonld/JsonldEncoder.php b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEncoder.php index 2b9ed2a..8aa289e 100644 --- a/core/modules/jsonld/lib/Drupal/jsonld/JsonldEncoder.php +++ b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEncoder.php @@ -7,7 +7,6 @@ namespace Drupal\jsonld; -use Symfony\Component\Serializer\Encoder\EncoderInterface; use Symfony\Component\Serializer\Encoder\JsonEncoder; /** @@ -15,7 +14,7 @@ * * Simply respond to JSON-LD requests using the JSON encoder. */ -class JsonldEncoder extends JsonEncoder implements EncoderInterface { +class JsonldEncoder extends JsonEncoder { /** * The formats that this Encoder supports. @@ -25,15 +24,17 @@ class JsonldEncoder extends JsonEncoder implements EncoderInterface { static protected $format = array('jsonld', 'drupal_jsonld'); /** - * Check whether the request is for JSON-LD. - * - * @param string $format - * The short name of the format returned by ContentNegotiation. - * - * @return bool - * Returns TRUE if the encoder can handle the request. + * Overrides \Symfony\Component\Serializer\Encoder\JsonEncoder::supportsEncoding() */ public function supportsEncoding($format) { return in_array($format, static::$format); } + + /** + * Overrides \Symfony\Component\Serializer\Encoder\JsonEncoder::supportsDecoding() + */ + public function supportsDecoding($format) { + return in_array($format, static::$format); + } + } diff --git a/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityNormalizer.php b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityNormalizer.php index b85941b..71e0dad 100644 --- a/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityNormalizer.php +++ b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityNormalizer.php @@ -7,14 +7,22 @@ namespace Drupal\jsonld; -use Drupal\Core\Entity\EntityNG; use Drupal\jsonld\JsonldNormalizerBase; +use Drupal\rdf\RdfConstants; use Symfony\Component\Serializer\Exception\RuntimeException; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; /** * Converts the Drupal entity object structure to JSON-LD array structure. */ -class JsonldEntityNormalizer extends JsonldNormalizerBase { +class JsonldEntityNormalizer extends JsonldNormalizerBase implements DenormalizerInterface { + + /** + * The interface or class that this Normalizer supports. + * + * @var string + */ + protected static $supportedInterfaceOrClass = 'Drupal\Core\Entity\EntityInterface'; /** * Implements \Symfony\Component\Serializer\Normalizer\NormalizerInterface::normalize() @@ -23,17 +31,57 @@ public function normalize($entity, $format = NULL) { $entityWrapper = new JsonldEntityWrapper($entity, $format, $this->serializer); $attributes = $entityWrapper->getProperties(); - $attributes = array('@id' => $entityWrapper->getId()) + $attributes; + $attributes = array( + '@id' => $entityWrapper->getId(), + '@type' => $entityWrapper->getTypes(), + ) + $attributes; return $attributes; } /** - * Implements \Symfony\Component\Serializer\Normalizer\NormalizerInterface::supportsNormalization() + * Implements \Symfony\Component\Serializer\Normalizer\DenormalizerInterface::denormalize() */ - public function supportsNormalization($data, $format = NULL) { - // @todo Switch to EntityInterface once all entity types are converted to - // EntityNG. - return parent::supportsNormalization($data, $format) && ($data instanceof EntityNG); + public function denormalize($data, $class, $format = null) { + if (!isset($data['@type'])) { + // @todo Throw an exception? + } + + // Every bundle has a type, identified by URI. A schema which provides more + // information about the type can be requested from that URI. From that + // schema, the entity type and bundle name are extracted. + $typeUri = is_array($data['@type']) ? $data['@type'][0] : $data['@type']; + $schema = $this->request($typeUri); + $bundle = $schema->{RdfConstants::DRUPAL_BUNDLE_NAME}; + $entity_type = $schema->{RdfConstants::DRUPAL_ENTITY_TYPE}; + $entity = entity_create($entity_type, array('type' => $bundle)); + + // For each attribute in the JSON-LD, add the values as fields to the newly + // created entity. It is assumed that the JSON attribute names are the same + // as the site's field names. + // @todo Possibly switch to URI expansion of attribute names. + foreach ($data as $field_name => $field_data) { + // Skip the JSON-LD specific terms, which start with '@'. + if ($field_name[0] === '@') { + continue; + } + + // Figure out the designated class for this field type, which is used by + // the Serializer to determine which Denormalizer to use. + // @todo Is there a better way to get the field type's associated class? + $fieldValue = $entity->get($field_name); + $fieldItem = $fieldValue->offsetGet(0); + $fieldItemClass = get_class($fieldItem); + // Iterate through the language keyed values and add them to the entity. + // The vnd.drupal.ld+json mime type will always use language keys, per + // http://drupal.org/node/1838700. + foreach ($field_data as $langcode => $field_item_data) { + $values = $this->serializer->denormalize($field_item_data, $fieldItemClass, $format); + $translation = $entity->getTranslation($langcode); + $translation->set($field_name, $values); + } + } + + return $entity; } } diff --git a/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityReferenceNormalizer.php b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityReferenceNormalizer.php index 1e6d27c..e28ce95 100644 --- a/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityReferenceNormalizer.php +++ b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityReferenceNormalizer.php @@ -7,14 +7,23 @@ namespace Drupal\jsonld; -use Drupal\Core\Entity\Field\Type\EntityReferenceItem; +use Drupal\Core\Entity\EntityNG; use Drupal\jsonld\JsonldNormalizerBase; +use ReflectionClass; use Symfony\Component\Serializer\Exception\RuntimeException; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; /** * Converts an EntityReferenceItem to a JSON-LD array structure. */ -class JsonldEntityReferenceNormalizer extends JsonldNormalizerBase { +class JsonldEntityReferenceNormalizer extends JsonldNormalizerBase implements DenormalizerInterface { + + /** + * The interface or class that this Normalizer supports. + * + * @var string + */ + protected static $supportedInterfaceOrClass = 'Drupal\Core\Entity\Field\Type\EntityReferenceItem'; /** * Implements \Symfony\Component\Serializer\Normalizer\NormalizerInterface::normalize() @@ -32,10 +41,19 @@ public function normalize($object, $format = NULL) { } /** - * Implements \Symfony\Component\Serializer\Normalizer\NormalizerInterface::supportsNormalization() + * Implements \Symfony\Component\Serializer\Normalizer\DenormalizerInterface::denormalize() + */ + public function denormalize($data, $class, $format = null) { + // @todo Support denormalization for Entity Reference. + return array(); + } + + /** + * Overrides \Drupal\jsonld\JsonldNormalizerBase::supportsDenormalization() */ - public function supportsNormalization($data, $format = NULL) { - return parent::supportsNormalization($data, $format) && ($data instanceof EntityReferenceItem); + public function supportsDenormalization($data, $type, $format = NULL) { + $reflection = new ReflectionClass($type); + return in_array($format, static::$format) && ($reflection->getName() == static::$supportedInterfaceOrClass || $reflection->isSubclassOf(static::$supportedInterfaceOrClass)); } } diff --git a/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityWrapper.php b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityWrapper.php index 65bf6e0..18ceba6 100644 --- a/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityWrapper.php +++ b/core/modules/jsonld/lib/Drupal/jsonld/JsonldEntityWrapper.php @@ -8,9 +8,18 @@ namespace Drupal\jsonld; use Drupal\Core\Entity\Entity; +use Drupal\rdf\SiteSchema\SchemaConstants; +use Drupal\rdf\SiteSchema\SiteSchema; /** * Provide an interface for JsonldNormalizer to get required properties. + * + * @todo Eventually, this class should be removed. It allows both the + * EntityNormalizer and the EntityReferenceNormalizer to have access to the + * same functions. If an $options parameter is added to the serialize + * signature, as requested in https://github.com/symfony/symfony/pull/4938, + * then the EntityReferenceNormalizer could simply call + * EntityNormalizer::normalize(), passing in the referenced entity. */ class JsonldEntityWrapper { @@ -49,6 +58,8 @@ public function __construct(Entity $entity, $format, $serializer) { $this->entity = $entity; $this->format = $format; $this->serializer = $serializer; + // @todo Remove hardcoded schema parameter. + $this->siteSchema = new SiteSchema(SchemaConstants::CONTENT_STAGING); } /** @@ -63,6 +74,16 @@ public function getId() { } /** + * Get the type array. + */ + public function getTypes() { + $entityType = $this->entity->entityType(); + $bundle = $this->entity->bundle(); + $bundleSchema = $this->siteSchema->bundle($entityType, $bundle); + return $bundleSchema->getUri(); + } + + /** * Get properties, excluding JSON-LD specific properties. * * @return array diff --git a/core/modules/jsonld/lib/Drupal/jsonld/JsonldFieldItemNormalizer.php b/core/modules/jsonld/lib/Drupal/jsonld/JsonldFieldItemNormalizer.php index 3fac801..bf421a1 100644 --- a/core/modules/jsonld/lib/Drupal/jsonld/JsonldFieldItemNormalizer.php +++ b/core/modules/jsonld/lib/Drupal/jsonld/JsonldFieldItemNormalizer.php @@ -10,11 +10,19 @@ use Drupal\Core\Entity\Field\FieldItemInterface; use Drupal\jsonld\JsonldNormalizerBase; use Symfony\Component\Serializer\Exception\RuntimeException; +use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; /** * Converts the Drupal entity object structure to JSON-LD array structure. */ -class JsonldFieldItemNormalizer extends JsonldNormalizerBase { +class JsonldFieldItemNormalizer extends JsonldNormalizerBase implements DenormalizerInterface { + + /** + * The interface or class that this Normalizer supports. + * + * @var string + */ + protected static $supportedInterfaceOrClass = 'Drupal\Core\Entity\Field\FieldItemInterface'; /** * Implements \Symfony\Component\Serializer\Normalizer\NormalizerInterface::normalize() @@ -24,10 +32,11 @@ public function normalize($object, $format = NULL) { } /** - * Implements \Symfony\Component\Serializer\Normalizer\NormalizerInterface::supportsNormalization() + * Implements \Symfony\Component\Serializer\Normalizer\DenormalizerInterface::denormalize() */ - public function supportsNormalization($data, $format = NULL) { - return parent::supportsNormalization($data, $format) && ($data instanceof FieldItemInterface); + public function denormalize($data, $class, $format = null) { + // For most fields, the field items array should simply be returned as is. + return $data; } } diff --git a/core/modules/jsonld/lib/Drupal/jsonld/JsonldNormalizerBase.php b/core/modules/jsonld/lib/Drupal/jsonld/JsonldNormalizerBase.php index 2508459..98603d2 100644 --- a/core/modules/jsonld/lib/Drupal/jsonld/JsonldNormalizerBase.php +++ b/core/modules/jsonld/lib/Drupal/jsonld/JsonldNormalizerBase.php @@ -8,7 +8,11 @@ namespace Drupal\jsonld; use Drupal\Core\Entity\EntityNG; +use Drupal\Core\HttpKernel; +use ReflectionClass; use Symfony\Component\Serializer\Exception\RuntimeException; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Normalizer\SerializerAwareNormalizer; @@ -18,6 +22,13 @@ abstract class JsonldNormalizerBase extends SerializerAwareNormalizer implements NormalizerInterface { /** + * The interface or class that this Normalizer supports. + * + * @var string + */ + protected static $supportedInterfaceOrClass; + + /** * The formats that this Normalizer supports. * * @var array @@ -28,7 +39,31 @@ * Implements \Symfony\Component\Serializer\Normalizer\NormalizerInterface::normalize() */ public function supportsNormalization($data, $format = NULL) { - return is_object($data) && in_array($format, static::$format); + return is_object($data) && in_array($format, static::$format) && ($data instanceof static::$supportedInterfaceOrClass); + } + + /** + * Implements \Symfony\Component\Serializer\Normalizer\DenormalizerInterface::supportsDenormalization() + * + * This class doesn't implement DenormalizerInterface, but most of its child + * classes do, so this method is implemented at this level to reduce code + * duplication. + */ + public function supportsDenormalization($data, $type, $format = NULL) { + $reflection = new ReflectionClass($type); + return in_array($format, static::$format) && $reflection->implementsInterface(static::$supportedInterfaceOrClass); } + /** + * Runs a GET request against a URI. + */ + protected function request($uri) { + $container = drupal_container(); + $kernel = $container->get('http_kernel'); + $request = $container->get('request'); + // @todo Add ESI-like exception handling. + $schemaRequest = Request::create($uri, 'get', array(), $request->cookies->all(), array(), $_SERVER); + $response = $kernel->handle($schemaRequest, HttpKernelInterface::SUB_REQUEST, true); + return json_decode($response->getContent()); + } } diff --git a/core/modules/jsonld/lib/Drupal/jsonld/JsonldFieldItemNormalizer.php b/core/modules/jsonld/lib/Drupal/jsonld/RdfBundleSchemaNormalizer.php similarity index 63% copy from core/modules/jsonld/lib/Drupal/jsonld/JsonldFieldItemNormalizer.php copy to core/modules/jsonld/lib/Drupal/jsonld/RdfBundleSchemaNormalizer.php index 3fac801..e843066 100644 --- a/core/modules/jsonld/lib/Drupal/jsonld/JsonldFieldItemNormalizer.php +++ b/core/modules/jsonld/lib/Drupal/jsonld/RdfBundleSchemaNormalizer.php @@ -2,32 +2,34 @@ /** * @file - * Definition of Drupal\jsonld\JsonldFieldItemNormalizer. + * Definition of Drupal\jsonld\RdfBundleSchemaNormalizer. */ namespace Drupal\jsonld; -use Drupal\Core\Entity\Field\FieldItemInterface; use Drupal\jsonld\JsonldNormalizerBase; +use Drupal\rdf\SiteSchema\BundleSchema; use Symfony\Component\Serializer\Exception\RuntimeException; /** * Converts the Drupal entity object structure to JSON-LD array structure. */ -class JsonldFieldItemNormalizer extends JsonldNormalizerBase { +class RdfBundleSchemaNormalizer extends JsonldNormalizerBase { /** * Implements \Symfony\Component\Serializer\Normalizer\NormalizerInterface::normalize() */ - public function normalize($object, $format = NULL) { - return $object->getPropertyValues(); + public function normalize($data, $format = NULL) { + $content['@id'] = $data->getUri(); + $content += $data->getProperties(); + return $content; } /** * Implements \Symfony\Component\Serializer\Normalizer\NormalizerInterface::supportsNormalization() */ public function supportsNormalization($data, $format = NULL) { - return parent::supportsNormalization($data, $format) && ($data instanceof FieldItemInterface); + return parent::supportsNormalization($data, $format) && ($data instanceof BundleSchema); } } diff --git a/core/modules/jsonld/lib/Drupal/jsonld/Tests/JsonldNormalizerTestBase.php b/core/modules/jsonld/lib/Drupal/jsonld/Tests/JsonldNormalizerTestBase.php deleted file mode 100644 index 229f77b..0000000 --- a/core/modules/jsonld/lib/Drupal/jsonld/Tests/JsonldNormalizerTestBase.php +++ /dev/null @@ -1,39 +0,0 @@ -uri(); - return $base_url . '/' . $uriInfo['path']; - } - -} diff --git a/core/modules/jsonld/lib/Drupal/jsonld/Tests/DrupalJsonldNormalizerTest.php b/core/modules/jsonld/lib/Drupal/jsonld/Tests/NormalizeDenormalizeTest.php similarity index 63% rename from core/modules/jsonld/lib/Drupal/jsonld/Tests/DrupalJsonldNormalizerTest.php rename to core/modules/jsonld/lib/Drupal/jsonld/Tests/NormalizeDenormalizeTest.php index 8845342..cd0df2c 100644 --- a/core/modules/jsonld/lib/Drupal/jsonld/Tests/DrupalJsonldNormalizerTest.php +++ b/core/modules/jsonld/lib/Drupal/jsonld/Tests/NormalizeDenormalizeTest.php @@ -2,23 +2,31 @@ /** * @file - * Definition of Drupal\jsonld\Tests\DrupalJsonldNormalizerTest. + * Definition of Drupal\jsonld\Tests\NormalizeDenormalizeTest. */ namespace Drupal\jsonld\Tests; use Drupal\config\Tests\ConfigEntityTest; use Drupal\Core\Language\Language; +use Drupal\jsonld\JsonldEncoder; use Drupal\jsonld\JsonldEntityNormalizer; use Drupal\jsonld\JsonldEntityReferenceNormalizer; use Drupal\jsonld\JsonldFieldItemNormalizer; -use Drupal\jsonld\Tests\JsonldNormalizerTestBase; +use Drupal\simpletest\WebTestBase; use Symfony\Component\Serializer\Serializer; /** * Test the vendor specific JSON-LD normalizer. */ -class DrupalJsonldNormalizerTest extends JsonldNormalizerTestBase { +class NormalizeDenormalizeTest extends WebTestBase { + + /** + * Modules to enable. + * + * @var array + */ + public static $modules = array('language', 'entity_test', 'jsonld_test'); /** * The format being tested. @@ -32,8 +40,8 @@ class DrupalJsonldNormalizerTest extends JsonldNormalizerTestBase { public static function getInfo() { return array( - 'name' => 'vnd.drupal.ld+json Normalization', - 'description' => "Test Drupal's vendor specific JSON-LD normalizer.", + 'name' => 'Normalize/Denormalize Test', + 'description' => "Test that entities can be normalized/denormalized in JSON-LD.", 'group' => 'JSON-LD', ); } @@ -49,42 +57,21 @@ function setUp() { 'field_item' => new JsonldFieldItemNormalizer(), 'entity' => new JsonldEntityNormalizer(), ); - $serializer = new Serializer($this->normalizers); + $serializer = new Serializer($this->normalizers, array(new JsonldEncoder())); $this->normalizers['entity']->setSerializer($serializer); - } - /** - * Tests the supportsNormalization function. - */ - public function testSupportsNormalization() { - $format = static::$format; - $supportedEntity = entity_create('entity_test', array()); - $unsupportedEntity = new ConfigEntityTest(); - $field = $supportedEntity->get('uuid'); - $entityreferenceField = $supportedEntity->get('user_id'); - - // Supported entity. - $this->assertTrue($this->normalizers['entity']->supportsNormalization($supportedEntity, static::$format), "Entity normalization is supported for $format on content entities."); - // Unsupported entity. - $this->assertFalse($this->normalizers['entity']->supportsNormalization($unsupportedEntity, static::$format), "Normalization is not supported for other entity types."); - - // Field item. - $this->assertTrue($this->normalizers['field_item']->supportsNormalization($field->offsetGet(0), static::$format), "Field item normalization is supported for $format."); - // Entity reference field item. - $this->assertTrue($this->normalizers['entityreference']->supportsNormalization($entityreferenceField->offsetGet(0), static::$format), "Entity reference field item normalization is supported for $format."); - } - - /** - * Tests the normalize function. - */ - public function testNormalize() { // Add German as a language. $language = new Language(array( 'langcode' => 'de', 'name' => 'Deutsch', )); language_save($language); + } + /** + * Tests the normalize function. + */ + public function testNormalize() { // Create a German entity. $values = array( 'langcode' => 'de', @@ -159,4 +146,51 @@ public function testNormalize() { $this->assertEqual($normalized['field_test_text'], $expectedArray['field_test_text'], 'Field with properties is nested correctly.'); } + function testDenormalize() { + $incomingData = array( + '@type' => url('jsonld-test/content-staging/entity_test/entity_test', array('absolute' => TRUE)), + 'name' => array( + 'en' => array( + array( + 'value' => $this->randomName(), + ), + ), + 'de' => array( + array( + 'value' => $this->randomName(), + ), + ), + ), + 'field_test_text' => array( + 'und' => array( + array( + 'value' => $this->randomName(), + 'format' => 'full_html', + ), + ), + ), + ); + + $entity = $this->normalizers['entity']->denormalize($incomingData, 'Drupal\Core\Entity\EntityNG', static::$format); + $this->assertEqual('entity_test', $entity->bundle(), "Denormalize creates entity with correct bundle."); + $this->assertEqual($incomingData['name']['en'], $entity->getTranslation('en')->get('name')->getValue(), "Translatable field denormalized correctly in default language."); + $this->assertEqual($incomingData['name']['de'], $entity->getTranslation('de')->get('name')->getValue(), "Translatable field denormalized correctly in translation language."); + $this->assertEqual($incomingData['field_test_text']['und'], $entity->get('field_test_text')->getValue(), "Untranslatable field denormalized correctly."); + } + + /** + * Get the Entity ID. + * + * @param Drupal\Core\Entity\EntityNG $entity + * Entity to get URI for. + * + * @return string + * Return the entity URI. + */ + protected function getEntityId($entity) { + global $base_url; + $uriInfo = $entity->uri(); + return $base_url . '/' . $uriInfo['path']; + } + } diff --git a/core/modules/jsonld/lib/Drupal/jsonld/Tests/SupportsSerializationTest.php b/core/modules/jsonld/lib/Drupal/jsonld/Tests/SupportsSerializationTest.php new file mode 100644 index 0000000..fdcc861 --- /dev/null +++ b/core/modules/jsonld/lib/Drupal/jsonld/Tests/SupportsSerializationTest.php @@ -0,0 +1,105 @@ + 'Supports class/format serialization test', + 'description' => "Test that normalizers and encoders support expected classes and formats.", + 'group' => 'JSON-LD', + ); + } + + /** + * Add the normalizer to be tested. + */ + function setUp() { + parent::setUp(); + + $this->normalizers = array( + 'entityreference' => new JsonldEntityReferenceNormalizer(), + 'field_item' => new JsonldFieldItemNormalizer(), + 'entity' => new JsonldEntityNormalizer(), + ); + $serializer = new Serializer($this->normalizers); + $this->normalizers['entity']->setSerializer($serializer); + } + + /** + * Tests the supportsNormalization function. + */ + public function testSupportsNormalization() { + $format = static::$format; + $supportedEntity = entity_create('entity_test', array()); + $unsupportedEntity = new ConfigEntityTest(); + $field = $supportedEntity->get('uuid'); + $entityreferenceField = $supportedEntity->get('user_id'); + + // Supported entity. + $this->assertTrue($this->normalizers['entity']->supportsNormalization($supportedEntity, static::$format), "Entity normalization is supported for $format on content entities."); + // Unsupported entity. + $this->assertFalse($this->normalizers['entity']->supportsNormalization($unsupportedEntity, static::$format), "Normalization is not supported for other entity types."); + + // Field item. + $this->assertTrue($this->normalizers['field_item']->supportsNormalization($field->offsetGet(0), static::$format), "Field item normalization is supported for $format."); + // Entity reference field item. + $this->assertTrue($this->normalizers['entityreference']->supportsNormalization($entityreferenceField->offsetGet(0), static::$format), "Entity reference field item normalization is supported for $format."); + } + + /** + * Tests the supportsNormalization function. + */ + public function testSupportsDenormalization() { + $format = static::$format; + $data = array(); + $supportedEntityClass = 'Drupal\Core\Entity\EntityNG'; + $unsupportedEntityClass = 'Drupal\config\Tests\ConfigEntityTest'; + $fieldClass = 'Drupal\Core\Entity\Field\Type\StringItem'; + $entityreferenceFieldClass = 'Drupal\Core\Entity\Field\Type\EntityReferenceItem'; + + // Supported entity. + $this->assertTrue($this->normalizers['entity']->supportsDenormalization($data, $supportedEntityClass, static::$format), "Entity denormalization is supported for $format on content entities."); + // Unsupported entity. + $this->assertFalse($this->normalizers['entity']->supportsDenormalization($data, $unsupportedEntityClass, static::$format), "Denormalization is not supported for other entity types."); + + // Field item. + $this->assertTrue($this->normalizers['field_item']->supportsDenormalization($data, $fieldClass, static::$format), "Field item denormalization is supported for $format."); + // Entity reference field item. + $this->assertTrue($this->normalizers['entityreference']->supportsDenormalization($data, $entityreferenceFieldClass, static::$format), "Entity reference field item denormalization is supported for $format."); + } + +} diff --git a/core/modules/jsonld/tests/modules/jsonld_test/jsonld_test.info b/core/modules/jsonld/tests/modules/jsonld_test/jsonld_test.info new file mode 100644 index 0000000..9bdfbc9 --- /dev/null +++ b/core/modules/jsonld/tests/modules/jsonld_test/jsonld_test.info @@ -0,0 +1,5 @@ +name = JSON-LD test module +description = Provides site schema definitions. +package = Testing +core = 8.x +hidden = TRUE diff --git a/core/modules/jsonld/tests/modules/jsonld_test/jsonld_test.module b/core/modules/jsonld/tests/modules/jsonld_test/jsonld_test.module new file mode 100644 index 0000000..3b3a2df --- /dev/null +++ b/core/modules/jsonld/tests/modules/jsonld_test/jsonld_test.module @@ -0,0 +1,6 @@ + 'application/ld+json')); + } +} \ No newline at end of file diff --git a/core/modules/rdf/lib/Drupal/rdf/EventSubscriber/RouteSubscriber.php b/core/modules/rdf/lib/Drupal/rdf/EventSubscriber/RouteSubscriber.php new file mode 100644 index 0000000..625e1a3 --- /dev/null +++ b/core/modules/rdf/lib/Drupal/rdf/EventSubscriber/RouteSubscriber.php @@ -0,0 +1,65 @@ +getRouteCollection(); + + // The paths of the site-generated schemas. + $schemaPaths = array( + SchemaConstants::CONTENT_STAGING, + SchemaConstants::SYNDICATION, + ); + + // Add the routes for all of the terms in both schemas. + foreach ($schemaPaths as $schemaPath) { + $schema = new SiteSchema($schemaPath); + $routes = $schema->getRoutes(); + foreach ($routes as $controller => $pattern) { + $route = new Route($pattern, array( + '_controller' => 'Drupal\rdf\SiteSchema\SchemaController::' . $controller, + 'schema_path' => $schemaPath, + ), array( + '_method' => 'GET', + )); + // Create the route name to use in the RouteCollection. Remove the + // trailing slash and replace characters, so that a path such as + // site-schema/syndication/ becomes rdf.site_schema.syndication. + $routeName = 'rdf.' . str_replace(array('-','/'), array('_', '.'), substr_replace($schemaPath ,"",-1)); + $collection->add($routeName, $route); + } + } + } + + /** + * Implements EventSubscriberInterface::getSubscribedEvents(). + */ + static function getSubscribedEvents() { + $events[RoutingEvents::DYNAMIC] = 'routes'; + return $events; + } +} + diff --git a/core/modules/rdf/lib/Drupal/rdf/RdfBundle.php b/core/modules/rdf/lib/Drupal/rdf/RdfBundle.php new file mode 100644 index 0000000..cd95af9 --- /dev/null +++ b/core/modules/rdf/lib/Drupal/rdf/RdfBundle.php @@ -0,0 +1,26 @@ +register('rdf.route_subscriber', 'Drupal\rdf\EventSubscriber\RouteSubscriber') + ->addTag('event_subscriber'); + } +} diff --git a/core/modules/rdf/lib/Drupal/rdf/RdfConstants.php b/core/modules/rdf/lib/Drupal/rdf/RdfConstants.php new file mode 100644 index 0000000..7a35312 --- /dev/null +++ b/core/modules/rdf/lib/Drupal/rdf/RdfConstants.php @@ -0,0 +1,29 @@ +bundle = $bundle; + } + + /** + * Implements \Drupal\rdf\SiteSchema\SchemaBase::getUri(). + */ + public function getUri() { + $path = str_replace(array('{entity_type}', '{bundle}'), array($this->entityType, $this->bundle), SchemaConstants::URI_PATTERN_BUNDLE); + return $this->siteSchema->getUri() . $path; + } + + /** + * Overrides \Drupal\rdf\SiteSchema\SchemaBase::getProperties(). + */ + public function getProperties() { + $properties = parent::getProperties(); + $properties[RdfConstants::RDFS_SUB_CLASS_OF] = $this->siteSchema->entity($this->entityType)->getUri(); + $properties[RdfConstants::DRUPAL_BUNDLE_NAME] = $this->bundle; + return $properties; + } + +} diff --git a/core/modules/rdf/lib/Drupal/rdf/SiteSchema/EntitySchema.php b/core/modules/rdf/lib/Drupal/rdf/SiteSchema/EntitySchema.php new file mode 100644 index 0000000..40a5251 --- /dev/null +++ b/core/modules/rdf/lib/Drupal/rdf/SiteSchema/EntitySchema.php @@ -0,0 +1,56 @@ +entityType = $entity_type; + } + + /** + * Implements \Drupal\rdf\SiteSchema\SchemaBase::getUri(). + */ + public function getUri() { + $path = str_replace('{entity_type}', $this->entityType , SchemaConstants::URI_PATTERN_ENTITY); + return $this->siteSchema->getUri() . $path; + } + + /** + * Overrides \Drupal\rdf\SiteSchema\SchemaBase::getProperties(). + */ + public function getProperties() { + $properties = parent::getProperties(); + $properties[RdfConstants::DRUPAL_ENTITY_TYPE] = $this->entityType; + return $properties; + } + +} diff --git a/core/modules/rdf/lib/Drupal/rdf/SiteSchema/SchemaBase.php b/core/modules/rdf/lib/Drupal/rdf/SiteSchema/SchemaBase.php new file mode 100644 index 0000000..7c116f2 --- /dev/null +++ b/core/modules/rdf/lib/Drupal/rdf/SiteSchema/SchemaBase.php @@ -0,0 +1,57 @@ +siteSchema = $siteSchema; + } + + /** + * Get the term properties. + * + * @return array + * An array of properties for this term, keyed by URI. + */ + public function getProperties() { + return array( + RdfConstants::RDFS_IS_DEFINED_BY => $this->siteSchema->getUri(), + ); + } + + /** + * Get the URI of the term. + * + * Implementations of this method will use the URI patterns defined in + * SchemaConstants and replace placeholders with actual values. + * + * @return string + * The URI of the term. + */ + abstract public function getUri(); + +} diff --git a/core/modules/rdf/lib/Drupal/rdf/SiteSchema/SchemaConstants.php b/core/modules/rdf/lib/Drupal/rdf/SiteSchema/SchemaConstants.php new file mode 100644 index 0000000..95c1f9a --- /dev/null +++ b/core/modules/rdf/lib/Drupal/rdf/SiteSchema/SchemaConstants.php @@ -0,0 +1,20 @@ + $entity_type))); + } + if (!array_key_exists($bundle, $entity_info['bundles'])) { + throw new NotFoundHttpException(t('Bundle @bundle not found', array('@bundle' => $bundle))); + } + + $serializer = drupal_container()->get('serializer'); + $siteSchema = new SiteSchema($schema_path); + // @todo Remove hard-coded mimetype once we have proper conneg. + $content = $serializer->serialize($siteSchema->bundle($entity_type, $bundle), 'jsonld'); + return new Response($content, 200, array('Content-type' => 'application/json')); + } + +} diff --git a/core/modules/rdf/lib/Drupal/rdf/SiteSchema/SiteSchema.php b/core/modules/rdf/lib/Drupal/rdf/SiteSchema/SiteSchema.php new file mode 100644 index 0000000..3510591 --- /dev/null +++ b/core/modules/rdf/lib/Drupal/rdf/SiteSchema/SiteSchema.php @@ -0,0 +1,70 @@ +schemaPath = $schemaPath; + } + + /** + * Get an entity's term definition in this vocabulary. + */ + public function entity($entity_type) { + return new EntitySchema($this, $entity_type); + } + + /** + * Get a bundle's term definition in this vocabulary. + */ + public function bundle($entity_type, $bundle) { + return new BundleSchema($this, $entity_type, $bundle); + } + + /** + * Get the URI of the schema. + * + * @return string + * The URI of the schema. + */ + public function getUri() { + return url($this->schemaPath, array('absolute' => TRUE)); + } + + /** + * Get the routes for the types of terms defined in this schema. + * + * @return array + * An array of route patterns, keyed by controller method name. + */ + public function getRoutes() { + return array( + 'bundle' => $this->schemaPath . SchemaConstants::URI_PATTERN_BUNDLE, + ); + } +} diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/SiteSchemaTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/SiteSchemaTest.php new file mode 100644 index 0000000..a23a03c --- /dev/null +++ b/core/modules/rdf/lib/Drupal/rdf/Tests/SiteSchemaTest.php @@ -0,0 +1,55 @@ + 'RDF site schema test', + 'description' => 'Confirm that site-generated schemas are created for entity, bundle, field, and field property.', + 'group' => 'RDF', + ); + } + + /** + * Tests site-generated schema. + */ + function testSiteSchema() { + $entityType = $bundle = 'entity_test'; + $schema = new SiteSchema(SchemaConstants::SYNDICATION); + $schemaPath = 'site-schema/syndication/'; + + // Bundle. + $bundleSchema = $schema->bundle($entityType, $bundle); + $bundleUri = url("$schemaPath$entityType/$bundle", array('absolute' => TRUE)); + $bundleProperties = array( + "http://www.w3.org/2000/01/rdf-schema#isDefinedBy" => url($schemaPath, array('absolute' => TRUE)), + "http://www.w3.org/2000/01/rdf-schema#subClassOf" => url("$schemaPath$entityType", array('absolute' => TRUE)), + ); + + $this->assertEqual($bundleSchema->getUri(), $bundleUri, 'Bundle term URI is generated correctly.'); + $this->assertEqual($bundleSchema->getProperties(), $bundleProperties, 'Bundle term properties are generated correctly.'); + } + +}