Browse Source

Added API functions

spficklin 14 years ago
parent
commit
e855324df4

+ 149 - 0
tripal_cv/tripal_cv.api.inc

@@ -0,0 +1,149 @@
+<?php
+
+/*************************************************************************
+ * Purpose: To retrieve a chado cv object
+ *
+ * @params where_options: array(
+ *													<column_name> => array(
+ *														'type' => <type of column: INT/STRING>,
+ *														'value' => <the vlaue you want to filter on>,
+ *														'exact' => <if TRUE use =; if FALSE use ~>,
+ *													)
+ *				)
+ * @return chado cv object with all fields from the chado cv table
+ */
+function tripal_cv_get_cv ($where_options) {
+	$previous_db = tripal_db_set_active('chado');
+
+	$where= array();
+	//generate the where clause from supplied options
+	// the key is the column name
+	foreach ($where_options as $key => $val_array) {
+		if (preg_match('/INT/', $val_array['type'])) {
+			$where[] = $key."=".$val_array['value'];
+		} else {
+			if ($val_array['exact']) { $operator='='; }
+			else { $operator='~'; }
+			$where[] = $key.$operator."'".$val_array['value']."'";
+		}
+	}
+	
+  $r = db_fetch_object(db_query(
+    "SELECT * FROM cv WHERE ".implode(' AND ',$where)
+  ));
+  
+  tripal_db_set_active($previous_db);
+
+  return $r;
+}
+/*************************************************************************
+ * return the cv object for the specified CV name
+ */
+function tripal_cv_get_cv_by_name ($name) {
+	$previous_db = tripal_db_set_active('chado');	
+   $r = db_fetch_object(db_query("SELECT * FROM cv WHERE name = '%s'",$name));
+   tripal_db_set_active($previous_db);
+
+  return $r;
+}
+/*************************************************************************
+ * return the cv object for the specified CV id
+ */
+function tripal_cv_get_cv_by_id ($cv_id) {
+	$previous_db = tripal_db_set_active('chado');	
+   $r = db_fetch_object(db_query("SELECT * FROM cv WHERE cv_id = %d",$cv_id));
+   tripal_db_set_active($previous_db);
+
+  return $r;
+}
+/*************************************************************************
+ * Purpose: Create an options array to be used in a form element
+ *   which provides a list of all chado cvs
+ *
+ * @return an array(cv_id => name) for each cv in the chado cv table
+ */
+function tripal_cv_get_cv_options() {
+
+  $previous_db = tripal_db_set_active('chado');
+  $result = db_query(
+    "SELECT cv_id, name FROM cv"
+  );
+  db_set_active($previous_db);
+
+  $options = array();
+  while ( $r = db_fetch_object($result) ) {
+    $options[$r->cv_id] = $r->name;
+  }
+
+  return $options;
+
+}
+
+/*************************************************************************
+ * Purpose: To retrieve a chado cvterm object
+ *
+ * @params where_options: array(
+ *													<column_name> => array(
+ *														'type' => <type of column: INT/STRING>,
+ *														'value' => <the vlaue you want to filter on>,
+ *														'exact' => <if TRUE use =; if FALSE use ~>,
+ *													)
+ *				)
+ * @return chado cvterm object with all fields from the chado cvterm table
+ */
+function tripal_cv_get_cvterm ($where_options) {
+	$previous_db = tripal_db_set_active('chado');
+
+	$where= array();
+	//generate the where clause from supplied options
+	// the key is the column name
+	foreach ($where_options as $key => $val_array) {
+		if (preg_match('/INT/', $val_array['type'])) {
+			$where[] = $key."=".$val_array['value'];
+		} else {
+			if ($val_array['exact']) { $operator='='; }
+			else { $operator='~'; }
+			$where[] = $key.$operator."'".$val_array['value']."'";
+		}
+	}
+	
+  $r = db_fetch_object(db_query(
+    "SELECT * FROM cvterm WHERE ".implode(' AND ',$where)
+  ));
+  
+  tripal_db_set_active($previous_db);
+
+  return $r;
+}
+
+/*************************************************************************
+ * Purpose: Create an options array to be used in a form element
+ *   which provides a list of all chado cvterms
+ * 
+ * @params cv_id: the chado cv_id
+ *   only cvterms with the supplied cv_id will be returned
+ * @return an array(cvterm_id => name) 
+ *   for each cvterm in the chado cvterm table where cv_id=that supplied
+ */
+function tripal_cv_get_cvterm_options($cv_id = 0) {
+
+  $previous_db = tripal_db_set_active('chado');
+  if ($cv_id > 0) {
+  	$result = db_query(
+    	"SELECT cvterm_id, name FROM cvterm WHERE cv_id=%d", $cv_id
+  	);
+  } else {
+  	$result = db_query(
+    	"SELECT cvterm_id, name FROM cvterm"
+  	);
+  }
+  db_set_active($previous_db);
+
+  $options = array();
+  while ( $r = db_fetch_object($result) ) {
+    $options[$r->cvterm_id] = $r->name;
+  }
+
+  return $options;
+
+}

+ 98 - 0
tripal_db/tripal_db.api.inc

@@ -0,0 +1,98 @@
+<?php
+
+/*************************************************************************
+ * Purpose: To retrieve a chado db object
+ *
+ * @params where_options: array(
+ *													<column_name> => array(
+ *														'type' => <type of column: INT/STRING>,
+ *														'value' => <the vlaue you want to filter on>,
+ *														'exact' => <if TRUE use =; if FALSE use ~>,
+ *													)
+ *				)
+ * @return chado db object with all fields from the chado db table
+ */
+function tripal_db_get_db ($where_options) {
+	$previous_db = tripal_db_set_active('chado');
+
+	$where= array();
+	//generate the where clause from supplied options
+	// the key is the column name
+	foreach ($where_options as $key => $val_array) {
+		if (preg_match('/INT/', $val_array['type'])) {
+			$where[] = $key."=".$val_array['value'];
+		} else {
+			if ($val_array['exact']) { $operator='='; }
+			else { $operator='~'; }
+			$where[] = $key.$operator."'".$val_array['value']."'";
+		}
+	}
+	
+  $r = db_fetch_object(db_query(
+    "SELECT * FROM db WHERE ".implode(' AND ',$where)
+  ));
+  
+  tripal_db_set_active($previous_db);
+
+  return $r;
+}
+
+/*************************************************************************
+ * Purpose: Create an options array to be used in a form element
+ *   which provides a list of all chado dbs
+ *
+ * @return an array(db_id => name) for each db in the chado db table
+ */
+function tripal_db_get_db_options() {
+
+  $previous_db = tripal_db_set_active('chado');
+  $result = db_query(
+    "SELECT db_id, name FROM db"
+  );
+  db_set_active($previous_db);
+
+  $options = array();
+  while ( $r = db_fetch_object($result) ) {
+    $options[$r->db_id] = $r->name;
+  }
+
+  return $options;
+
+}
+
+/*************************************************************************
+ * Purpose: To retrieve a chado dbxref object
+ *
+ * @params where_options: array(
+ *													<column_name> => array(
+ *														'type' => <type of column: INT/STRING>,
+ *														'value' => <the vlaue you want to filter on>,
+ *														'exact' => <if TRUE use =; if FALSE use ~>,
+ *													)
+ *				)
+ * @return chado dbxref object with all fields from the chado dbxref table
+ */
+function tripal_db_get_dbxref ($where_options) {
+	$previous_db = tripal_db_set_active('chado');
+
+	$where= array();
+	//generate the where clause from supplied options
+	// the key is the column name
+	foreach ($where_options as $key => $val_array) {
+		if (preg_match('/INT/', $val_array['type'])) {
+			$where[] = $key."=".$val_array['value'];
+		} else {
+			if ($val_array['exact']) { $operator='='; }
+			else { $operator='~'; }
+			$where[] = $key.$operator."'".$val_array['value']."'";
+		}
+	}
+	
+  $r = db_fetch_object(db_query(
+    "SELECT * FROM dbxref WHERE ".implode(' AND ',$where)
+  ));
+  
+  tripal_db_set_active($previous_db);
+
+  return $r;
+}

