'example_relationship', // the name of the table linking additional dbxrefs to this node
'base_table' => 'example', // the name of the chado table this node links to
'base_foreign_key' => 'example_id', // key to link to the chado content created by this node
'base_key_value' => $example_id, // the value of the above key
'fieldset_title' => 'Relationships', // the non-translated title for this fieldset
'additional_instructions' => '' // a non-stranslated string providing additional instructions
);
// Finally, and add the additional form elements to the form
chado_add_node_form_relationships($form, $form_state, $details);
return $form;
}
function chado_example_insert($node) {
// if there is an example_id in the $node object then this must be a sync so
// we can skip adding the chado_example as it is already there, although
// we do need to proceed with the rest of the insert
if (!property_exists($node, 'example_id')) {
// Add record to chado example table
// Add to any other tables needed
// Add all relationships
// Existing _relationship links with the current example as either the subject_id
// or object_id will be cleared and then re-added
chado_update_node_form_relationships(
$node,
'example_relationship',
$node->example_id
);
}
// Add record to chado_example linking example_id to new node
}
function chado_example_update($node) {
// Update record in chado example table
// Update any other tables needed
// Update all additional database references
// Existing _relationship links with the current example as either the subject_id
// or object_id will be cleared and then re-added
chado_update_node_form_relationships(
$node,
'example_relationship',
$node->example_id
);
// Don't need to update chado_example linking table since niether example_id or nid can be changed in update
}
* @endcode
*
* @ingroup tripal_chado_node_api
*/
/**
* Provides a form for adding to BASE_relationship and relationship tables
*
* @param $form
* The Drupal form array into which the relationship elements will be added
* @param $form_state
* The corresponding form_state array for the form
* @param $details
* An array defining details needed by this form. Required Keys are:
* - relationship_table: the name of the relationship table (ie: feature_relationship)
* - base_table: the name of the base table (ie: feature)
* - base_foreign_key: the name of the foreign key in the relationship table field linking this table to the non-relationship table (ie: feature_id)
* - base_key_value: the value of the base_foreign_key for the current form (ie: 999 if the feature_id=999)
* - nodetype: the non-translated singular title of this node type
* One of the following:
* - cv_id: the id of the ontology to supply terms for the type dropdown
* - cv_name: the name of the ontology to supply terms for the type dropdown
* Optional keys include:
* - fieldset_title: the non-translated title for this fieldset
* - additional_instructions: a non-translated string providing additional instructions
* - nodetype_plural: the non-translated plural title of this node type
* - select_options: must be an array where the [key] is a valid cvterm_id and
* the [value] is the human-readable name of the option. This is generated from the cv_name/id by default
* - base_name_field: the field in your base table you want to be used as the name of the record
* - subject_field_name: the name of the subject field in your relationship table (default: subject_id)
* - object_field_name: the name of the object field in your relationship table (default: object_id)
*
* @ingroup tripal_chado_node_api
*/
function chado_add_node_form_relationships(&$form, &$form_state, $details) {
// make sure the property table exists before proceeding.
if (!chado_table_exists($details['relationship_table'])) {
drupal_set_message("Cannot add relationship elements to the form. The relationship table, '" .
$details['relationship_table'] . "', does not exists", "error");
tripal_report_error('tcprops_form', TRIPAL_ERROR, "Cannot add relationship elements to the form.
The relationship table, '%name', cannot be found.", array('%name' => $details['relationship_table']));
return;
}
// make sure the specified cv exists
if (isset($details['cv_name'])) {
// make sure the cv_name is real
$result = chado_select_record('cv',array('cv_id'),array('name' => $details['cv_name']));
if (count($result) == 0) {
drupal_set_message("Cannot add relationship elements to the form. The CV name, '" .
$details['cv_name'] . "', does not exists", "error");
tripal_report_error('tcprops_form', TRIPAL_ERROR, "Cannot add relationship elements to the form.
The CV named, '%name', cannot be found.", array('%name' => $details['cv_name']));
return;
}
// add the cv_id option to the details array
$details['cv_id'] = $result[0]->cv_id;
}
elseif (isset($details['cv_id'])) {
// make sure the cv_id is real
$result = chado_select_record('cv', array('name'), array('cv_id' => $details['cv_id']));
if (count($result) == 0) {
drupal_set_message("Cannot add relationship elements to the form. The CV ID, '" .
$details['cv_id'] . "', does not exist", "error");
tripal_report_error('tcprops_form', TRIPAL_ERROR, "Cannot add relationship elements
to the form. The CV ID, '%id', cannot be found.", array('%id' => $details['cv_id']));
return;
}
// add the cv_name option to the details array
$details['cv_name'] = $result[0]->name;
}
else {
drupal_set_message("Please provide either a 'cv_name' or 'cv_id' as an
option for adding relationship to the form", "error");
tripal_report_error('tcprops_form', TRIPAL_ERROR, "Please provide either a
'cv_name' or 'cv_id' as an option for adding relationship to the form", array());
return;
}
$form_state['rebuild'] = TRUE;
// Set Defaults for optional fields
$details['fieldset_title'] = (isset($details['fieldset_title'])) ? $details['fieldset_title'] : 'Relationships';
$details['additional_instructions'] = (isset($details['additional_instructions'])) ? $details['additional_instructions'] : '';
$details['nodetype_plural'] = (isset($details['nodetype_plural'])) ? $details['nodetype_plural'] : $details['nodetype'] . 's';
$details['base_name_field'] = (isset($details['base_name_field'])) ? $details['base_name_field'] : 'uniquename';
$details['subject_field_name'] = (isset($details['subject_field_name'])) ? $details['subject_field_name'] : 'subject_id';
$details['object_field_name'] = (isset($details['object_field_name'])) ? $details['object_field_name'] : 'object_id';
// Some relationship tables don't have a rank
// thus we need to first check this table has a rank before trying to set it
$table_schema = chado_get_schema($details['relationship_table']);
$details['table_has_rank'] = (isset($table_schema['fields']['rank'])) ? TRUE : FALSE;
// Get Property Types for the Select List
if (isset($details['select_options'])) {
$type_options = $details['select_options'];
}
else {
if (isset($details['cv_name'])) {
$type_options = array();
$type_options[] = 'Select a Property';
$sql = "
SELECT DISTINCT CVT.cvterm_id, CVT.name, CVT.definition, CV.cv_id as cv_id
FROM {cvterm} CVT
INNER JOIN {cv} CV ON CVT.cv_id = CV.cv_id
WHERE
CV.name = :cv_name AND
NOT CVT.is_obsolete = 1
ORDER BY CVT.name ASC
";
$prop_types = chado_query($sql, array(':cv_name' => $details['cv_name']));
while ($prop = $prop_types->fetchObject()) {
$type_options[$prop->cvterm_id] = $prop->name;
$details['cv_id'] = $prop->cv_id;
}
}
elseif (isset($details['cv_id'])) {
$type_options = array();
$type_options[] = 'Select a Property';
$sql = "
SELECT DISTINCT CVT.cvterm_id, CVT.name, CVT.definition, CV.name AS cv_name
FROM {cvterm} CVT
INNER JOIN {cv} CV ON CVT.cv_id = CV.cv_id
WHERE
CV.cv_id = :cv_id AND
NOT CVT.is_obsolete = 1
ORDER BY CVT.name ASC
";
$prop_types = chado_query($sql, array(':cv_id' => $details['cv_id']));
while ($prop = $prop_types->fetchObject()) {
$type_options[$prop->cvterm_id] = $prop->name;
$details['cv_name'] = $prop->cv_name;
}
}
}
// Tell tripal administrators how to add terms to the property types drop down.
if (empty($type_options)) {
$tripal_message = tripal_set_message(
t('There are currently no property types! To add additional properties to the drop
down list, you need to add a controlled vocabulary term
to the %cv_name controlled vocabulary.',
array(
'%cv_name' => $details['cv_name'],
'@cvtermlink' => url('admin/tripal/chado/tripal_cv/cv/'.$details['cv_id'].'/cvterm/add')
)
),
TRIPAL_WARNING,
array('return_html' => TRUE)
);
}
else {
$tripal_message = tripal_set_message(
t('To add additional properties to the drop down list, you need to add
a controlled vocabulary term to the %cv_name controlled vocabulary.',
array(
'%cv_name' => $details['cv_name'],
'@cvtermlink' => url('admin/tripal/chado/tripal_cv/cv/' . $details['cv_id'] . '/cvterm/add')
)
),
TRIPAL_INFO,
array('return_html' => TRUE)
);
}
$form['relationships'] = array(
'#type' => 'fieldset',
'#title' => t($details['fieldset_title']),
'#description' => t('You may add relationships between this %nodetype and other
%nodetype_plural by entering the details below. You may add
as many relationships as desired by clicking the add button on the right. To
remove a relationship, click the remove button. ' . $details['additional_instructions'],
array('%nodetype' => $details['nodetype'], '%nodetype_plural' => $details['nodetype_plural'])),
'#prefix' => "
",
'#suffix' => '
',
'#weight' => 10
);
$form['relationships']['admin_message'] = array(
'#type' => 'markup',
'#markup' => $tripal_message
);
// this form element is a tree, so that we don't puke all of the values into then node variable
// it is set as a tree, and keeps them in the $form_state['values']['relationship_table'] heading.
$form['relationships']['relationship_table'] = array(
'#type' => 'markup',
'#tree' => TRUE,
'#prefix' => '',
'#suffix' => '
',
'#theme' => 'chado_node_relationships_form_table'
);
// Add defaults into form_state to be used elsewhere
$form['relationships']['relationship_table']['details'] = array(
'#type' => 'hidden',
'#value' => serialize($details)
);
// Add relationships already attached to the node
//---------------------------------------------
/* Relationships can come to us in two ways:
*
* 1) In the form state in the $form_state['chado_relationships']. Data is in this field
* when an AJAX call updates the form state or a validation error.
*
* 2) Directly from the database if the record already has _relationships associated. This
* data is only used the first time the form is loaded. On AJAX calls or validation
* errors the fields on the form are populated from the $form_state['chado_relationships']
* entry.
*/
if (isset($form_state['chado_relationships'])) {
$existing_rels = $form_state['chado_relationships'];
}
else {
$existing_rels = chado_query(
"SELECT
rel.*,
rel.".$details['subject_field_name']." as subject_id,
rel.".$details['object_field_name']." as object_id,
base1.".$details['base_name_field']." as object_name,
base2.".$details['base_name_field']." as subject_name,
cvterm.name as type_name
FROM {".$details['relationship_table']."} rel
LEFT JOIN {".$details['base_table']."} base1 ON base1.".$details['base_foreign_key']." = rel.".$details['object_field_name']."
LEFT JOIN {".$details['base_table']."} base2 ON base2.".$details['base_foreign_key']." = rel.".$details['subject_field_name']."
LEFT JOIN {cvterm} cvterm ON cvterm.cvterm_id = rel.type_id
WHERE rel.".$details['object_field_name']." = :base_key_value
OR rel.".$details['subject_field_name']." = :base_key_value",
array(':base_key_value' => $details['base_key_value'])
);
}
/* The format of the $existing_rels' array is either:
*
* From the chado_relationships array:
* $form_state['chado_relationships'] = array(
* '[type_id]-[rank]' => array(
* 'object_id' => [the _relationship.object_id value],
* 'object_name' => [the base_table.uniquename value linked on base_foreign_key=object_id],
* 'subject_id' => [the _relationship.subject_id value],
* 'subject_name' => [the base_table.uniquename value linked on base_foreign_key=subject_id],
* 'type_id' => [the _relationship.type_id value],
* 'type_name' => [the cvterm.name value linked on type_id],
* 'rank' => [the _relationship.rank value],
* ),
* );
*
* OR
* Populated from the database:
* $existing_rels = array(
* 0 => array(
* 'relationship_id' => [the _relationship.relationship_id value],
* 'object_id' => [the _relationship.object_id value],
* 'object_name' => [the base_table.uniquename value linked on base_foreign_key=object_id],
* 'subject_id' => [the _relationship.subject_id value],
* 'subject_name' => [the base_table.uniquename value linked on base_foreign_key=subject_id],
* 'type_id' => [the _relationship.type_id value],
* 'type_name' => [the cvterm.name value linked on type_id],
* 'rank' => [the _relationship.rank value],
* ),
* );
*
* NOTE: The main difference is the key
*
* Loop on the array elements of the $existing_rels array and add
* an element to the form for each one.
*/
foreach ($existing_rels as $relationship) {
if (array_key_exists($relationship->type_id, $type_options)) {
$rank = (isset($relationship->rank)) ? $relationship->rank : 0;
$form['relationships']['relationship_table'][$relationship->type_id]['#type'] = 'markup';
$form['relationships']['relationship_table'][$relationship->type_id]['#type'] = '';
$form['relationships']['relationship_table'][$relationship->type_id][$rank]['#type'] = 'markup';
$form['relationships']['relationship_table'][$relationship->type_id][$rank]['#value'] = '';
$form['relationships']['relationship_table'][$relationship->type_id][$rank]['object_id'] = array(
'#type' => 'hidden',
'#value' => $relationship->object_id
);
$form['relationships']['relationship_table'][$relationship->type_id][$rank]['subject_id'] = array(
'#type' => 'hidden',
'#value' => $relationship->subject_id
);
$form['relationships']['relationship_table'][$relationship->type_id][$rank]['type_id'] = array(
'#type' => 'hidden',
'#value' => $relationship->type_id
);
$form['relationships']['relationship_table'][$relationship->type_id][$rank]['object_name'] = array(
'#type' => 'markup',
'#markup' => $relationship->object_name
);
$form['relationships']['relationship_table'][$relationship->type_id][$rank]['type_name'] = array(
'#type' => 'markup',
'#markup' => $relationship->type_name
);
$form['relationships']['relationship_table'][$relationship->type_id][$rank]['subject_name'] = array(
'#type' => 'markup',
'#markup' => $relationship->subject_name
);
$form['relationships']['relationship_table'][$relationship->type_id][$rank]['rank'] = array(
'#type' => 'markup',
'#markup' => $rank
);
$form['relationships']['relationship_table'][$relationship->type_id][$rank]['rel_action'] = array(
'#type' => 'submit',
'#value' => t('Remove'),
'#name' => "rel_remove-".$relationship->type_id.'-'.$rank,
'#ajax' => array(
'callback' => 'chado_add_node_form_relationships_ajax_update',
'wrapper' => 'tripal-generic-edit-relationships-table',
'effect' => 'fade',
'method' => 'replace',
'prevent' => 'click'
),
// When this button is clicked, the form will be validated and submitted.
// Therefore, we set custom submit and validate functions to override the
// default node form submit. In the validate function we validate only the
// relationship fields and in the submit we remove the indicated relationship
// from the chado_relationships array. In order to keep validate errors
// from the node form validate and Drupal required errors for non-relationship fields
// preventing the user from removing relationships we set the #limit_validation_errors below
'#validate' => array('chado_add_node_form_relationships_form_remove_button_validate'),
'#submit' => array('chado_add_node_form_relationships_remove_button_submit'),
// Limit the validation of the form upon clicking this button to the relationship_table tree
// No other fields will be validated (ie: no fields from the main form or any other api
// added form).
'#limit_validation_errors' => array(
array('relationship_table') // Validate all fields within $form_state['values']['relationship_table']
)
);
}
}
$form['relationships']['relationship_table']['new']['object_name'] = array(
'#type' => 'textfield',
'#autocomplete_path' => 'tripal_ajax/relationship_nodeform/' . $details['base_table'] . '/' . $details['base_name_field'].'/name_to_id'
);
$form['relationships']['relationship_table']['new']['object_is_current'] = array(
'#type' => 'checkbox',
'#title' => t('Current '.$details['nodetype']),
);
$form['relationships']['relationship_table']['new']['type_name'] = array(
'#type' => 'select',
'#options' => $type_options,
);
$form['relationships']['relationship_table']['new']['subject_name'] = array(
'#type' => 'textfield',
'#autocomplete_path' => 'tripal_ajax/relationship_nodeform/' . $details['base_table'] . '/' . $details['base_name_field'].'/name_to_id'
);
$form['relationships']['relationship_table']['new']['subject_is_current'] = array(
'#type' => 'checkbox',
'#title' => t('Current ' . $details['nodetype']),
);
$form['relationships']['relationship_table']['new']['rank'] = array(
'#type' => 'markup',
'#markup' => ''
);
$form['relationships']['relationship_table']['new']['rel_action'] = array(
'#type' => 'submit',
'#value' => t('Add'),
'#name' => 'rel_add',
'#ajax' => array(
'callback' => 'chado_add_node_form_relationships_ajax_update',
'wrapper' => 'tripal-generic-edit-relationships-table',
'effect' => 'fade',
'method' => 'replace',
'prevent' => 'click'
),
// When this button is clicked, the form will be validated and submitted.
// Therefore, we set custom submit and validate functions to override the
// default node form submit. In the validate function we validate only the
// relationship fields and in the submit we add them to the chado_relationships
// array. In order to keep validate errors from the node form validate and Drupal
// required errors for non-relationship fields preventing the user from adding relationships we
// set the #limit_validation_errors below
'#validate' => array('chado_add_node_form_relationships_add_button_validate'),
'#submit' => array('chado_add_node_form_relationships_add_button_submit'),
// Limit the validation of the form upon clicking this button to the relationship_table tree
// No other fields will be validated (ie: no fields from the main form or any other api
// added form).
'#limit_validation_errors' => array(
array('relationship_table') // Validate all fields within $form_state['values']['relationship_table']
)
);
}
/**
* Validate the user input for creating a new relationship
* Called by the add button in chado_add_node_form_relationships
*
* @ingroup tripal_core
*/
function chado_add_node_form_relationships_add_button_validate($form, &$form_state) {
$details = unserialize($form_state['values']['relationship_table']['details']);
// First deal with autocomplete fields
// extract the base_id assuming '(###) NAME FIELD'
if (!empty($form_state['values']['relationship_table']['new']['subject_name'])) {
if (preg_match('/\((\d+)\) .*/', $form_state['values']['relationship_table']['new']['subject_name'], $matches)) {
$form_state['values']['relationship_table']['new']['subject_id'] = $matches[1];
}
else {
form_set_error('subject_name', 'You need to select the subject from the autocomplete drop-down');
}
}
if (!empty($form_state['values']['relationship_table']['new']['object_name'])) {
if (preg_match('/\((\d+)\) .*/', $form_state['values']['relationship_table']['new']['object_name'], $matches)) {
$form_state['values']['relationship_table']['new']['object_id'] = $matches[1];
}
else {
form_set_error('object_name', 'You need to select the subject from the autocomplete drop-down');
}
}
// At least one of the participants must be the current node
if (!($form_state['values']['relationship_table']['new']['subject_is_current'] OR $form_state['values']['relationship_table']['new']['object_is_current'])) {
// If the checkbox isn't set then check to see if either has the same uniquename as the node
if ($form_state['values']['relationship_table']['new']['subject_name'] == $form_state['values']['uniquename']) {
$form_state['values']['relationship_table']['new']['subject_is_current'] = 1;
form_set_error('subject_is_current', 'To set the current '.$details['nodetype'].', select the
checkbox. You entered the unique name of the current '.$details['nodetype'].' as the subject,
is this what you meant to do?');
}
elseif ($form_state['values']['relationship_table']['new']['subject_name'] == $form_state['values']['uniquename']) {
$form_state['values']['relationship_table']['new']['object_is_current'] = 1;
form_set_error('subject_is_current', 'To set the current '.$details['nodetype'].', select the
checkbox. You entered the unique name of the current '.$details['nodetype'].' as the subject,
is this what you meant to do?');
}
else {
form_set_error('object_is_current', 'At least one member of the relationship must be
the current '.$details['nodetype'].'. This is specified by checking the "Current '.$details['nodetype'].'"
checkbox for either the subject or object.');
}
}
// The non-current uniquename must be exist in the base table (subject)
if (!($form_state['values']['relationship_table']['new']['subject_is_current'])) {
$result = chado_select_record(
$details['base_table'],
array($details['base_name_field']),
array($details['base_foreign_key'] => $form_state['values']['relationship_table']['new']['subject_id'])
);
if (!isset($result[0])) {
form_set_error('subject_name', 'The subject must be the unique name of an
existing '.$details['nodetype'].' unless the "Current '.$details['nodetype'].'" checkbox is selected');
}
else {
$form_state['values']['relationship_table']['new']['subject_name'] = $result[0]->{$details['base_name_field']};
}
}
// The non-current uniquename must exist in the base table (object)
if (!($form_state['values']['relationship_table']['new']['object_is_current'])) {
$result = chado_select_record(
$details['base_table'],
array($details['base_name_field']),
array($details['base_foreign_key'] => $form_state['values']['relationship_table']['new']['object_id'])
);
if (!isset($result[0])) {
form_set_error('object_name', 'The object must be the unique name of an
existing '.$details['nodetype'].' unless the "Current '.$details['nodetype'].'" checkbox is selected');
}
else {
$form_state['values']['relationship_table']['new']['object_name'] = $result[0]->{$details['base_name_field']};
}
}
// The type must be a valid cvterm
if ($form_state['values']['relationship_table']['new']['type_name']) {
$form_state['values']['relationship_table']['new']['type_id'] = $form_state['values']['relationship_table']['new']['type_name'];
$result = chado_select_record(
'cvterm',
array('name'),
array('cvterm_id' => $form_state['values']['relationship_table']['new']['type_id'])
);
if (!isset($result[0])) {
form_set_error('type_id', 'The select type is not a valid controlled vocabulary term.');
}
else {
$form_state['values']['relationship_table']['new']['type_name'] = $result[0]->name;
}
}
else {
form_set_error('type_id', 'Please select a type of relationship');
}
}
/**
* Called by the add button in chado_add_node_form_relationships
*
* Create an array of additional relationships in the form state. This array will then be
* used to rebuild the form in subsequent builds
*
* @ingroup tripal_core
*/
function chado_add_node_form_relationships_add_button_submit(&$form, &$form_state) {
$details = unserialize($form_state['values']['relationship_table']['details']);
// if the chado_relationships array is not set then this is the first time modifying the
// relationship table. this means we need to include all the relationships from the db
if (!isset($form_state['chado_relationships'])) {
chado_add_node_form_relationships_create_relationship_formstate_array($form, $form_state);
}
$name = (isset($form_state['node']->{$details['base_table']}->uniquename)) ? $form_state['node']->{$details['base_table']}->uniquename : 'CURRENT';
// get details for the new relationship
if ($form_state['values']['relationship_table']['new']['subject_is_current']) {
$relationship = array(
'type_id' => $form_state['values']['relationship_table']['new']['type_id'],
'type_name' => $form_state['values']['relationship_table']['new']['type_name'],
'object_id' => $form_state['values']['relationship_table']['new']['object_id'],
'object_name' => $form_state['values']['relationship_table']['new']['object_name'],
'subject_id' => $form_state['node']->{$details['base_table']}->{$details['base_foreign_key']},
'subject_name' => $name,
'rank' => '0',
);
}
else {
$relationship = array(
'type_id' => $form_state['values']['relationship_table']['new']['type_id'],
'type_name' => $form_state['values']['relationship_table']['new']['type_name'],
'object_id' => $form_state['node']->{$details['base_table']}->{$details['base_foreign_key']},
'object_name' => $name,
'subject_id' => $form_state['values']['relationship_table']['new']['subject_id'],
'subject_name' => $form_state['values']['relationship_table']['new']['subject_name'],
'rank' => '0',
);
}
$key = $relationship['type_id'] . '-' . $relationship['rank'];
$form_state['chado_relationships'][$key] = (object) $relationship;
$form_state['rebuild'] = TRUE;
}
/**
* There is no user input for the remove buttons so there is no need to validate
* However, both a submit & validate need to be specified so this is just a placeholder
*
* Called by the many remove buttons in chado_add_node_form_relationships
*
* @ingroup tripal_core
*/
function chado_add_node_form_relationships_form_remove_button_validate($form, $form_state) {
// No Validation needed for remove
}
/**
* Remove the correct relationship from the form
* Called by the many remove buttons in chado_add_node_form_relationships
*
* @ingroup tripal_core
*/
function chado_add_node_form_relationships_remove_button_submit(&$form, &$form_state) {
// if the chado_relationships array is not set then this is the first time modifying the
// relationship table. this means we need to include all the relationships from the db
if (!isset($form_state['chado_relationships'])) {
chado_add_node_form_relationships_create_relationship_formstate_array($form, $form_state);
}
// remove the specified relationship from the form relationship table
if(preg_match('/rel_remove-([^-]+-[^-]+)/',$form_state['triggering_element']['#name'],$match)) {
$key = $match[1];
if (array_key_exists($key, $form_state['chado_relationships'])) {
unset($form_state['chado_relationships'][$key]);
}
}
$form_state['rebuild'] = TRUE;
}
/**
* Ajax function which returns the section of the form to be re-rendered
*
* @ingroup tripal_core
*/
function chado_add_node_form_relationships_ajax_update($form, $form_state) {
return $form['relationships']['relationship_table'];
}
/**
* Creates an array in form_state containing the existing relationships. This array is
* then modified by the add/remove buttons and used as a source for rebuilding the form.
*
* $form_state['chado_relationships'] = array(
* '[type_id]-[rank]' => array(
* 'object_id' => [the _relationship.object_id value],
* 'object_name' => [the base_table.uniquename value linked on base_foreign_key=object_id],
* 'subject_id' => [the _relationship.subject_id value],
* 'subject_name' => [the base_table.uniquename value linked on base_foreign_key=subject_id],
* 'type_id' => [the _relationship.type_id value],
* 'type_name' => [the cvterm.name value linked on type_id],
* 'rank' => [the _relationship.rank value],
* ),
* );
*
* @ingroup tripal_core
*/
function chado_add_node_form_relationships_create_relationship_formstate_array($form, &$form_state) {
$form_state['chado_relationships'] = array();
foreach (element_children($form['relationships']['relationship_table']) as $type_id) {
if ($type_id != 'new') {
foreach (element_children($form['relationships']['relationship_table'][$type_id]) as $rank) {
$element = $form['relationships']['relationship_table'][$type_id][$rank];
$rel = array(
'type_id' => $element['type_id']['#value'],
'object_id' => $element['object_id']['#value'],
'subject_id' => $element['subject_id']['#value'],
'type_name' => $element['type_name']['#markup'],
'object_name' => $element['object_name']['#markup'],
'subject_name' => $element['subject_name']['#markup'],
'rank' => $element['rank']['#markup']
);
$key = $rel['type_id'] . '-' . $rel['rank'];
$form_state['chado_relationships'][$key] = (object) $rel;
}
}
}
}
/**
* Function to theme the add/remove relationships form into a table
*
* @ingroup tripal_chado_node_api
*/
function theme_chado_add_node_form_relationships_table($variables) {
$element = $variables['element'];
$details = unserialize($element['details']['#value']);
$header = array(
'object_name' => t('Object ' . $details['base_name_field']),
'type_name' => t('Type'),
'subject_name' => t('Subject ' . $details['base_name_field']),
'rel_action' => t('Action')
);
$rows = array();
foreach (element_children($element) as $type_id) {
if ($type_id == 'new') {
$row = array();
$row['data'] = array();
foreach ($header as $fieldname => $title) {
if ($fieldname == 'subject_name') {
$row['data'][] = drupal_render($element[$type_id][$fieldname]) . drupal_render($element[$type_id]['subject_is_current']);
}
elseif ($fieldname == 'object_name') {
$row['data'][] = drupal_render($element[$type_id][$fieldname]) . drupal_render($element[$type_id]['object_is_current']);
}
else {
$row['data'][] = drupal_render($element[$type_id][$fieldname]);
}
}
$rows[] = $row;
}
else {
foreach (element_children($element[$type_id]) as $rank) {
$row = array();
$row['data'] = array();
foreach ($header as $fieldname => $title) {
$row['data'][] = drupal_render($element[$type_id][$rank][$fieldname]);
}
$rows[] = $row;
}
}
}
return theme('table', array(
'header' => $header,
'rows' => $rows
));
}
/**
* This function is used in a hook_insert, hook_update for a node form
* when the relationships form has been added to the form. It retrieves all of the relationships
* and returns them in an array of the format:
*
* $relationships[][] = array(
* 'subject_id' => ,
* 'object_id' => ,
* );
*
* This array can then be used for inserting or updating relationships manually
*
* @param $node
*
* @return
* A relationship array
*
* @ingroup tripal_chado_node_api
*/
function chado_retrieve_node_form_relationships($node) {
$rels = array();
if (isset($node->relationship_table)) {
foreach ($node->relationship_table as $type_id => $elements) {
if ($type_id != 'new' AND $type_id != 'details') {
foreach ($elements as $rank => $relationships) {
$rels[$type_id][$rank]['subject_id'] = $relationships['subject_id'];
$rels[$type_id][$rank]['object_id'] = $relationships['object_id'];
}
}
}
}
return $rels;
}
/**
* This function is used in hook_insert or hook_update and handles inserting of
* relationships between the current nodetype and other memebers of the same nodetype
*
* @param $node
* The node passed into hook_insert & hook_update
* @param $details
* - relationship_table: the name of the _relationship linking table (ie: feature_relationship)
* - foreignkey_value: the value of the foreign key (ie: 445, if there exists a feature where feature_id=445)
* @param $retrieved_relationships
* An array of relationships from chado_retrieve_node_form_relationships($node). This
* can be used if you need special handling for some of the relationships.
*
* @ingroup tripal_chado_node_api
*/
function chado_update_node_form_relationships($node, $details, $retrieved_relationships = FALSE) {
$relationship_table = $details['relationship_table'];
$current_id = $details['foreignkey_value'];
if (isset($node->relationship_table) AND ($current_id > 0)) {
// determine whether there is a rank in this relationship table
$form_details = unserialize($node->relationship_table['details']);
$has_rank = $form_details['table_has_rank'];
// First remove existing relationships links
chado_delete_record(
$relationship_table,
array($form_details['subject_field_name'] => $current_id)
);
chado_delete_record(
$relationship_table,
array($form_details['object_field_name'] => $current_id)
);
// Add back in relationships as needed
if ($retrieved_relationships) {
$relationships = $retrieved_relationships;
}
else {
$relationships = chado_retrieve_node_form_relationships($node);
}
foreach ($relationships as $type_id => $ranks) {
foreach ($ranks as $rank => $element) {
$values = array(
$form_details['subject_field_name'] => $element['subject_id'],
'type_id' => $type_id,
$form_details['object_field_name'] => $element['object_id']
);
// Set the current id if not already
// this is usually only necessary in an insert
if (empty($values[$form_details['subject_field_name']])) {
$values[$form_details['subject_field_name']] = $current_id;
}
if (empty($values[$form_details['object_field_name']])) {
$values[$form_details['object_field_name']] = $current_id;
}
if ($has_rank) {
// Ensure that the rank is Set & Current
$rank_select = chado_get_table_max_rank(
$relationship_table,
array(
$form_details['subject_field_name'] => $values['subject_id'],
'type_id' => $values['type_id'],
$form_details['object_field_name'] => $values['object_id'],
)
);
$values['rank'] = $rank_select + 1;
}
// add relationship
$success_link = chado_insert_record(
$relationship_table,
$values
);
}
}
}
}
/**
* Handles autocomplete for subject & object id
*
* @param $string
* The part of the string already typed in the textfield
*
* @ingroup tripal_core
*/
function chado_add_node_form_relationships_name_to_id_callback($base_table, $name_field, $string) {
$matches = array();
$base_key = $base_table.'_id';
$result = db_select('chado.'.$base_table, 'b')
->fields('b', array($base_key, $name_field))
->condition($name_field, '%' . db_like($string) . '%', 'LIKE')
->execute();
// save the query to matches
foreach ($result as $row) {
$key = '('.$row->{$base_key}.') '.substr($row->{$name_field},0,50) . '...';
$matches[$key] = check_plain($row->{$name_field});
}
// return for JS
drupal_json_output($matches);
}