Преглед изворни кода

Merge branch '7.x-3.x' into 467-tv3-entity_relationships

Stephen Ficklin пре 6 година
родитељ
комит
c275ac41eb

+ 81 - 19
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 = TRUE;
+    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;
 }

+ 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)) {

+ 8 - 3
tripal/includes/TripalEntityController.inc

@@ -47,7 +47,6 @@ class TripalEntityController extends EntityAPIController {
       $function = $module . '_entity_create';
       $function($entity, $values['type']);
     }
-
     return $entity;
 
   }
@@ -360,6 +359,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 +391,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);
       }
 

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

@@ -274,16 +274,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;
     }
@@ -743,6 +754,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

+ 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) {

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

@@ -44,12 +44,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;
@@ -57,8 +55,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) {
@@ -383,6 +383,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
@@ -407,6 +408,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
@@ -455,7 +457,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];
 }
 
 /**

+ 54 - 8
tripal_chado/includes/tripal_chado.fields.inc

@@ -554,7 +554,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 +569,6 @@ function tripal_chado_bundle_fields_info_custom(&$info, $details, $entity_type,
       ),
     );
   }
-
 }
 
 /**
@@ -717,8 +716,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 +863,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 +1046,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 +1208,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 +1218,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 +1323,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',
@@ -1794,6 +1816,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',
@@ -1995,6 +2020,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',
@@ -2157,6 +2185,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',
@@ -2439,7 +2470,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 +2547,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 +2585,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',
@@ -2617,6 +2660,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',

+ 1 - 1
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('load tripal data'),
     'type ' => MENU_CALLBACK,
     'file' => 'includes/loaders/tripal_chado.pub_importers.inc',