+ 338 - 0
tripal_feature/tripal_feature-db_references.inc

@@ -0,0 +1,338 @@
+<?php
+
+/*************************************************************************************************************
+ * @section 
+ * Deals with Adding DB references
+ */
+
+function tripal_feature_add_ALL_dbreferences_page($node) {
+  $output = '';
+
+  $output .= tripal_feature_implement_add_chado_properties_progress('db_references').'<br>';
+  $output .= '<b>All Database References should strictly pertain to THE CURRENT Individual</b><br>';
+  $output .= '<br><b>Current Database References</b><br>';
+  $output .= list_dbreferences_for_node($node->db_references);
+  $output .= '<br><br>';
+  $output .= drupal_get_form('tripal_feature_add_ONE_dbreference_form', $node);
+  $output .= '<br>';
+  $output .= drupal_get_form('tripal_feature_implement_add_chado_properties_navigate', 'db_references', $node->nid);
+  return $output;
+}
+
+
+/**
+ * Implements Hook_form()
+ * Handles adding of Database References to Stocks
+ */
+function tripal_feature_add_ONE_dbreference_form($form_state, $node) {
+
+  $stock_id = $node->stock_id;
+
+  $form['db_nid'] = array(
+    '#type' => 'hidden',
+    '#value' => $node->nid
+  );
+
+  $form['add_dbreference'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Add Database References') . '<span class="form-optional" title="This field is optional">(optional)</span>',
+  );
+
+  $form['add_properties']['db_stock_id'] = array(
+    '#type' => 'value',
+    '#value' => $stock_id,
+    '#required' => TRUE
+
+  );
+
+  $form['add_dbreference']['accession'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Accession Number'),
+  );
+
+  $form['add_dbreference']['db_description'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Description of Database Reference') . '<span class="form-optional" title="This field is optional">+</span>',
+    '#description' => t('Optionally enter a description about the database accession.')
+  );
+
+  $db_options = tripal_db_get_db_options();
+  $db_options[0] = 'Select a Database';
+  ksort($db_options);
+  $form['add_dbreference']['database'] = array(
+    '#type' => 'select',
+    '#title' => t('Database'),
+    '#options' => $db_options,
+  );
+
+  $form['add_dbreference']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Add Database Reference')
+  );
+
+  return $form;
+}
+
+function tripal_feature_add_ONE_dbreference_form_validate($form, &$form_state) {
+
+  // Only ensure db reference valid if adding
+  if ($form_state['clicked_button']['#value'] == t('Add Database Reference') ) {
+    //Do work of required validators
+    if ($form_state['values']['accession'] == '') {
+      form_set_error('accession', 'Accession field is Required.');
+    }
+
+    // Check database is valid db_id in chado
+    if ( $form_state['values']['database'] > 0) {
+    	$previous_db = tripal_db_set_active('chado');
+    	$tmp_obj = db_fetch_object(db_query("SELECT count(*) as count FROM db WHERE db_id=%d",$form_state['values']['database']));
+    	tripal_db_set_active($previous_db);
+    	
+      if ($tmp_obj->count != 1) {
+        form_set_error('database', 'The database you selected is not valid. Please choose another one.'); 
+      }
+    } else {
+      form_set_error('database', 'Please select a database');
+    }
+
+    // Check Accession is unique for database
+    $previous_db = tripal_db_set_active('chado');
+    $tmp_obj = db_fetch_object(db_query("SELECT count(*) as count FROM dbxref WHERE accession='%s'",$form_state['values']['accession']));
+    tripal_db_set_active($previous_db);
+    	
+    if ($tmp_obj->count > 0) {
+      form_set_error('accession', 'This accession has already been assigned to another stock.'); 
+    }
+
+  } //end of if adding
+
+} 
+
+function tripal_feature_add_ONE_dbreference_form_submit($form, &$form_state) {
+
+  // FIX: Sometimes on programatic submission of form (drupal_execute) values in the form state get lost
+  // 	  however, the post values always seem to be correct
+  if (empty($form_state['values']['db_stock_id'])) { $form_state['values']['db_stock_id'] = $form_state['clicked_button']['#post']['db_stock_id']; }
+
+  // Only Create if valid
+  if ($form_state['values']['database'] > 0) {
+    
+
+    // create dbxref
+    $previous_db = tripal_db_set_active('chado');
+    db_query(
+      "INSERT INTO dbxref (db_id, accession, description) VALUES (%d, '%s', '%s')",
+      $form_state['values']['database'],
+      $form_state['values']['accession'],
+      $form_state['values']['db_description']
+    );
+    tripal_db_set_active($previous_db);
+
+    //create stock_dbxref
+    $dbxref = tripal_db_get_dbxref( array('db_id'=>array('type'=>'INT','value'=>$form_state['values']['database']), 
+    																	'accession'=>array('type'=>'STRING','exact'=>TRUE,'value'=>$form_state['values']['accession']) ) );
+		if (!empty($dbxref->dbxref_id)) {
+			$previous_db = tripal_db_set_active('chado');
+    	db_query(
+      	"INSERT INTO stock_dbxref (stock_id, dbxref_id) VALUES (%d, %d)",
+      	$form_state['values']['db_stock_id'],
+      	$dbxref->dbxref_id
+    	);
+			tripal_db_set_active($previous_db);
+
+    	drupal_set_message('Successfully Added Database Reference');
+    } else {
+    	drupal_set_message('Database reference NOT successfully created...','error');
+    } //end of if dbxref was created successfully
+  } //end of if valid db reference
+
+}
+
+/************************************************************************************************************* 
+ * @section                                    
+ * Deals with Editing and Deleting Properties  
+ */                                            
+
+function tripal_feature_edit_ALL_dbreferences_page($node) {
+  $output = '';
+
+  $output .= drupal_get_form('tripal_feature_edit_ALL_db_references_form', $node);
+  $output .= '<br>';
+  $output .= drupal_get_form('tripal_feature_add_ONE_dbreference_form', $node);
+  $output .= '<br>';
+  $output .= drupal_get_form('tripal_feature_implement_back_to_stock_button', $node->nid);
+
+  return $output;
+}
+                                               
+/**                                            
+ * Implements Hook_form()                      
+ * Handles adding of Properties & Synonyms to Stocks
+ */                                        
+function tripal_feature_edit_ALL_db_references_form($form_state, $node) {
+  $form = array();
+
+  $form['nid'] = array(
+    '#type' => 'hidden',
+    '#value' => $node->nid
+  );
+
+  $i=0;
+  if (sizeof($node->db_references) != 0) {
+  foreach ($node->db_references as $ref) {
+    $i++;
+    $form["num-$i"] = array(
+      '#type' => 'item',
+      '#value' => $i.'.'
+    );
+
+    $form["accession-$i"] = array(
+      '#type' => 'textfield',
+      //'#title' => t('Accession'),
+      '#size' => 30,
+      '#required' => TRUE,
+      '#default_value' => $ref->accession
+    );
+
+    $db_options = tripal_db_get_db_options();
+    $db_options[0] = 'Select a Database';
+    ksort($db_options);
+    $form["database-$i"] = array( 
+      '#type' => 'select', 
+      //'#title' => t('Database'),
+      '#options' => $db_options, 
+      '#default_value' => $ref->db_id
+    );
+
+
+    $form["id-$i"] = array(
+      '#type' => 'hidden',
+      '#value' => $ref->dbxref_id
+    );
+
+    $form["submit-$i"] = array(
+      '#type' => 'submit',
+      '#value' => t("Delete #$i")
+    );
+
+  }} //end of foreach db ref
+
+  $form['num_db_references'] = array(
+    '#type' => 'hidden',
+    '#value' => $i
+  );
+
+  $form["submit-edits"] = array(
+    '#type' => 'submit',
+    '#value' => t('Update DB References')
+  );
+
+  return $form;
+}
+
+function tripal_feature_edit_ALL_db_references_form_submit($form, &$form_state) {
+
+  if ($form_state['clicked_button']['#value'] == t('Update DB References') ) {
+
+     //Update all
+     for ($i=1; $i<=$form_state['values']['num_db_references']; $i++) {
+       tripal_feature_update_db_reference(
+					$form_state['values']["id-$i"], 
+					$form_state['values']["database-$i"], 
+					$form_state['values']["accession-$i"]
+			);
+     }
+     drupal_set_message("Updated all Database References");
+     drupal_goto('node/'.$form_state['values']['nid']);
+
+  } elseif ( preg_match('/Delete #(\d+)/', $form_state['clicked_button']['#value'], $matches) ) {
+
+     $i = $matches[1];
+     tripal_feature_delete_db_reference($form_state['values']["id-$i"]);
+     drupal_set_message("Deleted Database Reference");
+
+  } else {
+    drupal_set_message("Unrecognized Button Pressed",'error');
+  }
+
+}
+
+function tripal_feature_update_db_reference($dbxref_id, $database_id, $accession) {
+
+  $previous_db = db_set_active('chado');
+  db_query(
+    "UPDATE dbxref SET db_id=%d, accession='%s' WHERE dbxref_id=%d",
+    $database_id, 
+    $accession,
+    $dbxref_id
+  );
+  db_set_active($previous_db);
+
+}
+
+function tripal_feature_delete_db_reference($dbxref_id) {
+
+  $previous_db = db_set_active('chado');
+  db_query(
+    "DELETE FROM dbxref WHERE dbxref_id=%d",
+    $dbxref_id
+  );
+
+  db_query(
+    "DELETE FROM stock_dbxref WHERE dbxref_id=%d",
+    $dbxref_id
+  );
+  db_set_active($previous_db);
+
+}
+
+function theme_tripal_feature_edit_ALL_db_references_form ($form) {
+  $output = '';
+
+  $output .= '<br><fieldset>';
+  $output .= '<legend>Edit Existing Database References<span class="form-optional" title="This field is optional">(optional)</span></legend>';
+  $output .= '<p>Below is a list of already existing database references, one per line. When entering a database reference, the accession '
+  	     .'is a unique identifier for this stock in the specified database.</p>';
+  $output .= '<table>';
+  $output .= '<tr><th>#</th><th>Database</th><th>Accession</th><th></th></tr>';
+
+  for ($i=1; $i<=$form['num_db_references']['#value']; $i++) {
+    $output .= '<tr><td>'.drupal_render($form["num-$i"]).'</td><td>'
+    	       .drupal_render($form["database-$i"]).'</td><td>'
+	       .drupal_render($form["accession-$i"]).'</td><td>'
+	       .drupal_render($form["submit-$i"]).'</td></tr>';
+  }
+
+  $output .= '</table><br>';
+  $output .= drupal_render($form);
+  $output .= '</fieldset>';
+
+  return $output;
+}
+
+/*************************************************************************************************************
+ * @section
+ * Supplimentary functions
+ */
+
+/**
+ * 
+ */
+function list_dbreferences_for_node($db_references) {
+
+  if (!empty($db_references) ) {
+    $output = '<table>';
+    $output .= '<tr><th>Database</th><th>Accession</th></tr>';
+
+    foreach ($db_references as $db) {
+        $output .= '<tr><td>'.$db->db_name.'</td><td>'.$db->accession.'</td></tr>';
+    } // end of foreach db reference 
+
+    $output .= '</table>'; 
+
+  } else {
+    $output = 'No Database References Added to the Current Stock';
+  }              
+
+  return $output;
+}     

