'example_property', // the name of the table linking additional properties to this node
'chado_id_field' => 'example_id', // key to link to the chado content created by this node
'chado_id' => $example_id, // the value of the above key
'cv_name' => 'example_prop_cv', // the name of the cv governing the _prop.type_id
'fieldset_title' => 'Additional References', // 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_properties($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 properties
// Existing _property links will be cleared and then re-added
tripal_api_chado_node_properties_form_update_properties(
$node, // the node object passed in via hook_insert()
'example_property', // the name of the _property linking table
'example', // the name of the base chado table for the node
'example_id', // key to link to the chado content created by this node
$node->example_id // value of the above key
);
}
// 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 properties
// Existing _property links will be cleared and then re-added
tripal_api_chado_node_properties_form_update_properties(
$node, // the node object passed in via hook_insert()
'example_property', // the name of the _property linking table
'example', // the name of the base chado table for the node
'example_id', // key to link to the chado content created by this node
$node->example_id // value of the above key
);
// 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 BASEprop table
*
* @param $form
* The Drupal form array into which the property form elements will be added
* @param $form_state
* The corresponding form_state array for the form
* @param $details
* An array defining details used by this form.
* Required keys that are always required:
* - property_table: the name of the property table (e.g.: featureprop, stockprop, etc.)
* Required keys for forms that update a record.
* - chado_id: the id of the record to which properties will be associated (e.g.: if a
* feature has a feature_id of 999 and we want to associate properties for that feature
* then the chado_id option should be 999)
* Require ONE of the following to identify the controlled vocabulary containing the properties to use:
* - cv_id: the unique key from the cv table
* - cv_name: the cv.name field uniquely identifying the controlled vocabulary
* Optional keys include:
* - chado_id_field: the foreign key field that links properties to the
* chado_id record. If this value is not specified it is determined using the
* traditional Chado naming scheme for property tables.
* - additional_instructions: provides additional instructions to the user
* for dealing with the property elements. These instructions are appended
* to the default instructions
* - fieldset_title: An alternate name for the fieldset in which the properties
* form is placed. By default the title is 'Properties'.
* - default_properties: An array of properties used to initialize the
* properties form. Each property shoudl be represented as an array with
* the following keys and values:
* 'cvterm': The cvterm object for the property type
* 'value': The property value
* - select_options: an array of terms to use for the drop down select box.
* this array will be used rather than populating the drop down with terms
* from the named vocabulary. The array must have keys with the cvterm_id
* and values with the cvterm name.
*
* @ingroup tripal_chado_node_api
*/
function chado_add_node_form_properties(&$form, &$form_state, $details) {
// Set defaults for optional fields
if (!array_key_exists('fieldset_title', $details)){
$details['fieldset_title'] = 'Properties';
}
if (!array_key_exists('additional_instructions', $details)){
$details['additional_instructions'] = '';
};
if (!array_key_exists('default_properties', $details)){
$details['default_properties'] = array();
};
if (!is_array($details['default_properties'])) {
drupal_set_message("The 'default_properties' option must be an array", "error");
tripal_report_error('tcprops_form', TRIPAL_ERROR,
"The 'default_properties' option must be an array",
array());
return;
}
// make sure the property table exists before proceeding.
if (!chado_table_exists($details['property_table'])) {
drupal_set_message("Cannot add property elements to the form. The property table, '" .
$details['property_table'] . "', does not exists", "error");
tripal_report_error('tcprops_form', TRIPAL_ERROR,
"Cannot add property elements to the form. The property table, '%name', cannot be found.",
array('%name' => $details['property_table']));
return;
}
// if the chado_id_field is not specified then set it using the
// typical chado naming scheme
if (!array_key_exists('chado_id_field', $details)) {
$chado_id_table = preg_replace('/prop$/', '', $details['property_table']);
$chado_id_field = $chado_id_table . '_id';
$details['chado_id_field'] = $chado_id_field;
}
// 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 property elements to the form. The CV name, '" .
$details['cv_name'] . "', does not exists", "error");
tripal_report_error('tcprops_form', TRIPAL_ERROR,
"Cannot add property 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 property elements to the form. The CV ID, '" .
$details['cv_id'] . "', does not exist", "error");
tripal_report_error('tcprops_form', TRIPAL_ERROR,
"Cannot add property 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 {
// If we didn't get given a cv identifier, then try retrieving the default one
// using the new cv defaults api
$default_cv = tripal_get_default_cv($details['property_table'], 'type_id');
if (!empty($default_cv)) {
$details['cv_id'] = $default_cv->cv_id;
$details['cv_name'] = $default_cv->name;
}
else {
$default_form_link = l('vocabulary defaults configuration page',
'admin/tripal/chado/tripal_cv/defaults',
array('attributes' => array('target' => '_blank')));
$message = "There is not a default vocabulary set for Property Types. Please set one using the $default_form_link.";
if (preg_match('/(\w+)_id/',$details['chado_id_field'],$matches)) {
$table = $matches[1];
$table = ucwords(str_replace('_',' ',$table));
$message = "There is not a default vocabulary set for $table Property Types. Please set one using the $default_form_link.";
}
tripal_set_message($message, TRIPAL_WARNING);
tripal_report_error('tcprops_form', TRIPAL_ERROR,
"Please provide either a 'cv_name' or 'cv_id' as an option for adding properties to the form",
array());
}
return;
}
// Get property types for the select list. If the user has provided a set
// then use those, otherwise get them from the cvterm table for specified cv.
if (array_key_exists('select_options', $details) and
is_array($details['select_options'])) {
$property_options = $details['select_options'];
}
// if the select options are not provided then try to get them on our own
else {
// if the vocabulary name is provided in the details then use that to
// get the terms
if (isset($details['cv_name'])) {
$property_options = array();
$property_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()) {
$property_options[$prop->cvterm_id] = $prop->name;
}
}
// if the cv_id is set in the $details array then use that to get the terms
elseif (isset($details['cv_id'])) {
$property_options = array();
$property_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()) {
$property_options[$prop->cvterm_id] = $prop->name;
}
}
}
// Tell tripal administrators how to add terms to the property types drop down.
if (empty($property_options)) {
$tripal_message = tripal_set_message(
t('There are currently no property types! To add 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_NOTICE,
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)
);
}
// Group all of the chado node api fieldsets into vertical tabs.
$form['chado_node_api'] = array(
'#type' => 'vertical_tabs',
'#attached' => array(
'css' => array(
'chado-node-api' => drupal_get_path('module', 'tripal_core') . '/theme/css/chado_node_api.css',
),
),
);
// the fieldset of the property elements
$form['properties'] = array(
'#type' => 'fieldset',
'#title' => t($details['fieldset_title']),
'#description' => t('Add properties by selecting a type
from the dropdown, enter a value and click the "Add" button. To
remove a property, click the remove button.' . $details['additional_instructions']),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#group' => 'chado_node_api',
'#weight' => 8,
'#attributes' => array('class' => array('chado-node-api','properties')),
'#attached' => array(
'js' => array(
'chado-node-api-vertical-tabs' => drupal_get_path('module', 'tripal_core') . '/theme/js/chadoNodeApi_updateVerticalTabSummary.js',
),
),
);
$form['properties']['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']['property_table'] heading.
$form['properties']['property_table'] = array(
'#type' => 'markup',
'#tree' => TRUE,
'#prefix' => '
',
'#suffix' => '
',
'#theme' => 'chado_node_properties_form_table'
);
// Add defaults into form_state to be used elsewhere
$form['properties']['property_table']['details'] = array(
'#type' => 'hidden',
'#value' => serialize($details)
);
/* Properties can come to us in two ways:
* 1) As entries in the $details['default_properties'] option
*
* 2) In the form state in the $form_state['chado_properties']. Data is in this field
* when an AJAX call updates the form state or a validation error.
*
* 3) Directly from the database if the record already has properties 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_properties']
* entry.
*/
if (isset($form_state['chado_properties'])) {
$existing_properties = $form_state['chado_properties'];
}
else {
// build the SQL for extracting properties already assigned to this record
$sql_args = array();
$sql_args[':chado_id'] = $details['chado_id'];
if (array_key_exists('cv_name', $details)) {
$cv_where = "CV.name = :cvname";
$sql_args[':cvname'] = $details['cv_name'];
}
elseif (array_key_exists('cv_id', $details)) {
$cv_where = "CV.cv_id = :cvid";
$sql_args[':cvid'] = $details['cv_id'];
}
$existing_properties = chado_query(
"SELECT
PP.".$details['property_table']."_id property_id,
CVT.cvterm_id as type_id,
CVT.name as type_name,
CVT.definition,
PP.value,
PP.rank
FROM {" . $details['property_table'] . "} PP
INNER JOIN {cvterm} CVT ON CVT.cvterm_id = PP.type_id
INNER JOIN {cv} CV ON CVT.cv_id = CV.cv_id
WHERE
PP." . $details['chado_id_field'] . " = :chado_id AND
$cv_where
ORDER BY CVT.name, PP.rank", $sql_args)->fetchAll();
// next add in any default properties
if (array_key_exists('default_properties', $details)) {
// next iterate through each of the default properties and create a new
// stdClass array that contains the fields needed.
foreach ($details['default_properties'] as $property) {
$new_prop = new stdClass();
$new_prop->type_id = $property['cvterm']->cvterm_id;
$new_prop->type_name = $property['cvterm']->name;
$new_prop->definition = $property['cvterm']->definition;
$new_prop->value = $property['value'];
$new_prop->property_id = 'TEMP' . uniqid();
$new_prop->rank = 'TEMP' . uniqid();
$existing_properties[] = $new_prop;
}
}
}
/* The format of the $existing_properties array is either:
*
* From the chado_properties array:
* $form_state['chado_properties'] = array(
* '[type_id]-[rank]' => array(
* 'type_id' => [the cvterm.cvterm_id value]
* 'type_name' => [the cvterm.name value]
* 'property_id' => [the property.property_id value, or temporary value if it doesn't yet exist],
* 'value' => [the BASEprop.value value],
* 'rank' => [the BASEprop.rank value or NULL if not saved yet],
* ),
* );
*
* OR
* Populated from the database:
* $existing_property = array(
* 0 => array(
* 'property_id' => [the property.property_id value],
* 'type_id' => [the cvterm.cvterm_id value]
* 'type_name' => [the cvterm.name value]
* 'value' => [the BASEprop.value value],
* 'rank' => [the BASEprop.rank value],
* ),
* );
*
* NOTE: The main difference is the key
*
* Loop on the array elements of the $existing_properties array and add
* an element to the form for each one as long as it's also in the
* $properties_options array.
*/
$num_properties = 0;
foreach ($existing_properties as $property) {
if (array_key_exists($property->type_id, $property_options)) {
$num_properties++;
$form['properties']['property_table'][$property->type_id]['#type'] = 'markup';
$form['properties']['property_table'][$property->type_id]['#value'] = '';
$form['properties']['property_table'][$property->type_id][$property->property_id]['#type'] = 'markup';
$form['properties']['property_table'][$property->type_id][$property->property_id]['#value'] = '';
$form['properties']['property_table'][$property->type_id][$property->property_id]['#attributes'] = array(
'class' => array('property', 'saved')
);
// Determine whether this property is unsaved or not.
// We can tell this by looking at the property_id: if it's not
// saved yet we will have entered a TEMP###.
if (preg_match('/^TEMP/', $property->property_id)) {
$form['properties']['property_table'][$property->type_id][$property->property_id]['#attributes'] = array(
'class' => array('property', 'unsaved')
);
}
$form['properties']['property_table'][$property->type_id][$property->property_id]['prop_type_id'] = array(
'#type' => 'hidden',
'#value' => $property->type_id
);
$form['properties']['property_table'][$property->type_id][$property->property_id]['prop_value'] = array(
'#type' => 'hidden',
'#value' => $property->value
);
$form['properties']['property_table'][$property->type_id][$property->property_id]['prop_rank'] = array(
'#type' => 'hidden',
'#value' => $property->rank
);
$form['properties']['property_table'][$property->type_id][$property->property_id]['property_id'] = array(
'#type' => 'hidden',
'#value' => $property->property_id
);
$form['properties']['property_table'][$property->type_id][$property->property_id]['type'] = array(
'#type' => 'markup',
'#markup' => $property->type_name
);
// If a definition is available we want to add that to the type column
// to make it easier for users to determine what an added property means.
if (isset($property->definition)) {
$form['properties']['property_table'][$property->type_id][$property->property_id]['type']['#markup'] = $property->type_name . '
' . $property->definition . '';
}
$form['properties']['property_table'][$property->type_id][$property->property_id]['value'] = array(
'#type' => 'markup',
'#markup' => $property->value,
);
$form['properties']['property_table'][$property->type_id][$property->property_id]['rank'] = array(
'#type' => 'markup',
'#markup' => $property->rank
);
// remove button
$form['properties']['property_table'][$property->type_id][$property->property_id]['property_action'] = array(
'#type' => 'submit',
'#value' => t('Remove'),
'#name' => "properties_remove-".$property->type_id.'-'.$property->property_id,
'#ajax' => array(
'callback' => "chado_add_node_form_subtable_ajax_update",
'wrapper' => 'tripal-generic-edit-properties-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
// property fields and in the submit we remove the indicated property
// from the chado_properties array. In order to keep validate errors
// from the node form validate and Drupal required errors for non-property fields
// preventing the user from removing properties we set the #limit_validation_errors below
'#validate' => array('chado_add_node_form_subtables_remove_button_validate'),
'#submit' => array('chado_add_node_form_subtables_remove_button_submit'),
// Limit the validation of the form upon clicking this button to the property_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('property_table') // Validate all fields within $form_state['values']['property_table']
),
);
}
}
// Quickly add a hidden field stating how many properties are currently added.
$form['properties']['num_properties'] = array(
'#type' => 'hidden',
'#value' => $num_properties,
'#attributes' => array('class' => 'num-properties')
);
// Form elements for adding a new property
//---------------------------------------------
$form['properties']['property_table']['new'] = array(
'#type' => 'markup',
'#prefix' => '',
'#suffix' => ''
);
// get the value selected (only works on AJAX call) and print the
// description
$type_desc = '';
if (isset($form_state['input']['property_table']['new']['type'])) {
$new_type_id = $form_state['input']['property_table']['new']['type'];
$new_term = tripal_get_cvterm(array('cvterm_id' => $new_type_id));
if ($new_term) {
$type_desc = $new_term->definition;
}
}
$form['properties']['property_table']['new']['type'] = array(
'#type' => 'select',
'#options' => $property_options, // Set at top of form
'#prefix' => '',
'#suffix' => '' . $type_desc . '',
'#ajax' => array(
'callback' => "chado_add_node_form_properties_ajax_desc",
'wrapper' => 'tripal-generic-edit-properties-new-desc',
'effect' => 'fade',
'method' => 'replace',
),
);
$form['properties']['property_table']['new']['value'] = array(
'#type' => 'textarea',
'#rows' => 2,
);
// add button
$form['properties']['property_table']['new']['property_action'] = array(
'#type' => 'submit',
'#value' => t('Add'),
'#name' => "properties-add",
'#ajax' => array(
'callback' => "chado_add_node_form_subtable_ajax_update",
'wrapper' => 'tripal-generic-edit-properties-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
// additional property fields and in the submit we add them to the chado_properties
// array. In order to keep validate errors from the node form validate and Drupal
// required errors for non-property fields preventing the user from adding properties we
// set the #limit_validation_errors below
'#validate' => array('chado_add_node_form_subtables_add_button_validate'),
'#submit' => array('chado_add_node_form_subtables_add_button_submit'),
// Limit the validation of the form upon clicking this button to the property_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('property_table') // Validate all fields within $form_state['values']['property_table']
)
);
}
/**
* Validate the user input for creating a new property
* Called by the add button in chado_add_node_form_properties
*
* @ingroup tripal_core
*/
function chado_add_node_form_properties_add_button_validate($form, &$form_state) {
// Ensure the type_id is supplied & Valid
$cvterm = chado_select_record(
'cvterm',
array('cvterm_id', 'name', 'definition'),
array('cvterm_id' => $form_state['values']['property_table']['new']['type'])
);
if (!isset($cvterm[0])) {
form_set_error('property_table][new][cvterm', 'Please select a property type before attempting to add a new property.');
}
else {
$form_state['values']['property_table']['new']['type_name'] = $cvterm[0]->name;
$form_state['values']['property_table']['new']['definition'] = $cvterm[0]->definition;
}
// Ensure value is supplied
if (empty($form_state['values']['property_table']['new']['value'])) {
form_set_error('property_table][new][value','You must enter the property value before attempting to add a new property.');
}
}
/**
* Called by the add button in chado_add_node_form_properties
*
* Create an array of properties 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_properties_add_button_submit($form, &$form_state) {
$details = unserialize($form_state['values']['property_table']['details']);
// if the chado_additional_properties array is not set then this is the first time modifying the
// property table. this means we need to include all the properties from the db
if (!isset($form_state['chado_properties'])) {
chado_add_node_form_properties_create_property_formstate_array($form, $form_state);
}
// get details for the new property
$property = array(
'type_id' => $form_state['values']['property_table']['new']['type'],
'type_name' => $form_state['values']['property_table']['new']['type_name'],
'definition' => $form_state['values']['property_table']['new']['definition'],
'property_id' => 'TEMP' . uniqid(),
'value' => $form_state['values']['property_table']['new']['value'],
'rank' => 'TEMP' . uniqid(),
);
$key = $property['type_id'] . '-' . $property['property_id'];
$form_state['chado_properties'][$key] = (object) $property;
// we don't want the new element to pick up the values from the previous element so wipe them out
unset($form_state['input']['property_table']['new']['type']);
unset($form_state['input']['property_table']['new']['type_name']);
unset($form_state['input']['property_table']['new']['definition']);
unset($form_state['input']['property_table']['new']['value']);
}
/**
* Called by the many remove buttons in chado_add_node_form_properties
*
* @ingroup tripal_core
*/
function chado_add_node_form_properties_remove_button_validate($form, &$form_state) {
// No validation needed.
}
/**
* Remove the correct property from the form
* Called by the many remove buttons in chado_add_node_form_properties
*
* @ingroup tripal_core
*/
function chado_add_node_form_properties_remove_button_submit(&$form, &$form_state) {
// if the chado_properties array is not set then this is the first time modifying the
// property table. this means we need to include all the properties from the db
if (!isset($form_state['chado_properties'])) {
chado_add_node_form_properties_create_property_formstate_array($form, $form_state);
}
// remove the specified property from the form property table
if(preg_match('/properties_remove-([^-]+-[^-]+)/',$form_state['triggering_element']['#name'],$match)) {
$key = $match[1];
if (array_key_exists($key, $form_state['chado_properties'])) {
unset($form_state['chado_properties'][$key]);
}
}
}
function chado_add_node_form_properties_ajax_desc($form, $form_state) {
return $form['properties']['property_table']['new']['type'];
}
/**
* Creates an array in form_state containing the existing properties. This array is
* then modified by the add/remove buttons and used as a source for rebuilding the form.
* This function get's called at each button (add and remove) button submits the first
* time one of the button's is clicked to instantiates the $form_state['chado_properties'] array
*
* $form_state['chado_properties'] = array(
* '[type_id]-[rank]' => array(
* 'type_id' => [the cvterm.cvterm_id value]
* 'type_name' => [the cvterm.name value]
* 'property_id' => [the property.property_id value, or NULL if it doesn't yet exist],
* 'value' => [the BASEprop.value value],
* 'rank' => [the BASEprop.rank value],
* ),
* );
*
* @ingroup tripal_core
*/
function chado_add_node_form_properties_create_property_formstate_array($form, &$form_state) {
$form_state['chado_properties'] = array();
foreach (element_children($form['properties']['property_table']) as $type_id) {
if ($type_id != 'new') {
foreach (element_children($form['properties']['property_table'][$type_id]) as $property_id) {
$element = $form['properties']['property_table'][$type_id][$property_id];
$property = array(
'type_id' => $element['prop_type_id']['#value'],
'type_name' => $element['type']['#markup'],
'property_id' => $element['property_id']['#value'],
'value' => $element['value']['#markup'],
'rank' => $element['rank']['#markup']
);
$key = $property['type_id'] . '-' . $property['property_id'];
$form_state['chado_properties'][$key] = (object) $property;
}
}
}
}
/**
* Function to theme the add/remove properties form into a table
*
* @ingroup tripal_chado_node_api
*/
function theme_chado_add_node_form_properties($variables) {
$element = $variables['element'];
$header = array(
'type' => array('data' => t('Type'), 'width' => '30%'),
'value' => array('data' => t('Value'), 'width' => '50%'),
'property_action' => array('data' => t('Actions'),'width' => '20%'),
);
$rows = array();
foreach (element_children($element) as $type_id) {
if ($type_id == 'new') {
$row = array();
$row['data'] = array();
foreach ($header as $fieldname => $title) {
$row['data'][] = drupal_render($element[$type_id][$fieldname]);
}
$rows[] = $row;
}
else {
foreach (element_children($element[$type_id]) as $version) {
$row = array();
$row['data'] = array();
$row['class'] = $element[$type_id][$version]['#attributes']['class'];
foreach ($header as $fieldname => $title) {
$row['data'][] = drupal_render($element[$type_id][$version][$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 chado node properties form has been added to the form. It retrieves all of the properties
* and returns them in an array of the format:
*
* $dbxefs[][] =
*
* This array can then be used for inserting or updating properties
*
* @param $node
*
* @return
* A property array
*
* @ingroup tripal_chado_node_api
*/
function chado_retrieve_node_form_properties($node) {
$properties = array();
if (isset($node->property_table)) {
foreach ($node->property_table as $type_id => $elements) {
if ($type_id != 'new' AND $type_id != 'details') {
foreach ($elements as $property_id => $element) {
$properties[$type_id][$element['prop_rank']] = $element['prop_value'];
}
}
}
}
return $properties;
}
/**
* This function is used in hook_insert or hook_update and handles inserting of any new
* properties
*
* @param $node
* The node passed into hook_insert & hook_update
* @param $details
* - property_table: the name of the _property linking table (ie: feature_property)
* - base_table: the name of the base table (ie: feature)
* - foreignkey_name: the name of the foreign key used to link to the node content (ie: feature_id)
* - foreignkey_value: the value of the foreign key (ie: 445, if there exists a feature where feature_id=445)
* @param $retrieved_properties
* An array of properties from chado_retrieve_node_form_properties($node). This can be used if you need
* special handling for some of the properties (See FeatureMap chado_featuremap_insert for an example)
*
* @ingroup tripal_chado_node_api
*/
function chado_update_node_form_properties($node, $details, $retrieved_properties = FALSE) {
$details['foreignkey_value'] = (isset($details['foreignkey_value'])) ? $details['foreignkey_value'] : 0;
if (isset($node->property_table) AND ($details['foreignkey_value'] > 0)) {
// First remove existing property links
chado_delete_record($details['property_table'], array($details['foreignkey_name'] => $details['foreignkey_value']));
// Add back in property links and insert properties as needed
if ($retrieved_properties) {
$properties = $retrieved_properties;
}
else {
$properties = chado_retrieve_node_form_properties($node);
}
foreach ($properties as $type_id => $ranks) {
foreach ($ranks as $rank => $value) {
if (preg_match('/^TEMP/', $rank)) {
$rank = chado_get_table_max_rank(
$details['property_table'],
array(
$details['foreignkey_name'] => $details['foreignkey_value'],
'type_id' => $type_id
)
);
$rank = strval($rank + 1);
}
$success = chado_insert_record(
$details['property_table'],
array(
$details['foreignkey_name'] => $details['foreignkey_value'],
'type_id' => $type_id,
'value' => $value,
'rank' => $rank
)
);
if (!$success) {
tripal_report_error('tripal_' . $details['base_table'], TRIPAL_ERROR,
$details['base_table'] . ' Insert: Unable to insert property type_id %cvterm with value %value.',
array('%cvterm' => $type_id, '%value' => $value));
}
}
}
}
}