Browse Source

Chado Node API: Replaces stock title functionality with the new API including handling the legacy options

Lacey Sanderson 11 years ago
parent
commit
115ab3e4b3

+ 41 - 1
tripal_core/api/tripal_core.chado_nodes.api.inc

@@ -93,6 +93,46 @@ function chado_get_nid_from_id($table, $id, $linking_table = NULL) {
   return db_query($sql, array(":" . $table . "_id" => $id))->fetchField();
 }
 
+/**
+ * Determine the chado base table for a given content type
+ *
+ * @param $content_type
+ *    The machine name of the content type (node type) you want to
+ *    determine the base chado table of
+ * @param $module
+ *    (Optional) The machine-name of the module implementing the
+ *    content type
+ *
+ * @return
+ *    The name of the chado base table for the specified content type
+ *
+ *  @ingroup tripal_chado_node_api
+ */
+function chado_node_get_base_table($content_type, $module = FALSE) {
+
+  if ($module) {
+    $node_info = call_user_func($details['module'] . '_node_info');
+  }
+  else {
+    $node_types = module_invoke_all('node_info');
+  
+    if (isset($node_types[$content_type])) {
+      $node_info = $node_types[$content_type];
+    }
+    else {
+      return FALSE;
+    }
+  }
+  
+  if (isset($node_info['chado_node_api']['base_table'])) {
+    return $node_info['chado_node_api']['base_table'];
+  }
+  else {
+    return FALSE;
+  }
+
+}
+
 /**
  * @section
  * Sync Form
@@ -826,4 +866,4 @@ function hook_chado_node_sync_select_query (&$select, &$joins, &$where_clauses,
   // Or filter the query using where clauses
   $where_clauses[] = 'example.myfavfield = :favvalue';
   $where_args[':favvalue'] = 'awesome-ness';
-}
+}

+ 170 - 27
tripal_core/api/tripal_core.chado_nodes.title_and_path.inc

@@ -61,33 +61,50 @@
  */
 
 /**
- * Get the title of a node based on the Title Format set in the admin section of the module
+ * Get the title of a node based on the Title Format set in the admin
+ * section of the module. If the format has not yet been set than
+ * the the unique constrain and name fields will be used to generate
+ * a default format
  *
  * @param $node
  *   The node whose title you want
+ *
+ * @ingroup tripal_chado_node_api
  */
 function chado_get_node_title($node) {
   $content_type = $node->type;
 
-  $format_record = db_select('tripal_token_formats','t')
-    ->fields('t')
-    ->condition('content_type', $content_type,'=')
-    ->condition('application', 'title','=')
-    ->execute()
-    ->fetchObject();
-
-  $title = $format_record->format;
-  $tokens = unserialize($format_record->tokens);
+  $format_record = chado_node_get_token_format('title',$content_type, array('return_record' => TRUE));
+
+  if (empty($format_record)) {
+    $base_table = chado_node_get_base_table($content_type);
+    $tokens = chado_node_generate_tokens($base_table);
+    
+    // Check for a legacy option
+    $title = chado_node_get_legacy_title_default($content_type);
+    
+    // Otherwise get the unique constraint option
+    if (empty($title)) {
+      $title = chado_node_get_unique_constraint_format($base_table);
+    }
+    chado_node_add_token_format('title',$content_type,$title,$tokens);
+  }
+  else {
+    $title = $format_record->format;
+    $tokens = unserialize($format_record->tokens);
+  }
 
   // Determine which tokens were used in the format string
-  if (preg_match_all('/\[[^]]+\]/',$format_record->format,$used_tokens)) {
+  if (preg_match_all('/\[[^]]+\]/',$title,$used_tokens)) {
 
     // Get the value for each token used
     foreach ($used_tokens[0] as $token) {
       $token_info = $tokens[$token];
-      $value = chado_get_token_value($token_info, $node);
+      if (!empty($token_info)) {
+        $value = chado_get_token_value($token_info, $node);
 
-      $title = str_replace($token,$value,$title);
+        $title = str_replace($token,$value,$title);
+      }
     }
   }
   else {
@@ -107,20 +124,25 @@ function chado_get_node_title($node) {
  * @param $details
  *   An array defining details used by this form.
  *   Required keys that are always required:
- *     -module: the name of the module implementing the node. For example, for features the module is tripal_feature.
+ *     -module: the name of the module implementing the node. For example, for features
+ *      the module is tripal_feature.
+ *     -options: an array of quick-choice options to supply to the user. The key should be
+ *      the token and the value should be a human-readable description of the option
  *   Optional keys include:
+ *     -content_type: the name of the content type. Defaults to module name.
  *     -fieldset_title: the title to use for the fieldset. Defaults to "Set Page Title".
+ *     -default_option: the default format to use which matches one of those in $details['options']
+ *     -custom_tokens: an array of custom tokens that follow the same format as those
+ *      generated by chado_node_generate_tokens().
+ *
+ * @ingroup tripal_chado_node_api
  */
 function chado_add_admin_form_set_title(&$form, &$form_state, $details) {
 
-  // Defaults
-  $details['fieldset_title'] = (isset($details['fieldset_title'])) ? $details['fieldset_title'] : 'Set Page Titles';
-  $details['additional_instructions'] = (isset($details['additional_instructions'])) ? $details['additional_instructions'] : '';
-
   // Get Node Info
   if (isset($details['module'])) {
     $node_info = call_user_func($details['module'] . '_node_info');
-    $chado_node_api = $node_info[ $details['module'] ]['chado_node_api'];
+    $chado_node_api = $node_info[ $details['content_type'] ]['chado_node_api'];
   }
   else {
     tripal_report_error(
@@ -130,9 +152,19 @@ function chado_add_admin_form_set_title(&$form, &$form_state, $details) {
     );
   }
 
+  // Defaults
+  $details['fieldset_title'] = (isset($details['fieldset_title'])) ? $details['fieldset_title'] : 'Set Page Titles';
+  $details['additional_instructions'] = (isset($details['additional_instructions'])) ? $details['additional_instructions'] : '';
+  $details['custom_tokens'] = (isset($details['custom_tokens'])) ? $details['custom_tokens'] : array();
+  $details['content_type'] = (isset($details['content_type'])) ? $details['content_type'] : $details['module'];
+  $details['default_option'] = (isset($details['default_option'])) ? $details['default_option'] : FALSE;
+  $details['default_option'] = ($details['default_option'] === FALSE) ? chado_node_get_token_format('title', $node_info[ $details['module'] ]['base']) : $details['default_option'];
+  $details['default_option'] = ($details['default_option'] === FALSE) ? $details['unique_option'] : $details['default_option'];
+
 
   // Determine what the tokens for the custom option should be using the chado schema api
   $tokens = chado_node_generate_tokens($chado_node_api['base_table']);
+  $tokens = array_merge($tokens, $details['custom_tokens']);
   $token_list = chado_node_format_tokens($tokens);
 
   // FORM PROPER
@@ -158,7 +190,7 @@ function chado_add_admin_form_set_title(&$form, &$form_state, $details) {
 
   $form['set_titles']['content_type'] = array(
     '#type' => 'hidden',
-    '#value' => $node_info[ $details['module'] ]['base'],
+    '#value' => $node_info[ $details['content_type'] ]['base'],
   );
 
   $details['options']['custom'] = 'Custom: See the text field below.';
@@ -171,7 +203,7 @@ function chado_add_admin_form_set_title(&$form, &$form_state, $details) {
       array('%plural' => $chado_node_api['record_type_title']['plural'])),
     '#required'      => FALSE,
     '#options'       => $details['options'],
-    '#default_value' => chado_node_get_token_format('title', $node_info[ $details['module'] ]['base']),
+    '#default_value' => $details['default_option'],
   );
 
   $form['set_titles']['title_format_variable'] = array(
@@ -187,7 +219,7 @@ function chado_add_admin_form_set_title(&$form, &$form_state, $details) {
       between the tokens. <strong>Important: be sure that whatever you choose
       will always be unique even considering future data that may be added. If in doubt,
       please select the unique constraint title option above.</strong>',
-    '#default_value' => chado_node_get_token_format('title', $node_info[ $details['module'] ]['base']),
+    '#default_value' => $details['default_option'],
     '#rows' => 1
   );
 
@@ -252,6 +284,38 @@ function chado_add_admin_form_set_title_form_submit($form, $form_state) {
   chado_node_add_token_format('title', $form_state['values']['content_type'], $format, $form_state['values']['tokens']);
 }
 
+/**
+ * Handles legacy title options
+ *
+ * Features & Stocks already had custom functionality to handle title
+ * setting before this API was created. That has since been removed but
+ * but to remain backwards compatible this function checks for those
+ * old settings and translates them into new defaults.
+ */
+function chado_node_get_legacy_title_default($content_type) {
+  if ($content_type == 'chado_feature') {
+
+  }
+  elseif ($content_type == 'chado_stock') {
+    $legacy_option = variable_get('chado_stock_title', 'unique_constraint');
+    switch ($legacy_option) {
+      case 'stock_unique_name':
+        $default_title_format = '[stock.uniquename]';
+        break;
+      case 'stock_name':
+        $default_title_format = '[stock.name]';
+        break;
+      case 'unique_constraint':
+        $default_title_format = '[stock.name], [stock.uniquename] ([stock.type_id>cvterm.name]) [stock.organism_id>organism.genus] [stock.organism_id>organism.species]';
+        break;
+    }
+    return $default_title_format;
+  }
+  else {
+    return FALSE;
+  }
+}
+
 /**
  * @section
  * Set Paths
@@ -308,11 +372,14 @@ function chado_node_add_token_format($application, $content_type, $format, $toke
  *   and 'path' for generating node paths
  * @param $content_type
  *   The name of the content type this format applies to (ie: $node->type)
- *
+ * @param $options
+ *   An array of any of the following options:
+ *    - return_record: if TRUE this will return the entire record rather
+ *      than just the format string
  * @return
  *   A string specifying the format
  */
-function chado_node_get_token_format($application, $content_type) {
+function chado_node_get_token_format($application, $content_type, $options) {
 
   $format_record = db_select('tripal_token_formats','t')
     ->fields('t')
@@ -322,13 +389,66 @@ function chado_node_get_token_format($application, $content_type) {
     ->fetchObject();
 
   if (is_object($format_record)) {
-    return $format_record->format;
+    if (isset($options['return_record'])) {
+      return $format_record;
+    }
+    else {
+      return $format_record->format;
+    }
   }
   else {
     return FALSE;
   }
 }
 
+/**
+ * Generate the unique constraint for a given base table using the
+ * Chado Schema API definition
+ *
+ * @param $base_table
+ *   The base table to generate the unique constraint format for
+ * @return
+ *   A format string including tokens describing the unique constraint
+ *   including all name fields
+ */
+function chado_node_get_unique_constraint_format($base_table) {
+
+  $table_descrip = chado_get_schema($base_table);
+  
+  // Find the name/uniquename from the base table
+  $names = array();
+  foreach($table_descrip['fields'] as $field_name => $field) {
+    if (preg_match('/name/',$field_name)) {
+      $names[$field_name] = "[$base_table.$field_name]";
+    }
+  }
+  uksort($names, 'tripal_sort_key_length_asc');
+
+
+  // Get tokens to match the unique key
+  $tokens = array();
+  foreach ($table_descrip['unique keys'] as $keyset) {
+    foreach ($keyset as $key) {
+      if (isset($names[$key])) {
+        // Do not add it into the tokens if it's already in the names
+        // since we don't want it repeated 2X
+      }
+      elseif ($key == 'type_id') {
+        $tokens[$key] = "[$base_table.type_id>cvterm.name]";
+      }
+      elseif ($key == 'organism_id') {
+        $tokens[$key] = "[$base_table.organism_id>organism.abbreviation]";
+      }
+      else {
+        $tokens[$key] = "[$base_table.$key]";
+      }
+    }
+  }
+  
+  $format = implode(', ',$names) . ' (' . implode(', ',$tokens) . ')';
+  return $format;
+}
+
 /**
  * Generate tokens for a particular base table
  *
@@ -432,7 +552,12 @@ function chado_get_token_value($token_info, $node) {
   foreach ($location as $index) {
     $index = trim($index);
     if (is_object($var)) {
-      $var = $var->{$index};
+      if (isset($var->{$index})) {
+        $var = $var->{$index};
+      }
+      else {
+        // @TODO: Error Handling
+      }
     }
     elseif (is_array($var)) {
       $var = $var[$index];
@@ -517,4 +642,22 @@ function chado_sort_tokens_by_location($tokenA, $tokenB) {
 
   // If the depth is equal then just use alphabetical basic string compare
   return ($tokenA['location'] < $tokenB['location']) ? -1 : 1;
-}
+}
+
+/**
+ * Sorts an associative array by key length where sorter keys will be first
+ *
+ * This is a uksort callback and shouldn't be called directly. To use;
+ *    uksort($arr, 'tripal_sort_key_length_asc');
+ */
+function tripal_sort_key_length_asc($a, $b) {
+  if (strlen($a) == strlen($b)) {
+    return 0;
+  }
+  elseif (strlen($a) > strlen($b)) {
+    return 1;
+  }
+  else {
+    return -1;
+  }
+}

+ 11 - 29
tripal_stock/includes/tripal_stock.admin.inc

@@ -52,36 +52,18 @@ function tripal_stock_admin() {
 
 
   // STOCK PAGE TITLES CONFIGURATION
-  $form['title'] = array(
-    '#type' => 'fieldset',
-    '#title' => t('Stock Page Titles'),
-    '#collapsible' => TRUE,
-    '#collapsed' => FALSE,
-  );
-  $form['title']['desc'] = array(
-    '#markup' => t('Each synced stock must have a unique page title, however, stocks
-      may have the same name if they are of different types or from different
-      organisms.  Therefore, we must be sure that the page titles can uniquely
-      identify the stock being viewed.  Select an option below that will
-      uniquely identify all stocks on your site.'),
-  );
-  $options = array(
-    'stock_unique_name'  => 'Only stock unique name',
-    'stock_name'         => 'Only stock name',
-    'unique_constraint'  => 'Includes stock name, uniquename, type and species',
-  );
-  $form['title']['chado_stock_title'] = array(
-    '#title'         => t('Stock Page Titles'),
-    '#type'          => 'radios',
-    '#description'   => t('Choose a title type  from the list above that is
-      guaranteed to be unique for all stocks If in doubt it is safest to choose
-      the last option as that guarantees uniqueness. Click the
-      \'Save Configuration\' button at the bottom to save your selection.'),
-    '#required'      => FALSE,
-    '#options'       => $options,
-    '#default_value' => variable_get('chado_stock_title', 'unique_constraint'),
+
+  $details = array(
+    'module' => 'tripal_stock',
+    'content_type' => 'chado_stock',
+    'options' => array(
+      '[stock.name]' => 'Stock Name Only',
+      '[stock.uniquename]' => 'Stock Unique Name Only',
+      '[stock.name], [stock.uniquename] ([stock.type_id>cvterm.name]) [stock.organism_id>organism.genus] [stock.organism_id>organism.species]' => 'Unique Contraint: Includes the name, uniquename, type and scientific name'
+    ),
+    'unique_option' => '[stock.name], [stock.uniquename] ([stock.type_id>cvterm.name]) [stock.organism_id>organism.genus] [stock.organism_id>organism.species]'
   );
-  
+  chado_add_admin_form_set_title($form, $form_state, $details);
 
   // STOCK URL CONFIGURATION
   $form['url'] = array(

+ 21 - 23
tripal_stock/includes/tripal_stock.chado_node.inc

@@ -77,32 +77,14 @@ function chado_stock_load($nodes) {
     $stock = chado_expand_var($stock, 'field', 'stock.uniquename');
     $stock = chado_expand_var($stock, 'field', 'stock.description');
 
-    // by default, the titles are saved using the unique constraint.  We will
-    // keep it the same, but remove the duplicate name if the unique name and name
-    // are identical
-    $title_type = variable_get('chado_stock_title', 'unique_constraint');
-    if($title_type == 'unique_constraint') {
-      if (strcmp($stock->name, $stock->uniquename)==0) {
-        $node->title = $stock->name . " (" . $stock->type_id->name . ") " . $stock->organism_id->genus . " " . $stock->organism_id->species ;
-      }
-      // in previous version of Tripal, the stock title was simply the unique name.
-      // so, we recreate the title just to be sure all of our stock pages are consistent
-      else {
-        $node->title = $stock->name . ", " . $stock->uniquename . " (" . $stock->type_id->name . ") " . $stock->organism_id->genus . " " . $stock->organism_id->species ;
-      }
-    }
-    // set the title to be the stock name or uniquename as configured
-    if($title_type == 'stock_name') {
-      $node->title = $stock->name;
-    }
-    if($title_type == 'stock_unique_name') {
-      $node->title = $stock->uniquename;
-    }
-
     // add this to the node
     $node->stock = $stock;
     $new_nodes[$nid] = $node;
 
+    // If your module is using the Chado Node: Title & Path API to allow custom titles
+    // for your node type. Every time you want the title of the node, you need to use the
+    // following API function:
+    $node->title = chado_get_node_title($node);
   }
 
   return $new_nodes;
@@ -816,7 +798,12 @@ function tripal_stock_node_presave($node) {
       }
       $values = array('organism_id' => $organism_id);
       $organism = chado_select_record('organism', array('genus','species'), $values);
-      $node->title = "$sname, $uniquename ($type) " . $organism[0]->genus . ' ' . $organism[0]->species;
+
+      // If your module is using the Chado Node: Title & Path API to allow custom titles
+      // for your node type. Every time you want the title of the node, you need to use the
+      // following API function:
+      $node->title = chado_get_node_title($node);
+
       if ($sname == $uniquename) {
         $node->title = "$sname ($type) " . $organism[0]->genus . ' ' . $organism[0]->species;
       }
@@ -902,6 +889,11 @@ function tripal_stock_node_insert($node) {
   switch ($node->type) {
     case 'chado_stock':
 
+      // If your module is using the Chado Node: Title & Path API to allow custom titles
+      // for your node type. Every time you want the title of the node, you need to use the
+      // following API function:
+      $node->title = chado_get_node_title($node);
+
       // on an insert we need to add the stock_id to the node object
       // so that the tripal_stock_get_stock_url function can set the URL properly
       $node->stock_id = chado_get_id_from_nid('stock', $node->nid);
@@ -928,6 +920,12 @@ function tripal_stock_node_update($node) {
   // add items to other nodes, build index and search results
   switch ($node->type) {
     case 'chado_stock':
+
+      // If your module is using the Chado Node: Title & Path API to allow custom titles
+      // for your node type. Every time you want the title of the node, you need to use the
+      // following API function:
+      $node->title = chado_get_node_title($node);
+
       // remove any previous alias
       db_query("DELETE FROM {url_alias} WHERE source = :source", array(':source' => "node/$node->nid"));