+ 390 - 0
tripal_feature/tripal_feature-properties.inc

@@ -0,0 +1,390 @@
+<?php
+
+/*************************************************************************************************************
+ * @section
+ * Deals with Adding Properties
+ */
+
+/**
+ * Implements Hook_form()
+ * Handles adding of Properties & Synonyms to Stocks
+ */
+function tripal_getfeature_add_ALL_property_page($node) {
+  $output = '';
+
+  $output .= implement_add_chado_properties_progress('properties').'<br>';
+  $output .= '<b>All Properties should strictly pertain to THE CURRENT Individual</b><br>';
+  $output .= '<br><b>Current Properties</b><br>';
+  $output .= list_properties_for_node($node->properties, $node->synonyms);
+  $output .= '<br><br>';
+  $output .= drupal_get_form('tripal_feature_add_ONE_property_form', $node);
+  $output .= '<br>';
+  $output .= drupal_get_form('implement_add_chado_properties_navigate', 'properties', $node->nid);
+  return $output;
+}
+
+function tripal_feature_add_ONE_property_form($form_state, $node) {
+  $form = array();
+  $stock_id = $node->stock_id;
+
+  $form['add_properties'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Add Property') . '<span class="form-optional" title="This field is optional"> (optional)</span>',
+  ); 
+
+  $form['prop_nid'] = array(
+    '#type' => 'hidden',
+    '#value' => $node->nid
+  );
+
+  $tmp_obj = tripal_cv_get_cvterm(array('name' => array('type'=>'STRING','exact'=>TRUE, 'value'=>'synonym'),
+  																	'cv_id' => array('type'=>'INT','value'=>variable_get('chado_stock_prop_types_cv', 'null') )));
+	$synonym_id = $tmp_obj->cvterm_id;
+	
+  $prop_type_options = tripal_cv_get_cvterm_options( variable_get('chado_stock_prop_types_cv', 'null') ); 
+  $prop_type_options[0] = 'Select a Type';
+  ksort($prop_type_options);
+  $form['add_properties']['prop_type_id'] = array(
+    '#type' => 'select',
+    '#title' => t('Type of Property'),
+    '#options' => $prop_type_options,
+  );
+
+  $form['add_properties']['prop_value'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Value') . '<span class="form-optional" title="This field is optional">+</span>',
+  );
+
+  $form['add_properties']['preferred_synonym'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Preferred Synonym (only applicable if type is synonym)'),
+  );
+
+  $form['add_properties']['prop_stock_id'] = array(
+    '#type' => 'value',
+    '#value' => $stock_id,
+    '#required' => TRUE
+  );
+
+  $form['add_properties']['submit-add'] = array(
+    '#type' => 'submit',         
+    '#value' => t('Add Property')
+  );
+
+  return $form;
+}
+
+function tripal_feature_add_ONE_property_form_validate($form, &$form_state) {
+
+  // Only Require if Adding Property
+  if ($form_state['clicked_button']['#value'] == t('Add Property') ) {
+
+		// Check that there is a stock
+		if ( $form_state['values']['prop_stock_id'] <= 0 ) {
+			form_set_error('prop_stock_id', 'There is no associated stock.');
+		}
+		
+    // Check that Selected a type
+    if ( $form_state['values']['prop_type_id'] == 0) {
+      form_set_error('prop_type_id', 'Please select a type of property.');
+    } else {
+      // Check that type is in chado
+      $previous_db = tripal_db_set_active('chado');
+      $num_rows = db_fetch_object(db_query("SELECT count(*) as count FROM cvterm WHERE cvterm_id=%d", $form_state['values']['prop_type_id']));
+      tripal_db_set_active($previous_db);
+      if ( $num_rows->count != 1) {
+        form_set_error('prop_type_id', "The type you selected is not valid. Please choose another one. (CODE:$num_rows)");
+      } // end of if more or less than 1 row
+    } // if no prop type
+
+    // only check preferred synonym if type is synonym
+    if ($form_state['values']['preferred_synonym'] == 1) {
+    $tmp_obj = tripal_cv_get_cvterm(array('name' => array('type'=>'STRING','exact'=>TRUE, 'value'=>'synonym'),
+  																	'cv_id' => array('type'=>'INT','value'=>variable_get('chado_stock_prop_types_cv', 'null') )));
+      if ($form_state['values']['prop_type_id'] != $tmp_obj->cvterm_id) {
+        form_set_error('preferred_synonym', 'Preferred Synonym Checkbox Only Applicable if Type of Property is Synonym');
+      }
+    }
+
+  } // if add Property
+
+}
+
+function tripal_feature_add_ONE_property_form_submit($form, &$form_state) {
+	
+  // if there is a property add it (only won't be a property if clicked next step w/ no property)
+  if ($form_state['values']['prop_type_id'] != 0) {
+    //determine the rank for this property
+    $max_rank = get_max_chado_rank('stockprop', 
+    															array('stock_id'=>array('type'=>'INT','value'=>$form_state['values']['prop_stock_id']), 
+    																		'type_id'=>array('type'=>'INT','value'=> $form_state['values']['prop_type_id']) ));
+    if ($max_rank == -1) { $rank = 0; 
+    } else { $rank = $max_rank+1; }
+    
+    $previous_db = tripal_db_set_active('chado');
+    db_query(
+      "INSERT INTO stockprop (stock_id, type_id, value, rank) VALUES (%d, %d, '%s', %d)",
+      $form_state['values']['prop_stock_id'],
+      $form_state['values']['prop_type_id'],
+      $form_state['values']['prop_value'],
+      $rank
+    );
+    tripal_db_set_active($previous_db);
+
+    drupal_set_message("Successfully Added Property");
+
+    // Set Preferred Synonym
+    if ($form_state['values']['preferred_synonym'] == 1) {
+
+      //use update node form so that both title and name get set
+      $node = node_load($form_state['values']['prop_nid']);
+      $node->title = $form_state['values']['prop_value'];
+      $node_form_state = array( 
+        'values' => array(
+					'title' => $form_state['values']['prop_value'], 
+					'op' => 'Save'
+				) 
+      );
+      module_load_include('inc', 'node', 'node.pages');
+      drupal_execute('chado_stock_node_form', $node_form_state, $node);
+
+    }
+
+  } //end of if property to add
+}
+
+/*************************************************************************************************************
+ * @section
+ * Deals with Editing and Deleting Properties
+ */
+
+function tripal_feature_edit_ALL_properties_page($node) {
+  $output = '';
+
+  $output .= drupal_get_form('tripal_feature_edit_ALL_properties_form', $node);
+  $output .= '<br>';
+  $output .= drupal_get_form('tripal_feature_add_ONE_property_form', $node);
+  $output .= '<br>';
+  $output .= drupal_get_form('implement_back_to_stock_button', $node->nid);
+
+  return $output;
+}
+
+/**
+ * Implements Hook_form()
+ * Handles adding of Properties & Synonyms to Stocks
+ */
+function tripal_feature_edit_ALL_properties_form($form_state, $node) {
+  $form = array();
+
+  $form['nid'] = array(
+    '#type' => 'hidden',
+    '#value' => $node->nid
+  );
+
+  $i=0;
+  if (is_array($node->properties) && is_array($node->synonyms)) { 
+  	$all_properties = array_merge($node->properties, $node->synonyms);
+  } elseif (is_array($node->properties)) { 
+  	$all_properties = $node->properties; 
+  } elseif (is_array($node->synonyms)) { 
+  	$all_properties = $node->synonyms;
+  } else { $all_properties = array(); }
+
+  if (sizeof($all_properties) != 0) {
+  foreach ($all_properties as $property) {
+    $i++;
+    $form["num-$i"] = array(
+      '#type' => 'item',
+      '#value' => $i.'.'
+    );
+
+    $form["id-$i"] = array(
+      '#type' => 'hidden',
+      '#value' => $property->stockprop_id
+    );
+
+    $prop_type_options = tripal_cv_get_cvterm_options( variable_get('chado_stock_prop_types_cv', 'null') );
+    ksort($prop_type_options);
+ 
+    $default = array_search($property->type, $prop_type_options);
+
+    $form["type-$i"] = array(
+      '#type' => 'select',
+      //'#title' => t('Type of Property'),
+      '#options' => $prop_type_options,
+      '#default_value' => $default 
+    );
+
+    $form["value-$i"] = array(
+      '#type' => 'textfield',
+      //'#title' => t('Value'),
+      '#default_value' => $property->value
+    );
+
+    if ($property->type == 'synonym') {
+      $form["preferred-$i"] = array(
+        '#type' => 'checkbox',
+        '#title' => t('Preferred Synonym'),
+      );
+    }
+
+    $form["submit-$i"] = array(
+      '#type' => 'submit',
+      '#value' => t("Delete #$i")
+    );
+
+  }} //end of foreach property
+
+  $form['num_properties'] = array(
+    '#type' => 'hidden',
+    '#value' => $i
+  );
+
+  $form["submit-edits"] = array(
+    '#type' => 'submit',
+    '#value' => t('Update Properties')
+  );
+
+  return $form;
+}
+
+function tripal_feature_edit_ALL_properties_form_submit($form, &$form_state) {
+
+  if ($form_state['clicked_button']['#value'] == t('Update Properties') ) {
+     //Update all
+     for ($i=1; $i<=$form_state['values']['num_properties']; $i++) {
+       tripal_feature_update_property($form_state['values']["id-$i"], $form_state['values']["type-$i"], $form_state['values']["value-$i"], $form_state['values']["preferred-$i"], $form_state['values']["nid"]);
+     }
+     drupal_set_message("Updated all Properties");
+     drupal_goto('node/'.$form_state['values']['nid']);
+  } elseif ( preg_match('/Delete #(\d+)/', $form_state['clicked_button']['#value'], $matches) ) {
+     $i = $matches[1];
+     tripal_feature_delete_property($form_state['values']["id-$i"], $form_state['values']["type-$i"], $form_state['values']["value-$i"]);
+     drupal_set_message("Deleted Property");
+  } else {
+    drupal_set_message("Unrecognized Button Pressed",'error');
+  }
+
+  
+}
+
+function tripal_feature_update_property($stockprop_id, $cvterm_id, $value, $preferred, $nid) {
+
+	$previous_db = tripal_db_set_active('chado');
+	$old_obj = db_fetch_object(db_query("SELECT * FROM stockprop WHERE stockprop_id=%d",$stockprop_id));
+	tripal_db_set_active($previous_db);
+	
+	// if they changed the type need to check rank
+	//   (if there is another property of the same type then rank needs to be increased to prevent collisions)
+	if ($cvterm_id == $old_obj->type_id) {
+	  $previous_db = tripal_db_set_active('chado');
+  	db_query(
+    	"UPDATE stockprop SET type_id=%d, value='%s' WHERE stockprop_id=%d",
+    	$cvterm_id, 
+    	$value,
+    	$stockprop_id
+  	);
+  	tripal_db_set_active($previous_db);
+  } else {
+      //determine the rank for this property
+    $max_rank = get_max_chado_rank('stockprop', 
+    															array('stock_id'=>array('type'=>'INT','value'=> $old_obj->stock_id), 
+    																		'type_id'=>array('type'=>'INT','value'=> $cvterm_id ) ));
+    if ($max_rank == -1) { $rank = 0; 
+    } else { $rank = $max_rank+1; }
+	  $previous_db = tripal_db_set_active('chado');
+  	db_query(
+    	"UPDATE stockprop SET type_id=%d, value='%s', rank=%d WHERE stockprop_id=%d",
+    	$cvterm_id, 
+    	$value,
+    	$rank,
+    	$stockprop_id
+  	);
+  	tripal_db_set_active($previous_db);  	
+  }
+
+  // Set Preferred Synonym
+  //use update node form so that both title and name get set                                                                                                                                                                       
+  if ($preferred) {
+    $node = node_load($nid);                                                                                                                                                                            
+    $node->title = $value;                                                                                                                                                                              
+    $node_form_state = array(                                                                                                                                                                                                        
+      'values' => array(                                                                                                                                                                                                             
+        'title' => $value,                                                                                                                                               
+        'op' => 'Save'                                                                                                                                                                                
+      )                                                                                                                                                                                                            
+    );                                                                                                                                                                                                                               
+    module_load_include('inc', 'node', 'node.pages');                                                                                                                                                                                
+    drupal_execute('chado_stock_node_form', $node_form_state, $node);  
+  }
+}
+
+function tripal_feature_delete_property($stockprop_id) {
+
+  $previous_db = tripal_db_set_active('chado');
+  db_query(
+    "DELETE FROM stockprop WHERE stockprop_id=%d",
+    $stockprop_id
+  );
+  tripal_db_set_active($previous_db);
+
+}
+
+function theme_tripal_feature_edit_ALL_properties_form ($form) {
+  $output = '';
+
+  $output .= '<br><fieldset>';
+  $output .= '<legend>Edit Already Existing Properties<span class="form-optional" title="This field is optional">(optional)</span></legend>';
+  $output .= '<p>Below is a list of already existing properties for this stock, one property per line. The type refers to the type of '
+  	     .'property and the value is the value for that property. For example, if this stock has a seed coat colour of green then '
+	     .'the property type=sead coat colour and the value=green. When the type of property is synonym, there is an extra checkbox '
+	     .'allowing you to specify which is the <b>Preferred Synonym</b>. This will change the current name of the stock.</p>';
+  $output .= '<table>';
+  $output .= '<tr><th>#</th><th>Type</th><th>Value</th><th></th></tr>';
+
+  for ($i=1; $i<=$form['num_properties']['#value']; $i++) {
+    $output .= '<tr><td>'.drupal_render($form["num-$i"]).'</td><td>'.drupal_render($form["type-$i"]).'</td><td>'.drupal_render($form["value-$i"]).drupal_render($form["preferred-$i"]).'</td><td>'.drupal_render($form["submit-$i"]).'</td></tr>';
+  }
+
+  $output .= '</table><br>';
+  $output .= drupal_render($form);
+  $output .= '</fieldset>';
+
+  return $output;
+}
+
+/*************************************************************************************************************
+ * @section
+ * Supplimentary functions
+ */
+
+/**
+ * 
+ */
+function list_properties_for_node($properties, $synonyms) {
+
+  if (!empty($properties) OR !empty($synonyms) ) {
+    $output = '<table>';
+    $output .= '<tr><th>Type</th><th>Value</th></tr>';
+
+    if (!empty($synonyms) ) {
+      foreach ($synonyms as $s) {
+        $output .= '<tr><td>synonym</td><td>'.$s.'</td></tr>';
+      }
+    }
+
+    if (!empty($properties) ) {
+      foreach ($properties as $p) {
+        $output .= '<tr><td>'.$p->type.'</td><td>'.$p->value.'</td></tr>';
+      } // end of foreach property
+    }
+
+    $output .= '</table>';
+
+  } else {
+    $output = 'No Properties Added to the Current Stock';
+  }
+
+  return $output;
+}

