소스 검색

Merge branch '7.x-3.x' into 474-tv3-importer_permissions

Lacey-Anne Sanderson 6 년 전
부모
커밋
472a41662d
28개의 변경된 파일882개의 추가작업 그리고 1105개의 파일을 삭제
  1. 1 1
      legacy/tripal_phylogeny/tripal_phylogeny.info
  2. 230 59
      tripal/api/tripal.entities.api.inc
  3. 1 0
      tripal/api/tripal.jobs.api.inc
  4. 16 1
      tripal/api/tripal.notice.api.inc
  5. 4 2
      tripal/api/tripal.terms.api.inc
  6. 6 5
      tripal/includes/TripalBundleUIController.inc
  7. 41 45
      tripal/includes/TripalEntityController.inc
  8. 3 3
      tripal/includes/TripalImporter.inc
  9. 1 1
      tripal/includes/TripalJob.inc
  10. 7 6
      tripal/includes/tripal.bulk_update.inc
  11. 0 780
      tripal/includes/tripal.extensions.inc
  12. 28 4
      tripal/includes/tripal.fields.inc
  13. 0 18
      tripal/tripal.module
  14. 1 0
      tripal_chado/api/tripal_chado.api.inc
  15. 3 1
      tripal_chado/api/tripal_chado.query.api.inc
  16. 201 0
      tripal_chado/includes/TripalFields/efo__array_design/efo__array_design.inc
  17. 37 0
      tripal_chado/includes/TripalFields/efo__array_design/efo__array_design_formatter.inc
  18. 75 0
      tripal_chado/includes/TripalFields/efo__array_design/efo__array_design_widget.inc
  19. 0 4
      tripal_chado/includes/TripalFields/local__contact/local__contact_widget.inc
  20. 2 2
      tripal_chado/includes/TripalFields/obi__organism/obi__organism.inc
  21. 22 8
      tripal_chado/includes/loaders/tripal_chado.pub_importers.inc
  22. 11 1
      tripal_chado/includes/setup/tripal_chado.setup.inc
  23. 11 9
      tripal_chado/includes/tripal_chado.field_storage.inc
  24. 164 9
      tripal_chado/includes/tripal_chado.fields.inc
  25. 1 0
      tripal_chado/includes/tripal_chado.pub_search.inc
  26. 8 3
      tripal_chado/tripal_chado.module
  27. 3 142
      tripal_ws/includes/TripalFields/remote__data/remote__data_widget.inc
  28. 5 1
      tripal_ws/tripal_ws.module

+ 1 - 1
legacy/tripal_phylogeny/tripal_phylogeny.info

@@ -2,7 +2,7 @@ name = Tripal Phylotree
 description = Supports the phylogeny tables of Chado by providing pages for viewing and editing of phylotrees. Table list at: http://gmod.org/wiki/chado_phylotree_Module. This module was added to Tripal through collaboration with the LegumeInformation group (http://http://legumeinfo.org/)
 core = 7.x
 project = tripal_phylogeny
-package = Tripal Extensions
+package = Tripal v2 Legacy
 version = 7.x-3.0-rc2
 dependencies[] = tripal_core
 dependencies[] = tripal_cv

+ 230 - 59
tripal/api/tripal.entities.api.inc

