Kaynağa Gözat

Merge branch '7.x-3.x' into 450-tv3-publishing_fields_with_defaults

Stephen Ficklin 6 yıl önce
ebeveyn
işleme
1cdf1b202f
25 değiştirilmiş dosya ile 521 ekleme ve 42 silme
  1. 1 2
      tripal/api/tripal.entities.api.inc
  2. 28 1
      tripal/api/tripal.terms.api.inc
  3. 49 0
      tripal/includes/TripalBundleUIController.inc
  4. 1 2
      tripal/includes/TripalEntityUIController.inc
  5. 11 1
      tripal/includes/TripalFields/TripalFieldWidget.inc
  6. 22 0
      tripal/includes/tripal.field_storage.inc
  7. 9 1
      tripal/includes/tripal.fields.inc
  8. 14 2
      tripal_chado/api/tripal_chado.query.api.inc
  9. 4 1
      tripal_chado/api/tripal_chado.variables.api.inc
  10. 13 2
      tripal_chado/includes/TripalFields/chado_linker__prop/chado_linker__prop_widget.inc
  11. 8 0
      tripal_chado/includes/TripalFields/data__accession/data__accession_widget.inc
  12. 14 3
      tripal_chado/includes/TripalFields/data__sequence/data__sequence_widget.inc
  13. 145 0
      tripal_chado/includes/TripalFields/operation__analysis/operation__analysis.inc
  14. 33 0
      tripal_chado/includes/TripalFields/operation__analysis/operation__analysis_formatter.inc
  15. 72 0
      tripal_chado/includes/TripalFields/operation__analysis/operation__analysis_widget.inc
  16. 2 2
      tripal_chado/includes/TripalFields/sbo__database_cross_reference/sbo__database_cross_reference_widget.inc
  17. 6 6
      tripal_chado/includes/TripalFields/schema__additional_type/schema__additional_type_widget.inc
  18. 1 1
      tripal_chado/includes/TripalFields/schema__alternate_name/schema__alternate_name_widget.inc
  19. 1 1
      tripal_chado/includes/TripalFields/schema__publication/schema__publication_widget.inc
  20. 2 2
      tripal_chado/includes/TripalFields/sio__annotation/sio__annotation_widget.inc
  21. 5 7
      tripal_chado/includes/loaders/tripal_chado.pub_importer_PMID.inc
  22. 10 0
      tripal_chado/includes/tripal_chado.field_storage.inc
  23. 64 2
      tripal_chado/includes/tripal_chado.fields.inc
  24. 6 1
      tripal_chado/includes/tripal_chado.phylotree.inc
  25. 0 5
      tripal_ws/includes/TripalWebService/TripalContentService_v0_1.inc

+ 1 - 2
tripal/api/tripal.entities.api.inc