+ 489 - 0
tripal_feature/tripal_feature-relationships.inc

@@ -0,0 +1,489 @@
+<?php
+
+/*************************************************************************************************************
+ * @section
+ * Deals with Adding Relationships
+ */
+
+function tripal_feature_add_ALL_relationships_page($node) {
+  $output = '';
+
+  $output .= tripal_feature_implement_add_chado_properties_progress('relationships').'<br>';
+  $output .= '<b>All Relationships should include the CURRENT Individual ('.$node->uniquename.')</b><br>';
+  $output .= '<br><b>Current Relationships</b><br>';
+  $output .= list_relationships_for_node($node->uniquename, $node->subject_relationships, $node->object_relationships);
+  $output .= '<br><br>';
+  $output .= drupal_get_form('tripal_feature_add_ONE_relationship_form', $node);
+  $output .= '<br>';
+  $output .= drupal_get_form('tripal_feature_implement_add_chado_properties_navigate', 'relationships', $node->nid);
+  return $output;
+}
+/*************************************************************************
+ * Implements Hook_form()
+ * Handles adding of Relationships to Stocks
+ */
+function tripal_feature_add_ONE_relationship_form($form_state, $node) {
+
+  $stock_id = $node->stock_id;
+  $organism_id = $node->organism->organism_id;
+  $_SESSION['organism'] = $organism_id; //needed for autocomplete enter stock to work
+
+  $form['rel_nid'] = array(
+    '#type' => 'hidden', 
+    '#value' => $node->nid
+  ); 
+
+  $form['add_relationships'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Add Relationships') . '<span class="form-optional" title="This field is optional">(optional)</span>',
+  );
+
+  $form['add_relationships']['description'] = array(
+    '#type' => 'item',
+    '#value' => t('Relationships are specified as follows: (Subject) (Type of Relationship) (Object). For example, Fred is_the_paternal_parent_of Matty, where Fred & Matty are both stocks.')
+  );
+
+  $form['add_relationships']['subject_id'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Subject'),
+    '#description' => 'The Uniquename, Name, Database Reference or Synonym of a Stock can be used here',
+  );
+
+  $cv = tripal_cv_get_cv_by_name('relationship');
+  $type_options = tripal_cv_get_cvterm_options($cv->cv_id);
+  $type_options[0] = 'Select a Type';
+  ksort($type_options);
+  $form['add_relationships']['type_id'] = array(
+    '#type' => 'select',
+    '#title' => t('Type of Relationship'),
+    '#options' => $type_options
+
+  );
+
+  $form['add_relationships']['object_id'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Object'),
+    '#description' => 'The Uniquename, Name, Database Reference or Synonym of a Stock can be used here',
+  );
+
+  $form['add_relationships']['r_description'] = array(
+    '#type' => 'textarea',
+    '#title' => t('Notes on the relationship') . '<span class="form-optional" title="This field is optional">+</span>',
+    '#description' => t('Should not include Genotypes and Phenotypes'),
+  );
+
+  $form['add_relationships']['submit'] = array(
+    '#type' => 'submit',
+    '#value' => t('Add a Relationship')
+  );
+
+  $form['add_relationships']['r_stock_id'] = array(
+    '#type' => 'value',
+    '#value' => $stock_id,
+    '#required' => TRUE
+
+  );
+
+  $form['add_relationships']['r_stock_uniquename'] = array( 
+    '#type' => 'value',
+    '#value' => $node->uniquename,
+    '#required' => TRUE
+  );
+
+  return $form;
+
+}
+/*************************************************************************
+*
+*/
+function tripal_feature_add_ONE_relationship_form_validate($form, &$form_state) {
+
+  //Require Validation if adding
+  if ($form_state['clicked_button']['#value'] == t('Add a Relationship') ) {
+    // check valid stock selected for subject
+    $criteria = array('unknown' => array('value'=> $form_state['values']['subject_id'], 
+      																		'columns'=>array('name','uniquename','accession','synonym') ));
+    $subject_results = get_chado_stocks($criteria,'ANY',$_SESSION['organism']);
+    if (sizeof($subject_results) > 1) {
+      $links= array();
+      for ($i=0; $i<sizeof($subject_results); $i++) { $links[] = l($i+1, "node/".$subject_results[$i]->nid); }
+      $message = "Too many stocks match '".$form_state['values']['subject_id']."'! "
+      	       	 . " Please refine your input to match ONLY ONE stock. <br>"
+		 . "To aid in this process, here are the stocks that match your initial input: "
+		 .join(', ',$links);
+      form_set_error('subject_id', $message);
+    } elseif (sizeof($subject_results) < 1) {
+      form_set_error('subject_id', "There are no stocks matching your input. Please check your input for typos and/or lookup the stock ".l('here', 'stocks'));
+    } elseif (sizeof($subject_results) == 1) {
+      $form_state['values']['subject_id'] = $subject_results[0]->stock_id;
+    }
+
+    // check valid stock selected for object
+    $criteria = array('unknown' => array('value'=> $form_state['values']['object_id'], 
+      																		'columns'=>array('name','uniquename','accession','synonym') ));
+    $object_results = get_chado_stocks($criteria,'ANY',$_SESSION['organism']);
+    if (sizeof($object_results) > 1) {
+      $links= array();
+      for ($i=0; $i<sizeof($object_results); $i++) { $links[] = l($i+1, "node/".$object_results[$i]->nid); } 
+      $message = "Too many stocks match '".$form_state['values']['object_id']."'! "
+                 . "Please refine your input to match ONLY ONE stock. <br>"
+                 . "To aid in this process, here are the stocks that match your initial input: "
+                 .join(', ',$links);
+      form_set_error('object_id', $message);
+    } elseif (sizeof($object_results) < 1) {
+      form_set_error('object_id', "There are no stocks matching your input. Please check your input for typos and/or lookup the stock ".l('here', 'stocks'));                                                                         
+    } elseif (sizeof($object_results) == 1) {
+      $form_state['values']['object_id'] = $object_results[0]->stock_id;
+    }
+
+    // check valid type selected
+    if ($form_state['values']['type_id'] == 0) {
+      form_set_error('type_id', 'Please select a type of relationship.');
+    } else {
+    	$previous_db = tripal_db_set_active('chado');
+    	$tmp_obj = db_fetch_object(db_query("SELECT count(*) as count FROM cvterm WHERE cvterm_id=%d",$form_state['values']['type_id']));
+    	tripal_db_set_active($previous_db);
+    	
+      if ($tmp_obj->count != 1) {
+        form_set_error('type_id', 'The type you selected is not valid. Please choose another one.');
+      }
+    }
+
+    // check either subject or object is the current stock
+    if ( $subject_results[0]->nid != $form_state['values']['rel_nid'] ) {
+      if ( $object_results[0]->nid != $form_state['values']['rel_nid'] ) {
+        form_set_error('subject_id', 'Either Subject or Object must be the current stock ('.$form_state['values']['r_stock_uniquename'].').');
+      }
+    }
+  } //end of require validation if adding relationship
+}
+/*************************************************************************
+*
+*/
+function tripal_feature_add_ONE_relationship_form_submit($form, &$form_state) {
+
+  if ($form_state['values']['subject_id'] > 0) {
+    $previous_db = db_set_active('chado');
+    db_query(
+      "INSERT INTO stock_relationship (subject_id, type_id, object_id, value) VALUES (%d, %d, %d, '%s')",
+      $form_state['values']['subject_id'],
+      $form_state['values']['type_id'],
+      $form_state['values']['object_id'],
+      $form_state['values']['r_description']
+    );
+    db_set_active($previous_db);
+
+    drupal_set_message('Successfully Added Relationship.');
+  } //end of insert relationship
+
+}
+
+/************************************************************************************************************* 
+ * @section                                           
+ * Deals with Editing and Deleting Properties         
+ */
+
+function tripal_feature_edit_ALL_relationships_page($node) {
+  $output = '';
+	
+  $output .= drupal_get_form('tripal_feature_edit_ALL_relationships_form', $node);
+  $output .= '<br>';
+  $output .= drupal_get_form('tripal_feature_add_ONE_relationship_form', $node);
+  $output .= '<br>';
+  $output .= drupal_get_form('tripal_feature_implement_back_to_stock_button', $node->nid);
+
+  return $output;
+}
+                                                      
+/*************************************************************************                                                 
+ * Implements Hook_form()                             
+ * Handles adding of Properties & Synonyms to Stocks  
+ */                                                   
+function tripal_feature_edit_ALL_relationships_form($form_state, $node) {
+  $form = array();
+
+  $form['nid'] = array(
+    '#type' => 'hidden',
+    '#value' => $node->nid
+  );
+  
+  $form['r_feature_uniquename'] = array(
+    '#type' => 'hidden',
+    '#value' => $node->uniquename
+  );
+
+  $i=0;
+  $relationships = array();
+  if(is_array($node->object_relationships)){    
+     $relationships = array_merge($relationships,$node->object_relationships);
+  }
+  if(is_array($node->subject_relationships)){    
+     $relationships = array_merge($relationships,$node->subject_relationships);
+  }
+  if (sizeof($relationships) != 0) {
+  foreach ($relationships as $r) {
+
+    $i++;
+    $form["num-$i"] = array(
+      '#type' => 'item',
+      '#value' => $i.'.'
+    );
+
+    $form["id-$i"] = array(
+      '#type' => 'hidden',
+      '#value' => $r->stock_relationship_id
+    );
+
+    //Enter relationship specific fields
+    if ( !empty($r->subject_id) ) { 
+      $default = $r->subject_uniquename;
+      $description = l($r->subject_name, 'node/'.$r->subject_nid); 
+    } else { 
+       $default = $node->uniquename; $description = 'Current Feature'; 
+    }
+    $form["subject_id-$i"] = array(
+      '#type' => 'textfield',      
+      //'#title' => t('Subject'), 
+      '#required'   => TRUE,
+      '#size' => 30,
+      '#default_value' => $default,
+      '#description' => $description,
+    ); 
+
+    $type_options = tripal_cv_get_cvterm_options( variable_get('chado_feature_relationship_cv', 'null') );
+    ksort($type_options);          
+    $form["type_id-$i"] = array(  
+      '#type' => 'select',    
+      //'#title' => t('Type of Relationship'), 
+      '#options' => $type_options,
+      '#required' => TRUE,
+      '#default_value' => $r->relationship_type_id
+    );
+
+    if ( !empty($r->object_id) ) { 
+      $default = $r->object_uniquename;
+      $description = l($r->object_name, 'node/'.$r->object_nid);
+    } else { $default = $node->uniquename; $description = 'Current Feature'; }
+    $form["object_id-$i"] = array(
+      '#type' => 'textfield',          
+      //'#title' => t('Object'),      
+      '#required'   => TRUE,
+      '#size' => 30,
+      '#default_value' => $default,
+      '#description' => $description
+    );
+
+    $form["submit-$i"] = array(
+      '#type' => 'submit',
+      '#value' => t("Delete #$i")
+    );
+
+  }} //end of foreach relationship
+
+  $form['num_relationships'] = array(
+    '#type' => 'hidden',
+    '#value' => $i
+  );
+
+  $form["submit-edits"] = array(
+    '#type' => 'submit',
+    '#value' => t('Update Relationships')
+  );
+
+  return $form;
+}
+/*************************************************************************
+*
+*/
+function tripal_feature_edit_ALL_relationships_form_validate($form, &$form_state) {
+
+  // Only Require if Updating Relationships
+  if ($form_state['clicked_button']['#value'] == t('Update Relationships') ) {
+
+    for ($i=1; $i<=$form_state['values']['num_relationships']; $i++) {
+      
+      // check valid stock selected for subject
+      $criteria = array('unknown' => array('value'=>$form_state['values']["subject_id-$i"], 
+      																		'columns'=>array('name','uniquename','accession','synonym') ));
+      $subject_results = get_chado_stocks($criteria,'ANY',$_SESSION['organism']);
+      if (sizeof($subject_results) > 1) {
+        $links= array();
+        for ($j=0; $j<sizeof($subject_results); $j++) { $links[] = l($j+1, "node/".$subject_results[$j]->nid); }
+        $message = "Too many stocks match '".$form_state['values']["subject_id-$i"]."'! "
+                 . "Please refine your input to match ONLY ONE stock. <br>" 
+                 . "To aid in this process, here are the stocks that match your initial input: "
+                 .join(', ',$links);
+        form_set_error("subject_id-$i", $message);
+      } elseif (sizeof($subject_results) < 1) { 
+        form_set_error("subject_id-$i", "There are no stocks matching your input. Please check your input for typos and/or lookup the stock ".l('here', 'stocks'));
+      } elseif (sizeof($subject_results) == 1) {
+        $form_state['values']["subject_id-$i"] = $subject_results[0]->stock_id;
+      } 
+
+      // check valid stock selected for object
+      $criteria = array('unknown' => array('value'=> $form_state['values']["object_id-$i"], 
+      																		'columns'=>array('name','uniquename','accession','synonym') ));
+      $object_results = get_chado_stocks($criteria,'ANY',$_SESSION['organism']);
+      if (sizeof($object_results) > 1) {
+        $links= array();
+        for ($j=0; $j<sizeof($object_results); $j++) { $links[] = l($j+1, "node/".$object_results[$j]->nid); }
+        $message = "Too many stocks match '".$form_state['values']["object_id-$i"]."'! "
+                 . "Please refine your input to match ONLY ONE stock. <br>" 
+                 . "To aid in this process, here are the stocks that match your initial input: "
+                 .join(', ',$links);
+        form_set_error("object_id-$i", $message);
+      } elseif (sizeof($object_results) < 1) {
+        form_set_error("object_id-$i", "There are no stocks matching your input. Please check your input for typos and/or lookup the stock ".l('here', 'stocks'));
+      } elseif (sizeof($object_results) == 1) {
+        $form_state['values']["object_id-$i"] = $object_results[0]->stock_id;
+      } 
+
+      // check valid type selected
+      if ($form_state['values']["type_id-$i"] == 0) {
+        form_set_error('type_id', 'Please select a type of relationship.');
+      } else {
+    		$previous_db = tripal_db_set_active('chado');
+    		$tmp_obj = db_fetch_object(db_query("SELECT count(*) as count FROM cvterm WHERE cvterm_id=%d",$form_state['values']["type_id-$i"]));
+    		tripal_db_set_active($previous_db);
+    	
+      	if ($tmp_obj->count != 1) {
+          form_set_error("type_id-$i", 'The type you selected is not valid. Please choose another one.');
+        }
+      }
+
+      // check either subject or object is the current stock
+      if ( $subject_results[0]->nid != $form_state['values']['nid'] ) {
+        if ( $object_results[0]->nid != $form_state['values']['nid'] ) {
+          form_set_error("subject_id-$i", 'Either Subject or Object must be the current stock ('.$form_state['values']['r_stock_uniquename'].').');
+        }
+      }
+
+    } // end of for each relationship
+  } //end of if updating relationships
+
+}
+/*************************************************************************
+*
+*/
+function tripal_feature_edit_ALL_relationships_form_submit($form, &$form_state) {
+
+  if ($form_state['clicked_button']['#value'] == t('Update Relationships') ) {
+     //Update all
+     for ($i=1; $i<=$form_state['values']['num_relationships']; $i++) {
+
+       //process stock textfields
+       tripal_feature_update_relationship(
+				$form_state['values']["id-$i"], 
+				$form_state['values']["subject_id-$i"],
+				$form_state['values']["type_id-$i"], 
+				$form_state['values']["object_id-$i"]
+			);
+     }
+     drupal_set_message("Updated all Relationships");
+     drupal_goto('node/'.$form_state['values']['nid']);
+
+  } elseif ( preg_match('/Delete #(\d+)/', $form_state['clicked_button']['#value'], $matches) ) {
+
+     $i = $matches[1];
+     tripal_feature_delete_relationship($form_state['values']["id-$i"]);
+     drupal_set_message("Deleted Relationship");
+
+  } elseif ($form_state['clicked_button']['#value'] == t('Back to Stock') ) {
+    drupal_goto('node/'.$form_state['values']['nid']);
+  } else {
+    drupal_set_message("Unrecognized Button Pressed",'error');
+  }
+
+}
+/*************************************************************************
+*
+*/
+function tripal_feature_update_relationship ($stock_relationship_id, $subject_id, $cvterm_id, $object_id) {
+
+  $previous_db = db_set_active('chado');
+  db_query(
+    "UPDATE stock_relationship SET subject_id=%d, type_id=%d, object_id=%d WHERE stock_relationship_id=%d",
+    $subject_id,
+    $cvterm_id, 
+    $object_id,
+    $stock_relationship_id
+  );
+  db_set_active($previous_db);
+
+}
+/*************************************************************************
+*
+*/
+function tripal_feature_delete_relationship ($stock_relationship_id) {
+
+  $previous_db = db_set_active('chado');
+  db_query(
+    "DELETE FROM stock_relationship WHERE stock_relationship_id=%d",
+    $stock_relationship_id
+  );
+  db_set_active($previous_db);
+
+}
+/*************************************************************************
+*
+*/
+function theme_tripal_feature_edit_ALL_relationships_form ($form) {
+  $output = '';
+  
+  $output .= '<br><fieldset>';
+  $output .= '<legend>Edit Already Existing Relationships<span class="form-optional" title="This field is optional">(optional)</span></legend>';
+  $output .= '<p>Each relationship for this stock is listed below, one per line. The textboxes indicating '
+  	    .'the subject and object of the relationship can contain the uniquename, name, database '
+	    .'reference or synonym of a stock of the same organism.</p>';
+  $output .= '<table>';
+  $output .= '<tr><th>#</th><th>Subject</th><th>Type</th><th>Object</th><th></th></tr>';
+
+  for ($i=1; $i<=$form['num_relationships']['#value']; $i++) {
+    $output .= '<tr><td>'.drupal_render($form["num-$i"]).'</td><td>'
+    	       .drupal_render($form["subject_id-$i"]).'</td><td>'
+	       .drupal_render($form["type_id-$i"]).'</td><td>'
+	       .drupal_render($form["object_id-$i"]).'</td><td>'
+	       .drupal_render($form["submit-$i"]).'</td></tr>';
+  }
+
+  $output .= '</table><br>';
+  $output .= drupal_render($form);
+  $output .= '</fieldset>';
+
+  return $output;
+}
+
+/*************************************************************************************************************
+ * @section
+ * Supplementary Functions
+ */
+
+/**
+ *
+ */
+function list_relationships_for_node($stock_name, $subject_relationships, $object_relationships) {
+
+  if (!empty($subject_relationships) OR !empty($object_relationships) ) {
+    $output = '<table>';
+    $output .= '<tr><th>Subject</th><th>Relationship Type</th><th>Object</th></tr>';
+
+    if (!empty($subject_relationships) ) {
+      foreach ($subject_relationships as $s) {
+        $output .= '<tr><td>'.$s->subject_name.'</td><td>'.$s->relationship_type.'</td><td>'.$stock_name.'</td></tr>';
+      }
+    }
+
+    if (!empty($object_relationships) ) {
+      foreach ($object_relationships as $o) {
+        $output .= '<tr><td>'.$stock_name.'</td><td>'.$o->relationship_type.'</td><td>'.$o->object_name.'</td></tr>';
+      } // end of foreach property
+    }
+
+    $output .= '</table>';
+  } else {
+    $output = 'No Relationships Involving the Current Stock'; 
+  }
+
+  return $output;
+
+}

