Bläddra i källkod

Fixed a few more bugs and updated docs

Stephen Ficklin 6 år sedan
förälder
incheckning
2d743df8c0

BIN
docs/user_guide/creating_content.create1.png


BIN
docs/user_guide/creating_content.create2.png


BIN
docs/user_guide/creating_content.create3.png


BIN
docs/user_guide/creating_content.create4.png


BIN
docs/user_guide/creating_content.create5.png


BIN
docs/user_guide/creating_content.create6.png


BIN
docs/user_guide/creating_content.create7.png


+ 50 - 11
docs/user_guide/creating_content.rst

@@ -40,24 +40,63 @@ Create a Tripal Content Type
 
 Creation of a new content type requires familiarity with Chado.  This is because data records used by content types must be mapped to actual data and the data lives in Chado.  Tripal's interface for creating content types allows you to provide the CV term for the type and then indicate where in Chado the data is/will be stored.  Chado is a flexible relational database schema.  Thus, it is possible for different sites to store data in different ways.  It is best practice however to follow community standards when storing data.  Therefore, please review the online documentation for Chado. If you are unclear how data for your content type should be stored in Chado please consider emailing the `Chado mailing list <http://gmod.org/wiki/GMOD_Mailing_Lists>`_ to ask for help or add a request for help on the Tripal issue queue.
 
-To add a new content type, start by navigating to **Structure → Tripal Content Types** and  click on the **Add Tripal Content Type** link at the top. This will take you to a web form that leads you through the process of creating a custom Tripal Content Type. First, enter for the name of the term you would like to use to describe your content in the Content Type autocomplete textbox (e.g. genetic_marker). Then, click **Lookup Term**. This should bring up a list of matching terms from which you can select the specific term you would like to use.  Sometimes the same term exists in multiple vocabularies and you can select the proper one.
+To add a new content type, start by navigating to **Structure → Tripal Content Types** and  click on the **Add Tripal Content Type** link at the top. This will take you to a web form that leads you through the process of creating a custom Tripal Content Type.
+
+Genetic Marker Example
+^^^^^^^^^^^^^^^^^^^^^^
+To demonstrate how to create a new content type we will use the example of a genetic marker. First, enter for the name of the term you would like to use to describe your content in the Content Type autocomplete textbox. Then, click **Lookup Term**. This should bring up a list of matching terms from which you can select the specific term you would like to use.  Sometimes the same term exists in multiple vocabularies and you can select the proper one.
 
 .. image:: creating_content.create1.png
 
-During content type creation there is as a section to specify which Chado tables will store your data. Chado is typically structured with primary **base** tables (e.g. organism, feature, stock, project, etc) and a set of linker and property tables that contain ancillary data related to the base records.  Here you must first choose the base table where primary records for your data type are stored.  For our example, because genetic markers are sequence features, they are stored in the Chado feature table. Once you select the Chado table, the form will ask additional questions to determine exactly how records of the content type can be found. Specifically, the following options are supported if the appropriate fields/tables are available:
+During content type creation there is as a section to specify which Chado tables will store your data. Chado is typically structured with primary **base** tables (e.g. organism, feature, stock, project, etc) and a set of linker and property tables that contain ancillary data related to the base records.  Here you must first choose the base table where primary records for your data type are stored.  For our example, because genetic markers are sequence features, they are stored in the Chado **feature** table.
 
-1. All records in the **base** table belong to the content type (e.g. tables: organism, analysis, etc.)
-2. The **base** table has a **type_id** that stores the CV term and this differentiates the records. (e.g. tables: feature, stock, library, etc.).
-3. The records can be differentiated by way of a property table which contains a **type_id** column for the CV term. (e.g. tables: featureprop, stockprop, libraryprop, etc.)
-4. The records can be differentiated by way of a linking table that associates records in the **base** table with the CV term (e.g. tables: feature_cvterm, stock_cvterm, etc.)
+.. image:: creating_content.create2.png
 
-For our genetic marker example, we can use the Chado **feature** table and **type_id** column to differentiate which records in the feature table are genetic markers. Thus we
+Next, you will be asked if all of the records in the selected table are of the desired content type.  Usually the answer to this is "No", especially if the Chado table has a **type_id** column.  In our case. The **feature** table does have a **type_id** column so we must select "No"
 
-- Select "No" not all records in the feature table are genetic markers
-- Type Column: type_id
+.. image:: creating_content.create3.png
 
-Then click Create Content Type to create a custom genetic marker content type.
+If all of the records in the selected table do not belong to the content type then the form knows enough about each Chado table to offer you appropriate options for how to store data for your content type.  The form knows that the **feature** table has a **type_id** column so it asks if we can differentiate records for our content type using the **type_id** field.  For our example genetic marker we can do so.
 
-.. image:: creating_content.create2.png
+.. image:: creating_content.create4.png
+
+Just prior to creating our content type we are provided a summary of our selection to review:
+
+
+.. image:: creating_content.create5.png
+
+Finally, click the **Create Content Type** to create a custom genetic marker content type.  We are provided with a message indicating that a job has been added for creation of the content type.  Depending how large the Chado database is, creation of a contnet type may take awhile, hence we must run it as a job.
+
+.. image:: creating_content.create6.png
 
 Once the content type is created, you can create pages for site visitors. This will be described later in this User's Guide. In short, you can manually create new records through brand new web forms that are created automatically for your content type, or you can use a data loader to import your data directly to Chado, then **Publish** those records through the Tripal interface.
