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();
   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
  * @section
  * Sync Form
  * Sync Form
@@ -826,4 +866,4 @@ function hook_chado_node_sync_select_query (&$select, &$joins, &$where_clauses,
   // Or filter the query using where clauses
   // Or filter the query using where clauses
   $where_clauses[] = 'example.myfavfield = :favvalue';
   $where_clauses[] = 'example.myfavfield = :favvalue';
   $where_args[':favvalue'] = 'awesome-ness';
   $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
  * @param $node
  *   The node whose title you want
  *   The node whose title you want
+ *
+ * @ingroup tripal_chado_node_api
  */
  */
 function chado_get_node_title($node) {
 function chado_get_node_title($node) {
   $content_type = $node->type;
   $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
   // 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
     // Get the value for each token used
     foreach ($used_tokens[0] as $token) {
     foreach ($used_tokens[0] as $token) {
       $token_info = $tokens[$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 {
   else {
@@ -107,20 +124,25 @@ function chado_get_node_title($node) {
  * @param $details
  * @param $details
  *   An array defining details used by this form.
  *   An array defining details used by this form.
  *   Required keys that are always required:
  *   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:
  *   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".
  *     -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) {
 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
   // Get Node Info
   if (isset($details['module'])) {
   if (isset($details['module'])) {
     $node_info = call_user_func($details['module'] . '_node_info');
     $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 {
   else {
     tripal_report_error(
     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
   // 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 = chado_node_generate_tokens($chado_node_api['base_table']);
+  $tokens = array_merge($tokens, $details['custom_tokens']);
   $token_list = chado_node_format_tokens($tokens);
   $token_list = chado_node_format_tokens($tokens);
 
 
   // FORM PROPER
   // FORM PROPER
@@ -158,7 +190,7 @@ function chado_add_admin_form_set_title(&$form, &$form_state, $details) {
 
 
   $form['set_titles']['content_type'] = array(
   $form['set_titles']['content_type'] = array(
     '#type' => 'hidden',
     '#type' => 'hidden',
-    '#value' => $node_info[ $details['module'] ]['base'],
+    '#value' => $node_info[ $details['content_type'] ]['base'],
   );
   );
 
 
   $details['options']['custom'] = 'Custom: See the text field below.';
   $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'])),
       array('%plural' => $chado_node_api['record_type_title']['plural'])),
     '#required'      => FALSE,
     '#required'      => FALSE,
     '#options'       => $details['options'],
     '#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(
   $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
       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,
       will always be unique even considering future data that may be added. If in doubt,
       please select the unique constraint title option above.</strong>',
       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
     '#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']);
   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
  * @section
  * Set Paths
  * Set Paths
@@ -308,11 +372,14 @@ function chado_node_add_token_format($application, $content_type, $format, $toke
  *   and 'path' for generating node paths
  *   and 'path' for generating node paths
  * @param $content_type
  * @param $content_type
  *   The name of the content type this format applies to (ie: $node->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
  * @return
  *   A string specifying the format
  *   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')
   $format_record = db_select('tripal_token_formats','t')
     ->fields('t')
     ->fields('t')
@@ -322,13 +389,66 @@ function chado_node_get_token_format($application, $content_type) {
     ->fetchObject();
     ->fetchObject();
 
 
   if (is_object($format_record)) {
   if (is_object($format_record)) {
-    return $format_record->format;
+    if (isset($options['return_record'])) {
+      return $format_record;
+    }
+    else {
+      return $format_record->format;
+    }
   }
   }
   else {
   else {
     return FALSE;
     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
  * Generate tokens for a particular base table
  *
  *
@@ -432,7 +552,12 @@ function chado_get_token_value($token_info, $node) {
   foreach ($location as $index) {
   foreach ($location as $index) {
     $index = trim($index);
     $index = trim($index);
     if (is_object($var)) {
     if (is_object($var)) {
-      $var = $var->{$index};
+      if (isset($var->{$index})) {
+        $var = $var->{$index};
+      }
+      else {
+        // @TODO: Error Handling
+      }
     }
     }
     elseif (is_array($var)) {
     elseif (is_array($var)) {
       $var = $var[$index];
       $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
   // If the depth is equal then just use alphabetical basic string compare
   return ($tokenA['location'] < $tokenB['location']) ? -1 : 1;
   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
   // 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
   // STOCK URL CONFIGURATION
   $form['url'] = array(
   $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.uniquename');
     $stock = chado_expand_var($stock, 'field', 'stock.description');
     $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
     // add this to the node
     $node->stock = $stock;
     $node->stock = $stock;
     $new_nodes[$nid] = $node;
     $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;
   return $new_nodes;
@@ -816,7 +798,12 @@ function tripal_stock_node_presave($node) {
       }
       }
       $values = array('organism_id' => $organism_id);
       $values = array('organism_id' => $organism_id);
       $organism = chado_select_record('organism', array('genus','species'), $values);
       $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) {
       if ($sname == $uniquename) {
         $node->title = "$sname ($type) " . $organism[0]->genus . ' ' . $organism[0]->species;
         $node->title = "$sname ($type) " . $organism[0]->genus . ' ' . $organism[0]->species;
       }
       }
@@ -902,6 +889,11 @@ function tripal_stock_node_insert($node) {
   switch ($node->type) {
   switch ($node->type) {
     case 'chado_stock':
     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
       // 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
       // 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);
       $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
   // add items to other nodes, build index and search results
   switch ($node->type) {
   switch ($node->type) {
     case 'chado_stock':
     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
       // remove any previous alias
       db_query("DELETE FROM {url_alias} WHERE source = :source", array(':source' => "node/$node->nid"));
       db_query("DELETE FROM {url_alias} WHERE source = :source", array(':source' => "node/$node->nid"));