+ 190 - 0
tripal_feature/tripal_feature-secondary_tables.inc

@@ -0,0 +1,190 @@
+<?php
+// $Id$
+
+function tripal_feature_implement_back_to_stock_button($form_state, $nid) {
+  $form = array();
+
+  $form['nid'] = array(
+    '#type' => 'hidden',
+    '#value' => $nid
+  );
+
+  $form["submit-back"] = array( 
+    '#type' => 'submit',
+    '#value' => t('Back to Stock') 
+  );
+
+  return $form;
+}
+
+function tripal_feature_implement_back_to_stock_button_submit($form, $form_state) {
+  drupal_goto('node/'.$form_state['values']['nid']);
+}
+
+function tripal_feature_implement_add_chado_properties_progress($current) {
+
+    $value = '<div class="form_progress"><div class="form_progress-text">'; 
+
+    if ($current == 'main') { $value .= '<span id="form-step-current">Create Basic Stock</span>'; } 
+    else { $value .= '<span id="form-step">Create Basic Stock</span>'; }
+
+    $value .= '<span id="form-segway">  >>  </span>';
+
+    if ($current == 'properties') { $value .= '<span id="form-step-current">Add Synonyms & Properties</span>'; }
+    else { $value .= '<span id="form-step">Add Synonyms & Properties</span>'; }
+
+    $value .= '<span id="form-segway">  >>  </span>';                       
+
+    if ($current == 'db_references') { $value .= '<span id="form-step-current">Add Database References</span>'; }
+    else { $value .= '<span id="form-step">Add Database References</span>'; }
+
+    $value .= '<span id="form-segway">  >>  </span>';         
+
+    if ($current == 'relationships') { $value .= '<span id="form-step-current">Add Relationships</span>'; }
+    else { $value .= '<span id="form-step">Add Relationships</span>'; }
+
+    $value .= '</div></div>';
+
+    return $value;
+
+}
+
+function tripal_feature_implement_add_chado_properties_navigate($form_state, $step, $nid) {
+  $form = array();
+
+  $form['current_step'] = array(
+    '#type' => 'hidden',
+    '#value' => $step
+  );
+
+  // Use this field to set all the steps and the path to each form
+  // where each step is of the form name;path and each step is separated by ::
+  $steps =array(
+    'properties' => 'node/%node/properties',
+    'db_references' => 'node/%node/db_references',
+    'relationships' => 'node/%node/relationships'
+  );
+  $steps_value = array();
+  foreach ($steps as $k => $v) { $steps_value[] = $k.';'.$v; }
+  $form['steps'] = array(
+    '#type' => 'hidden',
+    '#value' => implode('::', $steps_value)
+  );
+
+  $form['first_step'] = array(
+    '#type' => 'hidden',
+    '#value' => 'properties'
+  );
+
+  $form['last_step'] = array(
+    '#type' => 'hidden',
+    '#value' => 'relationships'
+  );
+
+  $form['nid'] = array(
+    '#type' => 'hidden',
+    '#value' => $nid
+  );
+
+  if ($step != $form['first_step']['#value']) {
+    $form['submit-prev'] = array(
+      '#type' => 'submit',
+      '#value' => t('Previous Step')
+    );
+  }
+
+  if ($step != $form['last_step']['#value']) {
+    $form['submit-next'] = array( 
+      '#type' => 'submit',
+      '#value' => t('Next Step')
+    );
+  }
+
+  if ($step == $form['last_step']['#value']) {
+    $form['submit-finish'] = array(
+      '#type' => 'submit', 
+      '#value' => t('Finish')
+    );
+  }
+
+  return $form;
+}
+
+function tripal_feature_implement_add_chado_properties_navigate_submit($form, $form_state) {
+
+  $raw_steps = preg_split('/::/', $form_state['values']['steps']); 
+
+  $steps = array();
+  $current_index = 'EMPTY';
+  $i=0;
+
+  foreach ($raw_steps as $raw_step) {
+    $step = preg_split('/;/', $raw_step);
+    $steps[$i] = $step;
+    
+    if ($step[0] == $form_state['values']['current_step']) {
+      $current_index = $i;
+    }
+
+    $i++;
+  }
+  $num_steps = $i;
+  
+  if (strcmp($current_index,'EMPTY') == 0) {
+    // No Matching Step
+    drupal_set_message('Could not determine next step -'.$form_state['values']['current_step'].', please contact the administrator', 'error');
+  } elseif ($current_index == 0) {
+    $next_goto = $steps[$current_index+1][1];
+  } elseif ($current_index == ($num_steps-1)) {
+    $prev_goto = $steps[$current_index-1][1];
+    $next_goto = 'node/%node';
+  } else {
+    $prev_goto = $steps[$current_index-1][1];
+    $next_goto = $steps[$current_index+1][1];
+  }
+
+  if ($form_state['clicked_button']['#value'] == t('Previous Step') ) {
+    //replace %node
+    $prev_goto = preg_replace('/%node/', $form_state['values']['nid'], $prev_goto);
+    $_REQUEST['destination'] = $prev_goto;
+  } elseif ($form_state['clicked_button']['#value'] == t('Next Step') ) {
+    $next_goto = preg_replace('/%node/', $form_state['values']['nid'], $next_goto);
+    $_REQUEST['destination'] = $next_goto;
+  } elseif ($form_state['clicked_button']['#value'] == t('Finish') ) {
+    $next_goto = preg_replace('/%node/', $form_state['values']['nid'], $next_goto);
+    $_REQUEST['destination'] = $next_goto;
+  }
+
+}
+
+/*************************************************************************************************************
+ * Implements Hook_form()
+ * Handles setting the is_obsolete property of stocks
+ */
+function tripal_stock_is_obsolete_form($node, $stock_id) {
+
+  $form['make_obsolete'] = array(
+    '#type' => 'submit',
+    '#value' => t('Mark Stock as Obsolete')
+  );
+
+  $form['make_obsolete_stock_id'] = array(
+    '#type' => 'value',
+    '#value' => $stock_id,
+    '#required' => TRUE
+  );
+
+  return $form;
+}
+
+function tripal_stock_is_obsolete_form_submit($form, &$form_state) {
+
+  $previous_db = db_set_active('chado');
+  db_query(
+    "UPDATE stock SET is_obsolete='t' WHERE stock_id=%d",
+    $form_state['values']['make_obsolete_stock_id']
+  );
+  db_set_active($previous_db);
+
+}
+