+
+.. note::
+
+  Each time you create a new content type, you get several new things:
+
+  - A new search tool will be created automatically for the content type
+  - A new set of permissions to help you control access is created.
+
+SNP Example
+^^^^^^^^^^^
+Perhaps we want to be more specific with our genetic marker pages and create pages for each type of genetic marker (e.g. SNP, RFLP, etc. pages).  Suppose for this example that we continue to store genetic markes in the feature table and use the genetic_marker term in  **type_id** as in the previous example.  To differentiate between different markers, we store a record in the **featureprop** table where the **featureprop.type_id** indicates the that the property provides the marker type and the **featureprop.value** column houses the string for the marker type (e.g. "SNP").  Thus, any genetic marker that has a property with this type of featureprop should form part of our SNP content type.
+
+To accomplish this we can walk through the content type creation form and set the following values:
+
+.. csv-table::
+  :header: 'Field', 'Value'
+
+  "Content Type", "SNP (SO:0000694)"
+  "Storage Backend", "Chado"
+  "Chado Table", "feature"
+  "Are all records in the 'feature' table of type 'genetic_marker'?", "No"
+  "Type column", "--None--",
+  "Do you want to use the 'featureprop' table to distinguish between content types?", "Yes"
+  "Base Type", "genetic_marker (SO:0001645)"
+  "Property Type", "type (rdfs:type)"
+  "Property Value", "SNP"
+
+.. image:: creating_content.create7.png
+
+After clicking the "Create content type" button a job will be submitted and we will have a new SNP content type whose data is saved to both the feature and featureprop tables.

+ 3 - 14
tripal/api/tripal.terms.api.inc

