validate | Eric's Drupal Blog

Content tagged with: validate

Eric's picture

Programmatically submit a webform using drupal_execute()

In this snippet, I'll show you how you can submit a webform programmatically using drupal_execute(). The first thing you'll need to do is figure out what the $form_state data looks like when the webform is submitted, so you can recreate that structure and pass it into drupal_execute().

One way to accomplish this is to add a validation/submit handler to the form using hook_form_alter() and then output the contents of the submitted data (using krumo, print_r, etc).

The following code will prepend a validation handler to the webform $form, so we can dump the submitted data to the screen:

<?php
function MYMODULE_form_alter(&$form, $form_state, $form_id) {
 
 
// define node id of webform
 
$webform_node_id = 146;
 
 
// check for form id of webform
 
if ($form_id == 'webform_client_form_' . $webform_node_id) {
 
   
// prepend a validation callback to the form
   
array_unshift($form['#validate'],
     
'_MYMODULE_form_alter_webform_' . $webform_node_id . '_validate');
 
  }
 
}
?>

And here is the validation handler which will dump the submitted data to the screen. NOTE: krumo() is available from the devel module; you could use print_r() as well:

<?php
function _MYMODULE_form_alter_webform_146_validate($form, &$form_state) {
 
// debug
 
krumo($form_state);
  die;
}
?>

Now, if I populate the webform with some data:

And submit the form, I will get the following debug output:

You'll need to mirror the structure of the submitted data when creating your $form_state variable, which will be passed into drupal_execute().

In the following function, I show how you can submit a webform programmatically. There is even additional code in there which loads a user's previously submitted data, if you care.

<?php
function MYMODULE_some_function() {

 
// define webform node id
 
$webform_node_id = 146;

 
// define user submitting the webform
 
$user_id = 2;

 
// load webform node
 
if ($node = node_load($webform_node_id)) {

   
// load module include file, per loading previously submitted webform data
   
module_load_include('inc', 'webform', 'webform_report');

   
// get submissions for user
   
$submissions = webform_get_submissions($node->nid, NULL, $user_id);

   
// get submission data ($submission) and submission id ($sid)
   
if (FALSE !== ($sid = key($submissions))) {
     
$submission = $submissions[$sid];
    }
    else {
     
$submission = NULL;
     
$sid = NULL;
    }

   
// create array of $form_state data
    // NOTE: be sure to use the debug output as a guide to make this array match!
   
$form_state = array(
     
'submitted' => true,
     
'values' => array(
       
'submission' => $submission,
       
'submitted' => array(
         
'test_field_1' => 'abc',
         
'test_field_2' => '123',
         
'test_field_3' => 'def',
        ),
       
'details' => array(
         
'email_subject' => $node->webform['email_subject'],
         
'email_from_name' => $node->webform['email_from_name'],
         
'email_from_address' => $node->webform['email_from_address'],
         
'nid' => $webform_node_id,
         
'sid' => $sid,
        ),
       
'op' => t('Submit'),
       
'submit' => t('Submit'),
       
'form_id' => 'webform_client_form_'. $webform_node_id,
      ),
    );

   
// Saves the webform data submited prior to login.
   
drupal_execute('webform_client_form_'. $webform_node_id, $form_state, $node, $submission, TRUE, FALSE);
   
  }

}
?>

gradient spacer
Eric's picture

Adding validation to the user edit form to ensure username is a valid email address

At some point you might want add validation to the user edit form to ensure username is a valid email address. You can accomplish this by adding a form_alter hook, testing for the user profile form, and adding a validation handler to the $form object.

<?php
function MYMODULE_form_alter(&$form, $form_state, $form_id) {
 
// test for the user profile edit form
 
if ($form_id == 'user_profile_form') {
   
// add another validation function to the list
   
$form['#validate'][] = '_MYMODULE_form_alter_user_profile_validate';
  }
}