+ 3 - 0
tripal_feature/tripal_feature.api.inc

@@ -0,0 +1,3 @@
+<?php
+
+

+ 52 - 0
tripal_organism/tripal_organism.api.inc

@@ -0,0 +1,52 @@
+<?php
+
+/*************************************************************************
+ * Purpose: Create an options array to be used in a form element
+ *   which provides a list of all chado organisms
+ *
+ * @return an array(organism_id => common_name) 
+ *   for each organism in the chado organism table
+ */
+function tripal_organism_get_organism_options() {
+
+  $previous_db = tripal_db_set_active('chado');
+  $result = db_query(
+    "SELECT organism_id, common_name FROM organism"
+  );
+  tripal_db_set_active($previous_db);
+
+  $options = array();
+  while ( $r = db_fetch_object($result) ) {
+    $options[$r->organism_id] = $r->common_name;
+  }
+
+  return $options;
+
+}
+
+/*************************************************************************
+ * Purpose: Return a given organism object using the nid or organism id
+ *
+ * @return organism object created by node load
+ */
+function tripal_organism_get_organism($nid=0, $organism_id=0) {
+
+	if (!empty($nid)) {
+		return node_load($nid);
+	} else {
+		if (!empty($organism_id)) {
+			$sql = "SELECT nid FROM {chado_organism} WHERE organism_id=%d";
+			$r = db_fetch_object(db_query($sql, $organism_id));
+			if (!empty($r->nid)) {
+				return node_load($r->nid);
+			} else {
+				drupal_set_message("Function: tripal_organism_get_organism() -no organism with that organism id sync'd with drupal", 'error');
+			}
+		} else {
+			drupal_set_message("Function: tripal_organism_get_organism() -need to supply at least one of node ID or Organism ID",'error');
+		}
+	}
+
+	return 0;
+	
+}