@@ -358,8 +358,7 @@ function tripal_load_bundle_entity($values) {
 }
 
 /**
- * Allows a module to write to the admin notification table
- * during the cron run.
+ * Allows a module to write to the admin notification table.
  *
  * @param $title
  *   A generic phrase indicating what the notification is for.

+ 28 - 1
tripal/api/tripal.terms.api.inc

@@ -389,7 +389,34 @@ function tripal_get_term_details($vocabulary, $accession) {
     $module = $stores[$keys[0]]['module'];
     $function = $module . '_vocab_get_term';
     if (function_exists($function)) {
-      return $function($vocabulary, $accession);
+      $term = $function($vocabulary, $accession);
+      
+      // Make sure the term has a URL. If it does not, then use the Tripal
+      // interface as the URL for the term.
+      $url_missing = FALSE;
+      if (!$term['url']) {
+        $url_missing = TRUE;
+        $term['url'] = url('cv/lookup/' . $term['vocabulary']['short_name'] . '/' . $term['accession'], ['absolute' => TRUE]);
+      }
+      if (!$term['vocabulary']['sw_url']) {
+        $url_missing = TRUE;
+        $term['vocabulary']['sw_url'] = url('cv/lookup/' . $term['vocabulary']['short_name'] . '/' . $term['accession'], ['absolute' => TRUE]);
+      }
+      // Let the user know that the vocabulary is missing.
+      if ($url_missing) {
+        tripal_add_notification(
+          "Missing CV term URL", 
+          t("The controlled vocabulary, %vocab, is missing a URL. Tripal will handle " .
+            "this by linking to the cv/lookup page of this site. However, the correct " .
+            "should be updated for this site", 
+            ['%vocab' => $term['vocabulary']['short_name']]),
+          'Controlled Vocabularies', 
+          NULL, 
+          'mising-vocab-' . $term['vocabulary']['short_name']
+        );
+      }
+      
+      return $term;
     }
   }
 }

+ 49 - 0
tripal/includes/TripalBundleUIController.inc

@@ -56,6 +56,55 @@ class TripalBundleUIController extends EntityDefaultUIController {
 
     return $forms;
   }
+  
+  /**
+   * Renders the Bundle overview table
+   */
+  public function overviewTable($conditions = array()) {
+    $entities = entity_load($this->entityType, FALSE, $conditions);
+
+    // Sort the entities by label.
+    $sorted = [];    
+    foreach ($entities as $entity) {
+      $sorted[$entity->label] = $entity;
+    }
+    ksort($sorted, SORT_STRING|SORT_FLAG_CASE);
+    
+    $rows = array();
+    foreach ($sorted as $entity) {
+      // Get the term for this content type
+      $additional_cols = [$entity->term->name . ' (' . l($entity->accession, 'cv/lookup/' . $entity->term->vocab->vocabulary . '/' . $entity->term->accession) . ')'];
+      $rows[] = $this->overviewTableRow($conditions, 
+        entity_id($this->entityType, $entity), $entity,
+        $additional_cols);
+    }
+    // Assemble the right table header.
+    $header = array(t('Label'));
+    if (!empty($this->entityInfo['exportable'])) {
+      $header[] = t('Status');
+    }
+    $header[] = array(
+      'data' => t('Term'),
+    );
+    // Add operations with the right colspan.
+    $field_ui = !empty($this->entityInfo['bundle of']) && module_exists('field_ui');
+    $exportable = !empty($this->entityInfo['exportable']);
+    $colspan = 3;
+    $colspan = $field_ui ? $colspan + 2 : $colspan;
+    $colspan = $exportable ? $colspan + 1 : $colspan;
+    $header[] = array(
+      'data' => t('Operations'),
+      'colspan' => $colspan,
+    );
+    
+    $render = array(
+      '#theme' => 'table',
+      '#header' => $header,
+      '#rows' => $rows,
+      '#empty' => t('None.'),
+    );
+    return $render;
+  }
 
 }
 

+ 1 - 2
tripal/includes/TripalEntityUIController.inc

@@ -316,7 +316,6 @@ function tripal_view_entity($entity, $view_mode = 'full') {
        $query->propertyCondition('status', 0);
      }
    }
-   //$query->propertyOrderBy('created', 'DESC');
 
    // Find out the total number of records and determine what page we're on, and
    // initialize the pager.
@@ -797,4 +796,4 @@ function tripal_entity_form_ajax_callback($form, $form_state) {
    }
    return FALSE;
 
- }
+ }

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

@@ -108,8 +108,8 @@ class TripalFieldWidget {
     );
     $widget['#field'] = $this->field;
     $widget['#instance'] = $this->instance;
-    $widget['#element_validate'] = array('tripal_field_widget_form_validate');
     $widget['#theme'] = 'tripal_field_default';