@@ -581,7 +581,8 @@ function tripal_get_vocabularies() {
  */
 function tripal_get_term_lookup_form(&$form, &$form_state, $default_name = '',
     $title = 'Vocabulary Term', $description = '', $is_required,
-    $field_name = '', $delta = 0, $callback = '', $wrapper = '', $validate = [], $weight = 0) {
+    $field_name = '', $delta = 0, $callback = '', $wrapper = '', $validate = [], 
+    $weight = 0) {
   
   if (!$callback) {
     $callback = 'tripal_get_term_lookup_form_ajax_callback';
@@ -693,14 +694,8 @@ function tripal_get_term_lookup_form(&$form, &$form_state, $default_name = '',
         '#default_value' => $checked,
         '#attributes' => $attrs,
         '#description' => '<b>Vocabulary:</b> ' . $term->cv_id->name . ' (' . $term->dbxref_id->db_id->name . ') ' . $term->cv_id->definition .
-          '<br><b>Term: </b> ' . $term->dbxref_id->db_id->name . ':' . $term->dbxref_id->accession . '.  ' .
+          '<br><b>Term ID: </b> ' . $term->dbxref_id->db_id->name . ':' . $term->dbxref_id->accession . '.  ' .
           '<br><b>Definition:</b>  ' . $definition,
-        '#ajax' => array(
-          'callback' => $callback,
-          'wrapper' => $ajax_wrapper_id,
-          'effect' => 'fade',
-          'method' => 'replace'
-        ),
       );
 
       if (array_key_exists('values', $form_state) and array_key_exists($term_element_name, $form_state['values']) and
@@ -738,12 +733,6 @@ function tripal_get_term_lookup_form(&$form, &$form_state, $default_name = '',
         '<br><b>Term: </b> ' . $term->dbxref_id->db_id->name . ':' . $term->dbxref_id->accession . '.  ' .
         '<br><b>Definition:</b>  ' . $definition . 
         '<br><b>Synonym:</b> ' . $synonym->synonym,
-        '#ajax' => array(
-          'callback' => $callback,
-          'wrapper' => $ajax_wrapper_id,
-          'effect' => 'fade',
-          'method' => 'replace'
-        ),
       );
       
       if (array_key_exists('values', $form_state) and array_key_exists($term_element_name, $form_state['values']) and

+ 10 - 10
tripal/includes/TripalBundleUIController.inc

@@ -646,9 +646,10 @@ function tripal_admin_add_type_form_step1_summary(&$form, &$form_state, $selecte
   $form['term_summary']['details'] = [
     '#type' => 'item',
     '#title' => t('Term'),
-    '#markup' => 'Vocabulary: ' . $selected_term->cv_id->name . ' (' . $selected_term->dbxref_id->db_id->name . ') ' . $selected_term->cv_id->definition .
-    '<br>Term: ' . $selected_term->dbxref_id->db_id->name . ':' . $selected_term->dbxref_id->accession . '.  ' .
-    '<br>Definition:  ' . $definition
+    '#markup' => 'Name: ' . $selected_term->name . 
+      '<br>Vocabulary: ' . $selected_term->cv_id->name . ' (' . $selected_term->dbxref_id->db_id->name . ') ' .
+      '<br>Term ID: ' . $selected_term->dbxref_id->db_id->name . ':' . $selected_term->dbxref_id->accession . '.  ' .
+      '<br>Definition:  ' . $definition
   ];
   $form['term_summary']['step1-return'] = array(
     '#type' => 'submit',
@@ -681,12 +682,6 @@ function tripal_admin_add_type_form_step2(&$form, &$form_state, $stores, $select
     '#title' => 'Storage backend',
     '#options' => $store_options,
     '#default_value' => $default_store,
-    '#ajax' => array(
-      'callback' => "tripal_admin_add_type_form_ajax_callback",
-      'wrapper' => "tripal-add-type-form",
-      'effect' => 'fade',
-      'method' => 'replace'
-    ),
     '#description' => 'Select a storage background for this content type.'
   );
   
@@ -797,6 +792,11 @@ function tripal_admin_add_type_form_validate($form, &$form_state) {
     $form_state['stage'] = 'step1';
   }
   if ($clicked_button =='step2-continue') {
+    
+    if (!$store_select) {
+      form_set_error('store_select', 'Please select only one vocabulary term.');
+    }
+    
     $form_state['rebuild'] = TRUE;
     $form_state['stage'] = 'step3';
   }
@@ -867,7 +867,7 @@ function tripal_admin_add_type_form_submit($form, &$form_state) {
       }
     }
     else {
-      drupal_set_message("The term '$accession' already exists as a content type.", 'warning');
+      drupal_set_message("The term ". $term->name . " (" . $vocabulary . ':' . $accession. ") already exists as a content type.", 'warning');
     }
   }
 }

+ 1 - 1
tripal/tripal.views.inc

@@ -31,7 +31,7 @@ function tripal_views_data() {
   // Job Management System
   tripal_views_data_jobs($data);
   tripal_views_data_tripal_entity($data);
-  tripal_views_data_fields($data);
+  //tripal_views_data_fields($data);
 
   $data['views']['tripal_area_collections'] = array(
     'title' => t('Tripal Content Data Collections'),

+ 149 - 186
tripal_chado/includes/tripal_chado.field_storage.inc

@@ -101,17 +101,20 @@ function tripal_chado_field_storage_write($entity_type, $entity, $op, $fields) {
     }
     // If there is no value then this is a cvterm table
     else {
-      $args = array(':title' => NULL);
+      $args = array(':uniquename' => 'null');
       $sql = "
         SELECT *
         FROM {pub}
-        WHERE title = :title
+        WHERE uniquename = :uniquename
       ";
-      $pub_id = chado_query($sql, $args)->fetchObject();
+      $pub = chado_query($sql, $args)->fetchObject();
+      if (!$pub) {
+        throw new Exception('Unable to save record because the NULL publication is missing from the pub table. Please add a null record where the uniquename value is "null".');
+      }
       $field_vals[$linker][] = [
         $base_pkey => $base_record_id,
         'cvterm_id' => $cvterm->cvterm_id,
-        'pub_id' => $pub_id->pub_id,
+        'pub_id' => $pub->pub_id,
       ];
     }
   }
@@ -826,12 +829,10 @@ function tripal_chado_field_storage_bundle_mapping_form_get_defaults($form, $for
   $default = array(
     'table' => '',
     'has_all' => '',
-    'use_cvterm' => '',
-    'cv_id' => '',
     'use_linker' => '',
     'use_prop' => '',
     'type_column' => '',
-    'prop_base_selected_term' => '',
+    'base_selected_term' => '',
     'prop_selected_term' => '',
     'prop_term_value' => '',
     'stage' => 'table-select',
@@ -870,18 +871,9 @@ function tripal_chado_field_storage_bundle_mapping_form_get_defaults($form, $for
   if (array_key_exists('prop_term_value', $form_state['values'])
     and $form_state['values']['prop_term_value']) {
     $default['prop_term_value'] = $form_state['values']['prop_term_value'];
-  }
-  if (array_key_exists('chado_type_use_cv', $form_state['values'])
-    and $form_state['values']['chado_type_use_cv']) {
-    $default['use_cvterm'] = $form_state['values']['chado_type_use_cv'];
-  }
-  if (array_key_exists('chado_type_cv_id', $form_state['values'])
-    and $form_state['values']['chado_type_cv_id']) {
-    $default['cv_id'] = $form_state['values']['chado_type_cv_id'];
-  }
-  
+  } 
   if (array_key_exists('term_name1', $form_state['values'])) {
-    $default['prop_base_selected_term'] = tripal_get_term_lookup_form_result($form, $form_state, '', 1);
+    $default['base_selected_term'] = tripal_get_term_lookup_form_result($form, $form_state, '', 1);
   }
   if (array_key_exists('term_name2', $form_state['values'])) {
     $default['prop_selected_term'] = tripal_get_term_lookup_form_result($form, $form_state, '', 2);
@@ -930,17 +922,8 @@ function tripal_chado_field_storage_bundle_mapping_form($form, &$form_state, $te
   else if ($default['stage'] == 'linker-select') {
     tripal_chado_field_storage_bundle_mapping_form_linker_select($form, $form_state, $term, $default);
   }
-  else if ($default['stage'] == 'linker-type-select') {
-    tripal_chado_field_storage_bundle_mapping_form_linker_type_select($form, $form_state, $term, $default);
-  }
-  else if ($default['stage'] == 'linker-cv-settings') {
-    tripal_chado_field_storage_bundle_mapping_form_linker_cv_settings($form, $form_state, $term, $default);
-  }
-  else if ($default['stage'] == 'linker-parent-settings') {
-    tripal_chado_field_storage_bundle_mapping_form_linker_parent_settings($form, $form_state, $term, $default);
-  }
-  else if ($default['stage'] == 'linker-cvterm-settings') {
-    tripal_chado_field_storage_bundle_mapping_form_linker_cvterm_settings($form, $form_state, $term, $default);
+  else if ($default['stage'] == 'linker-settings') {
+    tripal_chado_field_storage_bundle_mapping_form_linker_settings($form, $form_state, $term, $default);
   }
   else if ($default['stage'] == 'complete') {
     $submit_disabled = FALSE;
@@ -992,9 +975,9 @@ function tripal_chado_field_storage_bundle_mapping_form_summary(&$form, &$form_s
     '#type' => 'value',
     '#value' => $default['prop_selected_term'],
   ];
-  $form['prop_base_term'] = [
+  $form['base_term'] = [
     '#type' => 'value',
-    '#value' => $default['prop_base_selected_term'],
+    '#value' => $default['base_selected_term'],
   ];
   $form['prop_term_value'] = [
     '#type' => 'value',
@@ -1004,10 +987,6 @@ function tripal_chado_field_storage_bundle_mapping_form_summary(&$form, &$form_s
     '#type' => 'value',
     '#value' => $default['use_linker'],
   ];
-  $form['chado_type_use_cv'] = [
-    '#type' => 'value',
-    '#value' => $default['use_cvterm'],
-  ];
   
   //
   // Add the base table row.
@@ -1075,8 +1054,8 @@ function tripal_chado_field_storage_bundle_mapping_form_summary(&$form, &$form_s
   //
   //  Add the row for the base type for a property mapping
   //
-  if ($default['prop_base_selected_term']) {
-    $term = $default['prop_base_selected_term'][0];
+  if ($default['use_prop'] == 'Yes' and $default['base_selected_term']) {
+    $term = $default['base_selected_term'][0];
     $rows[] = [
       [
         'data' => 'Base Type',
@@ -1117,7 +1096,7 @@ function tripal_chado_field_storage_bundle_mapping_form_summary(&$form, &$form_s
   //  Add the row for the linker table selection
   //
   if ($default['use_linker']) {
-    $message = 'Yes. The field is distinguishable using a cvterm linker table.';
+    $message = 'Yes. The field is distinguishable using a cvterm linker table. The Content Type will be used to find records in the linker table';
     if ($default['use_linker'] == 'No') {
       $message = 'No. The field is not distinguishable using a cvterm linker table.';
     }
@@ -1131,21 +1110,18 @@ function tripal_chado_field_storage_bundle_mapping_form_summary(&$form, &$form_s
     ];
   }
   
-  if ($default['use_cvterm']) {
-    $message = 'Use a specific vocabulary.';
-    if ($default['use_cvterm'] == 'parent') {
-      $message = 'Use a all children of a parent term.';
-    }
-    if ($default['use_cvterm'] == 'cvterm') {
-      $message = 'Use this content type term.';
-    }
+  //
+  //  Add the row for the base type for a property mapping
+  //
+  if ($default['use_linker'] == 'Yes' and $default['base_selected_term']) {
+    $term = $default['base_selected_term'][0];
     $rows[] = [
       [
-        'data' => 'Linker identifier',
+        'data' => 'Base Type',
         'header' => TRUE,
         'width' => '20%',
       ],
-      $message,
+      $term->name . ' (' . $term->dbxref_id->db_id->name . ':' . $term->dbxref_id->accession .')',
     ];
   }
   
@@ -1163,7 +1139,7 @@ function tripal_chado_field_storage_bundle_mapping_form_summary(&$form, &$form_s
   $form['chado_settings_summary'] = [
     '#type' => 'markup',
     '#markup' => theme_table($table),
-    '#weight' => -10,
+    '#weight' => -100,
   ];
   
   if ($default['stage'] == 'complete') {
@@ -1339,23 +1315,8 @@ function tripal_chado_field_storage_bundle_mapping_form_has_all_select(&$form, &
  */
 function tripal_chado_field_storage_bundle_mapping_form_type_select(&$form, &$form_state, $term, $default) {
   
-  $term_name = $term->name;
-
-  // Get the list of columns in the default table.
-  $schema = chado_get_schema($default['table']);
-  $column_options = array('none' => '--None--');
-  $cvt_fkeys = (isset($schema['foreign keys']['cvterm'])) ? array_keys($schema['foreign keys']['cvterm']['columns']) : array();
-  foreach ($schema['fields'] as $column_name => $column_details) {
-    if (in_array($column_name, $cvt_fkeys)) {
-      $column_options[$column_name] = $column_name;
-    }
-  }
-
-  // If this table has no types then just return.
-  if (count($column_options) == 1) {
-    $default['type_column'] = '';
-    return;
-  }
+  $term_name = $term->name;  
+  $column_options = tripal_chado_field_storage_bundle_mapping_form_get_type_fks_options($default['table']);
   
   $default_column = !empty($default['type_column']) ? $default['type_column'] : 'type_id';
    
@@ -1417,19 +1378,7 @@ function tripal_chado_field_storage_bundle_mapping_form_prop_settings(&$form, &$
   
   $prop_term_value = $default['prop_term_value'];
   
-  // If a base table has a 'type_id' field then we must have the user
-  // specify the base table type as well.
-  $base_type_column = FALSE;
-  $schema = chado_get_schema($default['table']);
-  foreach ($schema['foreign keys'] as $fk_id => $details) {
-    if ($details['table'] == 'cvterm') {
-      foreach ($details['columns'] as $fk_left => $fk_right) {
-        if ($fk_left == 'type_id') {
-          $base_type_column = 'type_id';
-        }
-      }
-    }
-  }
+  $base_type_column = tripal_chado_field_storage_bundle_mapping_form_get_base_type_column($default['table']);
   
   $validate =[
     'tripal_chado_field_storage_bundle_mapping_form_validate',
@@ -1452,7 +1401,7 @@ function tripal_chado_field_storage_bundle_mapping_form_prop_settings(&$form, &$
     tripal_get_term_lookup_form($form, $form_state, '',
       'Base Type', $description, FALSE, '', 1,
       'tripal_admin_add_type_form_ajax_callback', 'tripal-add-type-form', 
-      $validate, -10);
+      $validate, -2);
   }
   
   // We need a term lookup form for the property type.
@@ -1520,61 +1469,30 @@ function tripal_chado_field_storage_bundle_mapping_form_linker_select(&$form, &$
 /**
  * 
  */
-function tripal_chado_field_storage_bundle_mapping_form_linker_type_select(&$form, &$form_state, $term, $default) {
-
-  $form['chado_type_use_cv'] = array(
-    '#type' => 'radios',
-    '#title' => 'How do you want to distinguish the "' . $term->name . '" records
-      within the cvterm table?',
-    '#options' => array(
-      'cvterm' => 'All records that are associated with this content type term?',
-      'cv' => 'All records that belong to a single controlled vocabulary?',
-      'parent' => 'All child records of the specified term?'
-    ),
-    '#description' => t('Records in the cvterm table are often not used for content
-        types. The records in the cvterm table are meant to be vocabulary terms.
-        However, there are times when records in the cvterm table can be
-        used for a content type. One example is for trait "pages" that
-        use phenotype values stored in the phenotype table.  Because records in
-        the cvterm table are vocabulary terms they do not have "types" so the
-        only ways to distinguish them are 1) to use the controlled vocabulary to
-        distinguish the records or 2) to use all children records of the
-        selected term.  Please select the appropriate value for this case.'),
-    '#default_value' => $default['use_cvterm'],
-  );
-  $form['chado-linker-type-select-continue'] = array(
-    '#type' => 'submit',
-    '#value' => t('Continue'),
-    '#name' => 'chado-linker-type-select-continue',
-    '#validate' => [
-      'tripal_chado_field_storage_bundle_mapping_form_validate',
-      'tripal_admin_add_type_form_validate'
-    ],
-  );
-}
-
-/**
- * 
- */
-function tripal_chado_field_storage_bundle_mapping_form_linker_cv_settings(&$form, &$form_state, $term, $default) {
+function tripal_chado_field_storage_bundle_mapping_form_linker_settings(&$form, &$form_state, $term, $default){
+    
+  $base_type_column = tripal_chado_field_storage_bundle_mapping_form_get_base_type_column($default['table']);
   
-  $cvs = chado_get_cv_select_options();
-  $form['chado_type_cv_id'] = array(
-    '#type' => select,
-    '#options' => $cvs,
-    '#title' => t('Select a controlled vocabulary'),
-    '#default_value' => $default['cv_id'],
-    '#ajax' => array(
-      'callback' => "tripal_admin_add_type_form_ajax_callback",
-      'wrapper' => "tripal-add-type-form",
-      'effect' => 'fade',
-      'method' => 'replace'
-    ),
-  );
-  $form['chado-linker-cv-settings-continue'] = array(
+  $validate =[
+    'tripal_chado_field_storage_bundle_mapping_form_validate',
+    'tripal_admin_add_type_form_validate'
+  ];
+  
+  $description = t('The ' . $default['table'] . ' table of Chado requires
+    that each record have a type.  You have indicated that this
+    content type is not distinguished by a column in the base tabe but
+    instead by a cvterm linker table.  However, the ' . $default['table'] . ' table requires
+    that a value be given for the ' . $base_type_column . '. Please indicate
+    what this type should be.');
+  tripal_get_term_lookup_form($form, $form_state, '',
+    'Base Type', $description, FALSE, '', 1,
+    'tripal_admin_add_type_form_ajax_callback', 'tripal-add-type-form',
+    $validate, -10);
+  
+  $form['chado-linker-settings-continue'] = array(
     '#type' => 'submit',
     '#value' => t('Continue'),
-    '#name' => 'chado-linker-cv-settings-continue',
+    '#name' => 'chado-linker-settings-continue',
     '#validate' => [
       'tripal_chado_field_storage_bundle_mapping_form_validate',
       'tripal_admin_add_type_form_validate'
@@ -1583,19 +1501,39 @@ function tripal_chado_field_storage_bundle_mapping_form_linker_cv_settings(&$for
 }
 
 /**
- *
+ * 
  */
-function tripal_chado_field_storage_bundle_mapping_form_linker_cvterm_settings(&$form, &$form_state, $term, $default) {
-  
-   // TODO:  need to complete this form.  
+function tripal_chado_field_storage_bundle_mapping_form_get_type_fks_options($table) {
+  // Get the list of columns in the default table.
+  $schema = chado_get_schema($table);
+  $column_options = array('none' => '--None--');
+  $cvt_fkeys = (isset($schema['foreign keys']['cvterm'])) ? array_keys($schema['foreign keys']['cvterm']['columns']) : array();
+  foreach ($schema['fields'] as $column_name => $column_details) {
+    if (in_array($column_name, $cvt_fkeys)) {
+      $column_options[$column_name] = $column_name;
+    }
+  }
+  return $column_options;
 }
-
 /**
- *
+ * 
  */
-function tripal_chado_field_storage_bundle_mapping_form_linker_parent_settings(&$form, &$form_state, $term, $default) {
+function tripal_chado_field_storage_bundle_mapping_form_get_base_type_column($table) {
   
-  // TODO:  need to complete this form.
+  // If a base table has a 'type_id' field then we must have the user
+  // specify the base table type as well.
+  $base_type_column = FALSE;
+  $schema = chado_get_schema($table);
+  foreach ($schema['foreign keys'] as $fk_id => $details) {
+    if ($details['table'] == 'cvterm') {
+      foreach ($details['columns'] as $fk_left => $fk_right) {
+        if ($fk_left == 'type_id') {
+          $base_type_column = 'type_id';
+        }
+      }
+    }
+  }
+  return $base_type_column;
 }
 
 /**
@@ -1611,7 +1549,13 @@ function tripal_chado_field_storage_bundle_mapping_form_validate($form, &$form_s
   // Get the form values.
   $default = tripal_chado_field_storage_bundle_mapping_form_get_defaults($form, $form_state);  
   $clicked_button = $form_state['clicked_button']['#name'];
-    
+
+  // Check if prop  and linker tables exist. We'll use these values later.
+  $prop_table = $default['table'] . 'prop';
+  $prop_exists = chado_table_exists($prop_table);
+  $linker_table = $default['table'] . '_cvterm';
+  $linker_exists = chado_table_exists($linker_table);
+  
   //
   // Valiate the table select stage
   //
@@ -1632,7 +1576,32 @@ function tripal_chado_field_storage_bundle_mapping_form_validate($form, &$form_s
       $form_state['chado-stage'] = 'complete';
     }
     else {
-      $form_state['chado-stage'] = 'type-select';
+      $column_options = tripal_chado_field_storage_bundle_mapping_form_get_type_fks_options($default['table']);      
+      // If this table has fields that link to the cvterm table then 
+      // let the user select the type column. The column_options is empty if
+      // it equals 1 because it has the --none-- element.
+      if (count($column_options) > 1) {
+        $form_state['chado-stage'] = 'type-select';
+      }
+      // Otherwise, see if there are other options....
+      else {
+        // If there is no type_id or the type_id column should not be
+        // used then we need to let the user select if they want to
+        // use the prop table or a cvterm linking table. We'll offer the
+        // prop table first.
+        if ($prop_exists) {
+          $form_state['chado-stage'] = 'prop-select';
+        }
+        else {
+          if ($linker_exists) {
+            $form_state['chado-stage'] = 'linker-select';
+          }
+          else {
+            $form_state['chado-stage'] = 'stop';
+          }
+        }
+      }
+
     }
   }
   
@@ -1648,21 +1617,15 @@ function tripal_chado_field_storage_bundle_mapping_form_validate($form, &$form_s
       // used then we need to let the user select if they want to 
       // use the prop table or a cvterm linking table. We'll offer the
       // prop table first.
-      $prop_table = $default['table']. 'prop';
-      $prop_exists = chado_table_exists($prop_table);
-      $linker_table = $default['table'] . '_cvterm';
-      $linker_exists = chado_table_exists($linker_table);      
       if ($prop_exists) {
         $form_state['chado-stage'] = 'prop-select';
       }
       else {
-        if (!$linker_exists) {
-          $form_state['chado-stage'] = 'stop';
+        if ($linker_exists) {
+          $form_state['chado-stage'] = 'linker-select';
         }
         else {
-          // TODO: add support for cvterm linker tables
-          $form_state['chado-stage'] = 'stop';
-          // $form_state['chado-stage'] = 'linker-select';
+          $form_state['chado-stage'] = 'stop';          
         }
       }
     }
@@ -1676,16 +1639,12 @@ function tripal_chado_field_storage_bundle_mapping_form_validate($form, &$form_s
       $form_state['chado-stage'] = 'prop-settings';
     }
     else if ($default['use_prop'] == 'No') {
-      $linker_table = $default['table'] . '_cvterm';
-      $linker_exists = chado_table_exists($linker_table);
-      if (!$linker_exists) {
-        $form_state['chado-stage'] = 'stop';
+      if ($linker_exists) {
+        $form_state['chado-stage'] = 'linker-select';      
       }
       else {
-        // TODO: add support for cvterm linker tables
         $form_state['chado-stage'] = 'stop';
-        // $form_state['chado-stage'] = 'linker-select';
-      }      
+      }
     }
     else {
       form_set_error('chado_type_use_prop', 'Please select a value.');
@@ -1700,7 +1659,7 @@ function tripal_chado_field_storage_bundle_mapping_form_validate($form, &$form_s
     // If a base type was needed then make sure we have a value selected.
     $valid = TRUE;
     if (array_key_exists('term_name1', $form_state['values'])) {
-      $base_selected = $default['prop_base_selected_term'];
+      $base_selected = $default['base_selected_term'];
       if (count($base_selected) == 0) {
         form_set_error('term_match1][term_name1', 'Please select a base table type vocabulary term.');
         $valid = FALSE;
@@ -1736,7 +1695,15 @@ function tripal_chado_field_storage_bundle_mapping_form_validate($form, &$form_s
   //
   if ($clicked_button == 'chado-linker-select-continue') {
     if ($default['use_linker'] == 'Yes') {
-      $form_state['chado-stage'] = 'linker-type-select';
+      // If our base table has a type_id then we need need to make the 
+      // user provide a value for it, otherwise we're done.
+      $base_type_column = tripal_chado_field_storage_bundle_mapping_form_get_base_type_column($default['table']);
+      if ($base_type_column) {
+        $form_state['chado-stage'] = 'linker-settings';
+      }
+      else {
+        $form_state['chado-stage'] = 'complete';
+      }
     }
     else if ($default['use_linker'] == 'No') {
       $form_state['chado-stage'] = 'stop';
@@ -1746,21 +1713,27 @@ function tripal_chado_field_storage_bundle_mapping_form_validate($form, &$form_s
     }
   }
   
-  if ($clicked_button == 'chado-linker-type-select-continue') {
-    if ($default['use_cvterm'] == 'cv') {
-      $form_state['chado-stage'] = 'linker-cv-settings';
-    }
-    else if ($default['use_cvterm'] == 'parent') {
-      $form_state['chado-stage'] = 'linker-parent-settings';
+  if ($clicked_button == 'chado-linker-settings-continue') {
+    $valid = TRUE;
+    if (array_key_exists('term_name1', $form_state['values'])) {
+      $base_selected = $default['base_selected_term'];
+      if (count($base_selected) == 0) {
+        form_set_error('term_match1][term_name1', 'Please select a base table type vocabulary term.');
+        $valid = FALSE;
+      }
+      if (count($base_selected) > 1) {
+        form_set_error('term_match1][term_name1', 'Please select only one base table type vocabulary term.');
+        $valid = FALSE;
+      }
     }
-    else if ($default['use_cvterm'] == 'cvterm') {
-      $form_state['chado-stage'] = 'linker-cvterm-settings';
+    if (!$valid) {
+      return;
     }
-    else {
-      form_set_error('chado_type_use_cv', 'Please select a value.');
-    }    
+    // If we're here then alll validations passed and we are good to go!
+    $form_state['chado-stage'] = 'complete';
   }
   
+ 
   //
   // Check for a reset.
   //
@@ -1781,19 +1754,6 @@ function tripal_chado_field_storage_bundle_mapping_form_submit($form,
 
   $default = tripal_chado_field_storage_bundle_mapping_form_get_defaults($form, $form_state);
   
-  // If the user selected to use the cvterm table then we have to
-  // handle it specially.
-  if ($default['use_cvterm'] == 'cv' and !empty($default['cv_id'])) {
-    $storage_args['data_table'] = $default['table'];
-    $storage_args['type_id'] = $form_state['values']['selected_cvterm_id'];
-    $storage_args['type_value'] = '';
-    if ($default['cv_id']) {
-      $storage_args['type_value'] = $default['cv_id'];
-    }
-    $storage_args['type_column'] = '';
-    return;
-  }
-
   // If we have a type_column then we know this type uses a column in the
   // base table, so we can set the storage args and return.
   if ($default['type_column'] and $default['type_column'] != 'none') {
@@ -1819,8 +1779,8 @@ function tripal_chado_field_storage_bundle_mapping_form_submit($form,
     $storage_args['type_column'] = 'type_id';
     $storage_args['type_id'] = $form_state['values']['prop_term'][0]->cvterm_id;
     $storage_args['type_value'] = $default['prop_term_value'];
-    if (is_array($form_state['values']['prop_base_term'])) {
-      $storage_args['base_type_id'] = $form_state['values']['prop_base_term'][0]->cvterm_id;
+    if (is_array($form_state['values']['base_term'])) {
+      $storage_args['base_type_id'] = $form_state['values']['base_term'][0]->cvterm_id;
     }
   }
 
@@ -1831,6 +1791,9 @@ function tripal_chado_field_storage_bundle_mapping_form_submit($form,
     $storage_args['type_id'] = $form_state['values']['selected_cvterm_id'];
     $storage_args['type_linker_table'] = $default['table'] . '_cvterm';
     $storage_args['type_column'] = 'cvterm_id';
+    if (is_array($form_state['values']['base_term'])) {
+      $storage_args['base_type_id'] = $form_state['values']['base_term'][0]->cvterm_id;
+    }
   }
 }
 

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

@@ -222,13 +222,16 @@ function tripal_chado_bundle_fields_info_custom(&$info, $details, $entity_type,
   $type_column = $details['chado_type_column'];
   $cvterm_id  = $details['chado_cvterm_id'];
   $type_value = $details['chado_type_value'];
+  $base_type_id = $details['chado_base_type_id'];
 
   $schema = chado_get_schema($table_name);
 
-  // Handle type_id fields that are not the type_column, except for the
-  // organism type_id as that is handled by the taxrank__infraspecific_taxon
-  // field.
-  if (array_key_exists('type_id', $schema['fields']) and 'type_id' != $type_column and $table_name != 'organism') {
+  // Add the additional_type field to all tables with a type_id that is not used
+  // as the type column nor has a $base_type_id (i.e. the content type uses a 
+  // prop or linker table to resolve the type).
+  if (array_key_exists('type_id', $schema['fields']) and 'type_id' != $type_column and 
+      !$base_type_id and $table_name != 'organism') {    
+
     $field_name = 'schema__additional_type';
     $field_type = 'schema__additional_type';
     $info[$field_name] = array(
@@ -715,7 +718,7 @@ function tripal_chado_bundle_fields_info_linker(&$info, $details, $entity_type,
   $prop_table = $table_name . 'prop';
   if (chado_table_exists($prop_table)) {
     
-    $props = tripal_chado_bundle_get_properties($table_name, $prop_table, $type_table, $type_column);
+    $props = tripal_chado_bundle_get_properties($table_name, $prop_table, $type_table, $type_column, $cvterm_id);
     foreach ($props as $term) {
           
       $field_name = strtolower(preg_replace('/[^\w]/','_', $term->dbxref_id->db_id->name . '__' . $term->name));
@@ -857,8 +860,10 @@ function tripal_chado_bundle_instances_info($entity_type, $bundle) {
     'chado_cvterm_id' => $chado_bundle->type_id,
     'chado_table' => $chado_bundle->data_table,
     'chado_type_table' => $chado_bundle->type_linker_table,
+    'chado_type_id' => $chado_bundle->type_id,
     'chado_type_column' => $chado_bundle->type_column,
     'chado_type_value' => $chado_bundle->type_value,
+    'chado_base_type_id' => $chado_bundle->base_type_id,
   );
 
   $info = array();
@@ -1282,10 +1287,14 @@ function tripal_chado_bundle_instances_info_custom(&$info, $entity_type, $bundle
   $type_column = $details['chado_type_column'];
   $cvterm_id  = $details['chado_cvterm_id'];
   $type_value = $details['chado_type_value'];
+  $base_type_id = $details['chado_base_type_id'];  
   $schema = chado_get_schema($table_name);
 
-  // An additional type for publications
-  if (array_key_exists('type_id', $schema['fields']) and 'type_id' != $type_column and $table_name != 'organism') {
+  // Add the additional_type field to all tables with a type_id that is not used
+  // as the type column nor has a $base_type_id (i.e. the content type uses a
+  // prop or linker table to resolve the type).
+  if (array_key_exists('type_id', $schema['fields']) and 'type_id' != $type_column and
+      !$base_type_id and $table_name != 'organism') { 
     $field_name = 'schema__additional_type';
     $is_required = FALSE;
     if (array_key_exists('not null', $schema['fields']['type_id']) and
@@ -2480,7 +2489,7 @@ function tripal_chado_bundle_instances_info_linker(&$info, $entity_type, $bundle
   $prop_table = $table_name . 'prop';
   if (chado_table_exists($prop_table)) {
 
-    $props = tripal_chado_bundle_get_properties($table_name, $prop_table, $type_table, $type_column);
+    $props = tripal_chado_bundle_get_properties($table_name, $prop_table, $type_table, $type_column, $cvterm_id);
     foreach ($props as $term) {     
 
        $field_name = strtolower(preg_replace('/[^\w]/','_', $term->dbxref_id->db_id->name . '__' . $term->name));
@@ -2752,7 +2761,7 @@ function tripal_chado_bundle_instances_info_linker(&$info, $entity_type, $bundle
  * @return
  *   An array of cvterm objects for the properties to be added as fields.
  */
-function tripal_chado_bundle_get_properties($table_name, $prop_table, $type_table, $type_column) {
+function tripal_chado_bundle_get_properties($table_name, $prop_table, $type_table, $type_column, $cvterm_id) {
   
   $tschema = chado_get_schema($table_name);
   $schema = chado_get_schema($prop_table);