$ontology_name)); while ($prop = $prop_types->fetchObject()) { $properties[$prop->cvterm_id] = $prop->name; } $exclude = array(); $include = array(); $instructions = t('To add additional properties to the drop down. ' . l("Add terms to the $ontology_name vocabulary", "admin/tripal/chado/tripal_cv/cvterm/add") . "."); // actually create and add the form tripal_core_properties_form( $form, $form_state, // form and form_state of the current form 'exampleprop', // properties table name 'example_id', // key to link to the chado content created by this node $ontology_name, // name of ontology governing your prop table type_id column $properties, // an array of properties to use in the drop-down $example_id, // the value of the above key $exclude, // elements from the ontology you don't want to be available as property types $include, // additional elements not in the ontology that you do what in the drop-down $instructions, // form specific instructions 'Properties' // name of the fieldset ); return $form; } function nodetype_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 each property (exampleprop table) // example_property = controlled vocab name for exampleprop.type_id $properties = tripal_core_properties_form_retreive($node, 'example_property'); foreach ($properties as $property => $elements) { foreach ($elements as $rank => $value) { $success = tripal_core_insert_property( 'example', //base table name $example_id, // key to link to the chado content created by this node $property, // cvterm.name of the property to be added $ontology_name, // name of the ontology the cvterm is from $value // the value o the property ); if (!$success) { watchdog( 'tripal_example', 'Example Update: Unable to insert property %cvterm %value.', array('%cvterm' => $property, '%value' => $value), WATCHDOG_ERROR ); } } } } // Add record to chado_example linking example_id to new node } function nodetype_update($node) { // Update record in chado example table // Update any other tables needed // First delete any existing properties tripal_core_chado_delete( 'exampleprop', // the name of the prop table array('example_id' => $example_id) // name of your key and the current value used to determine which to delete ); // Add each property (exampleprop table) // example_property = controlled vocab name for exampleprop.type_id $properties = tripal_core_properties_form_retreive($node, 'example_property'); foreach ($properties as $property => $elements) { foreach ($elements as $rank => $value) { $success = tripal_core_insert_property( 'example', //base table name $example_id, // key to link to the chado content created by this node $property, // cvterm.name of the property to be added $ontology_name, // name of the ontology the cvterm is from $value // the value o the property ); if (!$success) { watchdog( 'tripal_example', 'Example Update: Unable to insert property %cvterm %value.', array('%cvterm' => $property, '%value' => $value), WATCHDOG_ERROR ); } } } } // Don't need to update chado_example linking table since niether example_id or nid can be changed in update } * @endcode */ /** * Retrieve a property for a given base table record * * @param $basetable * The base table for which the property should be retrieved. Thus to retrieve a property * for a feature the basetable=feature and property is retrieved from featureprop * @param $record_id * The foriegn key field of the base table. This should be in integer. * @param $property * The cvterm name describing the type of properties to be retrieved * @param $cv_name * The name of the cv that the above cvterm is part of * * @return * An array in the same format as that generated by the function * tripal_core_generate_chado_var(). If only one record is returned it * is a single object. If more than one record is returned then it is an array * of objects * * @ingroup tripal_properties_api */ function tripal_core_get_property($basetable, $record_id, $property, $cv_name) { // get the foreign key for this property table $table_desc = tripal_core_get_chado_table_schema($basetable . 'prop'); $fkcol = key($table_desc['foreign keys'][$basetable]['columns']); // construct the array of values to be selected $values = array( $fkcol => $record_id, 'type_id' => array( 'cv_id' => array( 'name' => $cv_name, ), 'name' => $property, 'is_obsolete' => 0 ), ); $results = tripal_core_generate_chado_var($basetable . 'prop', $values); if ($results) { $results = tripal_core_expand_chado_vars($results, 'field', $basetable . 'prop.value'); } return $results; } /** * Insert a property for a given base table. By default if the property already * exists a new property is added with the next available rank. If * $update_if_present argument is specified then the record will be updated if it * exists rather than adding a new property. * * @param $basetable * The base table for which the property should be inserted. Thus to insert a property * for a feature the basetable=feature and property is inserted into featureprop * @param $record_id * The foriegn key value of the base table. This should be in integer. * @param $property * The cvterm name describing the type of properties to be inserted * @param $cv_name * The name of the cv that the above cvterm is part of * @param $value * The value of the property to be inserted (can be empty) * @param $update_if_present * A boolean indicating whether an existing record should be updated. If the * property already exists and this value is not specified or is zero then * a new property will be added with the next largest rank. * * @return * Return True on Insert/Update and False otherwise * * @ingroup tripal_properties_api */ function tripal_core_insert_property($basetable, $record_id, $property, $cv_name, $value, $update_if_present = 0) { // first see if the property already exists, if the user want's to update // then we can do that, but otherwise we want to increment the rank and // insert $props = tripal_core_get_property($basetable, $record_id, $property, $cv_name); if (!is_array($props) and $props) { $props = array($props); } $rank = 0; if (count($props) > 0) { if ($update_if_present) { return tripal_core_update_property($basetable, $record_id, $property, $cv_name, $value); } else { // iterate through the properties returned and check to see if the // property with this value already exists if not, get the largest rank // and insert the same property but with this new value foreach ($props as $p) { if ($p->rank > $rank) { $rank = $p->rank; } if (strcmp($p->value, $value) == 0) { return TRUE; } } // now add 1 to the rank $rank++; } } // make sure the cvterm exists. Otherwise we'll get an error with // prepared statements not matching $values = array( 'cv_id' => array( 'name' => $cv_name, ), 'name' => $property, ); $options = array(); $term = tripal_core_chado_select('cvterm', array('cvterm_id'), $values, $options); if (!$term or count($term) == 0) { watchdog('tripal_core', "Cannot find property '%prop_name' in vocabulary '%cvname'.", array('%prop_name' => $property, '%cvname' => $cv_name), WATCHDOG_ERROR); return FALSE; } // get the foreign key for this property table $table_desc = tripal_core_get_chado_table_schema($basetable . 'prop'); $fkcol = key($table_desc['foreign keys'][$basetable]['columns']); // construct the array of values to be inserted $values = array( $fkcol => $record_id, 'type_id' => array( 'cv_id' => array( 'name' => $cv_name, ), 'name' => $property, ), 'value' => $value, 'rank' => $rank, ); $options = array(); $result = tripal_core_chado_insert($basetable . 'prop', $values, $options); return $result; } /** * Update a property for a given base table record and property name. This * function should be used only if one record of the property will be present. * If the property name can have multiple entries (with increasing rank) then * use the function named tripal_core_update_property_by_id * * @param $basetable * The base table for which the property should be updated. The property table * is constructed using a combination of the base table name and the suffix * 'prop' (e.g. basetable = feature then property tabie is featureprop). * @param $record_id * The foreign key of the basetable to update a property for. This should be in integer. * For example, if the basetable is 'feature' then the $record_id should be the feature_id * @param $property * The cvterm name of property to be updated * @param $cv_name * The name of the cv that the above cvterm is part of * @param $value * The value of the property to be inserted (can be empty) * @param $insert_if_missing * A boolean indicating whether a record should be inserted if one doesn't exist to update * * Note: The property to be updated is select via the unique combination of $record_id and * $property and then it is updated with the supplied value * * @return * Return True on Update/Insert and False otherwise * * @ingroup tripal_properties_api */ function tripal_core_update_property($basetable, $record_id, $property, $cv_name, $value, $insert_if_missing = 0) { // first see if the property is missing (we can't update a missing property $prop = tripal_core_get_property($basetable, $record_id, $property, $cv_name); if (count($prop)==0) { if ($insert_if_missing) { return tripal_core_insert_property($basetable, $record_id, $property, $cv_name, $value); } else { return FALSE; } } // get the foreign key for this property table $table_desc = tripal_core_get_chado_table_schema($basetable . 'prop'); $fkcol = key($table_desc['foreign keys'][$basetable]['columns']); // construct the array that will match the exact record to update $match = array( $fkcol => $record_id, 'type_id' => array( 'cv_id' => array( 'name' => $cv_name, ), 'name' => $property, ), ); // construct the array of values to be updated $values = array( 'value' => $value, ); return tripal_core_chado_update($basetable . 'prop', $match, $values); } /** * Update a property for a given base table record. This function should be * used if multiple records of the same property will be present. Also, use this * function to change the property name of an existing property. * * @param $basetable * The base table for which the property should be updated. The property table * is constructed using a combination of the base table name and the suffix * 'prop' (e.g. basetable = feature then property tabie is featureprop). * @param $record_id * The primary key of the base table. This should be in integer. * For example, if the basetable is 'feature' then the $record_id should be the featureprop_id * @param $property * The cvterm name of property to be updated * @param $cv_name * The name of the cv that the above cvterm is part of * @param $value * The value of the property to be inserted (can be empty) * * @return * Return True on Update/Insert and False otherwise * * @ingroup tripal_properties_api */ function tripal_core_update_property_by_id($basetable, $record_id, $property, $cv_name, $value) { // get the primary key for this property table $table_desc = tripal_core_get_chado_table_schema($basetable . 'prop'); $pkcol = $table_desc['primary key'][0]; // construct the array that will match the exact record to update $match = array( $pkcol => $record_id, ); // construct the array of values to be updated $values = array( 'type_id' => array( 'cv_id' => array( 'name' => $cv_name, ), 'name' => $property, ), 'value' => $value, ); return tripal_core_chado_update($basetable . 'prop', $match, $values); } /** * Deletes a property for a given base table record using the property name * * @param $basetable * The base table for which the property should be deleted. Thus to deleted a property * for a feature the basetable=feature and property is deleted from featureprop * @param $record_id * The primary key of the basetable to delete a property for. This should be in integer. * @param $property * The cvterm name describing the type of property to be deleted * @param $cv_name * The name of the cv that the above cvterm is part of * * Note: The property to be deleted is select via the unique combination of $record_id and $property * * @return * Return True on Delete and False otherwise * * @ingroup tripal_properties_api */ function tripal_core_delete_property($basetable, $record_id, $property, $cv_name) { // get the foreign key for this property table $table_desc = tripal_core_get_chado_table_schema($basetable . 'prop'); $fkcol = key($table_desc['foreign keys'][$basetable]['columns']); // construct the array that will match the exact record to update $match = array( $fkcol => $record_id, 'type_id' => array( 'cv_id' => array( 'name' => $cv_name, ), 'name' => $property, ), ); return tripal_core_chado_delete($basetable . 'prop', $match); } /** * Deletes a property using the property ID * * @param $basetable * The base table for which the property should be deleted. Thus to deleted a property * for a feature the basetable=feature and property is deleted from featureprop * @param $record_id * The primary key of the basetable to delete a property for. This should be in integer. * * @return * Return True on Delete and False otherwise * * @ingroup tripal_properties_api */ function tripal_core_delete_property_by_id($basetable, $record_id) { // get the foreign key for this property table $table_desc = tripal_core_get_chado_table_schema($basetable . 'prop'); $pkcol = $table_desc['primary key'][0]; // construct the array that will match the exact record to update $match = array( $pkcol => $record_id, ); return tripal_core_chado_delete($basetable . 'prop', $match); } /** * This function is a wrapper for adding fields to an existing form for managing properties. * Many of the chado tables have a corresponding 'prop' table (e.g. analysisprop, contactprop, * organismprop, etc) and those prop tables all have the same schema. Use this function * to add all the necessary components to a form for allowing the user to add/edit properties to * a given record. To retreive properties in hook_insert or hook_update of a node form use * use the function tripal_core_properties_form_retreive(). * * @param $form * The Drupal form array into which the properties elements will be added * @param $form_state * The corresponding form_state array for the form * @param $prop_table * The name of the property table (e.g. anlaysisprop, contactprop) * @param $id_field * The name of the ID field in the property table (e.g. analysis_id, contact_id) * @param $cv_name * The name of the controlled vocabulary that these properties are derived from * @param $available_props * An array of properties to inclde in the properties drop down. This array should * have cvterm_id's as the key and the cvterm name as the value * @param $id * The current base table ID. For example, if the property table is analysisprop then the * value should be that of the analysis_id. If the property table is contactprop then the * value should be that of the contact_id. This is the record from which currently assigned * properties will be retrieved. * @param $exclude * An optional array of cvterms to exclude when retreiving terms already saved in the database. * Use this array when properties are present but should be handled elsewhere. * For example, for contacts, the description field is stored as a property because * the actual field is only 255 characters. The 'contact_description' therefore should * not be shown in the list of properties, even if present, because it is handled by * a different form element. * @param $include * An optional array of terms to pre-populate in the form. This argument can be used to * add a default set of pre-populated properties regardless if they exist in the database * or not. The array should be of the following form: * array( * array('cvterm' => $obj1, 'value' => $val1), * array('cvterm' => $obj2, 'value' => $val2), * ... etc * ); * The 'cvterm' key should have as a value an object with these properties: 'name', 'cvterm_id', 'definition'. * @param $instructions * An optional additional set of instructions for the form properties. * @param $fset_title * A title for the property field set. The default is 'Additional Details'. * @ingroup tripal_properties_api */ function tripal_core_properties_form(&$form, &$form_state, $prop_table, $id_field, $cv_name, $available_props, $id = NULL, $exclude = array(), $include = array(), $instructions = '', $fset_title = 'Additional Details') { $d_removed = array(); // lists removed properties // if we are re constructing the form from a failed validation or ajax callback // then use the $form_state['values'] values if (array_key_exists('values', $form_state)) { $d_removed = $form_state['values']['removed']; } // if we are re building the form from after submission (from ajax call) then // the values are in the $form_state['input'] array if (array_key_exists('input', $form_state) and !empty($form_state['input'])) { $d_removed = $form_state['input']['removed']; } $form['properties'] = array( '#type' => 'fieldset', '#title' => t($fset_title), '#description' => t('You may add additional properties by selecting a property type from the dropdown and adding text. You may add as many properties as desired by clicking the add button on the right. To remove a property, click the remove button. ' . $instructions), ); $form['properties']['table'] = array( '#type' => 'markup', '#value' => '', '#prefix' => '