The form_set_value function
This is a very useful function if for example you wish to make changes to a property on _validate, and see those changes on _submit.
Here is an example from http://drupal.org/node/51063.
Background info
On OG's invite form is a textarea called 'mails' where people may enter a list of e-mail addresses or usernames, either comma- or newline-separated:
<?php
function og_invite_form() {
$form['mails'] = array('#type' => 'textarea', '#title' => t('Email addresses or usernames'), '#description' => t('Enter up to %max email addresses or usernames. Separate multiple addresses by commas or new lines. Each will receive an invitation message from you.', array('%max' => $max)));
?>During the _validate process, the textarea input is parsed, a series of checks take place to ensure valid e-mail addresses exist:
<?php
function og_invite_validate($form_id, $form_values, $form) {
$mails = $form_values['mails'];
$mails = str_replace("\n", ',', $mails);
$emails = explode(',', $mails);
if (count($emails) > $max) {
form_set_error('mails', t("You may not specify more than %max email addresses or usernames.", array('%max' => $max)));
}
else {
$valid_emails = array();
$bad = array();
foreach ($emails as $email) {
$email = trim($email);
if (empty($email)) {
continue;
}
if (valid_email_address($email)) {
$valid_emails[] = $email;
}
else {
$account = user_load(array('name' => check_plain($email)));
if ($account->mail) {
$valid_emails[] = $account->mail;
}
else {
$bad[] = $email;
}
}
}
if (count($bad)) {
form_set_error('mails', t('invalid email address or username: '). implode(' ', $bad));
}
}
}
?>At the end of this process, we have a nice array called $valid_emails, which contains all of our valid e-mail addresses. However, we normally can't change form values during the _validate stage.
The problem
This means that when we get to our _submit function, we have to do the vast majority of this processing again:
1. Replacing the newlines with commas
2. Exploding the string into an array
3. Looping through each value
4. Trimming it and seeing if it's empty
5. Checking whether it's an e-mail or a username
What a waste, when $valid_emails is right there with all the data we need in it!
The solution
With form_set_value we can store a reference to the $valid_emails array, and then look at it when we're in _submit!
So first, add a property to the form itself to hold the valid e-mails:
<?php
og_invite_form:
$form['valid_emails'] = array('#type' => 'value', '#value' => array());
?>Next, in the validate function, after all of the processing is complete, store the value of the $valid_emails:
<?php
og_form_validate:
// ... all of that code from above ...
if (count($bad)) {
form_set_error('mails', t('invalid email address or username: '). implode(' ', $bad));
}
else {
// Store valid e-mails so we don't have to go through that looping again on submit
form_set_value($form['valid_emails'], $valid_emails);
}
}
?>Finally, in the submit function, retrieve the value:
<?php
function og_invite_submit() {
$emails = $form_values['valid_emails'];
?>And now we can just loop through them knowing that they've already been verified by the validation function.

VERSUS: _validate and _submit node hooks??
Correct me if I'm wrong (it's happened before, back in '83), but isn't this misleading for folks working with the node hooks?
hook_validate and hook_submit for nodes don't receive $form_id, $form_values, and $form... they receive a copy of or reference to the $node.
right?
I attempted the technique outlined here, but to get this pass-thru technique to work between _validate & _submit in a node module I had to register a 2nd #validate function via hook_form_alter. I don't have the page handy where I got the tip from, but somewhere within the walls of d.o.
How form_set_value() really works...
See my explanation of form_set_value() here:
http://drupal.org/node/160160#comment-820709
If this page didn't explain it for you.
Steve
A small note...
It's worth mentioning to anyone doing this for the first time that if they print_r within the validation function itself they will NOT see their form_values change. Put another way - one needs to check to see if your drupal_set_form is working in the submit function NOT the validation function.
~~~
HigherVisibility