Browse Source

API: Removed api module and re-instated the tripal_core dbxref/relationship apis, moved the new properties api into the tripal_core.properties.api.inc file with yet again new names. Not backwards compatible

Lacey Sanderson 11 years ago
parent
commit
b2d20ff7b2

+ 8 - 7
tripal_api/tripal_api.module

@@ -5,22 +5,22 @@
  */
 
 // Chado Query API: Functions to query (select/insert/update/delete) from chado
-require_once 'chado_query_api/tripal_api.chado_query.manage_properties.inc';
+//require_once 'chado_query_api/tripal_api.chado_query.manage_properties.inc';
 
 // Chado Node API: Functions to help standardize creating nodes for chado tables
-require_once 'chado_node_api/tripal_api.chado_node.properties.inc';
-require_once 'chado_node_api/tripal_api.chado_node.references.inc';
-require_once 'chado_node_api/tripal_api.chado_node.relationships.inc';
+//require_once 'chado_node_api/tripal_api.chado_node.properties.inc';
+//require_once 'chado_node_api/tripal_api.chado_node.references.inc';
+//require_once 'chado_node_api/tripal_api.chado_node.relationships.inc';
 
 // DEPRECATED Function Wrappers
-require_once 'DEPRECATED/tripal-2.0_pre-release.inc';
+//require_once 'DEPRECATED/tripal-2.0_pre-release.inc';
 
 /**
  * Implements hook_theme().
  * Registers template files/functions used by this module.
  *
  * @ingroup tripal_core
- */
+ *
 function tripal_api_theme($existing, $type, $theme, $path) {
   return array(
 
@@ -42,4 +42,5 @@ function tripal_api_theme($existing, $type, $theme, $path) {
       'render element' => 'element',
     ),
   );
-}
+}
+*/

+ 571 - 121
tripal_core/api/tripal_core.properties.api.inc

@@ -19,7 +19,7 @@
     //    form elements (e.g. buttons) and the form is being rebuilt but has not yet
     //    been validated
     //
-    // The properties elements added by this function do use AJAX calls from buttons,
+    // The reference elements added by this function do use AJAX calls from buttons,
     // therefore, it is important to check for form values in the $form_state['values']
     // for case #2 above, and in the $form_state['input'] for case #3.
     // See the chado analysis node form for an example.
@@ -27,68 +27,21 @@
 
     // Next, add in all the form array definition particular to your node type
 
-    // To add in the properties form elements, you first need to prepare the arguments
-    // for the function call.  One inportant argument is a list of properties that
-    // will be made avaialble for the user to select from.  You should query the
-    // database to retrieve the applicable terms from the cvterm table and store them in an array
-    // of where the cvterm.cvterm_id field is the key and the cvterm.name is the value.
-    // these terms should all be from the same vocabulary.
-    $properties = array();
-    $properties[] = 'Select a Property';
-    $sql = "
-      SELECT DISTINCT CVT.cvterm_id, CVT.name, CVT.definition
-      FROM  {cvterm} CVT
-        INNER JOIN {cv} CV ON CVT.cv_id = CV.cv_id
-      WHERE
-        CV.name = :ontology_name AND
-        NOT CVT.is_obsolete = 1
-      ORDER BY CVT.name ASC
-    ";
-
-    $ontology_name = 'name_of_proptype_ontology';  //you need to set this variable with the cv.name of the ontology governing your prop tables type_id
-    $prop_types = chado_query($sql, array(':ontology_name' => $ontology_name));
-    while ($prop = $prop_types->fetchObject()) {
-      $properties[$prop->cvterm_id] = $prop->name;
-    }
+    // To add in the chado properties form elements, you first need to prepare the arguments
+    // for the function call.
 
