diff --git a/core/includes/common.inc b/core/includes/common.inc index 97b73f4..d5c9e5b 100644 --- a/core/includes/common.inc +++ b/core/includes/common.inc @@ -1904,8 +1904,6 @@ function format_date($timestamp, $type = 'medium', $format = '', $timezone = NUL /** * Returns an ISO8601 formatted date based on the given date. * - * Callback for use within hook_rdf_mapping() implementations. - * * @param $date * A UNIX timestamp. * diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module index 6f2795a..45834df 100644 --- a/core/modules/comment/comment.module +++ b/core/modules/comment/comment.module @@ -2016,48 +2016,6 @@ function comment_ranking() { } /** - * Implements hook_rdf_mapping(). - */ -function comment_rdf_mapping() { - return array( - array( - 'type' => 'comment', - 'bundle' => RDF_DEFAULT_BUNDLE, - 'mapping' => array( - 'rdftype' => array('sioc:Post', 'sioct:Comment'), - 'title' => array( - 'predicates' => array('dc:title'), - ), - 'created' => array( - 'predicates' => array('dc:date', 'dc:created'), - 'datatype' => 'xsd:dateTime', - 'callback' => 'date_iso8601', - ), - 'changed' => array( - 'predicates' => array('dc:modified'), - 'datatype' => 'xsd:dateTime', - 'callback' => 'date_iso8601', - ), - 'comment_body' => array( - 'predicates' => array('content:encoded'), - ), - 'pid' => array( - 'predicates' => array('sioc:reply_of'), - 'type' => 'rel', - ), - 'uid' => array( - 'predicates' => array('sioc:has_creator'), - 'type' => 'rel', - ), - 'name' => array( - 'predicates' => array('foaf:name'), - ), - ), - ), - ); -} - -/** * Implements hook_file_download_access(). */ function comment_file_download_access($field, EntityInterface $entity, File $file) { diff --git a/core/modules/forum/forum.module b/core/modules/forum/forum.module index 872eb95..85b9c66 100644 --- a/core/modules/forum/forum.module +++ b/core/modules/forum/forum.module @@ -1306,7 +1306,7 @@ function forum_rdf_mapping() { 'rdftype' => array('sioc:Post', 'sioct:BoardPost'), 'taxonomy_forums' => array( 'predicates' => array('sioc:has_container'), - 'type' => 'rel', + 'mapping_type' => 'rel', ), ), ), diff --git a/core/modules/rdf/lib/Drupal/rdf/EventSubscriber/MappingSubscriber.php b/core/modules/rdf/lib/Drupal/rdf/EventSubscriber/MappingSubscriber.php index cc0104e..f168fa0 100644 --- a/core/modules/rdf/lib/Drupal/rdf/EventSubscriber/MappingSubscriber.php +++ b/core/modules/rdf/lib/Drupal/rdf/EventSubscriber/MappingSubscriber.php @@ -62,6 +62,7 @@ public function mapFieldForOutput(\Drupal\rdf\Mapping\MapFieldForOutputEvent $ev $event->addPredicates($properties); $datatype = $config->get('datatype'); $datatype_callback = $config->get('datatype_callback'); + $mapping_type = $config->get('mapping_type'); if (isset($datatype)) { $event->setDatatype($datatype); @@ -69,6 +70,9 @@ public function mapFieldForOutput(\Drupal\rdf\Mapping\MapFieldForOutputEvent $ev if (isset($datatype_callback)) { $event->setDatatypeCallback($datatype_callback); } + if (isset($mapping_type)) { + $event->setMappingType($mapping_type); + } } } diff --git a/core/modules/rdf/lib/Drupal/rdf/Mapping/MapFieldForOutputEvent.php b/core/modules/rdf/lib/Drupal/rdf/Mapping/MapFieldForOutputEvent.php index 682c67f..ce4869a 100644 --- a/core/modules/rdf/lib/Drupal/rdf/Mapping/MapFieldForOutputEvent.php +++ b/core/modules/rdf/lib/Drupal/rdf/Mapping/MapFieldForOutputEvent.php @@ -29,6 +29,8 @@ class MapFieldForOutputEvent extends Event { protected $datatypeCallback; + protected $mappingType; + /** * Constructor. * @@ -76,6 +78,15 @@ public function setDatatypeCallback($callable) { $this->datatypeCallback = $callable; } + /** + * Set the mapping type. + * + * @param string $mapping_type + */ + public function setMappingType($mapping_type) { + $this->mappingType = $mapping_type; + } + public function getPredicates() { return $this->predicates; } @@ -87,4 +98,8 @@ public function getDatatype() { public function getDatatypeCallback() { return $this->datatypeCallback; } + + public function getMappingType() { + return $this->mappingType; + } } diff --git a/core/modules/rdf/lib/Drupal/rdf/Mapping/RdfMappingManager.php b/core/modules/rdf/lib/Drupal/rdf/Mapping/RdfMappingManager.php index d9c5c73..70a0cf6 100644 --- a/core/modules/rdf/lib/Drupal/rdf/Mapping/RdfMappingManager.php +++ b/core/modules/rdf/lib/Drupal/rdf/Mapping/RdfMappingManager.php @@ -235,6 +235,7 @@ protected function mapFieldForOutput($term_schema) { $mapping['properties'] = $predicates; $mapping['datatype'] = $map_event->getDatatype(); $mapping['datatype_callback'] = $map_event->getDatatypeCallback(); + $mapping['mapping_type'] = $map_event->getMappingType(); } return array_filter($mapping); } diff --git a/core/modules/rdf/lib/Drupal/rdf/Plugin/Core/Entity/FieldRdfMapping.php b/core/modules/rdf/lib/Drupal/rdf/Plugin/Core/Entity/FieldRdfMapping.php index 89f7aae..a38eee3 100644 --- a/core/modules/rdf/lib/Drupal/rdf/Plugin/Core/Entity/FieldRdfMapping.php +++ b/core/modules/rdf/lib/Drupal/rdf/Plugin/Core/Entity/FieldRdfMapping.php @@ -84,6 +84,15 @@ class FieldRdfMapping extends ConfigEntityBase { public $datatype_callback; /** + * The type of mapping indicating if the target is a string or a resource. + * + * @todo deprecate in favor of EntityNG. + * + * @var string + */ + public $mapping_type; + + /** * Implements Drupal\Core\Entity\EntityInterface::id(). */ public function id() { diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php index bce0f35..e78e1ba 100644 --- a/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php +++ b/core/modules/rdf/lib/Drupal/rdf/Tests/CommentAttributesTest.php @@ -19,7 +19,7 @@ class CommentAttributesTest extends CommentTestBase { * * @var array */ - public static $modules = array('comment', 'rdf'); + public static $modules = array('comment', 'rdf', 'rdf_test'); public static function getInfo() { return array( diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/MappingDefinitionTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/MappingDefinitionTest.php index 52bcc7e..c77887a 100644 --- a/core/modules/rdf/lib/Drupal/rdf/Tests/MappingDefinitionTest.php +++ b/core/modules/rdf/lib/Drupal/rdf/Tests/MappingDefinitionTest.php @@ -43,7 +43,7 @@ function testAttributesInMarkup1() { // Ensure the default bundle mapping for node is used. These attributes come // from the node default bundle definition. - $node_title = $this->xpath("//meta[@property='dc:title' and @content='$node->title']"); + $node_title = $this->xpath("//meta[contains(@property, 'dc:title') and @content='$node->title']"); $node_meta = $this->xpath("//article[(@about='$url')]//span[contains(@property, 'dc:date') and contains(@property, 'dc:created') and @datatype='xsd:dateTime' and @content='$isoDate']"); $this->assertTrue(!empty($node_title), 'Property dc:title is present in meta tag.'); $this->assertTrue(!empty($node_meta), 'RDF type is present on post. Properties dc:date and dc:created are present on post date.'); @@ -53,44 +53,72 @@ function testAttributesInMarkup1() { * Tests if RDF mapping defined in rdf_test.install is used. * * Creates a content type and a node of type test_bundle_hook_install and - * tests whether the RDF mapping defined in rdf_test.install is used. + * tests whether the RDF mappings from the RDF mapping manager are used. */ function testAttributesInMarkup2() { $type = $this->drupalCreateContentType(array('type' => 'test_bundle_hook_install')); $node = $this->drupalCreateNode(array('type' => 'test_bundle_hook_install')); + + // Set bundle mapping config for test_bundle_hook_install. + $rdf_mapping_manager = drupal_container()->get('rdf.mapping_manager'); + $config = $rdf_mapping_manager->getBundleMappingConfig('node', 'test_bundle_hook_install'); + $bundle_mapping = array_merge($config->get(), array('types' => array('foo:mapping_install1', 'bar:mapping_install2'))); + $config->setData($bundle_mapping)->save(); + + // Set fields mapping config for test_bundle_hook_install. + $node_shared_field_mappings = array( + 'title' => array( + 'properties' => array('dc:title'), + ), + 'created' => array( + 'properties' => array('dc:date', 'dc:created'), + 'datatype' => 'xsd:dateTime', + 'datatype_callback' => 'date_iso8601', + ), + 'changed' => array( + 'properties' => array('dc:modified'), + 'datatype' => 'xsd:dateTime', + 'datatype_callback' => 'date_iso8601', + ), + 'body' => array( + 'properties' => array('content:encoded'), + ), + 'uid' => array( + 'properties' => array('sioc:has_creator'), + 'mapping_type' => 'rel', + ), + 'name' => array( + 'properties' => array('foaf:name'), + ), + 'comment_count' => array( + 'properties' => array('sioc:num_replies'), + 'datatype' => 'xsd:integer', + ), + 'last_activity' => array( + 'properties' => array('sioc:last_activity_date'), + 'datatype' => 'xsd:dateTime', + 'datatype_callback' => 'date_iso8601', + ), + ); + // Iterate over field mappings and save. + foreach ($node_shared_field_mappings as $field_name => $field_mapping) { + $config = $rdf_mapping_manager->getFieldMappingConfig('node', 'test_bundle_hook_install', $field_name); + $field_mapping = array_merge($config->get(), $field_mapping); + $config->setData($field_mapping)->save(); + } + $isoDate = date('c', $node->changed); $url = url('node/' . $node->nid); $this->drupalGet('node/' . $node->nid); // Ensure the mapping defined in rdf_module.test is used. - $test_bundle_title = $this->xpath("//meta[@property='dc:title' and @content='$node->title']"); + $test_bundle_title = $this->xpath("//meta[contains(@property, 'dc:title') and @content='$node->title']"); $test_bundle_meta = $this->xpath("//article[(@about='$url') and contains(@typeof, 'foo:mapping_install1') and contains(@typeof, 'bar:mapping_install2')]//span[contains(@property, 'dc:date') and contains(@property, 'dc:created') and @datatype='xsd:dateTime' and @content='$isoDate']"); $this->assertTrue(!empty($test_bundle_title), 'Property dc:title is present in meta tag.'); $this->assertTrue(!empty($test_bundle_meta), 'RDF type is present on post. Properties dc:date and dc:created are present on post date.'); } /** - * Tests if the default mapping for a node is being used. - * - * Creates a random content type and node and ensures the default mapping for - * the node is being used. - */ - function testAttributesInMarkup3() { - $type = $this->drupalCreateContentType(); - $node = $this->drupalCreateNode(array('type' => $type->type)); - $isoDate = date('c', $node->changed); - $url = url('node/' . $node->nid); - $this->drupalGet('node/' . $node->nid); - - // Ensure the default bundle mapping for node is used. These attributes come - // from the node default bundle definition. - $random_bundle_title = $this->xpath("//meta[@property='dc:title' and @content='$node->title']"); - $random_bundle_meta = $this->xpath("//article[(@about='$url') and contains(@typeof, 'sioc:Item') and contains(@typeof, 'foaf:Document')]//span[contains(@property, 'dc:date') and contains(@property, 'dc:created') and @datatype='xsd:dateTime' and @content='$isoDate']"); - $this->assertTrue(!empty($random_bundle_title), 'Property dc:title is present in meta tag.'); - $this->assertTrue(!empty($random_bundle_meta), 'RDF type is present on post. Properties dc:date and dc:created are present on post date.'); - } - - /** * Tests if default mapping for user is being used. * * Creates a random user and ensures the default mapping for the user is @@ -109,7 +137,7 @@ function testUserAttributesInMarkup() { $account_uri = url('user/' . $user2->uid); $person_uri = url('user/' . $user2->uid, array('fragment' => 'me')); - $user2_profile_about = $this->xpath('//article[@class="profile" and @typeof="sioc:UserAccount" and @about=:account-uri]', array( + $user2_profile_about = $this->xpath('//article[@class="profile" and contains(@typeof, "sioc:UserAccount") and @about=:account-uri]', array( ':account-uri' => $account_uri, )); $this->assertTrue(!empty($user2_profile_about), 'RDFa markup found on user profile page'); @@ -133,7 +161,7 @@ function testUserAttributesInMarkup() { $this->drupalGet('node/' . $node->nid); // Ensures the default bundle mapping for user is used on the Authored By // information on the node. - $author_about = $this->xpath('//a[@typeof="sioc:UserAccount" and @about=:account-uri and @property="foaf:name" and @datatype="" and contains(@lang, "")]', array( + $author_about = $this->xpath('//a[contains(@typeof, "sioc:UserAccount") and @about=:account-uri and contains(@property, "foaf:name") and @datatype="" and contains(@lang, "")]', array( ':account-uri' => $account_uri, )); $this->assertTrue(!empty($author_about), 'RDFa markup found on author information on post. The lang attribute on username is set to empty string.'); @@ -143,14 +171,13 @@ function testUserAttributesInMarkup() { * Creates a random term and ensures the right RDFa markup is used. */ function testTaxonomyTermRdfaAttributes() { - $vocabulary = $this->createVocabulary(); - $term = $this->createTerm($vocabulary); + $term = $this->createTerm(taxonomy_vocabulary_load('tags')); // Views the term and checks that the RDFa markup is correct. $this->drupalGet('taxonomy/term/' . $term->tid); $term_url = url('taxonomy/term/' . $term->tid); $term_label = $term->label(); - $term_rdfa_meta = $this->xpath('//meta[@typeof="skos:Concept" and @about=:term-url and contains(@property, "rdfs:label") and contains(@property, "skos:prefLabel") and @content=:term-label]', array( + $term_rdfa_meta = $this->xpath('//meta[contains(@typeof, "skos:Concept") and @about=:term-url and contains(@property, "rdfs:label") and contains(@property, "skos:prefLabel") and @content=:term-label]', array( ':term-url' => $term_url, ':term-label' => $term_label, )); diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/RdfaMarkupTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/RdfaMarkupTest.php index 92362ee..78707e5 100644 --- a/core/modules/rdf/lib/Drupal/rdf/Tests/RdfaMarkupTest.php +++ b/core/modules/rdf/lib/Drupal/rdf/Tests/RdfaMarkupTest.php @@ -81,7 +81,7 @@ function testAttributesInMarkupFile() { // Set the RDF mapping for the new field. $config = $this->mappingManager->getFieldMappingConfig('node', 'article', $field_name); - $field_mapping = array_merge($config->get(), array('properties' => array('rdfs:seeAlso'), 'type' => 'rel')); + $field_mapping = array_merge($config->get(), array('properties' => array('rdfs:seeAlso'), 'mapping_type' => 'rel')); $config->setData($field_mapping)->save(); // Get the test file that simpletest provides. diff --git a/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php b/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php index 45488bd..dd67950 100644 --- a/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php +++ b/core/modules/rdf/lib/Drupal/rdf/Tests/TrackerAttributesTest.php @@ -36,6 +36,54 @@ function setUp() { // Creates article content type. $this->drupalCreateContentType(array('type' => 'article', 'name' => t('Article'))); + // Set bundle RDF mapping config for article. + $rdf_mapping_manager = drupal_container()->get('rdf.mapping_manager'); + $config = $rdf_mapping_manager->getBundleMappingConfig('node', 'article'); + $bundle_mapping = array_merge($config->get(), array('types' => array('foaf:Document', 'sioc:Item'))); + $config->setData($bundle_mapping)->save(); + + // Set fields RDF mapping config for article. + $node_shared_field_mappings = array( + 'title' => array( + 'properties' => array('dc:title'), + ), + 'created' => array( + 'properties' => array('dc:date', 'dc:created'), + 'datatype' => 'xsd:dateTime', + 'datatype_callback' => 'date_iso8601', + ), + 'changed' => array( + 'properties' => array('dc:modified'), + 'datatype' => 'xsd:dateTime', + 'datatype_callback' => 'date_iso8601', + ), + 'body' => array( + 'properties' => array('content:encoded'), + ), + 'uid' => array( + 'properties' => array('sioc:has_creator'), + 'mapping_type' => 'rel', + ), + 'name' => array( + 'properties' => array('foaf:name'), + ), + 'comment_count' => array( + 'properties' => array('sioc:num_replies'), + 'datatype' => 'xsd:integer', + ), + 'last_activity' => array( + 'properties' => array('sioc:last_activity_date'), + 'datatype' => 'xsd:dateTime', + 'datatype_callback' => 'date_iso8601', + ), + ); + // Iterate over field mappings and save. + foreach ($node_shared_field_mappings as $field_name => $field_mapping) { + $config = $rdf_mapping_manager->getFieldMappingConfig('node', 'article', $field_name); + $field_mapping = array_merge($config->get(), $field_mapping); + $config->setData($field_mapping)->save(); + } + // Enables anonymous posting of content. user_role_change_permissions(DRUPAL_ANONYMOUS_RID, array( 'create article content' => TRUE, diff --git a/core/modules/rdf/rdf.api.php b/core/modules/rdf/rdf.api.php index b3f95ba..a1a7c18 100644 --- a/core/modules/rdf/rdf.api.php +++ b/core/modules/rdf/rdf.api.php @@ -68,11 +68,11 @@ function hook_rdf_mapping() { ), 'pid' => array( 'predicates' => array('sioc:reply_of'), - 'type' => 'rel', + 'mapping_type' => 'rel', ), 'uid' => array( 'predicates' => array('sioc:has_creator'), - 'type' => 'rel', + 'mapping_type' => 'rel', ), 'name' => array( 'predicates' => array('foaf:name'), diff --git a/core/modules/rdf/rdf.module b/core/modules/rdf/rdf.module index 3e4bf08..f149123 100644 --- a/core/modules/rdf/rdf.module +++ b/core/modules/rdf/rdf.module @@ -43,23 +43,23 @@ function rdf_help($path, $arg) { * 'type' => 'node', * 'bundle' => RDF_DEFAULT_BUNDLE, * 'mapping' => array( - * 'rdftype' => array('sioc:Item', 'foaf:Document'), + * 'types' => array('sioc:Item', 'foaf:Document'), * 'title' => array( - * 'predicates' => array('dc:title'), + * 'properties' => array('dc:title'), * ), * 'created' => array( - * 'predicates' => array('dc:date', 'dc:created'), + * 'properties' => array('dc:date', 'dc:created'), * 'datatype' => 'xsd:dateTime', - * 'callback' => 'date_iso8601', + * 'datatype_callback' => 'date_iso8601', * ), * 'body' => array( - * 'predicates' => array('content:encoded'), + * 'properties' => array('content:encoded'), * ), * 'uid' => array( - * 'predicates' => array('sioc:has_creator'), + * 'properties' => array('sioc:has_creator'), * ), * 'name' => array( - * 'predicates' => array('foaf:name'), + * 'properties' => array('foaf:name'), * ), * ), * ); @@ -103,37 +103,6 @@ function rdf_get_namespaces() { } /** - * Returns the mapping for attributes of a given entity type/bundle pair. - * - * @param $type - * An entity type. - * @param $bundle - * A bundle name. - * - * @return - * The mapping corresponding to the requested entity type/bundle pair or an - * empty array. - */ -function rdf_mapping_load($type, $bundle) { - $mapping_manager = drupal_container()->get('rdf.mapping_manager'); - $mapping = array( - 'rdftypes' => $mapping_manager->getBundleMapping($type, $bundle), - ); - $entity = entity_create($type, array('type' => $bundle)); - - $properties = $entity->getPropertyDefinitions(); - if (!empty($properties)) { - foreach ($properties as $field_name => $field_info) { - $field_mapping = $mapping_manager->getFieldMapping($type, $bundle, $field_name); - if (!empty($field_mapping)) { - $mapping[$field_name] = $field_mapping; - } - } - } - return $mapping; -} - -/** * @} End of "defgroup rdf". */ @@ -151,13 +120,13 @@ function rdf_mapping_load($type, $bundle) { * field-specific $item_attributes variables. * * @param $mapping - * An array containing a mandatory 'predicates' key and optional 'datatype', - * 'callback' and 'type' keys. For example: + * An array containing a mandatory 'properties' key and optional 'datatype', + * 'datatype_callback' and 'type' keys. For example: * @code * array( - * 'predicates' => array('dc:created'), + * 'properties' => array('dc:created'), * 'datatype' => 'xsd:dateTime', - * 'callback' => 'date_iso8601', + * 'datatype_callback' => 'date_iso8601', * ), * ); * @endcode @@ -172,7 +141,7 @@ function rdf_mapping_load($type, $bundle) { */ function rdf_rdfa_attributes($mapping, $data = NULL) { // The type of mapping defaults to 'property'. - $type = isset($mapping['type']) ? $mapping['type'] : 'property'; + $type = isset($mapping['mapping_type']) ? $mapping['mapping_type'] : 'property'; switch ($type) { // The mapping expresses the relationship between two resources. @@ -186,8 +155,8 @@ function rdf_rdfa_attributes($mapping, $data = NULL) { case 'property': $attributes['property'] = $mapping['properties']; // Convert $data to a specific format as per the callback function. - if (isset($data) && isset($mapping['callback'])) { - $callback = $mapping['callback']; + if (isset($data) && isset($mapping['datatype_callback'])) { + $callback = $mapping['datatype_callback']; $attributes['content'] = $callback($data); } if (isset($mapping['datatype'])) { @@ -204,6 +173,26 @@ function rdf_rdfa_attributes($mapping, $data = NULL) { */ /** + * Implements hook_comment_load(). + * + * @todo refactor to take advantage of the new Drupal 8 APIs. + */ +function rdf_comment_load($comments) { + foreach ($comments as $comment) { + // Pages with many comments can show poor performance. This information + // isn't needed until rdf_preprocess_comment() is called, but set it here + // to optimize performance for websites that implement an entity cache. + $mapping_manager = drupal_container()->get('rdf.mapping_manager'); + $created_mapping = $mapping_manager->getFieldMapping('comment', $comment->bundle(), 'created'); + $comment->rdf_data['date'] = rdf_rdfa_attributes($created_mapping, $comment->created->value); + $comment->rdf_data['nid_uri'] = url('node/' . $comment->nid->target_id); + if ($comment->pid->target_id) { + $comment->rdf_data['pid_uri'] = url('comment/' . $comment->pid->target_id, array('fragment' => 'comment-' . $comment->pid->target_id)); + } + } +} + +/** * Implements hook_theme(). */ function rdf_theme() { @@ -281,7 +270,7 @@ function rdf_preprocess_node(&$variables) { $mapping_manager = drupal_container()->get('rdf.mapping_manager'); $bundle_mapping = $mapping_manager->getBundleMapping('node', $variables['type']); $variables['attributes']['about'] = empty($variables['node_url']) ? NULL: $variables['node_url']; - $variables['attributes']['typeof'] = empty($bundle_mapping['rdftype']) ? NULL : $bundle_mapping['rdftype']; + $variables['attributes']['typeof'] = empty($bundle_mapping['types']) ? NULL : $bundle_mapping['types']; // Adds RDFa markup to the title of the node. Because the RDFa markup is // added to the