Sfoglia il codice sorgente

Adjustments to web services to support local formatters

Stephen Ficklin 7 anni fa
parent
commit
85d701158c

+ 1 - 0
tripal/includes/TripalFields/TripalFieldFormatter.inc

@@ -53,6 +53,7 @@ class TripalFieldFormatter {
       'label' => $class::$default_label,
       'field types' => $class::$field_types,
       'settings' => $class::$default_settings,
+      'TripalFieldFormatter' => TRUE,
     );
   }
 

+ 78 - 7
tripal_ws/includes/TripalFields/remote__data/remote__data.inc

@@ -72,7 +72,7 @@ class remote__data extends WebServicesField {
         'remote_site' => '',
         'description' => '',
         'rd_field_name' => '',
-			),
+      ),
   );
   // A boolean specifying that users should not be allowed to create
   // fields and instances of this field type through the UI. Such
@@ -88,10 +88,25 @@ class remote__data extends WebServicesField {
   // Holds an object describing the remote site that tihs field connects to.
   private $remote_site = NULL;
 
+  // Set to TRUE if this field is being loaded via web services. WE don't
+  // want remote fields loaded when a web-service call is made.
+  private $loaded_via_ws = FALSE;
+
   public function __construct($field, $instance) {
     parent::__construct($field, $instance);
 
-    //Get the site url from the tripal_sites table.
+    // This field should not do anything if it is loaded via web-services.
+    // We don't want remote content to be available in web services.  There
+    // is an if statement to not show this field in the web services but the
+    // entity_load function doesn't know this field shouldn't be loaded so
+    // we need to short-circuit that.
+    if (preg_match('/^web-services/', $_SERVER['REQUEST_URI'])) {
+      dpm('hi');
+      $this->loaded_via_ws = TRUE;
+      return;
+    }
+
+    // Get the site url from the tripal_sites table.
     $site_id_ws = $this->instance['settings']['data_info']['remote_site'];
     $this->remote_site = db_select('tripal_sites', 'ts')
       ->fields('ts')
@@ -110,8 +125,16 @@ class remote__data extends WebServicesField {
     // Set some defaults for the empty record.
     $entity->{$field_name}['und'][0] = array(
       'value' => array(),
+      'remote_entity' => array(),
     );
 
+    // If this field is being loaded via web services then just return.
+    dpm($this->loaded_via_ws);
+    return;
+    if ($this->loaded_via_ws) {
+      return;
+    }
+
     // Get the query set by the admin for this field and replace any tokesn
     $query_str = $this->instance['settings']['data_info']['query'];
     $bundle = tripal_load_bundle_entity(array('name' => $entity->bundle));
@@ -120,7 +143,7 @@ class remote__data extends WebServicesField {
     // Make the request.
     $data = $this->makeRemoteRequest($query_str);
     if(!$data){
-     return;
+      return;
     }
 
     $total_items = $data['totalItems'];
@@ -156,11 +179,59 @@ class remote__data extends WebServicesField {
     }
    }
    /**
-	 *
-	 * @see TripalField::settingsForm()
+    * Makes a request to a remote Tripal web services site.
+    *
+    * @param $query
+    *   The query string. This string is added to the URL for the remote
+    *   website.
+    */
+   private function makeRemoteRequest($query) {
+
+     // Build the URL to the remote web services.
+     $ws_url = $this->remote_site->url;
+     $ws_url = trim($ws_url, '/');
+     $ws_url .= '/web-services/content/v0.1';
+
+     // Build the Query and make and substitions needed.
+     $query_url = $ws_url . '/' . $query;
+     $options = array('timeout' => 360);
+     $data = drupal_http_request($query_url, $options);
+
+     if (!$data) {
+       tripal_report_error('tripal_ws', TRIPAL_ERROR,
+           t('Could not connect to the remote web service.'));
+       return FALSE;
+     }
+
+     // If the data object has an error then this is some sort of
+     // connection error (not a Tripal web servcies error).
+     if (property_exists($data, 'error')) {
+       tripal_report_error('tripal_ws', TRIPAL_ERROR,
+           'Web Services error on remote site: %error.',
+           array('%error' => $data->error));
+       return FALSE;
+     }
+
+     // We got a response, so convert it to a PHP array.
+     $data = drupal_json_decode($data->data);
+
+     // Check if there was a Tripal Web Services error.
+     if (array_key_exists('error', $data)) {
+       $error = '</pre>' . print_r($data['error'], TRUE) . '</pre>';
+       tripal_report_error('tripal_ws', TRIPAL_ERROR,
+           'Web Services error on remote site: %error.',
+           array('%error' => $error));
+       return FALSE;
+     }
+
+     return $data;
+   }
+   /**
+   *
+   * @see TripalField::settingsForm()
    */
-	public function instanceSettingsForm() {
-		$element = parent::instanceSettingsForm();
+  public function instanceSettingsForm() {
+    $element = parent::instanceSettingsForm();
     // Get the setting for the option for how this widget.
     $instance = $this->instance;
     $settings = '';

+ 0 - 1
tripal_ws/includes/TripalFields/remote__data/remote__data_formatter.inc

@@ -93,7 +93,6 @@ class remote__data_formatter extends WebServicesFieldFormatter {
       $content = t('There is no data about this record from the !site database.',
           array('!site' => l($site->name, $site->url)));
     }
-    dpm($items);
     foreach ($items as $index => $item) {
       $value = $item['value'];
       if (is_array($value)) {

+ 108 - 0
tripal_ws/includes/TripalWebService.inc

@@ -266,4 +266,112 @@ class TripalWebService {
      $supported_classes = array();
      return $supported_classes;
   }
+
+  /**
+   * Adds a term to the '@context' section for a given resource.
+   *
+   * @param $resource
+   *   A TripalWebServiceResource instance.
+   * @param $term
+   *   The term array.
+   * @return $key
+   *   The key (the term name but with spaces replaced with underscores).
+   */
+  public function addContextTerm($resource, $term) {
+    if (!is_a($resource, 'TripalWebServiceResource')) {
+      throw new Exception('addContextTerm: Please provide a $resource of type TripalWebServiceResource.');
+    }
+
+    // Make sure the vocab is present
+    $vocab = $term['vocabulary'];
+    $this->addContextVocab($resource, $vocab);
+
+    // Sanitize the term key
+    $key = $term['name'];
+    $key_adj = strtolower(preg_replace('/ /', '_', $term['name']));
+
+    // Create the compact IRI
+    $compact_iri = $vocab['short_name'] . ':' . $term['accession'];
+
+    // If the full naming is indicated in the service parameters then
+    // set the full name of the keys to include the vocab short name.
+    if (array_key_exists('full_keys', $this->params)) {
+      $key_adj = $vocab['short_name'] . ':' . $key_adj;
+    }
+
+    $iri = $term['url'];
+
+    $resource->addContextItem($key_adj, $compact_iri);
+    $resource->addContextItem($compact_iri, $iri);
+
+    return $key_adj;
+  }
+
+  /**
+   * Adds a vocabulary to the '@context' section for a given resource.
+   *
+   * @param $resource
+   *   A TripalWebServiceResource instance.
+   * @param $vocab
+   *   The vocabulary array.
+   */
+  public function addContextVocab($resource, $vocab) {
+
+    if (!is_a($resource, 'TripalWebServiceResource')) {
+      throw new Exception('addContextVocab: Please provide a $resource of type TripalWebServiceResource.');
+    }
+
+    $key = $vocab['short_name'];
+    // The URL here should be the URL prefix not the database home
+    // page.  But unfortunately, the URL prefix can't be guaranteed to be
+    // a true prefix. Not all databases place by the rules.  For this reason,
+    // we can never use JSON-LD compact IRIs. :-(
+    $iri = $vocab['url'];
+    $resource->addContextItem($key, $iri);
+  }
+
+  /**
+   * Adds a key/value property to the given resource.
+   *
+   * @param $resource
+   *   A TripalWebServiceResource instance.
+   * @param $term
+   *   The term array for the key.
+   * @param $value
+   *   The value to add.
+   *
+   * @return $key
+   *   The key (the term name but with spaces replaced with underscores).
+   */
+  public function addResourceProperty($resource, $term, $value) {
+    if (!is_a($resource, 'TripalWebServiceResource')) {
+      throw new Exception('addProperty: Please provide a $resource of type TripalWebServiceResource.');
+    }
+    // First add the term
+    $key = $this->addContextTerm($resource, $term);
+
+    // Then add the property.
+    $resource->addProperty($key, $value);
+  }
+  /**
+   * Sets the type for the given resource.
+   *
+   * The type exist in the context of the web service.
+   *
+   * @param $resource
+   *   A TripalWebServiceResource instance.
+   * @param $type
+   *   The type
+   */
+  public function setResourceType($resource, $term) {
+
+    if (!is_a($resource, 'TripalWebServiceResource')) {
+      throw new Exception('addProperty: Please provide a $resource of type TripalWebServiceResource.');
+    }
+    // First add the term
+    $key = $this->addContextTerm($resource, $term);
+
+    // Then set the type
+    $resource->setType($key);
+  }
 }

+ 46 - 57
tripal_ws/includes/TripalWebService/TripalEntityService_v0_1.inc

@@ -71,6 +71,9 @@ class TripalEntityService_v0_1 extends TripalWebService {
     $term = reset($term);
     $vocab = $term->vocab;
 
+    // Convert the term to a simple array
+    $term = tripal_get_term_details($term->vocab->vocabulary, $term->accession);
+
     // Get the TripalEntity
     $entity = tripal_load_entity('TripalEntity', array('id' => $entity_id));
     $entity = reset($entity);
@@ -87,17 +90,14 @@ class TripalEntityService_v0_1 extends TripalWebService {
     list($field, $instance, $term) = $this->findField($bundle, $expfield);
 
     // Next add in the ID and Type for this resources.
-    $key = $term['name'];
-    $key_adj = strtolower(preg_replace('/ /', '_', $term['name']));
-    $this->resource->addContextItem($key_adj, $term['url']);
-    $this->resource->setID(urlencode($key));
-    $this->resource->setType($key_adj);
+    $this->setResourceType($this->resource, $term);
+    $this->resource->setID(urlencode($term['name']));
 
     // Attach the field and then add it's values to the response.
     field_attach_load($entity->type, array($entity->id => $entity),
         FIELD_LOAD_CURRENT, array('field_id' => $field['id']));
 
-    $this->addEntityField($key_adj, $term, $entity, $bundle, $field, $instance, $service_path, $expfield);
+    $this->addEntityField($term, $entity, $bundle, $field, $instance, $service_path, $expfield);
   }
 
   /**
@@ -130,10 +130,12 @@ class TripalEntityService_v0_1 extends TripalWebService {
     $bundle = tripal_load_bundle_entity(array('label' => $ctype));
     $term = entity_load('TripalTerm', array('id' => $bundle->term_id));
     $term = reset($term);
-    $vocab = $term->vocab;
+
+    // Convert the $term to a simple array
+    $term = tripal_get_term_details($term->vocab->vocabulary, $term->accession);
 
     // Add the vocabulary to the context.
-    $this->resource->addContextItem($term->name, $term->url);
+    $this->resource->addContextItem($term['name'], $term['url']);
 
     // Get the TripalEntity.
     $entity = tripal_load_entity('TripalEntity', array('id' => $entity_id));
@@ -151,16 +153,12 @@ class TripalEntityService_v0_1 extends TripalWebService {
     $itemPage = tripal_get_term_details('schema', 'ItemPage');
     $label = tripal_get_term_details('rdfs', 'label');
     $this->resource->setID($entity_id);
-    $this->resource->setType($term->name);
-    $this->resource->addContextItem('label', $label['url']);
-    $this->resource->addContextItem('ItemPage', $itemPage['url']);
-    $this->resource->addProperty('label', $entity->title);
-    $this->resource->addProperty('ItemPage', url('/bio_data/' . $entity->id, array('absolute' => TRUE)));
+    $this->setResourceType($this->resource, $term);
+    $this->addResourceProperty($this->resource, $label, $entity->title);
+    $this->addResourceProperty($this->resource, $itemPage, url('/bio_data/' . $entity->id, array('absolute' => TRUE)));
 
+    // Add in the entitie's fields.
     $this->addEntityFields($entity, $bundle, $term, $service_path);
-
-//    tripal_ws_services_v0_1_get_content_add_fields($entity, $bundle, $api_url, $response, $ws_path, $ctype, $entity_id, $params);
-//    tripal_ws_services_v0_1_write_context($response, $ctype);
   }
 
   /**
@@ -237,8 +235,6 @@ class TripalEntityService_v0_1 extends TripalWebService {
       if (!$term) {
         continue;
       }
-      $key = $term['name'];
-      $key_adj = strtolower(preg_replace('/ /', '_', $key));
 
       // If this field should not be attached by default then just add a link
       // so that the caller can get the information separately.
@@ -250,27 +246,25 @@ class TripalEntityService_v0_1 extends TripalWebService {
         // that information.
         $items = field_get_items('TripalEntity', $entity, $field_name);
         if ($items and count($items) > 0 and $items[0]['value']) {
-          $this->resource->addContextItem($key_adj, $term['url']);
-          $this->resource->addProperty($key_adj, $service_path . '/' . $entity->id . '/' . urlencode($term['name']));
+          $this->addResourceProperty($this->resource, $term, $service_path . '/' . $entity->id . '/' . urlencode($term['name']));
         }
         else {
           if ($hide_fields == 'show') {
-            $this->resource->addContextItem($key_adj, $term['url']);
-            $this->resource->addProperty($key_adj, NULL);
+            $this->addResourceProperty($this->resource, $term, NULL);
           }
         }
         continue;
       }
 
       // Get the details for this field for the JSON-LD response.
-      $this->addEntityField($key_adj, $term, $entity, $bundle, $field, $instance, $service_path);
+      $this->addEntityField($term, $entity, $bundle, $field, $instance, $service_path);
     }
   }
 
   /**
    * Adds the field as a property of the entity resource.
    */
-  private function addEntityField($key, $term, $entity, $bundle, $field, $instance,
+  private function addEntityField($term, $entity, $bundle, $field, $instance,
       $service_path, $expfield = NULL) {
 
 
@@ -295,7 +289,7 @@ class TripalEntityService_v0_1 extends TripalWebService {
 
     $values = array();
     for ($i = 0; $i < count($items); $i++) {
-      $values[$i] = $this->sanitizeFieldKeys($items[$i]['value'], $bundle, $service_path);
+      $values[$i] = $this->sanitizeFieldKeys($this->resource, $items[$i]['value'], $bundle, $service_path);
     }
 
     if ($hide_fields == 'hide' and empty($values[0])) {
@@ -314,15 +308,13 @@ class TripalEntityService_v0_1 extends TripalWebService {
           }
         }
         else {
-          $this->resource->addContextItem($key, $term['url']);
-          $this->resource->addProperty($key, $values[0]);
+          $this->addResourceProperty($this->resource, $term, $values[0]);
         }
       }
       // If the value is not an array it's a scalar so add it as is to the
       // response.
       else {
-        $this->resource->addContextItem($key, $term['url']);
-        $this->resource->addProperty($key, $values[0]);
+        $this->addResourceProperty($this->resource, $term, $values[0]);
       }
     }
 
@@ -333,8 +325,7 @@ class TripalEntityService_v0_1 extends TripalWebService {
       // the resource for a collection.
       $response = new TripalWebServiceCollection($service_path . '/' . urlencode($expfield), $this->params);
       $label = tripal_get_term_details('rdfs', 'label');
-      $response->addContextItem('label', $label['url']);
-      $response->addProperty('label', $instance['label']);
+      $this->addResourceProperty($response, $label, $instance['label']);
       $i = 0;
       foreach ($values as $delta => $element) {
         $member = new TripalWebServiceResource($service_path . '/' . urlencode($expfield));
@@ -342,7 +333,7 @@ class TripalEntityService_v0_1 extends TripalWebService {
         // Add the context of the parent resource because all of the keys
         // were santizied and set to match the proper context.
         $member->setContext($this->resource);
-        $member->setType($key);
+        $this->setResourceType($member, $term);
         foreach ($element as $key => $value) {
           $member->addProperty($key, $value);
         }
@@ -361,7 +352,7 @@ class TripalEntityService_v0_1 extends TripalWebService {
   /**
    * Rewrites the keys of a field's items array for use with web services.
    */
-  private function sanitizeFieldKeys($value, $bundle, $service_path) {
+  private function sanitizeFieldKeys($resource, $value, $bundle, $service_path) {
     // If the entity is set to hide fields that have no values then we
     // want to honor that in the web services too.
     $hide_fields = tripal_get_bundle_variable('hide_empty_field', $bundle->id, 'hide');
@@ -383,15 +374,15 @@ class TripalEntityService_v0_1 extends TripalWebService {
           $vocabulary = $matches[1];
           $accession = $matches[2];
           $term = tripal_get_term_details($vocabulary, $accession);
+          $key = $this->addContextTerm($resource, $term);
 
-          $key_adj = strtolower(preg_replace('/ /', '_', $term['name']));
           if (is_array($v)) {
-            $temp[$key_adj] = $this->sanitizeFieldKeys($v, $bundle, $service_path);
+            $temp[$key] = $this->sanitizeFieldKeys($resource, $v, $bundle, $service_path);
           }
           else {
-            $temp[$key_adj] = $v;
+            $temp[$key] = $v;
           }
-          $this->resource->addContextItem($key_adj, $term['url']);
+          $term['name'] = $key;
 
         }
         else {
@@ -748,9 +739,7 @@ class TripalEntityService_v0_1 extends TripalWebService {
    */
   private function doContentTypeList($ctype) {
     $service_path = $this->getServicePath() . '/' . urlencode($ctype);
-    $label = tripal_get_term_details('rdfs', 'label');
     $this->resource = new TripalWebServiceCollection($service_path, $this->params);
-    $this->resource->addContextItem('label', $label['url']);
 
     // Get the TripalBundle, TripalTerm and TripalVocab type for this type.
     $bundle = tripal_load_bundle_entity(array('label' => $ctype));
@@ -758,7 +747,8 @@ class TripalEntityService_v0_1 extends TripalWebService {
     $term = reset($term);
 
     // Set the label for this collection.
-    $this->resource->addProperty('label', $bundle->label . " collection");
+    $label = tripal_get_term_details('rdfs', 'label');
+    $this->addResourceProperty($this->resource, $label, $bundle->label . " collection");
 
     // For quick lookup, get the mapping of WS keys to their appropriate fields.
     $field_mapping = $this->getFieldMapping($bundle);
@@ -839,13 +829,10 @@ class TripalEntityService_v0_1 extends TripalWebService {
       $itemPage = tripal_get_term_details('schema', 'ItemPage');
       $label = tripal_get_term_details('rdfs', 'label');
       $member = new TripalWebServiceResource($service_path);
-      $member->addContextItem('label', $label['url']);
-      $member->addContextItem('ItemPage', $itemPage['url']);
-      $member->addContextItem($term->name, $term->url);
       $member->setID($entity->id);
-      $member->setType($term->name);
-      $member->addProperty('label', $entity->title);
-      $member->addProperty('ItemPage', url('/bio_data/' . $entity->id, array('absolute' => TRUE)));
+      $this->setResourceType($member, $term);
+      $this->addResourceProperty($member, $label, $entity->title);
+      $this->addResourceProperty($member, $itemPage, url('/bio_data/' . $entity->id, array('absolute' => TRUE)));
       $this->resource->addMember($member);
     }
   }
@@ -855,10 +842,10 @@ class TripalEntityService_v0_1 extends TripalWebService {
    */
   private function doAllTypesList() {
     $service_path = $this->getServicePath();
-    $label = tripal_get_term_details('rdfs', 'label');
     $this->resource = new TripalWebServiceCollection($service_path, $this->params);
-    $this->resource->addContextItem('label', $label['url']);
-    $this->resource->addProperty('label', 'Content Types');
+
+    $label = tripal_get_term_details('rdfs', 'label');
+    $this->addResourceProperty($this->resource, $label, 'Content Types');
 
     // Get the list of published terms (these are the bundle IDs)
     $bundles = db_select('tripal_bundle', 'tb')
@@ -873,16 +860,21 @@ class TripalEntityService_v0_1 extends TripalWebService {
       $term = reset($entity);
       $vocab = $term->vocab;
 
+      // Convert the term to a simple array
+      $term = tripal_get_term_details($term->vocab->vocabulary, $term->accession);
+
       $member = new TripalWebServiceResource($service_path);
+      $member->setID(urlencode($bundle->label));
+
       // If the term has no URL then we'll default to using thie site's
       // term lookup service.
-      $url = $term->url;
+      $url = $term['url'];
       if (!$url) {
-        $url = url('cv/lookup/' . $term->vocab->vocabulary . '/' . $term->accession , array('absolute' => TRUE));
+        $url = url('cv/lookup/' . $term['vocabulary']['short_name'] . '/' . $term['accession'] , array('absolute' => TRUE));
+        $term['url'] = $url;
       }
-      $member->addContextItem($term->name, $url);
-      $member->addContextItem('label', $label['url']);
-      $member->addProperty('label', $bundle->label);
+      $this->setResourceType($member, $term);
+      $this->addResourceProperty($member, $label, $bundle->label);
       $member->addContextItem('description', 'hydra:description');
       // Get the bundle description. If no description is provided then
       // use the term definition
@@ -894,9 +886,6 @@ class TripalEntityService_v0_1 extends TripalWebService {
         $description = '';
       }
       $member->addProperty('description', $description);
-      $member->setID(urlencode($bundle->label));
-      $member->setType($term->name);
-
       $this->resource->addMember($member);
 
     }

+ 11 - 1
tripal_ws/includes/TripalWebServiceResource.inc

@@ -65,13 +65,21 @@ class TripalWebServiceResource {
   /**
    * Adds a term to the '@context' section for this resource.
    *
+   * This function should not be called directory.  Rather, the
+   * addContextTerm() and addContextVocab() functions built
+   * into the TripalWebService class should be used as  these  will help
+   * ensure terms are added proper for the context of the web service.
+   *
    * @param $name
    *   The term name.
    * @param $iri
    *   The Internationalized Resource Identifiers or it's shortcut.
+   *
    */
   public function addContextItem($name, $iri) {
-    // TODO: make sure that if a shortcut is used that the parent is present.
+    if (array_key_exists($name, $this->context)) {
+      return;
+    }
     $this->context[$name] = $iri;
   }
 
@@ -136,6 +144,7 @@ class TripalWebServiceResource {
 
       // If the vocabulary is not in the.
       if (!in_array($vocab, $keys)) {
+        dpm(debug_backtrace());
         throw new Exception("The key, '$key', has a vocabulary that has not yet been added to the " .
             "context. Use the addContextItem() function to add the vocabulary prior to adding a value for it.");
       }
@@ -143,6 +152,7 @@ class TripalWebServiceResource {
     else {
       // If the key is not in the context then throw an error.
       if (!in_array($key, $keys)) {
+        dpm(debug_backtrace());
         throw new Exception("The key, '$key', has not yet been added to the " .
             "context. Use the addContextItem() function to add this key prior to adding a value for it.");
       }

+ 16 - 1
tripal_ws/includes/tripal_ws.fields.inc

@@ -92,4 +92,19 @@ function tripal_ws_bundle_create_user_field($new_field, $bundle) {
       ),
     ));
   }
-}
+}
+/**
+ * Implements hook_ws_field_formatter_info_alter()
+ *
+ * Adds the remote__data field to every formatter so that existing formatters
+ * can be used for remote data (provided that remote data is compatible).
+ *
+ */
+function tripal_ws_field_formatter_info_alter(&$info) {
+  foreach ($info as $formatter_type => $details) {
+    if (array_key_exists('TripalFieldFormatter', $details)) {
+      $info[$formatter_type]['field types'][] = 'remote__data';
+    }
+  }
+  dpm($info);
+}

+ 5 - 1
tripal_ws/tripal_ws.install

@@ -1,5 +1,8 @@
 <?php
 
+
+function tripal_ws_install() {
+}
 /**
  * Implementation of hook_schema().
  *
@@ -60,4 +63,5 @@ function tripal_ws_tripal_sites_schema() {
     'primary key' => array('id'),
   );
   return $schema;
-}
+}
+