// define the validation function
function _MYMODULE_form_alter_user_profile_validate($form, &$form_state) {
 
// validate the username and set a form error as necessary
 
if (!valid_email_address($form_state['values']['name']))
   
form_set_error('name', 'Username must be a valid email address.');
}
?>

gradient spacer
Eric's picture

Creating a system for capturing email subscriptions using a CCK node type, a view, and a block module

A recent task that came my way way to create the functionality to capture email addresses using a simple subscription form. Since email is not a reliable means of capturing data, I used CCK to create nodes to capture the data and a view to show the results. First, I create a CCK node type called "email_subscription" which did not have a body or any custom fields, just the title for email address. I then created a view that shows the nodes in a table. Here's the module I created that generates a block module that contains the CCK node form. The block uses the CCK node form to capture the data. When the node is created, it uses the nodeapi hook to send a conformation email. There is also a function to validate the user's email address.

<?php
function MYMODULE_subscribe_block($op='list', $delta=0) {
 
// listing of blocks, such as on the admin/block page
 
if ($op == "list") {
   
$block[0]["info"] = t('Subscribe Block');
    return
$block;
  } else if (
$op == 'view') {
   
$block['subject'] = 'Subscribe';
   
$block['content'] = _MYMODULE_subscribe_block_main();
    return
$block;
  }
}

function
_MYMODULE_subscribe_block_main() {
 
// show the cck node form
 
return drupal_get_form('email_subscription_node_form',
    array(
     
'type' => 'email_subscription',
     
'uid' => $GLOBALS['user']->uid,
     
'name' => $GLOBALS['user']->name,
    )
  );
}

function
MYMODULE_subscribe_form_alter($form_id, &$form) {
  if (
$form_id == 'email_subscription_node_form') {
   
// remove preview button
   
unset($form['preview']);

   
// add custom validation
   
$form['#validate'] = array_merge(array('_MYMODULE_subscribe_node_form_validate' => array()), $form['#validate']);
  }
}

function
_MYMODULE_subscribe_node_form_validate($form_id, $form_values, $form) {
 
// validate title as email address
 
if (!valid_email_address($form_values['title'])) form_set_error('title', 'Email is not valid.');

 
// get list of already submitted emails
 
$sql = "select title from {node} where type = 'email_subscription'";

 
// if editing an existing node:
 
if ($form_values['nid']) $sql .= " and title!='" . db_escape_string($form_values['title']) . "'";

 
$resource = db_query($sql);
 
$results = array();
  while (
$row = db_fetch_array($resource)) $results[] = $row['title'];

 
// ensure email address has not already been subscribed
 
if (in_array($form_values['title'],$results)) form_set_error('title', 'Email has already been subscribed.');

}

function
MYMODULE_subscribe_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  if (
$node->type == 'email_subscription' && $op=='insert') {
   
// send email to user
   
mail($node->title, variable_get('site_name') . ' Subscription', 'Thank you for subscribing!', "From: " . variable_get('site_mail'));
  }
}
?>

gradient spacer
Eric's picture

Creating a multipage form using the Forms API

Recently I've been struggling with creating a multi-step CCK node form in Drupal 5. I was able to implement a solution that used a combination of form_alter and jQuery, but due to the amount of jQuery, it was too slow. I then attempted the same functionality in Drupal 6, but due to the number of changes in the Forms API, I decided to take a step back. Here's my first successful attempt at creating a multi-step form using a Drupal 6 module and the Forms API. The following code adds the ability to jump to any step of the form, save at any point, and dynamically creates steps based on the number of fieldsets. My next step will be transposing this code to work with a CCK node form.

Screenshot:

<?php
function multipage_menu() {
 
$items = array();
   
 
$items['multiStepForm'] = array(
   
'title' => t('Multi Step Form'),
   
'page callback' => 'drupal_get_form',
   
'page arguments' => array('multipage_test_form'),
   
'access arguments' => array('access content'),
  );
   
  return
$items;   
}