+    $widget['#element_validate'] = array('tripal_field_widget_form_validate');
   }
 
   /**
@@ -125,6 +125,16 @@ class TripalFieldWidget {
 
   }
 
+  /**
+   * Performs validation of the widget form when setting defaults.
+   *
+   * Use this validate to ensure that form values are entered correctly when
+   * a user edits the defaults on the field edit page (available from the
+   * "managed fields" section of the Content type page. 
+   */
+  public function validateDefaults($element, $form, &$form_state, $langcode, $delta) {
+    
+  }
 
   /**
    * Performs extra commands when the entity form is submitted.

+ 22 - 0
tripal/includes/tripal.field_storage.inc

@@ -76,10 +76,18 @@ function tripal_field_storage_query($query) {
   $select->join('tripal_bundle', 'TB', 'TE.bundle = TB.name');
   $select->fields('TE', array('id'));
   $select->fields('TB', array('name'));
+  
+  // Apply any entity condition filters.
+  if ($query->entityConditions) {
+    if (array_key_exists('bundle', $query->entityConditions)) {
+      $select->condition('TB.name', $query->entityConditions['bundle']['value']);
+    }
+  }
 
   // Add in any filters to the query.
   foreach ($query->fieldConditions as $index => $condition) {
     $field = $condition['field'];
+    
     // Skip conditions that don't belong to this storage type.
     if ($field['storage']['type'] != 'tripal_no_storage') {
       continue;
@@ -107,6 +115,20 @@ function tripal_field_storage_query($query) {
       $select->orderBy('TB.label', $direction);
     }
   }
+  
+  // Add a range of records to retrieve
+  if (isset($query->range)) {
+    $select->range($query->range['start'], $query->range['length']);
+  }
+  
+  // Only include records that are deleted.  Tripal doesn't keep track of
+  // records that are deleted that need purging separately so we can do nothing
+  // with this.
+  if (isset($query->deleted)) {
+    // There won't ever be field data marked as deleted so just created a 
+    // condition that always evaluates to false.
+    $select->where('1=0');
+  }
 
   // Perform the query and return the results.
   $entities = $select->execute();

+ 9 - 1
tripal/includes/tripal.fields.inc

@@ -771,7 +771,15 @@ function tripal_field_widget_form_validate($element, &$form_state, $form) {
   tripal_load_include_field_class($widget_class);
   if (class_exists($widget_class)) {
     $widget = new $widget_class($field, $instance);
-    $widget->validate($element, $form, $form_state, $langcode, $delta);
+    
+    // Set the validation function for this field widget depending on the
+    // form displaying the widget.
+    if ($form['#form_id'] == 'field_ui_field_edit_form') {
+      $widget->validateDefaults($element, $form, $form_state, $langcode, $delta);
+    }
+    else {
+      $widget->validate($element, $form, $form_state, $langcode, $delta);
+    }
   }
 }
 

+ 14 - 2
tripal_chado/api/tripal_chado.query.api.inc

@@ -2065,7 +2065,19 @@ function chado_db_select($table, $alias = NULL, array $options = array()) {
   if (empty($options['target'])) {
     $options['target'] = 'default';
   }
-  $conninfo = Database::getConnectionInfo();
-  $conn = new ChadoDatabaseConnection($conninfo['default']);
+   
+  // We only want one connection for chado_db_select, so the first time we
+  // create it, we'll save it in the $GLOBALS array for use next time this
+  // function is called. If we don't do this, then the function will
+  // open too many connections and cause the database server to block.
+  $conn = NULL;
+  if (!array_key_exists('chado_db_select_connnection', $GLOBALS)) {
+    $conninfo = Database::getConnectionInfo();
+    $conn = new ChadoDatabaseConnection($conninfo['default']);
+    $GLOBALS['chado_db_select_connnection'] = $conn;
+  }
+  else {
+    $conn = $GLOBALS['chado_db_select_connnection'];
+  }
   return $conn->select($table, $alias, $options);
 }

+ 4 - 1
tripal_chado/api/tripal_chado.variables.api.inc

@@ -788,9 +788,12 @@ function chado_expand_var($object, $type, $to_expand, $table_options = array())
       }
       $foreign_table_desc = chado_get_schema($foreign_table);
 
-      // TODO: if we don't get a foreign_table (which could happen of a custom 
+      // If we don't get a foreign_table (which could happen of a custom 
       // table is not correctly defined or the table name is mispelled then we 
       // should return gracefully.
+      if(!is_array($foreign_table_desc)) {
+        return $object;
+      }
 
       // BASE CASE: If it's connected to the base table via a FK constraint
       // then we have all the information needed to expand it now.

+ 13 - 2
tripal_chado/includes/TripalFields/chado_linker__prop/chado_linker__prop_widget.inc

@@ -7,7 +7,7 @@ class chado_linker__prop_widget extends ChadoFieldWidget {
   // The list of field types for which this formatter is appropriate.
   public static $field_types = array('chado_linker__prop');
 
-  /**
+    /**
    *
    * @see TripalFieldWidget::form()
    */
