The form_set_value function

Last modified: April 27, 2006 - 21:45

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??

emjayess - February 29, 2008 - 22:44

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...

SteveTurnbull - July 7, 2008 - 11:33

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...

Caleb G - June 26, 2008 - 18:46

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

 
 

Drupal is a registered trademark of Dries Buytaert.