function
multipage_test_form(&$form_state) {

 
// enable/disable debugging output
 
$form_state['storage']['#navigation']['debugging'] = false;
   
 
// per debugging
 
if ($form_state['storage']['#navigation']['debugging']) echo "<HR>LOADING FUNCTION: multipage_test_form<HR>";
   
 
// ensure step is set in storage
 
if (empty($form_state['storage']['#navigation']['step'])) {
   
$form_state['storage']['#navigation']['step'] = 1;
  } elseif (
$form_state['storage']['#navigation']['newStep']) {
   
// if the form has been submitted, check for a new step
   
$form_state['storage']['#navigation']['step'] = $form_state['storage']['#navigation']['newStep'];
    unset (
$form_state['storage']['#navigation']['newStep']);
  }
   
 
$form = array();
   
 
// add form fields
 
_multipage_test_form_add_fields($form, $form_state);
   
 
// calculate max number of steps
 
_multipage_test_form_max_steps($form, $form_state);

 
// create tabs
 
_multipage_test_form_create_tabs($form, $form_state);
   
 
// remove form fields per step
 
_multipage_test_form_remove_fields($form, $form_state);

 
// add tabs to form
 
_multipage_test_form_add_tabs($form, $form_state);
   
 
// add buttons to form
 
_multipage_test_form_add_buttons($form, $form_state);
   
  return
$form;
}

function
_multipage_test_form_add_fields(&$form, &$form_state) {
   
 
// per debugging
 
if ($form_state['storage']['#navigation']['debugging']) echo "<hr>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ADDING FIELDS<hr>";
   
 
// Fieldset A
   
 
$form['fieldset_a'] = array(
   
'#type' => 'fieldset',
   
'#title' => t('Fieldset A'),
  );
   
 
$form['fieldset_a']['textfield_a1'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Textfield A1'),
   
'#default_value' => $form_state['storage']['textfield_a1'],
  );

 
$form['fieldset_a']['textfield_a2'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Textfield A2'),
   
'#default_value' => $form_state['storage']['textfield_a2'],
  );

 
$form['fieldset_a']['textfield_a3'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Textfield A3'),
   
'#default_value' => $form_state['storage']['textfield_a3'],
  );
   
 
// Fieldset B
   
 
$form['fieldset_b'] = array(
   
'#type' => 'fieldset',
   
'#title' => t('Fieldset B'),
  );
   
 
$form['fieldset_b']['textfield_b1'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Textfield B1'),
   
'#default_value' => $form_state['storage']['textfield_b1'],
  );
   
 
$form['fieldset_b']['textfield_b2'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Textfield B2'),
   
'#default_value' => $form_state['storage']['textfield_b2'],
  );

 
$form['fieldset_b']['textfield_b3'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Textfield B3'),
   
'#default_value' => $form_state['storage']['textfield_b3'],
  );
   
 
// Fieldset C
   
 
$form['fieldset_c'] = array(
   
'#type' => 'fieldset',
   
'#title' => t('Fieldset C'),
  );
   
 
$form['fieldset_c']['textfield_c1'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Textfield C1'),
   
'#default_value' => $form_state['storage']['textfield_c1'],
  );
   
 
$form['fieldset_c']['textfield_c2'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Textfield C2'),
   
'#default_value' => $form_state['storage']['textfield_c2'],
  );

 
$form['fieldset_c']['textfield_c3'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Textfield C3'),
   
'#default_value' => $form_state['storage']['textfield_c3'],
  );

 
// Fields not in a fieldset
   
 
$form['textfield_d1'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Textfield D1'),
   
'#default_value' => $form_state['storage']['textfield_d1'],
  );
   
 
$form['textfield_d2'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Textfield D2'),
   
'#default_value' => $form_state['storage']['textfield_d2'],
  );
   
 
$form['textfield_d3'] = array(
   
'#type' => 'textfield',
   
'#title' => t('Textfield D3'),
   
'#default_value' => $form_state['storage']['textfield_d3'],
  );
  
}