-    // the properties form will add a select dropdown of terms containing the items in the $properties array
-    // constructed above, but it will also pre-populate rows of properties that already are associated
-    // with the object.  If you would like to pre-populated properties regardless if they exist in the database
-    // or not, you can create an $include array which has the following format:
-    //     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'.
-    $include = array();
-
-    // sometimes a property exists in the database and is properly associated with the object, but we do
-    // not want it to appear in the list of properties that are pre-populated. It may be handled in some
-    // other way.  For example, for contacts, the description field is stored as a property because
-    // the actual contact.description field is only 255 characters. The 'contact_description' property should
-    // not be shown in the list of properties, even if present, because it is handled by
-    // a different form element.  This array holds the value of the cvterm.name column of the cvterms
-    // to exclude
-    $exclude = array();
-
-    // the instructions argument provides additional instructions to the user beyond the default instructions.
-    $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") . ".");
-
-    // Finally, and add the properties form elements to 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
+    $details = array(
+      'property_table' => 'example_property',      // the name of the table linking additional properties to this node
+      '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
+      '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
+    tripal_api_chado_node_properties_form($form, $form_state, $details);
+
     return $form;
   }
 
@@ -103,37 +56,15 @@
 
       // Add to any other tables needed
 
-      // Add each property (exampleprop table). The tripal_core_properties_form_retrieve()
-      // function retrieves all of the properties and returns them in an array of the format:
-      //
-      // $properties[<property name>][<rank>] = <value
-      //
-      // This array can then be used for inserting or updating properties using the API call
-      //   tripal_hook_insert_property()
-      //
-      // 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 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
@@ -147,38 +78,16 @@
 
       // 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
+      // 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
       );
 
-      // 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
 
   }
@@ -514,3 +423,544 @@ function tripal_core_delete_property_by_id($basetable, $record_id) {
 
   return tripal_core_chado_delete($basetable . 'prop', $match);
 }