@@ -627,6 +627,8 @@ function tripal_get_content_type($bundle_name) {
  *
  * @param $bundle_name
  *   The name of the bundle to refresh (e.g. bio_data_4).
+ * @param $term
+ *   The term object for the bundle.
  *
  * @return
  *   The array of field instance names that were added.
@@ -634,38 +636,34 @@ function tripal_get_content_type($bundle_name) {
  * @ingroup tripal_entities_api
  */
 function tripal_create_bundle_fields($bundle, $term) {
-
   $added = array();
 
   // Allow modules to add fields to the new bundle.
   $modules = module_implements('bundle_fields_info');
-  $info = array();
+  $field_info = array();
   foreach ($modules as $module) {
     $function = $module . '_bundle_fields_info';
     $temp = $function('TripalEntity', $bundle);
     if (is_array($temp)) {
       // TODO: it would be good to check this array to make sure it follows
       // protocol.  It would help identify potential errors.
-      $info = array_merge($info, $temp);
+      $field_info = array_merge($field_info, $temp);
     }
   }
 
   // Allow modules to alter which fields should be attached to content
   // types they create.
-  drupal_alter('bundle_fields_info', $info, $bundle, $term);
+  drupal_alter('bundle_fields_info', $field_info, $bundle, $term);
 
   // Iterate through all of the fields and create them.
-  foreach ($info as $field_name => $details) {
+  foreach ($field_info as $field_name => $details) {
     $field_type = $details['type'];
 
-    // TODO: make sure the field term exits. If not then
-    // skip it.
-
     // If the field already exists then skip it.
     $field = field_info_field($details['field_name']);
     if ($field) {
       continue;
-    }
+    }    
 
     // Create the field.
     $field = field_create_field($details);
@@ -677,35 +675,99 @@ function tripal_create_bundle_fields($bundle, $term) {
 
   // Allow modules to add instances to the new bundle.
   $modules = module_implements('bundle_instances_info');
-  $info = array();
+  $instance_info = array();
   foreach ($modules as $module) {
     $function = $module . '_bundle_instances_info';
     $temp = $function('TripalEntity', $bundle);
     if (is_array($temp)) {
       // TODO: it would be good to check this array to make sure it follows
       // protocol.  It would help identify potential errors.
-      $info = array_merge($info, $temp);
+      $instance_info = array_merge($instance_info, $temp);
     }
   }
 
   // Allow modules to alter which fields should be attached to content
   // types they create.
-  drupal_alter('bundle_instances_info', $info, $bundle, $term);
-
+  drupal_alter('bundle_instances_info', $instance_info, $bundle, $term);
+  
+  // Get the list of existing instances
+  $existing_instances = field_info_instances('TripalEntity', $bundle->name);
+  
   // Iterate through all of the field instances and create them.
-  foreach ($info as $field_name => $details) {
+  foreach ($instance_info as $instance_name => $details) {
+    
+    // Make sure the instance has a term. If not, report it and skip the field.
+    if (!array_key_exists('term_vocabulary', $details['settings'])) {
+      tripal_report_error('tripal_fields', TRIPAL_WARNING,
+        'The field instance, !field, is missing the "term_vocabulary" setting. The field instance cannot be added. Please check the field settings.',
+        ['!field' => $instance_name], ['drupal_set_message' => TRUE]);
+        continue;
+    }
+    if (!array_key_exists('term_accession', $details['settings'])) {
+      tripal_report_error('tripal_fields', TRIPAL_WARNING,
+        'The field instance, !field, is missing the "term_accession" setting. The field instance cannot be added. Please check the field settings.',
+        ['!field' => $instance_name], ['drupal_set_message' => TRUE]);
+        continue;}
+    
+    // Make sure the term exists. If not, skip the field instance and 
+    // report an error.
+    $field_term_id = $details['settings']['term_vocabulary'] . ':' . $details['settings']['term_accession'];    
+    $field_term = tripal_get_term_details($details['settings']['term_vocabulary'], $details['settings']['term_accession']);
+    if (!$field_term) {
+      tripal_report_error('tripal_fields', TRIPAL_WARNING, 
+        'The term, !term, for the field, !field, does not exist in the database. The  ' .
+        'field instance cannot be added. Please make sure the term is correct and add it if necessary.',
+        ['!term' => $field_term_id,
+          '!field' => $instance_name],
+        ['drupal_set_message' => TRUE]);
+      continue;
+    }
+    
+    // Make sure the term is not used for any other existing field instance.
+    $skip = FALSE;
+    foreach ($existing_instances as $existing_name => $existing_instance) {
+      // If this instance term is the same as this exsiting term and the 
+      // instance name is not the same then we have a problem.
+      $existing_term_id = $existing_instance['settings']['term_vocabulary'] . ':' . $existing_instance['settings']['term_accession'];
+      $existing_field = field_info_field($existing_name);
+      if ($existing_term_id == $field_term_id and $instance_name != $existing_name) {
+        tripal_report_error('tripal_fields', TRIPAL_WARNING,
+          'The field, !field, uses a term, !term, that is already in use on this content type. The ' .
+          'field instance cannot be added.',
+          ['!term' => $existing_term_id,
+            '!field' => $instance_name],
+          ['drupal_set_message' => TRUE]);
+        $skip = TRUE;
+      }
+      
+      // If the instance term is the same as this exsting term but the storage
+      // types are different then we have a problem.
+      $existing_storage = $existing_field['storage']['type'];
+      $this_field_storage = $field_info[$details['field_name']]['storage']['type'];
+      if ($existing_term_id == $field_term_id and $existing_storage != $this_field_storage) {
+        tripal_report_error('tripal_fields', TRIPAL_WARNING,
+          'The field, !field, provided by the storage type, !type, uses a term, !term, that is already in use on this content type and provided by another storage backend. The ' .
+          'field instance cannot be added.  Perhaps, consider a different term and adjust the data in the database.',
+          ['!term' => $existing_term_id,
+           '!type' => $this_field_storage,
+           '!field' => $instance_name],
+          ['drupal_set_message' => TRUE]);
+        $skip = TRUE;
+      }
+    }
+    if ($skip) {
+      continue;
+    }
 
     // If the field is already attached to this bundle then skip it.
-    $field = field_info_field($details['field_name']);
-    if ($field and array_key_exists('bundles', $field) and
-        array_key_exists('TripalEntity', $field['bundles']) and
-        in_array($bundle->name, $field['bundles']['TripalEntity'])) {
+    if (array_key_exists($instance_name, $existing_instances)) {
       continue;
     }
 
     // Create the field instance.
     $instance = field_create_instance($details);
-    $added[] = $field_name;
+    $existing_instances[$instance_name] = $instance;
+    $added[] = $instance_name;
   }
   return $added;
 }
@@ -1007,14 +1069,14 @@ function tripal_get_default_title_format($bundle) {
 /**
  * Returns an array of tokens based on Tripal Entity Fields.
  *
- * @param TripalBundle $entity
+ * @param TripalBundle $bundle
  *    The bundle entity for which you want tokens.
  * @return
  *    An array of tokens where the key is the machine_name of the token.
  *
  * @ingroup tripal_entities_api
  */
-function tripal_get_entity_tokens($entity, $options = array()) {
+function tripal_get_entity_tokens($bundle, $options = array()) {
   $tokens = array();
 
   // Set default options.
@@ -1023,51 +1085,132 @@ function tripal_get_entity_tokens($entity, $options = array()) {
 
   if ($options['include id']) {
     $token = '[TripalBundle__bundle_id]';
-    $tokens[$token] = array(
+    $tokens[$token] = [
       'label' => 'Bundle ID',
       'description' => 'The unique identifier for this Tripal Content Type.',
       'token' => $token,
       'field_name' => NULL,
       'required' => TRUE
-    );
+    ];
 
     $token = '[TripalEntity__entity_id]';
-    $tokens[$token] = array(
+    $tokens[$token] = [
       'label' => 'Content/Entity ID',
       'description' => 'The unique identifier for an individual piece of Tripal Content.',
       'token' => $token,
       'field_name' => NULL,
       'required' => TRUE
-    );
+    ];
   }
 
-  $fields = field_info_instances('TripalEntity', $entity->name);
-  foreach ($fields as $f) {
-
-    // Build the token from the field information.
-    $token = '[' . $f['field_name'] . ']';
-    $current_token = array(
-      'label' => $f['label'],
-      'description' => $f['description'],
-      'token' => $token,
-      'field_name' => $f['field_name'],
-      'required' => $f['required']
-    );
-
-    // If the required only option is set then we only want to add
-    // required fields to the token list.
-    if ($options['required only'] AND $current_token['required']) {
-      $tokens[$token] = $current_token;
+  $instances = field_info_instances('TripalEntity', $bundle->name);
+  foreach ($instances as $instance_name => $instance) {
+    
+    if (!$instance['required'] and $options['required only']) {
+      continue;
+    }
+    
+    $use_field = FALSE;
+   
+    // Iterate through the TripalEntity fields and see if they have
+    // sub-elements, if so, add those as tokens too.
+    $field_name = $instance['field_name'];
+    if ($instance['entity_type'] == 'TripalEntity') {
+      if (tripal_load_include_field_class($field_name)) {
+        $field = field_info_field($field_name);
+        $field_obj = new $field_name($field, $instance);
+        $element_info = $field_obj->elementInfo();
+        $term_id = $instance['settings']['term_vocabulary'] . ':' . $instance['settings']['term_accession'];
+        if ($element_info and 
+            array_key_exists($term_id, $element_info) and 
+            array_key_exists('elements', $element_info[$term_id]) and count($element_info[$term_id]['elements']) > 0) {
+          $elements = $element_info[$term_id]['elements'];
+          _tripal_get_entity_tokens_for_elements($instance, $field_name, $elements, $tokens, $options);
+        }
+        else {
+          $use_field = TRUE;
+        }
+      }
+      else {
+        $use_field = TRUE;
+      }
+    }
+    else {
+      $use_field = TRUE;
     }
-    // If the required only option is not set then add everything.
-    elseif (!$options['required only']) {
-      $tokens[$token] = $current_token;
+    
+    // If we have no elements to add then just add the field as is.
+    if ($use_field) {
+      // Build the token from the field information.
+      $token = '[' . $instance['field_name'] . ']';
+      $tokens[$token] = [
+        'label' => $instance['label'],
+        'description' => $instance['description'],
+        'token' => $token,
+        'field_name' => $instance['field_name'],
+        'required' => $instance['required']
+      ];
     }
   }
 
   return $tokens;
 }
 
+/**
+ * A recursive helper function to get tokens for element sub fields.
+ * 
+ * @param $instance
+ *   A original field instance object.
+ * @param $parent
+ *   The name of the parent. The first time this is called outside of 
+ *   recursion this should be the field name.
+ * @param $elements
+ *   The array of elements to process.
+ * @param $tokens
+ *   The array of tokens to be added to.
+ */
+function _tripal_get_entity_tokens_for_elements($instance, $parent, $elements, &$tokens, $options) {
+  
+  // Iterate through all of the elements and add tokens for each one.
+  foreach ($elements as $child_term_id => $details) {
+    
+    // We don't need to add the entity element.
+    if ($child_term_id == 'entity') {
+      continue;
+    }
+    
+    // Skip elements that aren't required.
+    $required = array_key_exists('required', $details) ? $details['required'] : FALSE;
+    if (!$required and $options['required only']) {
+      continue;
+    }
+    $token = '[' . $parent . ',' . $child_term_id . ']'; 
+    $label = $child_term_id;
+    if (array_key_exists('name', $details)) {
+      $label = $details['name'];
+    }
+    elseif (preg_match('/:/', $child_term_id)) {
+      list($vocabulary, $accession) = explode(':', $child_term_id);
+      $term = tripal_get_term_details($vocabulary, $accession);
+      $label = $term['name'];
+    }
+
+    // Add the token!
+    $tokens[$token] = [
+      'label' => $label,
+      'description' => array_key_exists('description', $details) ? $details['description'] : '',
+      'token' => $token,
+      'field_name' => $instance['field_name'],
+      'required' => $required
+    ];
+    
+    // Recurse to include sub elements
+    if (array_key_exists('elements', $details)) {
+      _tripal_get_entity_tokens_for_elements($instance, $parent . ',' . $child_term_id, 
+        $details['elements'], $tokens, $options);
+    }
+  }
+}
 /**
  * Replace all Tripal Tokens in a given string.
  *
@@ -1088,8 +1231,8 @@ function tripal_get_entity_tokens($entity, $options = array()) {
  */
 function tripal_replace_entity_tokens($string, &$entity, $bundle_entity = NULL) {
   // Determine which tokens were used in the format string
-  $used_tokens = array();
-  if (preg_match_all('/\[\w+\]/', $string, $matches)) {
+  $used_tokens = [];
+  if (preg_match_all('/\[.*?\]/', $string, $matches)) {
     $used_tokens = $matches[0];
   }
 
@@ -1104,10 +1247,13 @@ function tripal_replace_entity_tokens($string, &$entity, $bundle_entity = NULL)
   // all synced entities causes extreme slowness, so we'll only attach
   // the necessary fields for replacing tokens.
   $attach_fields = array();
-  foreach($used_tokens as $token) {
-    $field_name = str_replace(array('.','[',']'), array('__','',''), $token);
 
-    if (!property_exists($entity, $field_name)) {
+  foreach($used_tokens as $token) {
+    $token = preg_replace('/[\[\]]/', '', $token);
+    $elements = explode(',', $token);
+    $field_name = array_shift($elements);
+    //$field_name = str_replace(array('.','[',']'), array('__','',''), $field_name);
+    if (!property_exists($entity, $field_name) or empty($entity->{$field_name})) {
       $field = field_info_field($field_name);
       $storage = $field['storage'];
       $attach_fields[$storage['type']]['storage'] = $storage;
@@ -1129,20 +1275,28 @@ function tripal_replace_entity_tokens($string, &$entity, $bundle_entity = NULL)
     module_invoke($storage['module'], 'field_storage_load', 'TripalEntity',
         $entities, FIELD_LOAD_CURRENT, $field_ids, array());
   }
-
+  
   // Now that all necessary fields are attached process the tokens.
   foreach($used_tokens as $token) {
-    $field_name = str_replace(array('.','[',']'), array('__','',''), $token);
+    $token = preg_replace('/[\[\]]/', '', $token);
+    $elements = explode(',', $token);
+    $field_name = array_shift($elements);
     $value = '';
-
+    
     if (property_exists($entity, $field_name)) {
+      $value = '';
       // Note: there is a memory leak in field_get_items() so we can't use it
       // here or bulk publishing will slowly erode memory.
-      //$field_value = field_get_items('TripalEntity', $entity, $field_name);
-      if (array_key_exists(0, $entity->{$field_name}['und'])) {
+      // $field_value = field_get_items('TripalEntity', $entity, $field_name);
+      if (array_key_exists('und', $entity->{$field_name}) and 
+          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.
+        // If the value is an array it means we have sub elements and we can
+        // descend through the array to look for matching value.
+        if (is_array($value) and count($elements) > 0) {
+          $value = _tripal_replace_entity_tokens_for_elements($elements, $value);
+        }
+      }    
     }
     // The TripalBundle__bundle_id is a special token for substituting the
     // bundle id.
@@ -1163,16 +1317,33 @@ function tripal_replace_entity_tokens($string, &$entity, $bundle_entity = NULL)
 
     // We can't support tokens that have multiple elements (i.e. in an array).
     if (is_array($value)) {
-      $string = str_replace($token, '', $string);
+      $string = str_replace('[' . $token . ']', '', $string);
     }
     else {
-      $string = str_replace($token, $value, $string);
+      $string = str_replace('[' . $token . ']', $value, $string);
     }
   }
 
   return $string;
 }
 
+/**
+ * A helper function for tripal_replace_entity_tokens to get token values.
+ * 
+ * This helper function is used when the tokens are from subelements.
+ * @param $entity
+ */
+function _tripal_replace_entity_tokens_for_elements($elements, $values) {
+  $term_id = array_shift($elements);
+  $value = $values[$term_id];
+  if (count($elements) == 0) {
+    return $value;
+  }
+  else {
+    _tripal_replace_entity_tokens_for_elements($elements, $value);
+  }
+}
+
 /**
  * Formats the tokens for display.
  *

+ 1 - 0
tripal/api/tripal.jobs.api.inc

@@ -415,6 +415,7 @@ function tripal_launch_job($do_parallel = 0, $job_id = NULL, $max_jobs = -1, $si
 
     // Run the job
     $callback = $job->getCallback();
+    print date('Y-m-d H:i:s') . ": Job ID " . $job_id . ".\n";
     print date('Y-m-d H:i:s') .": Calling: $callback(" . implode(", ", $string_args) . ")\n";
     try {
       $job->run();

+ 16 - 1
tripal/api/tripal.notice.api.inc

@@ -58,6 +58,8 @@ define('TRIPAL_DEBUG',7);
  *   An array of options. Some available options include:
  *     - print: prints the error message to the terminal screen. Useful when
  *       display is the command-line
+ *     - drupal_set_message: set to TRUE to call drupal_set_message with the 
+ *       same error.
  *
  * @ingroup tripal_notify_api
  */
@@ -113,7 +115,7 @@ function tripal_report_error($type, $severity, $message, $variables = array(), $
     watchdog($type, $message, $variables, $severity);
   }
   catch (Exception $e) {
-    print "CRITICAL (TRIPAL): Unable to register error message with watchdog: " . $e->getMessage(). "\n.";
+    print "CRITICAL (TRIPAL): Unable to add error message with watchdog: " . $e->getMessage(). "\n.";
     $options['print'] = TRUE;
   }
 
@@ -129,6 +131,19 @@ function tripal_report_error($type, $severity, $message, $variables = array(), $
   if (isset($options['print'])) {
     print $severity_string . ' (' . strtoupper($type) . '): ' . $print_message . "\n";
   }
+  
+  if (isset($options['drupal_set_message'])) {
+    if (in_array($severity, [TRIPAL_CRITICAL, TRIPAL_ERROR])) {
+      $status = 'error';
+    }
+    elseif ($severity == TRIPAL_WARNING) {
+      $status = 'warning';
+    }
+    else {
+      $status = 'status';
+    }
+    drupal_set_message($print_message, $status);
+  }
 
   // Print to the Tripal error log but only if the severity is not info.
   if (($severity != TRIPAL_INFO)) {

+ 4 - 2
tripal/api/tripal.terms.api.inc

@@ -378,6 +378,7 @@ function tripal_get_term_details($vocabulary, $accession) {
 
   if (empty($vocabulary) OR empty($accession)) {
     tripal_report_error('tripal_term', TRIPAL_ERROR, "Unable to retrieve details for term due to missing vocabulary and/or accession");
+    return FALSE;
   }
 
   // TODO: we need some sort of administrative interface that lets the user
@@ -390,7 +391,7 @@ function tripal_get_term_details($vocabulary, $accession) {
     $function = $module . '_vocab_get_term';
     if (function_exists($function)) {
       $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;
@@ -795,7 +796,8 @@ function tripal_get_term_lookup_form_result($form, $form_state, $field_name = ''
   $values = array();
   $selected = array();
   if ($field_name) {
-    if (array_key_exists('term_match', $form_state['values'][$field_name]['und'][$delta])) {
+    if (array_key_exists('term_match', $form_state['values'][$field_name]['und'][$delta]) and 
+      array_key_exists('terms_list', $form_state['values'][$field_name]['und'][$delta]['term_match'])) {
       $values = $form_state['values'][$field_name]['und'][$delta]['term_match']['terms_list'];
     }
   }

+ 6 - 5
tripal/includes/TripalBundleUIController.inc

@@ -347,7 +347,8 @@ function tripal_tripal_bundle_form($form, &$form_state, $entityDataType) {
   $form['url']['token_display'] = array(
     '#type' => 'fieldset',
     '#title' => t('Available Tokens'),
-    '#description' => t('Copy the token and paste it into the "URL Alias Pattern" text field above.'),
+    '#description' => t('Copy the token and paste it into the "URL Alias Pattern" ' . 
+      'text field above. Please choose tokens that will guarantee a unique URL.'),
     '#collapsible' => TRUE,
     '#collapsed' => TRUE
   );
@@ -488,8 +489,8 @@ function tripal_tripal_bundle_form_submit($form, &$form_state) {
       $includes = array(
         module_load_include('inc', 'tripal', 'includes/tripal.bulk_update'),
       );
-      tripal_add_job('Update all aliases', 'tripal', 'tripal_update_all_urls_and_titles', $args,
-        $user->uid, 10, $includes);
+      tripal_add_job('Update all aliases for content type: ' . $bundle->label, 'tripal', 
+        'tripal_update_all_urls_and_titles', $args, $user->uid, 10, $includes);
     }
     elseif ($trigger == 'Bulk update all aliases'){
       $update = $form_state['input']['url']['url_pattern'];
@@ -502,8 +503,8 @@ function tripal_tripal_bundle_form_submit($form, &$form_state) {
       $includes = array(
         module_load_include('inc', 'tripal', 'includes/tripal.bulk_update'),
       );
-      tripal_add_job('Update all aliases', 'tripal', 'tripal_update_all_urls_and_titles', $args,
-        $user->uid, 10, $includes);
+      tripal_add_job('Update all aliases for content type: ' . $bundle->label, 'tripal', 
+        'tripal_update_all_urls_and_titles', $args, $user->uid, 10, $includes);
     }
 
     $form_state['redirect'] = 'admin/structure/bio_data';

+ 41 - 45
tripal/includes/TripalEntityController.inc

@@ -47,7 +47,6 @@ class TripalEntityController extends EntityAPIController {
       $function = $module . '_entity_create';
       $function($entity, $values['type']);
     }
-
     return $entity;
 
   }
@@ -100,30 +99,23 @@ class TripalEntityController extends EntityAPIController {
    * Sets the title for an entity.
    *
    * @param $entity
+   *   The entity whose title should be changed.
    * @param $title
+   *   The title to use. It can contain tokens the correspond to field values.
+   *   Token should be be compatible with those returned by 
+   *   tripal_get_entity_tokens().
    */
   public function setTitle($entity, $title = NULL) {
-
+    
+    $bundle = tripal_load_bundle_entity(array('name' => $entity->bundle));
+    
     // If no title was supplied then we should try to generate one using the
     // default format set by admins.
-    if (!$title) {
-      // Load the TripalBundle entity for this TripalEntity.
-      // Get the format for the title based on the bundle of the entity.
-      // And then replace all the tokens with values from the entity fields.
-      $bundle_entity = tripal_load_bundle_entity(array('name' => $entity->bundle));
-      $title = tripal_get_title_format($bundle_entity);
-      $title = tripal_replace_entity_tokens($title, $entity, $bundle_entity);
-    }
-    // Check if the passed alias has tokens.
-    if($title && (preg_match_all("/\[[^\]]*\]/", $title, $bundle_tokens))) {
-
-      // Load the TripalBundle entity for this TripalEntity.
-      $bundle_entity = tripal_load_bundle_entity(array('name' => $entity->bundle));
-
-      // And then replace all the tokens with values from the entity fields.
-      $title = tripal_replace_entity_tokens($title, $entity, $bundle_entity);
+    if (!$title) {     
+      $title = tripal_get_title_format($bundle);
     }
-    // As long as we were able to determine a title, we should update it ;-).
+    $title = tripal_replace_entity_tokens($title, $entity, $bundle);
+    
     if ($title) {
       db_update('tripal_entity')
         ->fields(array(
@@ -136,6 +128,13 @@ class TripalEntityController extends EntityAPIController {
 
   /**
    * Sets the URL alias for an entity.
+   * 
+   * @param $entity
+   *   The entity whose URL alias should be changed.
+   * @param $alias
+   *   The alias to use. It can contain tokens the correspond to field values.
+   *   Token should be be compatible with those returned by 
+   *   tripal_get_entity_tokens().
    */
   public function setAlias($entity, $alias = NULL) {
     $source_url = "bio_data/$entity->id";
@@ -145,12 +144,10 @@ class TripalEntityController extends EntityAPIController {
     if (!$alias) {
 
       // Load the TripalBundle entity for this TripalEntity.
-      $bundle_entity = tripal_load_bundle_entity(array('name' => $entity->bundle));
-
       // First get the format for the url alias based on the bundle of the entity.
+      // Then replace all the tokens with values from the entity fields.
+      $bundle_entity = tripal_load_bundle_entity(array('name' => $entity->bundle));
       $alias = tripal_get_bundle_variable('url_format', $bundle_entity->id);
-
-      // And then replace all the tokens with values from the entity fields.
       $alias = tripal_replace_entity_tokens($alias, $entity, $bundle_entity);
     }
 
@@ -158,31 +155,28 @@ class TripalEntityController extends EntityAPIController {
     // the term name and entity id.
     if (!$alias) {
 
-      // Load the term for this TripalEntity.
+      // Load the term for this TripalEntity. Set a default based on the term 
+      // name and entity id. Then replace all the tokens with values from 
+      // the entity fields.
       $term = entity_load('TripalTerm', array('id' => $entity->term_id));
       $term = reset($term);
-
-      // Set a default based on the term name and entity id.
       $alias = str_replace(' ', '', $term->name) . '/[TripalEntity__entity_id]';
-
-      // And then replace all the tokens with values from the entity fields.
       $alias = tripal_replace_entity_tokens($alias, $entity, $bundle_entity);
     }
-    // Check if the passed alias has tokens.
+    
+    // Check if the passed alias has tokens. Load the TripalBundle entity for 
+    // this TripalEntity. Then replace all the tokens with values from the 
+    // entity fields.
     if($alias && (preg_match_all("/\[[^\]]*\]/", $alias, $bundle_tokens))) {
-
-      // Load the TripalBundle entity for this TripalEntity.
       $bundle_entity = tripal_load_bundle_entity(array('name' => $entity->bundle));
-
-      // And then replace all the tokens with values from the entity fields.
       $alias = tripal_replace_entity_tokens($alias, $entity, $bundle_entity);
     }
 
     // Make sure the alias doesn't contain spaces.
-    $alias = preg_replace('/\s+/','-',$alias);
+    //$alias = preg_replace('/\s+/','-',$alias);
     // Or any non alpha numeric characters.
-    $alias = preg_replace('/[^a-zA-Z0-9\-\/]/','',$alias);
-    $alias = preg_replace('/_/','-',$alias);
+    //$alias = preg_replace('/[^a-zA-Z0-9\-\/]/','',$alias);
+    //$alias = preg_replace('/_/','-',$alias);
 
     if ($alias) {
       // Determine if this alias has already been used.
@@ -210,10 +204,7 @@ class TripalEntityController extends EntityAPIController {
           'language' => 'und',
         );
 
-//        path_delete(array('source' => $source_url));
-//        $path = array('source' => $source_url, 'alias' => $alias);
-//        path_save($path);
-        //Now check if an entry with the source url for this entity already
+        // Now check if an entry with the source url for this entity already
         // exists. This is an issue when updating existing url aliases. To avoid
         // creating 404s existing aliases need to be updated and a redirect
         // created to handle the old alias.
@@ -246,15 +237,14 @@ class TripalEntityController extends EntityAPIController {
               ->condition('source', $source_url, '=')
               ->condition('pid', $ea->pid, '=')
               ->execute();
-
           }
         }
         else {
           drupal_write_record('url_alias', $values);
         }
       }
-      // If there is only one alias matching then it might just be that we already
-      // assigned this alias to this entity in a previous save.
+      // If there is only one alias matching then it might just be that we 
+      // already assigned this alias to this entity in a previous save.
       elseif ($num_aliases == 1) {
 
         $bundle_entity = tripal_load_bundle_entity(array('name' => $entity->bundle));
@@ -360,6 +350,9 @@ class TripalEntityController extends EntityAPIController {
         $invocation = 'entity_update';
         $pkeys = array('id');
       }
+      if (property_exists($entity, 'publish') and $entity->publish == TRUE) {
+        $invocation = 'entity_publish';
+      }
 
       // Invoke hook_entity_presave().
       module_invoke_all('entity_presave', $entity, $entity->type);
@@ -389,11 +382,14 @@ class TripalEntityController extends EntityAPIController {
       // Now we need to either insert or update the fields which are
       // attached to this entity. We use the same primary_keys logic
       // to determine whether to update or insert, and which hook we
-      // need to invoke.
+      // need to invoke.  We do not attach fields when publishing an entity.
+      // This is because a field may have default values and if so, those fields
+      // will be attached and the storage backend may then try to insert
+      // fields which should not be inserted because they already exist.
       if ($invocation == 'entity_insert') {
         field_attach_insert('TripalEntity', $entity);
       }
-      else {
+      if ($invocation == 'entity_update') {
         field_attach_update('TripalEntity', $entity);
       }
 

+ 3 - 3
tripal/includes/TripalImporter.inc

@@ -334,7 +334,7 @@ class TripalImporter {
           foreach ($fids as $fid) {
             $file = file_load($fid);
             $arguments['files'][] = array(
-              'file_path' => base_path() . drupal_realpath($file->uri),
+              'file_path' => drupal_realpath($file->uri),
               'fid' => $fid
             );
             $has_file++;
@@ -345,14 +345,14 @@ class TripalImporter {
           $fid = $file_details['fid'];
           $file = file_load($fid);
           $arguments['files'][] = array(
-            'file_path' => base_path() . drupal_realpath($file->uri),
+            'file_path' => drupal_realpath($file->uri),
             'fid' => $fid
           );
           $has_file++;
 
           // For backwards compatibility add the old 'file' element.
           $arguments['file'] = array(
-            'file_path' => base_path() . drupal_realpath($file->uri),
+            'file_path' => drupal_realpath($file->uri),
             'fid' => $fid
           );
         }

+ 1 - 1
tripal/includes/TripalJob.inc

@@ -160,7 +160,7 @@ class TripalJob {
     }
 
     $includes = $details['includes'];
-    if ($path and is_array($path)) {
+    if ($includes and is_array($includes)) {
       foreach ($includes as $path) {
         $full_path = $_SERVER['DOCUMENT_ROOT'] . base_path() . $path;
         if (!empty($path)) {

+ 7 - 6
tripal/includes/tripal.bulk_update.inc

@@ -8,6 +8,7 @@
  * @param $type
  */
 function tripal_update_all_urls_and_titles($bundle_id, $update, $type) {
+
   // Load all the entity_ids.
   $entity_table = 'chado_'.$bundle_id;
   $entities = db_select($entity_table, 'e')
@@ -15,16 +16,16 @@ function tripal_update_all_urls_and_titles($bundle_id, $update, $type) {
     ->orderBy('entity_id', 'ASC')
     ->execute();
   $num_entities = $entities->rowCount();
+  
   // Parse the $update variable for tokens and load those tokens.
-  preg_match_all("/\[[^\]]*\]/", $update, $bundle_tokens);
+  preg_match_all("'/\[.*?\]/'", $update, $bundle_tokens);
 
   $fields = array();
   foreach ($bundle_tokens as $bundle_token) {
-    foreach ($bundle_token as $token) {
-      $string = str_replace(array('[', ']'), '', $token);
-      $field_array = field_info_field($string);
-      $fields[] = $field_array['id'];
-    }
+    $elements = explode(',', $token);
+    $field_name = array_shift($elements);
+    $field_array = field_info_field($field_name);
+    $fields[] = $field_array['id'];
   }
 
   $i = 1;

+ 0 - 780
tripal/includes/tripal.extensions.inc

@@ -1,780 +0,0 @@
-<?php
-
-function tripal_extensions_form($form, &$form_state = NULL) {
-
-  // Get the RSS feed XML from the tripal.info website and save it to
-  // a temp file so that we don't have to keep pulling the XML
-  // everythime the page is loaded. If the temp file is older than 1 hours
-  // then we'll pull it again. The number of seconds in an hour is 3600.
-  $tmp_file = sys_get_temp_dir() . '/tripal_rss_extensions.xml';
-  if (!file_exists($tmp_file) or time() - filemtime($tmp_file) > 3600) {
-    $content = file_get_contents("http://tripal.info/rss/extensions.xml");
-    file_put_contents($tmp_file, $content);
-  }
-  else {
-    $content = file_get_contents($tmp_file);
-  }
-  $xml = new SimpleXmlElement($content);
-  $namespace = "http://tripal.info/rss/extensions/";
-
-
-  $tab = array_key_exists('tab', $_GET) ? $_GET['tab'] : '';
-
-  // Get any filters by categories.
-  $filters = array();
-  if (array_key_exists('values', $form_state)) {
-    foreach ($form_state['values'] as $key => $value) {
-      // Get the category to be filtered on.
-      $matches = array();
-      if (preg_match('/^categories-(.*?)$/', $key, $matches)) {
-        if ($value == 'any') {
-          continue;
-        }
-        $filters[$matches[1]] = $value;
-      }
-    }
-  }
-
-  // Parse the items into an array indexed by type and compatible versions.
-  $extensions = array();
-  $types = array();
-  $type_ids = array();
-  $categories = array();
-  $cvs = array();
-  $tvs = array();
-  foreach ($xml->channel->item as $extension) {
-    // Get the type of extension, convert that into a machine-readable name,
-    // and build the array of types.
-    $type = (string) $extension->category;
-    $type_id = preg_replace('/[^\w]/','_', strtolower($type));
-    $type_ids[$type] = $type_id;
-    if (!in_array($type_id, $types)) {
-      $types[$type] = 1;
-    }
-
-    // Get the categories list for this item.
-    $cats = preg_split('/, /', (string) $extension->children($namespace)->categories);
-
-    // Get the guid for this extension
-    $guid = (string) $extension->guid;
-
-    // In order to get fields in the 'tripal_extension' name space we must
-    // pass in the $namespace to the children function.  We first get the
-    // Tripal versions, then the chado versions and organize the elements
-    // accordintly.
-    $tvs_temp = preg_split('/, /', (string) $extension->children($namespace)->tripal_version);
-    foreach($tvs_temp as $tv) {
-      $tvs[$tv] = 1;
-      $cvs_temp = preg_split('/, /', (string) $extension->children($namespace)->chado_version);
-      foreach($cvs_temp as $cv) {
-        $cvs[$cv] = 1;
-
-        // Keep track of the categories this item has been assigned.
-        foreach ($cats as $cat) {
-          $categories[$tv][$cv][$type][$cat] = 1;
-          $categories['any'][$cv][$type][$cat] = 1;
-          $categories[$tv]['any'][$type][$cat] = 1;
-          $categories['any']['any'][$type][$cat] = 1;
-        }
-
-        // If there are filters then only include extensions that match the filters.
-        if (array_key_exists($type_id, $filters) and !in_array($filters[$type_id], $cats)) {
-          continue;
-        }
-
-        // Index the items by type, tripal version and chado version.
-        $item = array();
-        foreach ($extension->children() as $child) {
-          $item[$child->getName()] = (string) $child;
-        }
-        foreach ($extension->children($namespace) as $child) {
-          $item[$namespace][$child->getName()] = (string) $child;
-        }
-        $extensions[$tv][$cv][$type][$guid] = $item;
-        $extensions['any'][$cv][$type][$guid] = $item;
-        $extensions[$tv]['any'][$type][$guid] = $item;
-        $extensions['any']['any'][$type][$guid] = $item;
-      }
-    }
-  }
-
-  // Convert the arrays from an associative array into a normal array, and sort.
-  $types = array_keys($types);
-  sort($types);
-  $cvs = array_keys($cvs);
-  sort($cvs);
-  $tvs = array_keys($tvs);
-  sort($tvs);
-
-  // Get the Chado version and convert to the expected format
-  $chado_version = chado_get_version(TRUE);
-  $chado_version = preg_replace('/^(\d\.\d).*$/', "v$1x", $chado_version);
-  $my_chado_version = $chado_version;
-  // The default value can come from the pager links (thus via $_GET) or
-  // via ajax call (thus via $form_state).
-  if (array_key_exists('cv', $_GET)) {
-    $chado_version = $_GET['cv'];
-  }
-  if (array_key_exists('values', $form_state) and array_key_exists('cv', $form_state['values'])) {
-    $chado_version = $form_state['values']['cv'];
-  }
-
-  // Get the Tripal version. This is the version set in the tripal.info
-  $info = system_get_info('module', 'tripal');
-  $tripal_version = $info['version'];
-  $tripal_version = preg_replace('/^.*?-(\d\.\d+).*$/', "v$1", $tripal_version);
-  $my_tripal_version = $tripal_version;
-  if (array_key_exists('tv', $_GET)) {
-    $tripal_version = $_GET['tv'];
-  }
-  if (array_key_exists('values', $form_state) and array_key_exists('tv', $form_state['values'])) {
-    $tripal_version = $form_state['values']['tv'];
-  }
-
-  // Add the instructions.
-  $form['instructions'] = array(
-    '#type' => 'item',
-    '#markup' => t('This page will help you find extensions that are available
-      for Tripal.  Select an extension type from the vertical tabs. The content
-      of this page is constructed from an RSS feed provided by tripal.info.
-      There may be no content if the tripal.info site is unavailable. The RSS
-      feed will be cached for one hour.')
-  );
-  // Add the filters fieldset.
-  $form['filters'] = array(
-    '#type' => 'fieldset',
-    '#title' => 'Filters',
-    '#description' => t('You can filter which extensions are visible by
-      changing the Tripal ahd Chado versions. By default only those
-      extensions that are compatible with the currently installed Tripal
-      and Chado verions are shown.'),
-    '#collapsible' => TRUE,
-    '#collapsed' => TRUE,
-  );
-  $summary_message = 'Currently showing extensions compatible with ';
-  if ($tripal_version != 'any' and $chado_version != 'any') {
-    $summary_message .= "<strong>Tripal $tripal_version</strong> and <strong>Chado $chado_version</strong>.";
-  }
-  elseif ($tripal_version == 'any' and $chado_version != 'any') {
-    $summary_message .= "<strong>any Tripal</strong> version and <strong>Chado $chado_version</strong>.";
-  }
-  elseif ($tripal_version != 'any' and $chado_version == 'any') {
-    $summary_message .= "<strong>Tripal $tripal_version</strong> and <strong>any Chado</strong> version.";
-  }
-  elseif ($tripal_version == 'any' and $chado_version == 'any') {
-    $summary_message .= "<strong>any Tripal</strong> version and <strong>any Chado</strong> version.";
-  }
-  $form['filter_summary'] = array(
-    '#type' => 'item',
-    '#markup' => $summary_message,
-  );
-
-  // Add the Tripal version select box.
-  $options = array();
-  $options['any'] = '--Any--';
-  foreach ($tvs as $tv) {
-    $options[$tv] = $tv;
-  }
-  $form['filters']['tv'] = array(
-    '#type' => 'select',
-    '#title' => 'Tripal',
-    '#options' => $options,
-    '#default_value' => $tripal_version,
-    '#ajax'  => array(
-      'callback' => "tripal_extensions_form_ajax_callback",
-      'wrapper'  => 'tripal_extensions',
-      'effect'   => 'fade',
-      'method'   => 'replace',
-    ),
-    '#prefix' => '<div style="float: left;">',
-    '#suffix' => '</div>'
-  );
-
-  // Add the Chado version select box.
-  $options = array();
-  $options['any'] = '--Any--';
-  foreach ($cvs as $cv) {
-    $options[$cv] = $cv;
-  }
-  $form['filters']['cv'] = array(
-    '#type' => 'select',
-    '#title' => 'Chado',
-    '#options' => $options,
-    '#default_value' => $chado_version,
-    '#ajax'  => array(
-      'callback' => "tripal_extensions_form_ajax_callback",
-      'wrapper'  => 'tripal_extensions',
-      'effect'   => 'fade',
-      'method'   => 'replace',
-    ),
-    '#prefix' => '<div style="float: left; padding-left: 10px">',
-    '#suffix' => '</div>'
-  );
-
-  // Add the vertical tabs
-  $form['extensions'] = array(
-    '#type' => 'vertical_tabs',
-    '#default_tab' => $tab,
-  );
-
-  // Add the fieldsets for each type
-  foreach ($types as $type) {
-    $form[$type] = array(
-      '#id'          => $type_ids[$type],
-      '#type'        => 'fieldset',
-      '#title'       => $type . 's',
-      '#collapsed'   => TRUE,
-      '#collapsible' => TRUE,
-      '#group'       => 'extensions',
-    );
-  }
-
-  // Iterate through all of the extensions and add them to the form.
-  $compatible_extensions = array();
-  if (array_key_exists($tripal_version, $extensions) and
-      array_key_exists($chado_version, $extensions[$tripal_version])) {
-    $compatible_extensions = $extensions[$tripal_version][$chado_version];
-  }
-  tripal_extension_form_add_extensions($form, $form_state,
-    $compatible_extensions, $categories, $tripal_version,
-    $chado_version, $my_tripal_version, $my_chado_version, $type_ids,
-    $namespace, $filters);
-
-  foreach ($types as $type) {
-    if (count(element_children($form[$type])) == 0) {
-      $form[$type]['empty'] = array(
-        '#type' => 'item',
-        '#markup' => '<strong>There are no matching ' . strtolower($type) . '(s).</strong>',
-      );
-    }
-  }
-
-  $form['#prefix'] = '<div id="tripal_extensions">';
-  $form['#suffix'] = '</div>';
-  $form['#submit'][] = 'tripal_extensions_form_submit';
-  return $form;
-}
-
-/**
- * Adds each extension to the form.
- *
- * This function exits to simplify the the tripal_extension_form()
- * function.
- */
-function tripal_extension_form_add_extensions(&$form, $form_state, $extensions,
-  $categories, $tripal_version, $chado_version, $my_tripal_version,
-  $my_chado_version, $type_ids, $namespace, $filters) {
-
-  // Iterate through the extensions. We will add a pager for
-  // each type of extension, and display only those that should appear
-  // on the page.
-  $type_index = 0;
-  foreach ($extensions as $type => $extensions) {
-    $total_items = count($extensions);
-
-    // Indicate how many matching extensions were found
-    $form[$type]['total_found'] = array(
-      '#type' => 'item',
-      '#markup' => '<strong>Found ' . $total_items . ' matching ' . strtolower($type) . '(s)</strong>',
-    );
-
-    // Add the category select box;
-    $cats = array_keys($categories[$tripal_version][$chado_version][$type]);
-    sort($cats);
-    $options = array();
-    $options['any'] = '--Any--';
-    foreach ($cats as $cat) {
-      $options[$cat] = $cat;
-    }
-    // The default value can come from the pager links (thus via $_GET) or
-    // via ajax call (thus via $form_state).
-    $default_filter = '';
-    if (array_key_exists('categories-' . $type_ids[$type], $_GET)) {
-      $default_filter = $_GET['categories-' . $type_ids[$type]];
-    }
-    if (array_key_exists('values', $form_state) and array_key_exists('categories-' . $type_ids[$type], $form_state['values'])) {
-      $default_filter = $form_state['values']['categories-' . $type_ids[$type]];
-    }
-    $form[$type]['filters']['categories-' . $type_ids[$type]] = array(
-      '#type' => 'select',
-      '#title' => 'Filter by Category',
-      '#options' => $options,
-      '#default_value' => $default_filter,
-      '#ajax'  => array(
-        'callback' => "tripal_extensions_form_ajax_callback",
-        'wrapper'  => 'tripal_extensions',
-        'effect'   => 'fade',
-        'method'   => 'replace',
-      ),
-    );
-
-    // Initialize pager and gets current page
-    $num_per_page = 5;
-    $page = pager_default_initialize($total_items, $num_per_page, $type_index);
-
-    // Gets first record and last record to show
-    $start = ($page) * $num_per_page;
-    $end = ($start + $num_per_page < $total_items)? $start + $num_per_page : $total_items;
-    // Iterate through each of the elements and add them to the form if
-    // they are within the page
-    $extension_index = 0;
-    foreach ($extensions as $guid => $extension) {
-      // Skip items that aren't on our current page.
-      if ($extension_index < $start or $extension_index >= $end) {
-        $extension_index++;
-        continue;
-      }
-
-      $extension['title'] = trim($extension['title']);
-
-      // If this is an extension module then there will be a home page for it
-      $home_page = '';
-      if (array_key_exists('home_page', $extension[$namespace])) {
-        $home_page = "<strong>Project Home: </strong>" . $extension[$namespace]['home_page'] . "</br>";
-      }
-
-      // Determine if this extension is compatible with this site.
-      $incompatible = '';
-      $tvs_temp = preg_split('/, /', $extension[$namespace]['tripal_version']);
-      $cvs_temp = preg_split('/, /', $extension[$namespace]['chado_version']);
-      if (!in_array($my_tripal_version, $tvs_temp)) {
-        $incompatible .= "<li>This extension is not compatible with this version of Tripal.</li>";
-      }
-      if (!in_array($my_chado_version, $cvs_temp)) {
-        $incompatible .= "<li>This extension is not compatible with the installed Chado version.</li>";
-      }
-      $incompatible = t($incompatible);
-
-      // Determine if this extension is already installed.
-      $is_installed = '';
-      switch ($type) {
-        case 'Bulk Loader Template':
-          if (module_exists('tripal_bulk_loader')) {
-            $blk_id = db_select('tripal_bulk_loader_template' ,'tblt')
-              ->fields('tblt', array('template_id'))
-              ->condition('name', $extension['title'])
-              ->execute()
-              ->fetchField();
-            if ($blk_id) {
-              $is_installed = '<li>A bulk loader template with this name is already installed.</li>';
-            }
-          }
-          break;
-        case 'Materialized View':
-          $mview_id = chado_get_mview_id($extension[$namespace]['mview_name']);
-          if ($mview_id) {
-            $is_installed = '<li>A materialized view with this name is already installed.</li>';
-          }
-          break;
-        case 'Extension Module':
-          if (array_key_exists('drupal_project', $extension[$namespace]) and
-              module_exists($extension[$namespace]['drupal_project'])) {
-            $is_installed = '<li>A module with this name is already installed.</li>';
-          }
-          break;
-        default:
-          break;
-      }
-      $is_installed = t($is_installed);
-
-      // Does this module appear to be available on Drupal.org?
-      $project = '';
-      if ($type == 'Extension Module') {
-        // Does it have a drupal project name?
-        if (!array_key_exists('drupal_project', $extension[$namespace])) {
-          // Since it doesn't have a drupal project name is it in a sandbox?
-          if (!preg_match('/www.drupal.org\/sandbox/', $extension[$namespace]['home_page'])) {
-            $project = t("<li>This module does not appear to be available as a " .
-              "full Drupal project and thus cannot ".
-              "be downloaded here. You may have to manually download it.</li>");
-          }
-          else {
-            $project = ("<li>This module is in a sandbox on Drupal.org, and
-              cannot be downloaded from here. You will have to manually download
-              this module.</li>");
-          }
-        }
-      }
-
-      // Make sure the bulk loader module is installed, or we cannot provide
-      // the bulk loader import button.
-      $other = '';
-      if ($type == 'Bulk Loader Template' and !module_exists('tripal_bulk_loader')) {
-        $other = t('<li>The bulk loader
-          module is not enabled. If you would like to import a loading template
-          please enable it.</li>');
-      }
-
-      // If the user click's the button to import the extension then we
-      // need the item in the submit function so we can process the import.
-      $form[$type]['extension-' . $guid] = array(
-        '#type' => 'value',
-        '#value' => $extension,
-      );
-
-      $notices = '';
-      if ($is_installed) {
-        $notices = '<div class="messages status"><ul>' . $is_installed . '</ul></div>';
-      }
-      $warnings = '';
-      if ($project or $other) {
-        $warnings = '<div class="messages warning"><ul>' .
-          $project .  ' ' .
-          $other . '</ul></div>';
-      }
-      $errors = '';
-      if ($incompatible) {
-        $errors = '<div class="messages error"><ul>' . $incompatible .  '</ul></div>';
-      }
-
-      $state = '';
-      if (array_key_exists('dev_stage', $extension[$namespace])) {
-        $state = '<strong>Development State: </strong>' . $extension[$namespace]['dev_stage'] . "</br>";
-      }
-
-      // Create the form elements that we'll later theme into tables.
-      $form[$type][$guid]['header'] = array(
-        '#markup' => l($extension['title'], $extension['link']),
-      );
-      $form[$type][$guid]['details'] = array(
-        '#markup' => "" .
-        "<strong>Type:</strong> " . $type . "</br>" .
-        "<strong>Categories: </strong>" . $extension[$namespace]['categories'] . "</br>" .
-        "<strong>Authors: </strong>" . $extension[$namespace]['authors'] . "</br>" .
-        $state .
-        "<strong>Chado compatible versions: </strong>" . $extension[$namespace]['chado_version'] . "</br>" .
-        "<strong>Tripal compatible versions: </strong>" . $extension[$namespace]['tripal_version'] . "</br>" .
-        $home_page .
-        "<strong>tripal.info Page: </strong>" . l($extension['link'], $extension['link']) . "</br>" .
-        $notices .
-        $warnings .
-        $errors .
-        "<p>" . $extension['description'] . "</p>",
-      );
-      // Add an import button to each of types that can support import.
-      switch ($type) {
-        case 'Bulk Loader Template':
-          if (!$incompatible and !$is_installed and !$project) {
-            $form[$type][$guid]['import'] = array(
-              '#type' => 'submit',
-              '#value' => "Import Loader",
-              '#name' => "import-" . $guid,
-            );
-          }
-          break;
-        case 'Materialized View':
-          if (!$incompatible and !$is_installed and !$project) {
-            $form[$type][$guid]['import'] = array(
-              '#type' => 'submit',
-              '#value' => "Import MView",
-              '#name' => "import-" . $guid,
-            );
-          }
-          break;
-        case 'Extension Module':
-          if (!$incompatible and !$is_installed and !$project) {
-            $form[$type][$guid]['import'] = array(
-              '#type' => 'submit',
-              '#value' => "Download Module",
-              '#name' => "import-" . $guid,
-            );
-          }
-          break;
-        default:
-          break;
-      }
-      $form[$type][$guid]['#theme'] = 'tripal_extensions_form_tables';
-      $extension_index++;
-    }
-
-    // Now create and theme the pager.
-    $pager = array(
-      'tags' => array(),
-      'element' => $type_index,
-      'parameters' => array(
-        'tab' => $type_ids[$type],
-        'cv' => $chado_version,
-        'tv' => $tripal_version,
-      ),
-      'quantity' => $num_per_page,
-    );
-
-    // now add the category filters to the params array
-    foreach ($filters as $filter_id => $value) {
-      $pager['parameters']['categories-' . $filter_id] = $value;
-    }
-
-    // because this may be an ajax callback, the theme_pager will set the URL to be
-    // "system/ajax", so we need to reset that
-    $pager = theme('pager', $pager);
-    global $base_path;
-    $pager = str_replace($base_path . "system/ajax", "", $pager) ;
-
-    $form[$type]['pager'] = array(
-      '#type' => 'item',
-      '#markup' => $pager,
-    );
-    $type_index++;
-  }
-}
-
-/**
- * Process the import buttons.
- *
- * @param $form
- * @param $form_state
- */
-function tripal_extensions_form_submit($form, &$form_state) {
-  // get the guid
-  $clicked_button = $form_state['clicked_button']['#name'];
-  $guid = preg_replace('/^import-(\d+)$/', "$1", $clicked_button);
-  if ($guid) {
-    $namespace = "http://tripal.info/rss/extensions/";
-    $extension = $form_state['values']['extension-' . $guid];
-    $type = $extension['category'];
-    switch ($type) {
-      case 'Bulk Loader Template':
-        $options = array(
-          'template_name' => $extension['title'],
-          'template_array' => $extension[$namespace]['bulkldr_export'],
-          'strict' => TRUE,
-        );
-        $errors = array();
-        $warnings = array();
-        $success = tripal_insert_bulk_loader_template($options, $errors, $warnings);
-        if ($success) {
-          drupal_set_message("Bulk loader succesfully added.");
-        }
-        else {
-          drupal_set_message("Error importing this bulk loader.",  'error');
-          if (count($errors) > 0) {
-            foreach($errors as $field => $message) {
-              drupal_set_message($message, 'error');
-            }
-          }
-        }
-        break;
-      case 'Materialized View':
-        $module_name = 'tripal';
-        $mview_name = $extension[$namespace]['mview_name'];
-        $mview_schema = $extension[$namespace]['mview_schema'];
-        $mview_sql = $extension[$namespace]['mview_sql'];
-
-        // Validate the contents of the schema array.
-        // TODO: security issue!! Before using 'eval' on this string
-        // we should make sure the array is valid and there is no hidden
-        // PHP code.
-        $schema_array = array();
-        $success = eval("\$schema_array = $mview_schema;");
-        $error = chado_validate_custom_table_schema($schema_array);
-        if ($error) {
-          drupal_set_message("Cannot import Materialized View: $error", "error");
-        }
-        chado_add_mview($mview_name, $module_name, $schema_array, $mview_sql);
-        break;
-      case 'Extension Module':
-        if (array_key_exists('drupal_project', $extension[$namespace])) {
-          module_load_include('module', 'update', 'update');
-          module_load_include('inc', 'update', 'update.manager');
-          $project = $extension[$namespace]['drupal_project'];
-          $tar = tripal_extensions_get_latest_module_version($project);
-          if (!$tar) {
-            drupal_set_message('Cannot find a suitable release of this module
-              for download. You may need to manually install this module.', 'error');
-          }
-          else {
-
-            // Download the file from the Drupal repository
-            $local_cache = update_manager_file_get($tar);
-            if (!$local_cache) {
-              drupal_set_message('Cannot download the file. Check the
-                "Recent log messages" for relavent errors.', 'error');
-            }
-            else {
-              // The following code was borrowed from the update_manager_install_form_submit()
-              // of drupal in the modules/update/update.manager.inc file.
-              $directory = _update_manager_extract_directory();
-              try {
-                $archive = update_manager_archive_extract($local_cache, $directory);
-              }
-              catch (Exception $e) {
-                drupal_set_message('Cannot extract the file. Please check
-                  permissions in the modules directory', 'error');
-                return;
-              }
-              $archive_errors = update_manager_archive_verify($project, $local_cache, $directory);
-              if (!empty($archive_errors)) {
-                foreach ($archive_errors as $error) {
-                  drupal_set_message($error, 'error');
-                }
-              }
-              $project_location = $directory . '/' . $project;
-              try {
-                $updater = Updater::factory($project_location);
-              }
-              catch (Exception $e) {
-                drupal_set_message($e->getMessage(), 'error');
-                return;
-              }
-              $project_real_location = drupal_realpath($project_location);
-              $arguments = array(
-                'project' => $project,
-                'updater_name' => get_class($updater),
-                'local_url' => $project_real_location,
-              );
-              module_load_include('inc', 'update', 'update.authorize');
-              $filetransfer = new FileTransferLocal(DRUPAL_ROOT);
-              call_user_func_array('update_authorize_run_install', array_merge(array($filetransfer), $arguments));
-
-              drupal_set_message('It appears the module was downloaded and
-                extracted. You can now ' . l('enable this module'. 'admin/modules') . '.');
-            }
-          }
-        }
-        else {
-          drupal_set_message('Cannot download this module.  The Drpual project
-            name is not set. You may have to manually download this module, and
-            if possible encourage the developers to set the project name if it
-            has been fully published on Drupal.org already.', 'error');
-        }
-        break;
-      default:
-        break;
-    }
-  }
-}
-
-/**
- * The theme function for rendering each element's table.
- *
- * @param $variables
- */
-function theme_tripal_extensions_form_tables($variables) {
-   $element = $variables['element'];
-   $headers = array(
-     array(
-       'data' => drupal_render($element['header']),
-       'colspan' => 2,
-     )
-   );
-   $button = array_key_exists('import', $element) ? drupal_render($element['import']) : '&nbsp;';
-   $rows = array(
-     array(
-       array(
-         'data' => drupal_render($element['details']),
-       ),
-       array(
-         'data' => $button,
-         'width' => '5%',
-         'align' => 'right',
-       ),
-     ),
-   );
-
-   $table = array(
-     'header' => $headers,
-     'rows' => $rows,
-     'attributes' => array(),
-     'sticky' => FALSE,
-     'caption' => '',
-     'colgroups' => array(),
-     'empty' => '',
-   );
-
-  return theme_table($table);
-}
-
-/**
- * A callback function for the form
- *
- * @return unknown
- */
-function tripal_extensions_form_ajax_callback($form, $form_state) {
-  // This function need not do anything as the form will take care of
-  // updates needed. We just need to return the form.
-  return $form;
-}
-
-/**
- * Determines the most recent downloadable package for a module.
- *
- * This function will connect to Drupal.org's RSS feed for a project and
- * determine the most recent version of the module and return the URL
- * for it's package.
- *
- * @param $project
- */
-function tripal_extensions_get_latest_module_version($project_name) {
-  // First use the Drupal RESTful API to get the project
-  $url = "https://www.drupal.org/api-d7/node.json?type=project_module&field_project_machine_name=$project_name";
-  $result = json_decode(file_get_contents($url), TRUE);
-  $project = $result['list'][0];
-  $nid = $project['nid'];
-
-  // Second get the releases for this node and find releases for this Drupal
-  $url = "https://www.drupal.org/api-d7/node.json?type=project_release&field_release_project=$nid";
-  $result = json_decode(file_get_contents($url), TRUE);
-  $releases = $result['list'];
-  $drupal_version = VERSION;
-  $drupal_major = preg_replace('/^(\d+)\.\d+$/', "$1", $drupal_version);
-  $best_release = NULL;
-  foreach ($releases as $release) {
-    // This release must match the Drupal major version or it won't
-    // be compatiable. If it doesn't we'll skip it.
-    $release_version = $release['field_release_version'];
-    $release_drupal = preg_replace('/^(\d+)\.x-.*$/', "$1", $release_version);
-    if ($release_drupal != $drupal_major) {
-      continue;
-    }
-
-    // Set the current release to be the best one. On successive iterations
-    // we'll check to see if that is still true.
-    if ($best_release == NULL) {
-      $best_release = $release;
-      continue;
-    }
-    if ($release['field_release_version_major'] > $best_release['field_release_version_major']) {
-      $best_release = $release;
-      continue;
-    }
-    if ($release['field_release_version_patch'] > $best_release['field_release_version_patch']) {
-      $best_release = $release;
-      continue;
-    }
-
-    // If the best version has no extra part then let's keep it as this is the
-    // most stable release.
-    if (!$best_release['field_release_version_extra']) {
-      continue;
-    }
-
-    // Convert the 'extra' part to a numeric value that will let us compare
-    // the ranks of the release versions.
-    $extra_rank = array(
-      'unstable' => 1,
-      'alpha' => 2,
-      'beta' => 3,
-      'rc' => 4,
-    );
-    $matches = array();
-    $this_extra = 0;
-    if (preg_match('/^(.*?)(\d+)$/', $release['field_release_version_extra'], $matches)) {
-      $this_extra = $extra_rank[$matches[1]] . "." . $matches[2];
-    }
-    $best_extra = 0;
-    if (preg_match('/^(.*?)(\d+)$/', $best_release['field_release_version_extra'], $matches)) {
-      $best_extra = $extra_rank[$matches[1]] . "." . $matches[2];
-    }
-    if ($this_extra > $best_extra) {
-      $best_release = $release;
-      continue;
-    }
-  }
-  // If we have a best result then build the download string.
-  // TODO: we may need to make another web services call to get the actual
-  // download path, but for now we'll hard code the construction of it.
-  if ($best_release) {
-    return 'http://ftp.drupal.org/files/projects/' . $project_name . '-' . $best_release['field_release_version'] . '.tar.gz';
-  }
-  return '';
-}

+ 28 - 4
tripal/includes/tripal.fields.inc

@@ -265,16 +265,27 @@ function tripal_form_field_ui_field_overview_form_alter(&$form, &$form_state, $f
     $field = field_info_field($field_name);
     $instance = field_info_instance('TripalEntity', $field_name, $form['#bundle']);
     
+    // Warn users if a field is missing a term.
+    if ($instance and $instance['entity_type'] == 'TripalEntity' and 
+        array_key_exists('settings', $instance) and is_array($instance['settings']) and
+        (!array_key_exists('term_vocabulary', $instance['settings']) or !$instance['settings']['term_vocabulary'])) {
+      tripal_report_error('tripal_fields', TRIPAL_WARNING,
+          'The field, !field, is missing a controlled vocabulary term. Please edit the field and set a term, otherwise this field may not work properly.',
+          ['!field' => $field_name],
+          ['drupal_set_message' => TRUE]);
+    }
     // Warn users if any of the terms are not unique.
     if ($instance and array_key_exists('settings', $instance) and is_array($instance['settings']) and 
         array_key_exists('term_vocabulary', $instance['settings'])) {
       $term = $instance['settings']['term_vocabulary'] . ':' . $instance['settings']['term_accession'];
       if (array_key_exists($term, $used_terms)) {
         $used_terms[$term][] = $field_name;
-        drupal_set_message(t('The term !term is in use by multiple fields: !fields. 
-          This is not allowed. Every field must have a different controlled vocabulary term. 
-          Please correct the term assignments.', 
-          array('!term' => $term, '!fields' => implode(', ', $used_terms[$term]))), 'error');
+        tripal_report_error('tripal_fields', TRIPAL_WARNING,
+          'The term !term is in use by multiple fields: !fields. ' .
+          'This is not allowed. Every field must have a different controlled vocabulary term. ' . 
+          'Please correct the term assignments.',
+          ['!term' => $term, '!fields' => implode(', ', $used_terms[$term])], 
+          ['drupal_set_message' => TRUE]);
       }
       $used_terms[$term][] = $field_name;
     }
@@ -734,6 +745,19 @@ function tripal_field_instance_settings_form_alter_validate($form, &$form_state)
         }
       }
     }
+    
+    // Make sure this term is not already used.    
+    $bundle_name = $form_state['values']['instance']['bundle'];
+    $existing_instances = field_info_instances('TripalEntity', $bundle_name);
+    $field_term_id = $form_state['values']['instance']['settings']['term_vocabulary'] . ':' . $form_state['values']['instance']['settings']['term_accession'];
+    $field_name = $form_state['values']['instance']['field_name'];  
+    foreach ($existing_instances as $existing_name => $existing_instance) {
+      $existing_term_id = $existing_instance['settings']['term_vocabulary'] . ':' . $existing_instance['settings']['term_accession'];
+      if ($existing_term_id == $field_term_id and $field_name != $existing_name) {       
+        form_set_error('term-', t('The term, !term, is already in use on this content type.  A term can only be used once per content type. Please choose a different term.',
+          ['!term' => $field_term_id]));
+      }
+    }
 
     if ($num_selected > 1) {
       form_set_error('term-', 'Please select only one term

+ 0 - 18
tripal/tripal.module

@@ -131,24 +131,6 @@ function tripal_menu() {
     'access arguments' => array('administer tripal'),
   );
 
-  // Menu items for facilitating import of extension modules.
-  $items['admin/tripal/extension/available'] = array(
-    'title' => 'Available Extensions',
-    'description' => t('Look for extensions to add new functionality to this
-        site. Tripal can be extended with new functionality developed
-        by other Tripal site developers. These include modules with new or
-        different functionality, bulk loading templates, or materialized
-        views.  Anyone can create new extensions and share those for
-        others to use.  Once shared they will appear in this list.'),
-    'access arguments' => array('administer tripal'),
-    'page callback' => 'drupal_get_form',
-    'page arguments' => array('tripal_extensions_form'),
-    'type' => MENU_NORMAL_ITEM,
-    'file' => 'includes/tripal.extensions.inc',
-    'file path' => drupal_get_path('module', 'tripal'),
-    'weight' => -100
-  );
-
   /**
    * Jobs Management
    */

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

@@ -225,6 +225,7 @@ function chado_publish_records($values, $job_id = NULL) {
         // can deal with it.
         'chado_record' => chado_generate_var($table, array($pkey_field => $record_id)),
         'chado_record_id' => $record_id,
+        'publish' => TRUE,
       ));
       $entity = $entity->save();
       if (!$entity) {

+ 3 - 1
tripal_chado/api/tripal_chado.query.api.inc

@@ -1646,7 +1646,9 @@ function chado_select_record_check_value_type(&$op, &$value, $type) {
  *            F.uniquename = :feature_uniquename";
  * $args = array( ':feature_uniquename' => $form_state['values']['uniquename'] );
  * $result = chado_query($sql, $args);
- * foreach ($result as $r) { [Do something with the records here] }
+ * while ($r = $results->fetchObject()) { 
+ *   // Do something with the record object $r
+ * }
  * @endcode
  *
  * @ingroup tripal_chado_query_api

+ 201 - 0
tripal_chado/includes/TripalFields/efo__array_design/efo__array_design.inc

@@ -0,0 +1,201 @@
+<?php
+
+class efo__array_design extends ChadoField {
+
+  // The default lable for this field.
+  public static $default_label = 'Array Design';
+
+  // The default description for this field.
+  public static $description = 'An instrument design which describes the design of the array.';
+
+  // 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' => 'EFO',
+    // The name of the term.
+    'term_name' => 'array design',
+    // The unique ID (i.e. accession) of the term.
+    'term_accession' => '0000269',
+    // 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 = 'efo__array_design_widget';
+
+  // The default formatter for this field.
+  public static $default_formatter = 'efo__array_design_formatter';
+
+
+  /**
+   * @see TripalField::validate()
+   */
+  public function validate($entity_type, $entity, $langcode, $items, &$errors) {
+
+    // If we don't have an entity then we don't want to validate.  The case
+    // where this could happen is when a user is editing the field settings
+    // and trying to set a default value. In that case there's no entity and
+    // we don't want to validate.  There will always be an entity for creation
+    // and update operations of a content type.
+    if (!$entity) {
+      return;
+    }
+    $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'];
+    $linker_field = 'chado-' . $field_table . '__' . $field_column;
+    
+    // Get the field values.
+    foreach ($items as $delta => $values) {
+
+      // Get the field values.
+      $arraydesign_id = $values[$linker_field];
+      if (!$arraydesign_id or $arraydesign_id == 0) {
+        $errors[$field_name]['und'][0][] = array(
+          'message' =>  t("Please specify an array design."),
+          'error' => 'efo__array_design'
+        );
+      }
+    }
+  }
+
+  /**
+   * @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('arraydesign', 'name');
+    $version_term = chado_get_semweb_term('arraydesign', 'version');
+
+    // Set some defaults for the empty record.
+    $entity->{$field_name}['und'][0] = array(
+      'value' => array(),
+    );
+
+    if (!$record) {
+      return;
+    }
+    $linker_field = 'chado-' . $field_table . '__' . $field_column;
+    $entity->{$field_name}['und'][0]['value'] = array(
+      $name_term => $record->{$field_column}->name,
+      $version_term => $record->{$field_column}->version,
+    );
+    $entity->{$field_name}['und'][0][$linker_field] = $record->{$field_column}->arraydesign_id;
+
+    // Is there a published entity for this arraydesign?
+    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('arraydesign', 'name');
+    $version_term = chado_get_semweb_term('arraydesign', 'version');
+    
+    return array(
+      $field_term => array(
+        'operations' => array('eq', 'contains', 'starts'),
+        'sortable' => TRUE,
+        'searchable' => TRUE,
+        'readonly' => FALSE,
+        'type' => 'xs:complexType',
+        'elements' => array(
+          $name_term => array(
+            'searchable' => TRUE,
+            'name' => 'name',
+            'operations' => array('eq', 'ne', 'contains', 'starts'),
+            'sortable' => FALSE,
+            'type' => 'xs:string',
+            'readonly' => TRUE,
+            'required' => FALSE,
+          ),
+          $version_term => array(
+            'searchable' => TRUE,
+            'name' => 'version',
+            'operations' => array('eq', 'ne'),
+            'sortable' => TRUE,
+            'readonly' => FALSE,
+            'type' => 'xs:string',
+            'required' => TRUE,
+          ),
+          'entity' => array(
+            '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('arraydesign', 'name');
+    $version_term = $field_term_id . ',' . chado_get_semweb_term('arraydesign', 'version');
+
+    // Join to the organism table for this field.
+    $this->queryJoinOnce($query, 'arraydesign', $alias, "base.arraydesign_id = $alias.arraydesign_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);
+    }
+    // If the column is a subfield.
+    if ($condition['column'] == $version_term) {
+      $query->condition("$alias.version", $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('arraydesign', 'name');
+    $version_term = $field_term_id . ',' . chado_get_semweb_term('arraydesign', 'version');
+
+    // Join to the organism table for this field.
+    $this->queryJoinOnce($query, 'arraydesign', $alias, "base.arraydesign_id = $alias.arraydesign_id");
+
+    // Now perform the sort.
+    if ($order['column'] == $name_term) {
+      $query->orderBy("$alias.name", $order['direction']);
+    }
+    if ($order['column'] == $version_term) {
+      $query->orderBy("$alias.version", $order['direction']);
+    }
+  }
+}

+ 37 - 0
tripal_chado/includes/TripalFields/efo__array_design/efo__array_design_formatter.inc

@@ -0,0 +1,37 @@
+<?php
+
+class efo__array_design_formatter extends ChadoFieldFormatter {
+
+  // The default lable for this field.
+  public static $default_label = 'Array Design';
+
+  // The list of field types for which this formatter is appropriate.
+  public static $field_types = array('efo__array_design');
+
+  /**
+   * @see TripalFieldFormatter::view()
+   */
+  public function view(&$element, $entity_type, $entity, $langcode, $items, $display) {
+    if (count($items) > 0) {
+      
+      $name_term = chado_get_semweb_term('arraydesign', 'name');
+      $version_term = chado_get_semweb_term('arraydesign', 'version');
+      
+      $content = $items[0]['value'][$name_term];
+      if (isset($items[0]['value'][$version_term])) {
+        $content . '(' . $items[0]['value'][$version_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] = array(
+        '#type' => 'markup',
+        '#markup' => $content,
+      );
+    }
+  }
+}

+ 75 - 0
tripal_chado/includes/TripalFields/efo__array_design/efo__array_design_widget.inc

@@ -0,0 +1,75 @@
+<?php
+
+class efo__array_design_widget extends ChadoFieldWidget {
+
+  // The default lable for this field.
+  public static $default_label = 'Array Design';
+
+  // The list of field types for which this formatter is appropriate.
+  public static $field_types = array('efo__array_design');
+
+
+  /**
+   * @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;
+
+    $arraydesign_id = 0;
+    if (count($items) > 0 and array_key_exists($linker_field, $items[0])) {
+      $arraydesign_id = $items[0][$linker_field];
+    }
+
+    $widget['value'] = array(
+      '#type' => 'value',
+      '#value' => array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
+    );
+    $sql = "SELECT arraydesign_id, name, version FROM {arraydesign} ORDER BY name";
+    $results = chado_query($sql);
+    $options = ['' => '- Select an array design -'];
+    while ($r = $results->fetchObject()) {
+      $options[$r->arraydesign_id] = $r->name;
+      if ($r->version) {
+        $options[$r->arraydesign_id] = $r->name . '(' . $r->version . ')';
+      }
+    }
+    $widget[$linker_field] = array(
+      '#type' => 'select',
+      '#title' => $element['#title'],
+      '#description' => $element['#description'],
+      '#options' => $options,
+      '#default_value' => $arraydesign_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
+    $arraydesign_id = $form_state['values'][$field_name]['und'][0][$linker_field];
+    $form_state['values'][$field_name]['und'][0]['value'] = $arraydesign_id;
+  }
+}

+ 0 - 4
tripal_chado/includes/TripalFields/local__contact/local__contact_widget.inc

@@ -57,10 +57,6 @@ class local__contact_widget extends ChadoFieldWidget {
       '#value' => array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
     );
 
-    $widget['chado-' . $field_table . '__' . $pkey] = array(
-      '#type' => 'value',
-      '#default_value' => $record_id,
-    );
     $widget[$linker_field] = array(
       '#type' => 'value',
       '#default_value' => $contact_id,

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

@@ -31,10 +31,10 @@ class obi__organism extends ChadoField {
   );
 
   // The default widget for this field.
-  public static $default_widget = 'OBI__organism_widget';
+  public static $default_widget = 'obi__organism_widget';
 
   // The default formatter for this field.
-  public static $default_formatter = 'OBI__organism_formatter';
+  public static $default_formatter = 'obi__organism_formatter';
 
 
   /**

+ 22 - 8
tripal_chado/includes/loaders/tripal_chado.pub_importers.inc

@@ -74,10 +74,8 @@ function tripal_pub_importers_list() {
       <li>Create a new importer by clicking the 'New Importer' link above, and after saving it should appear in the list below.  Click the
           link labeled 'Import Pubs' to schedule a job to import the publications</li>
       <li>The first method only performs the import once.  However, you can schedule the
-          importer to run peridically by adding a cron job. See the " .
-     l("Pub Module help instructions", "admin/tripal/legacy/tripal_pub/help") . " to learn how to
-     set the importers to run automatically.") . '</li>
-     </ol><br>';
+          importer to run peridically by adding a cron job. </li> 
+     </ol><br>");
 
 
   $table = array(
@@ -125,9 +123,13 @@ function tripal_pub_importer_setup_page($action = 'new', $pub_import_id = NULL)
     drupal_set_message(t('If you want to create contact pages for authors, you must first ') . l(t('load the Tripal Contact Ontology'), 'admin/tripal/loaders/chado_vocabs/obo_loader'), 'error');
   }
 
+  /**
+   * Commenting the AGL message out until we get AGL working again.
+   * spf 6/22/2018
   if(!extension_loaded ('yaz')){
     drupal_set_message(t('<b>Note:</b> In order to create an importer using the USDA National Agricultural Library (AGL) you must install the yaz libraries. See the ') . l(t('Pub Module help page'), 'admin/tripal/legacy/tripal_pub/help') . ' for assistance.  If you do not want to use AGL you can ignore this warning.', 'warning');
   }
+  */
 
   // generate the search form
   $form = drupal_get_form('tripal_pub_importer_setup_form',  $pub_import_id, $action);
@@ -137,9 +139,9 @@ function tripal_pub_importer_setup_page($action = 'new', $pub_import_id = NULL)
 
   // retrieve any results
   if (array_key_exists('tripal_pub_import', $_SESSION)) {
-    $remote_db = $_SESSION['tripal_pub_import']['remote_db'];
-    $num_criteria = $_SESSION['tripal_pub_import']['num_criteria'];
-    $days = $_SESSION['tripal_pub_import']['days'];
+    $remote_db = array_key_exists('remote_db', $_SESSION['tripal_pub_import']) ? $_SESSION['tripal_pub_import']['remote_db'] : '';
+    $num_criteria = array_key_exists('num_criteria', $_SESSION['tripal_pub_import']) ? $_SESSION['tripal_pub_import']['num_criteria'] : '';
+    $days = array_key_exists('days', $_SESSION['tripal_pub_import']) ? $_SESSION['tripal_pub_import']['days'] : '';
 
     $search_array = array();
     $search_array['remote_db'] = $remote_db;
@@ -371,6 +373,11 @@ function tripal_pub_importer_setup_form($form, &$form_state = NULL, $pub_import_
   if (!$remote_db) {
     $remote_db = 'PMID';
   }
+  /**
+   * Removing AGL option until we get it fixed
+   * spf 6/22/2018
+   */
+  unset($remote_dbs['AGL']);
   $form['themed_element']['remote_db'] = array(
     '#title' => t('Remote Database'),
     '#type' => 'select',
@@ -639,7 +646,7 @@ function tripal_pub_importer_setup_form_validate($form, &$form_state) {
     }
 
     if (!$is_phrase) {
-      if (preg_match('/and/i', $search_terms) and preg_match('/or/i', $search_terms)) {
+      if (preg_match('/\sand\s/i', $search_terms) and preg_match('/\sor\s/i', $search_terms)) {
         form_set_error("search_terms-$i", "You may use 'AND' or 'OR' but cannot use both. Add a new entry below with the same scope for the other conunction.");
         $_SESSION['tripal_pub_import']['perform_search'] = 0;
       }
@@ -1537,6 +1544,13 @@ function tripal_execute_pub_importer($import_id, $job_id = NULL) {
         chado_node_sync_records('contact');
       }
     }
+    // For Tripal v3 we want to publish the new publications
+    else {
+      $bundle = tripal_load_bundle_entity(['label' => 'Publication']);
+      if ($bundle) {
+        chado_publish_records(['bundle_name' => $bundle->name], $job_id);
+      }
+    }
     tripal_set_job_progress($job_id, '100');
   }
   catch (Exception $e) {

+ 11 - 1
tripal_chado/includes/setup/tripal_chado.setup.inc

@@ -225,8 +225,10 @@ function tripal_chado_prepare_chado($job = NULL) {
     }
 
     drush_print("Creating common Tripal Content Types...");
+    drush_print("This may take awhile if you are upgrading a site that has lots of data...");
 
     // Create the 'Organism' entity type. This uses the obi:organism term.
+    drush_print("Creating Organism...");
     $error = '';
     $args = array(
       'vocabulary' => 'OBI',
@@ -251,6 +253,7 @@ function tripal_chado_prepare_chado($job = NULL) {
     }
 
     // Create the 'Analysis' entity type. This uses the local:analysis term.
+    drush_print("Creating Analysis...");
     $error = '';
     $args = array(
       'vocabulary' => 'operation',
@@ -275,6 +278,7 @@ function tripal_chado_prepare_chado($job = NULL) {
     }
 
     // Create the 'Project' entity type. This uses the local:project term.
+    drush_print("Creating Project...");
     $error = '';
     $args = array(
       'vocabulary' => 'local',
@@ -299,6 +303,7 @@ function tripal_chado_prepare_chado($job = NULL) {
     }
 
     // Create the 'Map' entity type. This uses the local:project term.
+    drush_print("Creating Map...");
     $error = '';
     $args = array(
       'vocabulary' => 'data',
@@ -334,6 +339,7 @@ function tripal_chado_prepare_chado($job = NULL) {
     chado_import_pub_by_dbxref('PMID:24163125');
 
     // Create the 'Publication' entity type.
+    drush_print("Creating Publication...");
     $error = '';
     $args = array(
       'vocabulary' => 'TPUB',
@@ -377,6 +383,7 @@ function tripal_chado_prepare_chado($job = NULL) {
     }
 
     // Create the 'Gene' entity type.
+    drush_print("Creating Gene...");
     $error = '';
     $args = array(
       'vocabulary' => 'SO',
@@ -402,6 +409,7 @@ function tripal_chado_prepare_chado($job = NULL) {
     }
 
     // Create the 'mRNA' entity type.
+    drush_print("Creating mRNA...");
     $error = '';
     $args = array(
       'vocabulary' => 'SO',
@@ -427,6 +435,7 @@ function tripal_chado_prepare_chado($job = NULL) {
     }
 
     // Create the 'biological sample' entity type.
+    drush_print("Creating Biological Sample...");
     $error = '';
     $args = array(
       'vocabulary' => 'sep',
@@ -451,6 +460,7 @@ function tripal_chado_prepare_chado($job = NULL) {
     }
 
     // Create the 'Phylogenetic tree' entity type.
+    drush_print("Creating Phylogenetic tree...");
     $error = '';
     $args = array(
       'vocabulary' => 'data',
@@ -549,7 +559,7 @@ function tripal_chado_fix_v1_3_custom_tables() {
 
   // Update the featuremap_dbxref table by adding an is_current field.
   if (!chado_column_exists('featuremap_dbxref', 'is_current')) {
-    chado_query("ALTER TABLE {featuremap_dbxref} ADD COLUMN is_current boolean DEFAULT true NOT NULL,;");
+    chado_query("ALTER TABLE {featuremap_dbxref} ADD COLUMN is_current boolean DEFAULT true NOT NULL;");
   }
 
   // Remove the previously managed custom tables from the

+ 11 - 9
tripal_chado/includes/tripal_chado.field_storage.inc

@@ -42,12 +42,10 @@ function tripal_chado_field_storage_write($entity_type, $entity, $op, $fields) {
   $base_pkey = $base_schema['primary key'][0];
 
   // 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);
-// dpm($field_vals);
-
-  // 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
-  // is an insert and we need to set the type_id if the table supports it.
+  list($field_vals, $field_items) = tripal_chado_field_storage_write_merge_fields($fields, $entity_type, $entity);
+  // dpm($field_vals);  
+  
+  // First, write the record for the base table.
   $values = $field_vals[$base_table];
   if ($record_id) {
     $values[$base_pkey] = $record_id;
@@ -55,8 +53,10 @@ function tripal_chado_field_storage_write($entity_type, $entity, $op, $fields) {
   elseif ($type_field and !$linker) {
     $values[$type_field] = $cvterm->cvterm_id;
   }
-
   $base_record_id = tripal_chado_field_storage_write_table($base_table, $values, $base_table);
+  if (!$base_record_id) {
+    throw new Exception('Unable to write fields to Chado: ' . print_r($field_items, TRUE));
+  }
 
   // If this is an insert then add the chado_entity record.
   if ($op == FIELD_STORAGE_INSERT) {
@@ -381,6 +381,7 @@ function tripal_chado_field_storage_load($entity_type, $entities, $age,
 function tripal_chado_field_storage_write_merge_fields($fields, $entity_type, $entity) {
   $all_fields = array();
   $base_fields = array();
+  $field_items = array();
 
   // Iterate through all of the fields and organize them into a
   // new fields array keyed by the table name
@@ -405,6 +406,7 @@ function tripal_chado_field_storage_write_merge_fields($fields, $entity_type, $e
     // are multi-valued.
     $items = field_get_items($entity_type, $entity, $field_name);
     $temp = array();
+    $field_items[$field_name] = $items;
     foreach ($items as $delta => $item) {
 
       // A field may have multiple items. The field can use items
@@ -453,7 +455,7 @@ function tripal_chado_field_storage_write_merge_fields($fields, $entity_type, $e
   }
 
   $all_fields = array_merge($base_fields, $all_fields);
-  return $all_fields;
+  return [$all_fields, $field_items];
 }
 
 /**
@@ -733,7 +735,7 @@ function tripal_chado_field_storage_query($query) {
   // 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)) {
+  if (property_exists($query, 'deleted') and $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');

+ 164 - 9
tripal_chado/includes/tripal_chado.fields.inc

@@ -532,6 +532,17 @@ function tripal_chado_bundle_fields_info_custom(&$info, $details, $entity_type,
           'type' => 'field_chado_storage',
         ),
       );
+      $field_name = 'efo__array_design';
+      $field_type = 'efo__array_design';
+      $info[$field_name] = array(
+        'field_name' => $field_name,
+        'type' => $field_type,
+        'cardinality' => 1,
+        'locked' => FALSE,
+        'storage' => array(
+          'type' => 'field_chado_storage',
+        ),
+      );
     }
   
   // For the pub_id field in the base table.
@@ -554,7 +565,7 @@ 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';
@@ -569,7 +580,6 @@ function tripal_chado_bundle_fields_info_custom(&$info, $details, $entity_type,
       ),
     );
   }
-
 }
 
 /**
@@ -717,8 +727,24 @@ function tripal_chado_bundle_fields_info_linker(&$info, $details, $entity_type,
       }
 
       $field_name = strtolower(preg_replace('/[^\w]/','_', $term->dbxref_id->db_id->name . '__' . $term->name));
-      $field_name = substr($field_name, 0, 32);
+
+      // The field name can only be 32 chars, but if our name is longer we need
+      // to add some random chars to ensure we don't have naming conflicts 
+      // with other terms (e.g. mitochondrial_genetic_code and 
+      // mitochondrial_genetic_code_name)
+      if (strlen($field_name) >= 32) {
+        $field_name = substr($field_name, 0, 20) . '_' . $term->cvterm_id;
+      }
       $field_type = 'chado_linker__prop';
+      
+      // Don't try to add a property that uses the same term as another field.
+      if (array_key_exists($field_name, $info)) {
+        tripal_report_error('chado_fields', TRIPAL_WARNING, 
+          'A field of type !type already exists, yet a property wants to use the same term. The property cannot be added.',
+         ['!type' => $field_name],
+         ['drupal_set_message' => TRUE]);
+        continue;
+      }
       $info[$field_name] = array(
         'field_name' => $field_name,
         'type' => $field_type,
@@ -848,8 +874,6 @@ 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;
 
 }
@@ -1033,11 +1057,11 @@ function tripal_chado_bundle_instances_info_base(&$info, $entity_type, $bundle,
     }
     if ($base_info['label'] == 'Timeaccessioned') {
       $base_info['label'] = 'Time Accessioned';
-      $base_info['description'] = 'Please enter the time that this record was first added to the database.';
+      $base_info['description'] = 'The time that this record was first added to the database.';
     }
     if ($base_info['label'] == 'Timelastmodified') {
       $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'] = 'The time that this record was last modified. The default is the current time.';
     }
 
     // Sometimes the boolean fields are listed as integer.  We need to
@@ -1195,6 +1219,8 @@ function tripal_chado_bundle_instances_info_base(&$info, $entity_type, $bundle,
       if ($column_name == 'name') {
         $base_info['widget']['type'] = 'text_textfield';
         $base_info['settings']['text_processing'] = '0';
+        $base_info['required'] = TRUE;
+        $base_info['description'] = 'A unique name for this assay..';
       }
       if ($column_name == 'protcol_id') {
         $base_info['label'] = 'Protocol';
@@ -1203,20 +1229,24 @@ function tripal_chado_bundle_instances_info_base(&$info, $entity_type, $bundle,
         $base_info['label'] = 'Array Batch Identifier';
         $base_info['widget']['type'] = 'text_textfield';
         $base_info['settings']['text_processing'] = '0';
+        $base_info['description'] = 'A unique identifier for the array batch.';
       }
       if ($column_name == 'operator_id') {
         $base_info['label'] = 'Operator';
+        $base_info['description'] = 'The individual who performed the assay.';
       }
       if ($column_name == 'arrayidentifier') {
         $base_info['label'] = 'Array Identifier';
         $base_info['widget']['type'] = 'text_textfield';
         $base_info['settings']['text_processing'] = '0';
+        $base_info['description'] = 'A unique alternate identifier for the array.';
       }
       if ($column_name == 'arraydesign_id') {
         $base_info['label'] = 'Array Design';
       }
       if ($column_name == 'assaydate') {
         $base_info['label'] = 'Assay Date';
+        $base_info['description'] = 'The date the assay was performed';
       }
     }
     //
@@ -1304,6 +1334,9 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
         'base_table' => $table_name,
         'vocabulary' => $default_vocab,
         'parent_term' => $parent_term,
+        'term_vocabulary' => 'schema',
+        'term_name' => 'additionalType',
+        'term_accession' => 'additionalType',
       ),
       'widget' => array(
         'type' => 'schema__additional_type_widget',
@@ -1425,6 +1458,9 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
         'chado_table' => $table_name,
         'chado_column' => $table_column,
         'base_table' => $table_name,
+        'term_accession' => '0100026',
+        'term_vocabulary' => 'OBI',
+        'term_name' => 'organism',
       ),
       'widget' => array(
         'type' => 'obi__organism_widget',
@@ -1457,6 +1493,9 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
         'chado_table' => 'biomaterial',
         'chado_column' => 'biosourceprovider_id',
         'base_table' => 'biomaterial',
+        'term_accession' => 'contact',
+        'term_vocabulary' => 'local',
+        'term_name' => 'contact',
       ),
       'widget' => array(
         'type' => 'local__contact_widget',
@@ -1524,6 +1563,9 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
         'chado_table' => $table_name,
         'chado_column' => 'cv_id',
         'base_table' => $table_name,
+        'term_accession' => '001080',
+        'term_vocabulary' => 'SIO',
+        'term_name' => 'vocabulary',
       ),
       'widget' => array(
         'type' => 'sio__vocabulary_widget',
@@ -1562,6 +1604,9 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
         'chado_table' => $table_name,
         'chado_column' => 'dbxref_id',
         'base_table' => $table_name,
+        'term_accession' => '2091',
+        'term_vocabulary' => 'data',
+        'term_name' => 'Accession',
       ),
       'widget' => array(
         'type' => 'data__accession_widget',
@@ -1598,6 +1643,9 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
         'chado_table' => $table_name,
         'chado_column' => 'md5checksum',
         'base_table' => $table_name,
+        'term_accession' => '2190',
+        'term_vocabulary' => 'data',
+        'term_name' => 'Sequence checksum',
       ),
       'widget' => array(
         'type' => 'data__sequence_checksum_widget',
@@ -1631,6 +1679,9 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
         'chado_table' => $table_name,
         'chado_column' => 'residues',
         'base_table' => $table_name,
+        'term_accession' => '2044',
+        'term_vocabulary' => 'data',
+        'term_name' => 'Sequence',
       ),
       'widget' => array(
         'type' => 'data__sequence_widget',
@@ -1666,6 +1717,9 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
         'chado_table' => $table_name,
         'chado_column' => 'seqlen',
         'base_table' => $table_name,
+        'term_accession' => '1249',
+        'term_vocabulary' => 'data',
+        'term_name' => 'delete	Sequence length',
       ),
       'widget' => array(
         'type' => 'data__sequence_length_widget',
@@ -1699,6 +1753,9 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
         'chado_table' => 'feature',
         'chado_column' => 'residues',
         'base_table' => 'feature',
+        'term_accession' => '2976',
+        'term_vocabulary' => 'data',
+        'term_name' => 'Protein sequence',
       ),
       'widget' => array(
         'type' => 'data__protein_sequence_widget',
@@ -1728,6 +1785,9 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
 //         'chado_table' => 'featureloc',
 //         'chado_column' => '',
 //         'base_table' => 'featureloc',
+//         'term_accession' => '',
+//         'term_vocabulary' => '',
+//         'term_name' => '',
 //       ),
 //       'widget' => array(
 //         'type' => 'so__cds_widget',
@@ -1762,6 +1822,9 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
 //         'chado_table' => $rel_table,
 //         'chado_column' => '',
 //         'base_table' => $table_name,
+//         'term_accession' => '',
+//         'term_vocabulary' => '',
+//         'term_name' => '',
 //       ),
 //       'widget' => array(
 //         'type' => 'so__transcript_widget',
@@ -1794,6 +1857,9 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
         'chado_table' => 'organism',
         'chado_column' => 'type_id',
         'base_table' => 'organism',
+        'term_vocabulary' => 'TAXRANK',
+        'term_name' => 'infraspecific_taxon',
+        'term_accession' => '0000046',
       ),
       'widget' => array(
         'type' => 'taxrank__infraspecific_taxon_widget',
@@ -1827,6 +1893,9 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
         'chado_table' => $table_name,
         'chado_column' => 'unittype_id',
         'base_table' => $table_name,
+        'term_accession' => '0000000',
+        'term_vocabulary' => 'UO',
+        'term_name' => 'unit',
       ),
       'widget' => array(
         'type' => 'uo__unit_widget',
@@ -1859,6 +1928,9 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
         'chado_table' => $table_name,
         'chado_column' => 'analysis_id',
         'base_table' => $table_name,
+        'term_accession' => 'source_data',
+        'term_vocabulary' => 'local',
+        'term_name' => 'source_data',
       ),
       'widget' => array(
         'type' => 'local__source_data_widget',
@@ -1917,6 +1989,9 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
         'chado_table' => 'phylotree',
         'chado_column' => 'type_id',
         'base_table' => 'phylotree',
+        'term_accession' => '0567',
+        'term_vocabulary' => 'operation',
+        'term_name' => 'Phylogenetic tree visualisation',
       ),
       'widget' => array(
         'type' => 'operation__phylotree_vis_widget',
@@ -1958,6 +2033,9 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
         'chado_table' => $table_name,
         'chado_column' => $table_column,
         'base_table' => $table_name,
+        'term_accession' => '00101',
+        'term_vocabulary' => 'sep',
+        'term_name' => 'Protocol',
       ),
       'widget' => array(
         'type' => 'sep__protocol_widget',
@@ -1995,6 +2073,9 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
         'chado_table' => $table_name,
         'chado_column' => 'pub_id',
         'base_table' => $table_name,
+        'term_accession' => 'publication',
+        'term_vocabulary' => 'schema',
+        'term_name' => 'publication',
       ),
       'widget' => array(
         'type' => 'schema__publication_widget',
@@ -2033,7 +2114,6 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
         'term_vocabulary' => 'NCIT',
         'term_name' => 'Operator',
         'term_accession' => 'C48036',
-        
       ),
       'widget' => array(
         'type' => 'local__contact_widget',
@@ -2049,6 +2129,39 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
         ),
       ),
     );
+    
+    $field_name = 'efo__array_design';
+    $info[$field_name] =  array(
+      'field_name' => $field_name,
+      'entity_type' => $entity_type,
+      'bundle' => $bundle->name,
+      'label' => 'Array design',
+      'description' => 'An instrument design which describes the design of the array.',
+      'required' => TRUE,
+      'settings' => array(
+        'auto_attach' => TRUE,
+        'chado_table' => 'assay',
+        'chado_column' => 'arraydesign_id',
+        'base_table' => 'assay',
+        'term_vocabulary' => 'EFO',
+        'term_name' => 'array design',
+        'term_accession' => '0000269',
+        
+      ),
+      'widget' => array(
+        'type' => 'efo__array_design_widget',
+        'settings' => array(
+          'display_label' => 1,
+        ),
+      ),
+      'display' => array(
+        'default' => array(
+          'label' => 'inline',
+          'type' => 'efo__array_design_formatter',
+          'settings' => array(),
+        ),
+      ),
+    );
   } 
   // Analysis Id
   if (array_key_exists('analysis_id', $schema['fields'])) {
@@ -2122,6 +2235,9 @@ function tripal_chado_bundle_instances_info_linker(&$info, $entity_type, $bundle
         'chado_table' => $contact_table,
         'base_table' => $table_name,
         'chado_column' => 'contact_id',
+        'term_accession' => 'contact',
+        'term_vocabulary' => 'local',
+        'term_name' => 'contact',
       ),
       'widget' => array(
         'type' => 'local__contact_widget',
@@ -2157,6 +2273,9 @@ function tripal_chado_bundle_instances_info_linker(&$info, $entity_type, $bundle
         'chado_table' => $dbxref_table,
         'chado_column' => $pkey,
         'base_table' => $table_name,
+        'term_vocabulary' => 'SBO',
+        'term_name' => 'Database Cross Reference',
+        'term_accession' => '0000554',
       ),
       'widget' => array(
         'type' => 'sbo__database_cross_reference_widget',
@@ -2194,6 +2313,9 @@ function tripal_chado_bundle_instances_info_linker(&$info, $entity_type, $bundle
 //         'chado_table' => $expression_table,
 //         'chado_column' => $pkey,
 //         'base_table' => $table_name,
+//         'term_accession' => '',
+//         'term_vocabulary' => '',
+//         'term_name' => '',
 //       ),
 //       'widget' => array(
 //         'type' => 'go__gene_expression_widget',
@@ -2229,6 +2351,9 @@ function tripal_chado_bundle_instances_info_linker(&$info, $entity_type, $bundle
         'chado_table' => 'featureloc',
         'chado_column' => $pkey,
         'base_table' => 'feature',
+        'term_accession' => '2012',
+        'term_vocabulary' => 'data',
+        'term_name' => 'Sequence coordinates',
       ),
       'widget' => array(
         'type' => 'data__sequence_coordinates_widget',
@@ -2263,6 +2388,9 @@ function tripal_chado_bundle_instances_info_linker(&$info, $entity_type, $bundle
         'chado_table' => 'featurepos',
         'chado_column' => $pkey,
         'base_table' => 'feature',
+        'term_accession' => '0000021',
+        'term_vocabulary' => 'OGI',
+        'term_name' => 'location on map',
       ),
       'widget' => array(
         'type' => 'ogi__location_on_map_widget',
@@ -2298,6 +2426,9 @@ function tripal_chado_bundle_instances_info_linker(&$info, $entity_type, $bundle
 //         'chado_table' => $genotype_table,
 //         'chado_column' => $pkey,
 //         'base_table' => $table_name,
+//         'term_accession' => '',
+//         'term_vocabulary' => '',
+//         'term_name' => '',
 //       ),
 //       'widget' => array(
 //         'type' => 'so__genotype_widget',
@@ -2333,6 +2464,9 @@ function tripal_chado_bundle_instances_info_linker(&$info, $entity_type, $bundle
 //         'chado_table' => $phenotype_table,
 //         'chado_column' => $pkey,
 //         'base_table' => $table_name,
+//         'term_accession' => '',
+//         'term_vocabulary' => '',
+//         'term_name' => '',
 //       ),
 //       'widget' => array(
 //         'type' => 'sbo__phenotype_widget',
@@ -2439,7 +2573,13 @@ function tripal_chado_bundle_instances_info_linker(&$info, $entity_type, $bundle
          }
 
          $field_name = strtolower(preg_replace('/[^\w]/','_', $term->dbxref_id->db_id->name . '__' . $term->name));
-         $field_name = substr($field_name, 0, 32);
+         // The field name can only be 32 chars, but if our name is longer we need
+         // to add some random chars to ensure we don't have naming conflicts
+         // with other terms (e.g. mitochondrial_genetic_code and
+         // mitochondrial_genetic_code_name)
+         if (strlen($field_name) >= 32) {
+           $field_name = substr($field_name, 0, 20) . '_' . $term->cvterm_id;
+         }
          $info[$field_name] = array(
            'field_name' => $field_name,
            'entity_type' => $entity_type,
@@ -2510,6 +2650,9 @@ function tripal_chado_bundle_instances_info_linker(&$info, $entity_type, $bundle
         'chado_table' => $term_table,
         'chado_column' => $pkey,
         'base_table' => $table_name,
+        'term_vocabulary' => 'SIO',
+        'term_name' => 'annotation',
+        'term_accession' => '001166',
       ),
       'widget' => array(
         'type' => 'sio__annotation_widget',
@@ -2545,6 +2688,9 @@ function tripal_chado_bundle_instances_info_linker(&$info, $entity_type, $bundle
         'chado_table' => $pub_table,
         'chado_column' => $pkey,
         'base_table' => $table_name,
+        'term_accession' => 'publication',
+        'term_vocabulary' => 'schema',
+        'term_name' => 'publication',
       ),
       'widget' => array(
         'type' => 'schema__publication_widget',
@@ -2581,6 +2727,9 @@ function tripal_chado_bundle_instances_info_linker(&$info, $entity_type, $bundle
         'chado_table' => $table_name,
         'chado_column' => $pkey,
         'base_table' => $table_name,
+        'term_accession' => '000631',
+        'term_vocabulary' => 'SIO',
+        'term_name' => 'references',
       ),
       'widget' => array(
         'type' => 'sio__references_widget',
@@ -2617,6 +2766,9 @@ function tripal_chado_bundle_instances_info_linker(&$info, $entity_type, $bundle
         'chado_table' => $rel_table,
         'chado_column' => $pkey,
         'base_table' => $table_name,
+        'term_vocabulary' => 'SBO',
+        'term_name' => 'Relationship',
+        'term_accession' => '0000374',
       ),
       'widget' => array(
         'type' => 'sbo__relationship_widget',
@@ -2652,6 +2804,9 @@ function tripal_chado_bundle_instances_info_linker(&$info, $entity_type, $bundle
         'chado_table' => $syn_table,
         'chado_column' => $pkey,
         'base_table' => $table_name,
+        'term_accession' => 'alternateName',
+        'term_vocabulary' => 'schema',
+        'term_name' => 'alternateName',
       ),
       'widget' => array(
         'type' => 'schema__alternate_name_widget',

+ 1 - 0
tripal_chado/includes/tripal_chado.pub_search.inc

@@ -308,6 +308,7 @@ function tripal_chado_pub_search_form($form, &$form_state) {
       '#type'          => 'textfield',
       '#default_value' => $search_terms,
       '#required'      => FALSE,
+      '#size' => 35,
     );
     $form['criteria'][$i]["scope-$i"] = array(
       '#type'          => 'select',

+ 8 - 3
tripal_chado/tripal_chado.module

@@ -407,7 +407,7 @@ function tripal_chado_menu() {
   );
   $items['admin/tripal/loaders/pub/edit/%'] = array(
     'page callback' => 'tripal_pub_importer_setup_page',
-    'page arguments' => array(5),
+    'page arguments' => array('edit', 5),
     'access arguments' => array('use chado_pub_bulk importer'),
     'type ' => MENU_CALLBACK,
     'file' => 'includes/loaders/tripal_chado.pub_importers.inc',
@@ -1053,7 +1053,7 @@ function tripal_chado_form_field_ui_field_edit_form_alter(&$form, &$form_state,
 
     // If this is a Chado field we need to preserve the Chado elements of the
     // settings or they will be lost if a user edits the field settings.
-    if (array_key_Exists('chado_table', $form['#instance']['settings'])) {
+    if (array_key_exists('chado_table', $form['#instance']['settings'])) {
       $form['instance']['settings']['base_table'] = array(
         '#type' => 'value',
         '#value' => $form['#instance']['settings']['base_table'],
@@ -1182,7 +1182,12 @@ function tripal_feature_match_features_page($id) {
     }
     $table_attrs = array('class' => 'tripal-data-table');
     $output = "<p>The following features match the name '$id'.</p>";
-    $output .= theme_table($header, $rows, $table_attrs, $caption);
+    $output .= theme_table(array(
+      'header' => $header, 
+      'rows' => $rows, 
+      'attributes' => $table_attrs, 
+      'caption' => $caption
+    ));
     return $output;
   }
 

+ 3 - 142
tripal_ws/includes/TripalFields/remote__data/remote__data_widget.inc

@@ -6,152 +6,13 @@ class remote__data_widget extends WebServicesFieldWidget {
   public static $default_label = 'Remote Data';
   // The list of field types for which this formatter is appropriate.
   public static $field_types = array('remote__data');
+ 
   /**
-   * Provides the form for editing of this field.
-   *
-   * This function corresponds to the hook_field_widget_form()
-   * function of the Drupal Field API.
-   *
-   * This form is diplayed when the user creates a new entity or edits an
-   * existing entity.  If the field is attached to the entity then the form
-   * provided by this function will be displayed.
-   *
-   * At a minimum, the form must have a 'value' element.  For Tripal, the
-   * 'value' element of a field always corresponds to the value that is
-   * presented to the end-user either directly on the page (with formatting)
-   * or via web services, or some other mechanism.  However, the 'value' is
-   * sometimes not enough for a field.  For example, the Tripal Chado module
-   * maps fields to table columns and sometimes those columns are foreign keys
-   * therefore, the Tripal Chado modules does not just use the 'value' but adds
-   * additional elements to help link records via FKs.  But even in this case
-   * the 'value' element must always be present in the return form and in such
-   * cases it's value should be set equal to that added in the 'load' function.
-   *
-   * @param $widget
-   * @param $form
-   *   The form structure where widgets are being attached to. This might be a
-   *   full form structure, or a sub-element of a larger form.
-   * @param $form_state
-   *   An associative array containing the current state of the form.
-   * @param $langcode
-   *   The language associated with $items.
-   * @param $items
-   *   Array of default values for this field.
-   * @param $delta
-   *   The order of this item in the array of subelements (0, 1, 2, etc).
-   * @param $element
-   * A form element array containing basic properties for the widget:
-   *  - #entity_type: The name of the entity the field is attached to.
-   *  - #bundle: The name of the field bundle the field is contained in.
-   *  - #field_name: The name of the field.
-   *  - #language: The language the field is being edited in.
-   *  - #field_parents: The 'parents' space for the field in the form. Most
-   *    widgets can simply overlook this property. This identifies the location
-   *    where the field values are placed within $form_state['values'], and is
-   *    used to access processing information for the field through the
-   *    field_form_get_state() and field_form_set_state() functions.
-   *  - #columns: A list of field storage columns of the field.
-   *  - #title: The sanitized element label for the field instance, ready for
-   *    output.
-   *  - #description: The sanitized element description for the field instance,
-   *    ready for output.
-   *  - #required: A Boolean indicating whether the element value is required;
-   *    for required multiple value fields, only the first widget's values are
-   *    required.
-   *  - #delta: The order of this item in the array of subelements; see
-   *    $delta above
+   * @see TripalFieldWidget::form()
    */
   public function form(&$widget, &$form, &$form_state, $langcode, $items, $delta, $element) {
     parent::form($widget, $form, $form_state, $langcode, $items, $delta, $element);
-    // Get the field settings.
-   /* $field_name = $this->field['field_name'];
-    $field_type = $this->field['type'];
-
-    // Get the setting for the option for how this widget.
-    $instance = $this->instance;
-    $settings = '';
-    $site_list = '';
-
-    $tokens = array();
-    // Get the form info from the bundle about to be saved.
-    $bundle_info = tripal_load_bundle_entity(array('name' => $form_state['build_info']['args']['0']['bundle']));
-    // Retrieve all available tokens.
-    $tokens = tripal_get_entity_tokens($bundle_info);
-    // If the field already has a value then it will come through the $items
-    // array.  This happens when editing an existing record.
-
-    // FORM PROPER
-    $widget['#prefix'] =  "<span id='$field_name-remote_data-$delta'>";
-    $widget['#suffix'] =  "</span>";
-
-    $widget['value'] = array(
-      '#type' => 'value',
-      '#value' => array_key_exists($delta, $items) ? $items[$delta]['value'] : '',
-    );
-
-    $widget['data_info'] = array(
-      '#type' => 'fieldset',
-      '#title' => 'Remote Data Settings',
-      '#description' => 'Provide the site name, query and description for the remote data source.',
-      '#collapsible' => TRUE,
-      '#collapsed' => FALSE,
-      '#prefix' => "<div id='set_titles-fieldset'>",
-      '#suffix' => '</div>',
-    );
-
-    // Get the site info from the tripal_sites table.
-      // Get the field groups associated with this bundle.
-    $sites = db_select('tripal_sites', 's')
-      ->fields('s')
-      ->execute()->fetchAll();
-
-    foreach ($sites as $site) {
-      $rows[] = $site->name;
-    }
-
-    $widget['data_info']['site'] = array(
-      '#type' => 'select',
-      '#title' => t('Site'),
-      '#options' => $rows,
-      '#default_value' => $site_list,
-    );
-
-    $widget['data_info']['query'] = array(
-      '#type' => 'textarea',
-      '#title' => 'Query',
-      '#description' => 'Build the query string that should be appended after the url. The tokens
-       listed below may be used in your query build.',
-      '#default_value' => $this->instance['settings']['data_info']['query'],
-      '#rows' => 5
-    );
-
-    $widget['set_titles']['token_display']['tokens'] = array(
-      '#type' => 'hidden',
-      '#value' => serialize($tokens)
-    );
-
-    $widget['data_info']['token_display'] = array(
-      '#type' => 'fieldset',
-      '#title' => 'Available Tokens',
-      '#description' => 'Copy the token and paste it into the "Query" text field above.',
-      '#collapsible' => TRUE,
-      '#collapsed' => TRUE
-    );
-
-    $widget['data_info']['token_display']['content'] = array(
-      '#type' => 'item',
-      '#markup' => theme_token_list($tokens),
-    );
-
-    $widget['data_info']['description'] = array(
-      '#type' => 'textarea',
-      '#title' => 'Description',
-      '#description' => 'Describe the data being pulled in.',
-      '#default_value' =>  $this->instance['settings']['data_info']['description'],
-      '#rows' => 1
-    );
-*/
-    //TODO Add test button to ensure query returns info.
+    
   }
   /**
    * Performs validation of the widgetForm.

+ 5 - 1
tripal_ws/tripal_ws.module

@@ -438,8 +438,12 @@ function tripal_ws_load_remote_entity($site_id, $api_version, $ctype, $id) {
 }
 
 function tripal_ws_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
+  // Don't let the user change the cardinality of web services fields
   if ($form['#instance']['entity_type'] == 'TripalEntity') {
+    if ($form['#field']['storage']['type'] == 'field_tripal_ws_storage') {
       $form['field']['cardinality']['#access'] = FALSE;
+      $form['instance']['required']['#access'] = FALSE;
+    }
   }
 }
 
@@ -472,4 +476,4 @@ function tripal_ws_entity_info_alter(&$entity_info) {
       'custom settings' => FALSE,
     ),
   );
-}
+}