Bladeren bron

Added relationship field. Added Chado tokens API functions. Fixed deltion of bundles

Stephen Ficklin 9 jaren geleden
bovenliggende
commit
8692c9a368

+ 8 - 4
tripal/api/tripal.entities.api.inc

@@ -75,6 +75,7 @@ function tripal_load_vocab_entity($values) {
  *
  * @param $values
  *   An associative array used to match a bundle.  Valid keys may:
+ *     - id: the numeric id of the bundle.
  *     - name:  the bundle name (e.g. 'bio_data_234')
  *     - label: the bundle label (e.g. 'Organism')
  *     - term_id: the term ID to which the bundle belongs
@@ -86,6 +87,9 @@ function tripal_load_bundle_entity($values) {
 
   $query = db_select('tripal_bundle', 'tb');
   $query->fields('tb');
+  if (array_key_exists('id', $values)) {
+    $query->condition('tb.id', $values['id']);
+  }
   if (array_key_exists('name', $values)) {
     $query->condition('tb.name', $values['name']);
   }
@@ -552,7 +556,7 @@ function tripal_get_default_title_format($entity) {
   $format = NULL;
 
   // Retrieve all available tokens.
-  $tokens = tripal_get_tokens($entity);
+  $tokens = tripal_get_entity_tokens($entity);
 
   // A) Check to see if more informed modules have suggested a title for this type.
   // Invoke hook_tripal_default_title_format() to get all suggestions from other modules.
@@ -654,7 +658,7 @@ function hook_tripal_default_title_format($entity, $available_tokens) {
  * @return
  *    An array of tokens where the key is the machine_name of the token.
  */
-function tripal_get_tokens($entity, $options = array()) {
+function tripal_get_entity_tokens($entity, $options = array()) {
   $tokens = array();
 
   // Set default options.
@@ -723,7 +727,7 @@ function tripal_get_tokens($entity, $options = array()) {
  * @return
  *   The string will all tokens replaced with values.
  */
-function tripal_replace_tokens($string, $entity, $bundle_entity = NULL) {
+function tripal_replace_entity_tokens($string, $entity, $bundle_entity = NULL) {
 
 
   // Determine which tokens were used in the format string
@@ -772,7 +776,7 @@ function tripal_replace_tokens($string, $entity, $bundle_entity = NULL) {
  * Formats the tokens for display.
  *
  * @param array $tokens
- *   A list of tokens generated via tripal_get_tokens().
+ *   A list of tokens generated via tripal_get_entity_tokens().
  * @return
  *   Rendered output describing the available tokens.
  */

+ 40 - 0
tripal/includes/TripalBundleController.inc

@@ -29,4 +29,44 @@ class TripalBundleController extends EntityAPIControllerExportable {
     return parent::create($values);
   }
 
+  /**
+   * Overrides the parent delete function.
+   *
+   * @param $ids
+   * @param DatabaseTransaction $transaction
+   */
+  public function delete($ids, DatabaseTransaction $transaction = NULL) {
+    $entities = $ids ? $this->load($ids) : FALSE;
+    if ($entities) {
+
+
+      foreach ($entities as $id => $entity) {
+        $bundle = tripal_load_bundle_entity(array('id' => $id));
+
+        // Remove the terms for the bundles that are to be deleted.
+        db_delete('tripal_term')
+          ->condition('id', $bundle->term_id)
+          ->execute();
+
+        // Remove the chado_entity records for this type.
+
+      }
+
+
+
+
+      // Use the parent function to delete the bundles.
+      parent::delete($ids, $transaction);
+
+      // Not sure what this does, but copied from the
+      // EntityAPIControllerExportable->delete() function which this one
+      // overrides.
+      foreach ($entities as $id => $entity) {
+        if (entity_has_status($this->entityType, $entity, ENTITY_IN_CODE)) {
+          entity_defaults_rebuild(array($this->entityType));
+          break;
+        }
+      }
+    }
+  }
 }

+ 2 - 2
tripal/includes/TripalBundleUIController.inc

@@ -214,7 +214,7 @@ function tripal_tripal_bundle_form($form, &$form_state, $entityDataType) {
     '#collapsed' => TRUE
   );
 
-  $tokens = tripal_get_tokens($entity_type);
+  $tokens = tripal_get_entity_tokens($entity_type);
   $form['set_titles']['tokens'] = array(
     '#type' => 'hidden',
     '#value' => serialize($tokens)
@@ -259,7 +259,7 @@ function tripal_tripal_bundle_form($form, &$form_state, $entityDataType) {
     '#rows' => 1
   );
 
-  $tokens = tripal_get_tokens($entity_type, array('required only' => TRUE));
+  $tokens = tripal_get_entity_tokens($entity_type, array('required only' => TRUE));
   $form['url']['tokens'] = array(
     '#type' => 'hidden',
     '#value' => serialize($tokens)

+ 5 - 4
tripal/includes/TripalEntityController.inc

@@ -79,10 +79,11 @@ class TripalEntityController extends EntityAPIController {
         // Delete any field data for this entity.
         field_attach_delete('TripalEntity', $entity);
 
-        // Finally delete the entity record from our base table.
+        // Delete the entity record from our base table.
         db_delete('tripal_entity')
           ->condition('id', $entity->id)
           ->execute();
+
       }
     }
     catch (Exception $e) {
@@ -114,7 +115,7 @@ class TripalEntityController extends EntityAPIController {
       $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);
+      $title = tripal_replace_entity_tokens($title, $entity, $bundle_entity);
 
     }
 
@@ -146,7 +147,7 @@ class TripalEntityController extends EntityAPIController {
       $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);
+      $alias = tripal_replace_entity_tokens($alias, $entity, $bundle_entity);
     }
 
     // If there was no defaults supplied by the admins
@@ -161,7 +162,7 @@ class TripalEntityController extends EntityAPIController {
       $alias = str_replace(' ', '', $term->name) . '/[TripalEntity__entity_id]';
 
       // And then replace all the tokens with values from the entity fields.
-      $alias = tripal_replace_tokens($alias, $entity, $bundle_entity);
+      $alias = tripal_replace_entity_tokens($alias, $entity, $bundle_entity);
     }
 
     // Make sure the alias doesn't contain spaces.

+ 122 - 2
tripal_chado/api/tripal_chado.api.inc

@@ -111,7 +111,7 @@ function tripal_chado_publish_records($values, $job_id = NULL) {
       $entity = entity_load('TripalEntity', array($entity->id));
       $entity = reset($entity);
       $title_format = tripal_get_title_format($bundle);
-      $title = tripal_replace_tokens($title_format, $entity, $bundle);
+      $title = tripal_replace_entity_tokens($title_format, $entity, $bundle);
       $ec->setTitle($entity, $title);
       $num_published++;
     }
@@ -125,4 +125,124 @@ function tripal_chado_publish_records($values, $job_id = NULL) {
   }
   drupal_set_message("Succesfully published $num_published " . $bundle->label . " record(s).");
   return TRUE;
-}
+}
+
+/**
+ * Returns an array of tokens based on Tripal Entity Fields.
+ *
+ * @param $base_table
+ *    The name of a base table in Chado.
+ * @return
+ *    An array of tokens where the key is the machine_name of the token.
+ */
+function tripal_get_chado_tokens($base_table) {
+
+  $tokens = array();
+  $table_descrip = chado_get_schema($base_table);
+  foreach ($table_descrip['fields'] as $field_name => $field_details) {
+
+    $token = '[' . $base_table . '.' . $field_name . ']';
+    $location = implode(' > ',array($base_table, $field_name));
+
+    $tokens[$token] = array(
+      'name' => ucwords(str_replace('_',' ',$base_table)) . ': ' . ucwords(str_replace('_',' ',$field_name)),
+      'table' => $base_table,
+      'field' => $field_name,
+      'token' => $token,
+      'description' => array_key_exists('description', $field_details) ? $field_details['description'] : '',
+      'location' => $location
+    );
+
+    if (!array_key_exists('description', $field_details) or preg_match('/TODO/',$field_details['description'])) {
+      $tokens[$token]['description'] = 'The '.$field_name.' field of the '.$base_table.' table.';
+    }
+  }
+
+  // RECURSION:
+  // Follow the foreign key relationships recursively
+  if (array_key_exists('foreign keys', $table_descrip)) {
+    foreach ($table_descrip['foreign keys'] as $table => $details) {
+      foreach ($details['columns'] as $left_field => $right_field) {
+
+        $sub_token_prefix = $base_table . '.' . $left_field;
+        $sub_location_prefix = implode(' > ',array($base_table, $left_field));
+
+        $sub_tokens = tripal_get_chado_tokens($table);
+        if (is_array($sub_tokens)) {
+          $tokens = array_merge($tokens, $sub_tokens);
+        }
+      }
+    }
+  }
+
+  return $tokens;
+}
+
+/**
+ * Replace all Chado Tokens in a given string.
+ *
+ * NOTE: If there is no value for a token then the token is removed.
+ *
+ * @param string $string
+ *   The string containing tokens.
+ * @param $record
+ *   A Chado record as generated by chado_generate_var()
+ *
+ * @return
+ *   The string will all tokens replaced with values.
+ */
+function tripal_replace_chado_tokens($string, $record) {
+  // Get the list of tokens
+  $tokens = tripal_get_chado_tokens($record->tablename);
+
+  // Determine which tokens were used in the format string
+  if (preg_match_all('/\[[^]]+\]/', $string, $used_tokens)) {
+    // Get the value for each token used
+    foreach ($used_tokens[0] as $token) {
+      $token_info = $tokens[$token];
+      if (!empty($token_info)) {
+        $table = $token_info['table'];
+        $var = $record;
+        $value = '';
+
+        // Iterate through each portion of the location string. An example string
+        // might be:  stock > type_id > name.
+        $location = explode('>', $token_info['location']);
+        foreach ($location as $index) {
+          $index = trim($index);
+
+          // if $var is an object then it is the $node object or a table
+          // that has been expanded.
+          if (is_object($var)) {
+            // check to see if the index is a member of the object. If so,
+            // then reset the $var to this value.
+            if (property_exists($var, $index)) {
+              $value = $var->$index;
+            }
+            else {
+              tripal_report_error('tripal_chado', TRIPAL_WARNING,
+                'Tokens: Unable to determine the value of %token. Things went awry when trying ' .
+                'to access \'%index\' for the following: \'%var\'.',
+                array('%token' => $token, '%index' => $index, '%var' => print_r($var,TRUE))
+              );
+            }
+          }
+          // if the $var is an array then there are multiple instances of the same
+          // table in a FK relationship (e.g. relationship tables)
+          elseif (is_array($var)) {
+            $value = $var[$index];
+          }
+          else {
+            tripal_report_error('tripal_chado', TRIPAL_WARNING,
+              'Tokens: Unable to determine the value of %token. Things went awry when trying ' .
+              'to access \'%index\' for the following: \'%var\'.',
+              array('%token' => $token, '%index' => $index, '%var' => print_r($var,TRUE))
+            );
+          }
+        }
+        $string = str_replace($token, $value, $string);
+      }
+    }
+  }
+  return $string;
+}

+ 12 - 0
tripal_chado/api/tripal_chado.variables.api.inc

@@ -251,6 +251,7 @@ function chado_generate_var($table, $values, $base_options = array()) {
       // add curent table
       $object->tablename = $table;
 
+      // For Tripal v2 compatibility
       // check if the current table maps to a node type-----------------------------------------------
       // if this table is connected to a node there will be a chado_tablename table in drupal
       if (db_table_exists('chado_' . $table)) {
@@ -268,6 +269,17 @@ function chado_generate_var($table, $values, $base_options = array()) {
         }
       }
 
+      // Check to see if the current table maps to an entity
+      $entity_id = db_select('chado_entity', 'ce')
+        ->fields('ce', array('entity_id'))
+        ->condition('data_table', $table)
+        ->condition('record_id', $object->{$table_primary_key})
+        ->execute()
+        ->fetchField();
+      if ($entity_id) {
+        $object->entity_id = $entity_id;
+      }
+
       // remove any fields where criteria needs to be evalulated---------------------------------------
       // The fields to be removed can be populated by implementing either
       // hook_exclude_field_from_<table>_by_default() where <table> is the current table

+ 3 - 2
tripal_chado/includes/fields/chado_base__dbxref_id.inc

@@ -126,10 +126,12 @@ function chado_base__dbxref_id_formatter_info() {
 function chado_base__dbxref_id_formatter(&$element, $entity_type, $entity, $field,
     $instance, $langcode, $items, $display) {
 
+  $record = $entity->chado_record;
+
   foreach ($items as $delta => $item) {
     $accession = '';
     if ($item['value']) {
-      $dbxref = chado_generate_var('dbxref', array('dbxref_id' => $item['value']));
+      $dbxref = $record->dbxref_id;
       $accession = $dbxref->db_id->name . ':' . $dbxref->accession;
       if ($dbxref->db_id->urlprefix) {
         $accession = l($accession, $dbxref->db_id->urlprefix . '/' . $dbxref->accession,
@@ -413,7 +415,6 @@ function chado_base__dbxref_id_load($field, $entity, $base_table, $record) {
     'dbxref__version' => '',
     'dbxref__description' => '',
   );
-
   // Get the primary dbxref record (if it's not NULL).  Because we have a
   // dbxref_id passed in by the base record, we will only have one record.
   if ($record->$field_column) {

+ 15 - 46
tripal_chado/includes/fields/chado_base__organism_id.inc

@@ -42,7 +42,6 @@ function chado_base__organism_id_attach_info($entity_type, $bundle, $target) {
   $cv_id      = $target['cv_id'];
   $cvterm_id  = $target['cvterm_id'];
 
-
   // Check the schema for the data table if it does not have
   // an 'organism_id' column then we don't want to attach this field.
   $schema = chado_get_schema($table_name);
@@ -190,7 +189,11 @@ function chado_base__organism_id_formatter_settings_form($field, $instance,
   );
   $headers = array('Token', 'Description');
   $rows = array();
-  $tokens = tripal_get_tokens($entity);
+
+  // Here we use the tripal_get_chado_tokens rather than the
+  // tripal_get_entity_tokens because we can't gurantee that all organisms
+  // have entities.
+  $tokens = tripal_get_chado_tokens('organism');
   foreach ($tokens as $token) {
     $rows[] = array(
       $token['token'],
@@ -236,70 +239,36 @@ function chado_base__organism_id_formatter(&$element, $entity_type, $entity,
 
   // Get the settings
   $settings = $display['settings'];
+  $record = $entity->chado_record;
 
   foreach ($items as $delta => $item) {
-    $organism = chado_select_record('organism', array('genus', 'species'), array('organism_id' => $item['value']));
+    $organism = $record->organism_id;
 
-    if ($settings['field_display_teaser'] == 0) {
+    if ($settings['field_display_teaser']) {
+    }
+    else {
       $field_name = $field['field_name'];
       $string = $settings['field_display_string'];
       $field_data = $entity->$field_name;
-      // TODO: add a way to get tokens from Chado records. this is
-      // needed in the case that a record is not published as an entity.
-      $content = tripal_replace_tokens($string, $field_data['und'][0]['entity']);
+      $content = tripal_replace_chado_tokens($string, $organism);
       $element[$delta] = array(
         '#type' => 'markup',
         '#markup' => $content,
       );
     }
-    else {
-
-    }
   }
 }
-
-/**
- * Loads the field values with appropriate data.
- *
- * This function is called by the tripal_chado_field_storage_load() for
- * each property managed by the field_chado_storage storage type.  This is
- * an optional hook function that is only needed if the field has
- * multiple form elements.
- *
- * @param $field
- * @param $entity
- * @param $base_table
- * @param $record
- */
-function chado_base__organism_id_load($field, $entity, $base_table, $record) {
-  $field_name = $field['field_name'];
-
-  // The organism_id is already set as the value. We need to get it and
-  // see if there is a published entity for this organism. If there is
-  // then we want to add the organism object generated using chado_generate_var
-  // as well as the entity to the record.
-  $organism_id = $entity->{$field_name}['und'][0]['value'];
-  $organism = chado_generate_var('organism', array('organism_id' => $organism_id));
-  $entity->{$field_name}['und'][0]['organism'] = $organism;
-  $org_entity = tripal_load_chado_entity('organism', $organism_id);
-  $entity->{$field_name}['und'][0]['entity'] = $org_entity;
-}
 /**
  * Implements hook_ws_formatter().
  */
-function chado_base__organism_id_ws_formatter(&$element, $entity_type, $entity,
+function chado_base__organism_id_ws_formatter($entity_type, $entity,
     $field, $instance, $items) {
 
+  $values = array();
   foreach ($items as $delta => $item) {
-    $organism = $item['organism'];
-    $entity = $item['entity'];
-    if ($entity) {
-      $element[$delta]['#entity'] = $entity;
-    }
-    $element[$delta]['genus'] = $organism->genus;
-    $element[$delta]['species'] = $organism->species;
-    $element[$delta]['common_name'] = $organism->common_name;
+
   }
+  return $values;
 }
 
 /**

+ 1 - 0
tripal_chado/includes/fields/chado_linker__cvterm_adder.inc

@@ -62,6 +62,7 @@ function chado_linker__cvterm_adder_attach_info($entity_type, $bundle, $target)
     'field_settings' => array(
       'base_table' => $table_name,
     ),
+    'cardinality' => 1,
     'storage' => 'field_chado_storage',
     'widget_settings' => array('display_label' => 1),
     'description' => '',

+ 1 - 2
tripal_chado/includes/fields/chado_linker__prop_adder.inc

@@ -47,7 +47,6 @@ function chado_linker__prop_adder_attach_info($entity_type, $bundle, $target) {
   $cv_id      = $target['cv_id'];
   $cvterm_id  = $target['cvterm_id'];
 
-
   // If the linker table does not exists then we don't want to add attach.
   $prop_table = $table_name . 'prop';
   if (!chado_table_exists($prop_table)) {
@@ -62,6 +61,7 @@ function chado_linker__prop_adder_attach_info($entity_type, $bundle, $target) {
     'field_settings' => array(
       'base_table' => $table_name,
     ),
+    'cardinality' => 1,
     'storage' => 'field_chado_storage',
     'widget_settings' => array('display_label' => 1),
     'description' => '',
@@ -70,7 +70,6 @@ function chado_linker__prop_adder_attach_info($entity_type, $bundle, $target) {
     // This feld is never visible so there are no field settings for
     // Chado nor the semantic web.
   );
-
   return $field_info;
 }
 /**

+ 0 - 1
tripal_chado/includes/fields/chado_linker__pub.inc

@@ -73,7 +73,6 @@ function chado_linker__pub_attach_info($entity_type, $bundle, $target) {
       ),
     ),
   );
-
   return $field_info;
 }
 /**

+ 393 - 0
tripal_chado/includes/fields/chado_linker__relationship.inc

@@ -0,0 +1,393 @@
+<?php
+
+/**
+ * Implements hook_info() for fields.
+ *
+ * This is a hook provided by the tripal_chado module for offloading the
+ * hook_field_info() hook for each field to specify.
+ */
+function chado_linker__relationship_info() {
+  return array(
+    'label' => t('Relationships'),
+    'description' => t('Relationships between features.'),
+    'default_widget' => 'chado_linker__relationship_widget',
+    'default_formatter' => 'chado_linker__relationship_formatter',
+    'settings' => array(),
+    'storage' => array(
+      'type' => 'field_chado_storage',
+      'module' => 'tripal_chado',
+      'active' => TRUE
+    ),
+  );
+}
+/**
+ * Implements hook_attach_info().
+ *
+ * This is a hook provided by the tripal_Chado module. It allows the field
+ * to specify which bundles it will attach to and to specify thee settings.
+ *
+ * @param $entity_type
+ * @param $entity
+ * @param $term
+ *
+ * @return
+ *   A field array
+ */
+function chado_linker__relationship_attach_info($entity_type, $bundle, $target) {
+  $field_info = array();
+
+  $table_name = $target['data_table'];
+  $type_table = $target['type_table'];
+  $type_field = $target['field'];
+  $cv_id      = $target['cv_id'];
+  $cvterm_id  = $target['cvterm_id'];
+
+  // If the linker table does not exists then we don't want to add attach.
+  $rel_table = $table_name . '_relationship';
+  if (!chado_table_exists($rel_table)) {
+    return $field_info;
+  }
+
+  $schema = chado_get_schema($rel_table);
+  $pkey = $schema['primary key'][0];
+
+  // Initialize the field array.
+  $field_info = array(
+    'field_name' => $table_name . '__relationship',
+    'field_type' => 'chado_linker__relationship',
+    'widget_type' => 'chado_linker__relationship_widget',
+    'widget_settings' => array('display_label' => 1),
+    'description' => '',
+    'label' => 'Relationsihps',
+    'is_required' => 0,
+    'cardinality' => FIELD_CARDINALITY_UNLIMITED,
+    'storage' => 'field_chado_storage',
+    'field_settings' => array(
+      'chado_table' => $rel_table,
+      'chado_column' => $pkey,
+      'base_table' => $table_name,
+      'semantic_web' => array(
+        'type' => '',
+        'ns' => '',
+        'nsurl' => '',
+      ),
+    ),
+  );
+
+  return $field_info;
+
+}
+/**
+ * Implements hook_widget_info.
+ *
+ * This is a hook provided by the tripal_chado module for offloading
+ * the hook_field_widget_info() hook for each field to specify.
+ */
+function chado_linker__relationship_widget_info() {
+  return array(
+    'label' => t('Relationship Settings'),
+    'field types' => array('chado_linker__relationship')
+  );
+}
+/**
+ * Implements hook_formatter_info.
+ *
+ * This is a hook provided by the tripal_chado module for
+ * offloading the hook_field_formatter_info() for each field
+ * to specify.
+ *
+ */
+function chado_linker__relationship_formatter_info() {
+  return array(
+    'label' => t('Relationships'),
+    'field types' => array('chado_linker__relationship'),
+    'settings' => array(
+    ),
+  );
+}
+
+/**
+ * Implements hook_formatter_settings_summary.
+ *
+ * This is a hook provided by the tripal_chado module for
+ * offloading the hook_field_formatter_settings_summary() for each field
+ * to specify.
+ *
+ */
+function chado_linker__relationship_formatter_settings_summary($field, $instance,
+    $view_mode) {
+
+}
+
+/**
+ * Provides a settings form for the formatter.
+ *
+ * This is a hook provided by the tripal_chado module for
+ * offloading the hook_field_formatter_settings_form() for each field
+ * to specify.
+ */
+function chado_linker__relationship_formatter_settings_form($field, $instance,
+    $view_mode, $form, &$form_state) {
+
+
+
+}
+
+/**
+ * Validation function for the chado_linker_featureloc_formatter_settings_form.
+ */
+function chado_linker__relationship_formatter_settings_form_validate(&$form, &$form_state) {
+
+  // Place here as an example for validating the settings form.
+}
+
+/**
+ * TODO: because this field is meant to handle any xxxxx_relationship table
+ * then feature hard-coding needs to be replaced as it won't work for
+ * stocks, etc.
+ */
+function chado_linker__relationship_formatter(&$element, $entity_type, $entity,
+    $field, $instance, $langcode, $items, $display) {
+
+  // Get the settings
+  $settings = $display['settings'];
+  $record = $entity->chado_record;
+
+  foreach ($items as $delta => $item) {
+
+    $all_relationships = $item['all_relationships'];
+    $object_rels = $all_relationships['object'];
+    $subject_rels = $all_relationships['subject'];
+    $content = '';
+
+    if (count($object_rels) > 0 or count($subject_rels) > 0) {
+
+      // first add in the subject relationships.
+      foreach ($subject_rels as $rel_type => $rels){
+        foreach ($rels as $obj_type => $objects){
+
+          // Make the verb in the sentence make sense in English.
+          switch ($rel_type) {
+            case 'integral part of':
+            case 'instance of':
+              $verb = 'is an';
+              break;
+            case 'proper part of':
+            case 'transformation of':
+            case 'genome of':
+            case 'part of':
+            case 'position of':
+            case 'sequence of':
+            case 'variant of':
+              $verb = 'is a';
+              break;
+            case 'derives from':
+            case 'connects on':
+            case 'contains':
+            case 'finishes':
+            case 'guides':
+            case 'has origin':
+            case 'has part':
+            case 'has quality':
+            case 'is consecutive sequence of':
+            case 'maximally overlaps':
+            case 'overlaps':
+            case 'starts':
+              $verb = '';
+              break;
+            default:
+              $verb = 'is';
+          }
+
+          // the $headers array is an array of fields to use as the colum headers.
+          // additional documentation can be found here
+          // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+          $headers = array('Feature Name' ,'Unique Name', 'Species', 'Type');
+
+          // the $rows array contains an array of rows where each row is an array
+          // of values for each column of the table in that row.  Additional documentation
+          // can be found here:
+          // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+          $rows = array();
+
+          foreach ($objects as $object){
+            // link the feature to it's node
+            $feature_name = $object->record->object_id->name;
+            if (property_exists($object->record, 'nid')) {
+              $feature_name = l($feature_name, "node/" . $object->record->nid, array('attributes' => array('target' => "_blank")));
+            }
+            // link the organism to it's node
+            $organism = $object->record->object_id->organism_id;
+            $organism_name = $organism->genus ." " . $organism->species;
+            if (property_exists($organism, 'nid')) {
+              $organism_name = l("<i>" . $organism->genus . " " . $organism->species . "</i>", "node/" . $organism->nid, array('html' => TRUE));
+            }
+            $rows[] = array(
+              array('data' => $feature_name, 'width' => '30%'),
+              array('data' => $object->record->object_id->uniquename, 'width' => '30%'),
+              array('data' => $organism_name, 'width' => '30%'),
+              array('data' => $object->record->object_id->type_id->name, 'width' => '10%'),
+            );
+           }
+           // the $table array contains the headers and rows array as well as other
+           // options for controlling the display of the table.  Additional
+           // documentation can be found here:
+           // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+           $table = array(
+             'header' => $headers,
+             'rows' => $rows,
+             'attributes' => array(
+               'id' => 'tripal_feature-table-relationship-object',
+               'class' => 'tripal-data-table'
+             ),
+             'sticky' => FALSE,
+             'caption' => "This " . $record->type_id->name . " $verb  $rel_type the following  <b>$obj_type</b> feature(s):",
+             'colgroups' => array(),
+             'empty' => '',
+           );
+
+           // once we have our table array structure defined, we call Drupal's theme_table()
+           // function to generate the table.
+           $content .= theme_table($table);
+         }
+      }
+
+      // second add in the object relationships.
+      foreach ($object_rels as $rel_type => $rels){
+        foreach ($rels as $subject_type => $subjects){
+
+          // Make the verb in the sentence make sense in English.
+          switch ($rel_type) {
+            case 'integral part of':
+            case 'instance of':
+              $verb = 'are an';
+              break;
+            case 'proper part of':
+            case 'transformation of':
+            case 'genome of':
+            case 'part of':
+            case 'position of':
+            case 'sequence of':
+            case 'variant of':
+              $verb = 'are a';
+              break;
+            case 'derives from':
+            case 'connects on':
+            case 'contains':
+            case 'finishes':
+            case 'guides':
+            case 'has origin':
+            case 'has part':
+            case 'has quality':
+            case 'is consecutive sequence of':
+            case 'maximally overlaps':
+            case 'overlaps':
+            case 'starts':
+              $verb = '';
+              break;
+            default:
+              $verb = 'are';
+          }
+
+          // the $headers array is an array of fields to use as the colum headers.
+          // additional documentation can be found here
+          // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+          $headers = array('Feature Name' ,'Unique Name', 'Species', 'Type');
+
+          // the $rows array contains an array of rows where each row is an array
+          // of values for each column of the table in that row.  Additional documentation
+          // can be found here:
+          // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+          $rows = array();
+
+          foreach ($subjects as $subject){
+            // link the feature to it's node
+            $feature_name = $subject->record->subject_id->name;
+            if (property_exists($subject->record, 'nid')) {
+              $feature_name = l($feature_name, "node/" . $subject->record->nid, array('attributes' => array('target' => "_blank")));
+            }
+            // link the organism to it's node
+            $organism = $subject->record->subject_id->organism_id;
+            $organism_name = $organism->genus ." " . $organism->species;
+            if (property_exists($organism, 'nid')) {
+              $organism_name = l("<i>" . $organism->genus . " " . $organism->species . "</i>", "node/" . $organism->nid, array('html' => TRUE));
+            }
+            $rows[] = array(
+              array('data' => $feature_name, 'width' => '30%'),
+              array('data' =>$subject->record->subject_id->uniquename, 'width' => '30%'),
+              array('data' =>$organism_name, 'width' => '30%'),
+              array('data' =>$subject->record->subject_id->type_id->name, 'width' => '10%'),
+            );
+           }
+           // the $table array contains the headers and rows array as well as other
+           // options for controlling the display of the table.  Additional
+           // documentation can be found here:
+           // https://api.drupal.org/api/drupal/includes%21theme.inc/function/theme_table/7
+           $table = array(
+             'header' => $headers,
+             'rows' => $rows,
+             'attributes' => array(
+               'id' => 'tripal_feature-table-relationship-subject',
+               'class' => 'tripal-data-table'
+             ),
+             'sticky' => FALSE,
+             'caption' => "The following <b>" . $subjects[0]->record->subject_id->type_id->name . " </b> feature(s) $verb $rel_type this " . $record->type_id->name . ":",
+             'colgroups' => array(),
+             'empty' => '',
+           );
+
+           // once we have our table array structure defined, we call Drupal's theme_table()
+           // function to generate the table.
+           $content .= theme_table($table);
+         }
+      }
+    }
+
+    // once we have our table array structure defined, we call Drupal's theme_table()
+    // function to generate the table.
+    $element[$delta] = array(
+      '#type' => 'markup',
+      '#markup' => $content,
+    );
+  }
+}
+
+/**
+ * Loads the field values with appropriate data.
+ *
+ * This function is called by the tripal_chado_field_storage_load() for
+ * each property managed by the field_chado_storage storage type.  This is
+ * an optional hook function that is only needed if the field has
+ * multiple form elements.
+ */
+function chado_linker__relationship_load($field, $entity, $base_table, $record) {
+  $field_name = $field['field_name'];
+
+
+  $entity->{$field_name}['und'][0]['all_relationships'] = tripal_get_feature_relationships($record);
+}
+
+
+/**
+ * Implements hook_ws_formatter().
+ */
+// function chado_linker__relationship_ws_formatter(&$element, $entity_type, $entity,
+//     $field, $instance, $items) {
+
+//   foreach ($items as $delta => $item) {
+
+//   }
+// }
+
+/**
+ *  Implements hook_widget().
+ */
+function chado_linker__relationship_widget(&$widget, $form, $form_state, $field, $instance, $langcode, $items, $delta, $element) {
+
+}
+/**
+ * Callback function for validating the chado_linker_featureloc_widget.
+ */
+function chado_linker__relationship_widget_validate($element, &$form_state) {
+
+}

+ 5 - 0
tripal_chado/includes/tripal_chado.field_storage.inc

@@ -270,6 +270,7 @@ function tripal_chado_field_storage_load($entity_type, $entities, $age,
     $columns = array('*');
     $match = array($pkey_field => $record_id);
     $record = chado_generate_var($base_table, $match);
+    $entity->chado_record = $record;
 
     // For now, expand all 'text' fields.
     // TODO: we want to be a bit smarter and allow the user to configure this
@@ -322,6 +323,7 @@ function tripal_chado_field_storage_load($entity_type, $entities, $age,
             $entity->{$field_name}['und'][0]['value'] = $record->$field_column;
           }
         }
+
         // Allow the creating module to alter the value if desired.  The
         // module should do this if the field has any other form elements
         // that need populationg besides the default value.
@@ -336,6 +338,9 @@ function tripal_chado_field_storage_load($entity_type, $entities, $age,
       // of form elements that might need populating so we'll offload the
       // loading of these fields to the field itself.
       if ($field_table != $base_table) {
+
+
+
         // Set an empty value by default, and let the hook function update it.
         $entity->{$field_name}['und'][0]['value'] = '';
         $load_function = $field_type . '_load';

+ 48 - 299
tripal_chado/includes/tripal_chado.fields.inc

@@ -507,6 +507,39 @@ function tripal_chado_form_field_ui_field_overview_form_alter(&$form, &$form_sta
   }
 }
 
+/**
+ * Implements hook_field_ws_formatter().
+ *
+ * The hook function is called by the tripal_ws module which provides
+ * the RESTful web services. If that module is not installed this function
+ * is never use.d
+ */
+function tripal_chado_field_ws_formatter($entity_type, $entity, $field_info,
+    $field, $items){
+
+  $values = array();
+
+  // Only deal with fields that were created by this module.
+  if ($field_info['storage']['type'] != 'field_chado_storage') {
+    return $values;
+  }
+
+  // See if the field file defines a formatter.
+  $field_type = $field_info['type'];
+  $function = $field_type . '_ws_formatter';
+  module_load_include('inc', 'tripal_chado', 'includes/fields/' . $field_type);
+
+  if (function_exists($function)) {
+    $values = $function($entity_type, $entity, $field_info, $field, $items);
+  }
+
+  // If no customizations exist then perform some default formatting
+  if (count($values) == 0) {
+  }
+
+  return $values;
+}
+
 /**
  * Implements hook_field_is_empty().
  */
@@ -612,318 +645,34 @@ function tripal_chado_add_bundle_fields($entity_type, $bundle, $term) {
   tripal_set_bundle_variable('chado_column', $bundle->id, $bundle_data['field']);
 
 
-
   // Call the hook_attach_info() for all Chado fields to see if any of them
   // want to attach themsevles to this bundle.
-  $fields = field_info_fields();
-  foreach ($fields as $field) {
-    $field_type = $field['type'];
-    if ($field['storage']['type'] == 'field_chado_storage') {
-      module_load_include('inc', 'tripal_chado', 'includes/fields/' . $field_type);
-      $function = $field_type . '_attach_info';
-
-      if (function_exists($function)) {
-        // Get the field info.
-        $field_info = $function($entity_type, $bundle, $bundle_data);
-        if (!is_array($field_info) or count(array_keys($field_info)) == 0) {
-          continue;
-        }
-
-        $field_name = $field_info['field_name'];
-        tripal_add_bundle_field($field_name, $field_info, $entity_type, $bundle_name);
+  // Iterate through the fields, include the file and run the info function.
+  $fields_path = drupal_get_path('module', 'tripal_chado') . '/includes/fields';
+  $field_files = file_scan_directory($fields_path, '/^chado_.*\.inc$/');
+  foreach ($field_files as $file) {
+    $field_type = $file->name;
+    module_load_include('inc', 'tripal_chado', 'includes/fields/' . $field_type);
+    $function = $field_type . '_attach_info';
+    if (function_exists($function)) {
+      // Get the field info.
+      $field_info = $function($entity_type, $bundle, $bundle_data);
+      if (!is_array($field_info) or count(array_keys($field_info)) == 0) {
+        continue;
       }
+      $field_name = $field_info['field_name'];
+      tripal_add_bundle_field($field_name, $field_info, $entity_type, $bundle_name);
     }
   }
 
   // Adds any remaining base fields that may not have been dealt with
   // by a custom field.
-  //tripal_chado_add_bundle_fields_base__fields($entity_type, $bundle_name, $bundle_data);
-
-
-}
-
-/**
- * Adds the fields for managing xrefs that are stored in a [base]_dbxref table.
- *
- * @param $entity_type
- * @param $bundle_name
- * @param $base_table
- * @param $dbxref_table
- */
-function tripal_chado_add_bundle_fields_linker__dbxref_field($entity_type_name, $bundle_name, $dbxref_table, $base_table) {
-  // We already have a dbxref_id field.
-  $field_name = $dbxref_table;
-  $schema = chado_get_schema($dbxref_table);
-  $pkey = $schema['primary key'][0];
-
-  // Initialize the field array.
-  $field_info = array(
-    'field_type' => 'chado_linker__dbxref',
-    'widget_type' => 'chado_linker__dbxref_widget',
-    'widget_settings' => array('display_label' => 1),
-    'description' => '',
-    'label' => 'Cross References',
-    'is_required' => 0,
-    'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-    'storage' => 'field_chado_storage',
-    'field_settings' => array(
-      // The Chado table that this field maps to.
-      'chado_table' => $dbxref_table,
-      // The column in the chado table that this field maps to.
-      'chado_column' => $pkey,
-      // The base table that this field is connected to.
-      'base_table' => $base_table,
-      'semantic_web' => array(
-        // The type is the term from a vocabulary that desribes this field..
-        'type' => '',
-        // The namepsace for the vocabulary (e.g. 'foaf').
-        'ns' => '',
-        // The URL for the namespace.  It must be that the type can be
-        // appended to the URL.
-        'nsurl' => '',
-      ),
-    ),
-  );
-
-  // If the base table has a 'dbxref_id' then change the label to
-  // indicate these are secondary cross references.
-  $schema = chado_get_schema($base_table);
-  if (array_key_exists('dbxref_id', $schema['fields'])) {
-    $field_info['label'] = 'Secondary Cross References';
-  }
-  tripal_add_bundle_field($field_name, $field_info, $entity_type_name, $bundle_name);
-}
-/**
- * Adds the fields for managing xrefs that are stored in a [base]_dbxref table.
- *
- * @param $entity_type
- * @param $bundle_name
- * @param $base_table
- * @param $dbxref_table
- */
-function tripal_chado_add_bundle_fields_linker__synonym_field($entity_type_name, $bundle_name, $syn_table, $base_table) {
-  // We already have a dbxref_id field.
-  $field_name = $syn_table;
-  $schema = chado_get_schema($syn_table);
-  $pkey = $schema['primary key'][0];
-
-  // Initialize the field array.
-  $field_info = array(
-    'field_type' => 'chado_linker__synonym',
-    'widget_type' => 'chado_linker__synonym_widget',
-    'widget_settings' => array('display_label' => 1),
-    'description' => '',
-    'label' => 'Synonyms',
-    'is_required' => 0,
-    'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-    'storage' => 'field_chado_storage',
-    'field_settings' => array(
-      // The Chado table that this field maps to.
-      'chado_table' => $syn_table,
-      // The column in the chado table that this field maps to.
-      'chado_column' => $pkey,
-      // The base table that this field is connected to.
-      'base_table' => $base_table,
-      'semantic_web' => array(
-        // The type is the term from a vocabulary that desribes this field..
-        'type' => '',
-        // The namepsace for the vocabulary (e.g. 'foaf').
-        'ns' => '',
-        // The URL for the namespace.  It must be that the type can be
-        // appended to the URL.
-        'nsurl' => '',
-      ),
-    ),
-  );
-
-  tripal_add_bundle_field($field_name, $field_info, $entity_type_name, $bundle_name);
-}
-/**
- * Adds the fields for managing xrefs that are stored in a [base]_dbxref table.
- *
- * @param $entity_type
- * @param $bundle_name
- * @param $base_table
- * @param $dbxref_table
- */
-function tripal_chado_add_bundle_fields_linker__featureloc_field($entity_type_name, $bundle_name) {
-  $field_name = 'featureloc';
-  $schema = chado_get_schema('featureloc');
-  $pkey = $schema['primary key'][0];
-
-  // Initialize the field array.
-  $field_info = array(
-    'field_type' => 'chado_linker__featureloc',
-    'widget_type' => 'chado_linker__featureloc_widget',
-    'widget_settings' => array('display_label' => 1),
-    'description' => '',
-    'label' => 'Alignments',
-    'is_required' => 0,
-    'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-    'storage' => 'field_chado_storage',
-    'field_settings' => array(
-      // The Chado table that this field maps to.
-      'chado_table' => 'featureloc',
-      // The column in the chado table that this field maps to.
-      'chado_column' => $pkey,
-      // The base table that this field is connected to.
-      'base_table' => 'feature',
-      'semantic_web' => array(
-        // The type is the term from a vocabulary that desribes this field..
-        'type' => '',
-        // The namepsace for the vocabulary (e.g. 'foaf').
-        'ns' => '',
-        // The URL for the namespace.  It must be that the type can be
-        // appended to the URL.
-        'nsurl' => '',
-      ),
-    ),
-  );
+  tripal_chado_add_bundle_fields_base__fields($entity_type, $bundle_name, $bundle_data);
 
-  tripal_add_bundle_field($field_name, $field_info, $entity_type_name, $bundle_name);
-}
-/**
- * Adds the fields for managing relationships that are stored in a [base]_relationship table.
- *
- * @param $entity_type
- * @param $bundle_name
- * @param $base_table
- * @param $dbxref_table
- */
-function tripal_chado_add_bundle_fields_linker__relationship_field(
-    $entity_type_name, $bundle_name, $rel_table, $base_table) {
-
-  $field_name = $rel_table;
-  $schema = chado_get_schema($rel_table);
-  $pkey = $schema['primary key'][0];
-
-  // Initialize the field array.
-  $field_info = array(
-    'field_type' => 'chado_linker__relationship',
-    'widget_type' => 'chado_linker__relationship_widget',
-    'widget_settings' => array('display_label' => 1),
-    'description' => '',
-    'label' => 'Relationsihps',
-    'is_required' => 0,
-    'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-    'storage' => 'field_chado_storage',
-    'field_settings' => array(
-      // The Chado table that this field maps to.
-      'chado_table' => $rel_table,
-      // The column in the chado table that this field maps to.
-      'chado_column' => $pkey,
-      // The base table that this field is connected to.
-      'base_table' => $base_table,
-      'semantic_web' => array(
-        // The type is the term from a vocabulary that desribes this field..
-        'type' => '',
-        // The namepsace for the vocabulary (e.g. 'foaf').
-        'ns' => '',
-        // The URL for the namespace.  It must be that the type can be
-        // appended to the URL.
-        'nsurl' => '',
-      ),
-    ),
-  );
 
-  tripal_add_bundle_field($field_name, $field_info, $entity_type_name, $bundle_name);
 }
-/**
- * Adds the fields for managing xrefs that are stored in a [base]_dbxref table.
- *
- * @param $entity_type
- * @param $bundle_name
- * @param $base_table
- * @param $dbxref_table
- */
-function tripal_chado_add_bundle_fields_linker__pub_field($entity_type_name, $bundle_name, $pub_table, $base_table) {
-  // We already have a dbxref_id field.
-  $field_name = $pub_table;
-  $schema = chado_get_schema($pub_table);
-  $pkey = $schema['primary key'][0];
-
-  // Initialize the field array.
-  $field_info = array(
-    'field_type' => 'chado_linker__pub',
-    'widget_type' => 'chado_linker__pub_widget',
-    'widget_settings' => array('display_label' => 1),
-    'description' => '',
-    'label' => 'Publications',
-    'is_required' => 0,
-    'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-    'storage' => 'field_chado_storage',
-    'field_settings' => array(
-      // The Chado table that this field maps to.
-      'chado_table' => $pub_table,
-      // The column in the chado table that this field maps to.
-      'chado_column' => $pkey,
-      // The base table that this field is connected to.
-      'base_table' => $base_table,
-      'semantic_web' => array(
-        // The type is the term from a vocabulary that desribes this field..
-        'type' => '',
-        // The namepsace for the vocabulary (e.g. 'foaf').
-        'ns' => '',
-        // The URL for the namespace.  It must be that the type can be
-        // appended to the URL.
-        'nsurl' => '',
-      ),
-    ),
-  );
 
-  tripal_add_bundle_field($field_name, $field_info, $entity_type_name, $bundle_name);
-}
-/**
- * Adds the fields for managing properties that are stored in a prop table.
- *
- * @param $entity_type_name
- * @param $bundle_name
- * @param $kv_table
- */
-function tripal_chado_add_bundle_fields_linker__prop_adder_field($entity_type_name, $bundle_name, $kv_table, $base_table) {
-  $field_name = $kv_table;
 
-  // Initialize the field array.
-  $field_info = array(
-    'field_type' => 'chado_linker__prop_adder',
-    'widget_type' => 'chado_linker__prop_adder_widget',
-    'field_settings' => array(
-      'base_table' => $base_table,
-    ),
-    'storage' => 'field_chado_storage',
-    'widget_settings' => array('display_label' => 1),
-    'description' => '',
-    'label' => 'Additional Properties',
-    'is_required' => 0,
-  );
-  tripal_add_bundle_field($field_name, $field_info, $entity_type_name, $bundle_name);
-}
-/**
- * Adds the fields for managing properties that are stored in a prop table.
- *
- * @param $entity_type_name
- * @param $bundle_name
- * @param $kv_table
- */
-function tripal_chado_add_bundle_fields_linker__cvterm_adder_field($entity_type_name, $bundle_name, $cvterm_table, $base_table) {
-  // First add a generic property field so that users can add new property types.
-  $field_name = $cvterm_table;
-
-  // Initialize the field array.
-  $field_info = array(
-    'field_type' => 'chado_linker__cvterm_adder',
-    'widget_type' => 'chado_linker__cvterm_adder_widget',
-    'field_settings' => array(
-      'base_table' => $base_table,
-    ),
-    'storage' => 'field_chado_storage',
-    'widget_settings' => array('display_label' => 1),
-    'description' => '',
-    'label' => 'Additional Annotation Types',
-    'is_required' => 0,
-  );
-  tripal_add_bundle_field($field_name, $field_info, $entity_type_name, $bundle_name);
-}
 /**
  * Adds the fields for the base table to the entity.
  */

+ 10 - 0
tripal_chado/includes/tripal_chado.term_storage.inc

@@ -135,9 +135,19 @@ function tripal_chado_vocab_select_term_form($form, &$form_state) {
     $terms = chado_expand_var($terms, 'field', 'cvterm.definition');
     $num_terms = 0;
     foreach ($terms as $term) {
+      // Save the user a click by setting the default value as 1 if there's
+      // only one matching term.
+      $default = FALSE;
+      $attrs = array();
+      if ($num_terms == 0 and count($terms) == 1) {
+        $default = TRUE;
+        $attrs = array('checked' => 'checked');
+      }
        $form['terms_list']['term-' . $term->cvterm_id] = array(
          '#type' => 'checkbox',
          '#title' =>  $term->name,
+         '#default_value' => $default,
+         '#attributes' => $attrs,
          '#description' => '<b>Vocabulary:</b> ' . $term->cv_id->name .
              '<br><b>Term: </b> ' . $term->dbxref_id->db_id->name . ':' . $term->dbxref_id->accession . '.  ' .
              '<br><b>Definition:</b>  ' . $term->definition,

+ 10 - 39
tripal_ws/includes/tripal_ws.rest.inc

@@ -490,46 +490,17 @@ function tripal_ws_get_content($api_url, &$response, $ws_args, $ctype, $entity_i
     }
 
     // We want to allow the field to format itself for web services if it
-    // wants to.  The file can do so if it implements a '_ws_formatter'
-    // function.
-    $function = $field_info['type'] . '_ws_formatter';
-    module_load_include('inc', $field['display']['default']['module'], 'includes/fields/' . $field_info['type']);
-    if (function_exists($function)) {
-      $values = array();
-      $function($values, $entity->type, $entity, $field_info, $field, $items);
-
-      // Iterate through the key/values returned and handle hashed keys
-      $add_vals = array();
-      for ($i = 0; $i < count($values); $i++) {
-        foreach ($values[$i] as $skey => $svalue) {
-          // If the key is '#entity' then this should like to another
-          // services.
-          if ($skey == '#entity') {
-            $sentity = $svalue;
-            $sbundle = tripal_load_bundle_entity(array('name' => $sentity->bundle));
-            $sterm = tripal_load_term_entity(array('term_id' => $sbundle->term_id));
-            $vocab = $sterm->vocab;
-            $add_vals['@id'] = $api_url . '/content/' . urlencode($sterm->name) . '/' . $sentity->id;
-            $add_vals['@type'] = $vocab->namespace . ':' . $sterm->name;
-            unset($values[$i][$skey]);
-          }
-        }
-        $values[$i] = array_merge($add_vals, $values[$i]);
-      }
+    // wants to.  If the module implements the hook_field_ws_formatter()
+    // then we'll retrieve the values from it.
+    $field_module = $field_info['storage']['module'];
+    $function = $field_module . '_field_ws_formatter';
+    $values = array();
 
-
-      if (count($values) == 0) {
-        $response[$key] = '';
-      }
-      if (count($values) == 1) {
-        $response[$key] = $values[0];
-      }
-      else {
-        $response[$key] = $values;
-      }
+    if (function_exists($function)) {
+      $values = $function($entity->type, $entity, $field_info, $field, $items);
     }
-    // If a function doesn't exist then just show the default value is is.
-    else {
+
+    if (count($values) == 0) {
       // Get the values based on cardinality
       if (count($items) == 1) {
         $values = $items[0]['value'];
@@ -541,8 +512,8 @@ function tripal_ws_get_content($api_url, &$response, $ws_args, $ctype, $entity_i
           $values[] = $items[$i]['value'];
         }
       }
-      $response[$key] = $values;
     }
+    $response[$key] = $values;
   }
 
  //$response['fields'] = $fields;