Explorar el Código

Converted linker_prop_adder to a TripalField class. Added validate and submit functions to the TripalField class. Updated linker_relationship field to use the new validate and submit functions

Stephen Ficklin hace 8 años
padre
commit
7e1971e600

+ 45 - 8
tripal/includes/TripalEntityUIController.inc

@@ -331,6 +331,7 @@ function tripal_view_entity($entity, $view_mode = 'full') {
    }
    else {
      field_attach_form('TripalEntity', $entity, $form, $form_state);
+
      $form['update_button'] = array(
        '#type' => 'submit',
        '#value' => t('Update'),
@@ -341,9 +342,15 @@ function tripal_view_entity($entity, $view_mode = 'full') {
        '#type' => 'submit',
        '#value' => t('Delete'),
        '#name' => 'delete_data',
-       '#weight' => 1001
+       '#weight' => 1002
      );
    }
+   $form['cancel_button'] = array(
+     '#type' => 'submit',
+     '#value' => t('Cancel'),
+     '#name' => 'cancel_data',
+     '#weight' => 1001
+   );
 
    // The entity object must be added to the $form_state in order for
    // the Entity API to work. It must have a key of the entity name.
@@ -366,24 +373,54 @@ function tripal_entity_form_ajax_callback($form, $form_state) {
   */
  function tripal_entity_form_validate($form, &$form_state) {
 
-   if (array_key_exists('clicked_button', $form_state) and
-       $form_state['clicked_button']['#name'] =='add_data') {
-     $entity = $form_state['TripalEntity'];
-     field_attach_form_validate('TripalEntity', $entity, $form, $form_state);
+   // If the user is cancelling or deleting the entity then don't validate.
+   if ($form_state['clicked_button']['#name'] =='cancel_data' or
+       $form_state['clicked_button']['#name'] =='delete_data') {
+     return;
    }
+   // For adds and updates, perform validation.
+   $entity = $form_state['TripalEntity'];
+   field_attach_form_validate('TripalEntity', $entity, $form, $form_state);
  }
 
-
  /**
   * Implements hook_submit() for the tripal_entity_form.
   */
  function tripal_entity_form_submit($form, &$form_state) {
    $entity = $form_state['TripalEntity'];
 
-   if ($form_state['clicked_button']['#name'] =='cancel') {
-     $form_state['redirect'] = "bio_data/" . $entity->id;
+   // Allow the fields to perform actions prior to submit by calling
+   // a hook_field_submit() functino.
+   $fields = field_info_instances('TripalEntity', $entity->bundle);
+   foreach ($fields as $field_name => $instance) {
+     $field = field_info_field($field_name);
+     $module = $field['module'];
+     $function = $module . '_field_submit';
+     if (function_exists($function)) {
+       // Get the items from the form_state and allow the caller to alter them.
+       $items = array();
+       $langcode = 'und';
+       field_default_extract_form_values('TripalEntity', $entity, $field,
+           $instance, $langcode, $items, $form, $form_state);
+       $function('TripalEntity', $entity, $field, $instance, $langcode, $items,
+           $form, $form_state);
+       // Copy any updated items into the $form_state 'values' array.
+       foreach ($items as $delta => $item) {
+         foreach ($item as $subfield => $value) {
+           $form_state['values'][$field_name][$langcode][$delta][$subfield] = $value;
+         }
+       }
+     }
    }
 
+   if ($form_state['clicked_button']['#name'] =='cancel_data') {
+     if ($entity) {
+      $form_state['redirect'] = "bio_data/" . $entity->id;
+     }
+     else {
+       $form_state['redirect'] = '';
+     }
+   }
    if ($form_state['clicked_button']['#name'] =='update_data' or
        $form_state['clicked_button']['#name'] =='add_data') {
 

+ 64 - 0
tripal/includes/TripalField.inc

@@ -195,6 +195,70 @@ class TripalField {
     );
   }
 
+  /**
+   *  Perform validation of the widget_form when adding or editing the entity.
+   *
+   *  Any errors encountered should be indicatd by adding a value to the $errors
+   *  array according to the instructions below.
+   *
+   *  @param $entity_type
+   *    The type of $entity.
+   *  @param $entity
+   *    The entity for the operation.
+   *  @param $field
+   *    The field structure for the operation.
+   *  @param $instance
+   *    The instance structure for $field on $entity's bundle.
+   *  @param $langcode
+   *    The language associated with $items.
+   *  @param $items
+   *    $entity->{$field['field_name']}[$langcode], or an empty array if unset.
+   *  @param $errors
+   *    The array of errors (keyed by field name, language code, and delta) that
+   *    have already been reported for the entity. The function should add its
+   *    errors to this array. Each error is an associative array with the
+   *    following keys and values:
+   *      - error: An error code (should be a string prefixed with the
+   *        module name).
+   *      - message: The human readable message to be displayed.
+   *
+   */
+  public function validate($entity_type, $entity, $field, $instance, $langcode,
+      $items, &$errors) {
+
+  }
+
+  /**
+   *  Performs extra commands when the entity form is submitted.
+   *
+   *  Drupal typically does not provide a submit hook for fields.  The
+   *  TripalField provides one to allow for behind-the-scenes actions to
+   *  occur.   This function should never be used for updates, deletes or
+   *  inserts into the storage backend. Rather, the appropriate Field Storage
+   *  implementation will take care of that. An example where this function
+   *  may be useful would be to set values in the $items array using values
+   *  of the other.
+   *
+   *  @param $entity_type
+   *    The type of $entity.
+   *  @param $entity
+   *    The entity for the operation.
+   *  @param $field
+   *    The field structure for the operation.
+   *  @param $instance
+   *    The instance structure for $field on $entity's bundle.
+   *  @param $langcode
+   *    The language associated with $items.
+   *  @param $items
+   *    $entity->{$field['field_name']}[$langcode], or an empty array if unset.
+   *  @param $form
+   *    The submitted form array.
+   *  @param $form_state.
+   *    The form state array.
+   */
+  public function submit($entity_type, $entity, $field, $instance, $langcode,
+      &$items, $form, &$form_state) {
+  }
   /**
    * Loads the field values from the underlying data store.
    *

+ 152 - 174
tripal_chado/includes/fields/chado_linker__prop_adder.inc

@@ -1,196 +1,174 @@
 <?php
-/**
- * Implements hook_info() for fields.
- *
- * This is a hook provided by the tripal_chado module for offloading the
- * hook_field_info() hook for each field to specify.
- *
- * Fields that add new fields. These fields are not shown on
- * pages.  They are avaiable to site curators when adding/updating
- * a record and allow the user to add new linker table fields.
- *
- */
-function chado_linker__prop_adder_info() {
-  return array(
-    'label' => t('Add a Property Type'),
-    'description' => t('This record may have any number of properties. Use
-          this field to first add the type.'),
-    'default_widget' => 'chado_linker__prop_adder_widget',
-    'default_formatter' => 'hidden',
-    'settings' => array(),
-    'storage' => array(
-      'type' => 'field_chado_storage',
-      'module' => 'tripal_chado',
-      'active' => TRUE
-    ),
-    'no_ui' => TRUE
-  );
-}
-/**
- * Implements hook_attach_info().
- *
- * This is a hook provided by the tripal_Chado module. It allows the field
- * to specify which bundles it will attach to and to specify thee settings.
- *
- * @param $entity_type
- * @param $entity
- * @param $term
- *
- * @return
- *   A field array
+
+class chado_linker__prop_adder extends TripalField {
+  /**
+   * @see TripalField::field_info()
+   */
+  function field_info() {
+    return array(
+      'label' => t('Add a Property Type'),
+      'description' => t('This record may have any number of properties. Use
+            this field to first add the type.'),
+      'default_widget' => 'chado_linker__prop_adder_widget',
+      'default_formatter' => 'hidden',
+      'settings' => array(),
+      'storage' => array(
+        'type' => 'field_chado_storage',
+        'module' => 'tripal_chado',
+        'active' => TRUE
+      ),
+      'no_ui' => TRUE
+    );
+  }
+  /**
+   * @see TripalField::attach_info()
  */
-function chado_linker__prop_adder_attach_info($entity_type, $bundle, $target) {
-  $field_info = array();
+  function attach_info($entity_type, $bundle, $target) {
+    $field_info = array();
+
+    $table_name = $target['data_table'];
+    $type_table = $target['type_table'];
+    $type_field = $target['field'];
+    $cv_id      = $target['cv_id'];
+    $cvterm_id  = $target['cvterm_id'];
 
-  $table_name = $target['data_table'];
-  $type_table = $target['type_table'];
-  $type_field = $target['field'];
-  $cv_id      = $target['cv_id'];
-  $cvterm_id  = $target['cvterm_id'];
+    // If the linker table does not exists then we don't want to add attach.
+    $prop_table = $table_name . 'prop';
+    if (!chado_table_exists($prop_table)) {
+      return $field_info;
+    }
 
-  // If the linker table does not exists then we don't want to add attach.
-  $prop_table = $table_name . 'prop';
-  if (!chado_table_exists($prop_table)) {
+    // Initialize the field array.
+    $field_info = array(
+      'field_name' => $prop_table,
+      'field_type' => 'chado_linker__prop_adder',
+      'widget_type' => 'chado_linker__prop_adder_widget',
+      'field_settings' => array(
+        'base_table' => $table_name,
+      ),
+      'cardinality' => 1,
+      'storage' => 'field_chado_storage',
+      'widget_settings' => array('display_label' => 1),
+      'description' => '',
+      'label' => 'Additional Properties',
+      'is_required' => 0,
+      // This feld is never visible so there are no field settings for
+      // Chado nor the semantic web.
+    );
     return $field_info;
   }
+  /**
+   * @see TripalField::widget_info()
+   */
+  function widget_info() {
+    return array(
+      'label' => t('Add a Property'),
+      'field types' => array('chado_linker__prop_adder'),
+    );
+  }
+  /**
+   * @see TripalField::widget_form()
+   */
+  function widget_form(&$widget, &$form, &$form_state,
+      $field, $instance, $langcode, $items, $delta, $element) {
 
-  // Initialize the field array.
-  $field_info = array(
-    'field_name' => $prop_table,
-    'field_type' => 'chado_linker__prop_adder',
-    'widget_type' => 'chado_linker__prop_adder_widget',
-    'field_settings' => array(
-      'base_table' => $table_name,
-    ),
-    'cardinality' => 1,
-    'storage' => 'field_chado_storage',
-    'widget_settings' => array('display_label' => 1),
-    'description' => '',
-    'label' => 'Additional Properties',
-    'is_required' => 0,
-    // This feld is never visible so there are no field settings for
-    // Chado nor the semantic web.
-  );
-  return $field_info;
-}
-/**
- * Implements hook_widget_info.
- *
- * This is a hook provided by the tripal_chado module for offloading
- * the hook_field_widget_info() hook for each field to specify.
- */
-function chado_linker__prop_adder_widget_info() {
-  return array(
-    'label' => t('Add a Property'),
-    'field types' => array('chado_linker__prop_adder'),
-  );
-}
-/**
- *
- */
-function chado_linker__prop_adder_widget(&$widget, $form, $form_state,
-    $field, $instance, $langcode, $items, $delta, $element) {
-  // This field has no value field.  Just a fieldset for adding new properties.
-  $widget['#element_validate'] = array('chado_linker__prop_adder_widget_validate');
+    // This field has no value field.  Just a fieldset for adding new properties.
+    $widget['#element_validate'] = array('chado_linker__prop_adder_widget_validate');
 
-  $widget['#type'] = 'fieldset';
-  $widget['#title'] = $element['#title'];
-  $widget['#description'] = $element['#description'];
-  $widget['#group'] = 'entity_form_vtabs';
+    $widget['#type'] = 'fieldset';
+    $widget['#title'] = $element['#title'];
+    $widget['#description'] = $element['#description'];
+    $widget['#group'] = 'entity_form_vtabs';
+
+    $widget['kvproperty_instructions'] = array(
+      '#type' => 'item',
+      '#markup' => t('You may add additional properties to this form by
+          providing a property name (from a vocabulary) in the field below
+          and clicking the "Add Property" button.  This will add a
+          new field to the form above for the property you entered.
+          In the future, this field will be present for all records
+          of this type.'),
+    );
+    $widget['value'] = array(
+      '#title' => t('Property Type'),
+      '#type' => 'textfield',
+      '#description' => t("Please enter the type of property that you want to
+          add.  As you type, suggestions will be provided."),
+      '#autocomplete_path' => "admin/tripal/storage/chado/auto_name/cvterm/",
+    );
+    $widget['kvproperty_adder_link'] = array(
+      '#type' => 'item',
+      '#markup' => '<span class="kvproperty-adder-link">' . l('Add a term', 'admin/tripal/vocab/cvterm/add', array('attributes' => array('target' => '_blank'))) . '</span>',
+    );
+    // When this button is clicked, the form will be validated and submitted.
+    // Therefore, we set custom submit and validate functions to override the
+    // default form submit.  In the validate function we set the form_state
+    // to rebuild the form so the submit function never actually gets called,
+    // but we need it or Drupal will run the default validate anyway.
+    // we also set #limit_validation_errors to empty so fields that
+    // are required that don't have values won't generate warnings.
+    $widget['kvproperty_adder_button'] = array(
+      '#value' => t('Add Property'),
+      '#type' => 'submit',
+      '#name' => 'kvproperty_adder_button',
+      '#limit_validation_errors' => array(array($field['field_name'])),
+    );
+  }
 
-  $widget['kvproperty_instructions'] = array(
-    '#type' => 'item',
-    '#markup' => t('You may add additional properties to this form by
-        providing a property name (from a vocabulary) in the field below
-        and clicking the "Add Property" button.  This will add a
-        new field to the form above for the property you entered.
-        In the future, this field will be present for all records
-        of this type.'),
-  );
-  $widget['value'] = array(
-    '#title' => t('Property Type'),
-    '#type' => 'textfield',
-    '#description' => t("Please enter the type of property that you want to
-        add.  As you type, suggestions will be provided."),
-    '#autocomplete_path' => "admin/tripal/storage/chado/auto_name/cvterm/",
-  );
-  $widget['kvproperty_adder_link'] = array(
-    '#type' => 'item',
-    '#markup' => '<span class="kvproperty-adder-link">' . l('Add a term', 'admin/tripal/vocab/cvterm/add', array('attributes' => array('target' => '_blank'))) . '</span>',
-  );
-  // When this button is clicked, the form will be validated and submitted.
-  // Therefore, we set custom submit and validate functions to override the
-  // default form submit.  In the validate function we set the form_state
-  // to rebuild the form so the submit function never actually gets called,
-  // but we need it or Drupal will run the default validate anyway.
-  // we also set #limit_validation_errors to empty so fields that
-  // are required that don't have values won't generate warnings.
-  $widget['kvproperty_adder_button'] = array(
-    '#value' => t('Add Property'),
-    '#type' => 'submit',
-    '#name' => 'kvproperty_adder_button',
-    '#submit' => array('chado_linker__prop_adder_widget_submit'),
-    '#limit_validation_errors' => array(array($field['field_name'])),
-  );
 }
 /**
  * Callback function for validating the chado_linker__prop_adder_widget.
  */
 function chado_linker__prop_adder_widget_validate($element, &$form_state) {
 
-   // Add the new field to the entity
-   if (array_key_exists('triggering_element', $form_state) and
-       $form_state['triggering_element']['#name'] == 'kvproperty_adder_button') {
+  // Add the new field to the entity
+  if (array_key_exists('triggering_element', $form_state) and
+      $form_state['triggering_element']['#name'] == 'kvproperty_adder_button') {
 
-     $form_state['rebuild'] = TRUE;
-     $field_name = $element['#field_name'];
-     $entity_type = $element['#entity']->type;
-     $bundle = $element['#entity']->bundle;
+        $form_state['rebuild'] = TRUE;
+        $field_name = $element['#field_name'];
+        $entity_type = $element['#entity']->type;
+        $bundle = $element['#entity']->bundle;
 
-     // Get the base table name from the field properties.
-     $field = field_info_field($field_name);
-     $base_table = $field['settings']['base_table'];
+        // Get the base table name from the field properties.
+        $field = field_info_field($field_name);
+        $base_table = $field['settings']['base_table'];
 
-     // Get the term for the property
-     $kvproperty = tripal_chado_get_field_form_values($field_name, $form_state);
-     $term = chado_generate_var('cvterm', array('name' => $kvproperty), $options = array('return_array' => TRUE));
+        // Get the term for the property
+        $kvproperty = tripal_chado_get_field_form_values($field_name, $form_state);
+        $term = chado_generate_var('cvterm', array('name' => $kvproperty), $options = array('return_array' => TRUE));
 
-     if (count($term) == 1) {
-       $prop_field_name = $field_name . '__' . $term[0]->cvterm_id;
+        if (count($term) == 1) {
+          $prop_field_name = $field_name . '__' . $term[0]->cvterm_id;
 
-       // The field name is the table name in this case. We want to get the
-       // primary key as this should be the field that maps th the value.
-       $schema = chado_get_schema($field_name);
-       $pkey = $schema['primary key'][0];
+          // The field name is the table name in this case. We want to get the
+          // primary key as this should be the field that maps th the value.
+          $schema = chado_get_schema($field_name);
+          $pkey = $schema['primary key'][0];
 
-       $field_info = array(
-         'field_type' => 'kvproperty',
-         'widget_type' => 'tripal_chado_kvproperty_widget',
-         'field_settings' => array(
-           'chado_table' => $field_name,
-           'chado_column' => $pkey,
-           'base_table' => $base_table,
-         ),
-         'storage' => 'field_chado_storage',
-         'widget_settings' => array(),
-         'description' => $term[0]->definition ? $term[0]->definition : '',
-         'label' => ucfirst(preg_replace('/_/', ' ', $term[0]->name)),
-         'is_required' => FALSE,
-         // All properties are unlimited.
-         'cardinality' => FIELD_CARDINALITY_UNLIMITED,
-       );
-       tripal_add_bundle_field($prop_field_name, $field_info, $entity_type, $bundle);
-     }
-     else if (count($term) > 1) {
-       form_set_error(implode('][', $element ['#parents']) . '][value', t("This term is present in multiple vocabularies. Please select the appropriate one."));
-     }
-     else {
-       form_set_error(implode('][', $element ['#parents']) . '][value', t("Please provide a property type to add."));
-     }
-   }
-}
-/**
- * Callback function for submitting the chado_linker__prop_adder_widget.
- */
-function chado_linker__prop_adder_widget_submit($element, &$form_state) {
+          $field_info = array(
+            'field_type' => 'kvproperty',
+            'widget_type' => 'tripal_chado_kvproperty_widget',
+            'field_settings' => array(
+              'chado_table' => $field_name,
+              'chado_column' => $pkey,
+              'base_table' => $base_table,
+            ),
+            'storage' => 'field_chado_storage',
+            'widget_settings' => array(),
+            'description' => $term[0]->definition ? $term[0]->definition : '',
+            'label' => ucfirst(preg_replace('/_/', ' ', $term[0]->name)),
+            'is_required' => FALSE,
+            // All properties are unlimited.
+            'cardinality' => FIELD_CARDINALITY_UNLIMITED,
+          );
+          tripal_add_bundle_field($prop_field_name, $field_info, $entity_type, $bundle);
+        }
+        else if (count($term) > 1) {
+          form_set_error(implode('][', $element ['#parents']) . '][value', t("This term is present in multiple vocabularies. Please select the appropriate one."));
+        }
+        else {
+          form_set_error(implode('][', $element ['#parents']) . '][value', t("Please provide a property type to add."));
+        }
+      }
 }

+ 199 - 135
tripal_chado/includes/fields/chado_linker__relationship.inc

@@ -226,7 +226,7 @@ class chado_linker__relationship extends TripalField {
     $widget['#fkeys'] = $schema['foreign keys'];
     $widget['#base_table'] = $base_table;
     $widget['#chado_record_id'] = $form['#entity']->chado_record_id;
-    $widget['#element_validate'] = array('chado_linker__relationship_validate');
+    //$widget['#element_validate'] = array('chado_linker__relationship_validate');
     $widget['#theme'] = 'chado_linker__relationship_widget';
     $widget['#prefix'] =  "<span id='$chado_table-$delta'>";
     $widget['#suffix'] =  "</span>";
@@ -294,7 +294,205 @@ class chado_linker__relationship extends TripalField {
       '#autocomplete_path' => "admin/tripal/storage/chado/auto_name/$base_table",
     );
   }
+  /**
+   * @see TripalField::validate()
+   */
+  function validate($entity_type, $entity, $field, $instance, $langcode, $items, &$errors) {
+
+    $field_name = $field['field_name'];
+    $field_type = $field['type'];
+    $field_table = $field['settings']['chado_table'];
+    $field_column = $field['settings']['chado_column'];
+    $base_table = $field['settings']['base_table'];
+
+    $chado_record_id = $entity->chado_record_id;
+
+    $schema = chado_get_schema($field_table);
+    $fkeys = $schema['foreign keys'];
+
+    foreach ($items as $delta => $item) {
+      $subject_id = $item[$field_table . '__subject_id'];
+      $object_id = $item[ $field_table . '__object_id'];
+      $type_id = $item[$field_table . '__type_id'];
+      $type_name = $item['type_name'];
+      $subject_name = $item['subject_name'];
+      $object_name = $item['object_name'];
+
+
+      // If the row is empty then just return, there's nothing to validate.
+      if (!$type_name and !$subject_name and !$object_name) {
+        contineu;
+      }
+
+      // Make sure we have values for all of the fields.
+      $form_error = FALSE;
+      if (!$type_name) {
+        $errors[$field['field_name']][$langcode][$delta][] = array(
+          'error' => 'chado_linker__relationship',
+          'message' => t("Please provide the type of relationship."),
+        );
+      }
+      if (!$subject_name) {
+        $errors[$field['field_name']][$langcode][$delta][] = array(
+          'error' => 'chado_linker__relationship',
+          'message' => t("Please provide the subject of the relationship."),
+        );
+      }
+      if (!$object_name) {
+        $errors[$field['field_name']][$langcode][$delta][] = array(
+          'error' => 'chado_linker__relationship',
+          'message' => t("Please provide the object of the relationship."),
+        );
+      }
+      if ($form_error) {
+        continue;
+      }
+
+      // Before submitting this form we need to make sure that our subject_id and
+      // object_ids are real values.  There are two ways to get the value, either
+      // just with the text value or with an [id: \d+] string embedded.  If the
+      // later we will pull it out.
+      $subject_id = '';
+      $fkey_rcolumn = $fkeys[$base_table]['columns']['subject_id'];
+      $matches = array();
+      if (preg_match('/\[id: (\d+)\]/', $subject_name, $matches)) {
+        $subject_id =  $matches[1];
+        $values = array($fkey_rcolumn => $subject_id);
+        $subject = chado_select_record($base_table, array($fkey_rcolumn), $values);
+        if (count($subject) == 0) {
+          $errors[$field['field_name']][$langcode][$delta][] = array(
+            'error' => 'chado_linker__relationship',
+            'message' => t("The subject record cannot be found using the specified id (e.g. [id: xx])."),
+          );
+        }
+      }
+      else {
+        $values = array('uniquename' => $subject_name);
+        $subject = chado_select_record($base_table, array($fkey_rcolumn), $values);
+        if (count($subject) == 0) {
+          $errors[$field['field_name']][$langcode][$delta][] = array(
+            'error' => 'chado_linker__relationship',
+            'message' => t("The subject record cannot be found. Please check spelling."),
+          );
+        }
+        elseif (count($subject) > 1) {
+          $errors[$field['field_name']][$langcode][$delta][] = array(
+            'error' => 'chado_linker__relationship',
+            'message' => t("The subject is not unique and therefore the relationship cannot be made."),
+          );
+        }
+      }
+
+      // Now check for a matching object.
+      $object_id = '';
+      $fkey_rcolumn = $fkeys[$base_table]['columns']['object_id'];
+      $matches = array();
+      if (preg_match('/\[id: (\d+)\]/', $object_name, $matches)) {
+        $object_id = $matches[1];
+        $values = array($fkey_rcolumn => $object_id);
+        $object = chado_select_record($base_table, array($fkey_rcolumn), $values);
+        if (count($subject) == 0) {
+          $errors[$field['field_name']][$langcode][$delta][] = array(
+            'error' => 'chado_linker__relationship',
+            'message' => t("The object record cannot be found using the specified id (e.g. [id: xx])."),
+          );
+        }
+      }
+      else {
+        $values = array('uniquename' => $object_name);
+        $object = chado_select_record($base_table, array($fkey_rcolumn), $values);
+        if (count($object) == 0) {
+          $errors[$field['field_name']][$langcode][$delta][] = array(
+            'error' => 'chado_linker__relationship',
+            'message' => t("The object record cannot be found. Please check spelling."),
+          );;
+        }
+        elseif (count($object) > 1) {
+          $errors[$field['field_name']][$langcode][$delta][] = array(
+            'error' => 'chado_linker__relationship',
+            'message' =>  t("The object is not unique and therefore the relationship cannot be made."),
+          );
+        }
+      }
+
+      // Make sure that either our object or our subject refers to the base record.
+      if ($object_id != $chado_record_id  and $subject_id != $chado_record_id) {
+        $errors[$field['field_name']][$langcode][$delta][] = array(
+          'error' => 'chado_linker__relationship',
+          'message' =>  t("Either the subject or the object in the relationship must refer to this record."),
+        );
+      }
 
+      if ($object_id == $chado_record_id  and $subject_id == $chado_record_id) {
+        $errors[$field['field_name']][$langcode][$delta][] = array(
+          'error' => 'chado_linker__relationship',
+          'message' =>  t("The subject and the object in the relationship cannot both refer to this record."),
+        );
+      }
+    }
+  }
+  /**
+   * @see TripalField::submit()
+   */
+  public function submit($entity_type, $entity, $field, $instance, $langcode,
+      &$items, $form, &$form_state) {
+        $field_name = $field['field_name'];
+    $field_type = $field['type'];
+    $field_table = $field['settings']['chado_table'];
+    $field_column = $field['settings']['chado_column'];
+    $base_table = $field['settings']['base_table'];
+
+    $chado_record_id = $entity->chado_record_id;
+
+    $schema = chado_get_schema($field_table);
+    $fkeys = $schema['foreign keys'];
+
+    foreach ($items as $delta => $item) {
+      $subject_id = $item[$field_table . '__subject_id'];
+      $object_id = $item[ $field_table . '__object_id'];
+      $type_id = $item[$field_table . '__type_id'];
+      $type_name = $item['type_name'];
+      $subject_name = $item['subject_name'];
+      $object_name = $item['object_name'];
+
+      // If the row is empty then skip this one, there's nothing to validate.
+      if (!$type_name and !$subject_name and !$object_name) {
+        continue;
+      }
+
+      // Get the subject ID.
+      $subject_id = '';
+      $fkey_rcolumn = $fkeys[$base_table]['columns']['subject_id'];
+      $matches = array();
+      if (preg_match('/\[id: (\d+)\]/', $subject_name, $matches)) {
+        $subject_id =  $matches[1];
+      }
+      else {
+        $values = array('uniquename' => $subject_name);
+        $subject = chado_select_record($base_table, array($fkey_rcolumn), $values);
+        $subject_id = $subject[0]->$fkey_rcolumn;
+      }
+
+      // Get the object ID.
+      $object_id = '';
+      $fkey_rcolumn = $fkeys[$base_table]['columns']['object_id'];
+      $matches = array();
+      if (preg_match('/\[id: (\d+)\]/', $object_name, $matches)) {
+        $object_id = $matches[1];
+      }
+      else {
+        $values = array('uniquename' => $object_name);
+        $object = chado_select_record($base_table, array($fkey_rcolumn), $values);
+        $object_id = $object[0]->$fkey_rcolumn;
+      }
+
+      // Set the IDs according to the values that were determined above.
+      $items[$delta][$field_table . '__subject_id'] = $subject_id;
+      $items[$delta][$field_table . '__object_id'] = $object_id;
+      $items[$delta][$field_table . '__type_id'] = $type_name;
+      $items[$delta][$field_table . '__rank'] = $item['_weight'];
+    }
+  }
   /**
    * @see TripalField::load()
    */
@@ -594,138 +792,4 @@ function theme_chado_linker__relationship_widget($variables) {
   return $layout;
 }
 
-/**
- *
- */
-function chado_linker__relationship_validate($element, &$form_state) {
 
-  $field_name = $element['#field_name'];
-  $delta = $element['#delta'];
-  $table_name = $element['#table_name'];
-  $fkeys = $element['#fkeys'];
-  $base_table = $element['#base_table'];
-  $chado_record_id = $element['#chado_record_id'];
-  $field = field_info_field($field_name);
-  $field_type = $field['type'];
-  $field_table = $field['settings']['chado_table'];
-  $field_column = $field['settings']['chado_column'];
-
-  // If the form ID is field_ui_field_edit_form, then the user is editing the
-  // field's values in the manage fields form of Drupal.  We don't want
-  // to validate it as if it were being used in a data entry form.
-  if ($form_state['build_info']['form_id'] =='field_ui_field_edit_form') {
-    return;
-  }
-
-  // Get the field values.
-  $subject_id = tripal_chado_get_field_form_values($field_name, $form_state, $delta, $field_table . '__subject_id');
-  $object_id = tripal_chado_get_field_form_values($field_name, $form_state, $delta, $field_table . '__object_id');
-  $type_id = tripal_chado_get_field_form_values($field_name, $form_state, $delta, $field_table . '__type_id');
-  $type_name = tripal_chado_get_field_form_values($field_name, $form_state, $delta, 'type_name');
-  $subject_name = tripal_chado_get_field_form_values($field_name, $form_state, $delta, 'subject_name');
-  $object_name = tripal_chado_get_field_form_values($field_name, $form_state, $delta, 'object_name');
-
-  // If the row is empty then just return, there's nothing to validate.
-  if (!$type_name and !$subject_name and !$object_name) {
-    return;
-  }
-
-  // Make sure we have values for all of the fields.
-  $form_error = FALSE;
-  if (!$type_name) {
-    form_set_error(implode('][', $element ['#parents']) . '][type_name',
-        t("Please provide the type of relationship."));
-  }
-  if (!$subject_name) {
-    form_set_error(implode('][', $element ['#parents']) . '][subject_name',
-        t("Please provide the subject of the relationship."));
-  }
-  if (!$object_name) {
-    form_set_error(implode('][', $element ['#parents']) . '][object_name',
-        t("Please provide the object of the relationship."));
-  }
-  if ($form_error) {
-    return;
-  }
-
-  // Before submitting this form we need to make sure that our subject_id and
-  // object_ids are real values.  There are two ways to get the value, either
-  // just with the text value or with an [id: \d+] string embedded.  If the
-  // later we will pull it out.
-  $subject_id = '';
-  $matches = array();
-  if (preg_match('/\[id: (\d+)\]/', $subject_name, $matches)) {
-    $subject_id = $matches[1];
-    tripal_chado_set_field_form_values($field_name, $form_state, $subject_id, $delta, $field_table . '__subject_id');
-  }
-  else {
-    $values = array(
-      'uniquename' => $subject_name,
-    );
-    $fkey_rcolumn = $fkeys[$base_table]['columns']['subject_id'];
-    $subject = chado_select_record($base_table, array($fkey_rcolumn), $values);
-    if (count($subject) == 0) {
-      form_set_error(implode('][', $element ['#parents']) . '][subject_name',
-          t("The subject record cannot be found. Please check spelling."));
-    }
-    elseif (count($subject) > 1) {
-      form_set_error(implode('][', $element ['#parents']) . '][subject_name',
-          t("The subject is not unique and therefore the relationship cannot be made."));
-    }
-    else {
-      $subject_id = $subject[0]->$fkey_rcolumn;
-      tripal_chado_set_field_form_values($field_name, $form_state, $subject_id, $delta, $field_table . '__subject_id');
-    }
-  }
-
-  // Now check for a matching object.
-  $object_id = '';
-  $matches = array();
-  if (preg_match('/\[id: (\d+)\]/', $object_name, $matches)) {
-    $object_id = $matches[1];
-    tripal_chado_set_field_form_values($field_name, $form_state, $object_id, $delta, $field_table . '__object_id');
-  }
-  else {
-    $values = array(
-      'uniquename' => $object_name,
-    );
-    $fkey_rcolumn = $fkeys[$base_table]['columns']['object_id'];
-    $object = chado_select_record($base_table, array($fkey_rcolumn), $values);
-    if (count($object) == 0) {
-      form_set_error(implode('][', $element ['#parents']) . '][object_name',
-          t("The object record cannot be found. Please check spelling."));
-    }
-    elseif (count($object) > 1) {
-      form_set_error(implode('][', $element ['#parents']) . '][object_name',
-          t("The object is not unique and therefore the relationship cannot be made."));
-    }
-    else {
-      $object_id = $object[0]->$fkey_rcolumn;
-      tripal_chado_set_field_form_values($field_name, $form_state, $object_id, $delta, $field_table . '__object_id');
-    }
-  }
-
-  // Make sure that either our object or our subject refers to the base record.
-  if ($object_id != $chado_record_id  and $subject_id != $chado_record_id) {
-    form_set_error(implode('][', $element ['#parents']) . '][subject_name',
-        t("Either the subject or the object in the relationship must refer to this record."));
-  }
-
-  if ($object_id == $chado_record_id  and $subject_id == $chado_record_id) {
-    form_set_error(implode('][', $element ['#parents']) . '][subject_name',
-        t("The subject and the object in the relationship cannot both refer to this record."));
-  }
-
-  // Now set the type_id to be the setting of the type_name field.
-  tripal_chado_set_field_form_values($field_name, $form_state, $type_name, $delta, $field_table . '__type_id');
-
-  // Reset the ranks of all fields based on their re-ordering in the form.
-  $schema = chado_get_schema($field_table);
-  if (array_key_exists('rank', $schema['fields'])) {
-    $weight = tripal_chado_get_field_form_values($field_name, $form_state, $delta, '_weight');
-    tripal_chado_set_field_form_values($field_name, $form_state, $weight, $delta, $field_table . '__rank');
-  }
-
- // form_set_error(implode('][', $element ['#parents']) . ']['type_name',
- //     t("Please provide the type of relationship."));
-}

+ 0 - 1
tripal_chado/includes/tripal_chado.field_storage.inc

@@ -39,7 +39,6 @@ function tripal_chado_field_storage_write($entity_type, $entity, $op, $fields) {
 
   // Convert the fields into a key/value list of fields and their values.
   $field_vals = tripal_chado_field_storage_write_merge_fields($fields, $entity_type, $entity);
-  //dpm($field_vals);
 
   // First, write the record for the base table.  If we have a record id then
   // this is an upate and we need to set the primary key.  If not, then this

+ 31 - 0
tripal_chado/includes/tripal_chado.fields.inc

@@ -326,7 +326,38 @@ function tripal_chado_field_widget_form_alter(&$element, &$form_state, $context)
   }
 }
 
+/**
+ * Implements hook_field_validate()
+ */
+function tripal_chado_field_validate($entity_type, $entity, $field, $instance,
+     $langcode, $items, &$errors) {
+  $field_type = $field['type'];
+  if ($field['storage']['type'] == 'field_chado_storage') {
+    module_load_include('inc', 'tripal_chado', 'includes/fields/' . $field_type);
+    if (preg_match('/^chado/', $field_type) and class_exists($field_type)) {
+      $field_obj = new $field_type();
+      $field_obj->validate($entity_type, $entity, $field, $instance,
+        $langcode, $items, $errors);
+    }
+  }
+}
 
+/**
+ * Implements hook_field_validate()
+ */
+function tripal_chado_field_submit($entity_type, $entity, $field, $instance,
+    $langcode, &$items, $form, &$form_state) {
+
+  $field_type = $field['type'];
+  if ($field['storage']['type'] == 'field_chado_storage') {
+    module_load_include('inc', 'tripal_chado', 'includes/fields/' . $field_type);
+    if (preg_match('/^chado/', $field_type) and class_exists($field_type)) {
+      $field_obj = new $field_type();
+      $field_obj->submit($entity_type, $entity, $field, $instance,
+          $langcode, $items, $form, $form_state);
+    }
+  }
+}
 
 /**
  * Returns a $field_info array for a field based on a database column.