@@ -109,6 +109,17 @@ class chado_linker__prop_widget extends ChadoFieldWidget {
       '#value' => $rank,
     );
   }
+  
+  /**
+   * @see TripalFieldWidget::validateDefaults()
+   */
+  public function validateDefaults($element, $form, &$form_state, $langcode, $delta) {
+    $field_name = $this->field['field_name'];
+    $field_table = $this->instance['settings']['chado_table'];
+    
+    $value = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__value'];
+    $form_state['values'][$field_name]['und'][$delta]['value'] = $value;    
+  }
 
   /**
    *
@@ -121,7 +132,7 @@ class chado_linker__prop_widget extends ChadoFieldWidget {
     $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];
     $base_table = $this->instance['settings']['base_table'];

+ 8 - 0
tripal_chado/includes/TripalFields/data__accession/data__accession_widget.inc

@@ -94,6 +94,14 @@ class data__accession_widget extends ChadoFieldWidget {
     $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'];
+    
+    // Is this field required?
+    if ($element['#required'] and !$db_id) {
+      form_set_error($field_name . '][und][0][db_id', "A database for the accession must be provided.");
+    }
+    if ($element['#required'] and !$accession) {
+      form_set_error($field_name . '][und][0][accession', "An accession number must be provided.");
+    }
 
     // If user did not select a database, we want to remove dbxref_id from the
     // field. We use '__NULL__' because this field is part of the base table

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

@@ -45,8 +45,19 @@ class data__sequence_widget extends ChadoFieldWidget {
       '#cols' => 30,
     );
   }
-
-
+  
+  /**
+   * @see TripalFieldWidget::validateDefaults()
+   */
+  public function validateDefaults($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'];
+    
+    $value = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $field_column];
+    $form_state['values'][$field_name]['und'][$delta]['value'] = $value;
+  }
+  
   /**
    *
    * @see TripalFieldWidget::submit()
@@ -55,7 +66,7 @@ class data__sequence_widget extends ChadoFieldWidget {
     $field_name = $this->field['field_name'];
     $field_table = $this->instance['settings']['chado_table'];
     $field_column = $this->instance['settings']['chado_column'];
-
+    
     // Remove any white spaces.
     $residues = $form_state['values'][$field_name]['und'][$delta]['chado-' . $field_table . '__' . $field_column];
     if ($residues) {

+ 145 - 0
tripal_chado/includes/TripalFields/operation__analysis/operation__analysis.inc

@@ -0,0 +1,145 @@
+<?php
+
+class operation__analysis extends ChadoField {
+
+  // The default lable for this field.
+  public static $default_label = 'Analysis';
+
+  // The default description for this field.
+  public static $description = 'Application of analytical methods to existing data of a specific type.';
+
+  // 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  = [
+    // The short name for the vocabulary (e.g. shcema, SO, GO, PATO, etc.).
+    'term_vocabulary' => 'operation',
+    // The name of the term.
+    'term_name' => 'Analysis',
+    // The unique ID (i.e. accession) of the term.
+    'term_accession' => '2945',
+    // 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 = 'operation__analysis_widget';
+
+  // The default formatter for this field.
+  public static $default_formatter = 'operation__analysis_formatter';
+
+
+  /**
+   * @see TripalField::load()
+   */
+  public function load($entity) {
+    $record = $entity->chado_record;
+    $settings = $this->instance['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'];
+
+    // Get the terms for each of the keys for the 'values' property.
+    $name_term = chado_get_semweb_term('analysis', 'name');
+
+    // Set some defaults for the empty record.
+    $entity->{$field_name}['und'][0] = [
+      'value' => [],
+    ];
+
+    if (!$record or !$record->analysis_id) {
+      return;
+    }
+    $linker_field = 'chado-' . $field_table . '__' . $field_column;
+    $entity->{$field_name}['und'][0]['value'] = [
+      $name_term => $record->{$field_column}->name,
+    ];
+    $entity->{$field_name}['und'][0][$linker_field] = $record->{$field_column}->analysis_id;
+
+    // Is there a published entity for this analysis?
+    if (property_exists($record->{$field_column}, 'entity_id')) {
+      $entity->{$field_name}['und'][0]['value']['entity'] = 'TripalEntity:' . $record->{$field_column}->entity_id;
+    }
+  }
+
+  
+  /**
+   * @see TripalField::elementInfo()
+   */
+  public function elementInfo() {
+    $field_term = $this->getFieldTermID();
+
+    $name_term = chado_get_semweb_term('analysis', 'name');
+    
+    return [
+      $field_term => [
+        'operations' => ['eq', 'contains', 'starts'],
+        'sortable' => TRUE,
+        'searchable' => TRUE,
+        'readonly' => FALSE,
+        'type' => 'xs:complexType',
+        'elements' => [
+          $name_term => [
+            'searchable' => TRUE,
+            'name' => 'name',
+            'operations' => ['eq', 'ne', 'contains', 'starts'],
+            'sortable' => FALSE,
+            'type' => 'xs:string',
+            'readonly' => TRUE,
+            'required' => FALSE,
+          ],
+          'entity' => [
+            'searchable' => FALSE,
+          ],
+        ],
+      ],
+    ];
+  }
+
+  /**
+   * @see ChadoField::query()
+   */
+  public function query($query, $condition) {
+    $alias = $this->field['field_name'];
+    $operator = $condition['operator'];
+
+    $field_term_id = $this->getFieldTermID();
+    $name_term = $field_term_id . ',' . chado_get_semweb_term('analysis', 'name');
+
+    // Join to the organism table for this field.
+    $this->queryJoinOnce($query, 'analysis', $alias, "base.analysis_id = $alias.analysis_id");
+
+    // If the column is the field name then we're during a search on the full
+    // scientific name.
+    if ($condition['column'] == $field_term_id or 
+        $condition['column'] == $name_term) {      
+      $query->condition("$alias.name", $condition['value'], $operator);
+    }
+  }
+
+  /**
+   * @see ChadoField::queryOrder()
+   */
+  public function queryOrder($query, $order) {
+    $alias = $this->field['field_name'];
+
+    $field_term_id = $this->getFieldTermID();
+    $name_term = $field_term_id . ',' . chado_get_semweb_term('analysis', 'name');
+
+    // Join to the organism table for this field.
+    $this->queryJoinOnce($query, 'analysis', $alias, "base.analysis_id = $alias.analysis_id");
+
+    // Now perform the sort.
+    if ($order['column'] == $name_term) {
+      $query->orderBy("$alias.name", $order['direction']);
+    }
+  }
+}

