You are here

function commerce_checkout_form_validate in Commerce Core 7

Validate handler for the continue button of the checkout form.

This function calls the validation function of each pane, followed by the submit function if the validation succeeded. As long as one pane fails validation, we then ask for the form to be rebuilt. Once all the panes are happy, we move on to the next page.

1 string reference to 'commerce_checkout_form_validate'
commerce_checkout_form in modules/checkout/includes/commerce_checkout.pages.inc
Builds the checkout form for the given order on the specified checkout page.

File

modules/checkout/includes/commerce_checkout.pages.inc, line 288
The page and form callbacks for use in the checkout form.

Code

function commerce_checkout_form_validate($form, &$form_state) {
  $checkout_page = $form_state['checkout_page'];

  // Load a fresh copy of the order stored in the form.
  $order = commerce_order_load($form_state['order']->order_id);

  // Catch and clear already pushed messages.
  $previous_messages = drupal_get_messages();

  // Load any pre-existing validation errors for the elements.
  $form_errors = form_get_errors();
  $errors = array();

  // If we found any errors at all on the page, go ahead and mark the form as
  // failing validation. This will ensure that even form elements on the page
  // that aren't part of a checkout pane trigger validation failure.
  $form_validate = TRUE;
  if (!empty($form_errors)) {
    $form_validate = FALSE;
  }
  foreach ((array) $form_errors as $element_path => $error) {
    list($pane_id, ) = explode('][', $element_path, 2);
    $errors[$pane_id][$element_path] = $error;
  }

  // Loop through the enabled checkout panes for the current page.
  foreach (commerce_checkout_panes(array(
    'enabled' => TRUE,
    'page' => $checkout_page['page_id'],
  )) as $pane_id => $checkout_pane) {
    $validate = TRUE;

    // If any element in the pane failed validation, we mark the pane as
    // unvalidated and replay the validation messages on top of it.
    if (!empty($errors[$pane_id])) {
      $validate = FALSE;
      foreach ($errors[$pane_id] as $element_path => $message) {
        if ($message) {
          drupal_set_message($message, 'error');
        }
      }
      if (isset($previous_messages['error'])) {
        $previous_messages['error'] = array_values(array_diff($previous_messages['error'], $errors[$pane_id]));
      }
    }

    // If the pane has defined a checkout form validate handler...
    if ($callback = commerce_checkout_pane_callback($checkout_pane, 'checkout_form_validate')) {

      // Give it a chance to process the submitted data.
      $validate &= $callback($form, $form_state, $checkout_pane, $order);
    }

    // Catch and clear panes' messages.
    $pane_messages = drupal_get_messages();

    // Submit the pane if it validated.
    if ($validate && ($callback = commerce_checkout_pane_callback($checkout_pane, 'checkout_form_submit'))) {
      $callback($form, $form_state, $checkout_pane, $order);
    }

    // Generate status messages.
    $form_state['storage']['messages'][$pane_id] = array_merge_recursive($pane_messages, drupal_get_messages());

    // A failed pane makes the form fail.
    $form_validate &= $validate;
  }

  // Restore messages and form errors.
  $_SESSION['messages'] = array_merge_recursive(array_filter($previous_messages), drupal_get_messages());
  $form_errors =& drupal_static('form_set_error', array());
  $form_state['storage']['errors'] = $form_errors;
  $form_errors = array();

  // Save the updated order object and reset the order in the form cache to
  // ensure rebuilt forms use the updated order.
  commerce_order_save($order);
  $form_state['build_info']['args'][0] = $order;

  // If a pane failed validation or the form state has otherwise been altered to
  // initiate a rebuild, return without moving to the next checkout page.
  if (!$form_validate || $form_state['rebuild']) {
    $form_state['rebuild'] = TRUE;
  }
}