diff --git a/core/modules/rdf/lib/Drupal/rdf/MapInputTypesEvent.php b/core/modules/rdf/lib/Drupal/rdf/MapInputTypesEvent.php new file mode 100644 index 0000000..20be166 --- /dev/null +++ b/core/modules/rdf/lib/Drupal/rdf/MapInputTypesEvent.php @@ -0,0 +1,90 @@ +inputUris = $inputUris; + $this->siteSchemaTypes = $siteSchemaTypes; + $this->siteSchemaUri = FALSE; + } + + /** + * Gets the input URI. + * + * @return array + * The array of incoming RDF type URIs. + */ + public function getInputUris() { + return $this->inputUris; + } + + /** + * Gets the cache of internal site schema types. + * + * @return array + * The cached site schema type array. + */ + public function getSiteSchemaTypes() { + return $this->siteSchemaTypes; + } + + /** + * Gets the site schema URI. + * + * @return string|bool + * The site schema type URI if set, FALSE if otherwise. + */ + public function getSiteSchemaUri() { + return $this->siteSchemaUri; + } + + /** + * Sets the site schema URI. + * + * @param string $uri + * The site schema type URI. + */ + public function setSiteSchemaUri($uri) { + $this->siteSchemaUri = $uri; + } +} diff --git a/core/modules/rdf/lib/Drupal/rdf/RdfBundle.php b/core/modules/rdf/lib/Drupal/rdf/RdfBundle.php index cd95af9..e32fd8d 100644 --- a/core/modules/rdf/lib/Drupal/rdf/RdfBundle.php +++ b/core/modules/rdf/lib/Drupal/rdf/RdfBundle.php @@ -22,5 +22,7 @@ class RdfBundle extends Bundle { public function build(ContainerBuilder $container) { $container->register('rdf.route_subscriber', 'Drupal\rdf\EventSubscriber\RouteSubscriber') ->addTag('event_subscriber'); + $container->register('rdf.site_schema.mapping_manager', 'Drupal\rdf\RdfMappingManager') + ->addArgument(new Reference('dispatcher')); } } diff --git a/core/modules/rdf/lib/Drupal/rdf/RdfMappingEvents.php b/core/modules/rdf/lib/Drupal/rdf/RdfMappingEvents.php new file mode 100644 index 0000000..5a7d9a8 --- /dev/null +++ b/core/modules/rdf/lib/Drupal/rdf/RdfMappingEvents.php @@ -0,0 +1,28 @@ +dispatcher = $dispatcher; + $this->siteSchemas = array( + new SiteSchema(SchemaConstants::CONTENT_STAGING), + new SiteSchema(SchemaConstants::SYNDICATION), + ); + } + + /** + * Convert an array of RDF type URIs to the corresponding TypedData IDs. + * + * @param array $inputRdfTypes + * An array of URIs for the type. + * + * @return array + * An array containing entity_type and bundle. + */ + public function getTypedDataIds($inputRdfTypes) { + // Get the cache of site schema types. + $siteSchemaTypes = $this->getCacheData('rdf:site_schema:types'); + // Map the RDF type from the incoming data to an RDF type defined in the + // internal site schema. + $typeUri = $this->mapInputTypes($inputRdfTypes); + // If no site schema URI has been determined, then it's impossible to know + // what entity type to create. Throw an exception. + if ($typeUri == FALSE) { + // @todo Throw exception. + } + // Use the mapped RDF type URI to get the TypedData API ids the rest of the + // system uses (entity type and bundle). + return $siteSchemaTypes[$typeUri]; + } + + /** + * Get the cached array of RDF terms and corresponding TypedData Ids. + * + * @param string $bin + * The cache to get (e.g. rdf:site_schema:types). + * + * @return array + * The cached data. + */ + protected function getCacheData($bin) { + $cache = cache()->get($bin); + // If the cache is empty, build it. + if ($cache == FALSE) { + switch ($bin) { + case 'rdf:site_schema:types': + $data = $this->buildTypeCache(); + break; + } + cache()->set($bin, $data, CacheBackendInterface::CACHE_PERMANENT, 'entity_info'); + return $data; + } + return $cache->data; + } + + /** + * Build the site schema type cache. + * + * @return array + * An array of TypedData API IDs, keyed by corresponding site schema URI. + */ + protected function buildTypeCache() { + $data = array(); + + // Type URIs correspond to bundles. Iterate through the bundles to get the + // URI and data for them. + foreach (entity_get_info() as $entityType => $entityInfo) { + // Only content entities are supported currently. + // @todo Consider supporting config entities. + $reflection = new ReflectionClass($entityInfo['class']); + if (!$reflection->implementsInterface('\Drupal\Core\Entity\ContentEntityInterface')) { + continue; + } + foreach ($entityInfo['bundles'] as $bundle => $bundleInfo) { + // Get a type URI for the bundle in each of the defined schemas. + foreach ($this->siteSchemas as $schema) { + $bundleSchema = new BundleSchema($schema, $entityType, $bundle); + $bundleUri = $bundleSchema->getUri(); + $data[$bundleUri] = array( + 'entity_type' => $entityType, + 'bundle' => $bundle, + ); + } + } + } + return $data; + } + + /** + * Map an array of incoming URIs to an internal site schema URI. + * + * @param array $inputRdfTypes + * An array of RDF type URIs. + * + * @return string + * The corresponding site schema type URI. + */ + protected function mapInputTypes($inputRdfTypes) { + // Create the event using the array of incoming RDF type URIs and the cache + // of internal site schema URIs. + $siteSchemaTypes = $this->getCacheData('rdf:site_schema:types'); + $typeMap = new MapInputTypesEvent($inputRdfTypes, $siteSchemaTypes); + + // Add the default listener. This doesn't do any mapping, it only sets the + // event's site schema URI if one of the incoming RDF types is a site + // schema type URI. + $this->dispatcher->addListener(RdfMappingEvents::MAP_INPUT_TYPES, function (MapInputTypesEvent $event) { + $inputUris = $event->getInputUris(); + $siteSchemaTypes = $event->getSiteSchemaTypes(); + foreach ($inputUris as $inputUri) { + if (isset($siteSchemaTypes[$inputUri])) { + $event->setSiteSchemaUri($inputUri); + $event->stopPropagation(); + } + } + }); + + // Allow other modules to map the incoming type URIs to an internal site + // schema type URI. For example, a content deployment module could take + // URIs from the staging site's schema and map them to the corresponding + // URI in the live site's schema. + $this->dispatcher->dispatch(RdfMappingEvents::MAP_INPUT_TYPES, $typeMap); + + return $typeMap->getSiteSchemaUri(); + } +}