+ 33 - 0
tripal_chado/includes/TripalFields/operation__analysis/operation__analysis_formatter.inc

@@ -0,0 +1,33 @@
+<?php
+
+class operation__analysis_formatter extends ChadoFieldFormatter {
+
+  // The default lable for this field.
+  public static $default_label = 'Analysis';
+
+  // The list of field types for which this formatter is appropriate.
+  public static $field_types = ['operation__analysis'];
+
+  /**
+   * @see TripalFieldFormatter::view()
+   */
+  public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
+    if (count($items) > 0) {
+      
+      $name_term = chado_get_semweb_term('analysis', 'name');
+      
+      $content = $items[0]['value'][$name_term];
+      if (array_key_exists('entity', $items[0]['value'])) {
+        list($entity_type, $entity_id) = explode(':', $items[0]['value']['entity']);
+        $content = l($content, 'bio_data/' . $entity_id);
+      }
+
+      // 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] = [
+        '#type' => 'markup',
+        '#markup' => $content,
+      ];
+    }
+  }
+}

+ 72 - 0
tripal_chado/includes/TripalFields/operation__analysis/operation__analysis_widget.inc

@@ -0,0 +1,72 @@
+<?php
+
+class operation__analysis_widget extends ChadoFieldWidget {
+
+  // The default lable for this field.
+  public static $default_label = 'Analysis';
+
+  // The list of field types for which this formatter is appropriate.
+  public static $field_types = ['operation__analysis'];
+
+
+  /**
+   * @see TripalFieldWidget::form()
+   */
+  public function 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'];
+
+    // Set the linker field appropriately.
+    $linker_field = 'chado-' . $field_table . '__' . $field_column;
+
+    $analysis_id = 0;
+    if (count($items) > 0 and array_key_exists($linker_field, $items[0])) {
+      $analysis_id = $items[0][$linker_field];
+    }
+
+    $widget['value'] = [
+      '#type' => 'value',
+      '#value' => array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
+    ];
+    $sql = "SELECT analysis_id, name FROM {analysis} ORDER BY name";
+    $results = chado_query($sql);
+    $options = ['' => '- Select an analysis -'];
+    while ($r = $results->fetchObject()) {
+      $options[$r->analysis_id] = $r->name;
+    }
+    $widget[$linker_field] = [
+      '#type' => 'select',
+      '#title' => $element['#title'],
+      '#description' => $element['#description'],
+      '#options' => $options,
+      '#default_value' => $analysis_id,
+      '#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_type = $this->field['type'];
+    $field_table = $this->instance['settings']['chado_table'];
+    $field_column = $this->instance['settings']['chado_column'];
+
+    // Set the linker field appropriately.
+    $linker_field = 'chado-' . $field_table . '__' . $field_column;
+    
+    // Make sure the value is set to the organism_id
+    $analysis_id = $form_state['values'][$field_name]['und'][0][$linker_field];
+    $form_state['values'][$field_name]['und'][0]['value'] = $analysis_id;
+  }
+}