function
_multipage_test_form_max_steps($form, &$form_state) {
   
 
// calculate max stpes if empty
 
if (empty($form_state['storage']['#navigation']['maxSteps'])) {
    
$fieldsetCount = 0;
    
$otherFields = false;
       
   
// loop through form elements
   
foreach ($form as $k => $v) {
     
// check for fieldset
     
if (substr($k,0,9)=='fieldset_' && is_array($v) && $v['#type']=='fieldset') {
       
$fieldsetCount++;
      } else {
       
$otherFields = true;   
      }
    }
       
   
// if there are other fields, increment max steps
   
if ($otherFields) {
     
$fieldsetCount++;
     
$form_state['storage']['#navigation']['otherFields'] = true;
    }
       
   
// add count to storage
   
$form_state['storage']['#navigation']['maxSteps'] = $fieldsetCount;

  }
}

function
_multipage_test_form_create_tabs(&$form, &$form_state) {

 
// per debugging
 
if ($form_state['storage']['#navigation']['debugging']) echo "<hr>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;CREATING TABS<hr>";
   
 
// create list of tabs if not set in storage
 
if (empty($form_state['storage']['#navigation']['tabs'])) {
   
$tabCount = 0;
   
$tabs = array();
   
   
// check for other fields
   
if ($form_state['storage']['#navigation']['otherFields']) {
     
$tabsCount++;
     
$tabs[$tabsCount] = "Start";
    }
       
   
// loop through form items
   
foreach ($form as $k => $v) {
      if (
substr($k,0,9)=='fieldset_' && is_array($v) && $v['#type']=='fieldset') {
       
$tabsCount++;
       
$tabs[$tabsCount] = $v['#title'];
      }
    }
       
   
// add tabs to storage
   
$form_state['storage']['#navigation']['tabs'] = $tabs;   
       
  }
  
}

function
_multipage_test_form_remove_fields(&$form, &$form_state) {

 
// per debugging
 
if ($form_state['storage']['#navigation']['debugging']) echo "<HR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;REMOVING FIELDS<HR>";
   
 
// set fieldset counter based on otherfields
 
if ($form_state['storage']['#navigation']['otherFields']) {
   
$fieldsetCount = 1;
  } else {
   
$fieldsetCount = 0;   
  }
   
 
// loop though form fields
 
foreach ($form as $k => $v) {

   
// ensure this form item is a fieldset
   
if (substr($k,0,9)=='fieldset_' && is_array($v) && $v['#type']=='fieldset') {

     
// increment count of fieldsets
     
$fieldsetCount++;

     
// unset fieldset
     
if ($form_state['storage']['#navigation']['step'] != $fieldsetCount) unset($form[$k]);
       
    } elseif (
is_array($v) && $form_state['storage']['#navigation']['otherFields'] && $form_state['storage']['#navigation']['step']>1) {
     
// unset field
     
unset($form[$k]);
    }
       
  }
   
}

function
_multipage_test_form_add_tabs(&$form, $form_state) {

 
// per debugging
 
if ($form_state['storage']['#navigation']['debugging']) echo "<HR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ADDING TABS<HR>";
   
 
$tabsArray = array();
 
$tabsCount = 0;
   
 
// loop through tabs and create buttons for each one
 
foreach ($form_state['storage']['#navigation']['tabs'] as $k => $v) {
   
$tabsCount++;
   
$tabsArray['tab_'.$k] = array(
     
'#type' => 'submit',
     
'#value' => t($v),
     
'#attributes' => array(
       
'class' => 'tabs' . ($tabsCount == $form_state['storage']['#navigation']['step'] ? ' active' : '')
      ),
    );
  }
   
 
// add tab buttons to beginning of form
 
$form = array_merge($tabsArray, $form);
   
}

