Browse Source

merge fix

Shawna 7 năm trước cách đây
mục cha
commit
57e2916b36
99 tập tin đã thay đổi với 4107 bổ sung2227 xóa
  1. 1 1
      legacy/tripal_cv/theme/templates/tripal_cv_help.tpl.php
  2. 10 3
      tripal/api/tripal.entities.api.inc
  3. 2 1
      tripal/includes/TripalBundleUIController.inc
  4. 1 1
      tripal/includes/TripalEntityUIController.inc
  5. 29 13
      tripal/includes/TripalFields/TripalField.inc
  6. 1 1
      tripal/includes/TripalFields/TripalFieldWidget.inc
  7. 38 2
      tripal/includes/TripalImporter.inc
  8. 14 3
      tripal/includes/TripalJob.inc
  9. 4 0
      tripal/includes/tripal.entity.inc
  10. 5 2
      tripal/includes/tripal.fields.inc
  11. 1 0
      tripal/tripal.info
  12. 37 1
      tripal/tripal.module
  13. 24 6
      tripal/tripal.views_default.inc
  14. 39 62
      tripal/tripal_views_query.inc
  15. 187 0
      tripal/views_handlers/tripal_views_handler_filter_numeric.inc
  16. 2 6
      tripal/views_handlers/tripal_views_handler_filter_string.inc
  17. 14 8
      tripal_chado/api/modules/tripal_chado.cv.api.inc
  18. 4 0
      tripal_chado/api/modules/tripal_chado.db.api.inc
  19. 32 16
      tripal_chado/api/modules/tripal_chado.pub.api.inc
  20. 1 1
      tripal_chado/api/tripal_chado.mviews.api.inc
  21. 12 5
      tripal_chado/api/tripal_chado.query.api.inc
  22. 21 0
      tripal_chado/includes/TripalFields/ChadoField.inc
  23. 75 17
      tripal_chado/includes/TripalFields/chado_linker__contact/chado_linker__contact.inc
  24. 31 34
      tripal_chado/includes/TripalFields/chado_linker__contact/chado_linker__contact_widget.inc
  25. 0 178
      tripal_chado/includes/TripalFields/chado_linker__cvterm/chado_linker__cvterm.inc
  26. 0 132
      tripal_chado/includes/TripalFields/chado_linker__cvterm/chado_linker__cvterm_formatter.inc
  27. 0 176
      tripal_chado/includes/TripalFields/chado_linker__cvterm/chado_linker__cvterm_widget.inc
  28. 23 0
      tripal_chado/includes/TripalFields/chado_linker__prop/chado_linker__prop.inc
  29. 38 28
      tripal_chado/includes/TripalFields/chado_linker__prop/chado_linker__prop_widget.inc
  30. 29 17
      tripal_chado/includes/TripalFields/data__accession/data__accession.inc
  31. 58 73
      tripal_chado/includes/TripalFields/data__accession/data__accession_widget.inc
  32. 11 4
      tripal_chado/includes/TripalFields/data__protein_sequence/data__protein_sequence.inc
  33. 1 8
      tripal_chado/includes/TripalFields/data__protein_sequence/data__protein_sequence_formatter.inc
  34. 4 10
      tripal_chado/includes/TripalFields/data__protein_sequence/data__protein_sequence_widget.inc
  35. 15 3
      tripal_chado/includes/TripalFields/data__sequence/data__sequence_widget.inc
  36. 9 9
      tripal_chado/includes/TripalFields/data__sequence_checksum/data__sequence_checksum_widget.inc
  37. 106 30
      tripal_chado/includes/TripalFields/data__sequence_coordinates/data__sequence_coordinates.inc
  38. 11 18
      tripal_chado/includes/TripalFields/data__sequence_coordinates/data__sequence_coordinates_formatter.inc
  39. 0 7
      tripal_chado/includes/TripalFields/data__sequence_length/data__sequence_length_formatter.inc
  40. 9 7
      tripal_chado/includes/TripalFields/data__sequence_length/data__sequence_length_widget.inc
  41. 0 7
      tripal_chado/includes/TripalFields/go__gene_expression/go__gene_expression_formatter.inc
  42. 37 8
      tripal_chado/includes/TripalFields/local__source_data/local__source_data.inc
  43. 7 3
      tripal_chado/includes/TripalFields/local__source_data/local__source_data_formatter.inc
  44. 40 15
      tripal_chado/includes/TripalFields/local__source_data/local__source_data_widget.inc
  45. 2 9
      tripal_chado/includes/TripalFields/obi__organism/obi__organism.inc
  46. 2 2
      tripal_chado/includes/TripalFields/obi__organism/obi__organism_widget.inc
  47. 0 8
      tripal_chado/includes/TripalFields/ogi__location_on_map/ogi__location_on_map_formatter.inc
  48. 58 43
      tripal_chado/includes/TripalFields/sbo__database_cross_reference/sbo__database_cross_reference.inc
  49. 17 12
      tripal_chado/includes/TripalFields/sbo__database_cross_reference/sbo__database_cross_reference_formatter.inc
  50. 39 123
      tripal_chado/includes/TripalFields/sbo__database_cross_reference/sbo__database_cross_reference_widget.inc
  51. 2 2
      tripal_chado/includes/TripalFields/sbo__phenotype/sbo__phenotype.inc
  52. 0 8
      tripal_chado/includes/TripalFields/sbo__phenotype/sbo__phenotype_formatter.inc
  53. 274 369
      tripal_chado/includes/TripalFields/sbo__relationship/sbo__relationship.inc
  54. 10 4
      tripal_chado/includes/TripalFields/sbo__relationship/sbo__relationship_widget.inc
  55. 38 1
      tripal_chado/includes/TripalFields/schema__additional_type/schema__additional_type.inc
  56. 8 13
      tripal_chado/includes/TripalFields/schema__additional_type/schema__additional_type_formatter.inc
  57. 83 1
      tripal_chado/includes/TripalFields/schema__additional_type/schema__additional_type_widget.inc
  58. 36 13
      tripal_chado/includes/TripalFields/schema__alternate_name/schema__alternate_name.inc
  59. 3 10
      tripal_chado/includes/TripalFields/schema__alternate_name/schema__alternate_name_formatter.inc
  60. 55 35
      tripal_chado/includes/TripalFields/schema__alternate_name/schema__alternate_name_widget.inc
  61. 0 43
      tripal_chado/includes/TripalFields/schema__publication/schema__publication.inc
  62. 2 15
      tripal_chado/includes/TripalFields/schema__publication/schema__publication_formatter.inc
  63. 37 31
      tripal_chado/includes/TripalFields/schema__publication/schema__publication_widget.inc
  64. 346 0
      tripal_chado/includes/TripalFields/sio__annotation/sio__annotation.inc
  65. 78 0
      tripal_chado/includes/TripalFields/sio__annotation/sio__annotation_formatter.inc
  66. 293 0
      tripal_chado/includes/TripalFields/sio__annotation/sio__annotation_widget.inc
  67. 0 30
      tripal_chado/includes/TripalFields/sio__references/sio__references.inc
  68. 0 9
      tripal_chado/includes/TripalFields/sio__references/sio__references_formatter.inc
  69. 1 1
      tripal_chado/includes/TripalFields/sio__vocabulary/sio__vocabulary.inc
  70. 29 2
      tripal_chado/includes/TripalFields/sio__vocabulary/sio__vocabulary_widget.inc
  71. 0 7
      tripal_chado/includes/TripalFields/so__genotype/so__genotype.inc
  72. 0 8
      tripal_chado/includes/TripalFields/so__genotype/so__genotype_formatter.inc
  73. 0 8
      tripal_chado/includes/TripalFields/so__transcript/so__transcript_formatter.inc
  74. 92 6
      tripal_chado/includes/TripalFields/taxrank__infraspecific_taxon/taxrank__infraspecific_taxon.inc
  75. 16 8
      tripal_chado/includes/TripalFields/taxrank__infraspecific_taxon/taxrank__infraspecific_taxon_formatter.inc
  76. 74 14
      tripal_chado/includes/TripalFields/taxrank__infraspecific_taxon/taxrank__infraspecific_taxon_widget.inc
  77. 5 0
      tripal_chado/includes/TripalFields/uo__unit/uo__unit.inc
  78. 42 1
      tripal_chado/includes/TripalFields/uo__unit/uo__unit_widget.inc
  79. 19 25
      tripal_chado/includes/TripalImporter/OBOImporter.inc
  80. 25 2
      tripal_chado/includes/setup/tripal_chado.setup.inc
  81. 13 0
      tripal_chado/includes/tripal_chado.cv.inc
  82. 5 0
      tripal_chado/includes/tripal_chado.db.inc
  83. 12 4
      tripal_chado/includes/tripal_chado.field_storage.inc
  84. 331 200
      tripal_chado/includes/tripal_chado.fields.inc
  85. 2 4
      tripal_chado/includes/tripal_chado.publish.inc
  86. 61 13
      tripal_chado/includes/tripal_chado.semweb.inc
  87. 1 0
      tripal_chado/theme/css/tripal_chado.css
  88. 130 0
      tripal_chado/tripal_chado.install
  89. 1 1
      tripal_chado/tripal_chado.module
  90. 0 4
      tripal_chado/tripal_chado.views_default.inc
  91. 11 3
      tripal_ds/includes/tripal_ds.ds.inc
  92. 0 1
      tripal_ds/tripal_ds.install
  93. 16 5
      tripal_ws/includes/TripalWebService.inc
  94. 0 19
      tripal_ws/includes/TripalWebService/TripalDocService_V0_1.inc
  95. 546 116
      tripal_ws/includes/TripalWebService/TripalEntityService_v0_1.inc
  96. 138 1
      tripal_ws/includes/TripalWebService/TripalVocabService_v0_1.inc
  97. 28 6
      tripal_ws/includes/TripalWebServiceCollection.inc
  98. 116 52
      tripal_ws/includes/TripalWebServiceResource.inc
  99. 27 19
      tripal_ws/tripal_ws.module

+ 1 - 1
legacy/tripal_cv/theme/templates/tripal_cv_help.tpl.php

@@ -15,7 +15,7 @@
    users access to view content and create a special role for creating, editing and other administrative tasks.</p></li>
    users access to view content and create a special role for creating, editing and other administrative tasks.</p></li>
 
 
       <li><p><b>Loading of Ontologies/Controlled Vocabularies</b>: You can access this loader at <?php
       <li><p><b>Loading of Ontologies/Controlled Vocabularies</b>: You can access this loader at <?php
-        print l('Admin->Tripal Management->Tripal CV->Load Ontology With OBO File', 'admin/tripal/tripal_cv/obo_loader')
+        print l('Admin->Tripal Management->Tripal CV->Load Ontology With OBO File', 'admin/tripal/loaders/chado_obo_loader')
         ?>. This loader allows you to choose from a list of common ontologies or
         ?>. This loader allows you to choose from a list of common ontologies or
         enter the URL or location to an OBO file. Even the list of common
         enter the URL or location to an OBO file. Even the list of common
         ontologies is using a URL ensuring you get the most up to date ontology.</p>
         ontologies is using a URL ensuring you get the most up to date ontology.</p>

+ 10 - 3
tripal/api/tripal.entities.api.inc

@@ -1056,7 +1056,9 @@ function tripal_replace_entity_tokens($string, &$entity, $bundle_entity = NULL)
       // Note: there is a memory leak in field_get_items() so we can't use it
       // Note: there is a memory leak in field_get_items() so we can't use it
       // here or bulk publising will slowly erode memory.
       // here or bulk publising will slowly erode memory.
       //$field_value = field_get_items('TripalEntity', $entity, $field_name);
       //$field_value = field_get_items('TripalEntity', $entity, $field_name);
-      $value = $entity->{$field_name}['und'][0]['value'];
+      if (array_key_exists(0, $entity->{$field_name}['und'])) {
+        $value = $entity->{$field_name}['und'][0]['value'];
+      }
       // TODO: deal with the value when it is not a scalar.
       // TODO: deal with the value when it is not a scalar.
     }
     }
     // The TripalBundle__bundle_id is a special token for substituting the
     // The TripalBundle__bundle_id is a special token for substituting the
@@ -1076,8 +1078,13 @@ function tripal_replace_entity_tokens($string, &$entity, $bundle_entity = NULL)
       $value = $entity->id;
       $value = $entity->id;
     }
     }
 
 
-    // Perform the replacement of the token with the value.
-    $string = str_replace($token, $value, $string);
+    // We can't support tokens that have multiple elements (i.e. in an array).
+    if (is_array($value)) {
+      $string = str_replace($token, '', $string);
+    }
+    else {
+      $string = str_replace($token, $value, $string);
+    }
   }
   }
 
 
   return $string;
   return $string;

+ 2 - 1
tripal/includes/TripalBundleUIController.inc

@@ -752,7 +752,8 @@ function tripal_admin_add_type_form_submit($form, &$form_state) {
         $form_state['redirect'] = "admin/structure/bio_data";
         $form_state['redirect'] = "admin/structure/bio_data";
       }
       }
       else {
       else {
-        drupal_set_message('New data type created.');
+        drupal_set_message('New content type created!');
+        drupal_set_message('Please ' . l("set the user permissions", "admin/people/permissions") . ' for this new content type.');
         tripal_admin_access($bundle);
         tripal_admin_access($bundle);
         $form_state['redirect'] = "admin/structure/bio_data";
         $form_state['redirect'] = "admin/structure/bio_data";
       }
       }

+ 1 - 1
tripal/includes/TripalEntityUIController.inc

@@ -648,7 +648,7 @@ function tripal_entity_form_ajax_callback($form, $form_state) {
    $langcode = 'und';
    $langcode = 'und';
    foreach ($instances as $field_name => $instance) {
    foreach ($instances as $field_name => $instance) {
      $entity_type = $instance['entity_type'];
      $entity_type = $instance['entity_type'];
-     if($entity_type == 'TripalEntity') {
+     if($entity_type == 'TripalEntity' and array_key_exists($field_name, $form)) {
        foreach ($form[$field_name][$langcode] as $delta => $field_form) {
        foreach ($form[$field_name][$langcode] as $delta => $field_form) {
          if (!preg_match('/^\d+$/', $delta)) {
          if (!preg_match('/^\d+$/', $delta)) {
            continue;
            continue;

+ 29 - 13
tripal/includes/TripalFields/TripalField.inc

@@ -208,7 +208,7 @@ class TripalField {
   /**
   /**
    * Describes this field to Tripal web services.
    * Describes this field to Tripal web services.
    *
    *
-   * The child class need not implement this function has all of the details
+   * The child class need not implement this function. It has all of the details
    * provided for elements by the elementInfo() function are used to generate
    * provided for elements by the elementInfo() function are used to generate
    * the details needed for Views.
    * the details needed for Views.
    *
    *
@@ -224,19 +224,28 @@ class TripalField {
     $field_details = $elements[$field_term];
     $field_details = $elements[$field_term];
 
 
     $searchable_keys = array();
     $searchable_keys = array();
+    $sortable_keys = array();
+
     if (array_key_exists('searchable', $field_details) and $field_details['searchable']) {
     if (array_key_exists('searchable', $field_details) and $field_details['searchable']) {
       $searchable_keys[$field_term_name] = $field_term;
       $searchable_keys[$field_term_name] = $field_term;
     }
     }
 
 
+    if (array_key_exists('sortable', $field_details) and $field_details['sortable']) {
+      $sortable_keys[$field_term_name] = $field_term;
+    }
+
     // Now add any entries for child elements.
     // Now add any entries for child elements.
     if (array_key_exists('elements', $field_details)) {
     if (array_key_exists('elements', $field_details)) {
       $elements = $field_details['elements'];
       $elements = $field_details['elements'];
       foreach ($elements as $element_name => $element_details) {
       foreach ($elements as $element_name => $element_details) {
-        $this->_addWebServiceElement($searchable_keys, $field_term_name, $field_term, $element_name, $element_details);
+        $this->_addWebServiceElement($searchable_keys, $sortable_keys, $field_term_name, $field_term, $element_name, $element_details);
       }
       }
     }
     }
 
 
-    return $searchable_keys;
+    return array(
+      'searchable' => $searchable_keys,
+      'sortable' => $sortable_keys
+    );
   }
   }
 
 
   /**
   /**
@@ -246,7 +255,9 @@ class TripalField {
    * @param $element_name
    * @param $element_name
    * @param $element_details
    * @param $element_details
    */
    */
-  protected function _addWebServiceElement(&$searchable_keys, $parent_term_name, $parent_term, $element_name, $element_details) {
+  protected function _addWebServiceElement(&$searchable_keys, &$sortable_keys,
+      $parent_term_name, $parent_term, $element_name, $element_details) {
+
     // Skip the 'entity' element, as we'll never make this searchable or
     // Skip the 'entity' element, as we'll never make this searchable or
     // viewable. It's meant for linking.
     // viewable. It's meant for linking.
     if ($element_name == 'entity') {
     if ($element_name == 'entity') {
@@ -262,12 +273,15 @@ class TripalField {
     if (array_key_exists('searchable', $element_details) and $element_details['searchable']) {
     if (array_key_exists('searchable', $element_details) and $element_details['searchable']) {
       $searchable_keys[$field_term_name] =  $field_term;
       $searchable_keys[$field_term_name] =  $field_term;
     }
     }
+    if (array_key_exists('sortable', $element_details) and $element_details['sortable']) {
+      $sortable_keys[$field_term_name] =  $field_term;
+    }
 
 
     // Now add any entries for child elements.
     // Now add any entries for child elements.
     if (array_key_exists('elements', $element_details)) {
     if (array_key_exists('elements', $element_details)) {
       $elements = $element_details['elements'];
       $elements = $element_details['elements'];
       foreach ($elements as $element_name => $element_details) {
       foreach ($elements as $element_name => $element_details) {
-        $this->_addWebServiceElement($searchable_keys, $field_term_name, $field_term, $element_name, $element_details);
+        $this->_addWebServiceElement($searchable_keys, $sortable_keys, $field_term_name, $field_term, $element_name, $element_details);
       }
       }
     }
     }
   }
   }
@@ -329,7 +343,7 @@ class TripalField {
     if (array_key_exists('searchable', $field_details) and $field_details['searchable']) {
     if (array_key_exists('searchable', $field_details) and $field_details['searchable']) {
       $filter_handler = 'tripal_views_handler_filter_string';
       $filter_handler = 'tripal_views_handler_filter_string';
       if (array_key_exists('type', $field_details) and $field_details['type'] == 'numeric') {
       if (array_key_exists('type', $field_details) and $field_details['type'] == 'numeric') {
-        $filter_handler = 'tripal_views_handler_filter';
+        $filter_handler = 'tripal_views_handler_filter_numeric';
       }
       }
       $data[$view_base_id][$field_name]['filter'] = array(
       $data[$view_base_id][$field_name]['filter'] = array(
         'handler' => $filter_handler,
         'handler' => $filter_handler,
@@ -343,6 +357,7 @@ class TripalField {
         $this->_addViewsDataElement($data, $view_base_id, $field_name, $element_name, $element_details);
         $this->_addViewsDataElement($data, $view_base_id, $field_name, $element_name, $element_details);
       }
       }
     }
     }
+
     return $data;
     return $data;
   }
   }
 
 
@@ -360,6 +375,11 @@ class TripalField {
     if ($element_name == 'entity') {
     if ($element_name == 'entity') {
       return;
       return;
     }
     }
+
+    if (!preg_match('/:/', $element_name)) {
+      return;
+    }
+
     $field_name = $parent . '.' . $element_name;
     $field_name = $parent . '.' . $element_name;
     list($vocabulary, $accession) = explode(':', $element_name);
     list($vocabulary, $accession) = explode(':', $element_name);
     $term = tripal_get_term_details($vocabulary, $accession);
     $term = tripal_get_term_details($vocabulary, $accession);
@@ -392,7 +412,7 @@ class TripalField {
     if (array_key_exists('searchable', $element_details) and $element_details['searchable']) {
     if (array_key_exists('searchable', $element_details) and $element_details['searchable']) {
       $filter_handler = 'tripal_views_handler_filter_element_string';
       $filter_handler = 'tripal_views_handler_filter_element_string';
       if (array_key_exists('type', $element_details) and $element_details['type'] == 'numeric') {
       if (array_key_exists('type', $element_details) and $element_details['type'] == 'numeric') {
-        $filter_handler = 'tripal_views_handler_filter';
+        $filter_handler = 'tripal_views_handler_filter_numeric';
       }
       }
       $data[$view_base_id][$field_name]['filter'] = array(
       $data[$view_base_id][$field_name]['filter'] = array(
         'handler' => $filter_handler,
         'handler' => $filter_handler,
@@ -422,10 +442,6 @@ class TripalField {
    *    The type of $entity.
    *    The type of $entity.
    *  @param $entity
    *  @param $entity
    *    The entity for the operation.
    *    The entity for the operation.
-   *  @param $field
-   *    The field structure for the operation.
-   *  @param $instance
-   *    The instance structure for $field on $entity's bundle.
    *  @param $langcode
    *  @param $langcode
    *    The language associated with $items.
    *    The language associated with $items.
    *  @param $items
    *  @param $items
@@ -440,7 +456,7 @@ class TripalField {
    *      - message: The human readable message to be displayed.
    *      - message: The human readable message to be displayed.
    *
    *
    */
    */
-  public function validate($entity_type, $entity, $field, $items, &$errors) {
+  public function validate($entity_type, $entity, $langcode, $items, &$errors) {
 
 
   }
   }
 
 
@@ -658,7 +674,7 @@ class TripalField {
   }
   }
 
 
   /**
   /**
-   * Afte a field instance is created the following function is run.
+   * After a field instance is created the following function is run.
    *
    *
    * This function is equivalent to the hook_field_create_field() hook of
    * This function is equivalent to the hook_field_create_field() hook of
    * the Drupal Field API. This function is invoked after a new field
    * the Drupal Field API. This function is invoked after a new field

+ 1 - 1
tripal/includes/TripalFields/TripalFieldWidget.inc

@@ -113,7 +113,7 @@ class TripalFieldWidget {
   }
   }
 
 
   /**
   /**
-   * Performs validation of the widgetForm.
+   * Performs validation of the widget form.
    *
    *
    * Use this validate to ensure that form values are entered correctly.
    * Use this validate to ensure that form values are entered correctly.
    * The 'value' key of this field must be set in the $form_state['values']
    * The 'value' key of this field must be set in the $form_state['values']

+ 38 - 2
tripal/includes/TripalImporter.inc

@@ -389,8 +389,16 @@ class TripalImporter {
         $file_remote = $this->arguments['file']['file_remote'];
         $file_remote = $this->arguments['file']['file_remote'];
         $this->logMessage('Download file: !file_remote...', array('!file_remote' => $file_remote));
         $this->logMessage('Download file: !file_remote...', array('!file_remote' => $file_remote));
 
 
+        // If this file is compressed then keepthe .gz extension so we can
+        // uncompress it.
+        $ext = '';
+        if (preg_match('/^(.*?)\.gz$/', $this->arguments['file']['file_remote'])) {
+          $ext = '.gz';
+        }
         // Create a temporary file.
         // Create a temporary file.
-        $temp = tempnam("temporary://", 'import_');
+        $temp = tempnam("temporary://", 'import_') . $ext;
+        $this->logMessage("Saving as: !file", array('!file' => $temp));
+
         $url_fh = fopen($file_remote, "r");
         $url_fh = fopen($file_remote, "r");
         $tmp_fh = fopen($temp, "w");
         $tmp_fh = fopen($temp, "w");
         if (!$url_fh) {
         if (!$url_fh) {
@@ -402,11 +410,39 @@ class TripalImporter {
         while (!feof($url_fh)) {
         while (!feof($url_fh)) {
           fwrite($tmp_fh, fread($url_fh, 255), 255);
           fwrite($tmp_fh, fread($url_fh, 255), 255);
         }
         }
-
         // Set the path to the file for the importer to use.
         // Set the path to the file for the importer to use.
         $this->arguments['file']['file_path'] = $temp;
         $this->arguments['file']['file_path'] = $temp;
         $this->is_prepared = TRUE;
         $this->is_prepared = TRUE;
       }
       }
+
+      // Is this file compressed?  If so, then uncompress it
+      $matches = array();
+      if (preg_match('/^(.*?)\.gz$/', $this->arguments['file']['file_path'], $matches)) {
+        $this->logMessage("Uncompressing: !file", array('!file' => $this->arguments['file']['file_path']));
+        $buffer_size = 4096;
+        $new_file_path = $matches[1];
+        $gzfile = gzopen($this->arguments['file']['file_path'], 'rb');
+        $out_file = fopen($new_file_path, 'wb');
+        if (!$out_file) {
+          throw new Exception("Cannot uncompress file: new temporary file, '$new_file_path', cannot be created.");
+        }
+
+        // Keep repeating until the end of the input file
+        while (!gzeof($gzfile)) {
+          // Read buffer-size bytes
+          // Both fwrite and gzread and binary-safe
+          fwrite($out_file, gzread($gzfile, $buffer_size));
+        }
+
+        // Files are done, close files
+        fclose($out_file);
+        gzclose($gzfile);
+
+        // Now remove the .gz file and reset the file_path to the new
+        // uncompressed version.
+        unlink($this->arguments['file']['file_path']);
+        $this->arguments['file']['file_path'] = $new_file_path;
+      }
     }
     }
     catch (Exception $e){
     catch (Exception $e){
       throw new Exception('Cannot prepare the importer: ' .  $e->getMessage());
       throw new Exception('Cannot prepare the importer: ' .  $e->getMessage());

+ 14 - 3
tripal/includes/TripalJob.inc

@@ -115,8 +115,19 @@ class TripalJob {
     }
     }
 
 
     $includes = $details['includes'];
     $includes = $details['includes'];
-    foreach ($includes as $include) {
-      require_once($include);
+    foreach ($includes as $path) {
+      $full_path = $_SERVER['DOCUMENT_ROOT'] . base_path() . $path;
+      if (!empty($path)) {
+        if (file_exists($path)) {
+          require_once($path);
+        }
+        elseif (file_exists($full_path)) {
+          require_once($path);
+        }
+        elseif (!empty($path)) {
+          throw new Exception("Included files for Tripal Job must exist. This path ($full_path) doesn't exist.");
+        }
+      }
     }
     }
     if (!function_exists($details['callback'])) {
     if (!function_exists($details['callback'])) {
       throw new Exception("Must provide a valid callback function to the tripal_add_job() function.");
       throw new Exception("Must provide a valid callback function to the tripal_add_job() function.");
@@ -253,7 +264,7 @@ class TripalJob {
       $record->job_id = $this->job->job_id;
       $record->job_id = $this->job->job_id;
       $record->end_time = time();
       $record->end_time = time();
       $record->error_msg = $this->job->error_msg;
       $record->error_msg = $this->job->error_msg;
-      $record->progress = $this->job->progress;
+      $record->progress = 100;
       $record->status = 'Completed';
       $record->status = 'Completed';
       $record->pid = '';
       $record->pid = '';
 
 

+ 4 - 0
tripal/includes/tripal.entity.inc

@@ -275,6 +275,10 @@ function tripal_entity_info_alter(&$entity_info){
  */
  */
 function tripal_entity_property_info_alter(&$info) {
 function tripal_entity_property_info_alter(&$info) {
 
 
+  // Sometimes this function is called when there are no Tripal Entities.
+  // Don't bother to do anything in this case.
+  if (!isset($info['TripalEntity']['bundles'])) { return TRUE; }
+
   // For each Tripal Content Type, we want to ensure all attached fields
   // For each Tripal Content Type, we want to ensure all attached fields
   // are added to the bundle properties.
   // are added to the bundle properties.
   foreach ($info['TripalEntity']['bundles'] as $bundle_name => $bundle) {
   foreach ($info['TripalEntity']['bundles'] as $bundle_name => $bundle) {

+ 5 - 2
tripal/includes/tripal.fields.inc

@@ -108,6 +108,7 @@ function tripal_field_views_data($field) {
       $data += $tfield->viewsData($view_base_id);
       $data += $tfield->viewsData($view_base_id);
     }
     }
   }
   }
+
   return $data;
   return $data;
 }
 }
 
 
@@ -694,9 +695,11 @@ function tripal_field_instance_settings_form_submit($form, &$form_state) {
 function tripal_field_widget_form_validate($element, &$form_state, $form) {
 function tripal_field_widget_form_validate($element, &$form_state, $form) {
   $field = $element['#field'];
   $field = $element['#field'];
   $instance = $element['#instance'];
   $instance = $element['#instance'];
-  $widget_class = $element['#field_name'] . '_widget';
+
   $langcode = $element['#language'];
   $langcode = $element['#language'];
   $delta = $element['#delta'];
   $delta = $element['#delta'];
+
+  $widget_class = $instance['widget']['type'];
   tripal_load_include_field_class($widget_class);
   tripal_load_include_field_class($widget_class);
   if (class_exists($widget_class)) {
   if (class_exists($widget_class)) {
     $widget = new $widget_class($field, $instance);
     $widget = new $widget_class($field, $instance);
@@ -810,7 +813,7 @@ function tripal_field_validate($entity_type, $entity, $field, $instance,
    $field_type = $field['type'];
    $field_type = $field['type'];
    if (tripal_load_include_field_class($field_type)) {
    if (tripal_load_include_field_class($field_type)) {
      $tfield = new $field_type($field, $instance);
      $tfield = new $field_type($field, $instance);
-     $tfield->validate($entity_type, $entity, $langcode,$items, $errors);
+     $tfield->validate($entity_type, $entity, $langcode, $items, $errors);
    }
    }
 }
 }
 
 

+ 1 - 0
tripal/tripal.info

@@ -19,6 +19,7 @@ files[] = views_handlers/tripal_views_handler_field_image.inc
 files[] = views_handlers/tripal_views_handler_field_boolean.inc
 files[] = views_handlers/tripal_views_handler_field_boolean.inc
 files[] = views_handlers/tripal_views_handler_filter.inc
 files[] = views_handlers/tripal_views_handler_filter.inc
 files[] = views_handlers/tripal_views_handler_filter_string.inc
 files[] = views_handlers/tripal_views_handler_filter_string.inc
+files[] = views_handlers/tripal_views_handler_filter_numeric.inc
 files[] = views_handlers/tripal_views_handler_filter_element_string.inc
 files[] = views_handlers/tripal_views_handler_filter_element_string.inc
 files[] = views_handlers/tripal_views_handler_filter_boolean_operator.inc
 files[] = views_handlers/tripal_views_handler_filter_boolean_operator.inc
 files[] = views_handlers/tripal_views_handler_filter_entity_string.inc
 files[] = views_handlers/tripal_views_handler_filter_entity_string.inc

+ 37 - 1
tripal/tripal.module

@@ -640,6 +640,42 @@ function tripal_form_alter(&$form, $form_state, $form_id) {
   if ($form_id == 'field_ui_field_edit_form' and $form['#instance']['entity_type'] == 'TripalEntity') {
   if ($form_id == 'field_ui_field_edit_form' and $form['#instance']['entity_type'] == 'TripalEntity') {
     tripal_field_instance_settings_form_alter($form, $form_state);
     tripal_field_instance_settings_form_alter($form, $form_state);
   }
   }
+
+  // Remove fields that have no form. It's just a bit too confusing to have
+  // widgets appear in the form but without and form elements inside them.
+  if ($form_id == 'tripal_entity_form') {
+    $children = element_children($form);
+    foreach ($children as $child) {
+      // count the number of form elements
+      if (array_key_exists('und', $form[$child])) {
+        $total_widgets = 0;
+        foreach ($form[$child]['und'] as $delta => $element) {
+          if (is_numeric($delta)) {
+            $total_widgets += count(element_children($element));
+            // Ignore the weight column
+            if (array_key_exists('_weight', $element)) {
+              $total_widgets--;
+            }
+            // Ignore a hidden value column
+            if (array_key_exists('value', $element) and $element['value']['#type'] == 'value') {
+              $total_widgets--;
+            }
+            // Some form elements don't have a 'value' and they don't have any
+            // widgets (i.e image field and description field. We don't
+            // want to loose those, so add one to the widget count.
+            if (!array_key_exists('value', $element)) {
+              $total_widgets++;
+            }
+          }
+        }
+        // If we have no widgets then here's not a form for this field so just
+        // remove it.
+        if ($total_widgets == 0) {
+          unset($form[$child]);
+        }
+      }
+    }
+  }
 }
 }
 
 
 function tripal_check_new_fields($bundle_name) {
 function tripal_check_new_fields($bundle_name) {
@@ -1096,7 +1132,7 @@ function tripal_field_display_TripalEntity_alter(&$display, $context){
  * @param $element
  * @param $element
  *   The field group object.
  *   The field group object.
  * @param $children
  * @param $children
- *   An array of field names that are cpntained in the field group
+ *   An array of field names that are contained in the field group.
  */
  */
 function tripal_field_group_table_rows_alter(&$element, &$children) {
 function tripal_field_group_table_rows_alter(&$element, &$children) {
 
 

+ 24 - 6
tripal/tripal.views_default.inc

@@ -145,6 +145,12 @@ function tripal_bundle_default_views(&$views) {
         $handler->display->display_options['fields']['schema__description']['alter']['trim'] = TRUE;
         $handler->display->display_options['fields']['schema__description']['alter']['trim'] = TRUE;
       }
       }
 
 
+      // Add a filter to show published content only.
+      $handler->display->display_options['filters']['status']['id'] = 'status';
+      $handler->display->display_options['filters']['status']['table'] = $base_table;
+      $handler->display->display_options['filters']['status']['field'] = 'status';
+      $handler->display->display_options['filters']['status']['value'] = '1';
+
       // Filter criterion.
       // Filter criterion.
       if (in_array($field_name, array('data__identifier', 'schema__name',
       if (in_array($field_name, array('data__identifier', 'schema__name',
           'data__accession', 'rdfs__label', 'taxrank__genus',
           'data__accession', 'rdfs__label', 'taxrank__genus',
@@ -172,22 +178,34 @@ function tripal_bundle_default_views(&$views) {
 
 
     // Add the default sorted column.
     // Add the default sorted column.
     if (in_array('data__identifier', $selected_fields)) {
     if (in_array('data__identifier', $selected_fields)) {
-      $handler->display->display_options['style_options']['default'] = 'data__identifier';
+      $handler->display->display_options['sorts']['priority']['id'] = $field_name;
+      $handler->display->display_options['sorts']['priority']['table'] = $base_table;
+      $handler->display->display_options['sorts']['priority']['field'] = 'data__identifier';
     }
     }
     else if (in_array('schema__name', $selected_fields)) {
     else if (in_array('schema__name', $selected_fields)) {
-      $handler->display->display_options['style_options']['default'] = 'schema__name';
+      $handler->display->display_options['sorts']['priority']['id'] = $field_name;
+      $handler->display->display_options['sorts']['priority']['table'] = $base_table;
+      $handler->display->display_options['sorts']['priority']['field'] = 'schema__name';
     }
     }
     else if (in_array('obi__organism', $selected_fields)) {
     else if (in_array('obi__organism', $selected_fields)) {
-      $handler->display->display_options['style_options']['default'] = 'obi__organism';
+      $handler->display->display_options['sorts']['priority']['id'] = $field_name;
+      $handler->display->display_options['sorts']['priority']['table'] = $base_table;
+      $handler->display->display_options['sorts']['priority']['field'] = 'obi__organism';
     }
     }
     else if (in_array('rdfs_label', $selected_fields)) {
     else if (in_array('rdfs_label', $selected_fields)) {
-      $handler->display->display_options['style_options']['default'] = 'rdfs_label';
+      $handler->display->display_options['sorts']['priority']['id'] = $field_name;
+      $handler->display->display_options['sorts']['priority']['table'] = $base_table;
+      $handler->display->display_options['sorts']['priority']['field'] = 'rdfs_label';
     }
     }
     else if (in_array('taxrank__genus', $selected_fields)) {
     else if (in_array('taxrank__genus', $selected_fields)) {
-      $handler->display->display_options['style_options']['default'] = 'taxrank__genus';
+      $handler->display->display_options['sorts']['priority']['id'] = $field_name;
+      $handler->display->display_options['sorts']['priority']['table'] = $base_table;
+      $handler->display->display_options['sorts']['priority']['field'] = 'taxrank__genus';
     }
     }
     else if (in_array('taxrank__species', $selected_fields)) {
     else if (in_array('taxrank__species', $selected_fields)) {
-      $handler->display->display_options['style_options']['default'] = 'taxrank__species';
+      $handler->display->display_options['sorts']['priority']['id'] = $field_name;
+      $handler->display->display_options['sorts']['priority']['table'] = $base_table;
+      $handler->display->display_options['sorts']['priority']['field'] = 'taxrank__species';
     }
     }
 
 
     // No results behavior: Global: Text area.
     // No results behavior: Global: Text area.

+ 39 - 62
tripal/tripal_views_query.inc

@@ -2,35 +2,6 @@
 
 
 class tripal_views_query extends views_plugin_query {
 class tripal_views_query extends views_plugin_query {
 
 
-  /**
-   * The EntityFieldQuery object used to perform the query
-   */
-  var $query;
-
-  /**
-   * The EntityFieldQuery object used to perform the count query.
-   * It will not include the order by and only fields that are used in
-   * filters.
-   */
-  var $cquery;
-
-  /**
-   * The fields that are to be included in the query.
-   */
-  var $fields;
-
-  /**
-   * The filters that are to be included in the query.
-   */
-  var $filters;
-
-  /**
-   * The sort item that are to be included in the query.
-   */
-  var $order;
-
-
-
   /**
   /**
    * Ensure a table exists in the queue.
    * Ensure a table exists in the queue.
    *
    *
@@ -116,14 +87,16 @@ class tripal_views_query extends views_plugin_query {
    *   here.
    *   here.
    */
    */
   public function add_where($group, $field_name, $value = NULL, $operator = NULL) {
   public function add_where($group, $field_name, $value = NULL, $operator = NULL) {
-    $this->filters[] = array(
-      'group' => $group,
-      'field_name' => $field_name,
-      'value' => $value,
-      'op' => $operator
-    );
 
 
     if ($value) {
     if ($value) {
+
+      $this->filters[] = array(
+        'group' => $group,
+        'field_name' => $field_name,
+        'value' => $value,
+        'op' => $operator
+      );
+
       // Handle the bundle properties separate from real fields.
       // Handle the bundle properties separate from real fields.
       if ($field_name == 'entity_id' or $field_name == 'status') {
       if ($field_name == 'entity_id' or $field_name == 'status') {
         $this->query->propertyCondition($field_name, $value, $operator);
         $this->query->propertyCondition($field_name, $value, $operator);
@@ -131,32 +104,32 @@ class tripal_views_query extends views_plugin_query {
         return;
         return;
       }
       }
 
 
-      // If the field_name comes to us with a period in it then it means that
-      // we need to separate the field name from sub-element names.
-      $matches = array();
-      if (preg_match('/^(.+?)\.(.*)$/', $field_name, $matches)) {
-         $field_name = $matches[1];
-         $element_name = $matches[2];
-         if (tripal_load_include_field_class($field_name)) {
-           $field = field_info_field($field_name);
-           $instance = field_info_instance('TripalEntity', $field_name, $this->query->entityConditions['bundle']['value']);
-           $field_obj = new $field_name($field, $instance);
-           $element_name = $field_obj->getFieldTermID() . ',' . $element_name;
-           // Replace periods with commas.
-           $element_name = preg_replace('/\./', ',', $element_name);
-           $this->query->fieldCondition($field_name, $element_name, $value, $operator);
-           $this->cquery->fieldCondition($field_name, $element_name, $value, $operator);
-         }
-         else {
-           throw new Exception("Unkown element id: '$element_name'.");
-         }
+      // For Tripal create fields the name of the field is an encoded
+      // string that contains the bundle term, field name and any
+      // sub elements. We need to extract them.
+      $elements = explode('.', $field_name);
+      $bundle_term = array_shift($elements);
+      $field_name = array_shift($elements);
+      $element_name = implode(',', $elements);
+
+      // Get the field and instance.
+      $field = field_info_field($field_name);
+      $instance = field_info_instance('TripalEntity', $field_name, $this->query->entityConditions['bundle']['value']);
+
+      // Construct the field term.
+      $field_term = $instance['settings']['term_vocabulary'] . ':' . $instance['settings']['term_accession'];
+
+      // Let's add add on the $field_term to the element_name and add the
+      // query condition.
+      if ($element_name) {
+        $element_name = $field_term . ',' . $element_name;
       }
       }
       else {
       else {
-        $instance = field_info_instance('TripalEntity', $field_name, $this->query->entityConditions['bundle']['value']);
-        $field_term = $instance['settings']['term_vocabulary'] . ':' . $instance['settings']['term_accession'];
-        $this->query->fieldCondition($field_name, $field_term, $value, $operator);
-        $this->cquery->fieldCondition($field_name, $field_term, $value, $operator);
+        $element_name = $field_term;
       }
       }
+
+      $this->query->fieldCondition($field_name, $element_name, $value, $operator);
+      $this->cquery->fieldCondition($field_name, $element_name, $value, $operator);
     }
     }
   }
   }
 
 
@@ -164,12 +137,13 @@ class tripal_views_query extends views_plugin_query {
    * Overrides add_orderby().
    * Overrides add_orderby().
    */
    */
   public function add_orderby($table, $field_name = NULL, $order = 'ASC', $alias = '', $params = array()) {
   public function add_orderby($table, $field_name = NULL, $order = 'ASC', $alias = '', $params = array()) {
-
     if ($field_name) {
     if ($field_name) {
-      // Make sure we don't put the orderby in more than once.
+      // If we already have an orderBy for this field then remove it so
+      // we can reset it.
       foreach ($this->order as $index => $order_details) {
       foreach ($this->order as $index => $order_details) {
         if ($order_details['field'] == $field_name) {
         if ($order_details['field'] == $field_name) {
-          return;
+          $this->order[$index]['direction'] = $order;
+          unset($this->order[$index]);
         }
         }
       }
       }
       $this->order[] = array(
       $this->order[] = array(
@@ -252,11 +226,14 @@ class tripal_views_query extends views_plugin_query {
         $this->pager->pre_execute($query);
         $this->pager->pre_execute($query);
         $num_items_per_page = $this->pager->get_items_per_page();
         $num_items_per_page = $this->pager->get_items_per_page();
         $offset = $this->pager->get_current_page() * $num_items_per_page;
         $offset = $this->pager->get_current_page() * $num_items_per_page;
+        // I'm not sure why an offset would come back as -1 but it has happened
+        // with Drupal Views.  This is a quick band-aid fix.
+        $offset = ($offset < 0) ? 0 : $offset;
         $query->range($offset, $num_items_per_page);
         $query->range($offset, $num_items_per_page);
 
 
         // Get the IDs
         // Get the IDs
         $results = $query->execute();
         $results = $query->execute();
-        $entity_ids = array_keys($results['TripalEntity']);
+        $entity_ids = (isset($results['TripalEntity']) AND is_array($results['TripalEntity'])) ? array_keys($results['TripalEntity']) : array();
 
 
         $this->pager->post_execute($view->result);
         $this->pager->post_execute($view->result);
         if ($this->pager->use_count_query() || !empty($view->get_total_rows)) {
         if ($this->pager->use_count_query() || !empty($view->get_total_rows)) {

+ 187 - 0
tripal/views_handlers/tripal_views_handler_filter_numeric.inc

@@ -0,0 +1,187 @@
+<?php
+
+class tripal_views_handler_filter_numeric extends tripal_views_handler_filter {
+
+  var $always_multiple = TRUE;
+
+  function operators() {
+    $operators = array(
+      '<' => array(
+        'title' => t('Is less than'),
+        'method' => 'op_simple',
+        'short' => t('<'),
+        'values' => 1,
+      ),
+      '<=' => array(
+        'title' => t('Is less than or equal to'),
+        'method' => 'op_simple',
+        'short' => t('<='),
+        'values' => 1,
+      ),
+      '=' => array(
+        'title' => t('Is equal to'),
+        'method' => 'op_simple',
+        'short' => t('='),
+        'values' => 1,
+      ),
+      '!=' => array(
+        'title' => t('Is not equal to'),
+        'method' => 'op_simple',
+        'short' => t('!='),
+        'values' => 1,
+      ),
+      '>=' => array(
+        'title' => t('Is greater than or equal to'),
+        'method' => 'op_simple',
+        'short' => t('>='),
+        'values' => 1,
+      ),
+      '>' => array(
+        'title' => t('Is greater than'),
+        'method' => 'op_simple',
+        'short' => t('>'),
+        'values' => 1,
+      ),
+    );
+
+    return $operators;
+  }
+
+
+  function op_simple($field) {
+    $this->query->add_where($this->options['group'], $field, $this->value, $this->operator);
+  }
+
+  function op_empty($field) {
+    if ($this->operator == 'empty') {
+      $operator = "IS NULL";
+    }
+    else {
+      $operator = "IS NOT NULL";
+    }
+
+    $this->query->add_where($this->options['group'], $field, NULL, $operator);
+  }
+
+
+
+  function option_definition() {
+    $options = parent::option_definition();
+
+    $options['expose']['contains']['required'] = array('default' => FALSE, 'bool' => TRUE);
+
+    return $options;
+  }
+
+  /**
+   * Build strings from the operators() for 'select' options
+   */
+  function operator_options($which = 'title') {
+    $options = array();
+    foreach ($this->operators() as $id => $info) {
+      $options[$id] = $info[$which];
+    }
+
+    return $options;
+  }
+
+  function admin_summary() {
+    if ($this->is_a_group()) {
+      return t('grouped');
+    }
+    if (!empty($this->options['exposed'])) {
+      return t('exposed');
+    }
+
+    $options = $this->operator_options('short');
+    $output = '';
+    if (!empty($options[$this->operator])) {
+      $output = check_plain($options[$this->operator]);
+    }
+    if (in_array($this->operator, $this->operator_values(1))) {
+      $output .= ' ' . check_plain($this->value);
+    }
+    return $output;
+  }
+
+  function operator_values($values = 1) {
+    $options = array();
+    foreach ($this->operators() as $id => $info) {
+      if (isset($info['values']) && $info['values'] == $values) {
+        $options[] = $id;
+      }
+    }
+
+    return $options;
+  }
+
+  /**
+   * Provide a simple textfield for equality
+   */
+  function value_form(&$form, &$form_state) {
+
+    // We have to make some choices when creating this as an exposed
+    // filter form. For example, if the operator is locked and thus
+    // not rendered, we can't render dependencies; instead we only
+    // render the form items we need.
+    $which = 'all';
+    if (!empty($form['operator'])) {
+      $source = ($form['operator']['#type'] == 'radios') ? 'radio:options[operator]' : 'edit-options-operator';
+    }
+    if (!empty($form_state['exposed'])) {
+      $identifier = $this->options['expose']['identifier'];
+
+      if (empty($this->options['expose']['use_operator']) || empty($this->options['expose']['operator_id'])) {
+        // exposed and locked.
+        $which = in_array($this->operator, $this->operator_values(1)) ? 'value' : 'none';
+      }
+      else {
+        $source = 'edit-' . drupal_html_id($this->options['expose']['operator_id']);
+      }
+    }
+
+    if ($which == 'all' || $which == 'value') {
+      $form['value'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Value'),
+        '#size' => 30,
+        '#default_value' => $this->value,
+      );
+      if (!empty($form_state['exposed']) && !isset($form_state['input'][$identifier])) {
+        $form_state['input'][$identifier] = $this->value;
+      }
+
+      if ($which == 'all') {
+        $form['value'] += array(
+          '#dependency' => array($source => $this->operator_values(1)),
+        );
+      }
+    }
+
+    if (!isset($form['value'])) {
+      // Ensure there is something in the 'value'.
+      $form['value'] = array(
+        '#type' => 'value',
+        '#value' => NULL
+      );
+    }
+  }
+
+  function operator() {
+    return $this->operator == '=' ? 'LIKE' : 'NOT LIKE';
+  }
+
+  /**
+   * Add this filter to the query.
+   */
+  function query() {
+    $this->ensure_my_table();
+    $field = "$this->table_alias.$this->real_field";
+
+    $info = $this->operators();
+    if (!empty($info[$this->operator]['method'])) {
+      $op_function = $info[$this->operator]['method'];
+      $this->{$op_function}($field);
+    }
+  }
+}

+ 2 - 6
tripal/views_handlers/tripal_views_handler_filter_string.inc

@@ -1,6 +1,6 @@
 <?php
 <?php
 class tripal_views_handler_filter_string extends tripal_views_handler_filter {
 class tripal_views_handler_filter_string extends tripal_views_handler_filter {
-  // exposed filter options
+
   var $always_multiple = TRUE;
   var $always_multiple = TRUE;
 
 
   function option_definition() {
   function option_definition() {
@@ -223,14 +223,10 @@ class tripal_views_handler_filter_string extends tripal_views_handler_filter {
 
 
   /**
   /**
    * Add this filter to the query.
    * Add this filter to the query.
-   *
-   * Due to the nature of fapi, the value and the operator have an unintended
-   * level of indirection. You will find them in $this->operator
-   * and $this->value respectively.
    */
    */
   function query() {
   function query() {
     $this->ensure_my_table();
     $this->ensure_my_table();
-    $field = $this->real_field;
+    $field = "$this->table_alias.$this->real_field";
 
 
     $info = $this->operators();
     $info = $this->operators();
     if (!empty($info[$this->operator]['method'])) {
     if (!empty($info[$this->operator]['method'])) {

+ 14 - 8
tripal_chado/api/modules/tripal_chado.cv.api.inc

@@ -1331,7 +1331,7 @@ function tripal_submit_obo_job($obo) {
   $obo['file']   = (isset($obo['file']))   ? $obo['file']   : NULL;
   $obo['file']   = (isset($obo['file']))   ? $obo['file']   : NULL;
 
 
   $includes = array(
   $includes = array(
-    module_load_include('inc', 'tripal_chado', 'includes/loaders/tripal_chado.obo_loader'),
+    drupal_get_path('module', 'tripal_chado') . '/includes/tripal_chado.cv.inc',
   );
   );
 
 
   if ($obo['obo_id']) {
   if ($obo['obo_id']) {
@@ -1340,18 +1340,24 @@ function tripal_submit_obo_job($obo) {
 
 
     $args = array($result->obo_id);
     $args = array($result->obo_id);
     return tripal_add_job("Load OBO " . $result->name, 'tripal_chado',
     return tripal_add_job("Load OBO " . $result->name, 'tripal_chado',
-       "tripal_chado_load_obo_v1_2_id", $args, $user->uid, 10, $includes);
+       "tripal_cv_load_obo", $args, $user->uid, 10, $includes);
   }
   }
   else {
   else {
     if ($obo['url']) {
     if ($obo['url']) {
-      $args = array($obo['name'], $obo['url']);
-      return tripal_add_job("Load OBO " . $obo['name'], 'tripal_chado',
-        "tripal_chado_load_obo_v1_2_url", $args, $user->uid, 10, $includes);
+      $sql = "SELECT * FROM {tripal_cv_obo} WHERE path = :url";
+      $result = db_query($sql, array(':url' => $obo['url']))->fetchObject();
+
+      $args = array($result->obo_id);
+      return tripal_add_job("Load OBO " . $result->name, 'tripal_chado',
+        "tripal_cv_load_obo", $args, $user->uid, 10, $includes);
     }
     }
     elseif ($obo['file']) {
     elseif ($obo['file']) {
-      $args = array($obo['name'], $obo['file']);
-      return tripal_add_job("Load OBO " . $obo['name'], 'tripal_chado',
-        "tripal_chado_load_obo_v1_2_file", $args, $user->uid, 10, $includes);
+      $sql = "SELECT * FROM {tripal_cv_obo} WHERE path = :file";
+      $result = db_query($sql, array(':url' => $obo['file']))->fetchObject();
+
+      $args = array($result->obo_id);
+      return tripal_add_job("Load OBO " . $result->name, 'tripal_chado',
+        "tripal_cv_load_obo", $args, $user->uid, 10, $includes);
     }
     }
   }
   }
   return FALSE;
   return FALSE;

+ 4 - 0
tripal_chado/api/modules/tripal_chado.db.api.inc

@@ -393,6 +393,10 @@ function tripal_insert_db($values, $options = array()) {
  *    - version: (Optional) The version of the database reference
  *    - version: (Optional) The version of the database reference
  *    - description: (Optional) A description of the database reference
  *    - description: (Optional) A description of the database reference
  *
  *
+ * @return
+ *   The newly inserted dbxref as an object, similar to that returned by
+ *   the chado_select_record() function.
+ *
  * @ingroup tripal_chado_api
  * @ingroup tripal_chado_api
  */
  */
 function tripal_insert_dbxref($values) {
 function tripal_insert_dbxref($values) {

+ 32 - 16
tripal_chado/api/modules/tripal_chado.pub.api.inc

@@ -302,7 +302,8 @@ function tripal_autocomplete_pub($string = '') {
   ";
   ";
   $pubs = chado_query($sql, array(':str' => $string . '%'));
   $pubs = chado_query($sql, array(':str' => $string . '%'));
   while ($pub = $pubs->fetchObject()) {
   while ($pub = $pubs->fetchObject()) {
-    $items[$pub->uniquename] = $pub->uniquename;
+    $val = $pub->title  . " [id:" . $pub->pub_id . "]";
+    $items[$val] = $pub->title;
   }
   }
 
 
   drupal_json_output($items);
   drupal_json_output($items);
@@ -1025,21 +1026,6 @@ function tripal_get_minimal_pub_info($pub) {
   $pub = chado_expand_var($pub, 'field', 'pub.title');
   $pub = chado_expand_var($pub, 'field', 'pub.title');
   $pub = chado_expand_var($pub, 'field', 'pub.volumetitle');
   $pub = chado_expand_var($pub, 'field', 'pub.volumetitle');
 
 
-  // get the citation
-  $values = array(
-    'pub_id' => $pub->pub_id,
-    'type_id' => array(
-      'name' => 'Citation',
-    ),
-  );
-  $options = array(
-    'include_fk' => array(
-    ),
-  );
-  $citation = chado_generate_var('pubprop', $values, $options);
-  $citation = chado_expand_var($citation, 'field', 'pubprop.value');
-  $citation = $citation->value;
-
   // get the abstract
   // get the abstract
   $values = array(
   $values = array(
     'pub_id' => $pub->pub_id,
     'pub_id' => $pub->pub_id,
@@ -1121,6 +1107,36 @@ function tripal_get_minimal_pub_info($pub) {
     $dbxrefs[] = $pub_dbxref->dbxref_id->db_id->name . ':' . $pub_dbxref->dbxref_id->accession;
     $dbxrefs[] = $pub_dbxref->dbxref_id->db_id->name . ':' . $pub_dbxref->dbxref_id->accession;
   }
   }
 
 
+  // get the citation
+  $values = array(
+    'pub_id' => $pub->pub_id,
+    'type_id' => array(
+      'name' => 'Citation',
+    ),
+  );
+  $options = array(
+    'include_fk' => array(
+    ),
+  );
+  $citation = chado_generate_var('pubprop', $values, $options);
+  if ($citation) {
+    $citation = chado_expand_var($citation, 'field', 'pubprop.value');
+    $citation = $citation->value;
+  }
+  else {
+    $pub_info = array(
+      'Title' => $pub->title,
+      'Publication Type' => $pub->type_id->name,
+      'Authors' => $authors_list,
+      'Series Name' => $pub->series_name,
+      'Volume' => $pub->volume,
+      'Issue' => $pub->issue,
+      'Pages' => $pub->pages,
+      'Publication Date' => $pub->pyear,
+    );
+    $citation = tripal_pub_create_citation($pub_info);
+  }
+
   return array(
   return array(
     'TPUB:0000039' => $pub->title,
     'TPUB:0000039' => $pub->title,
     'TPUB:0000003' => $citation,
     'TPUB:0000003' => $citation,

+ 1 - 1
tripal_chado/api/tripal_chado.mviews.api.inc

@@ -376,8 +376,8 @@ function tripal_populate_mview($mview_id) {
       chado_set_active($previous_db);
       chado_set_active($previous_db);
     }
     }
     catch (Exception $e) {
     catch (Exception $e) {
-      chado_set_active($previous_db);
       $transaction->rollback();
       $transaction->rollback();
+      chado_set_active($previous_db);
       // print and save the error message
       // print and save the error message
       $record = new stdClass();
       $record = new stdClass();
       $record->mview_id = $mview_id;
       $record->mview_id = $mview_id;

+ 12 - 5
tripal_chado/api/tripal_chado.query.api.inc

@@ -1321,8 +1321,12 @@ function chado_select_record($table, $columns, $values, $options = NULL) {
     // Require the field be in the table description.
     // Require the field be in the table description.
     if (!array_key_exists($field, $table_desc['fields'])) {
     if (!array_key_exists($field, $table_desc['fields'])) {
       tripal_report_error('tripal_chado', TRIPAL_ERROR,
       tripal_report_error('tripal_chado', TRIPAL_ERROR,
-        'chado_select_record: The field "%field" does not exist for the table "%table".  Cannot perform query. Values: %array',
-        array('%field' => $field, '%table' => $table, '%array' => print_r($values, 1)),
+        'chado_select_record: The field "%field" does not exist in the table "%table".  Cannot perform query. Values: %array. Fields: %fields',
+        array(
+          '%field' => $field,
+          '%table' => $table,
+          '%array' => print_r($values, 1),
+          '%fields' => print_r($table_desc['fields'], 1)),
         array('print' => $print_errors)
         array('print' => $print_errors)
       );
       );
       return array();
       return array();
@@ -1662,10 +1666,13 @@ function chado_query($sql, $args = array()) {
         chado_set_active($previous_db);
         chado_set_active($previous_db);
       }
       }
       catch (Exception $e) {
       catch (Exception $e) {
-        chado_set_active($previous_db);
-        throw $e;
+        try {
+          chado_set_active($previous_db);
+        }
+        catch (Exception $e2) {
+          throw new Exception($e->getMessage() . $e2->getMessage());
+        }
       }
       }
-
     }
     }
     // for all other tables we should have everything in scope so just run the query
     // for all other tables we should have everything in scope so just run the query
     else {
     else {

+ 21 - 0
tripal_chado/includes/TripalFields/ChadoField.inc

@@ -85,6 +85,27 @@ class ChadoField extends TripalField {
    */
    */
   public function queryOrder($query, $order) {
   public function queryOrder($query, $order) {
 
 
+
+    // If we are here it is because the child class did not implement the
+    // queryOrder function.  So, we will do our best to make the query work.
+    $chado_table = $this->instance['settings']['chado_table'];
+    $base_table = $this->instance['settings']['base_table'];
+    $bschema = chado_get_schema($base_table);
+    $bpkey = $bschema['primary key'][0];
+    $alias = 'dbx_linker';
+    $operator = $condition['operator'];
+
+    // If the chado_table and the base_table are the same then this is easy.
+    if ($chado_table == $base_table) {
+      // Get the base table column that is associated with the term
+      // passed as $condition['column'].
+      $base_field = tripal_get_chado_semweb_column($chado_table, $order['column']);
+      $query->orderBy('base.' . $base_field, $order['direction']);
+    }
+    else {
+      // If the two are not the same then we expect that the child class
+      // will implement a query() function.
+    }
   }
   }
 
 
   /**
   /**

+ 75 - 17
tripal_chado/includes/TripalFields/chado_linker__contact/chado_linker__contact.inc

@@ -61,8 +61,8 @@ class chado_linker__contact extends ChadoField {
    * @see TripalField::elements()
    * @see TripalField::elements()
    */
    */
   public function elementInfo() {
   public function elementInfo() {
-    $field_term = $this->getFieldTermID();
 
 
+    $field_term = $this->getFieldTermID();
     $type_term = tripal_get_chado_semweb_term('contact', 'type_id');
     $type_term = tripal_get_chado_semweb_term('contact', 'type_id');
     $name_term = tripal_get_chado_semweb_term('contact', 'name');
     $name_term = tripal_get_chado_semweb_term('contact', 'name');
     $description_term = tripal_get_chado_semweb_term('contact', 'description');
     $description_term = tripal_get_chado_semweb_term('contact', 'description');
@@ -76,7 +76,6 @@ class chado_linker__contact extends ChadoField {
         'elements' => array(
         'elements' => array(
           $type_term => array(
           $type_term => array(
             'searchable' => TRUE,
             'searchable' => TRUE,
-            'name' => 'type',
             'label' => 'Contact Type',
             'label' => 'Contact Type',
             'help' => 'The type of contact',
             'help' => 'The type of contact',
             'operations' => array('eq', 'ne', 'contains', 'starts'),
             'operations' => array('eq', 'ne', 'contains', 'starts'),
@@ -84,7 +83,6 @@ class chado_linker__contact extends ChadoField {
           ),
           ),
           $name_term => array(
           $name_term => array(
             'searchable' => TRUE,
             'searchable' => TRUE,
-            'name' => 'name',
             'label' => 'Contact Name',
             'label' => 'Contact Name',
             'help' => 'The name of the contact.',
             'help' => 'The name of the contact.',
             'operations' => array('eq', 'ne', 'contains', 'starts'),
             'operations' => array('eq', 'ne', 'contains', 'starts'),
@@ -92,11 +90,10 @@ class chado_linker__contact extends ChadoField {
           ),
           ),
           $description_term => array(
           $description_term => array(
             'searchable' => TRUE,
             'searchable' => TRUE,
-            'name' => 'description',
             'label' => 'Contact Description',
             'label' => 'Contact Description',
             'help' => 'A descriptoin of the contact.',
             'help' => 'A descriptoin of the contact.',
             'operations' => array('contains'),
             'operations' => array('contains'),
-            'sortable' => FALSE,
+            'sortable' => TRUE,
           ),
           ),
           'entity' => array(
           'entity' => array(
             'searchable' => FALSE,
             'searchable' => FALSE,
@@ -116,6 +113,7 @@ class chado_linker__contact extends ChadoField {
     $field_type = $this->field['type'];
     $field_type = $this->field['type'];
     $field_table = $this->instance['settings']['chado_table'];
     $field_table = $this->instance['settings']['chado_table'];
     $field_column = $this->instance['settings']['chado_column'];
     $field_column = $this->instance['settings']['chado_column'];
+    $base_table = $this->instance['settings']['base_table'];
 
 
     $type_term = tripal_get_chado_semweb_term('contact', 'type_id');
     $type_term = tripal_get_chado_semweb_term('contact', 'type_id');
     $name_term = tripal_get_chado_semweb_term('contact', 'name');
     $name_term = tripal_get_chado_semweb_term('contact', 'name');
@@ -123,7 +121,6 @@ class chado_linker__contact extends ChadoField {
 
 
     // Get the FK that links to the base record.
     // Get the FK that links to the base record.
     $schema = chado_get_schema($field_table);
     $schema = chado_get_schema($field_table);
-    $base_table = $entity->chado_table;
     $pkey = $schema['primary key'][0];
     $pkey = $schema['primary key'][0];
     if (!isset($schema['foreign keys'][$base_table]['columns'])) {
     if (!isset($schema['foreign keys'][$base_table]['columns'])) {
       return;
       return;
@@ -184,28 +181,89 @@ class chado_linker__contact extends ChadoField {
    * @see ChadoField::query()
    * @see ChadoField::query()
    */
    */
   public function query($query, $condition) {
   public function query($query, $condition) {
-    $contact_linker = $this->instance['settings']['chado_table'];
-    $base_table = $this->instance['settings']['base_table'];
-    $bschema = chado_get_schema($base_table);
-    $bpkey = $bschema['primary key'][0];
-    $alias = 'contact_linker';
+    $alias = $this->field['field_name'];
     $operator = $condition['operator'];
     $operator = $condition['operator'];
 
 
-    $type_term = tripal_get_chado_semweb_term('contact', 'type');
+    $field_term_id = $this->getFieldTermID();
+    $type_term = tripal_get_chado_semweb_term('contact', 'type_id');
     $name_term = tripal_get_chado_semweb_term('contact', 'name');
     $name_term = tripal_get_chado_semweb_term('contact', 'name');
     $description_term = tripal_get_chado_semweb_term('contact', 'description');
     $description_term = tripal_get_chado_semweb_term('contact', 'description');
 
 
-    if ($condition['column'] == $name_term) {
-      $this->queryJoinOnce($query, $contact_linker, $alias, "base.$bpkey = $alias.$bpkey");
-      $this->queryJoinOnce($query, 'contact', 'C', "C.contact_id = $alias.contact_id");
-      $query->condition("C.name", $condition['value'], $operator);
+    $contact_linker = $this->instance['settings']['chado_table'];
+    $base_table = $this->instance['settings']['base_table'];
+
+    // Get the FK that links to the base record.
+    $schema = chado_get_schema($contact_linker);
+    $pkey = $schema['primary key'][0];
+    $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
+    $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
+
+    // Join the contact linker table and then join the contact table.
+    $calias = $contact_linker . '_contact';
+    $this->queryJoinOnce($query, $contact_linker, $alias, "base.$fkey_rcolumn = $alias.$fkey_lcolumn");
+    $this->queryJoinOnce($query, 'contact', $calias, "$calias.contact_id = $alias.contact_id");
+
+    // Search by the contact name
+    if ($condition['column'] == $field_term_id or
+        $condition['column'] == $field_term_id . ',' . $name_term) {
+      $query->condition("$calias.name", $condition['value'], $operator);
+    }
+    // Search on the contact description.
+    if ($condition['column'] == $field_term_id . ',' . $description_term) {
+      $query->condition("$calias.description", $condition['value'], $operator);
     }
     }
-    if ($condition['column'] == 'contact.type') {
+    // Search on the contact type.
+    if ($condition['column'] == $field_term_id . ',' . $type_term) {
+      $talias = $contact_linker . '_contact_type';
+      $this->queryJoinOnce($query, 'cvterm', $talias, "$calias.type_id = $talias.cvterm_id");
+      $query->condition("$talias.name", $condition['value'], $operator);
+    }
+  }
 
 
+  /**
+   * @see ChadoField::queryOrder()
+   */
+  public function queryOrder($query, $order) {
+    $alias = $this->field['field_name'];
+    $field_term_id = $this->getFieldTermID();
+    $type_term = tripal_get_chado_semweb_term('contact', 'type_id');
+    $name_term = tripal_get_chado_semweb_term('contact', 'name');
+    $description_term = tripal_get_chado_semweb_term('contact', 'description');
+
+    $contact_linker = $this->instance['settings']['chado_table'];
+    $base_table = $this->instance['settings']['base_table'];
+
+    // Get the FK that links to the base record.
+    $schema = chado_get_schema($contact_linker);
+    $pkey = $schema['primary key'][0];
+    $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
+    $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
+
+    // Join the contact linker table and then join the contact table.
+    $calias = $contact_linker . '_contact';
+    $this->queryJoinOnce($query, $contact_linker, $alias, "base.$fkey_rcolumn = $alias.$fkey_lcolumn", "LEFT OUTER");
+    $this->queryJoinOnce($query, 'contact', $calias, "$calias.contact_id = $alias.contact_id", "LEFT OUTER");
+
+    // Search by the contact name
+    if ($order['column'] == $field_term_id or
+        $order['column'] == $field_term_id . ',' . $name_term) {
+      $query->orderBy("$calias.name", $order['direction']);
+    }
+    // Search on the contact description.
+    if ($order['column'] == $field_term_id . ',' . $description_term) {
+      $query->orderBy("$calias.description", $order['direction']);
+    }
+    // Search on the contact type.
+    if ($order['column'] == $field_term_id . ',' . $type_term) {
+      $talias = $contact_linker . '_contact_type';
+      $this->queryJoinOnce($query, 'cvterm', $talias, "$calias.type_id = $talias.cvterm_id", "LEFT OUTER");
+      $query->orderBy("$talias.name", $order['direction']);
     }
     }
   }
   }
 }
 }
 
 
+
+
 /**
 /**
  * An Ajax callback for the pub widget.
  * An Ajax callback for the pub widget.
  */
  */

+ 31 - 34
tripal_chado/includes/TripalFields/chado_linker__contact/chado_linker__contact_widget.inc

@@ -17,39 +17,38 @@ class chado_linker__contact_widget extends ChadoFieldWidget {
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
     $field_type = $this->field['type'];
     $field_type = $this->field['type'];
     $base_table = $this->instance['settings']['base_table'];
     $base_table = $this->instance['settings']['base_table'];
-    $chado_table = $this->instance['settings']['chado_table'];
+    $field_table = $this->instance['settings']['chado_table'];
     $chado_column = $this->instance['settings']['chado_column'];
     $chado_column = $this->instance['settings']['chado_column'];
     $instance = $this->instance;
     $instance = $this->instance;
 
 
     // Get the FK column that links to the base table.
     // Get the FK column that links to the base table.
-    $schema = chado_get_schema($chado_table);
+    $schema = chado_get_schema($field_table);
     $pkey = $schema['primary key'][0];
     $pkey = $schema['primary key'][0];
-    $lfkey_field = key($schema['foreign keys'][$base_table]['columns']);
+    $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
+    $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
 
 
     // Get the field defaults.
     // Get the field defaults.
     $record_id = '';
     $record_id = '';
-    $fk_value = array_key_exists('#entity', $element) and $element['#entity'] ? $element['#entity']->chado_record_id : NULL;
+    $fk_value = (array_key_exists('#entity', $element) and $element['#entity']) ? $element['#entity']->chado_record_id : NULL;
     $contact_id = '';
     $contact_id = '';
     $name = '';
     $name = '';
     $value = '';
     $value = '';
 
 
+    $name_term = tripal_get_chado_semweb_term('contact', 'name');
 
 
     // If the field already has a value then it will come through the $items
     // If the field already has a value then it will come through the $items
     // array.  This happens when editing an existing record.
     // array.  This happens when editing an existing record.
-    if (count($items) > 0) {
-      // Check for element values that correspond to fields in the Chado table.
-      $fk_value = tripal_get_field_item_keyval($items, 0, 'chado-' . $chado_table . '__' . $lfkey_field, $fk_value);
-      if (array_key_exists($delta, $items)) {
-        $record_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $chado_table . '__' . $pkey, $record_id);
-        $contact_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $chado_table . '__contact_id', $contact_id);
-      }
+    if (count($items) > 0 and array_key_exists($delta, $items)) {
+      $name = array_key_exists($name_term, $items[$delta]['value']) ? $items[$delta]['value'][$name_term] : $name;
+      $fk_value = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__' . $fkey_lcolumn, $fk_value);
+      $record_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__' . $pkey, $record_id);
+      $contact_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__contact_id', $contact_id);
     }
     }
 
 
     // Check $form_state['values'] to see if an AJAX call set the values.
     // Check $form_state['values'] to see if an AJAX call set the values.
-    if (array_key_exists('values', $form_state) and array_key_exists($delta, $form_state['values'])) {
-      $record_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__' . $pkey];
-      $fk_value = $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__' . $lfkey_field];
-      $contact_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__contact_id'];
+    if (array_key_exists('values', $form_state) and
+        array_key_exists($field_name, $form_state['values'])) {
+      $name = $form_state['values'][$field_name]['und'][$delta]['name'];
     }
     }
 
 
 
 
@@ -60,15 +59,15 @@ class chado_linker__contact_widget extends ChadoFieldWidget {
       '#value' => array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
       '#value' => array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
     );
     );
 
 
-    $widget['chado-' . $chado_table . '__' . $pkey] = array(
+    $widget['chado-' . $field_table . '__' . $pkey] = array(
       '#type' => 'value',
       '#type' => 'value',
       '#default_value' => $record_id,
       '#default_value' => $record_id,
     );
     );
-    $widget['chado-' . $chado_table . '__' . $lfkey_field] = array(
+    $widget['chado-' . $field_table . '__' . $fkey_lcolumn] = array(
       '#type' => 'value',
       '#type' => 'value',
       '#default_value' => $fk_value,
       '#default_value' => $fk_value,
     );
     );
-    $widget['chado-' . $chado_table . '__contact_id'] = array(
+    $widget['chado-' . $field_table . '__contact_id'] = array(
       '#type' => 'value',
       '#type' => 'value',
       '#default_value' => $contact_id,
       '#default_value' => $contact_id,
     );
     );
@@ -78,12 +77,6 @@ class chado_linker__contact_widget extends ChadoFieldWidget {
       '#title' => t('Contact'),
       '#title' => t('Contact'),
       '#default_value' => $name,
       '#default_value' => $name,
       '#autocomplete_path' => 'admin/tripal/storage/chado/auto_name/contact',
       '#autocomplete_path' => 'admin/tripal/storage/chado/auto_name/contact',
-      '#ajax' => array(
-        'callback' => "chado_linker__contact_widget_form_ajax_callback",
-        'wrapper' => "$chado_table-$delta",
-        'effect' => 'fade',
-        'method' => 'replace'
-      ),
       '#maxlength' => 100000,
       '#maxlength' => 100000,
     );
     );
   }
   }
@@ -93,31 +86,35 @@ class chado_linker__contact_widget extends ChadoFieldWidget {
    *
    *
    * @see TripalFieldWidget::submit()
    * @see TripalFieldWidget::submit()
    */
    */
-  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
+  public function validate($element, $form, &$form_state, $langcode, $delta) {
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
     $field_type = $this->field['type'];
     $field_type = $this->field['type'];
     $base_table = $this->instance['settings']['base_table'];
     $base_table = $this->instance['settings']['base_table'];
-    $chado_table = $this->instance['settings']['chado_table'];
+    $field_table = $this->instance['settings']['chado_table'];
     $chado_column = $this->instance['settings']['chado_column'];
     $chado_column = $this->instance['settings']['chado_column'];
     $instance = $this->instance;
     $instance = $this->instance;
-    $schema = chado_get_schema($chado_table);
 
 
+    // Get information about this contact linke rtable.
+    $schema = chado_get_schema($field_table);
     $pkey = $schema['primary key'][0];
     $pkey = $schema['primary key'][0];
     $lfkey_field = key($schema['foreign keys'][$base_table]['columns']);
     $lfkey_field = key($schema['foreign keys'][$base_table]['columns']);
 
 
-    // Get the field values.
-    $record_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__' . $pkey];
-    $fk_value = $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__' . $lfkey_field];
-    $contact_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__contact_id'];
+    // Get the name from the form state.
     $name = $form_state['values'][$field_name]['und'][$delta]['name'];
     $name = $form_state['values'][$field_name]['und'][$delta]['name'];
 
 
     // If the user provided a name then we want to set the foreign key
     // If the user provided a name then we want to set the foreign key
     // value to be the chado_record_id
     // value to be the chado_record_id
     if ($name) {
     if ($name) {
       $contact = chado_generate_var('contact', array('name' => $name));
       $contact = chado_generate_var('contact', array('name' => $name));
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $chado_table . '__contact_id'] = $contact->contact_id;
-      $form_state['values'][$field_name][$langcode][$delta]['value'] = $name;
+      if ($contact) {
+        $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__contact_id'] = $contact->contact_id;
+        $form_state['values'][$field_name]['und'][$delta]['value'] = $name;
+      }
+    }
+    // If no name is provided then we want to set the field for deletion.
+    else {
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $lfkey_field] = '';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__contact_id'] = '';
     }
     }
-    dpm($form_state['values']);
   }
   }
 }
 }

+ 0 - 178
tripal_chado/includes/TripalFields/chado_linker__cvterm/chado_linker__cvterm.inc

@@ -1,178 +0,0 @@
-<?php
-
-class chado_linker__cvterm extends ChadoField {
-
-
-  // --------------------------------------------------------------------------
-  //                     EDITABLE STATIC CONSTANTS
-  //
-  // The following constants SHOULD be set for each descendent class.  They are
-  // used by the static functions to provide information to Drupal about
-  // the field and it's default widget and formatter.
-  // --------------------------------------------------------------------------
-
-  // The default lable for this field.
-  public static $default_label = 'Chado Annotation';
-
-  // The default description for this field.
-  public static $description = 'This record can be annotated with terms from other
-              vocabularies.';
-
-  // Provide a list of instance specific settings. These can be access within
-  // the instanceSettingsForm.  When the instanceSettingsForm is submitted
-  // then Drupal with automatically change these settings for the instnace.
-  // It is recommended to put settings at the instance level whenever possible.
-  // If you override this variable in a child class be sure to replicate the
-  // term_name, term_vocab, term_accession and term_fixed keys as these are
-  // required for all TripalFields.
-  public static $default_instance_settings  = array(
-    // The short name for the vocabulary (e.g. shcema, SO, GO, PATO, etc.).
-    'term_vocabulary' => 'local',
-    // The name of the term.
-    'term_name' => 'cvterm',
-    // The unique ID (i.e. accession) of the term.
-    'term_accession' => 'cvterm',
-    // Set to TRUE if the site admin is allowed to change the term
-    // type. This will create form elements when editing the field instance
-    // to allow the site admin to change the term settings above.
-    'term_fixed' => FALSE,
-  );
-
-  // The default widget for this field.
-  public static $default_widget = 'chado_linker__cvterm_widget';
-
-  // The default formatter for this field.
-  public static $default_formatter = 'chado_linker__cvterm_formatter';
-
-  // A boolean specifying that users should not be allowed to create
-  // fields and instances of this field type through the UI. Such
-  // fields can only be created programmatically with field_create_field()
-  // and field_create_instance().
-  public static $no_ui = FALSE;
-
-
-
-  /**
-   *
-   * @see TripalField::load()
-   */
-  public function load($entity) {
-    $field_name = $this->field['field_name'];
-    $field_type = $this->field['type'];
-    $field_table = $this->instance['settings']['chado_table'];
-    $field_column = $this->instance['settings']['chado_column'];
-    $base_table = $this->instance['settings']['base_table'];
-
-    $vocabulary = $this->instance['settings']['term_vocabulary'];
-    $accession = $this->instance['settings']['term_accession'];
-    $cvterm = tripal_get_cvterm(array(
-      'dbxref_id' => array(
-        'db_id' => array(
-          'name' => $vocabulary,
-        ),
-        'accession' => $accession,
-      ),
-    ));
-    $cvterm_id = $cvterm->cvterm_id;
-
-    // Get the FK that links to the base record.
-    $schema = chado_get_schema($field_table);
-    $pkey = $schema['primary key'][0];
-    $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
-    $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
-
-    // Set some defaults for the empty record.
-    $chado_record = $entity->chado_record;
-    $entity->{$field_name}['und'][0] = array(
-      'value' => '',
-      'chado-' . $field_table . '__' . $fkey_lcolumn => '',
-      'chado-' . $field_table . '__' . 'cvterm_id' => '',
-      // The pub column is present in the cell_line_cvterm, feature_cvterm,
-      // library_cvterm, phenotype_comparision_cvterm, phenotype_cvterm,
-      // stock_cvterm, and stock_relationship_cvterm.
-      'chado-' . $field_table . '__' . 'pub_id' => '',
-      // The is_not column is present in feature_cvterm and stock_cvterm tables.
-      'chado-' . $field_table . '__' . 'is_not' => '',
-      // The rank column is present in the cell_line_cvterm, expression_cvterm,
-      // feature_cvterm, phenotype_comparision_cvterm, phenotype_cvterm,
-      // and stock_cvterm tables.
-      'chado-' . $field_table . '__' . 'rank' => '',
-      // The cvterm_type_id is present in the expression_cvterm table.
-      'cvterm_type_id' => '',
-      // The following field are to help link the cvterm.
-      'cv__cv_id' => '',
-      'cvterm__name' => '',
-    );
-
-    // Get the annotations associated with this base record for this fields type.
-    $columns = array('*');
-    $match = array(
-      $fkey_lcolumn => $chado_record->$fkey_rcolumn,
-      'cvterm_id' => $cvterm_id,
-    );
-    $options = array(
-      'return_array' => TRUE,
-      'order_by' => array('rank' => 'ASC')
-    );
-    $fcvterms = chado_select_record($field_table, $columns, $match, $options);
-    for ($i = 0; $i < count($fcvterms); $i++) {
-      $linker = $fcvterms[$i];
-      $cvterm = chado_generate_var('cvterm', array('cvterm_id' => $linker->cvterm_id));
-      $entity->{$field_name}['und'][$i] = array(
-        'value' => $linker->$pkey,
-        'chado-' . $field_table . '__' . $fkey_lcolumn => $linker->$fkey_lcolumn,
-        'chado-' . $field_table . '__' . 'cvterm_id' => $linker->cvterm_id,
-        'chado-' . $field_table . '__' . 'pub_id' => property_exists($linker, 'pub_id') ? $linker->pub_id : '',
-        'chado-' . $field_table . '__' . 'is_not' => property_exists($linker, 'is_not') ? $linker->is_not : '',
-        'chado-' . $field_table . '__' . 'rank' => property_exists($linker, 'rank') ? $linker->rank : '',
-        'chado-' . $field_table . '__' . 'cvterm_type_id' => property_exists($linker, 'cvterm_type_id') ? $linker->cvterm_type_id : '',
-        'cv__cv_id' => $cvterm->cv_id->cv_id,
-        'cvterm__name' => $cvterm->name,
-      );
-    }
-  }
-}
-
-/**
- * Theme function for the dbxref_id_widget.
- *
- * @param $variables
- */
-function theme_chado_linker__cvterm_widget($variables) {
-  $element = $variables['element'];
-
-  // These two fields were added to the widget to help identify the fields
-  // for layout.
-  $table_name = $element['#table_name'];
-  $fkey = $element['#fkey_field'];
-
-  $layout = "
-    <div class=\"annotation-cvterm-widget\">
-      <div class=\"annotation-cvterm-widget-item\">" .
-      drupal_render($element['cv__cv_id']) . "
-      </div>
-      <div class=\"annotation-cvterm-widget-item\">" .
-      drupal_render($element['cvterm__name']) . "
-      </div>
-      <div class=\"annotation-cvterm-widget-item\">" .
-      drupal_render($element['pub']) . "
-      </div>
-      <div class=\"annotation-cvterm-widget-item\">" .
-      drupal_render($element['chado-' . $table_name . '__is_not']) . "
-      </div>
-    </div>
-  ";
-  return $layout;
-}
-
-/**
- * An Ajax callback for the dbxref widget.
- */
-function chado_linker__cvterm_widget_form_ajax_callback($form, $form_state) {
-
-  $field_name = $form_state['triggering_element']['#parents'][0];
-  $delta = $form_state['triggering_element']['#parents'][2];
-
-
-  return $form[$field_name]['und'][$delta];
-}

+ 0 - 132
tripal_chado/includes/TripalFields/chado_linker__cvterm/chado_linker__cvterm_formatter.inc

@@ -1,132 +0,0 @@
-<?php
-
-class chado_linker__cvterm_formatter extends ChadoFieldFormatter {
-  // The default lable for this field.
-  public static $default_label = 'Chado Annotation';
-
-  // The list of field types for which this formatter is appropriate.
-  public static $field_types = array('chado_linker__cvterm');
-
-
-  /**
-   *
-   * @see TripalFieldFormatter::settingsForm()
-   */
-  public function settingsForm($view_mode, $form, &$form_state) {
-    $headers = array('Term', 'Definition', 'Is Not', 'Reference');
-    $rows = array();
-
-    $chado_table = $this->instance['settings']['chado_table'];
-    foreach ($items as $delta => $item) {
-      if ($item['chado-' . $chado_table . '__cvterm_id']) {
-        $cvterm = chado_generate_var('cvterm', array('cvterm_id' => $item['chado-' . $chado_table . '__cvterm_id']));
-        $dbxref = $cvterm->dbxref_id;
-
-        // Build the accession.
-        $accession = $dbxref->db_id->name . ':' . $dbxref->accession;
-        if ($dbxref->db_id->urlprefix) {
-          $accession = l($accession, tripal_get_dbxref_url($dbxref), array('attributes' => array('target' => '_blank')));
-        }
-
-        // Build the publication reference.
-        $pub_ref = '';
-        $pub_id = $item['chado-' . $chado_table . '__pub_id'];
-        if ($pub_id) {
-          $pub = chado_generate_var('pub', array('pub_id' => $pub_id));
-          $pub_ref = $pub->title;
-        }
-        $rows[] = array(
-          $accession,
-          $cvterm->definition,
-          $item['chado-' . $chado_table . '__is_not'] ? 'Yes' : '',
-          '',
-        );
-      }
-    }
-
-    // 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' => "$chado_table-table-terms",
-        'class' => 'tripal-data-table'
-      ),
-      'caption' => '',
-      'sticky' => FALSE,
-      'colgroups' => array(),
-      'empty' => 'There are no annotations of this type',
-    );
-
-    if (count($items) > 0) {
-      $element[0] = array(
-        '#type' => 'markup',
-        '#markup' => theme_table($table),
-      );
-    }
-  }
-
-  /**
-   *
-   * @see TripalFieldFormatter::view()
-   */
-  public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
-    $headers = array('Term', 'Definition', 'Is Not', 'Publication');
-    $rows = array();
-
-    $chado_table = $this->instance['settings']['chado_table'];
-    foreach ($items as $delta => $item) {
-      if ($item['chado-' . $chado_table . '__cvterm_id']) {
-        $cvterm = chado_generate_var('cvterm', array('cvterm_id' => $item['chado-' . $chado_table . '__cvterm_id']));
-        $dbxref = $cvterm->dbxref_id;
-
-        // Build the accession.
-        $accession = $dbxref->db_id->name . ':' . $dbxref->accession;
-        if ($dbxref->db_id->urlprefix) {
-          $accession = l($accession, tripal_get_dbxref_url($dbxref), array('attributes' => array('target' => '_blank')));
-        }
-
-        // Build the publication reference.
-        $pub_ref = '';
-        $pub_id = $item['chado-' . $chado_table . '__pub_id'];
-        if ($pub_id) {
-          $pub = chado_generate_var('pub', array('pub_id' => $pub_id));
-          $pub_ref = $pub->uniquename;
-        }
-        $rows[] = array(
-          $accession,
-          $cvterm->definition,
-          $item['chado-' . $chado_table . '__is_not'] ? 'Yes' : '',
-          $pub_ref,
-        );
-      }
-    }
-
-    // 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' => "$chado_table-table-terms",
-        'class' => 'tripal-data-table'
-      ),
-      'caption' => '',
-      'sticky' => FALSE,
-      'colgroups' => array(),
-      'empty' => 'There are no annotations of this type',
-    );
-
-    if (count($items) > 0) {
-      $element[0] = array(
-        '#type' => 'markup',
-        '#markup' => theme_table($table),
-      );
-    }
-  }
-}

+ 0 - 176
tripal_chado/includes/TripalFields/chado_linker__cvterm/chado_linker__cvterm_widget.inc

@@ -1,176 +0,0 @@
-<?php
-
-class chado_linker__cvterm_widget extends ChadoFieldWidget {
-  // The default lable for this field.
-  public static $default_label = 'Chado Annotation';
-
-  // The list of field types for which this formatter is appropriate.
-  public static $field_types = array('chado_linker__cvterm');
-
-  /**
-   *
-   * @see TripalFieldWidget::form()
-   */
-  public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
-    parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
-    $field_name = $this->field['field_name'];
-
-    $matches = array();
-    preg_match('/(.*?)__(\d+)/', $field_name, $matches);
-    // If the field name is not properly formatted then we can't tell what
-    // table and type this is.  So just return.
-    if (count($matches) != 3) {
-      return $widget;
-    }
-    $table_name = $matches[1];
-    $cv_id = $matches[2];
-
-    // Get the FK column that links to the base table.
-    $chado_table = $this->instance['settings']['chado_table'];
-    $base_table = $this->instance['settings']['base_table'];
-    $schema = chado_get_schema($chado_table);
-    $pkey = $schema['primary key'][0];
-    $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);
-    $fkey = $fkeys[0];
-
-    // Get the field defaults.
-    $record_id = '';
-    $fkey_value = $element['#entity']->chado_record_id;
-    $cvterm_name = '';
-    $cvterm_id = '';
-    $pub_id = '';
-    $uname = '';
-    $is_not = '';
-    $cvterm = NULL;
-
-    // If the field already has a value then it will come through the $items
-    // array.  This happens when editing an existing record.
-    if (array_key_exists($delta, $items)) {
-      $record_id = $items[$delta]['value'];
-      $cvterm_name = $items[$delta]['cvterm__name'];
-      $pub_id =$items[$delta]['chado-' . $table_name . '__pub_id'];
-      if ($pub_id && $pub_id != 1) {
-        $pub = chado_generate_var('pub', array('pub_id' => $pub_id));
-        $uname = $pub->uniquename;
-      }
-      $is_not = $items[$delta]['chado-' . $table_name . '__is_not'];
-      $cvterm_id = $items[$delta]['chado-' . $table_name . '__cvterm_id'];
-    }
-
-    // Check $form_state['values'] to see if an AJAX call set the values.
-    if (array_key_exists('values', $form_state) and array_key_exists($delta, $form_state['values'])) {
-      // See example in chado_linker_contact.inc
-      //       $record_id = tripal_chado_get_field_form_values($table_name, $form_state, $delta, $table_name);
-      //       $fkey_value = tripal_chado_get_field_form_values($table_name, $form_state, $delta, $table_name . '__' . $fkey);
-      //       $is_not = tripal_chado_get_field_form_values($table_name, $form_state, $delta, $table_name . '__is_not');
-      //       $cvterm_name = tripal_chado_get_field_form_values($table_name, $form_state, $delta, $table_name . '--cvterm__name');
-    }
-
-    if ($cvterm_name) {
-      $cvterm = chado_generate_var('cvterm', array('cv_id' => $cv_id, 'name' => $cvterm_name));
-    }
-
-    $schema = chado_get_schema('cvterm');
-    $options = tripal_get_cv_select_options();
-
-    $widget['#table_name'] = $chado_table;
-    $widget['#fkey_field'] = $fkey;
-    $widget['#prefix'] =  "<span id='$table_name-$delta'>";
-    $widget['#suffix'] =  "</span>";
-
-    $widget['value'] = array(
-      '#type' => 'value',
-      '#value' => key_exists($delta, $items) ? $items[$delta]['value'] : '',
-    );
-
-    $widget['chado-' . $table_name . '__' . $pkey] = array(
-      '#type' => 'value',
-      '#default_value' => $record_id,
-    );
-    $widget['cv__cv_id'] = array(
-      '#type' => 'value',
-      '#default_value' => $cv_id,
-    );
-    $widget['chado-' . $table_name . '__cvterm_id'] = array(
-      '#type' => 'value',
-      '#default_value' => $cvterm ? $cvterm->cvterm_id : '',
-    );
-    $widget['chado-' . $table_name . '__' . $fkey] = array(
-      '#type' => 'value',
-      '#default_value' => $fkey_value,
-    );
-
-    $widget['cvterm__name'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Term Name'),
-      '#default_value' => $cvterm_name,
-      '#required' => $element['#required'],
-      '#maxlength' => array_key_exists('length', $schema['fields']['name']) ? $schema['fields']['name']['length'] : 255,
-      '#autocomplete_path' => 'admin/tripal/storage/chado/auto_name/cvterm/' . $cv_id,
-      '#size' => 30
-    );
-
-    $widget['pub'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Publication'),
-      '#default_value' => $uname,
-      '#autocomplete_path' => 'admin/tripal/storage/chado/auto_name/pub',
-      '#ajax' => array(
-        'callback' => "schema__publication_widget_form_ajax_callback",
-        'wrapper' => "$table_name-$delta",
-        'effect' => 'fade',
-        'method' => 'replace'
-      ),
-      '#maxlength' => 100000,
-    );
-
-    $widget['chado-' . $table_name . '__pub_id'] = array(
-      '#type' => 'value',
-      '#default_value' => $pub_id ? $pub_id : 1,
-    );
-
-    $widget['chado-' . $table_name . '__is_not'] = array(
-      '#type' => 'checkbox',
-      '#title' => t('Is Not'),
-      '#default_value' => $is_not,
-      '#required' => $element['#required'],
-    );
-
-    $widget['cvterm__definition'] = array(
-      '#type' => 'item',
-      '#markup' => '',
-    );
-  }
-
-  /**
-   *
-   * @see TripalFieldWidget::submit()
-   */
-  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
-    $field_name = $this->field['field_name'];
-    $table_name = $this->instance['settings']['chado_table'];
-    $schema = chado_get_schema($table_name);
-    $pkey = $schema['primary key'][0];
-    $base_table = $this->instance['settings']['base_table'];
-    $lfkey_field = key($schema['foreign keys'][$base_table]['columns']);
-    $rfkey_field = $schema['foreign keys'][$base_table]['columns'][$lfkey_field];
-
-
-    // If the form ID is field_ui_field_edit_form, then the user is editing the
-    // field's values in the manage fields form of Drupal.  We don't want
-    // to validate it as if it were being used in a data entry form.
-    if ($form_state['build_info']['form_id'] =='field_ui_field_edit_form') {
-      return;
-    }
-
-    // If the user provided a cv_id and a name then we want to set the
-    // foreign key value to be the chado_record_idd
-    $cvterm_name = isset($form_state['values'][$field_name][$langcode][$delta]['cvterm__name']) ? $form_state['values'][$field_name][$langcode][$delta]['cvterm__name'] : '';
-
-    if (!$cvterm_name) {
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__cvterm_id'] = '';
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__' . $lfkey_field] = '';
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__pub_id'] = '';
-    }
-  }
-}

+ 23 - 0
tripal_chado/includes/TripalFields/chado_linker__prop/chado_linker__prop.inc

@@ -41,6 +41,8 @@ class chado_linker__prop extends ChadoField {
     'chado_column' => '',
     'chado_column' => '',
     // The base table.
     // The base table.
     'base_table' => '',
     'base_table' => '',
+    // The number of default rows to show. The default is 1.
+    'rows' => 1,
   );
   );
 
 
   // The default widget for this field.
   // The default widget for this field.
@@ -130,6 +132,7 @@ class chado_linker__prop extends ChadoField {
   public function query($query, $condition) {
   public function query($query, $condition) {
     $prop_linker = $this->instance['settings']['chado_table'];
     $prop_linker = $this->instance['settings']['chado_table'];
     $base_table = $this->instance['settings']['base_table'];
     $base_table = $this->instance['settings']['base_table'];
+
     $bschema = chado_get_schema($base_table);
     $bschema = chado_get_schema($base_table);
     $bpkey = $bschema['primary key'][0];
     $bpkey = $bschema['primary key'][0];
     $alias = $this->field['field_name'];
     $alias = $this->field['field_name'];
@@ -145,4 +148,24 @@ class chado_linker__prop extends ChadoField {
     $query->condition("$alias.value", $condition['value'], $operator);
     $query->condition("$alias.value", $condition['value'], $operator);
 
 
   }
   }
+
+  /**
+   * @see ChadoField::query()
+   */
+  public function queryOrder($query, $order) {
+    $prop_linker = $this->instance['settings']['chado_table'];
+    $base_table = $this->instance['settings']['base_table'];
+
+    $bschema = chado_get_schema($base_table);
+    $bpkey = $bschema['primary key'][0];
+    $alias = $this->field['field_name'];
+
+    $vocab = $this->instance['settings']['term_vocabulary'];
+    $accession = $this->instance['settings']['term_accession'];
+
+    $cvterm = tripal_get_cvterm(array('id' => $vocab . ':' . $accession));
+
+    $this->queryJoinOnce($query, $prop_linker, $alias, "base.$bpkey = $alias.$bpkey AND $alias.type_id = $cvterm->cvterm_id", "LEFT OUTER");
+    $query->orderBy("$alias.value", $order['direction']);
+  }
 }
 }

+ 38 - 28
tripal_chado/includes/TripalFields/chado_linker__prop/chado_linker__prop_widget.inc

@@ -17,13 +17,14 @@ class chado_linker__prop_widget extends ChadoFieldWidget {
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
     $field_type = $this->field['type'];
     $field_type = $this->field['type'];
     $base_table = $this->instance['settings']['base_table'];
     $base_table = $this->instance['settings']['base_table'];
-    $chado_table = $this->instance['settings']['chado_table'];
+    $field_table = $this->instance['settings']['chado_table'];
     $chado_column = $this->instance['settings']['chado_column'];
     $chado_column = $this->instance['settings']['chado_column'];
+    $rows = array_key_exists('rows', $this->instance['settings']) ? $this->instance['settings']['rows'] : 1;
     $instance = $this->instance;
     $instance = $this->instance;
 
 
     // Get the name of the pkey field for this property table and the name
     // Get the name of the pkey field for this property table and the name
     // of the FK field that links to the base table.
     // of the FK field that links to the base table.
-    $schema = chado_get_schema($chado_table);
+    $schema = chado_get_schema($field_table);
     $pkey = $schema['primary key'][0];
     $pkey = $schema['primary key'][0];
     $lfkey_field = key($schema['foreign keys'][$base_table]['columns']);
     $lfkey_field = key($schema['foreign keys'][$base_table]['columns']);
     $rfkey_field = $schema['foreign keys'][$base_table]['columns'][$lfkey_field];
     $rfkey_field = $schema['foreign keys'][$base_table]['columns'][$lfkey_field];
@@ -39,22 +40,23 @@ class chado_linker__prop_widget extends ChadoFieldWidget {
     // array.  This happens when editing an existing record.
     // array.  This happens when editing an existing record.
     if (count($items) > 0) {
     if (count($items) > 0) {
       // Check for element values that correspond to fields in the Chado table.
       // Check for element values that correspond to fields in the Chado table.
-      $fk_value = tripal_get_field_item_keyval($items, 0, 'chado-' . $chado_table . '__' . $lfkey_field, $fk_value);
-      $type_id = tripal_get_field_item_keyval($items, 0, 'chado-' . $chado_table . '__type_id', $type_id);
+      $fk_value = tripal_get_field_item_keyval($items, 0, 'chado-' . $field_table . '__' . $lfkey_field, $fk_value);
+      $type_id = tripal_get_field_item_keyval($items, 0, 'chado-' . $field_table . '__type_id', $type_id);
       if (array_key_exists($delta, $items)) {
       if (array_key_exists($delta, $items)) {
-        $record_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $chado_table . '__' . $pkey, $record_id);
-        $value = tripal_get_field_item_keyval($items, $delta, 'chado-' . $chado_table . '__value', $value);
-        $rank = tripal_get_field_item_keyval($items, $delta, 'chado-' . $chado_table . '__rank', $rank);
+        $record_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__' . $pkey, $record_id);
+        $value = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__value', $value);
+        $rank = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__rank', $rank);
       }
       }
     }
     }
 
 
     // Check $form_state['values'] to see if an AJAX call set the values.
     // Check $form_state['values'] to see if an AJAX call set the values.
-    if (array_key_exists('values', $form_state) and array_key_exists($delta, $form_state['values'])) {
-      $record_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__' . $pkey];
-      $fk_value = $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__' . $lfkey_field];
-      $type_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__type_id'];
-      $value = $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__value'];
-      $rank = $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__rank'];
+    if (array_key_exists('values', $form_state) and
+        array_key_exists($field_name, $form_state['values'])) {
+      $record_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $pkey];
+      $fk_value = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $lfkey_field];
+      $type_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__type_id'];
+      $value = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__value'];
+      $rank = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__rank'];
     }
     }
 
 
     // Use default value for the field if it's not already set
     // Use default value for the field if it's not already set
@@ -80,25 +82,27 @@ class chado_linker__prop_widget extends ChadoFieldWidget {
       '#value' => array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
       '#value' => array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
     );
     );
 
 
-    $widget['chado-' . $chado_table . '__' . $pkey] = array(
+    $widget['chado-' . $field_table . '__' . $pkey] = array(
       '#type' => 'hidden',
       '#type' => 'hidden',
       '#default_value' => $record_id,
       '#default_value' => $record_id,
     );
     );
-    $widget['chado-' . $chado_table . '__' . $lfkey_field] = array(
+    $widget['chado-' . $field_table . '__' . $lfkey_field] = array(
       '#type' => 'hidden',
       '#type' => 'hidden',
       '#value' => $fk_value,
       '#value' => $fk_value,
     );
     );
-    $widget['chado-' . $chado_table . '__value'] = array(
+    $widget['chado-' . $field_table . '__value'] = array(
       '#type' => 'textarea',
       '#type' => 'textarea',
       '#default_value' => $value,
       '#default_value' => $value,
       '#title' => $instance['label'],
       '#title' => $instance['label'],
       '#description' => $instance['description'],
       '#description' => $instance['description'],
+      '#rows' => $rows,
+      '#required' => $instance['required'],
     );
     );
-    $widget['chado-' . $chado_table . '__type_id'] = array(
+    $widget['chado-' . $field_table . '__type_id'] = array(
       '#type' => 'hidden',
       '#type' => 'hidden',
       '#value' => $type_id,
       '#value' => $type_id,
     );
     );
-    $widget['chado-' . $chado_table . '__rank'] = array(
+    $widget['chado-' . $field_table . '__rank'] = array(
       '#type' => 'hidden',
       '#type' => 'hidden',
       '#value' => $rank,
       '#value' => $rank,
     );
     );
@@ -108,26 +112,32 @@ class chado_linker__prop_widget extends ChadoFieldWidget {
    *
    *
    * @see TripalFieldWidget::submit()
    * @see TripalFieldWidget::submit()
    */
    */
-  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
+  public function validate($element, $form, &$form_state, $langcode, $delta) {
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
-    $chado_table = $this->instance['settings']['chado_table'];
-    $schema = chado_get_schema($chado_table);
+    $field_type = $this->field['type'];
+    $base_table = $this->instance['settings']['base_table'];
+    $field_table = $this->instance['settings']['chado_table'];
+    $chado_column = $this->instance['settings']['chado_column'];
+    $instance = $this->instance;
+
+    $schema = chado_get_schema($field_table);
     $pkey = $schema['primary key'][0];
     $pkey = $schema['primary key'][0];
     $base_table = $this->instance['settings']['base_table'];
     $base_table = $this->instance['settings']['base_table'];
     $lfkey_field = key($schema['foreign keys'][$base_table]['columns']);
     $lfkey_field = key($schema['foreign keys'][$base_table]['columns']);
     $rfkey_field = $schema['foreign keys'][$base_table]['columns'][$lfkey_field];
     $rfkey_field = $schema['foreign keys'][$base_table]['columns'][$lfkey_field];
 
 
-    $value = $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__value'];
+    $value = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__value'];
     $form_state['values'][$field_name]['und'][$delta]['value'] = $value;
     $form_state['values'][$field_name]['und'][$delta]['value'] = $value;
 
 
     // If the user removed the property then we want to clear out the other
     // If the user removed the property then we want to clear out the other
-    // fields so there is no insert.
+    // fields except the pkey value. If the pkey field is present and the value
+    // is present then the chado storage backend will delete the record.
     if (!$value) {
     if (!$value) {
-      $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__' . $pkey] = '';
-      $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__' . $lfkey_field] = '';
-      $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__type_id'] = '';
-      $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__value'] = '';
-      $form_state['values'][$field_name]['und'][$delta]['chado-' . $chado_table . '__rank'] = '';
+      $form_state['values'][$field_name]['und'][$delta]['value'] = 'delete_me';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $lfkey_field] = '';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__type_id'] = '';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__value'] = '';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__rank'] = '';
     }
     }
   }
   }
 }
 }

+ 29 - 17
tripal_chado/includes/TripalFields/data__accession/data__accession.inc

@@ -61,8 +61,6 @@ class data__accession extends ChadoField {
       'chado-' . $field_table . '__' . $field_column => '',
       'chado-' . $field_table . '__' . $field_column => '',
       'db_id' => '',
       'db_id' => '',
       'accession' => '',
       'accession' => '',
-      'version' => '',
-      'description' => '',
     );
     );
 
 
     // Get the primary dbxref record (if it's not NULL).  Because we have a
     // Get the primary dbxref record (if it's not NULL).  Because we have a
@@ -73,10 +71,8 @@ class data__accession extends ChadoField {
       $entity->{$field_name}['und'][0] = array(
       $entity->{$field_name}['und'][0] = array(
         'value' => $dbxref->accession,
         'value' => $dbxref->accession,
         'chado-' . $field_table . '__' . $field_column => $record->$field_column->$field_column,
         'chado-' . $field_table . '__' . $field_column => $record->$field_column->$field_column,
-        'db_id'       => $dbxref->db_id->db_id,
-        'accession'   => $dbxref->accession,
-        'version'     => $dbxref->version,
-        'description' => $dbxref->description,
+        'db_id' => $dbxref->db_id->db_id,
+        'accession' => $dbxref->accession,
       );
       );
     }
     }
   }
   }
@@ -85,25 +81,44 @@ class data__accession extends ChadoField {
    * @see ChadoField::query()
    * @see ChadoField::query()
    */
    */
   public function query($query, $condition) {
   public function query($query, $condition) {
-    $chado_table = $this->instance['settings']['chado_table'];
-    $base_table = $this->instance['settings']['base_table'];
-    $bschema = chado_get_schema($base_table);
-    $bpkey = $bschema['primary key'][0];
-    $alias = 'dbx_linker';
+    $alias = $this->field['field_name'];
     $operator = $condition['operator'];
     $operator = $condition['operator'];
 
 
+    $field_table = $this->instance['settings']['chado_table'];
+    $field_column = $this->instance['settings']['chado_column'];
+
+    $field_term_id = $this->getFieldTermID();
+    $accession_term = tripal_get_chado_semweb_term($field_table, $field_column);
+
     // We don't offer any sub elements so the value coming in should
     // We don't offer any sub elements so the value coming in should
     // always be the field_name.
     // always be the field_name.
-    if ($condition['column'] == 'data__accession') {
+    if ($condition['column'] == $accession_term) {
       $this->queryJoinOnce($query, 'dbxref', 'DBX', "DBX.dbxref_id = base.dbxref_id");
       $this->queryJoinOnce($query, 'dbxref', 'DBX', "DBX.dbxref_id = base.dbxref_id");
       $query->condition("DBX.accession", $condition['value'], $operator);
       $query->condition("DBX.accession", $condition['value'], $operator);
     }
     }
   }
   }
 
 
+  public function queryOrder($query, $order) {
+    $alias = $this->field['field_name'];
+    $operator = $condition['operator'];
+    $field_table = $this->instance['settings']['chado_table'];
+    $field_column = $this->instance['settings']['chado_column'];
+
+    $field_term_id = $this->getFieldTermID();
+    $accession_term = tripal_get_chado_semweb_term($field_table, $field_column);
+
+    // We don't offer any sub elements so the value coming in should
+    // always be the field_name.
+    if ($order['column'] == $accession_term) {
+      $this->queryJoinOnce($query, 'dbxref', 'DBX', "DBX.dbxref_id = base.dbxref_id", "LEFT OUTER");
+      $query->orderBy("DBX.accession", $order['direction']);
+    }
+  }
+
   /**
   /**
    * @see TripalField::validate()
    * @see TripalField::validate()
    */
    */
-  public function validate($entity_type, $entity, $field, $items, &$errors) {
+  public function validate($entity_type, $entity, $langcode, $items, &$errors) {
 
 
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
     $settings = $this->field['settings'];
     $settings = $this->field['settings'];
@@ -113,11 +128,8 @@ class data__accession extends ChadoField {
 
 
     // Get the field values.
     // Get the field values.
     foreach ($items as $delta => $values) {
     foreach ($items as $delta => $values) {
-      $fk_val = $values['chado-' . $field_table . '__' . $field_column];
       $db_id = $values['db_id'];
       $db_id = $values['db_id'];
       $accession = $values['accession'];
       $accession = $values['accession'];
-      $version = $values['version'];
-      $description = $values['description'];
 
 
       // Make sure that if a database ID is provided that an accession is also
       // Make sure that if a database ID is provided that an accession is also
       // provided.  Here we use the form_set_error function rather than the
       // provided.  Here we use the form_set_error function rather than the
@@ -138,7 +150,7 @@ class data__accession extends ChadoField {
           'error' => 'chado_base__dbxref',
           'error' => 'chado_base__dbxref',
         );
         );
       }
       }
-      if (!$db_id and !$accession and ($version or $description)) {
+      if (!$db_id and !$accession) {
         $errors[$field_name][$delta]['und'][] = array(
         $errors[$field_name][$delta]['und'][] = array(
           'message' => t("A database and the accession must both be provided for the primary cross reference."),
           'message' => t("A database and the accession must both be provided for the primary cross reference."),
           'error' => 'chado_base__dbxref',
           'error' => 'chado_base__dbxref',

+ 58 - 73
tripal_chado/includes/TripalFields/data__accession/data__accession_widget.inc

@@ -18,29 +18,24 @@ class data__accession_widget extends ChadoFieldWidget {
     $field_column = $this->instance['settings']['chado_column'];
     $field_column = $this->instance['settings']['chado_column'];
 
 
     // Get the field defaults.
     // Get the field defaults.
-    $fk_val = '';
+    $dbxref_id = '';
     $db_id = '';
     $db_id = '';
     $accession = '';
     $accession = '';
-    $version = '';
-    $description = '';
 
 
     // If the field already has a value then it will come through the $items
     // If the field already has a value then it will come through the $items
     // array.  This happens when editing an existing record.
     // array.  This happens when editing an existing record.
     if (count($items) > 0 and array_key_exists($delta, $items)) {
     if (count($items) > 0 and array_key_exists($delta, $items)) {
-      $fk_val = $items[$delta]['chado-' . $field_table . '__' . $field_column];
+      $dbxref_id = $items[$delta]['chado-' . $field_table . '__' . $field_column];
       $db_id = $items[$delta]['db_id'];
       $db_id = $items[$delta]['db_id'];
       $accession = $items[$delta]['accession'];
       $accession = $items[$delta]['accession'];
-      $version = $items[$delta]['version'];
-      $description = $items[$delta]['description'];
     }
     }
 
 
     // Check $form_state['values'] to see if an AJAX call set the values.
     // Check $form_state['values'] to see if an AJAX call set the values.
-    if (array_key_exists('values', $form_state)) {
-      $fk_val = isset($form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $field_column]) ? $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $field_column] : '';
+    if (array_key_exists('values', $form_state) and
+        array_key_exists($field_name, $form_state['values'])) {
+      $dbxref_id = isset($form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $field_column]) ? $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $field_column] : '';
       $db_id = isset($form_state['values'][$field_name]['und'][$delta]['db_id']) ? $form_state['values'][$field_name]['und'][$delta]['db_id'] : '';
       $db_id = isset($form_state['values'][$field_name]['und'][$delta]['db_id']) ? $form_state['values'][$field_name]['und'][$delta]['db_id'] : '';
       $accession = isset($form_state['values'][$field_name]['und'][$delta]['accession']) ? $form_state['values'][$field_name]['und'][$delta]['accession'] : '';
       $accession = isset($form_state['values'][$field_name]['und'][$delta]['accession']) ? $form_state['values'][$field_name]['und'][$delta]['accession'] : '';
-      $version = isset($form_state['values'][$field_name]['und'][$delta]['version']) ? $form_state['values'][$field_name]['und'][$delta]['version'] : '';
-      $description = isset($form_state['values'][$field_name]['und'][$delta]['description']) ? $form_state['values'][$field_name]['und'][$delta]['description'] : '';
     }
     }
 
 
     $schema = chado_get_schema('dbxref');
     $schema = chado_get_schema('dbxref');
@@ -52,12 +47,12 @@ class data__accession_widget extends ChadoFieldWidget {
 
 
     $widget['value'] = array(
     $widget['value'] = array(
       '#type' => 'value',
       '#type' => 'value',
-      '#value' => array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
+      '#value' => $dbxref_id,
     );
     );
 
 
     $widget['chado-' . $field_table . '__' . $field_column] = array(
     $widget['chado-' . $field_table . '__' . $field_column] = array(
       '#type' => 'value',
       '#type' => 'value',
-      '#default_value' => $fk_val,
+      '#default_value' => $dbxref_id,
     );
     );
 
 
     $widget['db_id'] = array(
     $widget['db_id'] = array(
@@ -81,39 +76,14 @@ class data__accession_widget extends ChadoFieldWidget {
       '#maxlength' => array_key_exists('length', $schema['fields']['accession']) ? $schema['fields']['accession']['length'] : 255,
       '#maxlength' => array_key_exists('length', $schema['fields']['accession']) ? $schema['fields']['accession']['length'] : 255,
       '#size' => 15,
       '#size' => 15,
       '#autocomplete_path' => 'admin/tripal/storage/chado/auto_name/dbxref/' . $db_id,
       '#autocomplete_path' => 'admin/tripal/storage/chado/auto_name/dbxref/' . $db_id,
-      '#ajax' => array(
-        'callback' => "tripal_chado_dbxref_widget_form_ajax_callback",
-        'wrapper' => "$field_name-dbxref--db-id",
-        'effect' => 'fade',
-        'method' => 'replace'
-      ),
       '#disabled' => $db_id ? FALSE : TRUE,
       '#disabled' => $db_id ? FALSE : TRUE,
     );
     );
-    $widget['version'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Version'),
-      '#default_value' => $version,
-      '#maxlength' => array_key_exists('length', $schema['fields']['version']) ? $schema['fields']['version']['length'] : 255,
-      '#size' => 5,
-      '#disabled' => $db_id ? FALSE : TRUE,
-    );
-    $widget['description'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Description'),
-      '#default_value' => $description,
-      '#size' => 20,
-      '#disabled' => $db_id ? FALSE : TRUE,
-    );
-    $widget['links'] = array(
-      '#type' => 'item',
-      '#markup' => l('Add a new database', 'admin/tripal/loaders/chado_db/add', array('attributes' => array('target' => '_blank')))
-    );
   }
   }
 
 
   /**
   /**
    * @see TripalFieldWidget::submit()
    * @see TripalFieldWidget::submit()
    */
    */
-  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
+  public function validate($element, $form, &$form_state, $langcode, $delta) {
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
     $settings = $this->field['settings'];
     $settings = $this->field['settings'];
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
@@ -121,26 +91,55 @@ class data__accession_widget extends ChadoFieldWidget {
     $field_table = $this->instance['settings']['chado_table'];
     $field_table = $this->instance['settings']['chado_table'];
     $field_column = $this->instance['settings']['chado_column'];
     $field_column = $this->instance['settings']['chado_column'];
 
 
-    $fk_val = isset($form_state['values'][$field_name][$langcode][$delta]['chado-' . $field_table . '__' . $field_column]) ? $form_state['values'][$field_name][$langcode][$delta]['chado-' . $field_table . '__' . $field_column] : '';
-    $db_id = isset($form_state['values'][$field_name][$langcode][$delta]['db_id']) ? $form_state['values'][$field_name][$langcode][$delta]['db_id'] : '';
-    $accession = isset($form_state['values'][$field_name][$langcode][$delta]['accession']) ? $form_state['values'][$field_name][$langcode][$delta]['accession'] : '';
-    if (!$accession) {
-      $accession = $form_state['values'][$field_name][$langcode][$delta]['value'];
-    }
-    $version = isset($form_state['values'][$field_name][$langcode][$delta]['version']) ? $form_state['values'][$field_name][$langcode][$delta]['version'] : '';
+    $dbxref_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__dbxref_id'];
+    $db_id = $form_state['values'][$field_name]['und'][$delta]['db_id'];
+    $accession = $form_state['values'][$field_name]['und'][$delta]['accession'];
 
 
     // If user did not select a database, we want to remove dbxref_id from the
     // If user did not select a database, we want to remove dbxref_id from the
-    // field.
+    // field. We use '__NULL__' because this field is part of the base table
+    // and this tells the Chado backend to insert a null rather than an empty
+    // string.
     if (!$db_id) {
     if (!$db_id) {
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $field_table . '__dbxref_id'] = '__NULL__';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__dbxref_id'] = '__NULL__';
     }
     }
     // If the dbxref_id does not match the db_id + accession then the user
     // If the dbxref_id does not match the db_id + accession then the user
     // has selected a new dbxref record and we need to update the hidden
     // has selected a new dbxref record and we need to update the hidden
     // value accordingly.
     // value accordingly.
     if ($db_id and $accession) {
     if ($db_id and $accession) {
       $dbxref = chado_generate_var('dbxref', array('db_id' => $db_id, 'accession' => $accession));
       $dbxref = chado_generate_var('dbxref', array('db_id' => $db_id, 'accession' => $accession));
-      if ($dbxref and $dbxref->dbxref_id != $fk_val) {
-        $form_state['values'][$field_name][$langcode][$delta]['chado-' . $field_table . '__dbxref_id'] = $dbxref->dbxref_id;
+      if ($dbxref and $dbxref->dbxref_id != $dbxref_id) {
+        $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__dbxref_id'] = $dbxref->dbxref_id;
+        $form_state['values'][$field_name]['und'][$delta]['value'] = $dbxref->dbxref_id;
+      }
+    }
+  }
+
+  /**
+   * @see TripalFieldWidget::submit()
+   */
+  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
+    $field_name = $this->field['field_name'];
+    $settings = $this->field['settings'];
+    $field_name = $this->field['field_name'];
+    $field_type = $this->field['type'];
+    $field_table = $this->instance['settings']['chado_table'];
+    $field_column = $this->instance['settings']['chado_column'];
+
+    $dbxref_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__dbxref_id'];
+    $db_id = $form_state['values'][$field_name]['und'][$delta]['db_id'];
+    $accession = $form_state['values'][$field_name]['und'][$delta]['accession'];
+
+    // If the accession doesn't exist then add it.
+    if ($db_id and $accession) {
+      $dbxref = chado_generate_var('dbxref', array('db_id' => $db_id, 'accession' => $accession));
+      if (!$dbxref) {
+        $values = array(
+          'db_id' => $db_id,
+          'accession' => $accession,
+        );
+        $dbxref = tripal_insert_dbxref($values);
+        $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__dbxref_id'] = $dbxref->dbxref_id;
+        $form_state['values'][$field_name]['und'][$delta]['value'] = $dbxref->dbxref_id;
       }
       }
     }
     }
   }
   }
@@ -157,13 +156,6 @@ class data__accession_widget extends ChadoFieldWidget {
         <div class=\"primary-dbxref-widget-item\">" .
         <div class=\"primary-dbxref-widget-item\">" .
           drupal_render($element['accession']) . "
           drupal_render($element['accession']) . "
         </div>
         </div>
-        <div class=\"primary-dbxref-widget-item\">" .
-          drupal_render($element['version']) . "
-        </div>
-        <div class=\"primary-dbxref-widget-item\">" .
-          drupal_render($element['description']) . "
-        </div>
-        <div class=\"primary-dbxref-widget-links\">" . drupal_render($element['links']) . "</div>
       </div>
       </div>
     ";
     ";
 
 
@@ -172,7 +164,6 @@ class data__accession_widget extends ChadoFieldWidget {
       '#value' => '',
       '#value' => '',
       '#description' => $element['#description'],
       '#description' => $element['#description'],
       '#children' => $layout,
       '#children' => $layout,
-      //    '#attributes' => array('class' => $classes),
     );
     );
 
 
     return theme('fieldset', array('element' => $fieldset));
     return theme('fieldset', array('element' => $fieldset));
@@ -186,23 +177,17 @@ function data__accession_widget_form_ajax_callback($form, $form_state) {
 
 
   $instance = $form['#instance'];
   $instance = $form['#instance'];
   $field_name = $form_state['triggering_element']['#parents'][0];
   $field_name = $form_state['triggering_element']['#parents'][0];
-  $field = field_info_field($field_name);
-  $field_type = $field['type'];
-  $field_table = $instance['settings']['chado_table'];
-  $field_column = $instance['settings']['chado_column'];
-  $field_prefix = 'chado-' . $field_table . '__' . $field_column;
-
-  //   $db_id = tripal_chado_get_field_form_values($field_name, $form_state, 0, $field_prefix . '--db_id');
-  //   $accession = tripal_chado_get_field_form_values($field_name, $form_state, 0, $field_prefix . '--accession');
+  $dbxref_id = $form_state['input'][$field_name]['und'][0]['chado-' . $field_table . '__dbxref_id'];
+  $db_id = $form_state['input'][$field_name]['und'][0]['db_id'];
+  $accession = $form_state['input'][$field_name]['und'][0]['accession'];
+
+  // If we don't have a match then this must be new accession. Because
+  // this is a database defined access we will automatically add the
+  // accession.
   if ($db_id and $accession) {
   if ($db_id and $accession) {
-    $values = array(
-      'db_id' => $db_id,
-      'accession' => $accession,
-    );
-    $options = array('is_duplicate' => TRUE);
-    $has_duplicate = chado_select_record('dbxref', array('*'), $values, $options);
-    if (!$has_duplicate) {
-      drupal_set_message('The selected cross reference is new and will be added for future auto completions.', 'warning');
+    $dbxref = chado_generate_var('dbxref', array('db_id' => $db_id, 'accession' => $accession));
+    if (!$dbxref) {
+      drupal_set_message('The accession provided does not exist in the database and will be added.', 'warning');
     }
     }
   }
   }
 
 

+ 11 - 4
tripal_chado/includes/TripalFields/data__protein_sequence/data__protein_sequence.inc

@@ -49,13 +49,15 @@ class data__protein_sequence extends ChadoField {
    */
    */
   public function elementInfo() {
   public function elementInfo() {
     $field_term = $this->getFieldTermID();
     $field_term = $this->getFieldTermID();
-    return array(
+    $info = array(
       $field_term => array(
       $field_term => array(
-        'operations' => array(),
+        'label' => 'Protein sequence',
+        'help' => 'The polypeptide sequence derived from mRNA',
         'sortable' => FALSE,
         'sortable' => FALSE,
         'searchable' => FALSE,
         'searchable' => FALSE,
       ),
       ),
     );
     );
+    return $info;
   }
   }
   /**
   /**
    * @see TripalField::load()
    * @see TripalField::load()
@@ -85,9 +87,14 @@ class data__protein_sequence extends ChadoField {
     ";
     ";
     $proteins = chado_query($sql, array(':feature_id' => $feature->feature_id));
     $proteins = chado_query($sql, array(':feature_id' => $feature->feature_id));
     while ($protein = $proteins->fetchObject()) {
     while ($protein = $proteins->fetchObject()) {
-      if ($protein->residues) {
-        $entity->{$field_name}['und'][$num_seqs++]['value'] = $protein->residues;
+      $entity->{$field_name}['und'][$num_seqs]['value'] = $protein->residues;
+      // Because we'll be saving a feature we need to maintain all of it's
+      // columns in the feature table. The following will add them all.
+      $columns = get_object_vars($protein);
+      foreach ($columns as $colname => $value) {
+        $entity->{$field_name}['und'][$num_seqs]['chado-feature__' . $colname] = $value;
       }
       }
+      $num_seqs++;
     }
     }
   }
   }
 }
 }

+ 1 - 8
tripal_chado/includes/TripalFields/data__protein_sequence/data__protein_sequence_formatter.inc

@@ -7,15 +7,8 @@ class data__protein_sequence_formatter extends ChadoFieldFormatter {
   // The list of field types for which this formatter is appropriate.
   // The list of field types for which this formatter is appropriate.
   public static $field_types = array('data__protein_sequence');
   public static $field_types = array('data__protein_sequence');
 
 
-
   /**
   /**
-   *
-   * @param unknown $element
-   * @param unknown $entity_type
-   * @param unknown $entity
-   * @param unknown $langcode
-   * @param unknown $items
-   * @param unknown $display
+   * @see TripalFieldFormatter::view()
    */
    */
   public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
   public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
     $content = 'There is no protein sequence.';
     $content = 'There is no protein sequence.';

+ 4 - 10
tripal_chado/includes/TripalFields/data__protein_sequence/data__protein_sequence_widget.inc

@@ -14,15 +14,9 @@ class data__protein_sequence_widget extends ChadoFieldWidget {
   public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
   public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
 
 
-    // TODO: add the form for setting a protein sequence.
-  }
-
-  /**
-   *
-   * @see TripalFieldWidget::submit()
-   */
-  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
-    $field_name = $this->field['field_name'];
-
+    // TODO: before we can create a widget we must have a way to
+    // save another record whose table matches the same as the base base
+    // table with the chado_storage backend getting confused as to what value
+    // belongs to which feature record.
   }
   }
 }
 }

+ 15 - 3
tripal_chado/includes/TripalFields/data__sequence/data__sequence_widget.inc

@@ -31,6 +31,11 @@ class data__sequence_widget extends ChadoFieldWidget {
     }
     }
 
 
     $widget['value'] = array(
     $widget['value'] = array(
+      '#type' => 'value',
+      '#value' => $residues,
+    );
+
+    $widget['chado-' . $field_table . '__' . $field_column] = array(
       '#type' => 'textarea',
       '#type' => 'textarea',
       '#title' => $element['#title'],
       '#title' => $element['#title'],
       '#description' => $element['#description'],
       '#description' => $element['#description'],
@@ -46,14 +51,21 @@ class data__sequence_widget extends ChadoFieldWidget {
    *
    *
    * @see TripalFieldWidget::submit()
    * @see TripalFieldWidget::submit()
    */
    */
-  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
+  public function validate($element, $form, &$form_state, $langcode, $delta) {
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
+    $field_table = $this->instance['settings']['chado_table'];
+    $field_column = $this->instance['settings']['chado_column'];
 
 
     // Remove any white spaces.
     // Remove any white spaces.
-    $residues = isset($form_state['values'][$field_name][$langcode][$delta]['value']) ? $form_state['values'][$field_name][$langcode][$delta]['value'] : '';
+    $residues = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $field_column];
     if ($residues) {
     if ($residues) {
       $residues = preg_replace('/\s/', '', $residues);
       $residues = preg_replace('/\s/', '', $residues);
-      $form_state['values'][$field_name][$langcode][$delta]['value'] = $residues;
+      $form_state['values'][$field_name]['und'][$delta]['value'] = $residues;
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $field_column] = $residues;
+    }
+    else {
+      $form_state['values'][$field_name]['und'][$delta]['value'] = 'delete_me';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $field_column] = '';
     }
     }
   }
   }
 }
 }

+ 9 - 9
tripal_chado/includes/TripalFields/data__sequence_checksum/data__sequence_checksum_widget.inc

@@ -30,7 +30,7 @@ class data__sequence_checksum_widget extends ChadoFieldWidget {
       '#type' => 'value',
       '#type' => 'value',
       '#value' => $md5checksum,
       '#value' => $md5checksum,
     );
     );
-    $widget['chado-feature__md5checksum'] = array(
+    $widget['chado-' . $field_table . '__md5checksum'] = array(
       '#type' => 'value',
       '#type' => 'value',
       '#value' => $md5checksum,
       '#value' => $md5checksum,
     );
     );
@@ -40,8 +40,8 @@ class data__sequence_checksum_widget extends ChadoFieldWidget {
    *
    *
    * @see TripalFieldWidget::submit()
    * @see TripalFieldWidget::submit()
    */
    */
-  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
-    $field = $this->field;
+  public function validate($element, $form, &$form_state, $langcode, $delta) {
+  $field = $this->field;
     $settings = $field['settings'];
     $settings = $field['settings'];
     $field_name = $field['field_name'];
     $field_name = $field['field_name'];
     $field_type = $field['type'];
     $field_type = $field['type'];
@@ -49,17 +49,17 @@ class data__sequence_checksum_widget extends ChadoFieldWidget {
     $field_column = $this->instance['settings']['chado_column'];
     $field_column = $this->instance['settings']['chado_column'];
 
 
     // Get the residues so we can calculate the length.
     // Get the residues so we can calculate the length.
-    $residues = isset($form_state['values']['data__sequence'][$langcode][0]['chado-feature__residues']) ? $form_state['values']['data__sequence'][$langcode][0]['chado-feature__residues'] : '';
-
-    if ($residues) {
+    if ($form_state['values']['data__sequence']['und'][0]['chado-feature__residues']){
       // Remove spaces and new lines from the residues string.
       // Remove spaces and new lines from the residues string.
+      $residues =  $form_state['values']['data__sequence']['und'][0]['chado-feature__residues'];
       $residues = preg_replace('/\s/', '', $residues);
       $residues = preg_replace('/\s/', '', $residues);
-      $form_state['values']['data__sequence'][$langcode][0]['chado-feature__residues'] = $residues;
-      $form_state['values'][$field_name][$langcode][$delta]['chado-feature__md5checksum'] = md5($residues);
+      $checksum = md5($residues);
+      $form_state['values'][$field_name]['und'][0]['chado-feature__md5checksum'] = $checksum;
+      $form_state['values'][$field_name]['und'][0]['value'] = $checksum;
     }
     }
     else {
     else {
       // Otherwise, remove the md5 value
       // Otherwise, remove the md5 value
-      $form_state['values'][$field_name][$langcode][$delta]['chado-feature__md5checksum'] = '__NULL__';
+      $form_state['values'][$field_name]['und'][0]['chado-feature__md5checksum'] = '__NULL__';
     }
     }
   }
   }
 }
 }

+ 106 - 30
tripal_chado/includes/TripalFields/data__sequence_coordinates/data__sequence_coordinates.inc

@@ -60,61 +60,136 @@ class data__sequence_coordinates extends ChadoField {
    */
    */
   public function elementInfo() {
   public function elementInfo() {
     $field_term = $this->getFieldTermID();
     $field_term = $this->getFieldTermID();
+
+    $reference_term = 'data:3002';
+    $fmin_term = tripal_get_chado_semweb_term('featureloc', 'fmin');
+    $fmax_term = tripal_get_chado_semweb_term('featureloc', 'fmax');
+    $strand_term = tripal_get_chado_semweb_term('featureloc', 'strand');
+    $phase_term = tripal_get_chado_semweb_term('featureloc', 'phase');
+
     return array(
     return array(
       $field_term => array(
       $field_term => array(
         'operations' => array(),
         'operations' => array(),
         'sortable' => FALSE,
         'sortable' => FALSE,
         'searchable' => FALSE,
         'searchable' => FALSE,
+        'label' => 'Location Coordinates',
+        'help' => 'The locations on other genomic sequences where this record has been aligned.',
         'elements' => array(
         'elements' => array(
-          'data:3002' => array(
+          $reference_term => array(
             'searchable' => TRUE,
             'searchable' => TRUE,
-            'name' => 'source_feature',
             'label' => 'Location Reference Name',
             'label' => 'Location Reference Name',
             'help' => 'The genomic feature on which this feature is localized.',
             'help' => 'The genomic feature on which this feature is localized.',
             'operations' => array('eq', 'ne', 'contains', 'starts'),
             'operations' => array('eq', 'ne', 'contains', 'starts'),
             'sortable' => TRUE,
             'sortable' => TRUE,
           ),
           ),
-          'local:fmin' => array(
+          $fmin_term => array(
             'searchable' => TRUE,
             'searchable' => TRUE,
-            'name' => 'feature min',
             'label' => 'Location Start Position',
             'label' => 'Location Start Position',
             'help' => 'The start position',
             'help' => 'The start position',
             'type' => 'numeric',
             'type' => 'numeric',
             'operations' => array('eq', 'gt', 'lt', 'gte' ,'lte'),
             'operations' => array('eq', 'gt', 'lt', 'gte' ,'lte'),
             'sortable' => TRUE,
             'sortable' => TRUE,
           ),
           ),
-          'local:fmax' => array(
+          $fmax_term => array(
             'searchable' => TRUE,
             'searchable' => TRUE,
-            'name' => 'feature max',
             'label' => 'Location End Position',
             'label' => 'Location End Position',
             'help' => 'The end position',
             'help' => 'The end position',
             'type' => 'numeric',
             'type' => 'numeric',
             'operations' => array('eq', 'gt', 'lt', 'gte' ,'lte'),
             'operations' => array('eq', 'gt', 'lt', 'gte' ,'lte'),
             'sortable' => TRUE,
             'sortable' => TRUE,
           ),
           ),
-          'data:2336' => array(
+          $phase_term => array(
             'searchable' => TRUE,
             'searchable' => TRUE,
-            'name' => 'phase',
             'type' => 'numeric',
             'type' => 'numeric',
             'label' => 'Location Phase',
             'label' => 'Location Phase',
             'help' => 'The phase of the feature (applicable only to coding sequences).',
             'help' => 'The phase of the feature (applicable only to coding sequences).',
             'operations' => array('eq', 'gt', 'lt', 'gte' ,'lte'),
             'operations' => array('eq', 'gt', 'lt', 'gte' ,'lte'),
             'sortable' => TRUE,
             'sortable' => TRUE,
           ),
           ),
-          'data:0853' => array(
+          $strand_term => array(
             'searchable' => TRUE,
             'searchable' => TRUE,
-            'name' => 'strand',
-            'type' => 'numeric',
             'label' => 'Location Strand',
             'label' => 'Location Strand',
             'help' => 'The orientation of this feature where it is localized',
             'help' => 'The orientation of this feature where it is localized',
             'operations' => array('eq', 'gt', 'lt', 'gte' ,'lte'),
             'operations' => array('eq', 'gt', 'lt', 'gte' ,'lte'),
-            'sortable' => TRUE,
+            'sortable' => FALSE,
           ),
           ),
         ),
         ),
       ),
       ),
     );
     );
   }
   }
 
 
+  /**
+   * @see ChadoField::query()
+   */
+  public function query($query, $condition) {
+    $alias = $this->field['field_name'];
+    $operator = $condition['operator'];
+
+    $field_term_id = $this->getFieldTermID();
+    $reference_term = $field_term_id . ',' . 'data:3002';
+    $fmin_term = $field_term_id . ',' . tripal_get_chado_semweb_term('featureloc', 'fmin');
+    $fmax_term = $field_term_id . ',' . tripal_get_chado_semweb_term('featureloc', 'fmax');
+    $strand_term = $field_term_id . ',' . tripal_get_chado_semweb_term('featureloc', 'strand');
+    $phase_term = $field_term_id . ',' . tripal_get_chado_semweb_term('featureloc', 'phase');
+
+    // Join to the organism table for this field.
+    $this->queryJoinOnce($query, 'featureloc', $alias, "base.feature_id = $alias.feature_id");
+    if ($condition['column'] == $reference_term) {
+      $salias = $alias . '_src';
+      $this->queryJoinOnce($query, 'feature', $salias, "$alias.srcfeature_id = $salias.feature_id");
+      $query->condition("$salias.name", $condition['value'], $operator);
+    }
+    if ($condition['column'] == $strand_term) {
+      $strand = '';
+      if ($condition['value'] == '-') {
+        $strand = -1;
+      }
+      if ($condition['value'] == '+') {
+        $strand = 1;
+      }
+      $query->condition("$alias.strand", $strand, $operator);
+    }
+    if ($condition['column'] == $fmin_term) {
+      $query->condition("$alias.fmin", $condition['value'] - 1, $operator);
+    }
+    if ($condition['column'] == $fmax_term) {
+      $query->condition("$alias.fmax", $condition['value'], $operator);
+    }
+    if ($condition['column'] == $phase_term) {
+      $query->condition("$alias.phase", $condition['value'], $operator);
+    }
+  }
+
+  /**
+   * @see ChadoField::queryOrder()
+   */
+  public function queryOrder($query, $order) {
+    $alias = $this->field['field_name'];
+
+    $field_term_id = $this->getFieldTermID();
+    $reference_term = $field_term_id . ',' . 'data:3002';
+    $fmin_term = $field_term_id . ',' . tripal_get_chado_semweb_term('featureloc', 'fmin');
+    $fmax_term = $field_term_id . ',' . tripal_get_chado_semweb_term('featureloc', 'fmax');
+    $strand_term = $field_term_id . ',' . tripal_get_chado_semweb_term('featureloc', 'strand');
+    $phase_term = $field_term_id . ',' . tripal_get_chado_semweb_term('featureloc', 'phase');
+
+    $this->queryJoinOnce($query, 'featureloc', $alias, "base.feature_id = $alias.feature_id", "LEFT OUTER");
+    if ($order['column'] == $reference_term) {
+      $salias = $alias . '_src';
+      $this->queryJoinOnce($query, 'feature', $salias, "$alias.srcfeature_id = $salias.feature_id", "LEFT OUTER");
+      $query->orderBy("$salias.name", $order['direction']);
+    }
+    if ($order['column'] == $fmin_term) {
+      $query->orderBy("$alias.fmin", $order['direction']);
+    }
+    if ($order['column'] == $fmax_term) {
+      $query->orderBy("$alias.fmax", $order['direction']);
+    }
+    if ($order['column'] == $phase_term) {
+      $query->orderBy("$alias.phase", $order['direction']);
+    }
+  }
+
   /**
   /**
    *
    *
    * @see TripalField::load()
    * @see TripalField::load()
@@ -124,6 +199,12 @@ class data__sequence_coordinates extends ChadoField {
     $feature = $entity->chado_record;
     $feature = $entity->chado_record;
     $num_seqs = 0;
     $num_seqs = 0;
 
 
+    $reference_term = 'data:3002';
+    $fmin_term = tripal_get_chado_semweb_term('featureloc', 'fmin');
+    $fmax_term = tripal_get_chado_semweb_term('featureloc', 'fmax');
+    $strand_term = tripal_get_chado_semweb_term('featureloc', 'strand');
+    $phase_term = tripal_get_chado_semweb_term('featureloc', 'phase');
+
     $options = array(
     $options = array(
       'return_array' => TRUE,
       'return_array' => TRUE,
       'order_by' => array('rank' => 'ASC'),
       'order_by' => array('rank' => 'ASC'),
@@ -132,19 +213,7 @@ class data__sequence_coordinates extends ChadoField {
 
 
     // Set some defauls for the empty record
     // Set some defauls for the empty record
     $entity->{$field_name}['und'][0] = array(
     $entity->{$field_name}['und'][0] = array(
-      'value' => array(
-        /*
-        // Types of elements that will appear in the value array.
-        // Annotation track
-        'data:3002' => '',
-        'local:fmin' => '',
-        'local:fmax' => '',
-        // phase
-        'data:2336' => '',
-        // strand
-        'data:0853' => '',
-        */
-      ),
+      'value' => '',
     );
     );
 
 
     // Get the featureloc records that this feature is aligned to.
     // Get the featureloc records that this feature is aligned to.
@@ -152,13 +221,20 @@ class data__sequence_coordinates extends ChadoField {
     if ($aligned) {
     if ($aligned) {
       foreach ($aligned as $index => $featureloc) {
       foreach ($aligned as $index => $featureloc) {
         $srcfeature = $featureloc->srcfeature_id->name;
         $srcfeature = $featureloc->srcfeature_id->name;
+        $strand = '';
+        if ($featureloc->strand == 1) {
+          $strand = '+';
+        }
+        else {
+          $strand = '-';
+        }
         $entity->{$field_name}['und'][0] = array(
         $entity->{$field_name}['und'][0] = array(
           'value' => array(
           'value' => array(
-            'data:3002' => $srcfeature,
-            'local:fmin' => $featureloc->fmin + 1,
-            'local:fmax' => $featureloc->fmax,
-            'data:2336' => $featureloc->phase,
-            'data:0853' => $featureloc->strand,
+            $reference_term => $srcfeature,
+            $fmin_term => $featureloc->fmin + 1,
+            $fmax_term => $featureloc->fmax,
+            $strand_term => $strand,
+            $phase_term => $featureloc->phase,
           ),
           ),
         );
         );
         $sentity_id = chado_get_record_entity_by_table('feature_id', $featureloc->srcfeature_id->feature_id);
         $sentity_id = chado_get_record_entity_by_table('feature_id', $featureloc->srcfeature_id->feature_id);

+ 11 - 18
tripal_chado/includes/TripalFields/data__sequence_coordinates/data__sequence_coordinates_formatter.inc

@@ -7,13 +7,6 @@ class data__sequence_coordinates_formatter extends ChadoFieldFormatter {
   // The list of field types for which this formatter is appropriate.
   // The list of field types for which this formatter is appropriate.
   public static $field_types = array('data__sequence_coordinates');
   public static $field_types = array('data__sequence_coordinates');
 
 
-  /**
-   *
-   * @see TripalFieldFormatter::settingsForm()
-   */
-  public function settingsForm($view_mode, $form, &$form_state) {
-
-  }
 
 
   /**
   /**
    *
    *
@@ -21,20 +14,20 @@ class data__sequence_coordinates_formatter extends ChadoFieldFormatter {
    */
    */
   public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
   public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
 
 
+    $reference_term = 'data:3002';
+    $fmin_term = tripal_get_chado_semweb_term('featureloc', 'fmin');
+    $fmax_term = tripal_get_chado_semweb_term('featureloc', 'fmax');
+    $strand_term = tripal_get_chado_semweb_term('featureloc', 'strand');
+    $phase_term = tripal_get_chado_semweb_term('featureloc', 'phase');
+
     $content = '';
     $content = '';
     foreach ($items as $item) {
     foreach ($items as $item) {
       if (!empty($item['value'])) {
       if (!empty($item['value'])) {
-        $srcfeature = $item['value']['data:3002'];
-        $fmin = $item['value']['local:fmin'];
-        $fmax = $item['value']['local:fmax'];
-        $phase = $item['value']['data:2336'];
-        $strand = $item['value']['data:0853'];
-        if ($strand == 1) {
-          $strand = '+';
-        }
-        else {
-          $strand = '-';
-        }
+        $srcfeature = $item['value'][$reference_term];
+        $fmin = $item['value'][$fmin_term];
+        $fmax = $item['value'][$fmax_term];
+        $phase = $item['value'][$phase_term];
+        $strand = $item['value'][$strand_term];
         $content .= $srcfeature . ':' . $fmin . '..' . $fmax . $strand;
         $content .= $srcfeature . ':' . $fmin . '..' . $fmax . $strand;
       }
       }
     }
     }

+ 0 - 7
tripal_chado/includes/TripalFields/data__sequence_length/data__sequence_length_formatter.inc

@@ -7,13 +7,6 @@ class data__sequence_length_formatter extends ChadoFieldFormatter {
   // The list of field types for which this formatter is appropriate.
   // The list of field types for which this formatter is appropriate.
   public static $field_types = array('data__sequence_length');
   public static $field_types = array('data__sequence_length');
 
 
-  /**
-   *
-   * @see TripalFieldFormatter::settingsForm()
-   */
-  public function settingsForm($view_mode, $form, &$form_state) {
-
-  }
 
 
   /**
   /**
    *
    *

+ 9 - 7
tripal_chado/includes/TripalFields/data__sequence_length/data__sequence_length_widget.inc

@@ -43,16 +43,18 @@ class data__sequence_length_widget extends ChadoFieldWidget {
     $field_table = $this->instance['settings']['chado_table'];
     $field_table = $this->instance['settings']['chado_table'];
     $field_column = $this->instance['settings']['chado_column'];
     $field_column = $this->instance['settings']['chado_column'];
 
 
-    // Get the residues so we can calculate teh length.
-    $residues = $form_state['values']['data__sequence']['und'][0]['value'];
-    // Remove any white spaces.
-    if ($residues) {
+    // Get the residues so we can calculate the length.
+    if ($form_state['values']['data__sequence']['und'][0]['chado-feature__residues']){
+      $residues =  $form_state['values']['data__sequence']['und'][0]['chado-feature__residues'];
+      // Remove spaces and new lines from the residues string.
       $residues = preg_replace('/\s/', '', $residues);
       $residues = preg_replace('/\s/', '', $residues);
-      $form_state['values']['data__sequence']['und'][0]['value'] = $residues;
-      $form_state['values']['data__sequence_length']['und'][0]['chado-feature__seqlen'] = strlen($residues);
+      $length = strlen($residues);
+      $form_state['values'][$field_name]['und'][0]['chado-feature__seqlen'] = $length;
+      $form_state['values'][$field_name]['und'][0]['value'] = $length;
     }
     }
     else {
     else {
-      $form_state['values']['data__sequence_length']['und'][0]['chado-feature__seqlen'] = '__NULL__';
+      // Otherwise, remove the md5 value
+      $form_state['values'][$field_name]['und'][0]['chado-feature__seqlen'] = '__NULL__';
     }
     }
   }
   }
 }
 }

+ 0 - 7
tripal_chado/includes/TripalFields/go__gene_expression/go__gene_expression_formatter.inc

@@ -7,13 +7,6 @@ class go__gene_expression_formatter extends ChadoFieldFormatter {
   // The list of field types for which this formatter is appropriate.
   // The list of field types for which this formatter is appropriate.
   public static $field_types = array('go__gene_expression');
   public static $field_types = array('go__gene_expression');
 
 
-  /**
-   *
-   * @see TripalFieldFormatter::settingsForm()
-   */
-  public function settingsForm($view_mode, $form, &$form_state) {
-
-  }
 
 
   /**
   /**
    *
    *

+ 37 - 8
tripal_chado/includes/TripalFields/local__source_data/local__source_data.inc

@@ -73,26 +73,20 @@ class local__source_data extends ChadoField {
         'elements' => array(
         'elements' => array(
           $sourcename_term => array(
           $sourcename_term => array(
             'searchable' => TRUE,
             'searchable' => TRUE,
-            'name' => 'sourcename',
             'label' => 'Data Source Name',
             'label' => 'Data Source Name',
             'help' => 'The name of the data source used for the analysis.',
             'help' => 'The name of the data source used for the analysis.',
-            'operations' => array('eq', 'ne', 'contains', 'starts'),
             'sortable' => TRUE,
             'sortable' => TRUE,
           ),
           ),
           $sourceversion_term => array(
           $sourceversion_term => array(
-            'searchable' => FALSE,
-            'name' => 'sourceversion',
+            'searchable' => TRUE,
             'label' => 'Data Source Version',
             'label' => 'Data Source Version',
             'help' => 'If applicable, the version number of the source data used for the analysis.',
             'help' => 'If applicable, the version number of the source data used for the analysis.',
-            'operations' => array('eq', 'ne', 'contains', 'starts'),
-            'sortable' => FALSE,
+            'sortable' => TRUE,
           ),
           ),
           $sourceuri_term => array(
           $sourceuri_term => array(
             'searchable' => FALSE,
             'searchable' => FALSE,
-            'name' => 'sourceuri',
             'label' => 'Data Source URI',
             'label' => 'Data Source URI',
             'help' => 'If applicable, the universal resource indicator (e.g. URL) of the source data used for the analysis.',
             'help' => 'If applicable, the universal resource indicator (e.g. URL) of the source data used for the analysis.',
-            'operations' => array(),
             'sortable' => FALSE,
             'sortable' => FALSE,
           ),
           ),
         ),
         ),
@@ -100,6 +94,41 @@ class local__source_data extends ChadoField {
     );
     );
   }
   }
 
 
+  /**
+   * @see ChadoField::query()
+   */
+  public function query($query, $condition) {
+    $operator = $condition['operator'];
+
+    $field_term_id = $this->getFieldTermID();
+    $sourcename_term = $field_term_id . ',' . tripal_get_chado_semweb_term('analysis', 'sourcename');
+    $sourceversion_term = $field_term_id . ',' . tripal_get_chado_semweb_term('analysis', 'sourceversion');
+    $sourceuri_term = $field_term_id . ',' . tripal_get_chado_semweb_term('analysis', 'sourceuri');
+
+    if ($condition['column'] == $sourcename_term) {
+      $query->condition("base.sourcename", $condition['value'], $operator);
+    }
+    if ($condition['column'] == $sourceversion_term) {
+      $query->condition("base.sourceversion", $condition['value'], $operator);
+    }
+  }
+  /**
+   * @see ChadoField::queryOrder()
+   */
+  public function queryOrder($query, $order) {
+    $field_term_id = $this->getFieldTermID();
+    $sourcename_term = $field_term_id . ',' . tripal_get_chado_semweb_term('analysis', 'sourcename');
+    $sourceversion_term = $field_term_id . ',' . tripal_get_chado_semweb_term('analysis', 'sourceversion');
+    $sourceuri_term = $field_term_id . ',' . tripal_get_chado_semweb_term('analysis', 'sourceuri');
+
+    if ($order['column'] == $sourcename_term) {
+      $query->orderBy("base.sourcename", $order['direction']);
+    }
+    if ($order['column'] == $sourceversion_term) {
+      $query->orderBy("base.sourceversion", $order['direction']);
+    }
+  }
+
   /**
   /**
    *
    *
    * @see TripalField::load()
    * @see TripalField::load()

+ 7 - 3
tripal_chado/includes/TripalFields/local__source_data/local__source_data_formatter.inc

@@ -13,16 +13,20 @@ class local__source_data_formatter extends ChadoFieldFormatter {
    */
    */
   public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
   public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
 
 
+    $sourcename_term = tripal_get_chado_semweb_term('analysis', 'sourcename');
+    $sourceversion_term = tripal_get_chado_semweb_term('analysis', 'sourceversion');
+    $sourceuri_term = tripal_get_chado_semweb_term('analysis', 'sourceuri');
+
     $content = 'The data source is not provided.';
     $content = 'The data source is not provided.';
     if ($items[0]['value']) {
     if ($items[0]['value']) {
       $content = "<dl class=\"tripal-dl\">";
       $content = "<dl class=\"tripal-dl\">";
-      if (!empty($items[0]['value']['schema:name'])) {
+      if (!empty($items[0]['value'][$sourcename_term])) {
         $content .= "<dt>Source Name</dt><dd>: " . $items[0]['value']['schema:name'] . " </dd>";
         $content .= "<dt>Source Name</dt><dd>: " . $items[0]['value']['schema:name'] . " </dd>";
       }
       }
-      if (!empty($items[0]['value']['IAO:0000129'])) {
+      if (!empty($items[0]['value'][$sourceversion_term])) {
         $content .= "<dt>Source Version</dt><dd>: " . $items[0]['value']['IAO:0000129'] . " </dd>";
         $content .= "<dt>Source Version</dt><dd>: " . $items[0]['value']['IAO:0000129'] . " </dd>";
       }
       }
-      if (!empty($items[0]['value']['data:1047'])) {
+      if (!empty($items[0]['value'][$sourceuri_term])) {
         $content .= "<dt>Source URI</dt><dd>: " . l($items[0]['value']['data:1047'], $items[0]['value']['data:1047'], array('attributes' => array('target' => '_blank'))) . " </dd>";
         $content .= "<dt>Source URI</dt><dd>: " . l($items[0]['value']['data:1047'], $items[0]['value']['data:1047'], array('attributes' => array('target' => '_blank'))) . " </dd>";
       }
       }
       $content .= "</dl>";
       $content .= "</dl>";

+ 40 - 15
tripal_chado/includes/TripalFields/local__source_data/local__source_data_widget.inc

@@ -36,15 +36,28 @@ class local__source_data_widget extends ChadoFieldWidget {
     // submit).
     // submit).
     if (array_key_exists('values', $form_state) and
     if (array_key_exists('values', $form_state) and
         array_key_exists($field_name, $form_state['values'])) {
         array_key_exists($field_name, $form_state['values'])) {
-      $sourcename = $form_state['values'][$field_name][$langcode][$delta]['chado-analysis__sourcename'];
-      $sourceversion = $form_state['values'][$field_name][$langcode][$delta]['chado-analysis__sourceversion'];
-      $sourceuri = $form_state['values'][$field_name][$langcode][$delta]['chado-analysis__sourceuri'];
+      $sourcename = $form_state['values'][$field_name]['und'][$delta]['source_data']['sourcename'];
+      $sourceversion = $form_state['values'][$field_name]['und'][$delta]['source_data']['sourceversion'];
+      $sourceuri = $form_state['values'][$field_name]['und'][$delta]['source_data']['sourceuri'];
     }
     }
 
 
     $widget['value'] = array(
     $widget['value'] = array(
       '#type' => 'value',
       '#type' => 'value',
       '#value' => $sourcename,
       '#value' => $sourcename,
     );
     );
+    $widget['chado-analysis__sourcename'] = array(
+      '#type' => 'value',
+      '#value' => $sourcename,
+    );
+    $widget['chado-analysis__sourceversion'] = array(
+      '#type' => 'value',
+      '#value' => $sourceversion,
+    );
+    $widget['chado-analysis__sourceuri'] = array(
+      '#type' => 'value',
+      '#value' => $sourceuri,
+    );
+
     $widget['source_data'] = array(
     $widget['source_data'] = array(
       '#type' => 'fieldset',
       '#type' => 'fieldset',
       '#title' => $this->instance['label'],
       '#title' => $this->instance['label'],
@@ -52,30 +65,29 @@ class local__source_data_widget extends ChadoFieldWidget {
       '#weight' => isset($element['#weight']) ? $element['#weight'] : 0,
       '#weight' => isset($element['#weight']) ? $element['#weight'] : 0,
       '#delta' => $delta,
       '#delta' => $delta,
     );
     );
-    $widget['source_data']['chado-analysis__sourcename'] = array(
+    $widget['source_data']['sourcename'] = array(
       '#type' => 'textfield',
       '#type' => 'textfield',
       '#title' => 'Data Source Name',
       '#title' => 'Data Source Name',
       '#description' => 'The name of the source where data was obtained for this analysis.',
       '#description' => 'The name of the source where data was obtained for this analysis.',
       '#default_value' => $sourcename,
       '#default_value' => $sourcename,
       '#required' => TRUE,
       '#required' => TRUE,
     );
     );
-    $widget['source_data']['chado-analysis__sourceversion'] = array(
+    $widget['source_data']['sourceversion'] = array(
       '#type' => 'textfield',
       '#type' => 'textfield',
       '#title' => 'Data Source Version',
       '#title' => 'Data Source Version',
       '#description' => 'The version number of the data source (if applicable).',
       '#description' => 'The version number of the data source (if applicable).',
       '#default_value' => $sourceversion,
       '#default_value' => $sourceversion,
     );
     );
-    $widget['source_data']['chado-analysis__sourceuri'] = array(
+    $widget['source_data']['sourceuri'] = array(
       '#type' => 'textfield',
       '#type' => 'textfield',
       '#title' => 'Data Source URI',
       '#title' => 'Data Source URI',
       '#description' => 'The URI (e.g. web URL) where the source data can be retreived.',
       '#description' => 'The URI (e.g. web URL) where the source data can be retreived.',
       '#default_value' => $sourceuri,
       '#default_value' => $sourceuri,
     );
     );
+
   }
   }
-  /**
-   * @see TripalFieldWidget::submit()
-   */
-  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
+
+  public function validate($element, $form, &$form_state, $langcode, $delta) {
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
     $field_type = $this->field['type'];
     $field_type = $this->field['type'];
     $table_name = $this->instance['settings']['chado_table'];
     $table_name = $this->instance['settings']['chado_table'];
@@ -83,10 +95,23 @@ class local__source_data_widget extends ChadoFieldWidget {
     $field_column = $this->instance['settings']['chado_column'];
     $field_column = $this->instance['settings']['chado_column'];
     $base_table = $this->instance['settings']['base_table'];
     $base_table = $this->instance['settings']['base_table'];
 
 
-    // Using a fieldset in our widget above throws off the structure
-    // of the values array.  So we need to reorganize it a bit:
-    $value = $form_state['values'][$field_name][$langcode][$delta]['value'];
-    $form_state['values'][$field_name][$langcode][$delta] = $form_state['values'][$field_name][$langcode][$delta]['source_data'];
-    $form_state['values'][$field_name][$langcode][$delta]['value'] = $value;
+    $source_name = $form_state['values'][$field_name]['und'][$delta]['source_data']['sourcename'];
+    $sourceversion = $form_state['values'][$field_name]['und'][$delta]['source_data']['sourceversion'];
+    $sourceuri = $form_state['values'][$field_name]['und'][$delta]['source_data']['sourceuri'];
+
+    // Set the value so the form element won't be ignored.
+    $form_state['values'][$field_name]['und'][$delta]['value'] = $source_name;
+
+    if (!$sourceversion) {
+      $sourceversion = '__NULL__';
+    }
+    if (!$sourceuri) {
+      $sourceuri = '__NULL__';
+    }
+
+    // And set the values for our Chado insert/update
+    $form_state['values'][$field_name]['und'][$delta]['chado-analysis__sourcename'] = $source_name;
+    $form_state['values'][$field_name]['und'][$delta]['chado-analysis__sourceversion'] = $sourceversion;
+    $form_state['values'][$field_name]['und'][$delta]['chado-analysis__sourceuri'] = $sourceuri;
   }
   }
 }
 }

+ 2 - 9
tripal_chado/includes/TripalFields/obi__organism/obi__organism.inc

@@ -40,7 +40,7 @@ class obi__organism extends ChadoField {
   /**
   /**
    * @see TripalField::validate()
    * @see TripalField::validate()
    */
    */
-  public function validate($entity_type, $entity, $field, $items, &$errors) {
+  public function validate($entity_type, $entity, $langcode, $items, &$errors) {
 
 
     $settings = $this->field['settings'];
     $settings = $this->field['settings'];
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
@@ -84,14 +84,7 @@ class obi__organism extends ChadoField {
 
 
     // Set some defaults for the empty record.
     // Set some defaults for the empty record.
     $entity->{$field_name}['und'][0] = array(
     $entity->{$field_name}['und'][0] = array(
-      'value' => array(
-        /*
-        // Types of elements that will appear in the value array.
-        $label_term => '',
-        $genus_term => '',
-        $species_term => '',
-        */
-      ),
+      'value' => array(),
     );
     );
 
 
     if ($record) {
     if ($record) {

+ 2 - 2
tripal_chado/includes/TripalFields/obi__organism/obi__organism_widget.inc

@@ -53,7 +53,7 @@ class obi__organism_widget extends ChadoFieldWidget {
     $field_table = $this->instance['settings']['chado_table'];
     $field_table = $this->instance['settings']['chado_table'];
 
 
     // Make sure the value is set to the organism_id
     // Make sure the value is set to the organism_id
-    $organism_id = $form_state['values'][$field_name][$langcode][0]['chado-' . $field_table . '__organism_id'];
-    $form_state['values'][$field_name][$langcode][0]['value'] = $organism_id;
+    $organism_id = $form_state['values'][$field_name]['und'][0]['chado-' . $field_table . '__organism_id'];
+    $form_state['values'][$field_name]['und'][0]['value'] = $organism_id;
   }
   }
 }
 }

+ 0 - 8
tripal_chado/includes/TripalFields/ogi__location_on_map/ogi__location_on_map_formatter.inc

@@ -7,14 +7,6 @@ class ogi__location_on_map_formatter extends ChadoFieldFormatter {
   // The list of field types for which this formatter is appropriate.
   // The list of field types for which this formatter is appropriate.
   public static $field_types = array('ogi__location_on_map');
   public static $field_types = array('ogi__location_on_map');
 
 
-  /**
-   *
-   * @see TripalFieldFormatter::settingsForm()
-   */
-  public function settingsForm($view_mode, $form, &$form_state) {
-
-  }
-
   /**
   /**
    *
    *
    * @see TripalFieldFormatter::view()
    * @see TripalFieldFormatter::view()

+ 58 - 43
tripal_chado/includes/TripalFields/sbo__database_cross_reference/sbo__database_cross_reference.inc

@@ -62,36 +62,33 @@ class sbo__database_cross_reference extends ChadoField {
    */
    */
   public function elementInfo() {
   public function elementInfo() {
 
 
+    $field_term = $this->getFieldTermID();
     $dbname_term = tripal_get_chado_semweb_term('db', 'name');
     $dbname_term = tripal_get_chado_semweb_term('db', 'name');
     $accession_term = tripal_get_chado_semweb_term('dbxref', 'accession');
     $accession_term = tripal_get_chado_semweb_term('dbxref', 'accession');
+    $dburl_term = tripal_get_chado_semweb_term('db', 'url');
 
 
-    $field_term = $this->getFieldTermID();
     return array(
     return array(
       $field_term => array(
       $field_term => array(
         'operations' => array(),
         'operations' => array(),
+        'label' => 'Cross Reference',
         'sortable' => FALSE,
         'sortable' => FALSE,
         'searchable' => FALSE,
         'searchable' => FALSE,
         'elements' => array(
         'elements' => array(
           $dbname_term => array(
           $dbname_term => array(
             'searchable' => TRUE,
             'searchable' => TRUE,
-            'name' => 'db_name',
-            'label' => 'Database Name',
+            'label' => 'Cross Reference Database Name',
             'help' => 'The name of the remote database that houses the cross reference.',
             'help' => 'The name of the remote database that houses the cross reference.',
-            'operations' => array('eq', 'ne', 'contains', 'starts'),
             'sortable' => TRUE,
             'sortable' => TRUE,
           ),
           ),
           $accession_term => array(
           $accession_term => array(
             'searchable' => TRUE,
             'searchable' => TRUE,
-            'name' => 'accession',
-            'label' => 'Database Accession',
+            'label' => 'Cross Reference Database Accession',
             'help' => 'The unique accession (identifier) in the database that houses the cross reference.',
             'help' => 'The unique accession (identifier) in the database that houses the cross reference.',
-            'operations' => array('eq', 'ne', 'contains', 'starts'),
             'sortable' => TRUE,
             'sortable' => TRUE,
           ),
           ),
-          'schema:url' => array(
+          $dburl_term => array(
             'searchable' => FALSE,
             'searchable' => FALSE,
-            'name' => 'URL',
-            'label' => 'Database URL',
+            'label' => 'Cross Reference Database URL',
             'help' => 'The URL of the database that houses the cross reference.',
             'help' => 'The URL of the database that houses the cross reference.',
             'sortable' => FALSE,
             'sortable' => FALSE,
           ),
           ),
@@ -117,25 +114,18 @@ class sbo__database_cross_reference extends ChadoField {
     $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
     $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
     $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
     $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
 
 
+    $dbname_term = tripal_get_chado_semweb_term('db', 'name');
+    $accession_term = tripal_get_chado_semweb_term('dbxref', 'accession');
+    $dburl_term = tripal_get_chado_semweb_term('db', 'url');
+
     // Set some defaults for the empty record.
     // Set some defaults for the empty record.
     $entity->{$field_name}['und'][0] = array(
     $entity->{$field_name}['und'][0] = array(
-      'value' => array(
-        /* sub elements that may be present in the values array
-        // Database name
-        'data:1048' => '',
-        // Accession
-        'data:2091' => '',
-        'schema:url' => '',
-        */
-      ),
+      'value' => '',
       'chado-' . $field_table . '__' . $pkey => '',
       'chado-' . $field_table . '__' . $pkey => '',
-      'chado-' . $field_table . '__' . $fkey_lcolumn => '',
+      'chado-' . $field_table . '__' . $fkey_lcolumn => $record->$fkey_rcolumn,
       'chado-' . $field_table . '__dbxref_id' => '',
       'chado-' . $field_table . '__dbxref_id' => '',
-      'dbxref_id' => '',
       'db_id' => '',
       'db_id' => '',
       'accession' => '',
       'accession' => '',
-      'version' => '',
-      'description' => '',
     );
     );
 
 
     $linker_table = $base_table . '_dbxref';
     $linker_table = $base_table . '_dbxref';
@@ -155,18 +145,15 @@ class sbo__database_cross_reference extends ChadoField {
         $URL = tripal_get_dbxref_url($dbxref);
         $URL = tripal_get_dbxref_url($dbxref);
         $entity->{$field_name}['und'][$i] = array(
         $entity->{$field_name}['und'][$i] = array(
           'value' => array(
           'value' => array(
-            'data:1048' => $dbxref->db_id->name,
-            'data:2091' => $dbxref->accession,
-            'schema:url' => $URL,
+            $dbname_term => $dbxref->db_id->name,
+            $accession_term => $dbxref->accession,
+            $dburl_term => $URL,
           ),
           ),
           'chado-' . $field_table . '__' . $pkey => $linker->$pkey,
           'chado-' . $field_table . '__' . $pkey => $linker->$pkey,
           'chado-' . $field_table . '__' . $fkey_lcolumn => $linker->$fkey_lcolumn->$fkey_lcolumn,
           'chado-' . $field_table . '__' . $fkey_lcolumn => $linker->$fkey_lcolumn->$fkey_lcolumn,
           'chado-' . $field_table . '__dbxref_id' => $dbxref->dbxref_id,
           'chado-' . $field_table . '__dbxref_id' => $dbxref->dbxref_id,
-          'dbxref_id' => $dbxref->dbxref_id,
           'db_id' => $dbxref->db_id->db_id,
           'db_id' => $dbxref->db_id->db_id,
           'accession' => $dbxref->accession,
           'accession' => $dbxref->accession,
-          'version' => $dbxref->version,
-          'description' => $dbxref->description,
         );
         );
         $i++;
         $i++;
       }
       }
@@ -179,21 +166,28 @@ class sbo__database_cross_reference extends ChadoField {
   public function query($query, $condition) {
   public function query($query, $condition) {
     $dbxref_linker = $this->instance['settings']['chado_table'];
     $dbxref_linker = $this->instance['settings']['chado_table'];
     $base_table = $this->instance['settings']['base_table'];
     $base_table = $this->instance['settings']['base_table'];
+    $field_table = $this->instance['settings']['chado_table'];
+
     $bschema = chado_get_schema($base_table);
     $bschema = chado_get_schema($base_table);
     $bpkey = $bschema['primary key'][0];
     $bpkey = $bschema['primary key'][0];
-    $alias = 'dbx_linker';
+
+    $alias = $this->field['field_name'];
     $operator = $condition['operator'];
     $operator = $condition['operator'];
 
 
-    if ($condition['column'] == 'database_cross_reference.database_name') {
-      $this->queryJoinOnce($query, $dbxref_linker, $alias, "base.$bpkey = $alias.$bpkey");
-      $this->queryJoinOnce($query, 'dbxref', 'DBX', "DBX.dbxref_id = $alias.dbxref_id");
-      $this->queryJoinOnce($query, 'db', 'DB', "DB.db_id = DBX.db_id");
-      $query->condition("DB.name", $condition['value'], $operator);
+    $field_term_id = $this->getFieldTermID();
+    $dbname_term = $field_term_id . ',' . tripal_get_chado_semweb_term('db', 'name');
+    $accession_term = $field_term_id . ',' . tripal_get_chado_semweb_term('dbxref', 'accession');
+    $dburl_term = $field_term_id . ',' . tripal_get_chado_semweb_term('db', 'url');
+
+    $this->queryJoinOnce($query, $field_table, $alias, "base.$bpkey = $alias.$bpkey");
+    $this->queryJoinOnce($query, 'dbxref', $alias . '_DBX', $alias . "_DBX.dbxref_id = $alias.dbxref_id");
+
+    if ($condition['column'] == $dbname_term) {
+      $this->queryJoinOnce($query, 'db', $alias . '_DB', $alias . "_DB.db_id = " . $alias . "_DBX.db_id");
+      $query->condition($alias . "_DB.name", $condition['value'], $operator);
     }
     }
-    if ($condition['column'] == 'database_cross_reference.accession') {
-      $this->queryJoinOnce($query, $dbxref_linker, $alias, "base.$bpkey = $alias.$bpkey");
-      $this->queryJoinOnce($query, 'dbxref', 'DBX', "DBX.dbxref_id = $alias.dbxref_id");
-      $query->condition("DBX.accession", $condition['value'], $operator);
+    if ($condition['column'] == $accession_term) {
+      $query->condition($alias . "_DBX.accession", $condition['value'], $operator);
     }
     }
   }
   }
 
 
@@ -201,13 +195,36 @@ class sbo__database_cross_reference extends ChadoField {
    * @see ChadoField::queryOrder()
    * @see ChadoField::queryOrder()
    */
    */
   public function queryOrder($query, $order) {
   public function queryOrder($query, $order) {
+    $dbxref_linker = $this->instance['settings']['chado_table'];
+    $base_table = $this->instance['settings']['base_table'];
+    $field_table = $this->instance['settings']['chado_table'];
+
+    $bschema = chado_get_schema($base_table);
+    $bpkey = $bschema['primary key'][0];
 
 
+    $alias = $this->field['field_name'];
+
+    $field_term_id = $this->getFieldTermID();
+    $dbname_term = $field_term_id . ',' . tripal_get_chado_semweb_term('db', 'name');
+    $accession_term = $field_term_id . ',' . tripal_get_chado_semweb_term('dbxref', 'accession');
+    $dburl_term = $field_term_id . ',' . tripal_get_chado_semweb_term('db', 'url');
+
+    $this->queryJoinOnce($query, $field_table, $alias, "base.$bpkey = $alias.$bpkey", "LEFT OUTER");
+    $this->queryJoinOnce($query, 'dbxref', $alias . '_DBX', $alias . "_DBX.dbxref_id = $alias.dbxref_id", "LEFT OUTER");
+
+    if ($order['column'] == $dbname_term) {
+      $this->queryJoinOnce($query, 'db', $alias . '_DB', $alias . "_DB.db_id = " . $alias . "_DBX.db_id", "LEFT OUTER");
+      $query->orderBy($alias . "_DB.name", $order['direction']);
+    }
+    if ($order['column'] == $accession_term) {
+      $query->orderBy($alias . "_DBX.accession", $order['direction']);
+    }
   }
   }
 
 
   /**
   /**
    * @see TripalField::validate()
    * @see TripalField::validate()
    */
    */
-  public function validate($entity_type, $entity, $field, $items, &$errors) {
+  public function validate($entity_type, $entity, $langcode, $items, &$errors) {
 
 
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
     $field_type = $this->field['type'];
     $field_type = $this->field['type'];
@@ -228,8 +245,6 @@ class sbo__database_cross_reference extends ChadoField {
       $dbxref_id = $values['chado-' . $field_table . '__dbxref_id'];
       $dbxref_id = $values['chado-' . $field_table . '__dbxref_id'];
       $db_id = $values['db_id'];
       $db_id = $values['db_id'];
       $accession = $values['accession'];
       $accession = $values['accession'];
-      $version = $values['version'];
-      $description = $values['description'];
 
 
       // Make sure that if a database ID is provided that an accession is also
       // Make sure that if a database ID is provided that an accession is also
       // provided.  Here we use the form_set_error function rather than the
       // provided.  Here we use the form_set_error function rather than the
@@ -250,7 +265,7 @@ class sbo__database_cross_reference extends ChadoField {
           'error' => 'sbo__database_cross_reference',
           'error' => 'sbo__database_cross_reference',
         );
         );
       }
       }
-      if (!$db_id and !$accession and ($version or $description)) {
+      if (!$db_id and !$accession) {
         $errors[$field_name][$delta]['und'][] = array(
         $errors[$field_name][$delta]['und'][] = array(
           'message' => t("A database and the accession must both be provided."),
           'message' => t("A database and the accession must both be provided."),
           'error' => 'sbo__database_cross_reference',
           'error' => 'sbo__database_cross_reference',

+ 17 - 12
tripal_chado/includes/TripalFields/sbo__database_cross_reference/sbo__database_cross_reference_formatter.inc

@@ -7,28 +7,33 @@ class sbo__database_cross_reference_formatter extends ChadoFieldFormatter {
   // The list of field types for which this formatter is appropriate.
   // The list of field types for which this formatter is appropriate.
   public static $field_types = array('sbo__database_cross_reference');
   public static $field_types = array('sbo__database_cross_reference');
 
 
-  /**
-   *
-   * @see TripalFieldFormatter::settingsForm()
-   */
-  public function settingsForm($view_mode, $form, &$form_state) {
-
-  }
-
   /**
   /**
    *
    *
    * @see TripalFieldFormatter::view()
    * @see TripalFieldFormatter::view()
    */
    */
   public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
   public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
-    $chado_table = $this->instance['settings']['chado_table'];
     $content = '';
     $content = '';
+
+    $field_name = $this->field['field_name'];
+    $field_type = $this->field['type'];
+    $field_table = $this->instance['settings']['chado_table'];
+    $field_column = $this->instance['settings']['chado_column'];
+    $base_table = $this->instance['settings']['base_table'];
+    $linker_table = $base_table . '_dbxref';
+
+    $dbname_term = tripal_get_chado_semweb_term('db', 'name');
+    $accession_term = tripal_get_chado_semweb_term('dbxref', 'accession');
+    $dburl_term = tripal_get_chado_semweb_term('db', 'url');
+
     foreach ($items as $delta => $item) {
     foreach ($items as $delta => $item) {
       if (!$item['value']) {
       if (!$item['value']) {
         continue;
         continue;
       }
       }
-      $content = $item['value']['data:1048'] . ':' . $item['value']['data:2091'];
-      if ($item['value']['schema:url']) {
-        $content = l($content, $item['value']['schema:url'], array('attributes' => array('target' => '_blank')));
+      $content = $item['value'][$dbname_term] . ':' . $item['value'][$accession_term];
+      if ($item['value'][$dburl_term]) {
+        $dbxref = tripal_get_dbxref(array('dbxref_id' => $item['chado-' . $linker_table . '__dbxref_id']));
+        $url = tripal_get_dbxref_url($dbxref);
+        $content = l($content, $url, array('attributes' => array('target' => '_blank')));
       }
       }
       $element[$delta] = array(
       $element[$delta] = array(
         '#type' => 'markup',
         '#type' => 'markup',

+ 39 - 123
tripal_chado/includes/TripalFields/sbo__database_cross_reference/sbo__database_cross_reference_widget.inc

@@ -13,15 +13,14 @@ class sbo__database_cross_reference_widget extends ChadoFieldWidget {
    */
    */
   public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
   public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
+
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
     $field_type = $this->field['type'];
     $field_type = $this->field['type'];
     $field_table = $this->instance['settings']['chado_table'];
     $field_table = $this->instance['settings']['chado_table'];
     $field_column = $this->instance['settings']['chado_column'];
     $field_column = $this->instance['settings']['chado_column'];
-
-    // Get the FK column that links to the base table.
-    $chado_table = $this->instance['settings']['chado_table'];
     $base_table = $this->instance['settings']['base_table'];
     $base_table = $this->instance['settings']['base_table'];
-    $schema = chado_get_schema($chado_table);
+
+    $schema = chado_get_schema($field_table);
     $pkey = $schema['primary key'][0];
     $pkey = $schema['primary key'][0];
     $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);
     $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);
     $fkey = $fkeys[0];
     $fkey = $fkeys[0];
@@ -32,8 +31,6 @@ class sbo__database_cross_reference_widget extends ChadoFieldWidget {
     $dbxref_id = '';
     $dbxref_id = '';
     $db_id = '';
     $db_id = '';
     $accession = '';
     $accession = '';
-    $version = '';
-    $description = '';
 
 
     // If the field already has a value then it will come through the $items
     // If the field already has a value then it will come through the $items
     // array.  This happens when editing an existing record.
     // array.  This happens when editing an existing record.
@@ -43,27 +40,18 @@ class sbo__database_cross_reference_widget extends ChadoFieldWidget {
       $dbxref_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__dbxref_id', $dbxref_id);
       $dbxref_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__dbxref_id', $dbxref_id);
       $db_id = tripal_get_field_item_keyval($items, $delta, 'db_id', $db_id);
       $db_id = tripal_get_field_item_keyval($items, $delta, 'db_id', $db_id);
       $accession = tripal_get_field_item_keyval($items, $delta, 'accession', $accession);
       $accession = tripal_get_field_item_keyval($items, $delta, 'accession', $accession);
-      $version = tripal_get_field_item_keyval($items, $delta, 'version', $version);
-      $description = tripal_get_field_item_keyval($items, $delta, 'description', $description);
     }
     }
 
 
     // Check $form_state['values'] to see if an AJAX call set the values.
     // Check $form_state['values'] to see if an AJAX call set the values.
-    if (array_key_exists('values', $form_state) and array_key_exists($delta, $form_state['values'])) {
-      $record_id = $form_state['values'][$field_name]['und'][$delta][$field_table . '__' . $pkey];
-      $fkey_value = $form_state['values'][$field_name]['und'][$delta][$field_table . '__' . $fkey];
-      $dbxref_id = $form_state['values'][$field_name]['und'][$delta][$field_table . '__dbxref_id'];
+    if (array_key_exists('values', $form_state) and
+        array_key_exists($field_name, $form_state['values'])) {
+      $record_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $pkey];
+      $fkey_value = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $fkey];
+      $dbxref_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__dbxref_id'];
       $db_id = $form_state['values'][$field_name]['und'][$delta]['db_id'];
       $db_id = $form_state['values'][$field_name]['und'][$delta]['db_id'];
       $accession = $form_state['values'][$field_name]['und'][$delta]['accession'];
       $accession = $form_state['values'][$field_name]['und'][$delta]['accession'];
-      $version = $form_state['values'][$field_name]['und'][$delta]['version'];
-      $description = $form_state['values'][$field_name]['und'][$delta]['description'];
     }
     }
 
 
-    $schema = chado_get_schema('dbxref');
-    $options = tripal_get_db_select_options();
-
-    $widget['#table_name'] = $chado_table;
-    $widget['#fkey_field'] = $fkey;
-    //$widget['#element_validate'] = array('sbo__database_cross_reference_widget_validate');
     $widget['#prefix'] =  "<span id='$field_name-dbxref--db-id-$delta'>";
     $widget['#prefix'] =  "<span id='$field_name-dbxref--db-id-$delta'>";
     $widget['#suffix'] =  "</span>";
     $widget['#suffix'] =  "</span>";
 
 
@@ -85,10 +73,7 @@ class sbo__database_cross_reference_widget extends ChadoFieldWidget {
       '#type' => 'value',
       '#type' => 'value',
       '#default_value' => $dbxref_id,
       '#default_value' => $dbxref_id,
     );
     );
-    $widget['dbxref_id'] = array(
-      '#type' => 'value',
-      '#default_value' => $dbxref_id,
-    );
+    $options = tripal_get_db_select_options();
     $widget['db_id'] = array(
     $widget['db_id'] = array(
       '#type' => 'select',
       '#type' => 'select',
       '#title' => t('Database'),
       '#title' => t('Database'),
@@ -102,6 +87,7 @@ class sbo__database_cross_reference_widget extends ChadoFieldWidget {
         'method' => 'replace'
         'method' => 'replace'
       ),
       ),
     );
     );
+    $schema = chado_get_schema('dbxref');
     $widget['accession'] = array(
     $widget['accession'] = array(
       '#type' => 'textfield',
       '#type' => 'textfield',
       '#title' => t('Accession'),
       '#title' => t('Accession'),
@@ -110,93 +96,47 @@ class sbo__database_cross_reference_widget extends ChadoFieldWidget {
       '#maxlength' => array_key_exists('length', $schema['fields']['accession']) ? $schema['fields']['accession']['length'] : 255,
       '#maxlength' => array_key_exists('length', $schema['fields']['accession']) ? $schema['fields']['accession']['length'] : 255,
       '#size' => 15,
       '#size' => 15,
       '#autocomplete_path' => 'admin/tripal/storage/chado/auto_name/dbxref/' . $db_id,
       '#autocomplete_path' => 'admin/tripal/storage/chado/auto_name/dbxref/' . $db_id,
-      '#ajax' => array(
-        'callback' => "sbo__database_cross_reference_widget_form_ajax_callback",
-        'wrapper' => "$field_name-dbxref--db-id-$delta",
-        'effect' => 'fade',
-        'method' => 'replace'
-      ),
-      '#disabled' => $db_id ? FALSE : TRUE,
-    );
-    $widget['version'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Version'),
-      '#default_value' => $version,
-      '#maxlength' => array_key_exists('length', $schema['fields']['version']) ? $schema['fields']['version']['length'] : 255,
-      '#size' => 5,
-      '#disabled' => $db_id ? FALSE : TRUE,
-    );
-    $widget['description'] = array(
-      '#type' => 'textfield',
-      '#title' => t('Description'),
-      '#default_value' => $description,
-      '#size' => 20,
       '#disabled' => $db_id ? FALSE : TRUE,
       '#disabled' => $db_id ? FALSE : TRUE,
     );
     );
-    if (!$db_id) {
-      $widget['links'] = array(
-        '#type' => 'item',
-        '#markup' => l('Add a database', 'admin/tripal/loaders/chado_db/add', array('attributes' => array('target' => '_blank')))
-      );
-    }
   }
   }
 
 
+  public function validate($element, $form, &$form_state, $langcode, $delta) {
 
 
-  /**
-   *
-   * @see TripalFieldWidget::submit()
-   */
-  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
     $field_type = $this->field['type'];
     $field_type = $this->field['type'];
     $table_name = $this->instance['settings']['chado_table'];
     $table_name = $this->instance['settings']['chado_table'];
     $field_table = $this->instance['settings']['chado_table'];
     $field_table = $this->instance['settings']['chado_table'];
     $field_column = $this->instance['settings']['chado_column'];
     $field_column = $this->instance['settings']['chado_column'];
     $base_table = $this->instance['settings']['base_table'];
     $base_table = $this->instance['settings']['base_table'];
+
     $schema = chado_get_schema($table_name);
     $schema = chado_get_schema($table_name);
     $pkey = $schema['primary key'][0];
     $pkey = $schema['primary key'][0];
     $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);
     $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);
     $fkey = $fkeys[0];
     $fkey = $fkeys[0];
 
 
     // Get the field values.
     // Get the field values.
-    $dbxref_id = isset($form_state['values'][$field_name][$langcode][$delta]['chado-' . $field_table . '__dbxref_id']) ? $form_state['values'][$field_name][$langcode][$delta]['chado-' . $field_table . '__dbxref_id'] : '';
-    $db_id = isset($form_state['values'][$field_name][$langcode][$delta]['db_id']) ? $form_state['values'][$field_name][$langcode][$delta]['db_id'] : '';
-    $accession = isset($form_state['values'][$field_name][$langcode][$delta]['accession']) ? $form_state['values'][$field_name][$langcode][$delta]['accession'] : '';
-    $version = isset($form_state['values'][$field_name][$langcode][$delta]['version']) ? $form_state['values'][$field_name][$langcode][$delta]['version'] : '';
-    $description = isset($form_state['values'][$field_name][$langcode][$delta]['description']) ? $form_state['values'][$field_name][$langcode][$delta]['description'] : '';
-
+    $dbxref_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__dbxref_id'];
+    $db_id = $form_state['values'][$field_name]['und'][$delta]['db_id'];
+    $accession = $form_state['values'][$field_name]['und'][$delta]['accession'];
 
 
+    // If user did not select a database, we want to remove the dbxref record.
+    // We do this by setting all values to empty except the value and the
+    // primary key.
+    if (!$db_id) {
+      $form_state['values'][$field_name]['und'][$delta]['value'] = 'delete_me';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $fkey] = '';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__dbxref_id'] = '';
+    }
     // If the dbxref_id does not match the db_id + accession then the user
     // If the dbxref_id does not match the db_id + accession then the user
     // has selected a new dbxref record and we need to update the hidden
     // has selected a new dbxref record and we need to update the hidden
     // value accordingly.
     // value accordingly.
     if ($db_id and $accession) {
     if ($db_id and $accession) {
-      // If the dbxref doesn't exist then let's add it.
-      $values = array(
-        'db_id' => $db_id,
-        'accession' => $accession,
-      );
-      $options = array('is_duplicate' => TRUE);
-      $has_duplicate = chado_select_record('dbxref', array('*'), $values, $options);
-      if (!$has_duplicate) {
-        tripal_insert_dbxref(array(
-          'db_id' => $db_id,
-          'accession' => $accession,
-        ));
-      }
       $dbxref = chado_generate_var('dbxref', array('db_id' => $db_id, 'accession' => $accession));
       $dbxref = chado_generate_var('dbxref', array('db_id' => $db_id, 'accession' => $accession));
       if ($dbxref and $dbxref->dbxref_id != $dbxref_id) {
       if ($dbxref and $dbxref->dbxref_id != $dbxref_id) {
-        $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__dbxref_id'] = $dbxref->dbxref_id;
-        $form_state['values'][$field_name][$langcode][$delta]['dbxref_id'] = $dbxref->dbxref_id;
+        $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__dbxref_id'] = $dbxref->dbxref_id;
+        $form_state['values'][$field_name]['und'][$delta]['value'] = $dbxref->dbxref_id;
       }
       }
     }
     }
-    // If the db_id and accession are not set, then remove the linker FK
-    // value to the base table, but leave the primary key so the record
-    // can be deleted.
-    else {
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__' . $fkey] = '';
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__dbxref_id'] = '';
-    }
-
   }
   }
 
 
   /**
   /**
@@ -204,11 +144,6 @@ class sbo__database_cross_reference_widget extends ChadoFieldWidget {
    */
    */
   public function theme($element) {
   public function theme($element) {
 
 
-    // These two fields were added to the widget to help identify the fields
-    // for layout.
-    $table_name = $element['#table_name'];
-    $fkey = $element['#fkey_field'];
-
     $layout = "
     $layout = "
       <div class=\"secondary-dbxref-widget\">
       <div class=\"secondary-dbxref-widget\">
         <div class=\"secondary-dbxref-widget-item\">" .
         <div class=\"secondary-dbxref-widget-item\">" .
@@ -217,13 +152,6 @@ class sbo__database_cross_reference_widget extends ChadoFieldWidget {
         <div class=\"secondary-dbxref-widget-item\">" .
         <div class=\"secondary-dbxref-widget-item\">" .
           drupal_render($element['accession']) . "
           drupal_render($element['accession']) . "
         </div>
         </div>
-        <div class=\"secondary-dbxref-widget-item\">" .
-          drupal_render($element['version']) . "
-        </div>
-        <div class=\"secondary-dbxref-widget-item\">" .
-          drupal_render($element['description']) . "
-        </div>
-        <div class=\"secondary-dbxref-widget-links\">" . drupal_render($element['links']) . "</div>
       </div>
       </div>
     ";
     ";
 
 
@@ -236,31 +164,19 @@ class sbo__database_cross_reference_widget extends ChadoFieldWidget {
  * An Ajax callback for the dbxref widget.
  * An Ajax callback for the dbxref widget.
  */
  */
 function sbo__database_cross_reference_widget_form_ajax_callback($form, $form_state) {
 function sbo__database_cross_reference_widget_form_ajax_callback($form, $form_state) {
-
-  $field_name = $form_state['triggering_element']['#parents'][0];
-  $delta = $form_state['triggering_element']['#parents'][2];
-  $field = field_info_field($field_name);
-  $field_type = $field['type'];
-  $instance = $form[$field_name]['und'][$delta]['#instance'];
-  $field_table = $instance['settings']['chado_table'];
-  $field_column = $instance['settings']['chado_column'];
-  $field_prefix = 'chado-' . $field_table . '__dbxref_id';
-
-  // Check to see if this dbxref already exists. If not then
-  // give a notice to the user that the dbxref will be added.
-  $db_id = $form_state['values'][$field_name]['und'][$delta]['db_id'];
-  $accession = $form_state['values'][$field_name]['und'][$delta]['accession'];
-  if ($db_id and $accession) {
-    $values = array(
-      'db_id' => $db_id,
-      'accession' => $accession,
-    );
-    $options = array('is_duplicate' => TRUE);
-    $has_duplicate = chado_select_record('dbxref', array('*'), $values, $options);
-    if (!$has_duplicate) {
-      drupal_set_message('The selected cross reference is new and will be added.');
-    }
+  // Get the triggering element
+  $form_element_name = $form_state['triggering_element']['#name'];
+  preg_match('/(.+?)\[(.+?)\]\[(.+?)\]/', $form_element_name, $matches);
+  $field = $matches[1];
+  $lang = $matches[2];
+  $delta = $matches[3];
+
+  // Return the widget that triggered the AJAX call
+  if (isset($form[$field][$lang][$delta])) {
+    return $form[$field][$lang][$delta];
+  }
+  // Alternatively, return the default value widget for the widget setting form
+  else {
+    return $form['instance']['default_value_widget'][$field];
   }
   }
-
-  return $form[$field_name]['und'][$delta];
 }
 }

+ 2 - 2
tripal_chado/includes/TripalFields/sbo__phenotype/sbo__phenotype.inc

@@ -65,8 +65,8 @@ class sbo__phenotype extends ChadoField {
     return array(
     return array(
       $field_term => array(
       $field_term => array(
         'operations' => array('eq', 'ne', 'contains', 'starts'),
         'operations' => array('eq', 'ne', 'contains', 'starts'),
-        'sortable' => TRUE,
-        'searchable' => TRUE,
+        'sortable' => FALSE,
+        'searchable' => FALSE,
       ),
       ),
     );
     );
   }
   }

+ 0 - 8
tripal_chado/includes/TripalFields/sbo__phenotype/sbo__phenotype_formatter.inc

@@ -7,14 +7,6 @@ class sbo__phenotype_formatter extends ChadoFieldFormatter {
   // The list of field types for which this formatter is appropriate.
   // The list of field types for which this formatter is appropriate.
   public static $field_types = array('sbo__phenotype');
   public static $field_types = array('sbo__phenotype');
 
 
-  /**
-   *
-   * @see TripalFieldFormatter::settingsForm()
-   */
-  public function settingsForm($view_mode, $form, &$form_state) {
-
-  }
-
   /**
   /**
    *
    *
    * @see TripalFieldFormatter::view()
    * @see TripalFieldFormatter::view()

+ 274 - 369
tripal_chado/includes/TripalFields/sbo__relationship/sbo__relationship.inc

@@ -84,6 +84,12 @@ class sbo__relationship extends ChadoField {
         'searchable' => FALSE,
         'searchable' => FALSE,
         'type' => 'string',
         'type' => 'string',
         'elements' => array(
         'elements' => array(
+          'SIO:000493' => array(
+            'searchable' => FALSE,
+            'label' => 'Relationship Clause',
+            'help' => 'An English phrase describing the relationships.',
+            'sortable' => FALSE,
+          ),
           'local:relationship_subject' => array(
           'local:relationship_subject' => array(
             'searchable' => FALSE,
             'searchable' => FALSE,
             'name' => 'relationship_subject',
             'name' => 'relationship_subject',
@@ -92,7 +98,6 @@ class sbo__relationship extends ChadoField {
             'elements' => array(
             'elements' => array(
               'rdfs:type' => array(
               'rdfs:type' => array(
                 'searchable' => TRUE,
                 'searchable' => TRUE,
-                'name' => 'subject_type',
                 'label' => 'Relationship Subject Type',
                 'label' => 'Relationship Subject Type',
                 'help' => 'The subject\'s data type in a relationship clause',
                 'help' => 'The subject\'s data type in a relationship clause',
                 'operations' => array('eq', 'ne', 'contains', 'starts'),
                 'operations' => array('eq', 'ne', 'contains', 'starts'),
@@ -100,7 +105,6 @@ class sbo__relationship extends ChadoField {
               ),
               ),
               'schema:name' => array(
               'schema:name' => array(
                 'searchable' => TRUE,
                 'searchable' => TRUE,
-                'name' => 'subject_name',
                 'label' => 'Relationship Subject Name',
                 'label' => 'Relationship Subject Name',
                 'help' => 'The subject\'s name in a relationship clause',
                 'help' => 'The subject\'s name in a relationship clause',
                 'operations' => array('eq', 'ne', 'contains', 'starts'),
                 'operations' => array('eq', 'ne', 'contains', 'starts'),
@@ -150,29 +154,28 @@ class sbo__relationship extends ChadoField {
       )
       )
     );
     );
   }
   }
-  /**
-   *
-   * @see TripalField::load()
-   */
-  public function load($entity) {
-    $settings = $this->field['settings'];
 
 
-    $record = $entity->chado_record;
-    $bundle = tripal_load_bundle_entity(array('name' => $entity->bundle));
+  private function loadRelationship($relationship, &$entity, $delta) {
 
 
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
-    $field_type = $this->field['type'];
     $field_table = $this->instance['settings']['chado_table'];
     $field_table = $this->instance['settings']['chado_table'];
-    $field_column = $this->instance['settings']['chado_column'];
     $base_table = $this->instance['settings']['base_table'];
     $base_table = $this->instance['settings']['base_table'];
 
 
-    // Get the PKey for this table
-    $schema = chado_get_schema($field_table);
-    $pkey = $schema['primary key'][0];
+    $rel_acc = $relationship->type_id->dbxref_id->db_id->name . ':' . $relationship->type_id->dbxref_id->accession;
+    $rel_type = $relationship->type_id->name;
+    $verb = $this->get_rel_verb($rel_type);
 
 
     // Get the foreign keys for the subject and object tables
     // Get the foreign keys for the subject and object tables
     $subject_fkey_table = '';
     $subject_fkey_table = '';
     $object_fkey_table = '';
     $object_fkey_table = '';
+
+    $schema = chado_get_schema($field_table);
+    $pkey = $schema['primary key'][0];
+    $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
+    $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
+
+    // Not all tables have the columns named 'subject_id' and 'object_id'.
+    // some have variations on that name and we need to determine what they are.
     $fkeys = $schema['foreign keys'];
     $fkeys = $schema['foreign keys'];
     $subject_id_key = 'subject_id';
     $subject_id_key = 'subject_id';
     $object_id_key = 'object_id';
     $object_id_key = 'object_id';
@@ -188,37 +191,172 @@ class sbo__relationship extends ChadoField {
         }
         }
       }
       }
     }
     }
+
+    // Get the schemas for the subject and object table.  These should
+    // be the same as the base table but just to be safe we'll get them
+    // separately.
     $subject_schema = chado_get_schema($subject_fkey_table);
     $subject_schema = chado_get_schema($subject_fkey_table);
-    $object_schema = chado_get_schema($object_fkey_table);
     $subject_pkey = $subject_schema['primary key'][0];
     $subject_pkey = $subject_schema['primary key'][0];
+    $object_schema = chado_get_schema($object_fkey_table);
     $object_pkey = $object_schema['primary key'][0];
     $object_pkey = $object_schema['primary key'][0];
 
 
-    // Get the FK that links to the base record.
+    // Not all realtionshp tables have a name field (e.g. organism_relationship)
+    // threfore in some cases we need to dig a bit deeper to get the entity
+    // name and the entity type name.
+    $subject_name = '';
+    $subject_type = '';
+    $object_name = '';
+    $object_type = '';
+
+    // The linked to table of a relationship linker table may not always
+    // have a type_id or name field.  So we have to be a bit more
+    // specific about how we set some variables.
+    switch ($relationship->tablename) {
+      case 'acquisition_relationship':
+        $subject_type = 'acquisition';
+        $object_type = 'acquisition';
+        break;
+      case 'analysis_relationship':
+        $subject_type = 'analysis';
+        $object_type = 'analysis';
+        break;
+      case 'biomaterial_relationship':
+        $subject_type = 'biomaterial';
+        $object_type = 'biomaterial';
+        break;
+      case 'cell_line_relationship':
+        $subject_type = 'cell_line';
+        $object_type = 'cell_line';
+        break;
+      case 'element_relationship':
+        $subject_name = $relationship->$subject_id_key->feature_id->name;
+        $object_name = $relationship->$object_id_key->feature_id->name;
+        break;
+      case 'organism_relationship':
+        $subject_name = $relationship->$subject_id_key->genus . ' ' . $relationship->$subject_id_key->species;
+        $object_name = $relationship->$object_id_key->genus . ' ' . $relationship->$object_id_key->species;
+        $subject_type = 'organism';
+        $object_type = 'organism';
+        break;
+      case 'project_relationship':
+        $subject_type = 'project';
+        $object_type = 'project';
+        break;
+      case 'phylonode_relationship':
+        $subject_name = $relationship->$subject_id_key->label;
+        $object_name = $relationship->$object_id_key->label;
+        break;
+      case 'pub_relationship':
+        $subject_name = $relationship->$subject_id_key->uniquename;
+        $object_name = $relationship->$object_id_key->uniquename;
+        break;
+      case 'quantification_relationship':
+        $subject_type = 'quantification';
+        $object_type = 'quantification';
+        break;
+      default:
+        $subject_name = isset($relationship->$subject_id_key->name) ? $relationship->$subject_id_key->name : '';
+        $subject_type = isset($relationship->$subject_id_key->type_id) ? $relationship->$subject_id_key->type_id->name : '';
+        $object_name = isset($relationship->$object_id_key->name) ? $relationship->$object_id_key->name : '';
+        $object_type = isset($relationship->$object_id_key->type_id) ? $relationship->$object_id_key->type_id->name : '';
+    }
+
+    $entity->{$field_name}['und'][$delta]['value'] = array(
+      'local:relationship_subject' => array(
+        'rdfs:type' => $subject_type,
+        'schema:name' => $subject_name,
+      ),
+      'local:relationship_type' => $relationship->type_id->name,
+      'local:relationship_object' => array(
+        'rdfs:type' => $object_type,
+        'schema:name' => $object_name,
+        'entity' => 'TripalEntity:' . $entity->id,
+      )
+    );
+
+    // If the subject or object have a unqiuename then add that in for refernce.
+    if (property_exists($relationship->$subject_id_key, 'uniquename')) {
+      $entity->{$field_name}['und'][$delta]['value']['local:relationship_subject']['data:0842'] = $relationship->$subject_id_key->uniquename;;
+    }
+    if (property_exists($relationship->$object_id_key, 'uniquename')) {
+      $entity->{$field_name}['und'][$delta]['value']['local:relationship_object']['data:0842'] = $relationship->$object_id_key->uniquename;
+    }
+
+    // Add in the TripalEntity ids if these base records in the relationship
+    // are published.
+    if (property_exists($relationship->$subject_id_key, 'entity_id')) {
+      $entity_id = $relationship->$subject_id_key->entity_id;
+      $entity->{$field_name}['und'][$delta]['value']['local:relationship_subject']['entity'] = 'TripalEntity:' . $entity_id;
+    }
+    if (property_exists($relationship->$object_id_key, 'entity_id')) {
+      $entity_id = $relationship->$object_id_key->entity_id;
+      $entity->{$field_name}['und'][$delta]['value']['local:relationship_object']['entity'] = 'TripalEntity:' . $entity_id;
+    }
+
+    // Add the clause to the values array.  The clause is a written version
+    // of the relationships.
+    $rel_type_clean = lcfirst(preg_replace('/_/', ' ', $rel_type));
+    $entity->{$field_name}['und'][$delta]['value']['SIO:000493'] = 'The ' . $subject_type . ', ' .
+      $subject_name . ', ' . $verb . ' '  . $rel_type_clean . ' this '  .
+      $object_type . '.';
+
+    $entity->{$field_name}['und'][$delta]['chado-' . $field_table . '__' . $pkey] = $relationship->$pkey;
+    $entity->{$field_name}['und'][$delta]['chado-' . $field_table . '__' . $subject_id_key] = $relationship->$subject_id_key->$subject_pkey;
+    $entity->{$field_name}['und'][$delta]['chado-' . $field_table . '__type_id'] = $relationship->type_id->cvterm_id;
+    $entity->{$field_name}['und'][$delta]['chado-' . $field_table . '__' . $object_id_key] = $relationship->$object_id_key->$object_pkey;
+
+    // For the widget to work properly we will preform values.
+    $entity->{$field_name}['und'][$delta]['type_name'] = $relationship->type_id->name;
+    $entity->{$field_name}['und'][$delta]['subject_name'] = $subject_name . ' [id: ' . $relationship->$subject_id_key->$subject_pkey . ']';
+    $entity->{$field_name}['und'][$delta]['object_name'] = $object_name  . ' [id: ' . $relationship->$object_id_key->$object_pkey . ']';
+    if (array_key_exists('value', $schema['fields'])) {
+      $entity->{$field_name}['und'][$delta]['chado-' . $field_table . '__value'] = $relationship->value;
+    }
+    if (array_key_exists('rank', $schema['fields'])) {
+      $entity->{$field_name}['und'][$delta]['chado-' . $field_table . '__rank'] = $relationship->rank;
+    }
+  }
+ /**
+   *
+   * @see TripalField::load()
+   */
+  public function load($entity) {
+    $settings = $this->field['settings'];
+
+    $record = $entity->chado_record;
+    $bundle = tripal_load_bundle_entity(array('name' => $entity->bundle));
+
+    $field_name = $this->field['field_name'];
+    $field_type = $this->field['type'];
+    $field_table = $this->instance['settings']['chado_table'];
+    $field_column = $this->instance['settings']['chado_column'];
+    $base_table = $this->instance['settings']['base_table'];
+
+    // Get the PKey for this table
     $schema = chado_get_schema($field_table);
     $schema = chado_get_schema($field_table);
+    $pkey = $schema['primary key'][0];
     $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
     $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
     $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
     $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
 
 
+    // Not all tables have the columns named 'subject_id' and 'object_id'.
+    // some have variations on that name and we need to determine what they are.
+    $fkeys = $schema['foreign keys'];
+    $subject_id_key = 'subject_id';
+    $object_id_key = 'object_id';
+    foreach ($fkeys as $fktable => $details) {
+      foreach ($details['columns'] as $fkey_lcolumn => $fkey_rcolumn) {
+        if (preg_match('/^subject_.*id/', $fkey_lcolumn)) {
+          $subject_id_key = $fkey_lcolumn;
+        }
+        if (preg_match('/^object_.*id/', $fkey_lcolumn)) {
+          $object_id_key = $fkey_lcolumn;
+        }
+      }
+    }
+
     // Set some defaults for the empty record.
     // Set some defaults for the empty record.
     $entity->{$field_name}['und'][0] = array(
     $entity->{$field_name}['und'][0] = array(
-      'value' => array(
-      /* The following shows what may be present in the value array
-        // Clause
-        'SIO:000493' => '',
-        'local:relationship_subject' => array(
-          // Identifier
-          'data:0842' => '',
-          'schema:name' => '',
-          'rdfs:type' => ''
-        ),
-        'local:relationship_object' => array(
-          // Identifier
-          'data:0842' => '',
-          'schema:name' => '',
-          'rdfs:type' => '',
-        ),
-        'local:relationship_type' => '',
-      */
-      ),
+      'value' => '',
       'chado-' . $field_table . '__' . $pkey => '',
       'chado-' . $field_table . '__' . $pkey => '',
       'chado-' . $field_table . '__' . $subject_id_key => '',
       'chado-' . $field_table . '__' . $subject_id_key => '',
       'chado-' . $field_table . '__' . $object_id_key => '',
       'chado-' . $field_table . '__' . $object_id_key => '',
@@ -269,244 +407,22 @@ class sbo__relationship extends ChadoField {
     if (!$record->$rel_table) {
     if (!$record->$rel_table) {
       return;
       return;
     }
     }
-    $srelationships = null;
-    $orelationships = null;
 
 
+    // Load the subject relationships
+    $i = 0;
     if (isset($record->$rel_table->$subject_id_key)) {
     if (isset($record->$rel_table->$subject_id_key)) {
       $srelationships = $record->$rel_table->$subject_id_key;
       $srelationships = $record->$rel_table->$subject_id_key;
-    }
-    if (isset($record->$rel_table->$object_id_key)) {
-      $orelationships = $record->$rel_table->$object_id_key;
-    }
-
-    $i = 0;
-    if ($orelationships) {
-      foreach ($orelationships as $relationship) {
-        $rel_acc = $relationship->type_id->dbxref_id->db_id->name . ':' . $relationship->type_id->dbxref_id->accession;
-        $rel_type = $relationship->type_id->name;
-        $verb = $this->get_rel_verb($rel_type);
-        $subject_id = $relationship->$subject_id_key->$subject_pkey;
-
-        // The linked to table of a relationship linker table may not always
-        // have a type_id or name field.  So we have to be a bit more
-        // specific about how we set some variables.
-        switch ($relationship->tablename) {
-          case 'acquisition_relationship':
-            $subject_type = 'acquisition';
-            $object_type = 'acquisition';
-            break;
-          case 'analysis_relationship':
-            $subject_type = 'analysis';
-            $object_type = 'analysis';
-            break;
-          case 'biomaterial_relationship':
-            $subject_type = 'biomaterial';
-            $object_type = 'biomaterial';
-            break;
-          case 'cell_line_relationship':
-            $subject_type = 'cell_line';
-            $object_type = 'cell_line';
-            break;
-          case 'element_relationship':
-            $subject_name = $relationship->$subject_id_key->feature_id->name;
-            $object_name = $relationship->$object_id_key->feature_id->name;
-            break;
-          case 'organism_relationship':
-            $subject_name = $relationship->$subject_id_key->genus . ' ' . $relationship->$subject_id_key->species;
-            $object_name = $relationship->$object_id_key->genus . ' ' . $relationship->$object_id_key->species;
-            $subject_type = 'organism';
-            $object_type = 'organism';
-            break;
-          case 'project_relationship':
-            $subject_type = 'project';
-            $object_type = 'project';
-            break;
-          case 'phylonode_relationship':
-            $subject_name = $relationship->$subject_id_key->label;
-            $object_name = $relationship->$object_id_key->label;
-            break;
-          case 'pub_relationship':
-            $subject_name = $relationship->$subject_id_key->uniquename;
-            $object_name = $relationship->$object_id_key->uniquename;
-            break;
-          case 'quantification_relationship':
-            $subject_type = 'quantification';
-            $object_type = 'quantification';
-            break;
-          default:
-            $subject_name = isset($relationship->$subject_id_key->name) ? $relationship->$subject_id_key->name : '';
-            $subject_type = isset($relationship->$subject_id_key->type_id) ? $relationship->$subject_id_key->type_id->name : '';
-            $object_name = isset($relationship->$object_id_key->name) ? $relationship->$object_id_key->name : '';
-            $object_type = isset($relationship->$object_id_key->type_id) ? $relationship->$object_id_key->type_id->name : '';
-        }
-
-        $entity->{$field_name}['und'][$i]['value'] = array(
-          'local:relationship_subject' => array(
-            'rdfs:type' => $subject_type,
-            'schema:name' => $subject_name,
-          ),
-          'local:relationship_type' => $relationship->type_id->name,
-          'local:relationship_object' => array(
-            'rdfs:type' => $object_type,
-            'schema:name' => $object_name,
-            'entity' => 'TripalEntity:' . $entity->id,
-          )
-        );
-
-        // See if an entity exists for the subject.
-        $data_table = preg_replace('/_relationship/', '', $relationship->tablename);
-        $sentity_id = chado_get_record_entity_by_table($data_table, $subject_id);
-        if ($sentity_id) {
-          $entity->{$field_name}['und'][$i]['value']['local:relationship_subject']['entity'] = 'TripalEntity:' . $sentity_id;
-        }
-
-        if (property_exists($relationship->$subject_id_key, 'uniquename')) {
-          $entity->{$field_name}['und'][$i]['value']['local:relationship_subject']['data:0842'] =  $relationship->$subject_id_key->uniquename;;
-        }
-        if (property_exists($relationship->$object_id_key, 'uniquename')) {
-          $entity->{$field_name}['und'][$i]['value']['local:relationship_object']['data:0842'] = $relationship->$object_id_key->uniquename;
-        }
-        if (property_exists($relationship->$subject_id_key, 'entity_id')) {
-          $entity_id = $relationship->$subject_id_key->entity_id;
-          $entity->{$field_name}['und'][$i]['value']['local:relationship_subject']['entity'] = 'TripalEntity:' . $entity_id;
-        }
-
-        // Add the clause to the values array.
-        $rel_type_clean = lcfirst(preg_replace('/_/', ' ', $rel_type));
-        $entity->{$field_name}['und'][$i]['value']['SIO:000493'] = 'The ' . $subject_type . ', ' .
-          $subject_name . ', ' . $verb . ' '  . $rel_type_clean . ' this '  .
-          $object_type . '.';
-
-        $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__' . $pkey] = $relationship->$pkey;
-        $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__' . $subject_id_key] = $relationship->$subject_id_key->$subject_pkey;
-        $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__type_id'] = $relationship->type_id->cvterm_id;
-        $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__' . $object_id_key] = $relationship->$object_id_key->$object_pkey;
-
-        $entity->{$field_name}['und'][$i]['type_name'] = $relationship->type_id->name;
-        $entity->{$field_name}['und'][$i]['subject_name'] = $subject_name . ' [id: ' . $relationship->$subject_id_key->$fkey_rcolumn . ']';
-        $entity->{$field_name}['und'][$i]['object_name'] = $object_name  . ' [id: ' . $relationship->$object_id_key->$fkey_rcolumn . ']';
-        if (array_key_exists('value', $schema['fields'])) {
-          $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__value'] = $relationship->value;
-        }
-        if (array_key_exists('rank', $schema['fields'])) {
-          $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__rank'] = $relationship->rank;
-        }
+      foreach ($srelationships as $relationship) {
+        $this->loadRelationship($relationship, $entity, $i);
         $i++;
         $i++;
       }
       }
     }
     }
 
 
-    if ($srelationships) {
-      foreach ($srelationships as $relationship) {
-        $rel_acc = $relationship->type_id->dbxref_id->db_id->name . ':' . $relationship->type_id->dbxref_id->accession;
-        $rel_type = $relationship->type_id->name;
-        $verb = $this->get_rel_verb($rel_type);
-        $object_id = $relationship->$object_id_key->$object_pkey;
-
-        // The linked to table of a relationship linker table may not always
-        // have a type_id or name field.  So we have to be a bit more
-        // specific about how we set some variables.
-        switch ($relationship->tablename) {
-          case 'acquisition_relationship':
-            $subject_type = 'acquisition';
-            $object_type = 'acquisition';
-            break;
-          case 'analysis_relationship':
-            $subject_type = 'analysis';
-            $object_type = 'analysis';
-            break;
-          case 'biomaterial_relationship':
-            $subject_type = 'biomaterial';
-            $object_type = 'biomaterial';
-            break;
-          case 'cell_line_relationship':
-            $subject_type = 'cell_line';
-            $object_type = 'cell_line';
-            break;
-          case 'element_relationship':
-            $subject_name = $relationship->$subject_id_key->feature_id->name;
-            $object_name = $relationship->$object_id_key->feature_id->name;
-            break;
-          case 'organism_relationship':
-            $subject_name = $relationship->$subject_id_key->genus . ' ' . $relationship->$subject_id_key->species;
-            $object_name = $relationship->$object_id_key->genus . ' ' . $relationship->$object_id_key->species;
-            $subject_type = 'organism';
-            $object_type = 'organism';
-            break;
-          case 'project_relationship':
-            $subject_type = 'project';
-            $object_type = 'project';
-            break;
-          case 'phylonode_relationship':
-            $subject_name = $relationship->$subject_id_key->label;
-            $object_name = $relationship->$object_id_key->label;
-            break;
-          case 'pub_relationship':
-            $subject_name = $relationship->$subject_id_key->uniquename;
-            $object_name = $relationship->$object_id_key->uniquename;
-            break;
-          case 'quantification_relationship':
-            $subject_type = 'quantification';
-            $object_type = 'quantification';
-            break;
-          default:
-            $subject_name = isset($relationship->$subject_id_key->name) ? $relationship->$subject_id_key->name : '';
-            $subject_type = isset($relationship->$subject_id_key->type_id) ? $relationship->$subject_id_key->type_id->name : '';
-            $object_name = isset($relationship->$object_id_key->name) ? $relationship->$object_id_key->name : '';
-            $object_type = isset($relationship->$object_id_key->type_id) ? $relationship->$object_id_key->type_id->name : '';
-        }
-
-        $entity->{$field_name}['und'][$i]['value'] = array(
-          'local:relationship_subject' => array(
-            'rdfs:type' => $subject_type,
-            'schema:name' => $subject_name,
-            'entity' => 'TripalEntity:' . $entity->id,
-          ),
-          'local:relationship_type' => $relationship->type_id->name,
-          'local:relationship_object' => array(
-            'rdfs:type' =>  $object_type,
-            'schema:name' => $object_name,
-          )
-        );
-
-        // See if an entity exists for the object.
-        $data_table = preg_replace('/_relationship/', '', $relationship->tablename);
-        $oentity_id = chado_get_record_entity_by_table($data_table, $object_id);
-        if ($oentity_id) {
-          $entity->{$field_name}['und'][$i]['value']['local:relationship_object']['entity'] = 'TripalEntity:' . $oentity_id;
-        }
-
-        if (property_exists($relationship->$subject_id_key, 'uniquename')) {
-          $entity->{$field_name}['und'][$i]['value']['local:relationship_subject']['data:0842'] = $relationship->$subject_id_key->uniquename;
-        }
-        if (property_exists($relationship->$object_id_key, 'uniquename')) {
-          $entity->{$field_name}['und'][$i]['value']['local:relationship_object']['data:0842'] = $relationship->$object_id_key->uniquename;
-        }
-        if (property_exists($relationship->$object_id_key, 'entity_id')) {
-          $entity_id = $relationship->$object_id_key->entity_id;
-          $entity->{$field_name}['und'][$i]['value']['local:relationship_object']['entity'] = 'TripalEntity:' . $entity_id;
-        }
-
-        // Add the clause to the value array.
-        $rel_type_clean = lcfirst(preg_replace('/_/', ' ', $rel_type));
-        $entity->{$field_name}['und'][$i]['value']['SIO:000493'] = 'This ' .
-          $subject_type . ' ' . $verb . ' '  . $rel_type_clean . ' the '  .
-          $object_type . ' ' . $object_name . '.';
-
-        $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__' . $pkey] = $relationship->$pkey;
-        $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__' . $subject_id_key] = $relationship->$subject_id_key->$subject_pkey;
-        $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__type_id'] = $relationship->type_id->cvterm_id;
-        $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__' . $object_id_key] = $relationship->$object_id_key->$object_pkey;
-
-        $entity->{$field_name}['und'][$i]['type_name'] = $relationship->type_id->name;
-        $entity->{$field_name}['und'][$i]['subject_name'] = $subject_name . ' [id: ' . $relationship->$subject_id_key->$fkey_rcolumn . ']';
-        $entity->{$field_name}['und'][$i]['object_name'] = $object_name . ' [id: ' . $relationship->$object_id_key->$fkey_rcolumn . ']';
-
-        if (array_key_exists('value', $schema['fields'])) {
-          $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__value'] = $relationship->value;
-        }
-        if (array_key_exists('rank', $schema['fields'])) {
-          $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__rank'] = $relationship->rank;
-        }
+    // Load the object relationships
+    if (isset($record->$rel_table->$object_id_key)) {
+      $orelationships = $record->$rel_table->$object_id_key;
+      foreach ($orelationships as $relationship) {
+        $this->loadRelationship($relationship, $entity, $i);
         $i++;
         $i++;
       }
       }
     }
     }
@@ -743,123 +659,112 @@ class sbo__relationship extends ChadoField {
     $option3 = isset($settings['relationship_types']) && trim($settings['relationship_types']);
     $option3 = isset($settings['relationship_types']) && trim($settings['relationship_types']);
     if ($option1 && ($option2 || $option3) == 1 ||
     if ($option1 && ($option2 || $option3) == 1 ||
         $option2 && ($option1 || $option3) == 1 ||
         $option2 && ($option1 || $option3) == 1 ||
-        $option3 && ($option1 || $option2) == 1
-        ) {
-          form_set_error(
-              "instance][settings][relationships",
-              t("Only one option is allowed to limit the relationship types.")
-              );
-          return;
-        }
+        $option3 && ($option1 || $option2) == 1) {
+      form_set_error("instance][settings][relationships", t("Only one option is allowed to limit the relationship types."));
+      return;
+    }
 
 
-        // For option3, make sure the supplied types are valid cvterms
-        if ($option3) {
-          $rel_types = explode(PHP_EOL, $settings['relationship_types']);
-          foreach($rel_types AS $type) {
-            $type =  trim($type);
-            // Ignore empty lines
-            if ($type == '') {
-              continue;
-            }
-            // Find the matching cvterm
-            $sql = "SELECT cvterm_id FROM {cvterm} WHERE name = :name";
-            $results = chado_query($sql, array(':name' => $type));
-            $terms = array();
-            while ($obj = $results->fetchObject()) {
-              $terms[] = $obj;
-            }
-            // Don't save the form  if a term can not be found or it matches more than one cvterm
-            $cv = '';
-            if (count($terms) == 0) {
-              // If a term can not be found, maybe the type contains '|', parse it as 'vocabulary|cvterm'
-              if (strpos($type, '|')) {
-                $tmp = explode('|', $type, 2);
-                $type = trim($tmp[1]);
-                $cv = tripal_get_cv(array('name' => trim($tmp[0])));
-                if($cv) {
-                  $sql = "SELECT cvterm_id FROM {cvterm} WHERE name = :name AND cv_id = :cv_id";
-                  $results = chado_query($sql, array(':name' => $type, ':cv_id' => $cv->cv_id));
-                  while ($obj = $results->fetchObject()) {
-                    $terms[] = $obj;
-                  }
-                }
-                else {
-                  $cv = $tmp[0];
-                }
-              }
-              if (count($terms) != 1) {
-                $message = "The term '@type' can not be found.";
-                $token = array('@type' => $type);
-                if ($cv) {
-                  $message =  "The term '@type' can not be found within the vocabulary '@vocab'.";
-                  $token['@vocab'] = $cv;
-                }
-                form_set_error(
-                    "instance][settings][relationships][relationship_types",
-                    t($message, $token)
-                    );
+    // For option3, make sure the supplied types are valid cvterms
+    if ($option3) {
+      $rel_types = explode(PHP_EOL, $settings['relationship_types']);
+      foreach($rel_types AS $type) {
+        $type =  trim($type);
+        // Ignore empty lines
+        if ($type == '') {
+          continue;
+        }
+        // Find the matching cvterm
+        $sql = "SELECT cvterm_id FROM {cvterm} WHERE name = :name";
+        $results = chado_query($sql, array(':name' => $type));
+        $terms = array();
+        while ($obj = $results->fetchObject()) {
+          $terms[] = $obj;
+        }
+        // Don't save the form  if a term can not be found or it matches more than one cvterm
+        $cv = '';
+        if (count($terms) == 0) {
+          // If a term can not be found, maybe the type contains '|', parse it as 'vocabulary|cvterm'
+          if (strpos($type, '|')) {
+            $tmp = explode('|', $type, 2);
+            $type = trim($tmp[1]);
+            $cv = tripal_get_cv(array('name' => trim($tmp[0])));
+            if($cv) {
+              $sql = "SELECT cvterm_id FROM {cvterm} WHERE name = :name AND cv_id = :cv_id";
+              $results = chado_query($sql, array(':name' => $type, ':cv_id' => $cv->cv_id));
+              while ($obj = $results->fetchObject()) {
+                $terms[] = $obj;
               }
               }
             }
             }
-            else if (count($terms) > 1) {
-              // If a type matches more than one term, parse it as 'vocabulary|cvterm' and try again
-              if (strpos($type, '|')) {
-                $tmp = explode('|', $type, 2);
-                $type = trim($tmp[1]);
-                $cv = tripal_get_cv(array('name' => trim($tmp[0])));
-                if ($cv) {
-                  $sql = "SELECT cvterm_id FROM {cvterm} WHERE name = :name AND cv_id = :cv_id";
-                  $results = chado_query($sql, array(':name' => $type, ':cv_id' => $cv->cv_id));
-                  while ($obj = $results->fetchObject()) {
-                    $terms[] = $obj;
-                  }
-                }
-              }
-              if(count($terms) != 1) {
-                form_set_error(
-                    "instance][settings][relationships][relationship_types",
-                    t("The term '@type' matches more than one term. Please specify its vocabulary in
-                  the format of 'vocabulary|@type'.", array('@type' => $type))
-                    );
-              }
+            else {
+              $cv = $tmp[0];
+            }
+          }
+          if (count($terms) != 1) {
+            $message = "The term '@type' can not be found.";
+            $token = array('@type' => $type);
+            if ($cv) {
+              $message =  "The term '@type' can not be found within the vocabulary '@vocab'.";
+              $token['@vocab'] = $cv;
             }
             }
+            form_set_error("instance][settings][relationships][relationship_types",
+                t($message, $token));
           }
           }
         }
         }
-
-        // For option2: Make sure the parent term is a valid cvterm
-        if ($option2) {
-          $cv_id = $settings['option2_vocab'];
-          $supertype = $settings['option2_parent'];
-          $term = tripal_get_cvterm(array(
-            'name' => trim($supertype),
-            'cv_id' => $cv_id,
-          ));
-          // Tripal cv autocomplete also allow cvterm synonyms, if the parent term doesn't match
-          // a cvterm, try cvtermsynonym
-          if (!$term) {
-            $synonym = tripal_get_cvterm(
-                array(
-                  'synonym' => array(
-                    'name' => trim($supertype),
-                  )
-                )
-                );
-            if ($synonym && $synonym->cv_id->cv_id == $cv_id) {
-              $term = $synonym;
+        else if (count($terms) > 1) {
+          // If a type matches more than one term, parse it as 'vocabulary|cvterm' and try again
+          if (strpos($type, '|')) {
+            $tmp = explode('|', $type, 2);
+            $type = trim($tmp[1]);
+            $cv = tripal_get_cv(array('name' => trim($tmp[0])));
+            if ($cv) {
+              $sql = "SELECT cvterm_id FROM {cvterm} WHERE name = :name AND cv_id = :cv_id";
+              $results = chado_query($sql, array(':name' => $type, ':cv_id' => $cv->cv_id));
+              while ($obj = $results->fetchObject()) {
+                $terms[] = $obj;
+              }
             }
             }
           }
           }
-          if (!isset($term->cvterm_id)) {
-            form_set_error(
-                "instance][settings][relationships][option2_parent",
-                t("The term '@type' is not a valid term for the vocabulary selected.", array('@type' => $supertype))
-                );
+          if(count($terms) != 1) {
+            form_set_error("instance][settings][relationships][relationship_types",
+              t("The term '@type' matches more than one term. Please specify its vocabulary in the format of 'vocabulary|@type'.", array('@type' => $type)));
           }
           }
         }
         }
+      }
+    }
+
+    // For option2: Make sure the parent term is a valid cvterm
+    if ($option2) {
+      $cv_id = $settings['option2_vocab'];
+      $supertype = $settings['option2_parent'];
+      $term = tripal_get_cvterm(array(
+        'name' => trim($supertype),
+        'cv_id' => $cv_id,
+      ));
+      // Tripal cv autocomplete also allow cvterm synonyms, if the parent term doesn't match
+      // a cvterm, try cvtermsynonym
+      if (!$term) {
+        $synonym = tripal_get_cvterm(
+            array(
+              'synonym' => array(
+                'name' => trim($supertype),
+              )
+            )
+            );
+        if ($synonym && $synonym->cv_id->cv_id == $cv_id) {
+          $term = $synonym;
+        }
+      }
+      if (!isset($term->cvterm_id)) {
+        form_set_error("instance][settings][relationships][option2_parent",
+            t("The term '@type' is not a valid term for the vocabulary selected.", array('@type' => $supertype)));
+      }
+    }
   }
   }
 
 
   /**
   /**
    * @see TripalField::validate()
    * @see TripalField::validate()
    */
    */
-  public function validate($entity_type, $entity, $field, $items, &$errors) {
+  public function validate($entity_type, $entity, $langcode, $items, &$errors) {
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
     $field_type = $this->field['type'];
     $field_type = $this->field['type'];
     $field_table = $this->instance['settings']['chado_table'];
     $field_table = $this->instance['settings']['chado_table'];

+ 10 - 4
tripal_chado/includes/TripalFields/sbo__relationship/sbo__relationship_widget.inc

@@ -14,6 +14,10 @@ class sbo__relationship_widget extends ChadoFieldWidget {
   public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
   public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
 
 
+    // TODO: make this widget deal better with the various relationship
+    // tables. See the load function as it does a better job of this.
+    return;
+
     // Get the field settings.
     // Get the field settings.
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
     $field_type = $this->field['type'];
     $field_type = $this->field['type'];
@@ -99,7 +103,8 @@ class sbo__relationship_widget extends ChadoFieldWidget {
     }
     }
 
 
     // Check $form_state['values'] to see if an AJAX call set the values.
     // Check $form_state['values'] to see if an AJAX call set the values.
-    if (array_key_exists('values', $form_state) and array_key_exists($delta, $form_state['values'])) {
+    if (array_key_exists('values', $form_state) and
+        array_key_exists($field_name, $form_state['values'])) {
       $record_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $pkey];
       $record_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $pkey];
       $subject_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $subject_id_key];
       $subject_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $subject_id_key];
       $object_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $object_id_key];
       $object_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $object_id_key];
@@ -329,15 +334,16 @@ class sbo__relationship_widget extends ChadoFieldWidget {
 
 
   /**
   /**
    *
    *
-   * @see TripalFieldWidget::submit()
+   * @see TripalFieldWidget::validate()
    */
    */
-  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
+  public function validate($element, $form, &$form_state, $langcode, $delta) {
+
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
     $field_type = $this->field['type'];
     $field_type = $this->field['type'];
     $field_table = $this->instance['settings']['chado_table'];
     $field_table = $this->instance['settings']['chado_table'];
     $field_column = $this->instance['settings']['chado_column'];
     $field_column = $this->instance['settings']['chado_column'];
     $base_table = $this->instance['settings']['base_table'];
     $base_table = $this->instance['settings']['base_table'];
-    $chado_record_id = $entity->chado_record_id;
+    $chado_record_id = array_key_exists('#entity', $element)? $element['#entity']->chado_record_id : NULL;
 
 
     $schema = chado_get_schema($field_table);
     $schema = chado_get_schema($field_table);
     $fkeys = $schema['foreign keys'];
     $fkeys = $schema['foreign keys'];

+ 38 - 1
tripal_chado/includes/TripalFields/schema__additional_type/schema__additional_type.inc

@@ -35,6 +35,14 @@ class schema__additional_type extends ChadoField {
     // type. This will create form elements when editing the field instance
     // type. This will create form elements when editing the field instance
     // to allow the site admin to change the term settings above.
     // to allow the site admin to change the term settings above.
     'term_fixed' => FALSE,
     'term_fixed' => FALSE,
+    // The name of the vocabulary that should be used to provide a list
+    // of terms to select form when providing the additional type.
+    // This should be the name of the controlled vocabulary from the cv table.
+    'vocabulary' => '',
+    // If the entire vocabulary is not to be used for the types and if the
+    // vocabulary is heirarchical then this will be the parent term.
+    // This should be of the format {db.name}:{dbxref.accession}
+    'parent_term' => '',
   );
   );
 
 
   // The default widget for this field.
   // The default widget for this field.
@@ -43,6 +51,36 @@ class schema__additional_type extends ChadoField {
   // The default formatter for this field.
   // The default formatter for this field.
   public static $default_formatter = 'schema__additional_type_formatter';
   public static $default_formatter = 'schema__additional_type_formatter';
 
 
+  /**
+   * @see ChadoField::query()
+   */
+  public function query($query, $condition) {
+    $alias = $this->field['field_name'];
+    $operator = $condition['operator'];
+
+    $field_name = $this->field['field_name'];
+    $field_type = $this->field['type'];
+    $field_table = $this->instance['settings']['chado_table'];
+    $field_column = $this->instance['settings']['chado_column'];
+
+    $this->queryJoinOnce($query, 'cvterm', $alias, "base.$field_column = $alias.cvterm_id");
+    $query->condition($alias . '.name' , $condition['value'], $operator);
+  }
+
+  /**
+   * @see ChadoField::query()
+   */
+  public function queryOrder($query, $order) {
+    $alias = $this->field['field_name'];
+
+    $field_name = $this->field['field_name'];
+    $field_type = $this->field['type'];
+    $field_table = $this->instance['settings']['chado_table'];
+    $field_column = $this->instance['settings']['chado_column'];
+
+    $this->queryJoinOnce($query, 'cvterm', $alias, "base.$field_column = $alias.cvterm_id", "LEFT OUTER");
+    $query->orderBy($alias . '.name' , $order['direction']);
+  }
 
 
   /**
   /**
    *
    *
@@ -57,7 +95,6 @@ class schema__additional_type extends ChadoField {
     $field_table = $this->instance['settings']['chado_table'];
     $field_table = $this->instance['settings']['chado_table'];
     $field_column = $this->instance['settings']['chado_column'];
     $field_column = $this->instance['settings']['chado_column'];
 
 
-
     // Set some defaults for the empty record.
     // Set some defaults for the empty record.
     $entity->{$field_name}['und'][0] = array(
     $entity->{$field_name}['und'][0] = array(
       'value' => $record->type_id->name,
       'value' => $record->type_id->name,

+ 8 - 13
tripal_chado/includes/TripalFields/schema__additional_type/schema__additional_type_formatter.inc

@@ -7,24 +7,19 @@ class schema__additional_type_formatter extends ChadoFieldFormatter {
   // The list of field types for which this formatter is appropriate.
   // The list of field types for which this formatter is appropriate.
   public static $field_types = array('schema__additional_type');
   public static $field_types = array('schema__additional_type');
 
 
-  /**
-   *
-   * @see TripalFieldFormatter::settingsForm()
-   */
-  public function settingsForm($view_mode, $form, &$form_state) {
-
-  }
-
   /**
   /**
    *
    *
    * @see TripalFieldFormatter::view()
    * @see TripalFieldFormatter::view()
    */
    */
   public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
   public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
-    foreach ($items as $delta => $item) {
-      $element[$delta] = array(
-        '#type' => 'markup',
-        '#markup' => $item['value'],
-      );
+    $content = '';
+    if (count($items) > 0) {
+      $content = $items[0]['value'];
     }
     }
+
+    $element[0] = array(
+      '#type' => 'markup',
+      '#markup' => $content,
+    );
   }
   }
 }
 }

+ 83 - 1
tripal_chado/includes/TripalFields/schema__additional_type/schema__additional_type_widget.inc

@@ -14,13 +14,95 @@ class schema__additional_type_widget extends ChadoFieldWidget {
   public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
   public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
 
 
+    $settings = $this->field['settings'];
+    $field_name = $this->field['field_name'];
+    $field_type = $this->field['type'];
+    $field_table = $this->instance['settings']['chado_table'];
+    $field_column = $this->instance['settings']['chado_column'];
+    $vocabulary = $this->instance['settings']['vocabulary'];
+    $parent_term = $this->instance['settings']['parent_term'];
+
+    $record_id = $element['#entity']->chado_record_id;
+    $value = '';
+    $type_id = '';
+
+    if (count($items) > 0) {
+      $type_id = $items[0]['chado-' . $field_table . '__type_id'];
+      $value = $items[0]['value'];
+    }
+
+    if (array_key_exists('values', $form_state) and array_key_exists($field_name, $form_state['values'])) {
+      $type_id = $form_state['values'][$field_name][$langcode][$delta]['value'];
+    }
+
+    $widget['value'] = array(
+      '#type' => 'value',
+      '#value' => $value,
+    );
+
+    If ($field_table == 'pub' && empty($vocabulary)){
+      $vocabulary = 'tripal_pub';
+    };
+    // If a parent_term is provided then use that to get the options
+    $options = array();
+    $options[] = 'Select a type';
+    if ($parent_term) {
+      list ($vocabulary, $accession) = explode(':', $parent_term);
+      if ($vocabulary and $accession) {
+        $sql = "
+          SELECT
+            CVTS.cvterm_id, CVTS.name
+          FROM {cvtermpath} CVTP
+            INNER JOIN {cvterm} CVTS ON CVTP.subject_id = CVTS.cvterm_id
+            INNER JOIN {cvterm} CVTO ON CVTP.object_id = CVTO.cvterm_id
+            INNER JOIN {dbxref} DBXO ON DBXO.dbxref_id = CVTO.dbxref_id
+            INNER JOIN {db} DBO      ON DBO.db_id = DBXO.db_id
+          WHERE
+            DBO.name = :vocabulary AND DBXO.accession = :accession AND
+            NOT CVTS.is_obsolete = 1
+          ORDER BY CVTS.name ASC
+       ";
+        $results = chado_query($sql, array(':vocabulary' => $vocabulary, ':accession' => $accession));
+        while ($term = $results->fetchObject()) {
+          $options[$term->cvterm_id] = $term->name;
+        }
+      }
+    }
+    elseif ($vocabulary) {
+      $cv = tripal_get_cv(array('name' => $vocabulary));
+      $options = tripal_get_cvterm_select_options($cv->cv_id);
+    }
+    $widget['chado-' . $field_table . '__type_id'] = array(
+      '#type' => 'select',
+      '#options' => $options,
+      '#title' => $element['#title'],
+      '#description' => $element['#description'],
+      '#weight' => isset($element['#weight']) ? $element['#weight'] : 0,
+      '#default_value' => $type_id,
+      '#delta' => $delta,
+    );
   }
   }
 
 
   /**
   /**
    *
    *
    * @see TripalFieldWidget::submit()
    * @see TripalFieldWidget::submit()
    */
    */
-  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
+  public function validate($element, $form, &$form_state, $langcode, $delta) {
+    $settings = $this->field['settings'];
+    $field_name = $this->field['field_name'];
+    $field_type = $this->field['type'];
+    $field_table = $this->instance['settings']['chado_table'];
+    $field_column = $this->instance['settings']['chado_column'];
+    $vocabulary = $this->instance['settings']['vocabulary'];
+    $parent_term = $this->instance['settings']['parent_term'];
+
+    $type_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__type_id'];
 
 
+    if (!$type_id) {
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__type_id'] = '__NULL__';
+    }
+    else {
+      $form_state['values'][$field_name]['und'][$delta]['value'] = $type_id;
+    }
   }
   }
 }
 }

+ 36 - 13
tripal_chado/includes/TripalFields/schema__alternate_name/schema__alternate_name.inc

@@ -59,9 +59,6 @@ class schema__alternate_name extends ChadoField {
     // Get the PKey for this table
     // Get the PKey for this table
     $schema = chado_get_schema($field_table);
     $schema = chado_get_schema($field_table);
     $pkey = $schema['primary key'][0];
     $pkey = $schema['primary key'][0];
-
-    // Get the FK that links to the base record.
-    $schema = chado_get_schema($field_table);
     $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
     $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
     $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
     $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
 
 
@@ -106,18 +103,44 @@ class schema__alternate_name extends ChadoField {
    * @see ChadoField::query()
    * @see ChadoField::query()
    */
    */
   public function query($query, $condition) {
   public function query($query, $condition) {
-    $syn_linker = $this->instance['settings']['chado_table'];
-    $base_table = $this->instance['settings']['base_table'];
-    $bschema = chado_get_schema($base_table);
-    $bpkey = $bschema['primary key'][0];
-    $alias = 'syn_linker';
+    $alias = $this->field['field_name'];
     $operator = $condition['operator'];
     $operator = $condition['operator'];
 
 
-    if ($condition['column'] == 'alternatename') {
-      $this->queryJoinOnce($query, $syn_linker, $alias, "base.$bpkey = $alias.$bpkey");
-      $this->queryJoinOnce($query, 'synonym', 'SYN', "SYN.synonym_id = $alias.synonym_id");
-      $query->condition("SYN.name", $condition['value']);
-    }
+    $field_name = $this->field['field_name'];
+    $field_type = $this->field['type'];
+    $field_table = $this->instance['settings']['chado_table'];
+    $field_column = $this->instance['settings']['chado_column'];
+    $base_table = $this->instance['settings']['base_table'];
+
+    $schema = chado_get_schema($field_table);
+    $pkey = $schema['primary key'][0];
+    $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
+    $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
+
+    $this->queryJoinOnce($query, $field_table, $alias, "base.$fkey_rcolumn = $alias.$fkey_lcolumn");
+    $this->queryJoinOnce($query, 'synonym', $alias . '_SYN', $alias . "_SYN.synonym_id = $alias.synonym_id");
+    $query->condition($alias . "_SYN.name", $condition['value']);
   }
   }
 
 
+  /**
+   * @see ChadoField::query()
+   */
+  public function queryOrder($query, $order) {
+    $alias = $this->field['field_name'];
+
+    $field_name = $this->field['field_name'];
+    $field_type = $this->field['type'];
+    $field_table = $this->instance['settings']['chado_table'];
+    $field_column = $this->instance['settings']['chado_column'];
+    $base_table = $this->instance['settings']['base_table'];
+
+    $schema = chado_get_schema($field_table);
+    $pkey = $schema['primary key'][0];
+    $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
+    $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
+
+    $this->queryJoinOnce($query, $field_table, $alias, "base.$fkey_rcolumn = $alias.$fkey_lcolumn", "LEFT OUTER");
+    $this->queryJoinOnce($query, 'synonym', $alias . '_SYN', $alias . "_SYN.synonym_id = $alias.synonym_id", "LEFT OUTER");
+    $query->orderBy($alias . "_SYN.name", $order['direction']);
+  }
 }
 }

+ 3 - 10
tripal_chado/includes/TripalFields/schema__alternate_name/schema__alternate_name_formatter.inc

@@ -7,29 +7,22 @@ class schema__alternate_name_formatter extends ChadoFieldFormatter {
   // The list of field types for which this formatter is appropriate.
   // The list of field types for which this formatter is appropriate.
   public static $field_types = array('schema__alternate_name');
   public static $field_types = array('schema__alternate_name');
 
 
-  /**
-   *
-   * @see TripalFieldFormatter::settingsForm()
-   */
-  public function settingsForm($view_mode, $form, &$form_state) {
-
-  }
-
   /**
   /**
    *
    *
    * @see TripalFieldFormatter::view()
    * @see TripalFieldFormatter::view()
    */
    */
   public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
   public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
     $list_items = array();
     $list_items = array();
+
     foreach ($items as $delta => $item) {
     foreach ($items as $delta => $item) {
       $list_items[] = $item['value'];
       $list_items[] = $item['value'];
     }
     }
     $list = 'There are no synonyms.';
     $list = 'There are no synonyms.';
-    if (count($list_items) > 1) {
+    if (count($list_items) > 0) {
       $list = array(
       $list = array(
         'title' => '',
         'title' => '',
         'items' => $list_items,
         'items' => $list_items,
-        'type' => 'ol',
+        'type' => 'ul',
         'attributes' => array(),
         'attributes' => array(),
       );
       );
       $list = theme_item_list($list);
       $list = theme_item_list($list);

+ 55 - 35
tripal_chado/includes/TripalFields/schema__alternate_name/schema__alternate_name_widget.inc

@@ -13,7 +13,6 @@ class schema__alternate_name_widget extends ChadoFieldWidget {
    */
    */
   public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
   public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
-
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
 
 
     // Get the FK column that links to the base table.
     // Get the FK column that links to the base table.
@@ -26,7 +25,7 @@ class schema__alternate_name_widget extends ChadoFieldWidget {
 
 
     // Get the field defaults.
     // Get the field defaults.
     $record_id = '';
     $record_id = '';
-    $fkey_value = array_key_exists('#entity', $element) and $element['#entity'] ? $element['#entity']->chado_record_id : NULL;
+    $fkey_value = (array_key_exists('#entity', $element) and $element['#entity']) ? $element['#entity']->chado_record_id : NULL;
     $synonym_id = '';
     $synonym_id = '';
     $pub_id = '';
     $pub_id = '';
     $is_current = TRUE;
     $is_current = TRUE;
@@ -47,8 +46,8 @@ class schema__alternate_name_widget extends ChadoFieldWidget {
     }
     }
 
 
     // Check $form_state['values'] to see if an AJAX call set the values.
     // Check $form_state['values'] to see if an AJAX call set the values.
-    if (array_key_exists('values', $form_state) and array_key_exists($delta, $form_state['values'])) {
-      $record_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__' . $pkey];
+    if (array_key_exists('values', $form_state) and
+        array_key_exists($field_name, $form_state['values'])) {
       $synonym_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__synonym_id'];
       $synonym_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__synonym_id'];
       $pub_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__pub_id'];
       $pub_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__pub_id'];
       $is_current = $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__is_current'];
       $is_current = $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__is_current'];
@@ -71,10 +70,9 @@ class schema__alternate_name_widget extends ChadoFieldWidget {
     // size of the name field to the proper size.
     // size of the name field to the proper size.
     $schema = chado_get_schema('synonym');
     $schema = chado_get_schema('synonym');
 
 
-    $widget['#table_name'] = $table_name;
-    $widget['#fkey_field'] = $fkey;
     $widget['#prefix'] =  "<span id='$table_name-$delta'>";
     $widget['#prefix'] =  "<span id='$table_name-$delta'>";
     $widget['#suffix'] =  "</span>";
     $widget['#suffix'] =  "</span>";
+    $widget['#table_name'] = $table_name;
 
 
     $widget['value'] = array(
     $widget['value'] = array(
       '#type' => 'value',
       '#type' => 'value',
@@ -125,12 +123,10 @@ class schema__alternate_name_widget extends ChadoFieldWidget {
       '#required' => $element['#required'],
       '#required' => $element['#required'],
     );
     );
   }
   }
-
   /**
   /**
-   *
-   * @see TripalFieldWidget::submit()
+   * @see TripalFieldWidget::validate()
    */
    */
-  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
+  public function validate($element, $form, &$form_state, $langcode, $delta) {
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
     $field_type = $this->field['type'];
     $field_type = $this->field['type'];
     $table_name = $this->instance['settings']['chado_table'];
     $table_name = $this->instance['settings']['chado_table'];
@@ -142,14 +138,53 @@ class schema__alternate_name_widget extends ChadoFieldWidget {
     $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);
     $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);
     $fkey = $fkeys[0];
     $fkey = $fkeys[0];
 
 
-    $record_id = isset($form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__' . $pkey]) ? $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__' . $pkey] : '';
-    $fkey_value = isset($form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__' . $fkey]) ? $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__' . $fkey] : '';
-    $synonym_id = isset($form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__synonym_id']) ? $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__synonym_id'] : '';
-    $pub_id = isset($form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__pub_id']) ? $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__pub_id'] : '';
-    $is_current = isset($form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__is_current']) ? $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__is_current'] : '';
-    $is_internal = isset($form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__is_internal']) ? $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__is_internal'] : '';
-    $syn_name = isset($form_state['values'][$field_name][$langcode][$delta]['name']) ? $form_state['values'][$field_name][$langcode][$delta]['name'] : '';
-    $syn_type = isset($form_state['values'][$field_name][$langcode][$delta]['type_id']) ? $form_state['values'][$field_name][$langcode][$delta]['type_id'] : '';
+
+    $pub_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__pub_id'];
+    $syn_name = $form_state['values'][$field_name]['und'][$delta]['name'];
+    $syn_type = $form_state['values'][$field_name]['und'][$delta]['type_id'];
+
+    // If the user provided a $syn_name and a $syn_type then we want to set
+    // the foreign key value to be the chado_record_id.
+    if ($syn_name and $syn_type) {
+      // Set the synonym_id and FK value
+      $synonym = chado_generate_var('synonym', array('name' => $syn_name, 'type_id' => $syn_type));
+      if ($synonym) {
+        $form_state['values'][$field_name]['und'][$delta]['value'] = $synonym->name;
+        $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__synonym_id'] = $synonym->synonym_id;
+      }
+      else {
+        $form_state['values'][$field_name]['und'][$delta]['value'] = $syn_name;
+      }
+      // If a publication is not provided then use the null pub.
+      if (!$pub_id) {
+        $pub = chado_generate_var('pub', array('uniquename' => 'null'));
+        $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__pub_id'] = $pub->pub_id;
+      }
+    }
+    // If no snynonym name is provided then we want to delete the record.
+    // To do this we have to set the value to something (here we just use
+    // the arbitrary 'delete_me', and set every other element to empty other
+    // than the pkey element.
+    else {
+      $form_state['values'][$field_name]['und'][$delta]['value'] = 'delete_me';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__' . $fkey] = '';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__synonym_id'] = '';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__is_internal'] = '';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__is_current'] = '';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__pub_id'] = '';
+    }
+  }
+
+  /**
+   *
+   * @see TripalFieldWidget::submit()
+   */
+  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
+    $field_name = $this->field['field_name'];
+    $table_name = $this->instance['settings']['chado_table'];
+
+    $syn_name = $form_state['values'][$field_name]['und'][$delta]['name'];
+    $syn_type = $form_state['values'][$field_name]['und'][$delta]['type_id'];
 
 
     // If the user provided a $syn_name and a $syn_type then we want to set
     // If the user provided a $syn_name and a $syn_type then we want to set
     // the foreign key value to be the chado_record_id.
     // the foreign key value to be the chado_record_id.
@@ -165,23 +200,9 @@ class schema__alternate_name_widget extends ChadoFieldWidget {
           'synonym_sgml' => '',
           'synonym_sgml' => '',
         ));
         ));
         $synonym = (object) $synonym;
         $synonym = (object) $synonym;
+        $form_state['values'][$field_name]['und'][$delta]['value'] = $synonym->name;
+        $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__synonym_id'] = $synonym->synonym_id;
       }
       }
-
-      // Set the synonym_id and FK value
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__synonym_id'] = $synonym->synonym_id;
-
-      if (!$pub_id) {
-        $pub = chado_generate_var('pub', array('uniquename' => 'null'));
-        $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__pub_id'] = $pub->pub_id;
-      }
-    }
-    else {
-      // If the $syn_name is not set, then remove the linker FK value to the base table.
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__' . $fkey] = '';
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__synonym_id'] = '';
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__is_internal'] = '';
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__is_current'] = '';
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__pub_id'] = '';
     }
     }
   }
   }
 
 
@@ -193,7 +214,6 @@ class schema__alternate_name_widget extends ChadoFieldWidget {
     // These two fields were added to the widget to help identify the fields
     // These two fields were added to the widget to help identify the fields
     // for layout.
     // for layout.
     $table_name = $element['#table_name'];
     $table_name = $element['#table_name'];
-    $fkey = $element['#fkey_field'];
 
 
     $layout = "
     $layout = "
       <div class=\"synonym-widget\">
       <div class=\"synonym-widget\">

+ 0 - 43
tripal_chado/includes/TripalFields/schema__publication/schema__publication.inc

@@ -94,7 +94,6 @@ class schema__publication extends ChadoField {
       'chado-' . $field_table . '__' . $pkey => '',
       'chado-' . $field_table . '__' . $pkey => '',
       'chado-' . $field_table . '__' . $fkey_lcolumn => '',
       'chado-' . $field_table . '__' . $fkey_lcolumn => '',
       'chado-' . $field_table . '__' . 'pub_id' => '',
       'chado-' . $field_table . '__' . 'pub_id' => '',
-      'uniquename' => '',
     );
     );
 
 
     $linker_table = $base_table . '_pub';
     $linker_table = $base_table . '_pub';
@@ -112,7 +111,6 @@ class schema__publication extends ChadoField {
         $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__' . $pkey] = $linker->$pkey;
         $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__' . $pkey] = $linker->$pkey;
         $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__' . $fkey_lcolumn] = $linker->$fkey_lcolumn->$fkey_lcolumn;
         $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__' . $fkey_lcolumn] = $linker->$fkey_lcolumn->$fkey_lcolumn;
         $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__' . 'pub_id'] = $pub->pub_id;
         $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__' . 'pub_id'] = $pub->pub_id;
-        $entity->{$field_name}['und'][$i]['uniquename'] =  $pub->uniquename;
 
 
         if (property_exists($pub, 'entity_id')) {
         if (property_exists($pub, 'entity_id')) {
           $entity->{$field_name}['und'][$i]['value']['entity'] = 'TripalEntity:' . $pub->entity_id;
           $entity->{$field_name}['und'][$i]['value']['entity'] = 'TripalEntity:' . $pub->entity_id;
@@ -121,45 +119,4 @@ class schema__publication extends ChadoField {
       }
       }
     }
     }
   }
   }
-
-  /**
-   * @see ChadoField::query()
-   */
-  public function query($query, $condition) {
-    $pub_linker = $this->instance['settings']['chado_table'];
-    $base_table = $this->instance['settings']['base_table'];
-    $bschema = chado_get_schema($base_table);
-    $bpkey = $bschema['primary key'][0];
-    $alias = 'pub_linker';
-    $operator = $condition['operator'];
-
-    if ($condition['column'] == 'publication.database_cross_reference') {
-      list($db_name, $accession) = explode(':', $condition['value']);
-
-      $this->queryJoinOnce($query, $pub_linker, $alias, "base.$bpkey = $alias.$bpkey");
-      $this->queryJoinOnce($query, 'pub_dbxref', 'PDBX', "PDBX.pub_id = $alias.pub_id");
-      $this->queryJoinOnce($query, 'dbxref', 'DBX', "DBX.dbxref_id = PDBX.dbxref_id");
-      $this->queryJoinOnce($query, 'db', 'DB', "DB.db_id = DBX.db_id");
-      $query->condition("DB.name", $db_name);
-      $query->condition("DBX.accession", $accession);
-    }
-
-    if ($condition['column'] == 'publication.title') {
-      $this->queryJoinOnce($query, $pub_linker, $alias, "base.$bpkey = $alias.$bpkey");
-      $this->queryJoinOnce($query, 'pub', 'PUB', "PUB.pub_id = $alias.pub_id");
-      $query->condition('PUB.title', $condition['value'], $operator);
-    }
-
-    if ($condition['column'] == 'publication.citation') {
-
-    }
-
-    if ($condition['column'] == 'publication.authors') {
-
-    }
-    if ($condition['column'] == 'publication.abstract') {
-
-    }
-  }
-
 }
 }

+ 2 - 15
tripal_chado/includes/TripalFields/schema__publication/schema__publication_formatter.inc

@@ -7,14 +7,6 @@ class schema__publication_formatter extends ChadoFieldFormatter {
   // The list of field types for which this formatter is appropriate.
   // The list of field types for which this formatter is appropriate.
   public static $field_types = array('schema__publication');
   public static $field_types = array('schema__publication');
 
 
-  /**
-   *
-   * @see TripalFieldFormatter::settingsForm()
-   */
-  public function settingsForm($view_mode, $form, &$form_state) {
-
-  }
-
   /**
   /**
    *
    *
    * @see TripalFieldFormatter::view()
    * @see TripalFieldFormatter::view()
@@ -25,19 +17,14 @@ class schema__publication_formatter extends ChadoFieldFormatter {
 
 
     foreach ($items as $delta => $item) {
     foreach ($items as $delta => $item) {
 
 
-      if (empty($item['value'])) {
-        continue;
-      }
       $title = isset($item['value']['TPUB:0000039']) ? $item['value']['TPUB:0000039'] : '';
       $title = isset($item['value']['TPUB:0000039']) ? $item['value']['TPUB:0000039'] : '';
       $citation = isset($item['value']['TPUB:0000003']) ? $item['value']['TPUB:0000003'] : '';
       $citation = isset($item['value']['TPUB:0000003']) ? $item['value']['TPUB:0000003'] : '';
       $entity = array_key_exists('entity', $item['value']) ? $item['value']['entity'] : '';
       $entity = array_key_exists('entity', $item['value']) ? $item['value']['entity'] : '';
       if ($entity) {
       if ($entity) {
         list($entity_type, $entity_id) = explode(':', $entity);
         list($entity_type, $entity_id) = explode(':', $entity);
         $new_title = l($title, 'bio_data/' . $entity_id);
         $new_title = l($title, 'bio_data/' . $entity_id);
-        // If a title has parens we need to escape them for the
-        // regular expression to work.
-        $title = preg_replace('/\(/', '\(', $title);
-        $title = preg_replace('/\)/', '\)', $title);
+        // Escape anything that isn't alphanumeric
+        $title = preg_replace('/([^\w])/', '\\\\$1', $title);
         $citation = preg_replace("/$title/", $new_title, $citation);
         $citation = preg_replace("/$title/", $new_title, $citation);
       }
       }
       $list_items[] = $citation;
       $list_items[] = $citation;

+ 37 - 31
tripal_chado/includes/TripalFields/schema__publication/schema__publication_widget.inc

@@ -25,15 +25,28 @@ class schema__publication_widget extends ChadoFieldWidget {
     $fkey = $fkeys[0];
     $fkey = $fkeys[0];
 
 
     // Get the field defaults.
     // Get the field defaults.
-    $fkey_value = (array_key_exists('#entity', $element) and is_object($element['#entity'])) ? $element['#entity']->chado_record_id : NULL;
+    $pkey_val = '';
+    $fkey_value = '';
     $pub_id = '';
     $pub_id = '';
-    $uname = '';
+    $title = '';
 
 
     // If the field already has a value then it will come through the $items
     // If the field already has a value then it will come through the $items
     // array.  This happens when editing an existing record.
     // array.  This happens when editing an existing record.
     if (count($items) > 0 and array_key_exists($delta, $items)) {
     if (count($items) > 0 and array_key_exists($delta, $items)) {
+      $pkey_val =  tripal_get_field_item_keyval($items, $delta, 'chado-' . $table_name . '__' . $pkey, $pkey_val);
+      $fkey_value = tripal_get_field_item_keyval($items, $delta, 'chado-' . $table_name . '__' . $fkey, $fkey_value);
       $pub_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $table_name . '__pub_id', $pub_id);
       $pub_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $table_name . '__pub_id', $pub_id);
-      $uname = tripal_get_field_item_keyval($items, $delta, 'uniquename', $uname);
+      if ($pub_id) {
+        $pub = tripal_get_publication(array('pub_id' => $pub_id));
+        $title =  $pub->title . ' [id:' . $pub->pub_id . ']';
+      }
+    }
+
+    // Check $form_state['values'] to see if an AJAX call set the values.
+    if (array_key_exists('values', $form_state) and
+        array_key_exists($field_name, $form_state['values'])) {
+      $title = $form_state['values'][$field_name]['und'][$delta]['pub_title'];
+      $pub_id = $form_state['values'][$field_name]['und'][$delta]['accession'];
     }
     }
 
 
     $schema = chado_get_schema('pub');
     $schema = chado_get_schema('pub');
@@ -50,7 +63,7 @@ class schema__publication_widget extends ChadoFieldWidget {
 
 
     $widget['chado-' . $table_name . '__' . $pkey] = array(
     $widget['chado-' . $table_name . '__' . $pkey] = array(
       '#type' => 'value',
       '#type' => 'value',
-      '#default_value' => '',
+      '#default_value' => $pkey_val,
     );
     );
     $widget['chado-' . $table_name . '__' . $fkey] = array(
     $widget['chado-' . $table_name . '__' . $fkey] = array(
       '#type' => 'value',
       '#type' => 'value',
@@ -61,17 +74,11 @@ class schema__publication_widget extends ChadoFieldWidget {
       '#default_value' => $pub_id,
       '#default_value' => $pub_id,
     );
     );
 
 
-    $widget['uniquename'] = array(
+    $widget['pub_title'] = array(
       '#type' => 'textfield',
       '#type' => 'textfield',
       '#title' => t('Publication'),
       '#title' => t('Publication'),
-      '#default_value' => $uname,
+      '#default_value' => $title,
       '#autocomplete_path' => 'admin/tripal/storage/chado/auto_name/pub',
       '#autocomplete_path' => 'admin/tripal/storage/chado/auto_name/pub',
-      '#ajax' => array(
-        'callback' => "schema__publication_widget_form_ajax_callback",
-        'wrapper' => "$table_name-$delta",
-        'effect' => 'fade',
-        'method' => 'replace'
-      ),
       '#maxlength' => 100000,
       '#maxlength' => 100000,
     );
     );
   }
   }
@@ -81,7 +88,7 @@ class schema__publication_widget extends ChadoFieldWidget {
    *
    *
    * @see TripalFieldWidget::submit()
    * @see TripalFieldWidget::submit()
    */
    */
-  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
+  public function validate($element, $form, &$form_state, $langcode, $delta) {
     // Get the FK column that links to the base table.
     // Get the FK column that links to the base table.
     $table_name = $this->instance['settings']['chado_table'];
     $table_name = $this->instance['settings']['chado_table'];
     $base_table = $this->instance['settings']['base_table'];
     $base_table = $this->instance['settings']['base_table'];
@@ -92,31 +99,30 @@ class schema__publication_widget extends ChadoFieldWidget {
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
 
 
     // Get the field values.
     // Get the field values.
-    $fkey_value = isset($form_state['values'][$field_name][$langcode][$delta]['value']) ? $form_state['values'][$field_name][$langcode][$delta]['value'] : '';
-    $pub_id = isset($form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__pub_id']) ? $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__pub_id'] : '';
-    $uname = isset($form_state['values'][$field_name][$langcode][$delta]['uniquename']) ? $form_state['values'][$field_name][$langcode][$delta]['uniquename'] : '';
+    $fkey_value = $form_state['values'][$field_name]['und'][$delta]['value'];
+    $pub_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__pub_id'];
+    $title = $form_state['values'][$field_name]['und'][$delta]['pub_title'];
 
 
-    // If the user provided a uniquename then we want to set the foreign key
+    // If the user provided a pub_title then we want to set the foreign key
     // value to be the chado_record_id
     // value to be the chado_record_id
-    if ($uname and !$pub_id) {
-      $pub = chado_generate_var('pub', array('uniquename' => $uname));
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__pub_id'] = $pub->pub_id;
+    if ($title) {
+      $matches = array();
+      if (preg_match('/^.*\[id:(\d+)]$/', $title, $matches)) {
+        $pub_id = $matches[1];
+        $pub = chado_generate_var('pub', array('pub_id' => $pub_id));
+        $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__pub_id'] = $pub->pub_id;
+        $form_state['values'][$field_name]['und'][$delta]['value'] = $pub->pub_id;
+      }
     }
     }
 
 
     // In the widgetFrom function we automatically add the foreign key
     // In the widgetFrom function we automatically add the foreign key
     // record.  But if the user did not provide a publication we want to take
     // record.  But if the user did not provide a publication we want to take
     // it out so that the Chado field_storage infrastructure won't try to
     // it out so that the Chado field_storage infrastructure won't try to
     // write a record.
     // write a record.
-    if (!$uname and !$pub_id) {
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__' . $fkey] = '';
-    }
-
-    // If the user removed the publication from the pub_uniquename field
-    // then we want to clear out the rest of the hidden values.
-    // Leave the primary key so the record can be deleted.
-    if (!$uname and $pub_id) {
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__' . $fkey] = '';
-      $form_state['values'][$field_name][$langcode][$delta]['chado-' . $table_name . '__pub_id'] = '';
+    if (!$title) {
+      $form_state['values'][$field_name]['und'][$delta]['value'] = 'delete_me';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__' . $fkey] = '';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $table_name . '__pub_id'] = '';
     }
     }
   }
   }
 
 
@@ -128,7 +134,7 @@ class schema__publication_widget extends ChadoFieldWidget {
     $layout = "
     $layout = "
       <div class=\"pub-widget\">
       <div class=\"pub-widget\">
         <div class=\"pub-widget-item\">" .
         <div class=\"pub-widget-item\">" .
-          drupal_render($element['uniquename']) . "
+          drupal_render($element['pub_title']) . "
         </div>
         </div>
       </div>
       </div>
     ";
     ";

+ 346 - 0
tripal_chado/includes/TripalFields/sio__annotation/sio__annotation.inc

@@ -0,0 +1,346 @@
+<?php
+
+class sio__annotation extends ChadoField {
+
+
+  // --------------------------------------------------------------------------
+  //                     EDITABLE STATIC CONSTANTS
+  //
+  // The following constants SHOULD be set for each descendent class.  They are
+  // used by the static functions to provide information to Drupal about
+  // the field and it's default widget and formatter.
+  // --------------------------------------------------------------------------
+
+  // The default lable for this field.
+  public static $default_label = 'Annotations';
+
+  // The default description for this field.
+  public static $description = 'This record is annotated with controlled vocabulary terms.';
+
+  // Provide a list of instance specific settings. These can be access within
+  // the instanceSettingsForm.  When the instanceSettingsForm is submitted
+  // then Drupal with automatically change these settings for the instnace.
+  // It is recommended to put settings at the instance level whenever possible.
+  // If you override this variable in a child class be sure to replicate the
+  // term_name, term_vocab, term_accession and term_fixed keys as these are
+  // required for all TripalFields.
+  public static $default_instance_settings  = array(
+    // The short name for the vocabulary (e.g. shcema, SO, GO, PATO, etc.).
+    'term_vocabulary' => 'SIO',
+    // The name of the term.
+    'term_name' => 'annotation',
+    // The unique ID (i.e. accession) of the term.
+    'term_accession' => '001166',
+    // Set to TRUE if the site admin is allowed to change the term
+    // type. This will create form elements when editing the field instance
+    // to allow the site admin to change the term settings above.
+    'term_fixed' => FALSE,
+  );
+
+  // The default widget for this field.
+  public static $default_widget = 'chado_linker__cvterm_widget';
+
+  // The default formatter for this field.
+  public static $default_formatter = 'chado_linker__cvterm_formatter';
+
+  // A boolean specifying that users should not be allowed to create
+  // fields and instances of this field type through the UI. Such
+  // fields can only be created programmatically with field_create_field()
+  // and field_create_instance().
+  public static $no_ui = FALSE;
+
+
+  public function validate($entity_type, $entity, $langcode, $items, &$errors) {
+
+    $field_name = $this->field['field_name'];
+
+    foreach ($items as $delta => $item) {
+      // Get the term that matches.
+      $cvterm_name = $item['cvterm_name'];
+      $cv_id = $item['cv_id'];
+      if($cvterm_name and $cv_id) {
+        $cvterm = chado_generate_var('cvterm', array(
+          'cv_id' => $cv_id,
+          'name' => $cvterm_name,
+        ));
+        if (!$cvterm) {
+          $errors[$field_name][$langcode][$delta][] = array(
+            'message' =>  t("Cannot find a term that matches the term name and vocabulary."),
+            'error' => 'cvterm_name'
+          );
+        }
+      }
+    }
+  }
+
+  /**
+   * @see TripalField::elementInfo()
+   */
+  public function elementInfo() {
+    $field_table = $this->instance['settings']['chado_table'];
+    $schema = chado_get_schema($field_table);
+
+    $vocabulary_term = tripal_get_chado_semweb_term('cvterm', 'cv_id');
+    $accession_term = tripal_get_chado_semweb_term('dbxref', 'accession');
+    $definition_term = tripal_get_chado_semweb_term('cvterm', 'definition');
+
+    $field_term = $this->getFieldTermID();
+    $info = array(
+      $field_term => array(
+        'operations' => array(),
+        'sortable' => FALSE,
+        'searchable' => FALSE,
+        'type' => 'array',
+        'elements' => array(
+          $vocabulary_term => array(
+            'sortable' => TRUE,
+            'searchable' => TRUE,
+            'label' => 'Annotation Term Vocabulary',
+          ),
+          $accession_term => array(
+            'sortable' => TRUE,
+            'searchable' => TRUE,
+            'label' => 'Annotation Term Accession',
+          ),
+          $definition_term => array(
+            'sortable' => TRUE,
+            'searchable' => TRUE,
+            'label' => 'Annotation Term Description',
+          ),
+        ),
+      ),
+    );
+
+    if (array_key_exists('is_not', $schema['fields'])) {
+      $negation_term = tripal_get_chado_semweb_term($field_table, 'is_not');
+      $info[$field_term]['elements'][$negation_term] = array(
+        'sortable' => FALSE,
+        'searchable' => FALSE,
+        'label' => 'Annotation Term Negates',
+      );
+    }
+    if (array_key_exists('rank', $schema['fields'])) {
+      $rank_term = tripal_get_chado_semweb_term($field_table, 'rank');
+      $info[$field_term]['elements'][$rank_term] = array(
+        'sortable' => FALSE,
+        'searchable' => FALSE,
+        'label' => 'Annotation Term Rank',
+        'type' => 'numeric'
+      );
+    }
+    if (array_key_exists('pub_id', $schema['fields'])) {
+    }
+    return $info;
+  }
+
+  /**
+   * @see ChadoField::query()
+   */
+  public function query($query, $condition) {
+    $alias = $this->field['field_name'];
+    $operator = $condition['operator'];
+
+    $field_table = $this->instance['settings']['chado_table'];
+    $base_table = $this->instance['settings']['base_table'];
+
+    $schema = chado_get_schema($field_table);
+    $pkey = $schema['primary key'][0];
+    $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
+    $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
+
+    $field_term_id = $this->getFieldTermID();
+
+    $vocabulary_term = $field_term_id . ',' . tripal_get_chado_semweb_term('cvterm', 'cv_id');
+    $accession_term = $field_term_id . ',' . tripal_get_chado_semweb_term('dbxref', 'accession');
+    $definition_term = $field_term_id . ',' . tripal_get_chado_semweb_term('cvterm', 'definition');
+
+
+    // Join to the xxx_cvterm table for this field.
+    $this->queryJoinOnce($query, $field_table, $alias, "base.$fkey_rcolumn = $alias.$fkey_lcolumn");
+
+    if ($condition['column'] == $vocabulary_term) {
+      $this->queryJoinOnce($query, 'cvterm', $alias . '_cvterm', $alias . ".cvterm_id = " . $alias . "_cvterm.cvterm_id");
+      $this->queryJoinOnce($query, 'dbxref', $alias . '_dbxref', $alias . "_cvterm.dbxref_id = " . $alias . "_dbxref.dbxref_id");
+      $this->queryJoinOnce($query, 'db', $alias . '_db', $alias . "_db.db_id = " . $alias . "_dbxref.db_id");
+      $query->condition($alias . '_db.name', $condition['value'], $operator);
+    }
+    if ($condition['column'] == $accession_term) {
+      $this->queryJoinOnce($query, 'cvterm', $alias . '_cvterm', $alias . ".cvterm_id = " . $alias . "_cvterm.cvterm_id");
+      $this->queryJoinOnce($query, 'dbxref', $alias . '_dbxref', $alias . "_cvterm.dbxref_id = " . $alias . "_dbxref.dbxref_id");
+      $query->condition($alias . '_dbxref.accession', $condition['value'], $operator);
+    }
+    if ($condition['column'] == $definition_term) {
+      $this->queryJoinOnce($query, 'cvterm', $alias . '_cvterm', $alias . ".cvterm_id = " . $alias . "_cvterm.cvterm_id");
+      $query->condition($alias . '_cvterm.definition', $condition['value'], $operator);
+    }
+  }
+
+  /**
+   * @see ChadoField::queryOrder()
+   */
+  public function queryOrder($query, $order) {
+    $alias = $this->field['field_name'];
+
+    $field_table = $this->instance['settings']['chado_table'];
+    $base_table = $this->instance['settings']['base_table'];
+
+    $schema = chado_get_schema($field_table);
+    $pkey = $schema['primary key'][0];
+    $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
+    $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
+
+    $field_term_id = $this->getFieldTermID();
+
+    $vocabulary_term = $field_term_id . ',' . tripal_get_chado_semweb_term('cvterm', 'cv_id');
+    $accession_term = $field_term_id . ',' . tripal_get_chado_semweb_term('dbxref', 'accession');
+    $definition_term = $field_term_id . ',' . tripal_get_chado_semweb_term('cvterm', 'definition');
+
+    // Join to the xxx_cvterm table for this field.
+    $this->queryJoinOnce($query, $field_table, $alias, "base.$fkey_rcolumn = $alias.$fkey_lcolumn");
+
+    if ($order['column'] == $vocabulary_term) {
+      $this->queryJoinOnce($query, 'cvterm', $alias . '_cvterm', $alias . ".cvterm_id = " . $alias . "_cvterm.cvterm_id", "LEFT OUTER");
+      $this->queryJoinOnce($query, 'dbxref', $alias . '_dbxref', $alias . "_cvterm.dbxref_id = " . $alias . "_dbxref.dbxref_id", "LEFT OUTER");
+      $this->queryJoinOnce($query, 'db', $alias . '_db', $alias . "_db.db_id = " . $alias . "_dbxref.db_id", "LEFT OUTER");
+      $query->orderBy($alias . "_db.name", $order['direction']);
+    }
+    if ($order['column'] == $accession_term) {
+      $this->queryJoinOnce($query, 'cvterm', $alias . '_cvterm', $alias . ".cvterm_id = " . $alias . "_cvterm.cvterm_id", "LEFT OUTER");
+      $this->queryJoinOnce($query, 'dbxref', $alias . '_dbxref', $alias . "_cvterm.dbxref_id = " . $alias . "_dbxref.dbxref_id", "LEFT OUTER");
+      $query->orderBy($alias . "_dbxref.accession", $order['direction']);
+    }
+    if ($order['column'] == $definition_term) {
+      $this->queryJoinOnce($query, 'cvterm', $alias . '_cvterm', $alias . ".cvterm_id = " . $alias . "_cvterm.cvterm_id");
+      $query->orderBy($alias . "_cvterm.definition", $order['direction']);
+    }
+  }
+  /**
+   *
+   * @see TripalField::load()
+   */
+  public function load($entity) {
+    $field_name = $this->field['field_name'];
+    $field_type = $this->field['type'];
+    $field_table = $this->instance['settings']['chado_table'];
+    $field_column = $this->instance['settings']['chado_column'];
+    $base_table = $this->instance['settings']['base_table'];
+
+    // Get the FK that links to the base record.
+    $schema = chado_get_schema($field_table);
+    $pkey = $schema['primary key'][0];
+    $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
+    $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
+
+    $vocabulary = tripal_get_chado_semweb_term('cvterm', 'cv_id');
+    $accession = tripal_get_chado_semweb_term('dbxref', 'accession');
+    $definition = tripal_get_chado_semweb_term('cvterm', 'definition');
+    if (array_key_exists('is_not', $schema['fields'])) {
+      $negation = tripal_get_chado_semweb_term($field_table, 'is_not');
+    }
+    if (array_key_exists('rank', $schema['fields'])) {
+      $rank_term = tripal_get_chado_semweb_term($field_table, 'rank');
+    }
+
+    // Set some defaults for the empty record.
+    $chado_record = $entity->chado_record;
+    $entity->{$field_name}['und'][0] = array(
+      'value' => '',
+      'chado-' . $field_table . '__' . $pkey => '',
+      'chado-' . $field_table . '__' . $fkey_lcolumn => $chado_record->$fkey_rcolumn,
+      'chado-' . $field_table . '__cvterm_id' => '',
+    );
+    if (array_key_exists('is_not', $schema['fields'])) {
+      $entity->{$field_name}['und'][0]['chado-' . $field_table . '__is_not'] = '';
+    }
+    if (array_key_exists('rank', $schema['fields'])) {
+      $entity->{$field_name}['und'][0]['chado-' . $field_table . '__rank'] = '';
+    }
+    if (array_key_exists('pub_id', $schema['fields'])) {
+      $entity->{$field_name}['und'][0]['chado-' . $field_table . '__pub_id'] = '';
+    }
+
+    // Get the annotations associated with this base record for this fields type.
+    $columns = array('*');
+    $match = array(
+      $fkey_lcolumn => $chado_record->$fkey_rcolumn,
+    );
+    $order_by = array($pkey => 'ASC');
+    if (array_key_exists('rank', $schema['fields'])) {
+      $order_by = array('rank' => 'ASC');
+    }
+    $options = array(
+      'return_array' => TRUE,
+      'order_by' => $order_by
+    );
+    $fcvterms = chado_select_record($field_table, $columns, $match, $options);
+    for ($i = 0; $i < count($fcvterms); $i++) {
+      $linker = $fcvterms[$i];
+      $cvterm = chado_generate_var('cvterm', array('cvterm_id' => $linker->cvterm_id));
+      $entity->{$field_name}['und'][$i] = array(
+        'value' => array(
+          $vocabulary => $cvterm->dbxref_id->db_id->name,
+          $accession => $cvterm->dbxref_id->accession,
+          $definition => $cvterm->definition
+        ),
+        'chado-' . $field_table . '__' . $pkey => $linker->$pkey,
+        'chado-' . $field_table . '__' . $fkey_lcolumn => $linker->$fkey_lcolumn,
+        'chado-' . $field_table . '__' . 'cvterm_id' => $linker->cvterm_id,
+      );
+      if (array_key_exists('is_not', $schema['fields'])) {
+        $entity->{$field_name}['und'][$i]['value'][$negation] = $linker->is_not;
+        $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__is_not'] = $linker->is_not;
+      }
+      if (array_key_exists('rank', $schema['fields'])) {
+        $entity->{$field_name}['und'][$i]['value'][$rank_term] = $linker->rank;
+        $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__rank'] = $linker->rank;
+      }
+      if (array_key_exists('pub_id', $schema['fields'])) {
+        $entity->{$field_name}['und'][$i]['chado-' . $field_table . '__pub_id'] = $linker->pub_id;
+      }
+    }
+  }
+}
+
+/**
+ * Theme function for the dbxref_id_widget.
+ *
+ * @param $variables
+ */
+function theme_chado_linker__cvterm_widget($variables) {
+  $element = $variables['element'];
+
+  // These two fields were added to the widget to help identify the fields
+  // for layout.
+  $table_name = $element['#table_name'];
+  $fkey = $element['#fkey_field'];
+
+  $layout = "
+    <div class=\"annotation-cvterm-widget\">
+      <div class=\"annotation-cvterm-widget-item\">" .
+      drupal_render($element['cv__cv_id']) . "
+      </div>
+      <div class=\"annotation-cvterm-widget-item\">" .
+      drupal_render($element['cvterm__name']) . "
+      </div>
+      <div class=\"annotation-cvterm-widget-item\">" .
+      drupal_render($element['pub']) . "
+      </div>
+      <div class=\"annotation-cvterm-widget-item\">" .
+      drupal_render($element['chado-' . $table_name . '__is_not']) . "
+      </div>
+    </div>
+  ";
+  return $layout;
+}
+
+/**
+ * An Ajax callback for the dbxref widget.
+ */
+function chado_linker__cvterm_widget_form_ajax_callback($form, $form_state) {
+
+  $field_name = $form_state['triggering_element']['#parents'][0];
+  $delta = $form_state['triggering_element']['#parents'][2];
+
+
+  return $form[$field_name]['und'][$delta];
+}

+ 78 - 0
tripal_chado/includes/TripalFields/sio__annotation/sio__annotation_formatter.inc

@@ -0,0 +1,78 @@
+<?php
+
+class sio__annotation_formatter extends ChadoFieldFormatter {
+  // The default lable for this field.
+  public static $default_label = 'Chado Annotation';
+
+  // The list of field types for which this formatter is appropriate.
+  public static $field_types = array('chado_linker__cvterm');
+
+  /**
+   *
+   * @see TripalFieldFormatter::view()
+   */
+  public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
+    $headers = array('Term', 'Definition');
+    $rows = array();
+
+    $field_table = $this->instance['settings']['chado_table'];
+    $schema = chado_get_schema($field_table);
+
+    $vocabulary_term = tripal_get_chado_semweb_term('cvterm', 'cv_id');
+    $accession_term = tripal_get_chado_semweb_term('dbxref', 'accession');
+    $definition_term = tripal_get_chado_semweb_term('cvterm', 'definition');
+    if (array_key_exists('is_not', $schema['fields'])) {
+      $negation_term = tripal_get_chado_semweb_term($field_table, 'is_not');
+    }
+
+    $chado_table = $this->instance['settings']['chado_table'];
+    foreach ($items as $delta => $item) {
+
+      if ($item['chado-' . $chado_table . '__cvterm_id']) {
+        $cvterm = chado_generate_var('cvterm', array('cvterm_id' => $item['chado-' . $chado_table . '__cvterm_id']));
+        $dbxref = $cvterm->dbxref_id;
+
+        // Build the accession.
+        $accession = $dbxref->db_id->name . ':' . $dbxref->accession;
+        if ($dbxref->db_id->urlprefix) {
+          $accession = l($accession, tripal_get_dbxref_url($dbxref), array('attributes' => array('target' => '_blank')));
+        }
+
+        $row = array(
+          $item['value'][$vocabulary_term] . ':' . $item['value'][$accession_term],
+          $item['value'][$definition_term],
+        );
+
+        if (array_key_exists('is_not', $schema['fields'])) {
+          if ($negation_term == FALSE) {
+            $row[1] = 'NOT ' . $row[1];
+          }
+        }
+
+        $rows[] = $row;
+      }
+    }
+
+    // Theme the results in a talbe.
+    $caption = 'This record is associated with the following annotations.';
+    $table = array(
+      'header' => $headers,
+      'rows' => $rows,
+      'attributes' => array(
+        'id' => "$chado_table-table-terms",
+        'class' => 'tripal-data-table'
+      ),
+      'caption' => $caption,
+      'sticky' => FALSE,
+      'colgroups' => array(),
+      'empty' => 'There are no annotations of this type',
+    );
+
+    if (count($items) > 0) {
+      $element[0] = array(
+        '#type' => 'markup',
+        '#markup' => theme_table($table),
+      );
+    }
+  }
+}

+ 293 - 0
tripal_chado/includes/TripalFields/sio__annotation/sio__annotation_widget.inc

@@ -0,0 +1,293 @@
+<?php
+
+class sio__annotation_widget extends ChadoFieldWidget {
+  // The default lable for this field.
+  public static $default_label = 'Chado Annotation';
+
+  // The list of field types for which this formatter is appropriate.
+  public static $field_types = array('chado_linker__cvterm');
+
+
+  /**
+   *
+   * @see TripalFieldWidget::form()
+   */
+  public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
+    parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
+
+    $field_name = $this->field['field_name'];
+    $field_type = $this->field['type'];
+    $field_table = $this->instance['settings']['chado_table'];
+    $field_column = $this->instance['settings']['chado_column'];
+    $base_table = $this->instance['settings']['base_table'];
+
+    // Get the FK that links to the base record.
+    $schema = chado_get_schema($field_table);
+    $pkey = $schema['primary key'][0];
+    $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
+    $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
+
+    $vocabulary = tripal_get_chado_semweb_term('cvterm', 'cv_id');
+    $accession = tripal_get_chado_semweb_term('dbxref', 'accession');
+    $definition = tripal_get_chado_semweb_term('cvterm', 'definition');
+    if (array_key_exists('is_not', $schema['fields'])) {
+      $negation = tripal_get_chado_semweb_term($field_table, 'is_not');
+    }
+
+    // Get the field defaults.
+    $record_id = '';
+    $fk_value = '';
+    $cvterm_id = '';
+    $pub_id = '';
+    $is_not = FALSE;
+    $cvterm_name = '';
+    $cv_id = '';
+    $cvterm = NULL;
+    $pub_name = '';
+
+    // If the field already has a value then it will come through the $items
+    // array.  This happens when editing an existing record.
+    if (array_key_exists($delta, $items)) {
+      // Check for element values that correspond to fields in the Chado table.
+      $record_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__' . $pkey, $record_id);
+      $fk_value = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__' . $fkey_lcolumn, $fk_value);
+      $cvterm_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__cvterm_id', $cvterm_id);
+
+      if (array_key_exists('pub_id', $schema['fields'])) {
+        $pub_name = tripal_get_field_item_keyval($items, $delta, 'pub', $pub_name);
+        $pub_id = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__pub_id', $pub_id);
+      }
+      if (array_key_exists('is_not', $schema['fields'])) {
+        $is_not = tripal_get_field_item_keyval($items, $delta, 'chado-' . $field_table . '__is_not', $is_not);
+      }
+
+      if ($cvterm_id) {
+        $cvterm = chado_generate_var('cvterm', array('cvterm_id' => $cvterm_id));
+        $cv_id = $cvterm->cv_id->cv_id;
+        $cvterm_name = $cvterm->name;
+      }
+    }
+
+    // Check $form_state['values'] to see if an AJAX call set the values.
+    if (array_key_exists('values', $form_state) and
+        array_key_exists($field_name, $form_state['values'])) {
+
+      $record_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $pkey];
+      $fk_value = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $fkey_lcolumn];
+      $cvterm_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__cvterm_id'];
+
+      if (array_key_exists('pub_id', $schema['fields'])) {
+        $pub_name = $form_state['values'][$field_name]['und'][$delta]['pub'];
+        $pub_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__pub_id'];
+      }
+      if (array_key_exists('is_not', $schema['fields'])) {
+        $is_not = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__is_not'];
+      }
+      $cvterm_name = $form_state['values'][$field_name]['und'][$delta]['cvterm_name'];
+      $cv_id = $form_state['values'][$field_name]['und'][$delta]['cv_id'];
+      $cvterm = chado_generate_var('cvterm', array(
+        'cv_id' => $cv_id,
+        'name' => $cvterm_name,
+      ));
+      if (!$cvterm) {
+        $cvterm_name = '';
+      }
+    }
+
+    $widget['#prefix'] =  "<span id='$field_name-sio--annotation-$delta'>";
+    $widget['#suffix'] =  "</span>";
+
+    // The value field isn't really used but it's needed because if
+    // it doesn't have a value the element won't be considered for
+    // insert/update.
+    $widget['value'] = array(
+      '#type' => 'value',
+      '#value' => $cvterm_id,
+    );
+
+    $widget['chado-' . $field_table . '__' . $pkey] = array(
+      '#type' => 'value',
+      '#default_value' => $record_id,
+    );
+    $widget['chado-' . $field_table . '__cvterm_id'] = array(
+      '#type' => 'value',
+      '#default_value' => $cvterm_id,
+    );
+    $widget['chado-' . $field_table . '__' . $fkey_lcolumn] = array(
+      '#type' => 'value',
+      '#default_value' => $fk_value,
+    );
+
+    $cvs = tripal_get_cv_select_options();
+    $widget['cv_id'] = array(
+      '#type' => 'select',
+      '#title' => t('Vocabulary'),
+      '#options' => $cvs,
+      '#default_value' => $cv_id,
+      '#required' => $element['#required'],
+      '#attributes' => array('style' => 'width: 200px;'),
+      '#ajax' => array(
+        'callback' => "sio__annotation_widget_form_ajax_callback",
+        'wrapper' => "$field_name-sio--annotation-$delta",
+        'effect' => 'fade',
+        'method' => 'replace'
+      ),
+    );
+    $cv_schema = chado_get_schema('cvterm');
+    $widget['cvterm_name'] = array(
+      '#type' => 'textfield',
+      '#title' => t('Term Name'),
+      '#default_value' => $cvterm_name,
+      '#maxlength' => array_key_exists('length', $cv_schema['fields']['name']) ? $cv_schema['fields']['name']['length'] : 255,
+      '#autocomplete_path' => 'admin/tripal/storage/chado/auto_name/cvterm/' . $cv_id,
+      '#disabled' => $cv_id ? FALSE : TRUE,
+    );
+
+    if (array_key_exists('pub_id', $schema['fields'])) {
+      $widget['pub'] = array(
+        '#type' => 'textfield',
+        '#title' => t('Publication'),
+        '#default_value' => $pub_name,
+        '#autocomplete_path' => 'admin/tripal/storage/chado/auto_name/pub',
+        '#maxlength' => 100000,
+        '#disabled' => $cv_id ? FALSE : TRUE,
+      );
+      $widget['chado-' . $field_table . '__pub_id'] = array(
+        '#type' => 'value',
+        '#default_value' => $pub_id ? $pub_id : '',
+      );
+    }
+
+    if (array_key_exists('is_not', $schema['fields'])) {
+      $widget['chado-' . $field_table . '__is_not'] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Negate this term (NOT)'),
+        '#default_value' => $is_not,
+        '#required' => $element['#required'],
+        '#disabled' => $cv_id ? FALSE : TRUE,
+      );
+    }
+    if (array_key_exists('rank', $schema['fields'])) {
+      $widget['chado-' . $field_table . '__rank'] = array(
+        '#type' => 'value',
+        '#default_value' => $delta,
+      );
+    }
+  }
+
+  /**
+   *
+   * @see TripalFieldWidget::submit()
+   */
+  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
+    $field_name = $this->field['field_name'];
+    $field_type = $this->field['type'];
+    $field_table = $this->instance['settings']['chado_table'];
+    $field_column = $this->instance['settings']['chado_column'];
+    $base_table = $this->instance['settings']['base_table'];
+
+    // Get the FK that links to the base record.
+    $schema = chado_get_schema($field_table);
+    $pkey = $schema['primary key'][0];
+    $fkey_lcolumn = key($schema['foreign keys'][$base_table]['columns']);
+    $fkey_rcolumn = $schema['foreign keys'][$base_table]['columns'][$fkey_lcolumn];
+
+    $vocabulary = tripal_get_chado_semweb_term('cvterm', 'cv_id');
+    $accession = tripal_get_chado_semweb_term('dbxref', 'accession');
+    $definition = tripal_get_chado_semweb_term('cvterm', 'definition');
+    if (array_key_exists('is_not', $schema['fields'])) {
+      $negation = tripal_get_chado_semweb_term($field_table, 'is_not');
+    }
+
+    $record_id = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $pkey];
+    $fk_value = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $fkey_lcolumn];
+
+    // If a publication ID was provided then make sure the form_state
+    // value for the pub_id is set correctly.
+    if (array_key_exists('pub_id', $schema['fields'])) {
+      $pub_name = $form_state['values'][$field_name]['und'][$delta]['pub'];
+      if ($pub_name) {
+        $pub = chado_generate_var('pub', array('uniquename' => $pub_name));
+        if ($pub) {
+          $form_state['values'][$field_name][$langcode][$delta]['chado-' . $field_table . '__pub_id'] = $pub->pub_id;
+        }
+      }
+      // Use the NULL pub.
+      else {
+        $pub = tripal_get_publication(array('uniquename' => 'null'));
+        $form_state['values'][$field_name][$langcode][$delta]['chado-' . $field_table . '__pub_id'] = $pub->pub_id;
+      }
+    }
+
+    // Make sure the rank is set.
+    if (array_key_exists('rank', $schema['fields'])) {
+      $rank = $form_state['values'][$field_name]['und'][$delta]['_weight'];
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__rank'] = $rank;
+    }
+
+    // Get the term that matches.
+    $cvterm_name = $form_state['values'][$field_name]['und'][$delta]['cvterm_name'];
+    $cv_id = $form_state['values'][$field_name]['und'][$delta]['cv_id'];
+    $cvterm = chado_generate_var('cvterm', array(
+      'cv_id' => $cv_id,
+      'name' => $cvterm_name,
+    ));
+    if ($cvterm) {
+      $form_state['values'][$field_name]['und'][$delta]['cvterm_name'] = '';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__cvterm_id'] = $cvterm->cvterm_id;
+      $form_state['values'][$field_name]['und'][$delta]['value'] = $cvterm->cvterm_id;
+    }
+    // Remove all values so we can delete this record if there is no
+    // cvterm.
+    else {
+      // There must be some value set.
+      $form_state['values'][$field_name]['und'][$delta]['value'] = 'delete_me';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__cvterm_id'] = '';
+      $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $fkey_lcolumn] = '';
+      if (array_key_exists('rank', $schema['fields'])) {
+        $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__rank'] = '';
+      }
+      if (array_key_exists('pub_id', $schema['fields'])) {
+        $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__pub_id'] = '';
+      }
+      if (array_key_exists('is_not', $schema['fields'])) {
+        $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '_is_not'] = '';
+      }
+    }
+  }
+
+  /**
+   * @see TripalFieldWidget::theme()
+   */
+  public function theme($element) {
+    $field_table = $this->instance['settings']['chado_table'];
+    $layout = "
+      <div class=\"sio--annotation-widget\">
+        <div class=\"sio--annotation-item\">" .
+          drupal_render($element['cv_id']) . "
+        </div>
+        <div class=\"sio--annotation-item\">" .
+          drupal_render($element['cvterm_name']) . "
+        </div>
+        <div class=\"sio--annotation-item\">" .
+          drupal_render($element['pub']) . "
+        </div>
+        <div class=\"sio--annotation-item\">" .
+          drupal_render($element['chado-' . $field_table . '__is_not']) . "
+        </div>
+      </div>
+    ";
+
+    return $layout;
+  }
+}
+
+/**
+ * An Ajax callback for the tripal_chado_admin_publish_form..
+ */
+function sio__annotation_widget_form_ajax_callback($form, $form_state) {
+  $field_name = $form_state['triggering_element']['#parents'][0];
+  $delta = $form_state['triggering_element']['#parents'][2];
+
+  return $form[$field_name]['und'][$delta];
+}

+ 0 - 30
tripal_chado/includes/TripalFields/sio__references/sio__references.inc

@@ -66,36 +66,6 @@ class sio__references extends ChadoField {
         'operations' => array(),
         'operations' => array(),
         'sortable' => FALSE,
         'sortable' => FALSE,
         'searchable' => FALSE,
         'searchable' => FALSE,
-        'elements' => array(
-          'rdfs:type' => array(
-            'searchable' => TRUE,
-            'name' => 'type',
-            'label' => 'Reference Type',
-            'help' => 'The type of item referred to by the publication.',
-            'operations' => array('eq', 'ne', 'contains', 'starts'),
-            'sortable' => TRUE,
-          ),
-          'schema:name' => array(
-            'searchable' => TRUE,
-            'name' => 'name',
-            'label' => 'Reference Name',
-            'help' => 'The name of the item referred to by the publication.',
-            'operations' => array('eq', 'ne', 'contains', 'starts'),
-            'sortable' => TRUE,
-          ),
-          'data:0842'=> array(
-            'searchable' => TRUE,
-            'name' => 'identifier',
-            'label' => 'Reference Identifier',
-            'help' => 'The unique identifier of the item referred to by the publication.',
-            'operations' => array('eq', 'ne', 'contains', 'starts'),
-            'sortable' => TRUE,
-          ),
-          'entity'=> array(
-            'searchable' => FALSE,
-            'sortable' => FALSE,
-          ),
-        ),
       ),
       ),
     );
     );
   }
   }

+ 0 - 9
tripal_chado/includes/TripalFields/sio__references/sio__references_formatter.inc

@@ -7,15 +7,6 @@ class sio__references_formatter extends ChadoFieldFormatter {
   // The list of field types for which this formatter is appropriate.
   // The list of field types for which this formatter is appropriate.
   public static $field_types = array('sio__references');
   public static $field_types = array('sio__references');
 
 
-
-  /**
-   *
-   * @see TripalFieldFormatter::settingsForm()
-   */
-  public function settingsForm($view_mode, $form, &$form_state) {
-
-  }
-
   /**
   /**
    *
    *
    * @see TripalFieldFormatter::view()
    * @see TripalFieldFormatter::view()

+ 1 - 1
tripal_chado/includes/TripalFields/sio__vocabulary/sio__vocabulary.inc

@@ -38,7 +38,7 @@ class sio__vocabulary extends ChadoField {
   /**
   /**
    * @see TripalField::validate()
    * @see TripalField::validate()
    */
    */
-  public function validate($entity_type, $entity, $field, $items, &$errors) {
+  public function validate($entity_type, $entity, $langcode, $items, &$errors) {
 
 
     $settings = $this->field['settings'];
     $settings = $this->field['settings'];
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];

+ 29 - 2
tripal_chado/includes/TripalFields/sio__vocabulary/sio__vocabulary_widget.inc

@@ -22,7 +22,34 @@ class sio__vocabulary_widget extends ChadoFieldWidget {
     $field_table = $this->instance['settings']['chado_table'];
     $field_table = $this->instance['settings']['chado_table'];
     $field_column = $this->instance['settings']['chado_column'];
     $field_column = $this->instance['settings']['chado_column'];
 
 
-    $cv_id = 0;
+    // If the items array is empty then we are creating a new entity.
+    // Since this is set when the entity type is created, we don't want to allow
+    // content managers to change it. Thus we need to look up the value for the
+    // entity type and use it here.
+    if (empty($items)) {
+      // Use the bundle to get the cv_id choosen for this cvterm-based entity.
+      // ASSUMPTION: the cv_id is saved as the "type_value" of the bundle.
+      $bundle = tripal_load_bundle_entity(array('name' => $widget['#bundle']));
+      $cv = tripal_get_cv(array('cv_id' => $bundle->type_value));
+
+      // Now populate the items array with defaults based on the cv.
+      if ($cv) {
+        $items[$delta] = array(
+          'value' => $cv->name,
+          'chado-' . $field_table . '__cv_id' => $cv->cv_id,
+        );
+      }
+      else {
+        tripal_report_error(
+          $field_name,
+          TRIPAL_ERROR,
+          'Unable to determine default vocabulary for :name Tripal Content Type',
+          array(':name' => $bundle->label)
+        );
+        drupal_set_message(t('Unable to determine default vocabulary for :name Tripal Content Type',
+          array(':name' => $bundle->label)), 'error');
+      }
+    }
 
 
     $widget['value'] = array(
     $widget['value'] = array(
       '#type' => 'value',
       '#type' => 'value',
@@ -30,7 +57,7 @@ class sio__vocabulary_widget extends ChadoFieldWidget {
     );
     );
     $widget['chado-' . $field_table . '__cv_id'] = array(
     $widget['chado-' . $field_table . '__cv_id'] = array(
       '#type' => 'value',
       '#type' => 'value',
-      '#value' => $items[$delta]['chado-' . $field_table . '__cv_id'],
+      '#value' => array_key_exists($delta, $items) ? $items[$delta]['chado-' . $field_table . '__cv_id'] : '',
     );
     );
     $widget['vocabulary_name'] = array(
     $widget['vocabulary_name'] = array(
       '#type' => 'item',
       '#type' => 'item',

+ 0 - 7
tripal_chado/includes/TripalFields/so__genotype/so__genotype.inc

@@ -63,32 +63,25 @@ class so__genotype extends ChadoField {
     $field_term = $this->getFieldTermID();
     $field_term = $this->getFieldTermID();
     return array(
     return array(
       $field_term => array(
       $field_term => array(
-        'operations' => array(),
         'sortable' => FALSE,
         'sortable' => FALSE,
         'searchable' => FALSE,
         'searchable' => FALSE,
         'elements' => array(
         'elements' => array(
           'rdfs:type' => array(
           'rdfs:type' => array(
             'searchable' => FALSE,
             'searchable' => FALSE,
-            'name' => 'genotype_type_name',
             'label' => 'Genotype Type',
             'label' => 'Genotype Type',
             'help' => 'The type of genotype.',
             'help' => 'The type of genotype.',
-            'operations' => array('eq', 'ne', 'contains', 'starts'),
             'sortable' => FALSE,
             'sortable' => FALSE,
           ),
           ),
           'schema:name' => array(
           'schema:name' => array(
-            'name' => 'genotype_name',
             'label' => 'Genotype Name',
             'label' => 'Genotype Name',
             'help' => 'The name of the genotype.',
             'help' => 'The name of the genotype.',
             'searchable' => FALSE,
             'searchable' => FALSE,
-            'operations' => array('eq', 'ne', 'contains', 'starts'),
             'sortable' => FALSE,
             'sortable' => FALSE,
           ),
           ),
           'schema:description' => array(
           'schema:description' => array(
-            'name' => 'genotype_description',
             'label' => 'Genotype Description',
             'label' => 'Genotype Description',
             'help' => 'A description of the genotype.',
             'help' => 'A description of the genotype.',
             'searchable' => FALSE,
             'searchable' => FALSE,
-            'operations' => array('eq', 'ne', 'contains', 'starts'),
             'sortable' => FALSE,
             'sortable' => FALSE,
           ),
           ),
         )
         )

+ 0 - 8
tripal_chado/includes/TripalFields/so__genotype/so__genotype_formatter.inc

@@ -7,14 +7,6 @@ class so__genotype_formatter extends ChadoFieldFormatter {
   // The list of field types for which this formatter is appropriate.
   // The list of field types for which this formatter is appropriate.
   public static $field_types = array('so__genotype');
   public static $field_types = array('so__genotype');
 
 
-  /**
-   *
-   * @see TripalFieldFormatter::settingsForm()
-   */
-  public function settingsForm($view_mode, $form, &$form_state) {
-
-  }
-
   /**
   /**
    *
    *
    * @see TripalFieldFormatter::view()
    * @see TripalFieldFormatter::view()

+ 0 - 8
tripal_chado/includes/TripalFields/so__transcript/so__transcript_formatter.inc

@@ -7,14 +7,6 @@ class so__transcript_formatter extends ChadoFieldFormatter {
   // The list of field types for which this formatter is appropriate.
   // The list of field types for which this formatter is appropriate.
   public static $field_types = array('so__transcript');
   public static $field_types = array('so__transcript');
 
 
-  /**
-   *
-   * @see TripalFieldFormatter::settingsForm()
-   */
-  public function settingsForm($view_mode, $form, &$form_state) {
-
-  }
-
   /**
   /**
    *
    *
    * @see TripalFieldFormatter::view()
    * @see TripalFieldFormatter::view()

+ 92 - 6
tripal_chado/includes/TripalFields/taxrank__infraspecific_taxon/taxrank__infraspecific_taxon.inc

@@ -59,15 +59,83 @@ class taxrank__infraspecific_taxon extends ChadoField {
    */
    */
   public function elementInfo() {
   public function elementInfo() {
     $field_term = $this->getFieldTermID();
     $field_term = $this->getFieldTermID();
+
+    $label_term = 'rdfs:label';
+    $infraspecific_name_term = tripal_get_chado_semweb_term('organism', 'infraspecific_name');
+    $infraspecific_type_term = tripal_get_chado_semweb_term('organism', 'type_id');
+
     return array(
     return array(
       $field_term => array(
       $field_term => array(
-        'operations' => array(),
         'sortable' => FALSE,
         'sortable' => FALSE,
-        'searchable' => FALSE,
+        'searchable' => TRUE,
+        'elements' => array(
+          $label_term => array(
+            'sortable' => FALSE,
+            'searchable' => TRUE,
+            'label' => 'Infraspecific Full Name',
+            'help' => 'The full infraspecific name including the rank and name.',
+          ),
+          $infraspecific_name_term => array(
+            'sortable' => TRUE,
+            'searchable' => TRUE,
+            'label' => 'Infrasepcies Name',
+            'help' => 'The infraspecific name of the organism below the rank of species.',
+          ),
+          $infraspecific_type_term => array(
+            'sortable' => TRUE,
+            'searchable' => TRUE,
+            'label' => 'Infraspecific Rank',
+            'help' => 'The infraspecific rank of the organism below the rank of species.',
+          ),
+        )
       ),
       ),
     );
     );
   }
   }
 
 
+  /**
+   * @see ChadoField::query()
+   */
+  public function query($query, $condition){
+    $alias = $this->field['field_name'];
+    $operator = $condition['operator'];
+
+    $field_term_id = $this->getFieldTermID();
+    $label_term = $field_term_id . ',' . 'rdfs:label';
+    $infraspecific_name_term = $field_term_id . ',' . tripal_get_chado_semweb_term('organism', 'infraspecific_name');
+    $infraspecific_type_term = $field_term_id . ',' . tripal_get_chado_semweb_term('organism', 'type_id');
+
+    if ($condition['column'] == $label_term or $condition['column'] == $field_term_id) {
+      $this->queryJoinOnce($query, 'cvterm', $alias . '_cvterm', $alias . "_cvterm.cvterm_id = base.type_id");
+      $query->where("CONCAT(" . $alias . "_cvterm.name, ' ', base.infraspecific_name) $operator :full_name",  array(':full_name' => $condition['value']));
+    }
+    if ($condition['column'] == $infraspecific_name_term) {
+      $query->condition('base.infraspecific_name', $condition['value'], $operator);
+    }
+    if ($condition['column'] == $infraspecific_type_term) {
+      $this->queryJoinOnce($query, 'cvterm', $alias . '_cvterm', $alias . "_cvterm.cvterm_id = base.type_id");
+      $query->condition($alias . '_cvterm.name', $condition['value'], $operator);
+    }
+  }
+  /**
+   * @see ChadoField::queryOrder()
+   */
+  public function queryOrder($query, $order) {
+    $alias = $this->field['field_name'];
+
+    $field_term_id = $this->getFieldTermID();
+    $label_term = $field_term_id . ',' . 'rdfs:label';
+    $infraspecific_name_term = $field_term_id . ',' . tripal_get_chado_semweb_term('organism', 'infraspecific_name');
+    $infraspecific_type_term = $field_term_id . ',' . tripal_get_chado_semweb_term('organism', 'type_id');
+
+    if ($order['column'] == $infraspecific_name_term) {
+      $query->orderBy('base.infraspecific_name', $order['direction']);
+    }
+    if ($order['column'] == $infraspecific_type_term) {
+      $this->queryJoinOnce($query, 'cvterm', $alias . '_cvterm', $alias . "_cvterm.cvterm_id = base.type_id", "LEFT OUTER");
+      $query->orderBy($alias . '_cvterm.name', $order['direction']);
+    }
+  }
+
   /**
   /**
    *
    *
    * @see TripalField::load()
    * @see TripalField::load()
@@ -81,15 +149,33 @@ class taxrank__infraspecific_taxon extends ChadoField {
     $field_table = $this->instance['settings']['chado_table'];
     $field_table = $this->instance['settings']['chado_table'];
     $field_column = $this->instance['settings']['chado_column'];
     $field_column = $this->instance['settings']['chado_column'];
 
 
+    $entity->{$field_name}['und'][0]['value'] = '';
+
+    if (chado_get_version() < 1.3) {
+      return;
+    }
+
+    $label_term = 'rdfs:label';
+    $infraspecific_name_term = tripal_get_chado_semweb_term('organism', 'infraspecific_name');
+    $infraspecific_type_term = tripal_get_chado_semweb_term('organism', 'type_id');
+
     // Set some defaults for the empty record.
     // Set some defaults for the empty record.
     $entity->{$field_name}['und'][0] = array(
     $entity->{$field_name}['und'][0] = array(
-      'value' => '',
-      'organism__type_id' => '',
+      'value' => array(),
+      'chado-organism__infraspecific_name' => '',
+      'chado-organism__type_id' => '',
     );
     );
 
 
+    if ($record->infraspecific_name) {
+      $label = $record->type_id->name . ' ' . $record->infraspecific_name;
+      $entity->{$field_name}['und'][0]['value'][$label_term] = $label;
+      $entity->{$field_name}['und'][0]['value'][$infraspecific_name_term] = $record->infraspecific_name;
+      $entity->{$field_name}['und'][0]['chado-organism__infraspecific_name'] = $record->infraspecific_name;
+    }
+
     if ($record->type_id) {
     if ($record->type_id) {
-      $entity->{$field_name}['und'][0]['value'] = $record->type_id->name;
-      $entity->{$field_name}['und'][0]['organism__type_id'] = $record->type_id->cvterm_id;
+      $entity->{$field_name}['und'][0]['value'][$infraspecific_type_term] = $record->type_id->name;
+      $entity->{$field_name}['und'][0]['chado-organism__type_id'] = $record->type_id->cvterm_id;
     }
     }
   }
   }
 }
 }

+ 16 - 8
tripal_chado/includes/TripalFields/taxrank__infraspecific_taxon/taxrank__infraspecific_taxon_formatter.inc

@@ -7,19 +7,27 @@ class taxrank__infraspecific_taxon_formatter extends ChadoFieldFormatter {
   // The list of field types for which this formatter is appropriate.
   // The list of field types for which this formatter is appropriate.
   public static $field_types = array('taxrank__infraspecific_taxon');
   public static $field_types = array('taxrank__infraspecific_taxon');
 
 
-  /**
-   *
-   * @see TripalFieldFormatter::settingsForm()
-   */
-  public function settingsForm($view_mode, $form, &$form_state) {
-
-  }
-
   /**
   /**
    *
    *
    * @see TripalFieldFormatter::view()
    * @see TripalFieldFormatter::view()
    */
    */
   public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
   public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
 
 
+    $label_term = 'rdfs:label';
+    $infraspecific_name_term = tripal_get_chado_semweb_term('organism', 'infraspecific_name');
+    $infraspecific_type_term = tripal_get_chado_semweb_term('organism', 'type_id');
+
+    if (is_array($items[0]['value']) and array_key_exists($infraspecific_name_term, $items[0]['value'])) {
+      $infraspecific_name = $items[0]['value'][$infraspecific_name_term];
+      $infraspecific_type = $items[0]['value'][$infraspecific_type_term];
+      $content = $items[0]['value'][$label_term];
+
+      // The cardinality of this field is 1 so we don't have to
+      // iterate through the items array, as there will never be more than 1.
+      $element[0] = array(
+        '#type' => 'markup',
+        '#markup' => $content,
+      );
+    }
   }
   }
 }
 }

+ 74 - 14
tripal_chado/includes/TripalFields/taxrank__infraspecific_taxon/taxrank__infraspecific_taxon_widget.inc

@@ -7,50 +7,110 @@ class taxrank__infraspecific_taxon_widget extends ChadoFieldWidget {
   // The list of field types for which this formatter is appropriate.
   // The list of field types for which this formatter is appropriate.
   public static $field_types = array('taxrank__infraspecific_taxon');
   public static $field_types = array('taxrank__infraspecific_taxon');
 
 
+
   /**
   /**
    *
    *
    * @see TripalFieldWidget::form()
    * @see TripalFieldWidget::form()
    */
    */
   public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
   public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
+
     $settings = $this->field['settings'];
     $settings = $this->field['settings'];
     $field_name = $this->field['field_name'];
     $field_name = $this->field['field_name'];
     $field_type = $this->field['type'];
     $field_type = $this->field['type'];
     $field_table = $this->instance['settings']['chado_table'];
     $field_table = $this->instance['settings']['chado_table'];
     $field_column = $this->instance['settings']['chado_column'];
     $field_column = $this->instance['settings']['chado_column'];
 
 
+    $infra_name = '';
     $type_id = 0;
     $type_id = 0;
-    if (count($items) > 0 and array_key_exists('organism__type_id', $items[0])) {
-      $type_id = $items[0]['organism__type_id'];
+
+    if (count($items) > 0) {
+      $type_id = array_key_exists('chado-organism__type_id', $items[0]) ? $items[0]['chado-organism__type_id'] : $type_id;
+      $infra_name = array_key_exists('chado-organism__infraspecific_name', $items[0]) ? $items[0]['chado-organism__infraspecific_name'] : $infra_name;
     }
     }
 
 
-    $form['value'] = array(
+    if (array_key_exists('values', $form_state) and
+        array_key_exists($field_name, $form_state['values'])) {
+      $type_id = $form_state['values'][$field_name][$langcode][$delta]['infraname']['specific_epithet'];
+      $infra_name = $form_state['values'][$field_name][$langcode][$delta]['infraname']['infrapsecific_epithet'];
+    }
+
+    $widget['value'] = array(
       '#type' => 'value',
       '#type' => 'value',
       '#value' =>  array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
       '#value' =>  array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
     );
     );
+    $widget['chado-organism__type_id'] = array(
+      '#type' => 'value',
+      '#value' =>  $type_id,
+    );
+    $widget['chado-organism__infraspecific_name'] = array(
+      '#type' => 'value',
+      '#value' =>  $infra_name,
+    );
 
 
-    $cv = tripal_get_default_cv($field_table, $field_column);
+    $cv = tripal_get_cv(array('name' => 'taxonomic_rank'));
+    $terms = tripal_get_cvterm_select_options($cv->cv_id);
+
+    // Unfortunately the taxonomic_rank vocabulary is not properly organized
+    // such that we an only include terms below 'species'. Therefore we will
+    // just list them here and hope we haven't missed one.
+    $valid_terms = array('cultivar', 'subspecies', 'varietas', 'subvariety', 'forma', 'subforma');
     $options = array();
     $options = array();
-    if ($cv) {
-      $options = tripal_get_cvterm_select_options($cv->cv_id);
+    $options[] = '--Select a rank--';
+    foreach  ($terms as $cvterm_id => $name) {
+      if (in_array($name, $valid_terms)) {
+        $options[$cvterm_id] = $name;
+      }
     }
     }
-    $widget['organism__type_id'] = array(
-      '#type' => 'select',
+
+    $widget['infraname'] = array(
+      '#type' => 'fieldset',
       '#title' => $element['#title'],
       '#title' => $element['#title'],
-      '#description' => $element['#description'],
+      '#collapsible' => FALSE,
+      '#collapsed' => FALSE,
+      '#description' => $element['#description']
+    );
+    $widget['infraname']['specific_epithet'] = array(
+      '#type' => 'select',
+      '#title' => 'Specific Epithet',
+      '#description' => 'The rank below species. This field may be left blank if not appropriate.',
       '#options' => $options,
       '#options' => $options,
       '#default_value' => $type_id,
       '#default_value' => $type_id,
+    );
+    $widget['infraname']['infrapsecific_epithet'] = array(
+      '#type' => 'textfield',
+      '#title' => 'Infrapsecific Epithet',
+      '#description' => 'The name below species.',
+      '#default_value' => $infra_name,
       '#required' => $element['#required'],
       '#required' => $element['#required'],
-      '#weight' => isset($element['#weight']) ? $element['#weight'] : 0,
-      '#delta' => $delta,
     );
     );
   }
   }
 
 
   /**
   /**
-   *
-   * @see TripalFieldWidget::submit()
+   * @see TripalFieldWidget::validate()
    */
    */
-  public function submit($form, &$form_state, $entity_type, $entity, $langcode, $delta) {
+  public function validate($element, $form, &$form_state, $langcode, $delta) {
+    $field_name = $this->field['field_name'];
+    $field_table = $this->instance['settings']['chado_table'];
+    $field_column = $this->instance['settings']['chado_column'];
+
+    $type_id = $form_state['values'][$field_name]['und'][0]['infraname']['specific_epithet'];
+    $infra_name = $form_state['values'][$field_name]['und'][0]['infraname']['infrapsecific_epithet'];
+
+    if ($infra_name and $type_id) {
+      $form_state['values'][$field_name]['und'][0]['value'] = $infra_name;
+      $form_state['values'][$field_name]['und'][0]['chado-organism__type_id'] = $type_id;
+      $form_state['values'][$field_name]['und'][0]['chado-organism__infraspecific_name'] = $infra_name;
+    }
+    if ($infra_name and !$type_id) {
+      $form_state['values'][$field_name]['und'][0]['value'] = $infra_name;
+      $form_state['values'][$field_name]['und'][0]['chado-organism__type_id'] = '__NULL__';
+      $form_state['values'][$field_name]['und'][0]['chado-organism__infraspecific_name'] = $infra_name;
+    }
+    else {
+      $form_state['values'][$field_name]['und'][0]['chado-organism__type_id'] = '__NULL__';
+      $form_state['values'][$field_name]['und'][0]['chado-organism__infraspecific_name'] = '__NULL__';
+    }
 
 
   }
   }
 }
 }

+ 5 - 0
tripal_chado/includes/TripalFields/uo__unit/uo__unit.inc

@@ -56,6 +56,11 @@ class uo__unit extends ChadoField {
 
 
     if ($record) {
     if ($record) {
       $entity->{$field_name}['und'][0]['value'] = $record->unittype_id->name;
       $entity->{$field_name}['und'][0]['value'] = $record->unittype_id->name;
+      $entity->{$field_name}['und'][0]['chado-' . $field_table . '__unittype_id'] = $record->unittype_id->cvterm_id;
+      $entity->{$field_name}['und'][0]['chado-cvterm__name'] = $record->unittype_id->name;
+      $entity->{$field_name}['und'][0]['chado-cvterm__definition'] = $record->unittype_id->definition;
+      $entity->{$field_name}['und'][0]['chado-cvterm__cv_id'] = $record->unittype_id->cv_id->cv_id;
+      $entity->{$field_name}['und'][0]['chado-cv__name'] = $record->unittype_id->cv_id->name;
     }
     }
   }
   }
 }
 }

+ 42 - 1
tripal_chado/includes/TripalFields/uo__unit/uo__unit_widget.inc

@@ -16,6 +16,47 @@ class uo__unit_widget extends ChadoFieldWidget {
 
 
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
 
 
-    // TODO: add a form for changing the unit types.
+    $settings = $this->field['settings'];
+    $field_name = $this->field['field_name'];
+    $field_type = $this->field['type'];
+    $field_table = $this->instance['settings']['chado_table'];
+    $field_column = $this->instance['settings']['chado_column'];
+
+    $unittype_id = 0;
+    if (count($items) > 0 and array_key_exists('chado-' . $field_table . '__unittype_id', $items[0])) {
+      $unittype_id = $items[0]['chado-' . $field_table . '__unittype_id'];
+    }
+
+    $widget['value'] = array(
+      '#type' => 'value',
+      '#value' => array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
+    );
+    $cv = tripal_get_cv(array('name' => 'featuremap_units'));
+    $options = tripal_get_cvterm_select_options($cv->cv_id);
+    unset($options[0]);
+    $widget['chado-' . $field_table . '__unittype_id'] = array(
+      '#type' => 'select',
+      '#title' => $element['#title'],
+      '#description' => $element['#description'],
+      '#options' => $options,
+      '#default_value' => $unittype_id,
+      '#empty_option' => '- Select a Unit -',
+      '#required' => $element['#required'],
+      '#weight' => isset($element['#weight']) ? $element['#weight'] : 0,
+      '#delta' => $delta,
+    );
+  }
+
+  /**
+   * @see TripalFieldWidget::validate()
+   */
+  public function validate($element, $form, &$form_state, $langcode, $delta) {
+
+    $field_name = $this->field['field_name'];
+    $field_table = $this->instance['settings']['chado_table'];
+
+    // Make sure the value is set to the organism_id
+    $unittype_id = $form_state['values'][$field_name]['und'][0]['chado-' . $field_table . '__unittype_id'];
+    $form_state['values'][$field_name]['und'][0]['value'] = $unittype_id;
   }
   }
 }
 }

+ 19 - 25
tripal_chado/includes/TripalImporter/OBOImporter.inc

@@ -553,11 +553,9 @@ class OBOImporter extends TripalImporter {
   private function loadOBO_v1_2($file, &$newcvs) {
   private function loadOBO_v1_2($file, &$newcvs) {
 
 
     $header = array();
     $header = array();
-
-    // make sure our temporary table exists
     $ret = array();
     $ret = array();
 
 
-    // empty the temp table
+    // Empty the temp table.
     $sql = "DELETE FROM {tripal_obo_temp}";
     $sql = "DELETE FROM {tripal_obo_temp}";
     chado_query($sql);
     chado_query($sql);
 
 
@@ -566,7 +564,7 @@ class OBOImporter extends TripalImporter {
     // parse the obo file
     // parse the obo file
     $default_db = $this->parse($file, $header);
     $default_db = $this->parse($file, $header);
 
 
-    // add the CV for this ontology to the database.  The v1.2 definition
+    // Add the CV for this ontology to the database.  The v1.2 definition
     // specifies a 'default-namespace' to be used if a 'namespace' is not
     // specifies a 'default-namespace' to be used if a 'namespace' is not
     // present for each stanza.  Some ontologies have adopted the v1.4 method
     // present for each stanza.  Some ontologies have adopted the v1.4 method
     // in their v1.2 files and not including it.
     // in their v1.2 files and not including it.
@@ -577,10 +575,10 @@ class OBOImporter extends TripalImporter {
       }
       }
       $newcvs[$header['default-namespace'][0]] = $defaultcv->cv_id;
       $newcvs[$header['default-namespace'][0]] = $defaultcv->cv_id;
     }
     }
-    // if the 'default-namespace' is missing
+    // If the 'default-namespace' is missing.
     else {
     else {
 
 
-      // look to see if an 'ontology' key is present.  It is part of the v1.4
+      // Look to see if an 'ontology' key is present.  It is part of the v1.4
       // specification so it shouldn't be in the file, but just in case
       // specification so it shouldn't be in the file, but just in case
       if (array_key_exists('ontology', $header)) {
       if (array_key_exists('ontology', $header)) {
         $defaultcv = tripal_insert_cv(strtoupper($header['ontology'][0]), '');
         $defaultcv = tripal_insert_cv(strtoupper($header['ontology'][0]), '');
@@ -597,11 +595,11 @@ class OBOImporter extends TripalImporter {
           "should go.  Instead, those terms will be placed in the '!vocab' vocabulary.",
           "should go.  Instead, those terms will be placed in the '!vocab' vocabulary.",
           array('!vocab' => $defaultcv->name), TRIPAL_WARNING);
           array('!vocab' => $defaultcv->name), TRIPAL_WARNING);
     }!
     }!
-    // add any typedefs to the vocabulary first
+    // Add any typedefs to the vocabulary first.
     $this->logMessage("Step 2: Loading type defs...");
     $this->logMessage("Step 2: Loading type defs...");
     $this->loadTypeDefs($defaultcv, $newcvs, $default_db);
     $this->loadTypeDefs($defaultcv, $newcvs, $default_db);
 
 
-    // next add terms to the vocabulary
+    // Next add terms to the vocabulary.
     $this->logMessage("Step 3: Loading terms...");
     $this->logMessage("Step 3: Loading terms...");
     if (!$this->processTerms($defaultcv, $newcvs, $default_db)) {
     if (!$this->processTerms($defaultcv, $newcvs, $default_db)) {
       throw new Exception('Cannot add terms from this ontology');
       throw new Exception('Cannot add terms from this ontology');
@@ -668,7 +666,7 @@ class OBOImporter extends TripalImporter {
 
 
     $i = 0;
     $i = 0;
 
 
-    // iterate through each term from the OBO file and add it
+    // Iterate through each term from the OBO file and add it.
     $sql = "
     $sql = "
       SELECT * FROM {tripal_obo_temp}
       SELECT * FROM {tripal_obo_temp}
       WHERE type = 'Term'
       WHERE type = 'Term'
@@ -691,7 +689,7 @@ class OBOImporter extends TripalImporter {
       $term = unserialize(base64_decode($t->stanza));
       $term = unserialize(base64_decode($t->stanza));
       $this->setItemsHandled($i);
       $this->setItemsHandled($i);
 
 
-      // add/update this term
+      // Add/update this term.
       if (!$this->processTerm($term, $defaultcv->name, 0, $newcvs, $default_db)) {
       if (!$this->processTerm($term, $defaultcv->name, 0, $newcvs, $default_db)) {
         throw new Exception("Failed to process terms from the ontology");
         throw new Exception("Failed to process terms from the ontology");
       }
       }
@@ -752,6 +750,14 @@ class OBOImporter extends TripalImporter {
       throw new Exception("Cannot add the term " . $term['id'][0]);
       throw new Exception("Cannot add the term " . $term['id'][0]);
     }
     }
 
 
+    // Remove any relationships that this term already has (in case it was
+    // updated) and we'll re-add them.
+    $sql = "
+      DELETE FROM {cvterm_relationship} CVTR
+      WHERE CVTR.subject_id = :cvterm_id
+    ";
+    chado_query($sql, array(':cvterm_id' => $cvterm->cvterm_id));
+
     if (array_key_exists('namespace', $term)) {
     if (array_key_exists('namespace', $term)) {
       $newcvs[$term['namespace'][0]] = $cvterm->cv_id;
       $newcvs[$term['namespace'][0]] = $cvterm->cv_id;
     }
     }
@@ -863,18 +869,6 @@ class OBOImporter extends TripalImporter {
       foreach ($term['relationship'] as $value) {
       foreach ($term['relationship'] as $value) {
         $rel = preg_replace('/^(.+?)\s.+?$/', '\1', $value);
         $rel = preg_replace('/^(.+?)\s.+?$/', '\1', $value);
         $object = preg_replace('/^.+?\s(.+?)$/', '\1', $value);
         $object = preg_replace('/^.+?\s(.+?)$/', '\1', $value);
-        // The Gene Ontology uses 'has_part' for transitive relationships, but
-        // it specifically indicates that 'has_part' should not be used for
-        // grouping annotations.  Unfortunately, this means that when we
-        // try to popoulate the cvtermpath table a 'has_part' relationships
-        // will be used for exactly that purpose: to group annotations.  This
-        // doesn't seem to the be the case for other vocabularies such as the
-        // sequence ontology that uses has_part as primary relationship between
-        // terms. So, when loading the GO, we'll not include has_part
-        // relationships.
-        /*if ($rel == 'has_part' and $cvterm->dbxref_id->db_id->name == 'GO') {
-        continue;
-        }*/
         if (!$this->addRelationship($cvterm, $defaultcv, $rel, $object, $is_relationship, $default_db)) {
         if (!$this->addRelationship($cvterm, $defaultcv, $rel, $object, $is_relationship, $default_db)) {
           throw new Exception("Cannot add relationship $rel: $object");
           throw new Exception("Cannot add relationship $rel: $object");
         }
         }
@@ -917,7 +911,7 @@ class OBOImporter extends TripalImporter {
   private function addRelationship($cvterm, $defaultcv, $rel,
   private function addRelationship($cvterm, $defaultcv, $rel,
       $objname, $object_is_relationship = 0, $default_db = 'OBO_REL') {
       $objname, $object_is_relationship = 0, $default_db = 'OBO_REL') {
 
 
-    // make sure the relationship cvterm exists
+    // Make sure the relationship cvterm exists.
     $term = array(
     $term = array(
       'name' => $rel,
       'name' => $rel,
       'id' => "$default_db:$rel",
       'id' => "$default_db:$rel",
@@ -930,7 +924,7 @@ class OBOImporter extends TripalImporter {
     $relcvterm = tripal_insert_cvterm($term, array('update_existing' => FALSE));
     $relcvterm = tripal_insert_cvterm($term, array('update_existing' => FALSE));
 
 
     if (!$relcvterm) {
     if (!$relcvterm) {
-      // if the relationship term couldn't be found in the default_db provided
+      // If the relationship term couldn't be found in the default_db provided
       // then do on more check to find it in the relationship ontology
       // then do on more check to find it in the relationship ontology
       $term = array(
       $term = array(
         'name' => $rel,
         'name' => $rel,
@@ -947,7 +941,7 @@ class OBOImporter extends TripalImporter {
       }
       }
     }
     }
 
 
-    // get the object term
+    // Get the object term.
     $oterm = $this->getTerm($objname);
     $oterm = $this->getTerm($objname);
     if (!$oterm) {
     if (!$oterm) {
       throw new Exception("Could not find object term $objname\n");
       throw new Exception("Could not find object term $objname\n");

+ 25 - 2
tripal_chado/includes/setup/tripal_chado.setup.inc

@@ -52,7 +52,6 @@ function tripal_chado_prepare_form_submit($form, $form_state) {
      $args = array();
      $args = array();
      $includes = array(
      $includes = array(
         module_load_include('inc', 'tripal_chado', 'includes/setup/tripal_chado.setup'),
         module_load_include('inc', 'tripal_chado', 'includes/setup/tripal_chado.setup'),
-        module_load_include('inc', 'tripal_chado', 'includes/loaders/tripal_chado.obo_loader'),
      );
      );
      tripal_add_job('Prepare Chado', 'tripal_chado',
      tripal_add_job('Prepare Chado', 'tripal_chado',
        'tripal_chado_prepare_chado', $args,
        'tripal_chado_prepare_chado', $args,
@@ -137,7 +136,15 @@ function tripal_chado_load_ontologies() {
 /**
 /**
  * Prepares Chado for use by Tripal.
  * Prepares Chado for use by Tripal.
  */
  */
-function tripal_chado_prepare_chado() {
+function tripal_chado_prepare_chado($job = NULL) {
+
+  // Retrieve the job arguement in order to report progress.
+  if (is_int($job)) {
+    $job = new TripalJob();
+    $job->load($job_id);
+  }
+  $report_progress = TRUE;
+  if (!is_object($job)) { $report_progress = FALSE; }
 
 
   try {
   try {
 
 
@@ -171,20 +178,28 @@ function tripal_chado_prepare_chado() {
       tripal_chado_fix_v1_3_custom_tables();
       tripal_chado_fix_v1_3_custom_tables();
     }
     }
 
 
+    if ($report_progress) { $job->setProgress(5); }
+
     // Import commonly used ontologies if needed.
     // Import commonly used ontologies if needed.
     drush_print("Loading Ontologies...");
     drush_print("Loading Ontologies...");
     tripal_chado_load_ontologies();
     tripal_chado_load_ontologies();
 
 
+    if ($report_progress) { $job->setProgress(50); }
+
     // Populate the semantic web associations for Chado tables/fields.
     // Populate the semantic web associations for Chado tables/fields.
     drush_print("Making semantic connections for Chado tables/fields...");
     drush_print("Making semantic connections for Chado tables/fields...");
     tripal_chado_populate_chado_semweb_table();
     tripal_chado_populate_chado_semweb_table();
 
 
+    if ($report_progress) { $job->setProgress(60); }
+
     // Initialize the population of the chado_cvterm_mapping table.  This will
     // Initialize the population of the chado_cvterm_mapping table.  This will
     // map existing data types already in Chado so that when users want to
     // map existing data types already in Chado so that when users want to
     // add new content types it simplifies the form for them.
     // add new content types it simplifies the form for them.
     drush_print("Map Chado Controlled vocabularies to Tripal Terms...");
     drush_print("Map Chado Controlled vocabularies to Tripal Terms...");
     tripal_chado_map_cvterms();
     tripal_chado_map_cvterms();
 
 
+    if ($report_progress) { $job->setProgress(70); }
+
     drush_print("Creating common Tripal Content Types...");
     drush_print("Creating common Tripal Content Types...");
 
 
     // Create the 'Organism' entity type. This uses the obi:organism term.
     // Create the 'Organism' entity type. This uses the obi:organism term.
@@ -204,6 +219,7 @@ function tripal_chado_prepare_chado() {
         throw new Exception($error['!message']);
         throw new Exception($error['!message']);
       }
       }
     }
     }
+    if ($report_progress) { $job->setProgress(74); }
 
 
     // Create the 'Analysis' entity type. This uses the local:analysis term.
     // Create the 'Analysis' entity type. This uses the local:analysis term.
     $error = '';
     $error = '';
@@ -222,6 +238,7 @@ function tripal_chado_prepare_chado() {
         throw new Exception($error['!message']);
         throw new Exception($error['!message']);
       }
       }
     }
     }
+    if ($report_progress) { $job->setProgress(78); }
 
 
     // Create the 'Project' entity type. This uses the local:project term.
     // Create the 'Project' entity type. This uses the local:project term.
     $error = '';
     $error = '';
@@ -240,6 +257,7 @@ function tripal_chado_prepare_chado() {
         throw new Exception($error['!message']);
         throw new Exception($error['!message']);
       }
       }
     }
     }
+    if ($report_progress) { $job->setProgress(82); }
 
 
     // Create the 'Map' entity type. This uses the local:project term.
     // Create the 'Map' entity type. This uses the local:project term.
     $error = '';
     $error = '';
@@ -265,6 +283,7 @@ function tripal_chado_prepare_chado() {
     );
     );
     $cvterm = tripal_get_cvterm($identifier);
     $cvterm = tripal_get_cvterm($identifier);
     tripal_chado_add_cvterm_mapping($cvterm->cvterm_id, 'featuremap', NULL);
     tripal_chado_add_cvterm_mapping($cvterm->cvterm_id, 'featuremap', NULL);
+    if ($report_progress) { $job->setProgress(86); }
 
 
     // Import a publication so we get all of the properties before
     // Import a publication so we get all of the properties before
     // creating the content type.
     // creating the content type.
@@ -306,6 +325,7 @@ function tripal_chado_prepare_chado() {
     );
     );
     $result = chado_select_record('pub_dbxref', array('pub_id'), $values);
     $result = chado_select_record('pub_dbxref', array('pub_id'), $values);
     chado_delete_record('pub', array('pub_id' => $result[0]->pub_id));
     chado_delete_record('pub', array('pub_id' => $result[0]->pub_id));
+    if ($report_progress) { $job->setProgress(90); }
 
 
     // Create the 'Gene' entity type.
     // Create the 'Gene' entity type.
     $error = '';
     $error = '';
@@ -325,6 +345,7 @@ function tripal_chado_prepare_chado() {
         throw new Exception($error['!message']);
         throw new Exception($error['!message']);
       }
       }
     }
     }
+    if ($report_progress) { $job->setProgress(94); }
 
 
     // Create the 'mRNA' entity type.
     // Create the 'mRNA' entity type.
     $error = '';
     $error = '';
@@ -344,6 +365,7 @@ function tripal_chado_prepare_chado() {
         throw new Exception($error['!message']);
         throw new Exception($error['!message']);
       }
       }
     }
     }
+    if ($report_progress) { $job->setProgress(98); }
 
 
     // Add the supported loaders
     // Add the supported loaders
     variable_set('tripal_pub_supported_dbs', array('PMID', 'AGL'));
     variable_set('tripal_pub_supported_dbs', array('PMID', 'AGL'));
@@ -352,6 +374,7 @@ function tripal_chado_prepare_chado() {
     variable_set('tripal_chado_is_prepared', TRUE);
     variable_set('tripal_chado_is_prepared', TRUE);
   }
   }
   catch (Exception $e) {
   catch (Exception $e) {
+    $job->logMessage($e);
     throw new Exception($e);
     throw new Exception($e);
   }
   }
 }
 }

+ 13 - 0
tripal_chado/includes/tripal_chado.cv.inc

@@ -1,4 +1,17 @@
 <?php
 <?php
+
+/**
+ * Loads an OBO File using the new TripalImporter. Expected to be run by a Tripal Job.
+ */
+function tripal_cv_load_obo($obo_id) {
+
+  module_load_include('inc', 'tripal_chado', 'includes/TripalImporter/OBOImporter');
+  $obo_importer = new OBOImporter();
+  $obo_importer->create(array('obo_id' => $obo_id));
+  $obo_importer->run();
+
+}
+
 /**
 /**
  * Provide landing page to the new admin pages
  * Provide landing page to the new admin pages
  *
  *

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

@@ -151,6 +151,11 @@ function tripal_chado_add_db_form_fields(&$form, $form_state, $dbid = NULL) {
     $default_desc = $db->description;
     $default_desc = $db->description;
     $default_url = $db->url;
     $default_url = $db->url;
     $default_urlprefix = $db->urlprefix;
     $default_urlprefix = $db->urlprefix;
+
+    $form['dbid'] = array(
+      '#type' => 'value',
+      '#value' => $dbid,
+    );
   }
   }
 
 
   // add a fieldset for the Drupal Schema API
   // add a fieldset for the Drupal Schema API

+ 12 - 4
tripal_chado/includes/tripal_chado.field_storage.inc

@@ -43,7 +43,8 @@ function tripal_chado_field_storage_write($entity_type, $entity, $op, $fields) {
 
 
   // Convert the fields into a key/value list of fields and their values.
   // Convert the fields into a key/value list of fields and their values.
   $field_vals = tripal_chado_field_storage_write_merge_fields($fields, $entity_type, $entity);
   $field_vals = tripal_chado_field_storage_write_merge_fields($fields, $entity_type, $entity);
-dpm($field_vals);
+//dpm($field_vals);
+
   // First, write the record for the base table.  If we have a record id then
   // First, write the record for the base table.  If we have a record id then
   // this is an update and we need to set the primary key.  If not, then this
   // this is an update and we need to set the primary key.  If not, then this
   // is an insert and we need to set the type_id if the table supports it.
   // is an insert and we need to set the type_id if the table supports it.
@@ -387,7 +388,8 @@ function tripal_chado_field_storage_write_merge_fields($fields, $entity_type, $e
     $field = field_info_field_by_id($field_id);
     $field = field_info_field_by_id($field_id);
     $field_name = $field['field_name'];
     $field_name = $field['field_name'];
     $instance = field_info_instance('TripalEntity', $field['field_name'], $entity->bundle);
     $instance = field_info_instance('TripalEntity', $field['field_name'], $entity->bundle);
-    // Some fields (e.g. chado_linker_cvterm_adder) don't add data to
+
+    // Some fields don't add data to
     // Chado so they don't have a table, but they are still attached to the
     // Chado so they don't have a table, but they are still attached to the
     // entity. Just skip these.
     // entity. Just skip these.
     if (!array_key_exists('chado_table', $instance['settings'])) {
     if (!array_key_exists('chado_table', $instance['settings'])) {
@@ -553,6 +555,12 @@ function tripal_chado_field_storage_query($query) {
   // Make sure we only get records of the correct entity type
   // Make sure we only get records of the correct entity type
   $cquery->condition('TE.bundle', $query->entityConditions['bundle']['value']);
   $cquery->condition('TE.bundle', $query->entityConditions['bundle']['value']);
 
 
+  // Iterate through all the property conditions. These will be filters
+  // on the tripal_entity table.
+  foreach ($query->propertyConditions as $index => $condition) {
+    $cquery->condition('TE.' . $condition['column'], $condition['value']);
+  }
+
   // Now set any ordering.
   // Now set any ordering.
   foreach ($query->order as $index => $sort) {
   foreach ($query->order as $index => $sort) {
     // Add in property ordering.
     // Add in property ordering.
@@ -620,8 +628,8 @@ function tripal_chado_field_storage_query($query) {
     } // end if ($sort['type'] == 'field') {
     } // end if ($sort['type'] == 'field') {
   } // end foreach ($query->order as $index => $sort) {
   } // end foreach ($query->order as $index => $sort) {
 
 
-  //dpm($cquery->__toString());
-  //dpm($cquery->getArguments());
+//        dpm($cquery->__toString());
+//        dpm($cquery->getArguments());
 
 
   $records = $cquery->execute();
   $records = $cquery->execute();
 
 

+ 331 - 200
tripal_chado/includes/tripal_chado.fields.inc

@@ -70,6 +70,13 @@ function tripal_chado_bundle_fields_info_base(&$info, $details, $entity_type, $b
       continue;
       continue;
     }
     }
 
 
+    // Skip the infraspecific type_id and name from the organism table as we
+    // have a special field for those.
+    if ($table_name == 'organism' and ($column_name == 'type_id' or
+        $column_name == 'infraspecific_name')) {
+      continue;
+    }
+
     // Skip the cvterm.is_relationshptype.
     // Skip the cvterm.is_relationshptype.
     if ($table_name == 'cvterm' and $column_name == 'is_relationshiptype') {
     if ($table_name == 'cvterm' and $column_name == 'is_relationshiptype') {
       continue;
       continue;
@@ -88,7 +95,7 @@ function tripal_chado_bundle_fields_info_base(&$info, $details, $entity_type, $b
         array('%table_name' => $table_name, '%column_name' => $column_name)), 'error');
         array('%table_name' => $table_name, '%column_name' => $column_name)), 'error');
       continue;
       continue;
     }
     }
-    $field_name = strtolower($cvterm->dbxref_id->db_id->name . '__' . preg_replace('/ /', '_', $cvterm->name));
+    $field_name = strtolower($cvterm->dbxref_id->db_id->name . '__' . preg_replace('/[^\w]/', '_', $cvterm->name));
     $field_name = substr($field_name, 0, 32);
     $field_name = substr($field_name, 0, 32);
 
 
     // Skip the primary key field.
     // Skip the primary key field.
@@ -96,9 +103,9 @@ function tripal_chado_bundle_fields_info_base(&$info, $details, $entity_type, $b
       continue;
       continue;
     }
     }
 
 
-    // Skip the type field that will always be custom
-    if (($table_name == $type_table and $column_name == $type_column) or
-         $column_name == 'type_id') {
+    // If the type_id defines the content type and it's part of the
+    // base table and this column is the type_id then skip it.
+    if (!$type_table and $type_column and $column_name == $type_column) {
       continue;
       continue;
     }
     }
 
 
@@ -165,7 +172,9 @@ function tripal_chado_bundle_fields_info_base(&$info, $details, $entity_type, $b
     //
     //
     // PUB TABLE
     // PUB TABLE
     //
     //
-    elseif ($table_name == 'pub' and $column_name == 'uniquename') {
+    if ($table_name == 'pub' and (
+        $column_name == 'uniquename' or $column_name == 'title' or
+        $column_name == 'volumetitle')) {
       $base_info['type'] = 'text';
       $base_info['type'] = 'text';
       $base_info['settings']['text_processing'] = 0;
       $base_info['settings']['text_processing'] = 0;
     }
     }
@@ -187,12 +196,8 @@ function tripal_chado_bundle_fields_info_custom(&$info, $details, $entity_type,
 
 
   $schema = chado_get_schema($table_name);
   $schema = chado_get_schema($table_name);
 
 
-  // BASE TYPE_ID
-  // Exclude the type_id field on base tables where content types are mapped
-  // by the type_id field or on the organism table where the type_id is mean
-  // as an infraspecific name type.
-  if (array_key_exists('type_id', $schema['fields']) and
-      $table_name != 'organism' and $type_column != 'type_id') {
+  // An additional type for the publication
+  if ($table_name == 'pub') {
     $field_name = 'schema__additional_type';
     $field_name = 'schema__additional_type';
     $field_type = 'schema__additional_type';
     $field_type = 'schema__additional_type';
     $info[$field_name] = array(
     $info[$field_name] = array(
@@ -297,7 +302,7 @@ function tripal_chado_bundle_fields_info_custom(&$info, $details, $entity_type,
     );
     );
   }
   }
 
 
-  // PROTEIN & CDS SEQUENCE
+  // PROTEIN & CDS
   if ($table_name == 'feature' and
   if ($table_name == 'feature' and
       ($bundle->label == 'mRNA' or $bundle->label == 'transcript'))  {
       ($bundle->label == 'mRNA' or $bundle->label == 'transcript'))  {
     $field_name = 'data__protein_sequence';
     $field_name = 'data__protein_sequence';
@@ -325,39 +330,37 @@ function tripal_chado_bundle_fields_info_custom(&$info, $details, $entity_type,
 //     );
 //     );
   }
   }
 
 
-  // GENE TRANSCRIPTS
-  $rel_table = $table_name . '_relationship';
-  if (chado_table_exists($rel_table) and $bundle->label == 'gene') {
-    $field_name = 'so__transcript';
-    $field_type = 'so__transcript';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-      'locked' => FALSE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-  }
-
-  // ORGANISM TYPE_ID
-//   if ($table_name == 'organism' and array_key_exists('type_id', $schema['fields'])) {
-//     $field_name = 'taxarank__infraspecific_taxon';
-//     $field_type = 'taxarank__infraspecific_taxon';
+//   // GENE TRANSCRIPTS
+//   $rel_table = $table_name . '_relationship';
+//   if (chado_table_exists($rel_table) and $bundle->label == 'gene') {
+//     $field_name = 'so__transcript';
+//     $field_type = 'so__transcript';
 //     $info[$field_name] = array(
 //     $info[$field_name] = array(
 //       'field_name' => $field_name,
 //       'field_name' => $field_name,
 //       'type' => $field_type,
 //       'type' => $field_type,
-//       'cardinality' => 1,
+//       'cardinality' => FIELD_CARDINALITY_UNLIMITED,
 //       'locked' => FALSE,
 //       'locked' => FALSE,
 //       'storage' => array(
 //       'storage' => array(
 //         'type' => 'field_chado_storage',
 //         'type' => 'field_chado_storage',
 //       ),
 //       ),
-//       'settings' => array(
-//       ),
 //     );
 //     );
 //   }
 //   }
 
 
+  // ORGANISM TYPE_ID
+  if ($table_name == 'organism' and array_key_exists('type_id', $schema['fields'])) {
+    $field_name = 'taxrank__infraspecific_taxon';
+    $field_type = 'taxrank__infraspecific_taxon';
+    $info[$field_name] = array(
+      'field_name' => $field_name,
+      'type' => $field_type,
+      'cardinality' => 1,
+      'locked' => FALSE,
+      'storage' => array(
+        'type' => 'field_chado_storage',
+      ),
+    );
+  }
+
   // FEATUREMAP UNITTYPE_ID
   // FEATUREMAP UNITTYPE_ID
   if ($table_name == 'featuremap') {
   if ($table_name == 'featuremap') {
     $field_name = 'uo__unit';
     $field_name = 'uo__unit';
@@ -497,37 +500,37 @@ function tripal_chado_bundle_fields_info_linker(&$info, $details, $entity_type,
     );
     );
   }
   }
 
 
-  // GENOTYPE
-  $genotype_table = $table_name . '_genotype';
-  if (chado_table_exists($genotype_table)) {
-    $field_name = 'so__genotype';
-    $field_type = 'so__genotype';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-      'locked' => FALSE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-  }
+//   // GENOTYPE
+//   $genotype_table = $table_name . '_genotype';
+//   if (chado_table_exists($genotype_table)) {
+//     $field_name = 'so__genotype';
+//     $field_type = 'so__genotype';
+//     $info[$field_name] = array(
+//       'field_name' => $field_name,
+//       'type' => $field_type,
+//       'cardinality' => FIELD_CARDINALITY_UNLIMITED,
+//       'locked' => FALSE,
+//       'storage' => array(
+//         'type' => 'field_chado_storage',
+//       ),
+//     );
+//   }
 
 
-  // PHENOTYPE
-  $phenotype_table = $table_name . '_phenotype';
-  if (chado_table_exists($phenotype_table)) {
-    $field_name = 'sbo__phenotype';
-    $field_type = 'sbo__phenotype';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'type' => $field_type,
-      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-      'locked' => FALSE,
-      'storage' => array(
-        'type' => 'field_chado_storage',
-      ),
-    );
-  }
+//   // PHENOTYPE
+//   $phenotype_table = $table_name . '_phenotype';
+//   if (chado_table_exists($phenotype_table)) {
+//     $field_name = 'sbo__phenotype';
+//     $field_type = 'sbo__phenotype';
+//     $info[$field_name] = array(
+//       'field_name' => $field_name,
+//       'type' => $field_type,
+//       'cardinality' => FIELD_CARDINALITY_UNLIMITED,
+//       'locked' => FALSE,
+//       'storage' => array(
+//         'type' => 'field_chado_storage',
+//       ),
+//     );
+//   }
 
 
   // PROPERTIES
   // PROPERTIES
   $prop_table = $table_name . 'prop';
   $prop_table = $table_name . 'prop';
@@ -563,6 +566,27 @@ function tripal_chado_bundle_fields_info_linker(&$info, $details, $entity_type,
     }
     }
   }
   }
 
 
+  // CVTERMS
+  $term_table = $table_name . '_cvterm';
+  if (chado_table_exists($term_table)) {
+    $schema = chado_get_schema($term_table);
+    $pkey = $schema['primary key'][0];
+    $lkey = key($schema['foreign keys'][$table_name]['columns']);
+    $rkey = $schema['foreign keys'][$table_name]['columns'][$lkey];
+
+    $field_name = 'sio__annotation';
+    $field_type = 'sio__annotation';
+    $info[$field_name] = array(
+      'field_name' => $field_name,
+      'type' => $field_type,
+      'cardinality' => FIELD_CARDINALITY_UNLIMITED,
+      'locked' => FALSE,
+      'storage' => array(
+        'type' => 'field_chado_storage',
+      ),
+    );
+  }
+
   // PUBLICATIONS
   // PUBLICATIONS
   $pub_table = $table_name . '_pub';
   $pub_table = $table_name . '_pub';
   if (chado_table_exists($pub_table)) {
   if (chado_table_exists($pub_table)) {
@@ -702,6 +726,13 @@ function tripal_chado_bundle_instances_info_base(&$info, $entity_type, $bundle,
       continue;
       continue;
     }
     }
 
 
+    // Skip the infraspecific type_id and name from the organism table as we
+    // have a special field for those.
+    if ($table_name == 'organism' and ($column_name == 'type_id' or
+        $column_name == 'infraspecific_name')) {
+      continue;
+    }
+
     // Don't create base fields for the primary key and the type_id field.
     // Don't create base fields for the primary key and the type_id field.
     if ($column_name == $pkey or $column_name == $type_column) {
     if ($column_name == $pkey or $column_name == $type_column) {
       continue;
       continue;
@@ -720,7 +751,7 @@ function tripal_chado_bundle_instances_info_base(&$info, $entity_type, $bundle,
       continue;
       continue;
     }
     }
 
 
-    $field_name = strtolower($cvterm->dbxref_id->db_id->name . '__' . preg_replace('/ /', '_', $cvterm->name));
+    $field_name = strtolower($cvterm->dbxref_id->db_id->name . '__' . preg_replace('/[^\w]/', '_', $cvterm->name));
     $field_name = substr($field_name, 0, 32);
     $field_name = substr($field_name, 0, 32);
 
 
     // Skip the primary key field.
     // Skip the primary key field.
@@ -728,8 +759,9 @@ function tripal_chado_bundle_instances_info_base(&$info, $entity_type, $bundle,
       continue;
       continue;
     }
     }
 
 
-    // Skip the type field.
-    if ($table_name == $type_table and $column_name == $type_column) {
+    // If the type_id defines the content type and it's part of the
+    // base table and this column is the type_id then skip it.
+    if (!$type_table and $type_column and $column_name == $type_column) {
       continue;
       continue;
     }
     }
 
 
@@ -823,46 +855,87 @@ function tripal_chado_bundle_instances_info_base(&$info, $entity_type, $bundle,
         unset($base_info['settings']['format']);
         unset($base_info['settings']['format']);
       }
       }
     }
     }
-    elseif ($base_info['label'] == 'Timeaccessioned') {
+    if ($base_info['label'] == 'Timeaccessioned') {
       $base_info['label'] = 'Time Accessioned';
       $base_info['label'] = 'Time Accessioned';
       $base_info['description'] = 'Please enter the time that this record was first added to the database.';
       $base_info['description'] = 'Please enter the time that this record was first added to the database.';
     }
     }
-    elseif ($base_info['label'] == 'Timelastmodified') {
+    if ($base_info['label'] == 'Timelastmodified') {
       $base_info['label'] = 'Time Last Modified';
       $base_info['label'] = 'Time Last Modified';
       $base_info['description'] = 'Please enter the time that this record was last modified. The default is the current time.';
       $base_info['description'] = 'Please enter the time that this record was last modified. The default is the current time.';
     }
     }
     //
     //
     // ORGANISM TABLE
     // ORGANISM TABLE
     //
     //
-    elseif ($table_name == 'organism' and $column_name == 'comment') {
+    if ($table_name == 'organism' and $column_name == 'comment') {
       $base_info['label'] = 'Description';
       $base_info['label'] = 'Description';
     }
     }
     //
     //
     // PUB TABLE
     // PUB TABLE
     //
     //
-    elseif ($table_name == 'pub' and $column_name == 'uniquename') {
-      $base_info['widget_type'] = 'text_textfield';
+    if ($table_name == 'pub') {
+      if ($column_name == 'title' or $column_name == 'type_id') {
+        $base_info['required'] = TRUE;
+      }
+      if($column_name == 'uniquename' or $column_name == 'title' or $column_name == 'volumetitle') {
+        $base_info['widget']['type'] = 'text_textfield';
+        $base_info['settings']['text_processing'] = '0';
+      }
+      if($column_name == 'uniquename') {
+        $base_info['label'] = 'Unique Local Identifier';
+        $base_info['required'] = TRUE;
+        $base_info['description'] = 'This publication is housed in Chado whic requires a unique identifer (or name) be provided for every publication. This identifier need not be shown to end-users but it is required. Each site must decide on a format for this unique name.';
+      }
+      if($column_name == 'title') {
+        $base_info['description'] = 'The title of the published work.';
+      }
+      if($column_name == 'series_name') {
+        $base_info['description'] = 'The name media that produces a series of publications (e.g. journal, conference proceedings, etc.).';
+      }
+      if($column_name == 'issue') {
+        $base_info['description'] = 'The issue of the series (e.g. journal) where the publication was printed.';
+      }
+      if($column_name == 'volume') {
+        $base_info['description'] = 'The volume of the series (e.g. journal) where the publication was printed.';
+      }
+      if($column_name == 'pyear') {
+        $base_info['label'] = 'Publication Year';
+        $base_info['required'] = TRUE;
+      }
+      if($column_name == 'pages') {
+        $base_info['label'] = 'Page Numbers';
+      }
+      if($column_name == 'pubplace') {
+        $base_info['label'] = 'Publication Location';
+      }
+      if($column_name == 'volumetitle') {
+        $base_info['label'] = 'Volumn Title';
+        $base_info['label'] = 'The title of the volume (if applicable).';
+      }
+      if($column_name == 'miniref') {
+        $base_info['label'] = 'Mini Local identifier';
+        $base_info['description'] = 'Some sites use small identifiers for each publication. if your site uses this please provide the proper miniref for this publication.';
+      }
     }
     }
 
 
     //
     //
     // ANALYSIS TABLE
     // ANALYSIS TABLE
     //
     //
-    elseif ($table_name == 'analysis' and $column_name == 'name') {
+    if ($table_name == 'analysis' and $column_name == 'name') {
       $base_info['required'] = TRUE;
       $base_info['required'] = TRUE;
     }
     }
-    elseif ($table_name == 'analysis' and $column_name == 'program') {
+    if ($table_name == 'analysis' and $column_name == 'program') {
       $base_info['description'] = 'The program name (e.g. blastx, blastp, sim4, genscan. If the analysis was not derived from a software package then provide a very brief description of the pipeline, workflow or method.';
       $base_info['description'] = 'The program name (e.g. blastx, blastp, sim4, genscan. If the analysis was not derived from a software package then provide a very brief description of the pipeline, workflow or method.';
       $base_info['label'] = 'Program, Pipeline, Workflow or Method Name';
       $base_info['label'] = 'Program, Pipeline, Workflow or Method Name';
     }
     }
-    elseif ($table_name == 'analysis' and $column_name == 'algorithm') {
+    if ($table_name == 'analysis' and $column_name == 'algorithm') {
       $base_info['label'] = 'Source Version';
       $base_info['label'] = 'Source Version';
       $base_info['description'] = 'The name of the algorithm used to produce the dataset if different from the program.';
       $base_info['description'] = 'The name of the algorithm used to produce the dataset if different from the program.';
     }
     }
-    elseif ($table_name == 'analysis' and $column_name == 'programversion') {
+    if ($table_name == 'analysis' and $column_name == 'programversion') {
       $base_info['label'] = 'Program Version';
       $base_info['label'] = 'Program Version';
       $base_info['description'] = 'The version of the program used to perform this analysis. (e.g. TBLASTX 2.0MP-WashU [09-Nov-2000]. Enter "n/a" if no version is available or applicable.';
       $base_info['description'] = 'The version of the program used to perform this analysis. (e.g. TBLASTX 2.0MP-WashU [09-Nov-2000]. Enter "n/a" if no version is available or applicable.';
     }
     }
-    elseif ($table_name == 'analysis' and $column_name == 'timeexecuted') {
+    if ($table_name == 'analysis' and $column_name == 'timeexecuted') {
       $base_info['label'] = 'Date Performed';
       $base_info['label'] = 'Date Performed';
       $base_info['description'] = 'The date and time when the analysis was performed.';
       $base_info['description'] = 'The date and time when the analysis was performed.';
     }
     }
@@ -876,7 +949,7 @@ function tripal_chado_bundle_instances_info_base(&$info, $entity_type, $bundle,
     //
     //
     // PROJECT TABLE
     // PROJECT TABLE
     //
     //
-    elseif ($table_name == 'project' and $column_name == 'description') {
+    if ($table_name == 'project' and $column_name == 'description') {
       $base_info['label'] = 'Short Description';
       $base_info['label'] = 'Short Description';
     }
     }
     $info[$field_name] = $base_info;
     $info[$field_name] = $base_info;
@@ -901,12 +974,8 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
   $type_value = $details['chado_type_value'];
   $type_value = $details['chado_type_value'];
   $schema = chado_get_schema($table_name);
   $schema = chado_get_schema($table_name);
 
 
-  // BASE TYPE_ID
-  // Exclude the type_id field on base tables where content types are mapped
-  // by the type_id field or on the organism table where the type_id is mean
-  // as an infraspecific name type.
-  if (array_key_exists('type_id', $schema['fields']) and
-      $table_name != 'organism' and $type_column != 'type_id') {
+  // An additional type for publications
+  if ($table_name == 'pub') {
     $field_name = 'schema__additional_type';
     $field_name = 'schema__additional_type';
     $is_required = FALSE;
     $is_required = FALSE;
     if (array_key_exists('not null', $schema['fields']['type_id']) and
     if (array_key_exists('not null', $schema['fields']['type_id']) and
@@ -917,14 +986,16 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
       'field_name' => $field_name,
       'field_name' => $field_name,
       'entity_type' => $entity_type,
       'entity_type' => $entity_type,
       'bundle' => $bundle->name,
       'bundle' => $bundle->name,
-      'label' => 'Type',
-      'description' => 'Select a type for this record.',
+      'label' => 'Publication Type',
+      'description' => 'Select the publication type.',
       'required' => $is_required,
       'required' => $is_required,
       'settings' => array(
       'settings' => array(
         'auto_attach' => TRUE,
         'auto_attach' => TRUE,
         'chado_table' => $table_name,
         'chado_table' => $table_name,
         'chado_column' => 'type_id',
         'chado_column' => 'type_id',
         'base_table' => $table_name,
         'base_table' => $table_name,
+        'vocabulary' => 'tripal_pub',
+        'parent_term' => 'TPUB:0000015',
       ),
       ),
       'widget' => array(
       'widget' => array(
         'type' => 'schema__additional_type_widget',
         'type' => 'schema__additional_type_widget',
@@ -1212,71 +1283,71 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
   }
   }
 
 
 
 
-  // GENE TRANSCRIPTS
-  $rel_table = $table_name . '_relationship';
-  if (chado_table_exists($rel_table) and $bundle->label == 'gene') {
-    $field_name = 'so__transcript';
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Transcripts',
-      'description' => 'Transcripts that are part of this gene.',
-      'required' => FALSE,
-      'settings' => array(
-        'auto_attach' => FALSE,
-        'chado_table' => $rel_table,
-        'chado_column' => '',
-        'base_table' => $table_name,
-      ),
-      'widget' => array(
-        'type' => 'so__transcript_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'above',
-          'type' => 'so__transcript_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
-
-  // ORGANISM TYPE_ID
-//   if ($table_name == 'organism' and array_key_exists('type_id', $schema['fields'])) {
-//     $field_name = 'taxarank__infraspecific_taxon';
+//   // GENE TRANSCRIPTS
+//   $rel_table = $table_name . '_relationship';
+//   if (chado_table_exists($rel_table) and $bundle->label == 'gene') {
+//     $field_name = 'so__transcript';
 //     $info[$field_name] = array(
 //     $info[$field_name] = array(
 //       'field_name' => $field_name,
 //       'field_name' => $field_name,
 //       'entity_type' => $entity_type,
 //       'entity_type' => $entity_type,
 //       'bundle' => $bundle->name,
 //       'bundle' => $bundle->name,
-//       'label' => 'Infraspecific Taxon',
-//       'description' => 'The Infraspecific Taxon.',
+//       'label' => 'Transcripts',
+//       'description' => 'Transcripts that are part of this gene.',
 //       'required' => FALSE,
 //       'required' => FALSE,
 //       'settings' => array(
 //       'settings' => array(
-//         'auto_attach' => TRUE,
-//         'chado_table' => 'organism',
-//         'chado_column' => 'type_id',
-//         'base_table' => 'organism',
+//         'auto_attach' => FALSE,
+//         'chado_table' => $rel_table,
+//         'chado_column' => '',
+//         'base_table' => $table_name,
 //       ),
 //       ),
 //       'widget' => array(
 //       'widget' => array(
-//         'type' => 'taxarank__infraspecific_taxon_widget',
+//         'type' => 'so__transcript_widget',
 //         'settings' => array(
 //         'settings' => array(
 //           'display_label' => 1,
 //           'display_label' => 1,
 //         ),
 //         ),
 //       ),
 //       ),
 //       'display' => array(
 //       'display' => array(
 //         'default' => array(
 //         'default' => array(
-//           'label' => 'inline',
-//           'type' => 'taxarank__infraspecific_taxon_formatter',
+//           'label' => 'above',
+//           'type' => 'so__transcript_formatter',
 //           'settings' => array(),
 //           'settings' => array(),
 //         ),
 //         ),
 //       ),
 //       ),
 //     );
 //     );
 //   }
 //   }
 
 
+  // ORGANISM TYPE_ID
+  if ($table_name == 'organism' and array_key_exists('type_id', $schema['fields'])) {
+    $field_name = 'taxrank__infraspecific_taxon';
+    $info[$field_name] = array(
+      'field_name' => $field_name,
+      'entity_type' => $entity_type,
+      'bundle' => $bundle->name,
+      'label' => 'Infraspecific Taxon',
+      'description' => 'The Infraspecific Taxon.',
+      'required' => FALSE,
+      'settings' => array(
+        'auto_attach' => TRUE,
+        'chado_table' => 'organism',
+        'chado_column' => 'type_id',
+        'base_table' => 'organism',
+      ),
+      'widget' => array(
+        'type' => 'taxrank__infraspecific_taxon_widget',
+        'settings' => array(
+          'display_label' => 1,
+        ),
+      ),
+      'display' => array(
+        'default' => array(
+          'label' => 'inline',
+          'type' => 'taxrank__infraspecific_taxon_formatter',
+          'settings' => array(),
+        ),
+      ),
+    );
+  }
+
 
 
   // FEATURE SEQLEN
   // FEATURE SEQLEN
   if ($table_name == 'featuremap') {
   if ($table_name == 'featuremap') {
@@ -1555,75 +1626,75 @@ function tripal_chado_bundle_instances_info_linker(&$info, $entity_type, $bundle
     );
     );
   }
   }
 
 
-  // GENOTYPE
-  $genotype_table = $table_name . '_genotype';
-  if (chado_table_exists($genotype_table)) {
-    $field_name = 'so__genotype';
-    $schema = chado_get_schema($genotype_table);
-    $pkey = $schema['primary key'][0];
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Genotype',
-      'description' => 'The genotypes associated with this record.',
-      'required' => FALSE,
-      'settings' => array(
-        'auto_attach' => FALSE,
-        'chado_table' => $genotype_table,
-        'chado_column' => $pkey,
-        'base_table' => $table_name,
-      ),
-      'widget' => array(
-        'type' => 'so__genotype_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'hidden',
-          'type' => 'so__genotype_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
+//   // GENOTYPE
+//   $genotype_table = $table_name . '_genotype';
+//   if (chado_table_exists($genotype_table)) {
+//     $field_name = 'so__genotype';
+//     $schema = chado_get_schema($genotype_table);
+//     $pkey = $schema['primary key'][0];
+//     $info[$field_name] = array(
+//       'field_name' => $field_name,
+//       'entity_type' => $entity_type,
+//       'bundle' => $bundle->name,
+//       'label' => 'Genotype',
+//       'description' => 'The genotypes associated with this record.',
+//       'required' => FALSE,
+//       'settings' => array(
+//         'auto_attach' => FALSE,
+//         'chado_table' => $genotype_table,
+//         'chado_column' => $pkey,
+//         'base_table' => $table_name,
+//       ),
+//       'widget' => array(
+//         'type' => 'so__genotype_widget',
+//         'settings' => array(
+//           'display_label' => 1,
+//         ),
+//       ),
+//       'display' => array(
+//         'default' => array(
+//           'label' => 'hidden',
+//           'type' => 'so__genotype_formatter',
+//           'settings' => array(),
+//         ),
+//       ),
+//     );
+//   }
 
 
-  // PHENOTYPE
-  $phenotype_table = $table_name . '_phenotype';
-  if (chado_table_exists($phenotype_table)) {
-    $field_name = 'sbo__phenotype';
-    $schema = chado_get_schema($phenotype_table);
-    $pkey = $schema['primary key'][0];
-    $info[$field_name] = array(
-      'field_name' => $field_name,
-      'entity_type' => $entity_type,
-      'bundle' => $bundle->name,
-      'label' => 'Phenotype',
-      'description' => 'The phenotypes associated with this record.',
-      'required' => FALSE,
-      'settings' => array(
-        'auto_attach' => FALSE,
-        'chado_table' => $phenotype_table,
-        'chado_column' => $pkey,
-        'base_table' => $table_name,
-      ),
-      'widget' => array(
-        'type' => 'sbo__phenotype_widget',
-        'settings' => array(
-          'display_label' => 1,
-        ),
-      ),
-      'display' => array(
-        'default' => array(
-          'label' => 'hidden',
-          'type' => 'sbo__phenotype_formatter',
-          'settings' => array(),
-        ),
-      ),
-    );
-  }
+//   // PHENOTYPE
+//   $phenotype_table = $table_name . '_phenotype';
+//   if (chado_table_exists($phenotype_table)) {
+//     $field_name = 'sbo__phenotype';
+//     $schema = chado_get_schema($phenotype_table);
+//     $pkey = $schema['primary key'][0];
+//     $info[$field_name] = array(
+//       'field_name' => $field_name,
+//       'entity_type' => $entity_type,
+//       'bundle' => $bundle->name,
+//       'label' => 'Phenotype',
+//       'description' => 'The phenotypes associated with this record.',
+//       'required' => FALSE,
+//       'settings' => array(
+//         'auto_attach' => FALSE,
+//         'chado_table' => $phenotype_table,
+//         'chado_column' => $pkey,
+//         'base_table' => $table_name,
+//       ),
+//       'widget' => array(
+//         'type' => 'sbo__phenotype_widget',
+//         'settings' => array(
+//           'display_label' => 1,
+//         ),
+//       ),
+//       'display' => array(
+//         'default' => array(
+//           'label' => 'hidden',
+//           'type' => 'sbo__phenotype_formatter',
+//           'settings' => array(),
+//         ),
+//       ),
+//     );
+//   }
 
 
   // PROPERTIES
   // PROPERTIES
   $prop_table = $table_name . 'prop';
   $prop_table = $table_name . 'prop';
@@ -1695,6 +1766,13 @@ function tripal_chado_bundle_instances_info_linker(&$info, $entity_type, $bundle
        while ($prop = $props->fetchObject()) {
        while ($prop = $props->fetchObject()) {
 
 
          $term = chado_generate_var('cvterm', array('cvterm_id' => $prop->type_id));
          $term = chado_generate_var('cvterm', array('cvterm_id' => $prop->type_id));
+         $term = chado_expand_var($term, 'field', 'cvterm.definition');
+
+         // Skip the Publiation Type property for pubs as this is
+         // already handled by the pub.type_id field.
+         if ($term->name == 'Publication Type' and $term->cv_id->name == 'tripal_pub') {
+           continue;
+         }
 
 
          // The tripal_analysis_KEGG, tripal_analysis_blast, and
          // The tripal_analysis_KEGG, tripal_analysis_blast, and
          // tripal_analysis_interpro modules store results in the analysisprop
          // tripal_analysis_interpro modules store results in the analysisprop
@@ -1738,10 +1816,63 @@ function tripal_chado_bundle_instances_info_linker(&$info, $entity_type, $bundle
              ),
              ),
            ),
            ),
          );
          );
+
+         // Make some customizations to some fields
+         if ($term->name == 'Citation' and $term->cv_id->name == 'tripal_pub') {
+           $info[$field_name]['required'] = TRUE;
+           $info[$field_name]['description'] = t('All publications must have a unique citation.
+            Please enter the full citation for this publication.  For PubMed style citations list
+            the last name of the author followed by initials. Each author should be separated by a comma. Next comes
+            the title, followed by the series title (e.g. journal name), publication date (4 digit year, 3 character Month, day), volume, issue and page numbers. You may also use HTML to provide a link in the citation.
+            Below is an example: <pre>Medeiros PM, Ladio AH, Santos AM, Albuquerque UP. <a href="http://www.ncbi.nlm.nih.gov/pubmed/23462414" target="_blank">Does the selection of medicinal plants by Brazilian local populations
+              suffer taxonomic influence?</a> J Ethnopharmacol. 2013 Apr 19; 146(3):842-52.</pre>');
+           $info[$field_name]['settings']['rows'] = 3;
+         }
+         if ($term->name == 'Abstract' and $term->cv_id->name == 'tripal_pub') {
+           $info[$field_name]['settings']['rows'] = 5;
+         }
        }
        }
      }
      }
    }
    }
 
 
+  // CVTERMS
+  $term_table = $table_name . '_cvterm';
+  if (chado_table_exists($term_table)) {
+    $schema = chado_get_schema($term_table);
+    $pkey = $schema['primary key'][0];
+    $lkey = key($schema['foreign keys'][$table_name]['columns']);
+    $rkey = $schema['foreign keys'][$table_name]['columns'][$lkey];
+
+    $field_name = 'sio__annotation';
+    $info[$field_name] = array(
+      'field_name' => $field_name,
+      'entity_type' => $entity_type,
+      'bundle' => $bundle->name,
+      'label' => 'Annotations',
+      'description' => 'Annotations that are associated with this record.',
+      'required' => FALSE,
+      'settings' => array(
+        'auto_attach' => FALSE,
+        'chado_table' => $term_table,
+        'chado_column' => $pkey,
+        'base_table' => $table_name,
+      ),
+      'widget' => array(
+        'type' => 'sio__annotation_widget',
+        'settings' => array(
+          'display_label' => 1,
+        ),
+      ),
+      'display' => array(
+        'default' => array(
+          'label' => 'hidden',
+          'type' => 'sio__annotation_formatter',
+          'settings' => array(),
+        ),
+      ),
+    );
+  }
+
 
 
   // PUBLICATIONS
   // PUBLICATIONS
   $pub_table = $table_name . '_pub';
   $pub_table = $table_name . '_pub';

+ 2 - 4
tripal_chado/includes/tripal_chado.publish.inc

@@ -2,8 +2,7 @@
 
 
 function tripal_chado_publish_form($form, &$form_state) {
 function tripal_chado_publish_form($form, &$form_state) {
 
 
-  global $language;
-  $langcode = $language->language;
+  $langcode = 'und';
 
 
   $bundle_name = '';
   $bundle_name = '';
   if (array_key_exists('values', $form_state)) {
   if (array_key_exists('values', $form_state)) {
@@ -141,9 +140,8 @@ function tripal_chado_publish_form_validate($form, &$form_state) {
 function tripal_chado_publish_form_submit($form, &$form_state) {
 function tripal_chado_publish_form_submit($form, &$form_state) {
   if ($form_state['clicked_button']['#name'] == 'publish_btn') {
   if ($form_state['clicked_button']['#name'] == 'publish_btn') {
     global $user;
     global $user;
-    global $language;
 
 
-    $langcode = $language->language;
+    $langcode = 'und';
 
 
     $bundle_name = $form_state['values']['bundle_name'];
     $bundle_name = $form_state['values']['bundle_name'];
     $bundle = tripal_load_bundle_entity(array('name' => $bundle_name));
     $bundle = tripal_load_bundle_entity(array('name' => $bundle_name));

+ 61 - 13
tripal_chado/includes/tripal_chado.semweb.inc

@@ -27,6 +27,7 @@ function tripal_chado_populate_chado_semweb_table() {
   tripal_chado_populate_vocab_IAO();
   tripal_chado_populate_vocab_IAO();
   tripal_chado_populate_vocab_LOCAL();
   tripal_chado_populate_vocab_LOCAL();
   tripal_chado_populate_vocab_NCBITAXON();
   tripal_chado_populate_vocab_NCBITAXON();
+  tripal_chado_populate_vocab_OBCS();
   tripal_chado_populate_vocab_OBI();
   tripal_chado_populate_vocab_OBI();
   tripal_chado_populate_vocab_OGI();
   tripal_chado_populate_vocab_OGI();
   tripal_chado_populate_vocab_RDFS();
   tripal_chado_populate_vocab_RDFS();
@@ -201,7 +202,7 @@ function tripal_chado_populate_vocab_SCHEMA() {
     'cv_name' => 'schema',
     'cv_name' => 'schema',
     'definition' => 'URL of the item.',
     'definition' => 'URL of the item.',
   ));
   ));
-  tripal_associate_chado_semweb_term('db', 'URL', $term);
+  tripal_associate_chado_semweb_term('db', 'url', $term);
 
 
   // Typically the type_id field is used for distinguishing between records
   // Typically the type_id field is used for distinguishing between records
   // but in the case that it isn't then we need to associate a term with it
   // but in the case that it isn't then we need to associate a term with it
@@ -270,6 +271,34 @@ function tripal_chado_populate_vocab_SIO() {
   ));
   ));
   tripal_associate_chado_semweb_term('featurepos', 'mappos', $term);
   tripal_associate_chado_semweb_term('featurepos', 'mappos', $term);
 
 
+  $term = tripal_insert_cvterm(array(
+    'id' => 'SIO:001166',
+    'name' => 'annotation',
+    'cv_name' => 'SIO',
+    'definition' => 'An annotation is a written explanatory or critical description, or other in-context information (e.g., pattern, motif, link), that has been associated with data or other types of information.',
+  ));
+  tripal_associate_chado_semweb_term('feature_cvterm', 'cvterm_id', $term);
+  tripal_associate_chado_semweb_term('analysis_cvterm', 'cvterm_id', $term);
+  tripal_associate_chado_semweb_term('cell_line_cvterm', 'cvterm_id', $term);
+  tripal_associate_chado_semweb_term('environment_cvterm', 'cvterm_id', $term);
+  tripal_associate_chado_semweb_term('expression_cvterm', 'cvterm_id', $term);
+  tripal_associate_chado_semweb_term('library_cvterm', 'cvterm_id', $term);
+  tripal_associate_chado_semweb_term('organism_cvterm', 'cvterm_id', $term);
+  tripal_associate_chado_semweb_term('phenotype_cvterm', 'cvterm_id', $term);
+  tripal_associate_chado_semweb_term('stock_cvterm', 'cvterm_id', $term);
+  tripal_associate_chado_semweb_term('stock_relationship_cvterm', 'cvterm_id', $term);
+
+
+  $term = tripal_insert_cvterm(array(
+    'id' => 'SIO:000281',
+    'name' => 'negation',
+    'cv_name' => 'SIO',
+    'definition' => 'NOT is a logical operator in that has the value true if its operand is false.',
+  ));
+  tripal_associate_chado_semweb_term('feature_cvterm', 'is_not', $term);
+  tripal_associate_chado_semweb_term('analysis_cvterm', 'is_not', $term);
+  tripal_associate_chado_semweb_term('organism_cvterm', 'is_not', $term);
+  tripal_associate_chado_semweb_term('stock_cvterm', 'is_not', $term);
 
 
   $term = tripal_insert_cvterm(array(
   $term = tripal_insert_cvterm(array(
     'id' => 'SIO:001080',
     'id' => 'SIO:001080',
@@ -513,6 +542,29 @@ function tripal_chado_populate_vocab_ERO() {
   ));
   ));
 }
 }
 
 
+/**
+ * Adds the Information Artifact Ontology database and terms.
+ */
+function tripal_chado_populate_vocab_OBCS() {
+  tripal_insert_db(array(
+    'name' => 'OBCS',
+    'description' => 'Ontology of Biological and Clinical Statistics.',
+    'url' => 'https://github.com/obcs/obcs',
+    'urlprefix' => 'http://purl.obolibrary.org/obo/{db}_{accession}',
+  ));
+  tripal_insert_cv(
+    'OBCS',
+    'Ontology of Biological and Clinical Statistics.'
+  );
+
+  $term = tripal_insert_cvterm(array(
+    'id' => 'OBCS:0000117',
+    'name' => 'rank order',
+    'cv_name' => 'OBCS',
+    'definition' => 'A data item that represents an arrangement according to a rank, i.e., the position of a particular case relative to other cases on a defined scale.',
+  ));
+  tripal_associate_chado_semweb_term(NULL, 'rank', $term);
+}
 /**
 /**
  * Adds the Information Artifact Ontology database and terms.
  * Adds the Information Artifact Ontology database and terms.
  */
  */
@@ -569,7 +621,7 @@ function tripal_chado_populate_vocab_IAO() {
     'name' => 'IAO',
     'name' => 'IAO',
     'description' => 'The Information Artifact Ontology (IAO).',
     'description' => 'The Information Artifact Ontology (IAO).',
     'url' => 'https://github.com/information-artifact-ontology/IAO/',
     'url' => 'https://github.com/information-artifact-ontology/IAO/',
-    'urlprefix' => 'http://purl.obolibrary.org/obo/IAO_',
+    'urlprefix' => 'http://purl.obolibrary.org/obo/{db}_{accession}',
   ));
   ));
   tripal_insert_cv(
   tripal_insert_cv(
     'IAO',
     'IAO',
@@ -838,6 +890,13 @@ function tripal_chado_populate_vocab_LOCAL() {
   ));
   ));
   tripal_associate_chado_semweb_term(NULL, 'is_obsolete', $term);
   tripal_associate_chado_semweb_term(NULL, 'is_obsolete', $term);
 
 
+  $term = tripal_insert_cvterm(array(
+    'id' => 'local:miniref',
+    'name' => 'Mini-ref',
+    'definition' => 'A small in-house unique identifier for a publication.',
+    'cv_name' => 'local',
+  ));
+  tripal_associate_chado_semweb_term('pub', 'miniref', $term);
 
 
   //-----------------------------
   //-----------------------------
   // Relationship Terms
   // Relationship Terms
@@ -1197,17 +1256,6 @@ function tripal_chado_populate_vocab_LOCAL() {
   ));
   ));
   tripal_associate_chado_semweb_term('featureloc', 'fmax', $term);
   tripal_associate_chado_semweb_term('featureloc', 'fmax', $term);
 
 
-  $term = tripal_insert_cvterm(array(
-    'id' => 'local:unknown_fmin',
-    'name' => ' minimal boundary',
-    'definition' => 'The leftmost, minimal boundary in the linear range ' .
-    'represented by the feature location. Sometimes this is called ' .
-    'start although this is confusing because it does not necessarily ' .
-    'represent the 5-prime coordinate.',
-    'cv_name' => 'local',
-  ));
-  tripal_associate_chado_semweb_term('featureloc', 'fmin', $term);
-
 
 
   //--------------
   //--------------
   // Analysis Terms
   // Analysis Terms

+ 1 - 0
tripal_chado/theme/css/tripal_chado.css

@@ -2,6 +2,7 @@
 
 
 .synonym-widget-item,
 .synonym-widget-item,
 .primary-dbxref-widget-item,
 .primary-dbxref-widget-item,
+.sio--annotation-item,
 .secondary-dbxref-widget-item,
 .secondary-dbxref-widget-item,
 .kvproperty-adder-widget-item,
 .kvproperty-adder-widget-item,
 .chado-linker--relationship-widget-item,
 .chado-linker--relationship-widget-item,

+ 130 - 0
tripal_chado/tripal_chado.install

@@ -1071,4 +1071,134 @@ function tripal_chado_update_7308() {
   }
   }
 }
 }
 
 
+/**
+ * Add cvterm 'annotation' and maps to cvterm linking tables.
+ */
+function tripal_chado_update_7309() {
+  try {
+    $term = tripal_insert_cvterm(array(
+      'id' => 'SIO:001166',
+      'name' => 'annotation',
+      'cv_name' => 'SIO',
+      'definition' => 'An annotation is a written explanatory or critical description, or other in-context information (e.g., pattern, motif, link), that has been associated with data or other types of information.',
+    ));
+    tripal_associate_chado_semweb_term('feature_cvterm', 'cvterm_id', $term);
+    tripal_associate_chado_semweb_term('analysis_cvterm', 'cvterm_id', $term);
+    tripal_associate_chado_semweb_term('cell_line_cvterm', 'cvterm_id', $term);
+    tripal_associate_chado_semweb_term('environment_cvterm', 'cvterm_id', $term);
+    tripal_associate_chado_semweb_term('expression_cvterm', 'cvterm_id', $term);
+    tripal_associate_chado_semweb_term('library_cvterm', 'cvterm_id', $term);
+    tripal_associate_chado_semweb_term('organism_cvterm', 'cvterm_id', $term);
+    tripal_associate_chado_semweb_term('phenotype_cvterm', 'cvterm_id', $term);
+    tripal_associate_chado_semweb_term('stock_cvterm', 'cvterm_id', $term);
+    tripal_associate_chado_semweb_term('stock_relationship_cvterm', 'cvterm_id', $term);
+
+
+    $term = tripal_insert_cvterm(array(
+      'id' => 'SIO:000281',
+      'name' => 'negation',
+      'cv_name' => 'SIO',
+      'definition' => 'NOT is a logical operator in that has the value true if its operand is false.',
+    ));
+    tripal_associate_chado_semweb_term('feature_cvterm', 'is_not', $term);
+    tripal_associate_chado_semweb_term('analysis_cvterm', 'is_not', $term);
+    tripal_associate_chado_semweb_term('organism_cvterm', 'is_not', $term);
+    tripal_associate_chado_semweb_term('stock_cvterm', 'is_not', $term);
+  }
+  catch (\PDOException $e) {
+    $error = $e->getMessage();
+    throw new DrupalUpdateException('Could not perform update: '. $error);
+  }
+}
+/**
+ * Adds the 'OBCS' and rank order term.
+ */
+function tripal_chado_update_7310() {
+  try {
+    tripal_insert_db(array(
+      'name' => 'OBCS',
+      'description' => 'Ontology of Biological and Clinical Statistics.',
+      'url' => 'https://github.com/obcs/obcs',
+      'urlprefix' => 'http://purl.obolibrary.org/obo/{db}_{accession}',
+    ));
+    tripal_insert_cv(
+        'OBCS',
+        'Ontology of Biological and Clinical Statistics.'
+    );
+
+    $term = tripal_insert_cvterm(array(
+      'id' => 'OBCS:0000117',
+      'name' => 'rank order',
+      'cv_name' => 'OBCS',
+      'definition' => 'A data item that represents an arrangement according to a rank, i.e., the position of a particular case relative to other cases on a defined scale.',
+    ));
+    tripal_associate_chado_semweb_term(NULL, 'rank', $term);
+  }
+  catch (\PDOException $e) {
+    $error = $e->getMessage();
+    throw new DrupalUpdateException('Could not perform update: '. $error);
+  }
+}
+/**
+ * Fix a mistake with the association of the term with featureloc.fmin.
+ */
+function tripal_chado_update_7311() {
+  try {
+    $term = tripal_insert_cvterm(array(
+      'id' => 'local:fmin',
+      'name' => 'minimal boundary',
+      'definition' => 'The leftmost, minimal boundary in the linear range ' .
+        'represented by the feature location. Sometimes this is called ' .
+        'start although this is confusing because it does not necessarily ' .
+        'represent the 5-prime coordinate.',
+      'cv_name' => 'local',
+    ));
+    tripal_associate_chado_semweb_term('featureloc', 'fmin', $term);
+  }
+  catch (\PDOException $e) {
+    $error = $e->getMessage();
+    throw new DrupalUpdateException('Could not perform update: '. $error);
+  }
+}
+/**
+ * Associates a local term with the pub.miniref column.
+ */
+function tripal_chado_update_7312() {
+  try {
 
 
+    $term = tripal_insert_cvterm(array(
+      'id' => 'local:miniref',
+      'name' => 'Mini-ref',
+      'definition' => 'A small in-house unique identifier for a publication.',
+      'cv_name' => 'local',
+    ));
+    tripal_associate_chado_semweb_term('pub', 'miniref', $term);
+    $term = tripal_insert_cvterm(array(
+      'id' => 'schema:url',
+      'name' => 'url',
+      'cv_name' => 'schema',
+      'definition' => 'URL of the item.',
+    ));
+    tripal_associate_chado_semweb_term('db', 'url', $term);
+  }
+  catch (\PDOException $e) {
+    $error = $e->getMessage();
+    throw new DrupalUpdateException('Could not perform update: '. $error);
+  }
+}
+
+/**
+ * Run the cvtermpath for the Tripal Pub and Contact ontologies.
+ */
+function tripal_chado_update_7313() {
+  try {
+    $cv = tripal_get_cv(array('name' => 'tripal_pub'));
+    tripal_update_cvtermpath($cv->cv_id);
+    $cv = tripal_get_cv(array('name' => 'tripal_contact'));
+    tripal_update_cvtermpath($cv->cv_id);
+  }
+  catch (\PDOException $e) {
+    $error = $e->getMessage();
+    throw new DrupalUpdateException('Could not perform update: '. $error);
+  }
+}

+ 1 - 1
tripal_chado/tripal_chado.module

@@ -644,7 +644,7 @@ function tripal_chado_menu() {
     'title' => 'Edit a Database Reference',
     'title' => 'Edit a Database Reference',
     'description' => 'Edit existing Database References.',
     'description' => 'Edit existing Database References.',
     'page callback' => 'drupal_get_form',
     'page callback' => 'drupal_get_form',
-    'page arguments' => array('tripal_chado_db_edit_form',6),
+    'page arguments' => array('tripal_chado_db_edit_form', 5),
     'access callback' => 'user_access',
     'access callback' => 'user_access',
     'access arguments' => array('administer db cross-references'),
     'access arguments' => array('administer db cross-references'),
     'file' => 'includes/tripal_chado.db.inc',
     'file' => 'includes/tripal_chado.db.inc',

+ 0 - 4
tripal_chado/tripal_chado.views_default.inc

@@ -506,10 +506,6 @@ function tripal_chado_defaultview_admin_cvs_listing() {
     'label-1' => 'Add Vocabulary',
     'label-1' => 'Add Vocabulary',
     'path-1' => 'admin/tripal/loaders/chado_cv/add',
     'path-1' => 'admin/tripal/loaders/chado_cv/add',
   );
   );
-  $handler->display->display_options['header']['action_links_area']['link-2'] = array(
-    'label-2' => 'Load Ontology',
-    'path-2' => 'admin/tripal/vocab/obo_loader',
-  );
   /* No results behavior: Global: Text area */
   /* No results behavior: Global: Text area */
   $handler->display->display_options['empty']['text']['id'] = 'area';
   $handler->display->display_options['empty']['text']['id'] = 'area';
   $handler->display->display_options['empty']['text']['table'] = 'views';
   $handler->display->display_options['empty']['text']['table'] = 'views';

+ 11 - 3
tripal_ds/includes/tripal_ds.ds.inc

@@ -300,10 +300,10 @@ function _ds_layout_pub_settings_info($bundle_name, $instances) {
         field_update_instance($instance);
         field_update_instance($instance);
       }
       }
       elseif($instance_name == 'tpub__publication_type' || $instance_name == 'tpub__doi' || $instance_name == 'tpub__publication_date') {
       elseif($instance_name == 'tpub__publication_type' || $instance_name == 'tpub__doi' || $instance_name == 'tpub__publication_date') {
-        array_push($properties, $instance);
+        array_push($properties, $instance_name);
       }
       }
       else {
       else {
-        array_push($disabled_instances, $instance);
+        array_push($disabled_instances, $instance_name);
       }
       }
 
 
     }
     }
@@ -317,7 +317,7 @@ function _ds_layout_pub_settings_info($bundle_name, $instances) {
       // updating fields here to ensure name consistency.
       // updating fields here to ensure name consistency.
       $group_field_name = substr($group_field_name, 0, 27);
       $group_field_name = substr($group_field_name, 0, 27);
 
 
-      // Add randomm numbers to ensure the field name is unique within the 32
+      // Add random numbers to ensure the field name is unique within the 32
       // character limit of the field.
       // character limit of the field.
       $group_field_name = $group_field_name.rand(0, 99999);
       $group_field_name = $group_field_name.rand(0, 99999);
 
 
@@ -337,6 +337,11 @@ function _ds_layout_pub_settings_info($bundle_name, $instances) {
       $region_right = array_merge($region_right, $properties);
       $region_right = array_merge($region_right, $properties);
       $all_fields+= [ 'group_prop_tripalpane' => 'right', 'group_prop_table' => 'right' ];
       $all_fields+= [ 'group_prop_tripalpane' => 'right', 'group_prop_table' => 'right' ];
     }
     }
+    if(!empty($all_fields)){
+      foreach ($disabled_instances as $disabled_field) {
+        $all_fields += [$disabled_field => 'disabled'];
+      }
+    }
 
 
     // Add blocks to $region_left and build the toc field that is placed within.
     // Add blocks to $region_left and build the toc field that is placed within.
     _ds_fields_info_write($bundle_name);
     _ds_fields_info_write($bundle_name);
@@ -372,6 +377,9 @@ function _ds_layout_pub_settings_info($bundle_name, $instances) {
     );
     );
     $record->settings = $settings;
     $record->settings = $settings;
     drupal_write_record('ds_layout_settings', $record);
     drupal_write_record('ds_layout_settings', $record);
+    // Clear the Drpual chace
+    cache_clear_all();
+    watchdog('debug', '<pre>$record: '. print_r($record, TRUE) .'</pre>');
   }
   }
   catch (Exception $e) {
   catch (Exception $e) {
     watchdog_exception('tripal_ds', $e);
     watchdog_exception('tripal_ds', $e);

+ 0 - 1
tripal_ds/tripal_ds.install

@@ -79,7 +79,6 @@ function tripal_ds_disable(){
   $output .= '</ul>';
   $output .= '</ul>';
   if(!empty($entities_with_tripal_panes)){
   if(!empty($entities_with_tripal_panes)){
     drupal_set_message($output, 'warning');
     drupal_set_message($output, 'warning');
-
   }
   }
 }
 }
 
 

+ 16 - 5
tripal_ws/includes/TripalWebService.inc

@@ -62,7 +62,7 @@ class TripalWebService {
    */
    */
   public function __construct($base_path) {
   public function __construct($base_path) {
     if (!$base_path) {
     if (!$base_path) {
-      throw new Exception('Pleaes provide a $base_path argument when creating a new TripalWebService.');
+      throw new Exception('Please provide a $base_path argument when creating a new TripalWebService.');
     }
     }
 
 
     // Create a default resource so that the service always some something.
     // Create a default resource so that the service always some something.
@@ -190,11 +190,7 @@ class TripalWebService {
       '@id' => '',
       '@id' => '',
       '@type' => $type,
       '@type' => $type,
     );
     );
-
-    // Get the data array and set the IRIs fore each ID.
     $data = $this->getData();
     $data = $this->getData();
-    //$this->setIDs($data);
-
     return array_merge($json_ld, $data);
     return array_merge($json_ld, $data);
   }
   }
 
 
@@ -255,4 +251,19 @@ class TripalWebService {
     $this->resource->addContextItem('error', 'rdfs:error');
     $this->resource->addContextItem('error', 'rdfs:error');
     $this->resource->addProperty('error', $message);
     $this->resource->addProperty('error', $message);
   }
   }
+
+  /**
+   * Retrieves an array contining the supported classes.
+   *
+   * Supported classe are resources provided by this web services and the
+   * operations supported by those classes.
+   *
+   * @return
+   *   An array of TripalWebServiceResource objects that follow the Hydra
+   *   documentation for documenting supported classes.
+   */
+  public function getSupportedClasses() {
+     $supported_classes = array();
+     return $supported_classes;
+  }
 }
 }

+ 0 - 19
tripal_ws/includes/TripalWebService/TripalDocService_V0_1.inc

@@ -1,19 +0,0 @@
-<?php
-
-class TripalDocService_v0_1 extends TripalWebService {
-
-  /**
-   * The human-readable label for this web service.
-   */
-  public static $label = 'API Documentation';
-  /**
-   * A bit of text to describe what this service provides.
-   */
-  public static $description = 'Provides documentation for the use of this web services.';
-  /**
-   * A machine-readable type for this service. This name must be unique
-   * among all Tripal web services and is used to form the URL to access
-   * this service.
-   */
-  public static $type = 'doc';
-}

+ 546 - 116
tripal_ws/includes/TripalWebService/TripalEntityService_v0_1.inc

@@ -6,13 +6,15 @@ class TripalEntityService_v0_1 extends TripalWebService {
    * The human-readable label for this web service.
    * The human-readable label for this web service.
    */
    */
   public static $label = 'Content Types';
   public static $label = 'Content Types';
+
   /**
   /**
    * A bit of text to describe what this service provides.
    * A bit of text to describe what this service provides.
    */
    */
-  public static $description = 'Provides acesss to the biological and ' .
-    'ancilliary data available on this site. Each content type represents ' .
-    'biological data that is defined in a controlled vocabulary (e.g. ' .
-    'Sequence Ontology term: gene (SO:0000704)).';
+  public static $description = 'Provides acesss to the biological and
+    ancilliary data available on this site. Each content type represents
+    biological data that is defined in a controlled vocabulary (e.g.
+    Sequence Ontology term: gene (SO:0000704)).';
+
   /**
   /**
    * A machine-readable type for this service. This name must be unique
    * A machine-readable type for this service. This name must be unique
    * among all Tripal web services and is used to form the URL to access
    * among all Tripal web services and is used to form the URL to access
@@ -61,7 +63,7 @@ class TripalEntityService_v0_1 extends TripalWebService {
    */
    */
   private function doExpandedField($ctype, $entity_id, $expfield) {
   private function doExpandedField($ctype, $entity_id, $expfield) {
     $service_path = $this->getServicePath() . '/' . urlencode($ctype) . '/' . $entity_id;
     $service_path = $this->getServicePath() . '/' . urlencode($ctype) . '/' . $entity_id;
-    $this->resource = new TripalWebServiceResource($service_path);
+    $this->resource = new TripalWebServiceResource($service_path, $this->doc_path);
 
 
     // Get the TripalBundle, TripalTerm and TripalVocab for this type.
     // Get the TripalBundle, TripalTerm and TripalVocab for this type.
     $bundle = tripal_load_bundle_entity(array('label' => $ctype));
     $bundle = tripal_load_bundle_entity(array('label' => $ctype));
@@ -75,9 +77,13 @@ class TripalEntityService_v0_1 extends TripalWebService {
 
 
     // If we couldn't match this field argument to a field and entity then return
     // If we couldn't match this field argument to a field and entity then return
     if (!$entity) {
     if (!$entity) {
-      throw new Exception("Cannot find this entity.");
+      throw new Exception("Cannot find this record.");
     }
     }
 
 
+    // Check that the user has access to this entity.  If not then the
+    // function call will throw an error.
+    $this->checkAccess($entity);
+
     list($field, $instance, $term) = $this->findField($bundle, $expfield);
     list($field, $instance, $term) = $this->findField($bundle, $expfield);
 
 
     // Next add in the ID and Type for this resources.
     // Next add in the ID and Type for this resources.
@@ -129,10 +135,19 @@ class TripalEntityService_v0_1 extends TripalWebService {
     // Add the vocabulary to the context.
     // Add the vocabulary to the context.
     $this->resource->addContextItem($term->name, $term->url);
     $this->resource->addContextItem($term->name, $term->url);
 
 
-    // Get the TripalEntity
+    // Get the TripalEntity.
     $entity = tripal_load_entity('TripalEntity', array('id' => $entity_id));
     $entity = tripal_load_entity('TripalEntity', array('id' => $entity_id));
     $entity = reset($entity);
     $entity = reset($entity);
 
 
+    // If we couldn't match this field argument to a field and entity then return
+    if (!$entity) {
+      throw new Exception("Cannot find this record.");
+    }
+
+    // Check that the user has access to this entity.  If not then the
+    // function call will throw an error.
+    $this->checkAccess($entity);
+
     $itemPage = tripal_get_term_details('schema', 'ItemPage');
     $itemPage = tripal_get_term_details('schema', 'ItemPage');
     $label = tripal_get_term_details('rdfs', 'label');
     $label = tripal_get_term_details('rdfs', 'label');
     $this->resource->setID($entity_id);
     $this->resource->setID($entity_id);
@@ -148,6 +163,29 @@ class TripalEntityService_v0_1 extends TripalWebService {
 //    tripal_ws_services_v0_1_write_context($response, $ctype);
 //    tripal_ws_services_v0_1_write_context($response, $ctype);
   }
   }
 
 
+  /**
+   * Ensures that user's only have access to content they should see.
+   *
+   * Denies access to an entity if it is unpublished or if the user does
+   * not have permission to see it.
+   *
+   * @param $entity
+   *   The full entity object.
+   *
+   * @throws Exception
+   */
+  private function checkAccess($entity) {
+    global $user;
+
+    if (!tripal_entity_access('view', $entity, $user, 'TripalEntity')) {
+      throw new Exception("Permission Denied.");
+    }
+    // Don't show entities that aren't published
+    if ($entity->status == 0) {
+      throw new Exception("This record is currently unavailable.");
+    }
+  }
+
   /**
   /**
    * Adds the fields as properties of an entity resource.
    * Adds the fields as properties of an entity resource.
    */
    */
@@ -286,7 +324,7 @@ class TripalEntityService_v0_1 extends TripalWebService {
 
 
       // If this is the expanded field page then we need to swap out
       // If this is the expanded field page then we need to swap out
       // the resource for a collection.
       // the resource for a collection.
-      $response = new TripalWebServiceCollection($service_path . '/' . urlencode($expfield));
+      $response = new TripalWebServiceCollection($service_path . '/' . urlencode($expfield), $this->params);
       $label = tripal_get_term_details('rdfs', 'label');
       $label = tripal_get_term_details('rdfs', 'label');
       $response->addContextItem('label', $label['url']);
       $response->addContextItem('label', $label['url']);
       $response->addProperty('label', $instance['label']);
       $response->addProperty('label', $instance['label']);
@@ -327,10 +365,12 @@ class TripalEntityService_v0_1 extends TripalWebService {
     if (is_array($value)) {
     if (is_array($value)) {
       $temp = array();
       $temp = array();
       foreach ($value as $k => $v) {
       foreach ($value as $k => $v) {
+
         // exclude fields that have no values so we can hide them
         // exclude fields that have no values so we can hide them
-        if (empty($v) and $hide_fields == 'hide') {
+        if (!isset($v) and $hide_fields == 'hide') {
           continue;
           continue;
         }
         }
+
         $matches = array();
         $matches = array();
         if (preg_match('/^(.+):(.+)$/', $k, $matches)) {
         if (preg_match('/^(.+):(.+)$/', $k, $matches)) {
           $vocabulary = $matches[1];
           $vocabulary = $matches[1];
@@ -342,7 +382,7 @@ class TripalEntityService_v0_1 extends TripalWebService {
             $temp[$key_adj] = $this->sanitizeFieldKeys($v, $bundle, $service_path);
             $temp[$key_adj] = $this->sanitizeFieldKeys($v, $bundle, $service_path);
           }
           }
           else {
           else {
-            $temp[$key_adj] = $v !== "" ? $v : NULL;
+            $temp[$key_adj] = $v;
           }
           }
           $this->resource->addContextItem($key_adj, $term['url']);
           $this->resource->addContextItem($key_adj, $term['url']);
 
 
@@ -360,7 +400,7 @@ class TripalEntityService_v0_1 extends TripalWebService {
 
 
     }
     }
     else {
     else {
-      $new_value = $value !== "" ? $value : NULL;
+      $new_value = $value;
     }
     }
 
 
     return $new_value;
     return $new_value;
@@ -394,22 +434,16 @@ class TripalEntityService_v0_1 extends TripalWebService {
   }
   }
 
 
   /**
   /**
-   * Creates a collection of resources for a given type.
+   * A helper function to make it easy to map between keys and their fields.
+   *
+   * @bundle
+   *   The bundle object.  Fields attached to this bundle will be included
+   *   in the mapping array.
+   * @return
+   *   An associative arrray that maps web servcies keys to fields and
+   *   fields to web services keys (reciprocol).
    */
    */
-  private function doContentTypeList($ctype) {
-    $service_path = $this->getServicePath() . '/' . urlencode($ctype);
-    $label = tripal_get_term_details('rdfs', 'label');
-    $this->resource = new TripalWebServiceCollection($service_path);
-    $this->resource->addContextItem('label', $label['url']);
-
-    // Get the TripalBundle, TripalTerm and TripalVocab type for this type.
-    $bundle = tripal_load_bundle_entity(array('label' => $ctype));
-    $term = entity_load('TripalTerm', array('id' => $bundle->term_id));
-    $term = reset($term);
-
-    // Set the label for this collection.
-    $this->resource->addProperty('label', $bundle->label . " collection");
-
+  private function getFieldMapping($bundle) {
     // Iterate through the fields and create a $field_mapping array that makes
     // Iterate through the fields and create a $field_mapping array that makes
     // it easier to determine which filter criteria belongs to which field. The
     // it easier to determine which filter criteria belongs to which field. The
     // key is the label for the field and the value is the field name. This way
     // key is the label for the field and the value is the field name. This way
@@ -422,8 +456,8 @@ class TripalEntityService_v0_1 extends TripalWebService {
           if ($bundle_name == $bundle->name) {
           if ($bundle_name == $bundle->name) {
             $instance = field_info_instance('TripalEntity', $field['field_name'], $bundle_name);
             $instance = field_info_instance('TripalEntity', $field['field_name'], $bundle_name);
             if (array_key_exists('term_accession', $instance['settings'])){
             if (array_key_exists('term_accession', $instance['settings'])){
-              $vocabulary = $instance['settings']['term_vocabulary'];
-              $accession = $instance['settings']['term_accession'];
+                $vocabulary = $instance['settings']['term_vocabulary'];
+                $accession = $instance['settings']['term_accession'];
               $fterm = tripal_get_term_details($vocabulary, $accession);
               $fterm = tripal_get_term_details($vocabulary, $accession);
               $key = $fterm['name'];
               $key = $fterm['name'];
               $key = strtolower(preg_replace('/ /', '_', $key));
               $key = strtolower(preg_replace('/ /', '_', $key));
@@ -434,45 +468,171 @@ class TripalEntityService_v0_1 extends TripalWebService {
         }
         }
       }
       }
     }
     }
+    return $field_mapping;
+  }
 
 
-    // Convert the filters to their field names
-    $new_params = array();
-    $order = array();
-    $order_dir = array();
-    $URL_add = array();
-    foreach ($this->params as $param => $value) {
-      $URL_add[] = "$param=$value";
+  /**
+   * Gets any order by statements provided by the user.
+   *
+   * @field_mapping
+   *   An array that maps WS keys to field names. As provided by the
+   *   getFieldMapping() function.
+   * @return
+   *   An array of fields for ordering.
+   *
+   * @throws Exception
+   */
+  private function getOrderBy($field_mapping,  $bundle) {
+    $order_by = array();
 
 
-      // Ignore non filter parameters
-      if ($param == 'page' or $param == 'limit') {
-        continue;
-      }
+    // Handle order separately.
+    if (array_key_exists('order', $this->params)) {
+      $order_params = $this->params['order'];
+      $dir = 'ASC';
 
 
-      // Handle order separately
-      if ($param == 'order') {
-        $temp = explode(',', $value);
-        foreach ($temp as $key) {
-          $matches = array();
-          $dir = 'ASC';
-          // The user can provide a direction by separating the field key and the
-          // direction with a '|' character.
-          if (preg_match('/^(.*)\|(.*)$/', $key, $matches)) {
-            $key = $matches[1];
-            if ($matches[2] == 'ASC' or $matches[2] == 'DESC') {
-              $dir = $matches[2];
+      // If the user provided more than one order statement then those are
+      // separated by a semicolong.
+      $items = explode(';', $order_params);
+      foreach ($items as $key) {
+
+        // The user can provide a direction by separating the field key and the
+        // direction with a '|' character.
+        $matches = array();
+        if (preg_match('/^(.*)\|(.*)$/', $key, $matches)) {
+          $key = $matches[1];
+          if ($matches[2] == 'ASC' or $matches[2] == 'DESC') {
+            $dir = $matches[2];
+          }
+          else {
+            throw new Exception('Please provide "ASC" or "DESC" for the ordering direction');
+          }
+        }
+
+        // Break apart any subkeys and pull the first one as this is the parent
+        // field.
+        $subkeys = explode(',', $key);
+        if (count($subkeys) > 0) {
+          $key = $subkeys[0];
+        }
+
+        if (array_key_exists($key, $field_mapping)) {
+          $key_field_name = $field_mapping[$key];
+          $key_field = field_info_field($key_field_name);
+          $key_instance = field_info_instance('TripalEntity', $key_field_name, $bundle->name);
+
+          // Complex fields provied by the TripalField class may have sub
+          // elements that support filtering.  We need to see if the user
+          // wants to filter on those.
+          $field_class = $key_field['type'];
+          if (tripal_load_include_field_class($field_class)) {
+            // To find out which fields are sortable we'll call the
+            // webServicesData() function.
+            $key_field = new $field_class($key_field, $key_instance);
+            $ws_data = $key_field->webServicesData();
+            $sortable_keys = $ws_data['sortable'];
+            $criteria = implode('.', $subkeys);
+            if (array_key_exists($criteria, $sortable_keys)) {
+              $order_by[$key_field_name][] = array(
+                'column' => $sortable_keys[$criteria],
+                'dir' => $dir,
+              );
             }
             }
             else {
             else {
-              // TODO: handle error of providing an incorrect direction.
+              throw new Exception("The value, '$criteria', is not available for sorting.");
             }
             }
           }
           }
-          if (array_key_exists($key, $field_mapping)) {
-            $order[$field_mapping[$key]] = $key;
-            $order_dir[] = $dir;
-          }
+          // If this field is not a TripalField then it should just have
+          // a simple value and we can query for that.
           else {
           else {
-            // TODO: handle error of providing a non existing field name.
+            $key_field_id = $key_instance['settings']['term_vocabulary'] . ':' . $key_instance['settings']['term_accession'];
+
+            $order_by[$key_field_name][] = array(
+              'column' => $key_field_id,
+              'dir' => $dir,
+            );
+          }
+
+        }
+        else {
+          throw new Exception("The value, '$key', is not available for sorting.");
+        }
+      }
+    }
+
+    // If there is no ordering that is set then set a default order.
+    if (count(array_keys($order_by)) == 0) {
+      $key_field_names = array();
+      if (in_array('data__identifier', $field_mapping)) {
+        $key_field_names['data__identifier'][] = 'identifier';
+      }
+      else if (in_array('schema__name', $field_mapping)) {
+        $key_field_names['schema__name'][] = 'name';
+      }
+      else if (in_array('rdfs_label', $field_mapping)) {
+        $key_field_names['rdfs_label'][] = 'label';
+      }
+      else if (in_array('taxrank__genus', $field_mapping)) {
+        $key_field_names['taxrank__genus'][] = 'genus';
+        $key_field_names['taxrank__species'][] = 'species';
+      }
+      foreach ($key_field_names as $key_field_name => $criteria) {
+        $key_field = field_info_field($key_field_name);
+        $key_instance = field_info_instance('TripalEntity', $key_field_name, $bundle->name);
+        $key_field_id = $key_instance['settings']['term_vocabulary'] . ':' . $key_instance['settings']['term_accession'];
+        $field_class = $key_field['type'];
+        if (tripal_load_include_field_class($field_class)) {
+          // To find out which fields are sortable we'll call the
+          // webServicesData() function.
+          $key_field = new $field_class($key_field, $key_instance);
+          $ws_data = $key_field->webServicesData();
+          $sortable_keys = $ws_data['sortable'];
+          if (array_key_exists($criteria, $sortable_keys)) {
+            $order_by[$key_field_name][] = array(
+              'column' => $sortable_keys[$criteria],
+              'dir' => $dir,
+            );
           }
           }
         }
         }
+       // If this field is not a TripalField then it should just have
+          // a simple value and we can query for that.
+        else {
+          $order_by[$key_field_name][] = array(
+            'column' => $key_field_id,
+            'dir' => 'ASC',
+          );
+        }
+      }
+    }
+
+    return $order_by;
+  }
+
+  /**
+   * Gets any filter by statements provided by the user.
+   *
+   * @field_mapping
+   *   An array that maps WS keys to field names. As provided by the
+   *   getFieldMapping() function.
+   *
+   * @return
+   *   An array of fields for filtering.
+   *
+   * @throws Exception
+   */
+  private function getFilters($field_mapping, $bundle) {
+    $filters = array();
+
+    // Iterate through the paramter list provided by user.
+    foreach ($this->params as $param => $value) {
+
+      // Ignore non filter parameters.
+      if ($param == 'page' or $param == 'limit') {
+        continue;
+      }
+
+      // Ignore the order parameter as that is handled by the getOrderBy()
+      // function
+      if ($param == 'order') {
         continue;
         continue;
       }
       }
 
 
@@ -501,16 +661,20 @@ class TripalEntityService_v0_1 extends TripalWebService {
         // Complex fields provied by the TripalField class may have sub
         // Complex fields provied by the TripalField class may have sub
         // elements that support filtering.  We need to see if the user
         // elements that support filtering.  We need to see if the user
         // wants to filter on those.
         // wants to filter on those.
-        if (tripal_load_include_field_class($key_field_name)) {
+        $field_class = $key_field['type'];
+        if (tripal_load_include_field_class($field_class)) {
           // To find out which fields are searchable we'll call the wsData()
           // To find out which fields are searchable we'll call the wsData()
           // function.
           // function.
-          $key_field = new $key_field_name($key_field, $key_instance);
-          $searchable_keys = $key_field->webServicesData();
+          $key_field = new $field_class($key_field, $key_instance);
+          $ws_data = $key_field->webServicesData();
+          $searchable_keys = $ws_data['searchable'];
           $criteria = implode('.', $subkeys);
           $criteria = implode('.', $subkeys);
           if (array_key_exists($criteria, $searchable_keys)) {
           if (array_key_exists($criteria, $searchable_keys)) {
-            $new_params[$key_field_name]['value'] = $value;
-            $new_params[$key_field_name]['op'] = $op;
-            $new_params[$key_field_name]['column'] = $searchable_keys[$criteria];
+            $filters[$key_field_name][] = array(
+              'value' => $value,
+              'op' => $op,
+              'column' => $searchable_keys[$criteria]
+            );
           }
           }
           else {
           else {
             throw new Exception("The filter term, '$criteria', is not available for use.");
             throw new Exception("The filter term, '$criteria', is not available for use.");
@@ -521,9 +685,11 @@ class TripalEntityService_v0_1 extends TripalWebService {
         else {
         else {
           $key_field_id = $key_instance['settings']['term_vocabulary'] . ':' . $key_instance['settings']['term_accession'];
           $key_field_id = $key_instance['settings']['term_vocabulary'] . ':' . $key_instance['settings']['term_accession'];
 
 
-          $new_params[$key_field_name]['value'] = $value;
-          $new_params[$key_field_name]['op'] = $op;
-          $new_params[$key_field_name]['column'] = $key_field_id;
+          $filters[$key_field_name][] = array(
+            'value' => $value,
+            'op' => $op,
+            'column' => $key_field_id,
+          );
         }
         }
       }
       }
       else {
       else {
@@ -531,44 +697,93 @@ class TripalEntityService_v0_1 extends TripalWebService {
       }
       }
     }
     }
 
 
-    // Get the list of entities for this bundle.
+    // Now convert the operation for each filter to one that is compatible
+    // with TripalFieldQuery.
+    foreach ($filters as $key_field_name => $key_filters) {
+      foreach ($key_filters as $i => $filter) {
+        $op = '=';
+        switch ($filters[$key_field_name][$i]['op']) {
+          case 'eq':
+            $op = '=';
+            break;
+          case 'gt':
+            $op = '>';
+            break;
+          case 'gte':
+            $op = '>=';
+            break;
+          case 'lt':
+            $op = '<';
+            break;
+          case 'lte':
+            $op = '<=';
+            break;
+          case 'ne':
+            $op = '<>';
+            break;
+          case 'contains':
+            $op = 'CONTAINS';
+            break;
+          case 'starts':
+            $op = 'STARTS WITH';
+            break;
+          default:
+            $op = '=';
+        }
+        $filters[$key_field_name][$i]['op'] = $op;
+      }
+    }
+    return $filters;
+  }
+
+  /**
+   * Creates a collection of resources for a given type.
+   */
+  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));
+    $term = entity_load('TripalTerm', array('id' => $bundle->term_id));
+    $term = reset($term);
+
+    // Set the label for this collection.
+    $this->resource->addProperty('label', $bundle->label . " collection");
+
+    // For quick lookup, get the mapping of WS keys to their appropriate fields.
+    $field_mapping = $this->getFieldMapping($bundle);
+
+    // Get arrays for filters and order by statements.
+    $filters = $this->getFilters($field_mapping, $bundle);
+    $order_by = $this->getOrderBy($field_mapping, $bundle);
+
+    // Initialize the query to search for records for out bundle type
+    // that are published.
     $query = new TripalFieldQuery();
     $query = new TripalFieldQuery();
     $query->entityCondition('entity_type', 'TripalEntity');
     $query->entityCondition('entity_type', 'TripalEntity');
     $query->entityCondition('bundle', $bundle->name);
     $query->entityCondition('bundle', $bundle->name);
-    foreach($new_params as $field_name => $details) {
-      $value = $details['value'];
-      $column_name = $details['column'];
-      switch ($details['op']) {
-        case 'eq':
-          $op = '=';
-          break;
-        case 'gt':
-          $op = '>';
-          break;
-        case 'gte':
-          $op = '>=';
-          break;
-        case 'lt':
-          $op = '<';
-          break;
-        case 'lte':
-          $op = '<=';
-          break;
-        case 'ne':
-          $op = '<>';
-          break;
-        case 'contains':
-          $op = 'CONTAINS';
-          break;
-        case 'starts':
-          $op = 'STARTS WITH';
-          break;
-        default:
-          $op = '=';
-      }
-      // We pass in the $column_name as an identifier for any sub fields
-      // that are present for the fields.
-      $query->fieldCondition($field_name, $column_name, $value, $op);
+    $query->propertyCondition('status', 1);
+
+    // Now iterate through the filters and add those.
+    foreach ($filters as $key_field_name => $key_filters) {
+      foreach ($key_filters as $i => $filter) {
+         $column_name = $filter['column'];
+         $value = $filter['value'];
+         $op = $filter['op'];
+        $query->fieldCondition($key_field_name, $column_name, $value, $op);
+      }
+    }
+
+    // Now set the order by.
+    foreach ($order_by as $key_field_name => $key_order) {
+      foreach ($key_order as $i => $order) {
+        $column_name = $order['column'];
+        $dir = $order['dir'];
+        $query->fieldOrderBy($key_field_name, $column_name, $dir);
+      }
     }
     }
 
 
     // Perform the query just as a count first to get the number of records.
     // Perform the query just as a count first to get the number of records.
@@ -587,12 +802,6 @@ class TripalEntityService_v0_1 extends TripalWebService {
     $total_pages = ceil($num_records / $limit);
     $total_pages = ceil($num_records / $limit);
     $page = array_key_exists('page', $this->params) ? $this->params['page'] : 1;
     $page = array_key_exists('page', $this->params) ? $this->params['page'] : 1;
 
 
-    // Set the query order
-    $order_keys = array_keys($order);
-    for($i = 0; $i < count($order_keys); $i++) {
-      $query->fieldOrderBy($order_keys[$i], $order[$order_keys[$i]], $order_dir[$i]);
-    }
-
     // Set the query range
     // Set the query range
     $start = ($page - 1) * $limit;
     $start = ($page - 1) * $limit;
     $query->range($start, $limit);
     $query->range($start, $limit);
@@ -602,8 +811,14 @@ class TripalEntityService_v0_1 extends TripalWebService {
 
 
     $this->resource->initPager($num_records, $limit, $page);
     $this->resource->initPager($num_records, $limit, $page);
 
 
-    // Iterate through the entities and add them to the list.
-    foreach ($results['TripalEntity'] as $entity_id => $stub) {
+    // Check to make sure there are results.
+    $entity_ids = array();
+    if (isset($results['TripalEntity']) AND is_array($results['TripalEntity'])) {
+      $entity_ids = $results['TripalEntity'];
+    }
+
+    // Iterate through the entities and add them to the output list.
+    foreach ($entity_ids as $entity_id => $stub) {
       // We don't need all of the attached fields for an entity so, we'll
       // We don't need all of the attached fields for an entity so, we'll
       // not use the entity_load() function.  Instead just pull it from the
       // not use the entity_load() function.  Instead just pull it from the
       // database table.
       // database table.
@@ -634,7 +849,7 @@ class TripalEntityService_v0_1 extends TripalWebService {
   private function doAllTypesList() {
   private function doAllTypesList() {
     $service_path = $this->getServicePath();
     $service_path = $this->getServicePath();
     $label = tripal_get_term_details('rdfs', 'label');
     $label = tripal_get_term_details('rdfs', 'label');
-    $this->resource = new TripalWebServiceCollection($service_path);
+    $this->resource = new TripalWebServiceCollection($service_path, $this->params);
     $this->resource->addContextItem('label', $label['url']);
     $this->resource->addContextItem('label', $label['url']);
     $this->resource->addProperty('label', 'Content Types');
     $this->resource->addProperty('label', 'Content Types');
 
 
@@ -651,22 +866,237 @@ class TripalEntityService_v0_1 extends TripalWebService {
       $term = reset($entity);
       $term = reset($entity);
       $vocab = $term->vocab;
       $vocab = $term->vocab;
 
 
+      $member = new TripalWebServiceResource($service_path);
+      // If the term has no URL then we'll default to using thie site's
+      // term lookup service.
+      $url = $term->url;
+      if (!$url) {
+        $url = url('cv/lookup/' . $term->vocab->vocabulary . '/' . $term->accession , array('absolute' => TRUE));
+      }
+      $member->addContextItem($term->name, $url);
+      $member->addContextItem('label', $label['url']);
+      $member->addProperty('label', $bundle->label);
+      $member->addContextItem('description', 'hydra:description');
       // Get the bundle description. If no description is provided then
       // Get the bundle description. If no description is provided then
       // use the term definition
       // use the term definition
       $description = tripal_get_bundle_variable('description', $bundle->id);
       $description = tripal_get_bundle_variable('description', $bundle->id);
       if (!$description) {
       if (!$description) {
         $description = $term->definition;
         $description = $term->definition;
       }
       }
-      $member = new TripalWebServiceResource($service_path);
-      $member->addContextItem($term->name, $term->url);
-      $member->addContextItem('label', $label['url']);
-      $member->addContextItem('description', 'hydra:description');
+      if (!$description) {
+        $description = '';
+      }
+      $member->addProperty('description', $description);
       $member->setID(urlencode($bundle->label));
       $member->setID(urlencode($bundle->label));
       $member->setType($term->name);
       $member->setType($term->name);
-      $member->addProperty('label', $bundle->label);
-      $member->addProperty('description', $description);
+
       $this->resource->addMember($member);
       $this->resource->addMember($member);
 
 
     }
     }
   }
   }
+
+  /**
+   * @see TripalWebService::getSupportedClasses()
+   */
+  public function getSupportedClasses() {
+
+    global $user;
+
+    // An array of TripalWebServiceResources containing a
+    // description of the supported classes.
+    $supported_classes = array();
+
+    // Get the list of published terms (these are the bundle IDs)
+    $bundles = db_select('tripal_bundle', 'tb')
+      ->fields('tb')
+      ->orderBy('tb.label', 'ASC')
+      ->execute();
+
+    // Iterate through the terms and add an entry in the collection.
+    $i = 0;
+    while ($bundle = $bundles->fetchObject()) {
+      $entity =  entity_load('TripalTerm', array('id' => $bundle->term_id));
+      $term = reset($entity);
+      $vocab = $term->vocab;
+
+      // 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;
+      }
+
+      $supported = new TripalWebServiceResource($this->getServicePath());
+      $supported->addContextItem('supportedOperation', 'hydra:supportedOperation');
+      $supported->addContextItem('supportedProperty', 'hydra:supportedProperty');
+      $supported->setID(urlencode($bundle->label));
+      $supported->setType('hydra:Class');
+      $supported->addProperty('hydra:title', $bundle->label);
+      $supported->addProperty('hydra:description', $description);
+
+      // Add in the supported operations for this content type.
+      $operations = array();
+
+      // If the user can view this content type.
+      if (user_access('view ' . $bundle->name)) {
+        // All content types allow GET (if the user has view permission).
+        $get_op = new TripalWebServiceResource($this->getServicePath());
+        $get_op->addContextItem('supportedOperation', 'hydra:supportedOperation');
+        $get_op->addContextItem('method', 'hydra:method');
+        $get_op->addContextItem('statusCodes', 'hydra:statusCodes');
+        $get_op->addContextItem('label', 'rdfs:label');
+        $get_op->addContextItem('description', 'rdfs:comment');
+        $get_op->addContextItem('expects', array(
+          "@id" => "hydra:expects",
+          "@type" => "@id"
+        ));
+        $get_op->addContextItem('returns', array(
+          "@id" => "hydra:returns",
+          "@type" => "@id"
+        ));
+        $get_op->setID('_:' . preg_replace('/[^\w]/', '_', strtolower($bundle->label)) . '_retrieve');
+        $get_op->setType('hydra:Operation');
+        $get_op->addProperty('method', 'GET');
+        if (preg_match('/^[aeiou]/i', $bundle->label)) {
+          $get_op->addProperty('label', "Retrieves an " . $bundle->label . " entity.");
+        }
+        else {
+          $get_op->addProperty('label', "Retrieves a " . $bundle->label . " entity.");
+        }
+        $get_op->addProperty('description', NULL);
+        $get_op->addProperty('expects', NULL);
+        $get_op->addProperty('returns', $term->url);
+        $get_op->addProperty('statusCodes', array(
+          array(
+            'code' => 404,
+            'description' => 'The ' . $bundle->label . ' could not be found using the provided ID.'
+          ),
+        ));
+        $operations[] = $get_op;
+      }
+
+      // If the user can create this content type.
+      if (user_access('create ' . $bundle->name)) {
+        // All content types allow GET (if the user has view permission).
+        $create_op = new TripalWebServiceResource($this->getServicePath());
+        $create_op->addContextItem('method', 'hydra:method');
+        $create_op->addContextItem('statusCodes', 'hydra:statusCodes');
+        $create_op->addContextItem('label', 'rdfs:label');
+        $create_op->addContextItem('description', 'rdfs:comment');
+        $create_op->addContextItem('code', 'hydra:statusCode');
+        $create_op->addContextItem('expects', array(
+          "@id" => "hydra:expects",
+          "@type" => "@id"
+        ));
+        $create_op->addContextItem('returns', array(
+          "@id" => "hydra:returns",
+          "@type" => "@id"
+        ));
+        $create_op->setID('_:' . preg_replace('/[^\w]/', '_', strtolower($bundle->label)) . '_create');
+        $create_op->setType('http://schema.org/CreateAction');
+        $create_op->addProperty('method', 'POST');
+        if (preg_match('/^[aeiou]/i', $bundle->label)) {
+          $create_op->addProperty('label', "Creates an " . $bundle->label . " entity.");
+        }
+        else {
+          $create_op->addProperty('label', "Creates a " . $bundle->label . " entity.");
+        }
+        $create_op->addProperty('description', NULL);
+        $create_op->addProperty('expects', $term->url);
+        $create_op->addProperty('returns', $term->url);
+        $create_op->addProperty('statusCodes', array(
+          array(
+            'code' => 404,
+            'description' => 'The ' . $bundle->label . ' could not be created.'
+          ),
+          array(
+            'code' => 409,
+            'description' => 'The ' . $bundle->label . ' already exists.'
+          ),
+        ));
+        $operations[] = $create_op;
+      }
+
+      // If the user can edit this content type.
+      if (user_access('edit ' . $bundle->name)) {
+        // All content types allow GET (if the user has view permission).
+        $edit_op = new TripalWebServiceResource($this->getServicePath());
+        $edit_op->addContextItem('method', 'hydra:method');
+        $edit_op->addContextItem('statusCodes', 'hydra:statusCodes');
+        $edit_op->addContextItem('label', 'rdfs:label');
+        $edit_op->addContextItem('description', 'rdfs:comment');
+        $edit_op->addContextItem('code', 'hydra:statusCode');
+        $edit_op->addContextItem('expects', array(
+          "@id" => "hydra:expects",
+          "@type" => "@id"
+        ));
+        $edit_op->addContextItem('returns', array(
+          "@id" => "hydra:returns",
+          "@type" => "@id"
+        ));
+        $edit_op->setID('_:' . preg_replace('/[^\w]/', '_', strtolower($bundle->label)) . '_update');
+        $edit_op->setType('http://schema.org/UpdateAction');
+        $edit_op->addProperty('method', 'PUT');
+        if (preg_match('/^[aeiou]/i', $bundle->label)) {
+          $edit_op->addProperty('label', "Update and replace an " . $bundle->label . " entity.");
+        }
+        else {
+          $edit_op->addProperty('label', "Update and replace a " . $bundle->label . " entity.");
+        }
+        $edit_op->addProperty('description', NULL);
+        $edit_op->addProperty('expects', $term->url);
+        $edit_op->addProperty('returns', $term->url);
+        $edit_op->addProperty('statusCodes', array(
+          array(
+            'code' => 404,
+            'description' => 'The ' . $bundle->label . ' could not be updated using the provided ID.'
+          ),
+        ));
+        $operations[] = $edit_op;
+      }
+
+      // If the user can edit this content type.
+      if (user_access('delete ' . $bundle->name)) {
+        // All content types allow GET (if the user has view permission).
+        $delete_op = new TripalWebServiceResource($this->getServicePath());
+        $delete_op->addContextItem('method', 'hydra:method');
+        $delete_op->addContextItem('statusCodes', 'hydra:statusCodes');
+        $delete_op->addContextItem('label', 'rdfs:label');
+        $delete_op->addContextItem('description', 'rdfs:comment');
+        $delete_op->addContextItem('code', 'hydra:statusCode');
+        $delete_op->addContextItem('expects', array(
+          "@id" => "hydra:expects",
+          "@type" => "@id"
+        ));
+        $delete_op->addContextItem('returns', array(
+          "@id" => "hydra:returns",
+          "@type" => "@id"
+        ));
+        $delete_op->setID('_:' . preg_replace('/[^\w]/', '_', strtolower($bundle->label)) . '_delete');
+        $delete_op->setType('http://schema.org/DeleteAction');
+        $delete_op->addProperty('method', 'DELETE');
+        if (preg_match('/^[aeiou]/i', $bundle->label)) {
+          $delete_op->addProperty('label', "Deletes an " . $bundle->label . " entity.");
+        }
+        else {
+          $delete_op->addProperty('label', "Deletes a " . $bundle->label . " entity.");
+        }
+        $delete_op->addProperty('description', NULL);
+        $delete_op->addProperty('expects', $term->url);
+        $delete_op->addProperty('returns', $term->url);
+        $delete_op->addProperty('statusCodes', array(
+          array(
+            'code' => 404,
+            'description' => 'The ' . $bundle->label . ' could not be deleted using the provided ID.'
+          ),
+        ));
+        $operations[] = $delete_op;
+      }
+
+      $supported->addProperty('supportedOperation', $operations);
+      $supported_classes[] = $supported;
+    }
+
+    return $supported_classes;
+  }
 }
 }

+ 138 - 1
tripal_ws/includes/TripalWebService/TripalVocabService_v0_1.inc

@@ -15,5 +15,142 @@ class TripalVocabService_v0_1 extends TripalWebService {
    * among all Tripal web services and is used to form the URL to access
    * among all Tripal web services and is used to form the URL to access
    * this service.
    * this service.
    */
    */
-  public static $type = 'vocabulary';
+  public static $type = 'vocab';
+
+
+  /**
+   * @see TripalWebService::handleRequest()
+   */
+  public function handleRequest() {
+    $this->resource->addContextItem('vocab', $this->getServicePath() . '#');
+
+    $this->resource->addContextItem('ApiDocumentation', 'hydra:ApiDocumentation');
+    $this->resource->addContextItem('supportedClass', 'hydra:supportedClass');
+    $this->resource->setType('ApiDocumentation');
+    $this->resource->setID('vocab/' . $this->getVersion());
+
+    // We need to list the content types as properties of the EntryPoint.
+    $properties = array();
+
+
+    // Iterate through all of the web services and get their documentation
+    $services = tripal_get_web_services();
+    foreach ($services as $service_class) {
+      tripal_load_include_web_service_class($service_class);
+      $service = new $service_class($this->base_path);
+      $supported_classes = $service->getSupportedClasses();
+      foreach ($supported_classes as $supported) {
+        $this->resource->addProperty('supportedClass', $supported);
+      }
+      if ($service_class::$type != 'vocab') {
+        $event_prop = new TripalWebServiceResource($this->getServicePath());
+        $event_prop->addProperty('hydra:title', $service_class::$type);
+        $event_prop->addProperty('hydra:description', $service_class::$description);
+        $event_prop->addContextItem('required', 'hydra:reqiured');
+        $event_prop->addProperty('required', NULL);
+        $event_prop->addContextItem('readonly', 'hydra:readonly');
+        $event_prop->addProperty('readonly', TRUE);
+        $event_prop->addContextItem('writeonly', 'hydra:writeonly');
+        $event_prop->addProperty('writeonly', FALSE);
+        $event_prop->addContextItem('property', array(
+          "@id" => "hydra:property",
+          "@type" => "@id"
+        ));
+        //$event_prop->setID('');
+        //$event_prop->setType('');
+        $prop = new TripalWebServiceResource($this->getServicePath());
+        $prop->setID('vocab:EntryPoint/' . $service_class::$type);
+        $prop->setType('hydra:Link');
+        $prop->addContextItem('label', 'rdfs:label');
+        $prop->addProperty('label', $service_class::$label);
+        $prop->addContextItem('description', 'rdfs:comment');
+        $prop->addProperty('description', $service_class::$description);
+        $prop->addContextItem('domain', array(
+          "@id" => "rdfs:domain",
+          "@type" => "@id"
+        ));
+        $prop->addProperty('domain', 'vocab:EntryPoint');
+        $prop->addContextItem('range', array(
+          "@id" => "rdfs:range",
+          "@type" => "@id"
+        ));
+        $prop->addProperty('range', 'hydra:Collection');
+
+        $prop_ops = array();
+        $prop_op = new TripalWebServiceResource($this->getServicePath());
+        $prop_op->setID('_:event_collectionretrieve');
+        $prop_op->setType('hydra:Operation');
+        $prop_op->addContextItem('method', 'hydra:method');
+        $prop_op->addProperty('method', 'GET');
+        $prop_op->addContextItem('label', 'rdfs:label');
+        $prop_op->addProperty('label', 'Retrieves all ' . $service_class::$label . ' entities.');
+        $prop_op->addContextItem('description', 'rdfs:comment');
+        $prop_op->addProperty('description', NULL);
+        $prop_op->addContextItem('expects', array(
+          "@id" => "hydra:expects",
+          "@type" => "@id"
+        ));
+        $prop_op->addProperty('expects', NULL);
+        $prop_op->addContextItem('returns', array(
+          "@id" => "hydra:returns",
+          "@type" => "@id"
+        ));
+        $prop_op->addProperty('returns', 'hydra:Collection');
+        $prop_op->addContextItem('statusCodes', 'hydra:statusCodes');
+        $prop_op->addProperty('statusCodes', array());
+        $prop_ops[] = $prop_op;
+
+        $prop->addContextItem('supportedOperation', 'hydra:supportedOperation');
+        $prop->addProperty('supportedOperation', $prop_ops);
+        $event_prop->addProperty('property', $prop);
+        $properties[] = $event_prop;
+      }
+    }
+
+    // Add in the generic supported classes.
+    $entry_class = new TripalWebServiceResource($this->base_path);
+    $entry_class->addContextItem('label', 'rdfs:label');
+    $entry_class->setID($this->getServicePath() . '#EntryPoint');
+    $entry_class->setType('hydra:Class');
+    $entry_class->addProperty('label', 'EntryPoint');
+    $entry_class->addContextItem('description', 'rdfs:comment');
+    $entry_class->addProperty('description', 'The main entry point or homepage of the API');
+    $entry_class->addContextItem('subClassOf', array(
+      "@id" => "rdfs:subClassOf",
+      "@type" => "@id"
+    ));
+    $entry_class->addProperty('subClassOf', NULL);
+    $entry_class->addContextItem('supportedOperation', 'hydra:supportedOperation');
+    $entry_class->addContextItem('supportedProperty', 'hydra:supportedProperty');
+
+
+    $operations = array();
+
+    $get_op = new TripalWebServiceResource($this->getServicePath());
+    $get_op->addContextItem('method', 'hydra:method');
+    $get_op->addProperty('method', 'GET');
+    $get_op->addContextItem('statusCodes', 'hydra:statusCodes');
+    $get_op->addProperty('statusCodes', array());
+    $get_op->addContextItem('label', 'rdfs:label');
+    $get_op->addProperty('label', "The APIs main entry point.");
+    $get_op->addContextItem('description', 'rdfs:comment');
+    $get_op->addProperty('description', NULL);
+    $get_op->addContextItem('expects', array(
+      "@id" => "hydra:expects",
+      "@type" => "@id"
+    ));
+    $get_op->addProperty('expects', NULL);
+    $get_op->addContextItem('returns', array(
+      "@id" => "hydra:returns",
+      "@type" => "@id"
+    ));
+    $get_op->addProperty('returns', "vocab:EntryPoint");
+    $get_op->setID('_:entry_point');
+    $get_op->setType('hydra:Operation');
+
+    $operations[] = $get_op;
+    $entry_class->addProperty('supportedOperation', $operations);
+    $entry_class->addProperty('supportedProperty', $properties);
+    $this->resource->addProperty('supportedClass', $entry_class);
+  }
 }
 }

+ 28 - 6
tripal_ws/includes/TripalWebServiceCollection.inc

@@ -32,15 +32,28 @@ class TripalWebServiceCollection extends TripalWebServiceResource {
   protected $page;
   protected $page;
 
 
 
 
+  /**
+   * The parameters as collected by the parent TripalWebService.  We need
+   * the parameters because this Resource generates first, next, prev, and last
+   * links and we need to maintain the parameters a user may have
+   * provided in those links.
+   */
+  protected $params;
+
   /**
   /**
    * Implements the constructor.
    * Implements the constructor.
    *
    *
    * @param TripalWebService $service
    * @param TripalWebService $service
    *   An instance of a TripalWebService or class that extends it.
    *   An instance of a TripalWebService or class that extends it.
    */
    */
-  public function __construct($service_path) {
+  public function __construct($service_path, $params) {
     parent::__construct($service_path);
     parent::__construct($service_path);
+
+    // Initialize private member variables.
+    $this->params = $params;
     $this->members = array();
     $this->members = array();
+
+    // Add some terms to the context.
     $term = tripal_get_term_details('hydra', 'Collection');
     $term = tripal_get_term_details('hydra', 'Collection');
     $this->addContextItem('Collection', $term['url']);
     $this->addContextItem('Collection', $term['url']);
     $term = tripal_get_term_details('hydra', 'totalItems');
     $term = tripal_get_term_details('hydra', 'totalItems');
@@ -111,6 +124,15 @@ class TripalWebServiceCollection extends TripalWebServiceResource {
 
 
     if ($this->doPaging == TRUE) {
     if ($this->doPaging == TRUE) {
 
 
+      // Save any parameters provided by the user
+      $saved_params = '';
+      foreach ($this->params as $pkey => $pval) {
+        if (in_array($pkey, array('page', 'limit', 'first', 'last', 'next', 'prev'))) {
+          continue;
+        }
+        $saved_params .= '&' . $pkey . '=' . $pval;
+      }
+
       $data['totalItems'] = $this->totalItems;
       $data['totalItems'] = $this->totalItems;
       $total_pages = ceil($this->totalItems / $this->itemsPerPage);
       $total_pages = ceil($this->totalItems / $this->itemsPerPage);
       $page = $this->page;
       $page = $this->page;
@@ -118,18 +140,18 @@ class TripalWebServiceCollection extends TripalWebServiceResource {
 
 
       if ($this->totalItems > 0) {
       if ($this->totalItems > 0) {
         $data['view'] = array(
         $data['view'] = array(
-          '@id' => $this->service_path . '?' . implode('&', array_merge(array("page=$page", "limit=$limit"))),
+          '@id' => $this->service_path . '?' . implode('&', array_merge(array("page=$page", "limit=$limit"))) . $saved_params,
           '@type' => 'PartialCollectionView',
           '@type' => 'PartialCollectionView',
-          'first' => $this->service_path . '?' . implode('&', array_merge(array("page=1", "limit=$limit"))),
-          'last' => $this->service_path . '?' . implode('&', array_merge(array("page=$total_pages", "limit=$limit"))),
+          'first' => $this->service_path . '?' . implode('&', array_merge(array("page=1", "limit=$limit"))) . $saved_params,
+          'last' => $this->service_path . '?' . implode('&', array_merge(array("page=$total_pages", "limit=$limit"))) . $saved_params,
         );
         );
         $prev = $page - 1;
         $prev = $page - 1;
         $next = $page + 1;
         $next = $page + 1;
         if ($prev > 0) {
         if ($prev > 0) {
-          $data['view']['previous'] = $this->service_path .'?' . implode('&', array("page=$prev", "limit=$limit"));
+          $data['view']['previous'] = $this->service_path .'?' . implode('&', array("page=$prev", "limit=$limit")) . $saved_params;
         }
         }
         if ($next < $total_pages) {
         if ($next < $total_pages) {
-          $data['view']['next'] = $this->service_path . '?' . implode('&', array("page=$next", "limit=$limit"));
+          $data['view']['next'] = $this->service_path . '?' . implode('&', array("page=$next", "limit=$limit")) . $saved_params;
         }
         }
       }
       }
     }
     }

+ 116 - 52
tripal_ws/includes/TripalWebServiceResource.inc

@@ -32,21 +32,21 @@ class TripalWebServiceResource {
   /**
   /**
    * Implements the constructor.
    * Implements the constructor.
    *
    *
-   * @param TripalWebService $service
-   *   An instance of a TripalWebService or class that extends it.
+   * @param  $service_path
+   *
    */
    */
   public function __construct($service_path) {
   public function __construct($service_path) {
+
     $this->context = array();
     $this->context = array();
     $this->data = array();
     $this->data = array();
     $this->service_path = $service_path;
     $this->service_path = $service_path;
 
 
     // First, add the RDFS and Hydra vocabularies to the context.  All Tripal
     // First, add the RDFS and Hydra vocabularies to the context.  All Tripal
     // web services should use these.
     // web services should use these.
-    $vocab = tripal_get_vocabulary_details('rdfs');
-    $this->addContextItem('rdfs', $vocab['url']);
+    $this->addContextItem('rdf', "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
+    $this->addContextItem('rdfs', 'http://www.w3.org/2000/01/rdf-schema#');
 
 
-    $vocab = tripal_get_vocabulary_details('hydra');
-    $this->addContextItem('hydra', $vocab['url']);
+    $this->addContextItem('hydra', "http://www.w3.org/ns/hydra/core#");
 
 
     $vocab = tripal_get_vocabulary_details('dc');
     $vocab = tripal_get_vocabulary_details('dc');
     $this->addContextItem('dc', $vocab['url']);
     $this->addContextItem('dc', $vocab['url']);
@@ -55,7 +55,8 @@ class TripalWebServiceResource {
     $this->addContextItem('schema', $vocab['url']);
     $this->addContextItem('schema', $vocab['url']);
 
 
     $vocab = tripal_get_vocabulary_details('local');
     $vocab = tripal_get_vocabulary_details('local');
-    $this->addContextItem('local', $vocab['url']);
+    $this->addContextItem('local', url($vocab['url'], array('absolute' => TRUE)). '/');
+
 
 
     $this->data['@id'] = $service_path;
     $this->data['@id'] = $service_path;
     $this->data['@type'] = '';
     $this->data['@type'] = '';
@@ -96,16 +97,59 @@ class TripalWebServiceResource {
    *   The type
    *   The type
    */
    */
   public function setType($type) {
   public function setType($type) {
-    $keys = array_keys($this->context);
-    if (!in_array($type, $keys)) {
-      throw new Exception("The resource type, '$type', has not yet been added to the " .
-          "context of the web service. Use the addContextItem() function of the web service " .
-          "to add this term.");
-    }
+    $this->checkKey($type);
     $this->type = $type;
     $this->type = $type;
     $this->data['@type'] = $type;
     $this->data['@type'] = $type;
   }
   }
 
 
+  /**
+   * Checks a key to ensure it is in the Context before being used.
+   *
+   * This function should be used before adding a property or type to this
+   * resource.  It ensures that the key for the property is already in the
+   * context.
+   *
+   * @param $key
+   *   The key to check.
+   * @throws Exception
+   */
+  private function checkKey($key) {
+    // Make sure the key is already present in the context.
+    $keys = array_keys($this->context);
+
+    // Keys that are full HTML are acceptable
+    if (preg_match('/^(http|https):\/\/.*/', $key)) {
+      return;
+    }
+
+    // If the key has a colon separating the vocabulary and the term then we
+    // just need to make sure that the vocabulary is present.
+    $matches = array();
+    if (preg_match('/^(.*?):(.*?)$/', $key, $matches)) {
+      $vocab = $matches[1];
+      $accession = $matches[2];
+
+      // The underscore represents the blank node. So, these keys are okay.
+      if ($vocab == '_') {
+        return;
+      }
+
+      // If the vocabulary is not in the.
+      if (!in_array($vocab, $keys)) {
+        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.");
+      }
+    }
+    else {
+      // If the key is not in the context then throw an error.
+      if (!in_array($key, $keys)) {
+        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.");
+      }
+    }
+  }
+
+
   /**
   /**
    * Set's the unique identifier for the resource.
    * Set's the unique identifier for the resource.
    *
    *
@@ -119,7 +163,30 @@ class TripalWebServiceResource {
    */
    */
   public function setID($id) {
   public function setID($id) {
     $this->id = $id;
     $this->id = $id;
-    $this->data['@id'] = $this->service_path . '/' . $id;
+    $this->data['@id'] = $this->getURI($id);
+  }
+
+  /**
+   * Retreives the IRI for an entity of a given ID in this web service.
+   *
+   * @param $id
+   *   The unique identifier for the resource.
+   */
+  public function getURI($id) {
+    // If this is a key/value pair for an id and if the vocab portion is
+    // an underscore then this represents a blank node and we don't want
+    // to add the full path.
+    $matches = array();
+    if (preg_match('/^(.*?):(.*?)$/', $id, $matches)) {
+      $vocab = $matches[1];
+      if ($vocab == '_') {
+        return $id;
+      }
+      return $id;
+    }
+    else {
+      return $this->service_path . '/' . $id;
+    }
   }
   }
 
 
 
 
@@ -152,7 +219,8 @@ class TripalWebServiceResource {
    * Adds a new key/value pair to the web serivces response.
    * Adds a new key/value pair to the web serivces response.
    *
    *
    * The value must either be a scalar or another TripalWebServiceResource
    * The value must either be a scalar or another TripalWebServiceResource
-   * object.
+   * object.  If the same key is usesd multiple times then the resulting
+   * resource will be presented as an array of elements.
    *
    *
    * @param unknown $key
    * @param unknown $key
    *   The name of the $key to add. This key must already be present in the
    *   The name of the $key to add. This key must already be present in the
@@ -164,49 +232,45 @@ class TripalWebServiceResource {
    */
    */
   public function addProperty($key, $value) {
   public function addProperty($key, $value) {
 
 
-    // Make sure the key is already present in the context.
-    $keys = array_keys($this->context);
-    if (!in_array($key, $keys)) {
-      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.");
+    $this->checkKey($key);
+
+    // If this is a numeric array then go through each element and add them.
+    if (is_array($value) and count(array_filter(array_keys($value), 'is_int')) == count(array_keys($value))) {
+      if (!array_key_exists($key, $this->data)) {
+        $this->data[$key] = array();
+      }
+      foreach ($value as $item) {
+        $this->addProperty($key, $item);
+      }
+      return;
     }
     }
-    if (is_scalar($value)) {
-      $this->data[$key] = $value;
+
+    // If this is a TripalWebServiceResource then get it's data and use that
+    // as the new value.
+    if (is_a($value, 'TripalWebServiceResource') or is_subclass_of($value, 'TripalWebServiceResource')) {
+      // Add in the context items to this resource.
+      $context = $value->getContext();
+      foreach ($context as $k => $v) {
+        $this->addContextItem($k, $v);
+      }
+      $value = $value->getData();
     }
     }
-    else if (!is_subclass_of($value, 'TripalWebServiceResource')) {
+
+    // If this key doesn't exist then add the value directly to the key.
+    if (!array_key_exists($key, $this->data)) {
       $this->data[$key] = $value;
       $this->data[$key] = $value;
     }
     }
+    // Else if it does exist then we need to make sure that the element is
+    // an array and add it.
     else {
     else {
-      throw new Exception("The value must either be a scalar or a TripalWebServiceResource");
-    }
-  }
-
-  /**
-   * A recursive function that ensures all keys in an item are in the context.
-   *
-   * @param $key
-   *   The name of the current key.
-   * @param $value
-   *   The avlue assigned to the current key.
-   *
-   * @throws Exception
-   *   Throws an exception of a key is not present in the context.
-   */
-  private function checkDataItem($key, $value) {
-    // Make sure the key is already present in the context.
-    $keys = array_keys($this->context);
-    if (!in_array($key, $keys)) {
-      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.");
-    }
-    // If the value is an associative array then recurse
-    if (is_array($value)) {
-      // Check if this is an associatave array (non-integer keys).
-      if (count(array_filter(array_keys($array), 'is_string')) > 0) {
-        foreach ($value as $sub_key => $sub_value) {
-          $this->checkDataItem($sub_key, $sub_value);
-        }
+      // If this is the second element, then convert it to an array.  The
+      // second test in the condition below is for for a numeric array.
+      if (!is_array($this->data[$key]) or count(array_filter(array_keys($this->data[$key]), 'is_string')) > 0) {
+        $element = $this->data[$key];
+        $this->data[$key] = array();
+        $this->data[$key][] = $element;
       }
       }
+      $this->data[$key][] = $value;
     }
     }
   }
   }
 
 

+ 27 - 19
tripal_ws/tripal_ws.module

@@ -104,7 +104,17 @@ function tripal_ws_get_services() {
   global $base_url;
   global $base_url;
   $service_path = $base_url . '/web-services';
   $service_path = $base_url . '/web-services';
 
 
-  drupal_add_http_header('Content-Type', 'application/json');
+
+  // This should go out as ld+json
+  drupal_add_http_header('Content-Type', 'application/ld+json');
+
+  // Add a link header for the vocabulary service so that clients
+  // know where to find the docs.
+  tripal_load_include_web_service_class('TripalVocabService_v0_1');
+  $service = new TripalVocabService_v0_1($service_path);
+  $vocab = tripal_get_vocabulary_details('hydra');
+  drupal_add_http_header('Link', '<' . $service->getServicePath() . '>; rel="http://www.w3.org/ns/hydra/core#apiDocumentation"');
+  drupal_add_http_header('Cache-Control', "no-cache");
 
 
   try {
   try {
     $ws_path = func_get_args();
     $ws_path = func_get_args();
@@ -196,19 +206,28 @@ function tripal_ws_list_services() {
 
 
   // Create the parent resource which is a collection.
   // Create the parent resource which is a collection.
   $resource = new TripalWebServiceResource($base_path);
   $resource = new TripalWebServiceResource($base_path);
-  $resource->addContextItem('entrypoint', 'hydra:entrypoint');
-  $resource->setType('entrypoint');
 
 
-  // Now add the member to the collection
+  // Add the vocabulary to the context.
+  tripal_load_include_web_service_class('TripalVocabService_v0_1');
+  $service = new TripalVocabService_v0_1($base_path);
+  $resource->addContextItem('vocab', $service->getServicePath() . '#');
+  $resource->addContextItem('EntryPoint', 'vocab:EntryPoint');
+  $resource->setType('EntryPoint');
+
+  // Now add the services as properties.
   foreach ($services as $service_class) {
   foreach ($services as $service_class) {
     tripal_load_include_web_service_class($service_class);
     tripal_load_include_web_service_class($service_class);
+    if ($service_class == 'TripalVocabService_v0_1') {
+      continue;
+    }
     $service = new $service_class($base_path);
     $service = new $service_class($base_path);
-    $version = $service->getVersion();
-    $resource->addContextItem($service_class::$type, '');
+    $resource->addContextItem($service_class::$type, array(
+      '@id' => 'vocab:EntryPoint/' . $service_class::$type,
+      '@type' => '@id',
+    ));
     $resource->addProperty($service_class::$type, $service->getServicePath());
     $resource->addProperty($service_class::$type, $service->getServicePath());
   }
   }
 
 
-  // For discoverability add the document webservice.
   $service->setResource($resource);
   $service->setResource($resource);
   $response = $service->getResponse();
   $response = $service->getResponse();
   print drupal_json_encode($response);
   print drupal_json_encode($response);
@@ -248,21 +267,10 @@ function tripal_ws_services() {
     // TODO: What do we do if no version is provided?
     // TODO: What do we do if no version is provided?
   }
   }
 
 
-  drupal_add_http_header('Content-Type', 'application/json');
+  drupal_add_http_header('Content-Type', 'application/ld+json');
   print drupal_json_encode($response);
   print drupal_json_encode($response);
 }
 }
 
 
-/**
- *
- * @param $entities
- * @param $type
- */
-function tripal_ws_entity_load($entities, $type) {
-  foreach ($entities as $entity) {
-
-  }
-}
-
 /**
 /**
  *
  *
  * @param $site_id
  * @param $site_id