+ 2 - 2
tripal_chado/includes/TripalFields/sbo__database_cross_reference/sbo__database_cross_reference_widget.inc

@@ -99,7 +99,7 @@ class sbo__database_cross_reference_widget extends ChadoFieldWidget {
       '#disabled' => $db_id ? FALSE : TRUE,
     );
   }
-
+    
   /**
    * @see TripalFieldWidget::validate()
    */
@@ -111,7 +111,7 @@ class sbo__database_cross_reference_widget extends ChadoFieldWidget {
     $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($table_name);
     $pkey = $schema['primary key'][0];
     $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);

+ 6 - 6
tripal_chado/includes/TripalFields/schema__additional_type/schema__additional_type_widget.inc

@@ -19,8 +19,8 @@ class schema__additional_type_widget extends ChadoFieldWidget {
     $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'];
+    $enforce_vocabulary = $this->instance['settings']['vocabulary'];
+    $enforce_parent_term = $this->instance['settings']['parent_term'];
     
     $linker_field = 'chado-' . $field_table . '__' . $field_column;
 
@@ -44,8 +44,8 @@ class schema__additional_type_widget extends ChadoFieldWidget {
     // 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 ($enforce_parent_term) {
+      list ($vocabulary, $accession) = explode(':', $enforce_parent_term);
       if ($vocabulary and $accession) {
         $sql = "
           SELECT
@@ -69,8 +69,8 @@ class schema__additional_type_widget extends ChadoFieldWidget {
         }
       }
     }
-    elseif ($vocabulary) {
-      $cv = chado_get_cv(array('name' => $vocabulary));
+    elseif ($enforce_vocabulary) {
+      $cv = chado_get_cv(array('name' => $enforce_vocabulary));
       $options = chado_get_cvterm_select_options($cv->cv_id);
     }
     // If no vocabulary or parent term are provided then just give a generic

+ 1 - 1
tripal_chado/includes/TripalFields/schema__alternate_name/schema__alternate_name_widget.inc

@@ -123,6 +123,7 @@ class schema__alternate_name_widget extends ChadoFieldWidget {
       '#required' => $element['#required'],
     );
   }
+    
   /**
    * @see TripalFieldWidget::validate()
    */
@@ -139,7 +140,6 @@ class schema__alternate_name_widget extends ChadoFieldWidget {
     $fkeys = array_values($schema['foreign keys'][$base_table]['columns']);
     $fkey = $fkeys[0];
 
-
     $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'];

+ 1 - 1
tripal_chado/includes/TripalFields/schema__publication/schema__publication_widget.inc

@@ -150,7 +150,7 @@ class schema__publication_widget extends ChadoFieldWidget {
     // it out so that the Chado field_storage infrastructure won't try to
     // write a record.
     if (!$title) {
-      $form_state['values'][$field_name]['und'][$delta]['value'] = '';
+      $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 . '__pub_id'] = '';
     }

+ 2 - 2
tripal_chado/includes/TripalFields/sio__annotation/sio__annotation_widget.inc

@@ -174,7 +174,7 @@ class sio__annotation_widget extends ChadoFieldWidget {
       );
     }
   }