function
_multipage_test_form_add_buttons(&$form, &$form_state) {

 
// per debugging
 
if ($form_state['storage']['#navigation']['debugging']) echo "<HR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;ADDING BUTTONS<HR>";
   
 
// add previous button
 
if ($form_state['storage']['#navigation']['step']>1) {
   
$form['previous'] = array(
     
'#type' => 'submit',
     
'#value' => t('Previous'),
    );       
  }
   
 
// add next button
 
if ($form_state['storage']['#navigation']['step']<$form_state['storage']['#navigation']['maxSteps']) {
   
$form['next'] = array(
     
'#type' => 'submit',
     
'#value' => t('Next'),
    );       
  }

 
// add save button
 
$form['submit'] = array(
   
'#type' => 'submit',
   
'#value' => t('Save'),
  );
   
}

function
multipage_test_form_validate($form, &$form_state) {

 
// per debugging
 
if ($form_state['storage']['#navigation']['debugging']) echo "<hr>FORM VALIDATED<hr>";

}

function
multipage_test_form_submit($form, &$form_state) {

 
// per debugging
 
if ($form_state['storage']['#navigation']['debugging']) echo "<hr>FORM SUBMITTED<hr>";
   
 
// loop through submitted form values
 
foreach ($form_state['values'] as $k => $v) {
   
// add certain fields to storage
   
if (substr($k, 0, 10)=='textfield_') {
     
$form_state['storage'][$k] = $v;
    }
  }
   
 
// handle button action
 
switch ($form_state['clicked_button']['#value']) {
    case
'Previous':
           
     
// set the state to rebuild
     
$form_state['rebuild'] = TRUE;
           
     
// set new step
     
if ($form_state['storage']['#navigation']['step']>1) {
       
$form_state['storage']['#navigation']['newStep'] = $form_state['storage']['#navigation']['step']-1;
      }
           
      break;
       
    case
'Next':
           
     
// set the state to rebuild
     
$form_state['rebuild'] = TRUE;
           
     
// set new step
     
if ($form_state['storage']['#navigation']['step']<$form_state['storage']['#navigation']['maxSteps']) {
       
$form_state['storage']['#navigation']['newStep'] = $form_state['storage']['#navigation']['step']+1;
      }
           
      break;
       
    case
'Save':
     
// TODO
     
break;
           
   
// tabs
   
default:
           
     
// check if the button value maps to a tab
     
$key = array_search($form_state['clicked_button']['#value'], $form_state['storage']['#navigation']['tabs']);
      if (
$key) {
       
$form_state['storage']['#navigation']['newStep'] = $key;
      }
           
      break;
  }
   
}
?>

gradient spacer
Eric's picture

Adding custom validation to a CCK node type form

Here is a quick code snippet that enables you to add your own custom validation to a CCK node type form.

<?php
function MYMODULE_form_alter($form_id, &$form) {
 
// create a list of node types that require custom validation
 
$nodeTypes = array(
   
'MYNODETYPE1',
   
'MYNODETYPE2',
  );
   
 
// check if the form id is a node form, and if it exists in the above array
 
if (substr($form_id,-10)=='_node_form' && in_array(substr($form_id, 0, strlen($form_id)-10), $nodeTypes)) {
   
$form['#validate'] = array_merge(array('_MYMODULE_node_form_validate' => array()), $form['#validate']);
  }
}

function
_MYMODULE_node_form_validate($form_id, $form_values, $form)
{
 
// DEBUG: use print_r($form_values) to see what has been submitted
  // TODO: check for errors here, and use form_set_error() as necessary

  // for example:
 
if ($form_values['MYFIELD'][0]['value'] == 'SOMETHING NAUGHTY') {
   
form_set_error('MYFIELD', 'MY CUSTOM ERROR MESSAGE');
  }

}
?>

gradient spacer Syndicate content