diff sites/all/modules/rdfx/rdfx.terms.inc @ 4:ce11bbd8f642

added modules
author danieleb <danielebarchiesi@me.com>
date Thu, 19 Sep 2013 10:38:44 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/sites/all/modules/rdfx/rdfx.terms.inc	Thu Sep 19 10:38:44 2013 +0100
@@ -0,0 +1,622 @@
+<?php
+
+/**
+ * @file
+ * Functions for managing RDF Terms.
+ */
+
+function rdfx_get_properties() {
+  $property_tids = _rdfx_get_terms('property');
+  return $property_tids;
+}
+
+function rdfx_get_classes() {
+  $class_tids = _rdfx_get_terms('class');
+  return $class_tids;
+}
+
+function _rdfx_get_terms($term_type) {
+  $term_types = rdfx_term_types();
+  switch ($term_type) {
+    case 'property':
+      $types = array_keys($term_types['properties']['term_types']);
+      break;
+    case 'class':
+      $types = array_keys($term_types['classes']['term_types']);
+      break;
+    default:
+      $types = array_merge(array_keys($term_types['properties']['term_types']), array_keys($term_types['classes']['term_types']));
+  }
+  $query = db_select('rdfx_term_types', 'rdftt')
+    ->fields('rdft', array('tid'))
+    ->condition('rdftt.type', $types, 'IN');
+  $query->join('rdfx_terms', 'rdft', 'rdftt.tid = rdft.tid');
+  $query->join('rdfx_namespaces', 'rdfns', 'rdfns.nsid = rdft.nsid');
+  $query->join('rdfx_vocabulary_graphs', 'rdfvg', 'rdfvg.main_ns = rdfns.nsid');
+  $terms = $query->execute()->fetchCol();
+  return $terms;
+}
+
+/**
+ * Gets a list of all defined namespaces.
+ */
+function rdfx_get_namespaces() {
+  $rdf_namespaces = &drupal_static(__FUNCTION__);
+  if (empty($rdf_namespaces)) {
+    $rdf_namespaces = rdf_get_namespaces();
+  }
+  return $rdf_namespaces;
+}
+
+/**
+ * Implements hook_rdf_namespaces.
+ */
+function rdfx_rdf_namespaces() {
+  // Starts with some additionnal common namespaces which core does not include.
+  $ns_mappings = array(
+    'owl'      => 'http://www.w3.org/2002/07/owl#',
+    'rdf'      => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#',
+    'rss'      => 'http://purl.org/rss/1.0/',
+    // url() does not support empty fragment.
+    'site'     => url('ns', array('absolute' => TRUE)) . '#',
+  );
+
+  // Gets the custom namespaces stored in the database.
+  $query = db_select('rdfx_vocabulary_graphs', 'g');
+  $query->fields('n', array('prefix', 'uri'));
+  $query->join('rdfx_namespaces', 'n', 'g.main_ns = n.nsid');
+  $query->orderBy('n.prefix');
+  $namespaces = $query->execute()->fetchAllKeyed();
+  foreach ($namespaces as $prefix => $uri) {
+    $ns_mappings[$prefix] = $uri;
+  }
+
+  return $ns_mappings;
+}
+
+/**
+ * Saves the main namespace mapping for a vocabulary graph and the additional
+ * namespace mappings as defined in the document.
+ */
+function _rdfx_save_vocabulary($main_ns, $main_ns_prefix, $vocabulary) {
+  $current_time = REQUEST_TIME;
+  // If the vocabulary URI matches the main_ns of a vocabulary source, then
+  // this is an update to that record. Otherwise, this is a newly imported
+  // source.
+  $gid = rdfx_get_gid($main_ns);
+
+  // If there is an existing vocabulary, make sure that the main_ns is in the
+  // namespaces array and that the user defined mapping is the last in the
+  // array so the prefix reflects the user definition. Also change the
+  // vocabulary graph updated date.
+  if ($gid) {
+    $vocabulary['namespaces'][$main_ns_prefix] = $main_ns;
+    db_update('rdfx_vocabulary_graphs')
+      ->fields(array('date_updated' => $current_time,))
+      ->execute();
+  }
+
+  // If this is a new vocabulary, create a graph with a main namespace and
+  // add the additional namespaces.
+  else {
+    // @todo If the vocab URI isn't used in any terms, don't add it to ns table.
+    // This may happen where multiple files are defining a vocabulary.
+
+    // @todo This should be handled as a transaction in case there is an error
+    // in the middle. If there is an error, then there will be an SQL error
+    // when the user retries the import.
+
+    // Insert this namespace to get the nsid. The vocabulary_source entry will
+    // point to this nsid for the main_ns. We temporarily insert 0 for the gid,
+    // then update when we have the real gid.
+    $nsid = db_insert('rdfx_namespaces')
+      ->fields(array('uri' => $main_ns, 'prefix' => $main_ns_prefix, 'gid' => '0'))
+      ->execute();
+    $gid = db_insert('rdfx_vocabulary_graphs')
+      ->fields(array(
+          'main_ns' => $nsid,
+          'date_created' => $current_time,
+          'date_updated' => $current_time,))
+      ->execute();
+    db_update('rdfx_namespaces')
+      ->condition('nsid', $nsid)
+      ->fields(array('gid' => $gid))
+      ->execute();
+  }
+  // Insert/update the vocabulary title.
+  if (count($vocabulary['title']) > 0) {
+    foreach ($vocabulary['title'] as $langcode => $title) {
+      $query = db_merge('rdfx_vocabulary_details')
+        ->key(array('gid' => $gid, 'language' => $langcode))
+        ->fields(array('language' => $langcode, 'label' => $title));
+      $status = $query->execute();
+    }
+  }
+
+  // Insert/update the vocabulary description.
+  if (count($vocabulary['description']) > 0) {
+    foreach ($vocabulary['description'] as $langcode => $description) {
+      $query = db_merge('rdfx_vocabulary_details')
+        ->key(array('gid' => $gid, 'language' => $langcode))
+        ->fields(array('language' => $langcode, 'description' => $description));
+      $status = $query->execute();
+    }
+  }
+
+  // Insert/update the other namespace mappings used in this vocabulary graph.
+  if (count($vocabulary['namespaces']) > 0) {
+    foreach ($vocabulary['namespaces'] as $prefix => $namespace) {
+      if ($namespace != $main_ns) {
+        $query = db_merge('rdfx_namespaces')
+          ->key(array('gid' => $gid, 'uri' => $namespace))
+          ->fields(array('uri' => $namespace, 'prefix' => $prefix, 'gid' => $gid))
+          ->updateFields(array('prefix' => $prefix));
+        $status = $query->execute();
+      }
+    }
+  }
+
+  $nsids = rdfx_get_nsids($main_ns);
+  return $nsids;
+}
+
+/**
+ * Saves vocabulary terms.
+ */
+function rdfx_save_terms($vocabulary_uri, $prefix, $vocabulary) {
+  $nsids = _rdfx_save_vocabulary($vocabulary_uri, $prefix, $vocabulary);
+  foreach ($vocabulary['terms'] as $term_type => $terms) {
+    foreach ($terms as $term_uri => $term_description) {
+      list($term_ns, $term_local_name) = rdfx_split_uri($term_uri);
+      if (isset($nsids[$term_ns])) {
+        $nsid = $nsids[$term_ns];
+      }
+      else {
+        // If the namespace wasn't mapped to a prefix in the source graph, we
+        // didn't save it to the namespaces table, so we need to add an entry.
+
+        // @todo For the prefix value, we save the URI... should this be changed?
+        $gid = rdfx_get_gid($vocabulary_uri);
+        $nsid = db_insert('rdfx_namespaces')
+          ->fields(array('uri' => $term_ns, 'prefix' => $term_ns, 'gid' => $gid))
+          ->execute();
+        $nsids[$term_ns] = $nsid;
+      }
+
+      // Get the tid of this term, saving to {rdfx_terms} if not already there.
+      $tid = db_query("SELECT tid FROM {rdfx_terms} WHERE nsid = :nsid AND local_name = :localname", array(':nsid' => $nsid, ':localname' => $term_local_name))->fetchField();
+      if ($tid == NULL) {
+        $tid = db_insert('rdfx_terms')
+          ->fields(array('nsid', 'local_name'))
+          ->values(array(
+            'nsid' => $nsid,
+            'local_name' => $term_local_name,
+          ))
+          ->execute();
+      }
+
+      // Add the current type to this term in {rdfx_term_types}.
+      db_merge('rdfx_term_types')
+        ->key(array('tid' => $tid, 'type' => $term_type))
+        ->fields(array(
+            'tid' => $tid,
+            'type' => $term_type,
+        ))
+        ->execute();
+
+      // Add label and comment to {rdfx_term_details}.
+      $term_details = array();
+      if (isset($term_description['label'])) {
+        foreach ($term_description['label'] as $lang => $text) {
+          $term_details[$lang]['label'] = $text;
+        }
+      }
+      if (isset($term_description['comment'])) {
+        foreach ($term_description['comment'] as $lang => $text) {
+          $term_details[$lang]['comment'] = $text;
+        }
+      }
+      if (!empty($term_details)) {
+        foreach ($term_details as $lang => $details) {
+          db_merge('rdfx_term_details')
+            ->key(array('tid' => $tid, 'language' => $lang))
+            ->fields(array(
+                'tid' => $tid,
+                'language' => $lang,
+                'label' => isset($details['label']) ? $details['label'] : NULL,
+                'comment' => isset($details['comment']) ? $details['comment'] :  NULL,
+            ))
+            ->execute();
+        }
+      }
+
+      // Add relationships to their respective tables. This is handled as a
+      // complicated set of loops to reduce code duplication. To add a new
+      // relationship, just add the array key that is used in
+      // $types['properties']['description'] to define the relationship, and
+      // then add the name of the table that stores the relationship.
+      $relationships = array(
+        'domain' => 'rdfx_term_domains',
+        'range' => 'rdfx_term_ranges',
+      );
+      foreach ($relationships as $relationship => $table_name) {
+        if (isset($term_description[$relationship])) {
+          foreach ($term_description[$relationship] as $related_term) {
+            $related_term_tid = rdfx_get_tid($related_term, $vocabulary_uri);
+            if ($related_term_tid) {
+              db_merge($table_name)
+                ->key(array('tid' => $tid, $relationship . '_tid' => $related_term_tid))
+                ->fields(array(
+                    'tid' => $tid,
+                    $relationship . '_tid' => $related_term_tid,
+                ))
+                ->execute();
+            }
+          }
+        }
+      }
+    }
+  }
+  // @todo Add a hook that passes the $vocabulary and the $model.
+}
+
+/**
+ * Returns metadata about term types defined by rdf modules.
+ *
+ * If your module needs to determine what term types are being supplied by
+ * other modules, call this function. Querying rdfx database tables directly
+ * for this information is discouraged. Any additional term types should be
+ * added through the corresponding alter hook.
+ *
+ * Three major bins of data are stored: tags, value_types, and functions. Each
+ * entry in these bins is keyed by the value stored in the actual VotingAPI
+ * tables, and contains an array with (minimally) 'name' and 'description' keys.
+ * Modules can add extra keys to their entries if desired.
+ *
+ * This metadata can be modified or expanded using hook_rdfx_term_types_alter().
+ *
+ * @return
+ *   An array of metadata defined by RDFx Terms and altered by rdf modules.
+ *
+ * @see hook_rdfx_term_types_alter()
+ *
+ * Modeled on VotingAPI votingapi_metadata.
+ */
+function rdfx_term_types($reset = FALSE) {
+  static $types;
+  if ($reset || !isset($types)) {
+    $types['classes']['term_types'] = array();
+    $types['properties']['term_types'] = array();
+
+    $term_details = '';
+
+    // @todo Should the inference consider subProp and subClass relationships
+    // as well. ie. should all OWL classes also have the type RDFS Class
+
+    // @todo Switch to drupal cache
+    $types['classes']['term_types'] = array(
+      'rdfs_class' => array(
+        'uri' => 'http://www.w3.org/2000/01/rdf-schema#Class',
+        'inference' => array(
+          'http://www.w3.org/2000/01/rdf-schema#subClassOf' => array(
+            'subject',
+            'object',
+          ),
+          'http://www.w3.org/2000/01/rdf-schema#domain' => array(
+            'object',
+          ),
+          'http://www.w3.org/2000/01/rdf-schema#range' => array(
+            'object',
+          ),
+        ),
+      ),
+      'owl_class' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#Class',
+        'inference' => array(
+          'http://www.w3.org/2002/07/owl#equivalentClass' => array(
+            'subject',
+            'object',
+          ),
+          'http://www.w3.org/2002/07/owl#disjointWith' => array(
+            'subject',
+            'object',
+          ),
+        ),
+      ),
+    );
+
+    $types['properties']['term_types'] = array (
+      'rdf_property' => array(
+        'uri' => 'http://www.w3.org/1999/02/22-rdf-syntax-ns#Property',
+        'inference' => array(
+          'http://www.w3.org/2000/01/rdf-schema#domain' => array(
+            'subject',
+          ),
+          'http://www.w3.org/2000/01/rdf-schema#range' => array(
+            'subject',
+          ),
+          'http://www.w3.org/2000/01/rdf-schema#subPropertyOf' => array(
+            'subject',
+            'object',
+          ),
+          'http://www.w3.org/2002/07/owl#equivalentProperty' => array(
+            'subject',
+            'object',
+          ),
+          'http://www.w3.org/2002/07/owl#inverseOf' => array(
+            'subject',
+            'object',
+          ),
+        ),
+      ),
+      'owl_property_datatype' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#DatatypeProperty',
+        'inference' => array(
+        ),
+      ),
+      'owl_property_object' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#ObjectProperty',
+        'inference' => array(
+        ),
+      ),
+      'owl_property_functional' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#FunctionalProperty',
+        'inference' => array(
+        ),
+      ),
+      'owl_property_inverse_functional' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#InverseFunctionalProperty',
+        'inference' => array(
+        ),
+      ),
+      'owl_property_symmetric' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#SymmetricProperty',
+        'inference' => array(
+        ),
+      ),
+      'owl_property_asymmetric' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#AsymmetricProperty',
+        'inference' => array(
+        ),
+      ),
+      'owl_property_annotation' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#AnnotationProperty',
+        'inference' => array(
+        ),
+      ),
+      'owl_property_reflexive' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#ReflexiveProperty',
+        'inference' => array(
+        ),
+      ),
+      'owl_property_irreflexive' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#IrreflexiveProperty',
+        'inference' => array(
+        ),
+      ),
+      'owl_property_transitive' => array(
+        'uri' => 'http://www.w3.org/2002/07/owl#TransitiveProperty',
+        'inference' => array(
+        ),
+      ),
+    );
+
+    $types['classes']['description'] = array(
+      'superclass' => array(
+        'http://www.w3.org/2000/01/rdf-schema#subClassOf' => array(
+          'object',
+        ),
+      ),
+      'disjoint' => array(
+        'http://www.w3.org/2002/07/owl#disjointWith' => array(
+          'object',
+        ),
+      ),
+    );
+
+    $types['properties']['description'] = array(
+      'domain' => array(
+        'http://www.w3.org/2000/01/rdf-schema#domain' => array(
+          'object',
+        ),
+      ),
+      'range' => array(
+        'http://www.w3.org/2000/01/rdf-schema#range' => array(
+          'object',
+        ),
+      ),
+      'superproperty' => array(
+        'http://www.w3.org/2000/01/rdf-schema#subPropertyOf' => array(
+          'object',
+        ),
+      ),
+      'inverse' => array(
+        'http://www.w3.org/2002/07/owl#inverseOf' => array(
+          'object',
+        ),
+      ),
+    );
+    drupal_alter('rdfx_term_types', $types);
+  }
+
+  return $types;
+}
+
+/**
+ * Splits a URI into namespace and localpart.
+ */
+function rdfx_split_uri ($uri) {
+  $parts = ARC2::splitURI($uri);
+  return $parts;
+}
+
+function rdfx_get_tid($term_uri, $graph_main_ns) {
+  $nsids = rdfx_get_nsids($graph_main_ns);
+  list($term_ns, $term_local_name) = rdfx_split_uri($term_uri);
+  if (isset($nsids[$term_ns])) {
+    $tid = db_query("SELECT tid FROM {rdfx_terms} WHERE nsid = :nsid AND local_name = :localname", array(':nsid' => $nsids[$term_ns], ':localname' => $term_local_name))->fetchField();
+    return $tid;
+  }
+  else {
+    return NULL;
+  }
+}
+
+function rdfx_get_gid($main_ns) {
+  $gids = db_select('rdfx_namespaces', 'rdfns', array());
+  $gids->join('rdfx_vocabulary_graphs', 'rdfvg', 'rdfvg.main_ns = rdfns.nsid');
+  $gids
+    ->fields('rdfns', array('gid'))
+    ->condition('rdfns.uri', $main_ns);
+  // @todo There should only be one result if there is a matching vocab source.
+  // However, perhaps we should test to make sure and throw an error?
+  $gid = $gids->execute()->fetchField();
+  return $gid;
+}
+
+function rdfx_get_nsids($main_ns) {
+  $gid = rdfx_get_gid($main_ns);
+  $nsids = db_query("SELECT uri, nsid FROM {rdfx_namespaces} WHERE gid = :gid", array(':gid' => $gid))->fetchAllKeyed();
+  return $nsids;
+}
+
+function rdfx_curie($tid) {
+  $query = db_select('rdfx_terms', 'rdft')
+    ->fields('rdft', array('local_name'))
+    ->fields('rdfns', array('prefix'))
+    ->condition('rdft.tid', $tid, '=');
+  $query->join('rdfx_namespaces', 'rdfns', 'rdfns.nsid = rdft.nsid');
+  $result = $query->execute()->fetch();
+  $curie = $result->prefix . ':' . $result->local_name;
+  return $curie;
+}
+
+function _rdfx_get_term_details($tid, $langcode = 'und') {
+  $query_language = db_query("SELECT language FROM {rdfx_term_details} WHERE tid = :tid", array(':tid' => $tid));
+  $languages = $query_language->fetchCol();
+  if (!in_array($langcode, $languages)) {
+    if (in_array('und', $languages)) {
+      $langcode = 'und';
+    }
+    elseif (in_array('en', $languages)) {
+      $langcode = 'en';
+    }
+    else {
+      return;
+    }
+  }
+  $query = db_select('rdfx_term_details', 'rdfd')
+    ->fields('rdfd', array('label', 'comment'))
+    ->condition('rdfd.tid', $tid, '=')
+    ->condition('language', $langcode, '=');
+  $details = $query->execute()->fetch();
+  return $details;
+}
+
+/**
+ * Queries a set of triples for classes and properties, and builds
+ * an associative array describing the vocabulary and any
+ * classes and properties found.
+ *
+ * @param array $model An ARC2-style array of triples an RDFS vocabulary or OWL ontology
+ * @param array $namespaces Associative array of namespaces parsed from the RDF file
+ * @param string $ns_prefix Namespace prefix for the vocabulary
+ * @param string $ns_uri Only terms in this namespace will be considered
+ * @return array Array describing the vocabulary, its classes and properties.
+ */
+function _rdfx_extract_schema(&$model, $namespaces, $ns_prefix, $ns_uri) {
+  $vocabulary_details = _rdfx_get_vocabulary_details($model, $ns_uri);
+  $terms = _rdfx_fetch_terms($model);
+  $vocabulary = array(
+      'uri' => $ns_uri,
+      'title' => $vocabulary_details['title'],
+      'description' => $vocabulary_details['description'],
+      'terms' => $terms,
+      'namespaces' => $namespaces,
+  );
+  return $vocabulary;
+}
+
+function _rdfx_fetch_terms(&$model) {
+  $terms = array();
+  $term_uris = array();
+
+  // Retrieve the queries for term retrieval. This may have been modified by
+  // other modules.
+  $term_type_groups = rdfx_term_types();
+
+  foreach($term_type_groups as $term_type_group => $group) {
+    foreach ($group['term_types'] as $term_type => $term) {
+      $query = array(
+        array('?', 'http://www.w3.org/1999/02/22-rdf-syntax-ns#type', $term['uri']),
+      );
+      foreach ($term['inference'] as $inference_uri => $query_types) {
+        foreach ($query_types as $query_type) {
+          switch ($query_type) {
+            case 'subject':
+              $query[] = array('?', $inference_uri, null);
+              break;
+            case 'object':
+              $query[] = array(null, $inference_uri, '?');
+              break;
+          }
+        }
+      }
+      $term_uris[$term_type] = _rdfx_query_find_uris($model, $query);
+
+      // Add term details and various relationships for each term, as defined
+      // in rdfx_term_types() and altered by hook_rdfx_term_types_alter().
+      $query_x = array();
+      foreach ($term_uris[$term_type] as $term_uri) {
+
+        $terms[$term_type][$term_uri] = _evoc_query_for_term_description($model, $term_uri);
+        foreach ($group['description'] as $property => $queries) {
+          foreach ($queries as $predicate_uri => $query_types) {
+            foreach ($query_types as $query_type) {
+              switch ($query_type) {
+                case 'subject':
+                  $query_x[$term_uri][$property][] = array('?', $predicate_uri, $term_uri);
+                  break;
+                case 'object':
+                  $query_x[$term_uri][$property][] = array($term_uri, $predicate_uri, '?');
+                  break;
+              }
+            }
+          }
+          $terms[$term_type][$term_uri][$property] = _rdfx_query_find_uris($model, $query_x[$term_uri][$property]);
+        }
+      }
+    }
+  }
+  return $terms;
+}
+
+function _rdfx_get_vocabulary_details(&$model, $ns_uri) {
+  $query_predicates = array(
+    'title' => array(
+      'http://www.w3.org/2000/01/rdf-schema#label',
+      'http://purl.org/dc/elements/1.1/title',
+      'http://purl.org/dc/terms/title',
+    ),
+    'description' => array(
+      'http://www.w3.org/2000/01/rdf-schema#comment',
+      'http://purl.org/dc/elements/1.1/description',
+      'http://purl.org/dc/terms/description',
+    ),
+  );
+
+  if (substr($ns_uri, -1) == '#') {
+    $uri = substr($ns_uri, 0, -1);
+  }
+
+  foreach ($query_predicates as $query_element => $predicates) {
+    foreach ($predicates as $predicate) {
+      $queries[$query_element][] = array($ns_uri, $predicate, '?');
+//       if ($uri !== NULL) {
+//         $queries[$query_element][] = array($uri, $predicate, '?');
+//       }
+    }
+    $details[$query_element] = _rdfx_query_find_literal($model, $queries[$query_element]);
+  }
+  return $details;
+}