+
+/**
+ * @section
+ * Properties Form to be added to node forms
+ */
+
+/**
+ * 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 needed by this form. Required Keys are:
+ *     - property_table: the name of the property linking table (ie: featureprop)
+ *     - base_foreign_key: the name of the foreign key linking this table to the non-property 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)
+ *   Require ONE of the following:
+ *     The controlled vocabulary governing the property types
+ *       -cv_id: the unique key from the cv table
+ *       -cv_name: the cv.name field uniquely identifying the controlled vocab
+ *   Optional keys include:
+ *     - fieldset_title: the non-translated title for this fieldset
+ *     - additional_instructions: a non-translated string providing additional instructions
+ */
+function chado_node_properties_form(&$form, &$form_state, $details) {
+
+  // Set Defaults for optional fields
+  $details['fieldset_title'] = 'Properties';
+  $details['additional_instructions'] = '';
+
+  // Get Property Types for the Select List
+  if (isset($details['cv_name'])) {
+    $property_options = array();
+    $property_options[] = 'Select a Property';
+    $sql = "
+      SELECT DISTINCT CVT.cvterm_id, CVT.name, CVT.definition
+      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;
+    }
+  } elseif (isset($details['cv_id'])) {
+    $property_options = array();
+    $property_options[] = 'Select a Property';
+    $sql = "
+      SELECT DISTINCT CVT.cvterm_id, CVT.name, CVT.definition
+      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;
+    }
+  }
+
+  // the fieldset of the property elements
+  $form['properties'] = array(
+    '#type' => 'fieldset',
+    '#title' => t($details['fieldset_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.
+      To add additional properties to the drop down. ' . $details['additional_instructions']),
+    '#prefix' => "<div id='properties-fieldset'>",
+    '#suffix' => '</div>'
+  );
+
+  // 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' => '<div id="tripal-generic-edit-properties-table">',
+    '#suffix' => '</div>',
+    '#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) 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.
+   *
+   * 2) 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 {
+    if (isset($details['cv_name'])) {
+      $existing_properties = chado_query(
+        "SELECT CVT.cvterm_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['base_foreign_key'] . " = :base_key_value AND
+        CV.name = '" .$details['cv_name']. "'
+        ORDER BY CVT.name, PP.rank",
+         array(':base_key_value' => $details['base_key_value'])
+      );
+    } elseif (isset($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['base_foreign_key'] . " = :base_key_value AND
+        CV.cv_id = '" .$details['cv_id']. "'
+        ORDER BY CVT.name, PP.rank",
+         array(':base_key_value' => $details['base_key_value'])
+      );
+    }
+  }
+
+  /* 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 NULL if it doesn't yet exist],
+   *     'value' => [the BASEprop.value value],
+   *     'rank' => [the BASEprop.rank value],
+   *   ),
+   * );
+   *
+   * OR
+   * Populated from the database:
+   * $existing_property = array(
+   *   0 => array(
+   *     'property_id' => [the property.property_id value, or NULL if it doesn't yet exist],
+   *     '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.
+   */
+  foreach ($existing_properties as $property) {
+
+    $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->rank]['#type'] = 'markup';
+    $form['properties']['property_table'][$property->type_id][$property->rank]['#value'] = '';
+
+    $form['properties']['property_table'][$property->type_id][$property->rank]['prop_type_id'] = array(
+      '#type' => 'hidden',
+      '#value' => $property->type_id
+    );
+
+    $form['properties']['property_table'][$property->type_id][$property->rank]['prop_value'] = array(
+      '#type' => 'hidden',
+      '#value' => $property->value
+    );
+
+    $form['properties']['property_table'][$property->type_id][$property->rank]['property_id'] = array(
+      '#type' => 'hidden',
+      '#value' => $property->property_id
+    );
+
+    $form['properties']['property_table'][$property->type_id][$property->rank]['type'] = array(
+      '#type' => 'markup',
+      '#markup' => $property->type_name
+    );
+
+    $form['properties']['property_table'][$property->type_id][$property->rank]['value'] = array(
+      '#type' => 'markup',
+      '#markup' => $property->value
+    );
+
+    $form['properties']['property_table'][$property->type_id][$property->rank]['rank'] = array(
+      '#type' => 'markup',
+      '#markup' => $property->rank
+    );
+    // remove button
+    $form['properties']['property_table'][$property->type_id][$property->rank]['property_action'] = array(
+      '#type' => 'submit',
+      '#value' => t('Remove'),
+      '#name' => "property_remove-".$property->type_id.'-'.$property->rank,
+      '#ajax' => array(
+        'callback' => "chado_node_properties_form_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_node_properties_form_remove_button_validate'),
+      '#submit' => array('chado_node_properties_form_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']
+      )
+    );
+  }
+
+  // Form elements for adding a new property
+  //---------------------------------------------
+  $form['properties']['property_table']['new'] = array(
+    '#type' => 'markup',
+    '#prefix' => '<span class="addtl-properties-add-new-property">',
+    '#suffix' => '</span>'
+  );
+
+  $form['properties']['property_table']['new']['type'] = array(
+    '#type' => 'select',
+    '#options' => $property_options, // Set at top of form
+  );
+
+  $form['properties']['property_table']['new']['value'] = array(
+    '#type' => 'textfield',
+  );
+
+  // add button
+  $form['properties']['property_table']['new']['property_action'] = array(
+    '#type' => 'submit',
+    '#value' => t('Add'),
+    '#name' => "property-add",
+    '#ajax' => array(
+      'callback' => "chado_node_properties_form_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_node_properties_form_add_button_validate'),
+    '#submit' => array('chado_node_properties_form_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_node_properties_form
+ */
+function chado_node_properties_form_add_button_validate($form, &$form_state) {
+
+  // Ensure the type_id is supplied & Valid
+  $cvterm = tripal_core_chado_select(
+    'cvterm',
+    array('cvterm_id', 'name'),
+    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;
+  }
+
+  // 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_node_properties_form
+ *
+ * Create an array of properties in the form state. This array will then be
+ * used to rebuild the form in subsequent builds
+ */
+function chado_node_properties_form_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_node_properties_form_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'],
+    'property_id' => NULL,
+    'value' => $form_state['values']['property_table']['new']['value'],
+    'rank' => '0',
+  );
+
+  // get max rank
+  $rank = tripal_core_get_max_chado_rank(
+    $details['property_table'],
+    array(
+      $details['base_foreign_key'] => $details['base_key_value'],
+      'type_id' => $property['type_id']
+    )
+  );
+  $property['rank'] = strval($rank + 1);
+
+  $key = $property['type_id'] . '-' . $property['rank'];
+  $form_state['chado_properties'][$key] = (object) $property;
+
+  $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_node_properties_form
+ */
+function chado_node_properties_form_remove_button_validate($form, $form_state) {
+  // No Validation needed for remove
+}
+
+/**
+ * Remove the correct property from the form
+ * Called by the many remove buttons in chado_node_properties_form
+ */
+function chado_node_properties_form_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_node_properties_form_create_property_formstate_array($form, $form_state);
+  }
+
+  // remove the specified property from the form property table
+  if(preg_match('/property_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]);
+    }
+  }
+
+  $form_state['rebuild'] = TRUE;
+}
+
+/**
+ * Ajax function which returns the section of the form to be re-rendered
+ */
+function chado_node_properties_form_ajax_update($form, $form_state) {
+  return $form['properties']['property_table'];
+}
+
+/**
+ * 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],
+ *   ),
+ * );
+ */
+function chado_node_properties_form_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 $rank) {
+          $element = $form['properties']['property_table'][$type_id][$rank];
+          $property = array(
+            'type_id' => $element['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['rank'];
+          $form_state['chado_properties'][$key] = (object) $property;
+      }
+    }
+  }
+}
+
+/**
+ * Function to theme the add/remove properties form into a table
+ */
+function theme_chado_node_properties_form_table($variables) {
+  $element = $variables['element'];
+
+  $header = array(
+    'type' => t('Type'),
+    'value' => t('Value'),
+    'rank' => t('Rank'),
+    'property_action' => t('Actions'),
+  );
+
+  $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();
+        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[<type_id>][<rank>] = <value>
+ *
+ * This array can then be used for inserting or updating properties
+ *
+ * @param $node
+ *
+ * @return
+ *   A property array
+ *
+ * @ingroup tripal_properties_api
+ */
+function chado_node_properties_form_retreive($node) {
+  $properties = array();
+  foreach ($node->property_table as $type_id => $elements) {
+    if ($type_id != 'new' AND $type_id != 'details') {
+      foreach ($elements as $rank => $element) {
+        $properties[$type_id][$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)
+ */
+function chado_node_properties_form_update_properties($node, $details) {
+
+  // First remove existing property links
+  tripal_core_chado_delete($details['property_table'], array($details['foreignkey_name'] => $details['foreignkey_value']));
+
+  // Add back in property links and insert properties as needed
+  $properties = chado_node_properties_form_retreive($node);
+  foreach ($properties as $type_id => $ranks) {
+    foreach ($ranks as $rank => $value) {
+
+      $success = tripal_core_chado_insert(
+        $details['property_table'],
+        array(
+          $details['foreignkey_name'] => $details['foreignkey_value'],
+          'type_id' => $type_id,
+          'value' => $value,
+          'rank' => $rank
+        )
+      );
+
+      if (!$success) {
+        watchdog(
+          'tripal_' . $details['base_table'],
+          $details['base_table'] . ' Insert: Unable to insert property type_id %cvterm with value %value.',
+          array('%cvterm' => $type_id, '%value' => $value),
+          WATCHDOG_ERROR
+        );
+      }
+
+    }
+  }
+}

+ 1 - 2
tripal_core/tripal_core.info

@@ -6,5 +6,4 @@ package = Tripal
 version = 7.x-2.0-beta1
 configure = admin/tripal
 
-dependencies[] = views
-dependencies[] = tripal_api
+dependencies[] = views

+ 3 - 3
tripal_core/tripal_core.module

@@ -42,9 +42,9 @@ require_once "api/tripal_core_chado_nodes.api.inc";
 require_once "api/tripal_core_custom_tables.api.inc";
 require_once "api/tripal_core_jobs.api.inc";
 require_once "api/tripal_core_mviews.api.inc";
-//require_once "api/tripal_core.properties.api.inc";
-//require_once "api/tripal_core.database_references.api.inc";
-//require_once "api/tripal_core.relationships.api.inc";
+require_once "api/tripal_core.properties.api.inc";
+require_once "api/tripal_core.database_references.api.inc";
+require_once "api/tripal_core.relationships.api.inc";
 
 require_once "includes/jobs.inc";
 require_once "includes/mviews.inc";