Bladeren bron

Merge branch '7.x-3.x' of github.com:tripal/tripal into 7.x-3.x

Chun-Huai Cheng 9 jaren geleden
bovenliggende
commit
e220b12bde

+ 2 - 2
tripal_chado/includes/tripal_chado.entity.inc

@@ -17,7 +17,7 @@ function tripal_chado_entity_create(&$entity, $type) {
     $entity->chado_record_id = NULL;
 
     // Add in the Chado table information for this entity type.
-    $bundle = tripal_load_bundle_entity($entity->bundle);
+    $bundle = tripal_load_bundle_entity(array('name' => $entity->bundle));
     $chado_table = tripal_get_bundle_variable('chado_table', $bundle->id);
     $chado_column = tripal_get_bundle_variable('chado_column', $bundle->id);
     if ($chado_table) {
@@ -53,7 +53,7 @@ function tripal_chado_entity_load($entities, $type) {
         $entity->chado_record_id = NULL;
 
         // Add in the Chado table information for this entity type.
-        $bundle = tripal_load_bundle_entity($entity->bundle);
+        $bundle = tripal_load_bundle_entity(array('name' => $entity->bundle));
         $chado_table = tripal_get_bundle_variable('chado_table', $bundle->id);
         $chado_column = tripal_get_bundle_variable('chado_column', $bundle->id);
         if ($chado_table) {

+ 2 - 2
tripal_chado/includes/tripal_chado.field_storage.inc

@@ -19,7 +19,7 @@ function tripal_chado_field_storage_info() {
 function tripal_chado_field_storage_write($entity_type, $entity, $op, $fields) {
 
   // Get the bundle and the term for this entity.
-  $bundle = tripal_load_bundle_entity($entity->bundle);
+  $bundle = tripal_load_bundle_entity(array('name' => $entity->bundle));
   $term = entity_load('TripalTerm', array('id' => $entity->term_id));
   $term = reset($term);
 
@@ -364,7 +364,7 @@ function tripal_chado_field_storage_unnest_fields($fields, $entity_type, $entity
 /**
  * Implements hook_field_storage_query().
  *
- * Used by EntityFieldQuery to find the entities having certain entity 
+ * Used by EntityFieldQuery to find the entities having certain entity
  * and field conditions and sort them in the given field order.
  *
  * NOTE: This function needs to exist or errors are triggered but so far it doesn't

+ 16 - 10
tripal_entities/api/tripal_entities.api.inc

@@ -51,18 +51,24 @@ function tripal_load_vocab_entity($namespace) {
 /**
  * Retrieves a TripalBundle entity that matches the given arguments.
  *
- * @param $name
- *   The name the bundle (e.g. bio-data_234).
+ * @param $values
+ *   An associative array used to match a bundle.  Valid keys may be 'name' or
+ *   'label' (e.g. array('name' => 'bio-data_234').
  *
  * @return
  *   A TripalBundle entity object or NULL if not found.
  */
-function tripal_load_bundle_entity($name) {
-  $bundle = db_select('tripal_bundle', 'tb')
-    ->fields('tb')
-    ->condition('tb.name', $name)
-    ->execute()
-    ->fetchObject();
+function tripal_load_bundle_entity($values) {
+
+  $query = db_select('tripal_bundle', 'tb');
+  $query->fields('tb');
+  if (array_key_exists('name', $values)) {
+    $query->condition('tb.name', $values['name']);
+  }
+  if (array_key_exists('label', $values)) {
+    $query->condition('tb.label', $values['label']);
+  }
+  $bundle = $query->execute()->fetchObject();
 
   if ($bundle) {
     $entity = entity_load('TripalBundle', array($bundle->id));
@@ -128,7 +134,7 @@ function tripal_create_bundle($namespace, $accession, $term_name, &$error = '')
   variable_set('menu_rebuild_needed', TRUE);
 
   // Get the bundle object.
-  $bundle = tripal_load_bundle_entity($bundle_name);
+  $bundle = tripal_load_bundle_entity(array('name' => $bundle_name));
 
   // Allow modules to now add fields to the bundle
   module_invoke_all('add_bundle_fields', 'TripalEntity', $bundle, $term);
@@ -507,7 +513,7 @@ function tripal_replace_tokens($string, $entity, $bundle_entity = NULL) {
 
         // Load the bundle entity if we weren't given it.
         if (!$bundle_entity) {
-          $bundle_entity = tripal_load_bundle_entity($entity->bundle);
+          $bundle_entity = tripal_load_bundle_entity(array('name' => $entity->bundle));
         }
 
         // This token should be the id of the TripalBundle.

+ 34 - 34
tripal_entities/includes/TripalEntityController.inc

@@ -55,7 +55,7 @@ class TripalEntityController extends EntityAPIController {
    * @param array $ids
    *    An array of the ids denoting which entities to delete.
    * @param DatabaseTransaction $transaction
-   *    Optionally a DatabaseTransaction object to use. Allows overrides to pass in 
+   *    Optionally a DatabaseTransaction object to use. Allows overrides to pass in
    *    their transaction object.
    */
   public function delete($ids, $transaction = NULL) {
@@ -63,18 +63,18 @@ class TripalEntityController extends EntityAPIController {
     if (!$transaction) {
       $transaction = db_transaction();
     }
-    
+
     try {
-      
+
       // First load the entity.
       $entities = entity_load('TripalEntity', $ids);
-      
+
       // Then properly delete each one.
       foreach ($entities as $entity) {
-      
+
         // Invoke hook_entity_delete().
         module_invoke_all('entity_delete', $entity, $entity->type);
-        
+
         // Delete any field data for this entity.
         field_attach_delete('TripalEntity', $entity);
 
@@ -107,11 +107,11 @@ class TripalEntityController extends EntityAPIController {
     if (!$title) {
 
       // Load the TripalBundle entity for this TripalEntity.
-      $bundle_entity = tripal_load_bundle_entity($entity->bundle);
-      
+      $bundle_entity = tripal_load_bundle_entity(array('name' => $entity->bundle));
+
       // First get the format for the title based on the bundle of the entity.
       $title = tripal_get_title_format($bundle_entity);
-      
+
       // And then replace all the tokens with values from the entity fields.
       $title = tripal_replace_tokens($title, $entity, $bundle_entity);
 
@@ -133,25 +133,25 @@ class TripalEntityController extends EntityAPIController {
    */
   public function setAlias($entity, $alias = NULL) {
     $source_url = "bio-data/$entity->id";
-    
+
     // If no alias was supplied then we should try to generate one using the
     // default format set by admins.
     if (!$alias) {
-    
+
       // Load the TripalBundle entity for this TripalEntity.
       $bundle_entity = tripal_bundle_load($entity->bundle);
-      
+
       // First get the format for the url alias based on the bundle of the entity.
       $alias = tripal_get_bundle_variable('url_format', $bundle_entity->id);
 
       // And then replace all the tokens with values from the entity fields.
       $alias = tripal_replace_tokens($alias, $entity, $bundle_entity);
     }
-    
+
     // If there was no defaults supplied by the admins
     // then we should gneerate our own using the term name and entity id.
     if (!$alias) {
-      
+
       // Load the term for this TripalEntity.
       $term = entity_load('TripalTerm', array('id' => $entity->term_id));
       $term = reset($term);
@@ -168,20 +168,20 @@ class TripalEntityController extends EntityAPIController {
     // Or any non alpha numeric characters.
     $alias = preg_replace('/[^a-zA-Z0-9\-\/]/','',$alias);
     $alias = preg_replace('/_/','-',$alias);
-    
+
     if ($alias) {
-           
+
       // Determine if this alias has already been used.
       $num_aliases = db_query('SELECT count(*) as num_alias FROM {url_alias} WHERE alias=:alias',
         array(':alias' => $alias))->fetchField();
-      
+
       // Either there isn't an alias yet so we just create one.
       // OR an Alias already exists but we would like to add a new one.
       if ($num_aliases == 0) {
-      
+
         // First delete any previous alias' for this entity.
         path_delete(array('source' => $source_url));
-        
+
         // Then save the new one.
         $path = array('source' => $source_url, 'alias' => $alias);
         path_save($path);
@@ -189,19 +189,19 @@ class TripalEntityController extends EntityAPIController {
       // If there is only one alias matching then it might just be that we already
       // assigned this alias to this entity in a previous save.
       elseif ($num_aliases == 1) {
-      
+
         $bundle_entity = tripal_bundle_load($entity->bundle);
-        
+
         // Checking to see if the single alias is for the same entity and if not
         // warning the admin that the alias is already used (ie: not unique?)
         $same_alias = db_query('SELECT count(*) as num_alias FROM {url_alias} WHERE alias=:alias AND source=:source',
           array(':alias' => $alias, ':source' => $source_url))->fetchField();
         if (!$same_alias) {
 
-          $msg = 'The URL alias, %alias, already exists for another page. Please ensure the pattern 
+          $msg = 'The URL alias, %alias, already exists for another page. Please ensure the pattern
             supplied on the <a href="!link" target="_blank">%type Edit Page</a> under URL Path options is unique.';
           $msg_var = array(
-              '%alias' => $alias, 
+              '%alias' => $alias,
               '!link' => url("admin/structure/bio-data/manage/$entity->bundle"),
               '%type' => $bundle_entity->label
             );
@@ -212,14 +212,14 @@ class TripalEntityController extends EntityAPIController {
             $msg_var
           );
           drupal_set_message(t($msg, $msg_var), 'warning');
-          
+
         }
       }
-      // If there are more then one alias' matching what we generated then there's 
+      // If there are more then one alias' matching what we generated then there's
       // a real problem and we need to warn the administrator.
       else {
         $bundle_entity = tripal_bundle_load($entity->bundle);
-        
+
         $aliases = db_query('SELECT source FROM {url_alias} WHERE alias=:alias',
           array(':alias' => $alias))->fetchAll();
         $pages = array();
@@ -227,16 +227,16 @@ class TripalEntityController extends EntityAPIController {
           $pages[] = $a->source;
         }
 
-        $msg = 'The URL alias, %alias, already exists for multiple pages! Please ensure the pattern 
+        $msg = 'The URL alias, %alias, already exists for multiple pages! Please ensure the pattern
           supplied on the <a href="!link" target="_blank">%type Edit Page</a> under URL Path options is unique.';
         $msg_var = array(
-            '%alias' => $alias, 
+            '%alias' => $alias,
             '!link' => url("admin/structure/bio-data/manage/$entity->bundle"),
             '%type' => $bundle_entity->label
           );
         drupal_set_message(t($msg, $msg_var), 'error');
-        
-        $msg .= ' This url alias has already been used for the following pages: %pages. 
+
+        $msg .= ' This url alias has already been used for the following pages: %pages.
           You can manually delete alias\' using a combination of path_load() and path_delete().';
         $msg_var['%pages'] = implode(', ', $pages);
         tripal_report_error(
@@ -245,11 +245,11 @@ class TripalEntityController extends EntityAPIController {
           $msg,
           $msg_var
         );
-          
+
       }
     }
   }
-  
+
   /**
    * Saves the custom fields using drupal_write_record().
    */
@@ -301,10 +301,10 @@ class TripalEntityController extends EntityAPIController {
       else {
         field_attach_update('TripalEntity', $entity);
       }
-      
+
       // Set the title for this entity.
       $this->setTitle($entity);
-      
+
       // Set the path/url alias for this entity.
       $this->setAlias($entity);
 

+ 1 - 2
tripal_entities/includes/TripalEntityUIController.inc

@@ -38,7 +38,7 @@ class TripalEntityUIController extends EntityDefaultUIController {
     foreach ($bundles as $bundle_name) {
       $matches = array();
       if (preg_match('/^bio-data_(.*?)$/', $bundle_name, $matches)) {
-        $bundle = tripal_load_bundle_entity($bundle_name);
+        $bundle = tripal_load_bundle_entity(array('name' => $bundle_name));
         // Get the term for this bundle
         $term = entity_load('TripalTerm', array('id' => $matches[1]));
         $term = reset($term);
@@ -419,4 +419,3 @@ function tripal_entities_view_entity($entity, $view_mode = 'full') {
      drupal_set_message(t('The tripal_entity %name was not deleted.', array('%name' => $entity->title)), "error");
    }
  }
- 

+ 263 - 40
tripal_ws/includes/tripal_ws.rest.inc

@@ -1,8 +1,12 @@
 <?php
 
+/**
+ *
+ */
 function tripal_ws_rest() {
 
   global $base_url;
+  $ws_args = func_get_args();
 
   // Set some initial variables.
   $response = array();
@@ -13,26 +17,28 @@ function tripal_ws_rest() {
   $page_limit = 25;
   $pager_id = 0;
 
-  $response['@context'] =  array(
-    'schema' => 'http://schema.org/',
-    'foaf' => 'http://xmlns.com/foaf/0.1/',
-    'dc' => 'http://purl.org/dc/elements/1.1/',
-  );
-  $response['@id'] = $api_url;
-
-  $namespace   = arg(3) ? arg(3) : '';
-  $bundle_name = arg(4) ? arg(4) : '';
+  // Set some defaults for the response.
+  $response['@context'] =  array();
 
   // Lump everything ito a try block so that if there is a problem we can
   // throw an error and have that returned in the response.
   try {
-    if (!$namespace) {
-      tripal_ws_get_content_types($api_url, $response);
-    }
-    if ($namespace and !$bundle_name) {
-      tripal_ws_get_content_type($api_url, $response, $namespace);
-    }
 
+    // The services is the first argument
+    $service = (count($ws_args) > 0) ? $ws_args[0] : '';
+
+    switch ($service) {
+      case 'doc':
+        tripal_ws_handle_doc_service($api_url, $response);
+        break;
+      case 'content':
+        tripal_ws_handle_content_service($api_url, $response, $ws_args);
+        break;
+      case 'vocab':
+        break;
+      default:
+        tripal_ws_handle_no_service($api_url, $response);
+    }
   }
   catch (Exception $e) {
     watchdog('tripal_ws', $e->getMessage(), array(), WATCHDOG_ERROR);
@@ -51,15 +57,49 @@ function tripal_ws_rest() {
     'site_slogan' => variable_get('site_slogan', 'Unspecified'),
     'site_email' =>  variable_get('site_mail', 'Unspecified'),
   ); */
-  print drupal_json_output($response);
+
+  // Rather than use the drupal_json_output() funciton we manually specify
+  // content type because we want it to be 'ld+json'.
+  drupal_add_http_header('Content-Type', 'application/ld+json');
+  print drupal_json_encode($response);
 }
+
 /**
+ * Provides the Hydra compatible apiDocumentation page that describes this API.
  *
- * @param unknown $api_url
- * @param unknown $response
+ * @param $api_url
+ * @param $response
  */
-function tripal_ws_get_content_types($api_url, &$response) {
+function tripal_ws_handle_doc_service($api_url, &$response) {
+  // First, add the vocabularies used into the @context section.
+  $response['@context']['rdfs'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+  $response['@context']['hydra'] = 'http://www.w3.org/ns/hydra/core#';
+
+  // Next add in the ID for tihs resource.
+  $site_name = variable_get('site_name', '');
+  $response['@id'] = $api_url . '/ws-doc/';
+  $response['title'] =  $site_name . ": RESTful Web Services API";
+  $response['entrypoint'] = $api_url;
+  $response['description'] = "A fully queryable REST API using JSON-LD and " .
+    "discoverable using the WC3 Hydra specification.";
+
+  // Lastly, add in the terms used into the @context section.
+  $response['@context']['title'] = 'hydra:title';
+  $response['@context']['entrypoint'] = array(
+    "@id" => "hydra:entrypoint",
+    "@type" => "@id",
+  );
+  $response['@context']['description'] = 'hydra:description';
+}
 
+/**
+ * This function specifies the types of resources avaiable via the API.
+ *
+ * @param $api_url
+ * @param $response
+ * @param $ws_args
+ */
+function tripal_ws_handle_no_service($api_url, &$response) {
 
   // Add in the term's will use for keys to the context.
   $response['@context']['itemListElement'] = 'schema:itemListElement';
@@ -76,7 +116,66 @@ function tripal_ws_get_content_types($api_url, &$response) {
   $response['@type'] = 'ItemList';
   $response['itemListOrder'] = 'ItemListOrderAscending';
   $response['numberOfItems'] = 0;
-  $response['name'] = 'Content Types';
+  $response['name'] = 'Services';
+  $response['itemListElement'][] = array(
+    '@type' => 'ListItem',
+    'position' => 1,
+    'item' => array(
+      '@id' => $api_url . '/data/',
+      '@type' => $vocab->namespace . ':' . $term->accession,
+      'name' => $term->name,
+      'description' => 'This service provides acesss to the biological and ' .
+        'anciallary data available on this site.',
+    ),
+  );
+}
+
+/**
+ *
+ * @param $api_url
+ * @param $response
+ * @param $ws_args
+ */
+function tripal_ws_handle_content_service($api_url, &$response, $ws_args) {
+
+  // Get the content type.
+  $ctype     = (count($ws_args) > 1) ? $ws_args[1] : '';
+  $entity_id = (count($ws_args) > 2) ? $ws_args[2] : '';
+
+  // If we have no content type then list all of the available content types.
+  if (!$ctype) {
+    tripal_ws_get_content_types($api_url, $response);
+  }
+  // If we don't have an entity ID then show a paged list of entities with
+  // the given type.
+  else if ($ctype and !$entity_id) {
+    tripal_ws_get_content_type($api_url, $response, $ws_args, $ctype);
+  }
+  // If we have a content type and an entity ID then show the entity
+  else {
+    tripal_ws_get_content($api_url, $response, $ws_args, $ctype, $entity_id);
+  }
+}
+
+/**
+ * Provides a collection (list) of all of the content types.
+ *
+ * @param $api_url
+ * @param $response
+ */
+function tripal_ws_get_content_types($api_url, &$response) {
+
+  // First, add the vocabularies used into the @context section.
+  $response['@context']['rdfs'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+  $response['@context']['hydra'] = 'http://www.w3.org/ns/hydra/core#';
+
+  // Next add in the ID for tihs resource.
+  $response['@id'] = $api_url . '/content';
+
+  // Start the list.
+  $response['@type'] = 'Collection';
+  $response['totalItems'] = 0;
+  $response['label'] = 'Content Types';
 
   // Get the list of published terms (these are the bundle IDs)
   $bundles = db_select('tripal_bundle', 'tb')
@@ -84,14 +183,13 @@ function tripal_ws_get_content_types($api_url, &$response) {
     ->orderBy('tb.label', 'ASC')
     ->execute();
   $terms = array();
+
+  // Iterate through the terms and add the mas a entry in the collection.
   while ($bundle = $bundles->fetchObject()) {
     $entity =  entity_load('TripalTerm', array('id' => $bundle->term_id));
-    $terms[$bundle->label] = reset($entity);
-  }
-
-  $i = 0;
-  foreach ($terms as $name => $term) {
+    $term = reset($entity);
     $vocab = $term->vocab;
+
     if (!array_key_exists($vocab->namespace, $response['@context'])) {
       // If there is no URL prefix then use this API's vocabulary API
       if ($term->urlprefix) {
@@ -101,29 +199,154 @@ function tripal_ws_get_content_types($api_url, &$response) {
         $response['@context'][$vocab->namespace] = $api_url . '/vocab/' . $vocab->namespace . '/';
       }
     }
-    $response['itemListElement'][] = array(
-      '@type' => 'ListItem',
-      'position' => $i + 1,
-      'item' => array(
-        '@id' => $api_url . '/bio-data/' . $term->name,
-        '@type' => $vocab->namespace . ':' . $term->accession,
-        'name' => $term->name,
-        'description' => $term->definition,
-      ),
+    // Get the bundle description. If no description is provided then
+    // use the term definition
+    $description = tripal_get_bundle_variable('description', $bundle->id);
+    if (!$description) {
+      $description = $term->definition;
+    }
+    // Add the bundle as a content type.
+    $response['member'][] = array(
+      '@id' => $api_url . '/content/' . $bundle->label,
+      '@type' => $vocab->namespace . ':' . $term->accession,
+      'label' => $bundle->label,
+      'description' => $description,
     );
     $i++;
   }
-  $response['numberOfItems'] = $i;
+  $response['totalItems'] = $i;
+
+  // Lastly, add in the terms used into the @context section.
+  $response['@context']['Collection'] = 'hydra:Collection';
+  $response['@context']['totalItems'] = 'hydra:totalItems';
+  $response['@context']['member'] = 'hydra:member';
+  $response['@context']['label'] = 'rdfs:label';
+  $response['@context']['description'] = 'hydra:description';
+}
+
+/**
+ *
+ * @param $api_url
+ * @param $response
+ * @param $ws_args
+ */
+function tripal_ws_get_content_type($api_url, &$response, $ws_args, $ctype) {
+
+  // First, add the vocabularies used into the @context section.
+  $response['@context']['rdfs'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+  $response['@context']['hydra'] = 'http://www.w3.org/ns/hydra/core#';
+  $response['@context']['schema'] = 'https://schema.org/';
+
+  // Next add in the ID for tihs resource.
+  $response['@id'] = $api_url . '/content/' . $ctype;
+
+  // Get the TripalBundle, TripalTerm and TripalVocab type for this type.
+  $bundle = tripal_load_bundle_entity(array('label' => $ctype));
+  $entity =  entity_load('TripalTerm', array('id' => $bundle->term_id));
+  $term = reset($entity);
+  $vocab = $term->vocab;
+
+  // Start the list.
+  $response['@type'] = 'Collection';
+  $response['totalItems'] = 0;
+  // TODO: perhaps we should also have a plural label and get rid of the word
+  // 'records'.
+  $response['label'] = $bundle->label . " records";
+
+  // Get the list of entities for this bundle.
+  $query = new EntityFieldQuery;
+  $query->entityCondition('entity_type', 'TripalEntity')
+    ->entityCondition('bundle', $bundle->name)
+    ->propertyOrderBy('title', 'DESC')
+    ->pager(10);
+
+  // Iterate through the entities and add them to the list.
+  $results = $query->execute();
+  $i = 0;
+  if (isset($results['TripalEntity'])) {
+    $entities = entity_load('TripalEntity', array_keys($results['TripalEntity']));
+    foreach ($entities as $entity) {
+      $response['member'][] = array(
+        '@id' => $api_url . '/content/' . $ctype . '/' .  $bundle->id,
+        '@type' => $vocab->namespace . ':' . $term->accession,
+        'label' => $entity->title,
+        'itemPage' => url('/bio-data/' . $entity->id, array('absolute' => TRUE)),
+      );
+      $i++;
+    }
+  }
+  $response['totalItems'] = $i;
+
+  // Lastly, add in the terms used into the @context section.
+  $response['@context']['Collection'] = 'hydra:Collection';
+  $response['@context']['totalItems'] = 'hydra:totalItems';
+  $response['@context']['member'] = 'hydra:member';
+  $response['@context']['label'] = 'rdfs:label';
+  $response['@context']['itemPage'] = 'schema:itemPage';
+
 }
 
 /**
  *
- * @param unknown $api_url
- * @param unknown $response
- * @param unknown $vocab
- * @param unknown $name
+ * @param $api_url
+ * @param $response
+ * @param $ws_args
  */
-function tripal_ws_get_content_type($api_url, &$response, $vocab, $name) {
+function tripal_ws_get_content($api_url, &$response, $ws_args, $ctype, $entity_id) {
+
+  // First, add the vocabularies used into the @context section.
+  $response['@context']['rdfs'] = 'http://www.w3.org/1999/02/22-rdf-syntax-ns#';
+  $response['@context']['hydra'] = 'http://www.w3.org/ns/hydra/core#';
+  $response['@context']['schema'] = 'https://schema.org/';
+
+  // Get the TripalBundle, TripalTerm and TripalVocab type for this type.
+  $bundle = tripal_load_bundle_entity(array('label' => $ctype));
+  $entity =  entity_load('TripalTerm', array('id' => $bundle->term_id));
+  $term = reset($entity);
+  $vocab = $term->vocab;
+
+  // Get the TripalEntity
+  $entity = entity_load('TripalEntity', array('id' => $entity_id));
+  $entity = reset($entity);
+
+  // Next add in the ID and Type for this resources.
+  $response['@id'] = $api_url . '/content/' . $ctype . '/' . $entity_id;
+  $response['@type'] = $vocab->namespace . ':' . $term->accession,;
+  $response['totalItems'] = 0;
+  // TODO: perhaps we should also have a plural label and get rid of the word
+  // 'records'.
+  $response['label'] = $bundle->label . " records";
+
+  // Get the list of entities for this bundle.
+  $query = new EntityFieldQuery;
+  $query->entityCondition('entity_type', 'TripalEntity')
+  ->entityCondition('bundle', $bundle->name)
+  ->propertyOrderBy('title', 'DESC')
+  ->pager(10);
+
+  // Iterate through the entities and add them to the list.
+  $results = $query->execute();
+  $i = 0;
+  if (isset($results['TripalEntity'])) {
+    $entities = entity_load('TripalEntity', array_keys($results['TripalEntity']));
+    foreach ($entities as $entity) {
+      $response['member'][] = array(
+        '@id' => $api_url . '/content/' . $ctype . '/' .  $bundle->id,
+        '@type' => $vocab->namespace . ':' . $term->accession,
+        'label' => $entity->title,
+        'itemPage' => url('/bio-data/' . $bundle->id, array('absolute' => TRUE)),
+      );
+      $i++;
+    }
+  }
+  $response['totalItems'] = $i;
+
+  // Lastly, add in the terms used into the @context section.
+  $response['@context']['Collection'] = 'hydra:Collection';
+  $response['@context']['totalItems'] = 'hydra:totalItems';
+  $response['@context']['member'] = 'hydra:member';
+  $response['@context']['label'] = 'rdfs:label';
+  $response['@context']['itemPage'] = 'schema:itemPage';
 
 }
 

+ 21 - 1
tripal_ws/tripal_ws.module

@@ -1,5 +1,25 @@
 <?php
 
+
+/**
+ * Implements hook_init()
+ */
+function tripal_ws_init() {
+  global $base_url;
+
+  $version = 'v0.1';
+  $api_url = $base_url . '/ws/' . $version;
+
+  // Following the WC3 Hydra documentation, we want to add  LINK to the header
+  // of the site that indicates where the API documentation can be found.
+  // This allows a hydra-enabled client to discover the API and use it.
+  $attributes = array(
+    'rel' => 'http://www.w3.org/ns/hydra/core#apiDocumentation',
+    'href' => $api_url . '/ws-doc/',
+  );
+  drupal_add_html_head_link($attributes, $header = FALSE);
+}
+
 /**
  * Implements hook_menu().
  * Defines all menu items needed by Tripal Core
@@ -9,7 +29,7 @@
 function tripal_ws_menu() {
 
   // Web Services API callbacks.
-  $items['ws/bio-data/v0.1'] = array(
+  $items['ws/v0.1'] = array(
     'title' => 'Tripal Entities Web Services API v0.1',
     'page callback' => 'tripal_ws_rest',
     'access arguments' => array('access content'),