-
+ 
   /**
    *
    * @see TripalFieldWidget::submit()
@@ -185,7 +185,7 @@ class sio__annotation_widget extends ChadoFieldWidget {
     $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];

+ 5 - 7
tripal_chado/includes/loaders/tripal_chado.pub_importer_PMID.inc

@@ -356,7 +356,7 @@ function tripal_pub_PMID_parse_pubxml($pub_xml) {
   if (!$pub_xml) {
     return $pub;
   }
-
+  
   // read the XML and iterate through it.
   $xml = new XMLReader();
   $xml->xml(trim($pub_xml));
@@ -512,9 +512,7 @@ function tripal_pub_PMID_parse_article($xml, &$pub) {
           tripal_pub_PMID_parse_journal($xml, $pub);
           break;
         case 'ArticleTitle':
-          $xml->read();
-          // remoave any trailing period from the title
-          $pub['Title'] = trim(preg_replace('/\.$/', '', $xml->value));
+          $pub['Title'] = $xml->readString();
           break;
         case 'Abstract':
           tripal_pub_PMID_parse_abstract($xml, $pub);
@@ -675,14 +673,14 @@ function tripal_pub_PMID_parse_abstract($xml, &$pub) {
       switch ($element) {
         case 'AbstractText':
           $label = $xml->getAttribute('Label');
-          $xml->read();
+          $value = $xml->readString();
           if ($label) {
-            $part = "<p><b>$label</b></br>" . $xml->value . '</p>';
+            $part = "<p><b>$label</b></br>" . $value . '</p>';
             $abstract .= $part;
             $pub['Structured Abstract Part'][] = $part;
           }
           else {
-            $abstract .= '<p>' . $xml->value . '</p>';
+            $abstract .= "<p>" . $value . "</p>";
           }
           break;
         case 'CopyrightInformation':

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

@@ -730,6 +730,16 @@ function tripal_chado_field_storage_query($query) {
       } // end foreach ($field['bundles']['TripalEntity'] as $bundle_name) {
     } // end if ($sort['type'] == 'field') {
   } // end foreach ($query->order as $index => $sort) {
+  
+  
+  // Only include records that are deleted.  Tripal doesn't keep track of
+  // records that are deleted that need purging separately so we can do nothing
+  // with this.
+  if (isset($query->deleted)) {
+    // There won't ever be field data marked as deleted so just created a
+    // condition that always evaluates to false.
+    $cquery->where('1=0');
+  }
 
  //dpm($cquery->__toString());
  //dpm($cquery->getArguments());

+ 64 - 2
tripal_chado/includes/tripal_chado.fields.inc

@@ -554,6 +554,21 @@ function tripal_chado_bundle_fields_info_custom(&$info, $details, $entity_type,
       ),
     );
   } 
+  
+  // Analysis Id
+  if (array_key_exists('analysis_id', $schema['fields'])) {
+    $field_name = 'operation__analysis';
+    $field_type = 'operation__analysis';
+    $info[$field_name] = array(
+      'field_name' => $field_name,
+      'type' => $field_type,
+      'cardinality' => 1,
+      'locked' => FALSE,
+      'storage' => array(
+        'type' => 'field_chado_storage',
+      ),
+    );
+  }
 
 }
 
@@ -833,6 +848,8 @@ function tripal_chado_bundle_instances_info($entity_type, $bundle) {
   tripal_chado_bundle_instances_info_custom($info, $entity_type, $bundle, $details);
   tripal_chado_bundle_instances_info_linker($info, $entity_type, $bundle, $details);
 
+  // dpm($info);
+
   return $info;
 
 }
@@ -1527,6 +1544,11 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
   // BASE DBXREF
   if (array_key_exists('dbxref_id', $schema['fields'])) {
     $field_name = 'data__accession';
+    $required = FALSE;
+    if (array_key_exists('not null', $schema['fields']['dbxref_id']) and
+        $schema['fields']['dbxref_id']['not null']) {
+      $required = TRUE;
+    }
     $info[$field_name] = array(
       'field_name' => $field_name,
       'entity_type' => $entity_type,
@@ -1534,7 +1556,7 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
       'label' => 'Accession',
       'description' => 'This field specifies the unique stable accession (ID) for
         this record. It requires that this site have a database entry.',
-      'required' => FALSE,
+      'required' => $required,
       'settings' => array(
         'auto_attach' => TRUE,
         'chado_table' => $table_name,
@@ -2028,6 +2050,46 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
       ),
     );
   } 
+  // Analysis Id
+  if (array_key_exists('analysis_id', $schema['fields'])) {
+    $field_name = 'operation__analysis';
+    $is_required = FALSE;
+    if (array_key_exists('not null', $schema['fields']['analysis_id']) and
+        $schema['fields']['analysis_id']['not null']) {
+      $is_required = TRUE;
+    }
+    $info[$field_name] =  array(
+      'field_name' => $field_name,
+      'entity_type' => $entity_type,
+      'bundle' => $bundle->name,
+      'label' => 'Analysis',
+      'description' => 'Application of analytical methods to existing data of a specific type.',
+      'required' => $is_required,
+      'settings' => array(
+        'auto_attach' => TRUE,
+        'chado_table' => $table_name,
+        'chado_column' => 'analysis_id',
+        'base_table' => $table_name,
+        'term_vocabulary' => 'operation',
+        'term_name' => 'Analysis',
+        'term_accession' => '2945',
+        
+      ),
+      'widget' => array(
+        'type' => 'operation__analysis_widget',
+        'settings' => array(
+          'display_label' => 0,
+        ),
+      ),
+      'display' => array(
+        'default' => array(
+          'label' => 'inline',
+          'type' => 'operation__analysis_formatter',
+          'settings' => array(),
+        ),
+      ),
+    );
+  }
 }
 
 /**
@@ -2947,4 +3009,4 @@ function tripal_chado_field_views_data_alter(&$result, $field, $module) {
       }
     }
   }
-}
+}

+ 6 - 1
tripal_chado/includes/tripal_chado.phylotree.inc

@@ -5,6 +5,11 @@
  * @param $phylotree
  */
 function tripal_phylogeny_prepare_tree_viewer($phylotree) {
+  
+  // If the phylotree is not provided then just return;
+  if (!$phylotree) {
+    tripal_report_error('tripal_phylotree', TRIPAL_ERROR, 'tripal_phylogeny_prepare_tree_viewer: must provide a $phylotree argument.');
+  }
 
   // Don't prepare for viewing more than once.
   if (property_exists($phylotree, 'prepared_to_view') and
@@ -24,7 +29,7 @@ function tripal_phylogeny_prepare_tree_viewer($phylotree) {
 
   // Don't show tick marks for the taxonomy tree.
   $skip_ticks = 0;
-  if ($phylotree->type_id->name == 'taxonomy' or $phylotree->type_id->name == 'Species tree') {
+  if (!is_null($phylotree->type_id) and ($phylotree->type_id->name == 'taxonomy' or $phylotree->type_id->name == 'Species tree')) {
     $skip_ticks = 1;
   }
 

+ 0 - 5
tripal_ws/includes/TripalWebService/TripalContentService_v0_1.inc

@@ -996,11 +996,6 @@ class TripalContentService_v0_1 extends TripalWebService {
       $member->addContextItem($accession, 'vocab:' . $accession);
       $member->setType($accession);
 
-      // Make sure the term has a URL.
-      $url = $term['url'];
-      if (!$url) {
-        throw new Exception(t('Missing a URL for the term: @term.', array('@term' => $term['vocabulary']['short_name'] . ':' . $term['accession'])));
-      }
       $this->addResourceProperty($member, $label, $bundle->label . ' Collection');
       $member->addContextItem('description', 'rdfs:comment');
       // Get the bundle description. If no description is provided then