I've added a comment to the documentation for form_set_value with my findings from the last few hours. I though you might want the code example. I'll copy it at the end of this post so you can review more quickly, and merge in an example if you like. I think you may want to pay special attention to the forum post I linked. There's a lot of different keywords from search engines hitting it.
I hope I help someone with this.

Cheers, Lance!

______________________________
Having fought with this for a couple hours now, I thought I'd leave notes of what I found here.
Before I begin:
http://drupal.org/node/160160 is unclear, but is the top result after this page on search engines due to length. This page may need to be updated if the proper documentation can not be understood from this page.

When using drupal 6, this is the process you must use:

Optional

function hook_form(){
//... Previous Code

// You *can* (and should) declare a placeholder for the value to be inserted into later.
$form['placeholder'] = array(
 '#type' => 'value'
 ,'#value' = > NULL // Placeholder value. Meaningless
);
//... Other Code
}

Required

Because the form_set_value function requires more arguments than standard hook_validate functions provide, you must use hook_form_alter to do custom validation for your form:

function hook_form_alter(&$form, $form_state, $form_id){
 if ($form_id == '{node_type}_node_form') {
  $form['#validate'][] = 'hook_validate_custom';
 }

With the form set to validate through your new function, create it. Note that $form_state must be a reference.

hook_validate_custom($form, &$form_state){
 // ... Validation Code
 form_set_value( array('#parents' => array('array_key_parent', 'array_key_to_replace')) , $value, $form_state);
 // ... Other Code
}

Sorry for the inline array.
Here's a breakdown of the three parameters you must pass in:

  1. An array with one item: '#parents'. '#parents' is another array. '#parents' should be the arrays keys needed to reach the form value you want to replace. For instance:
    $first_parameter = array(
     '#parents' => array(
      'first_key_in_path'
      ,'second_key_in_path'
      ,'key_to_replace' // Always the last one. *Will* create if it doesn't exist.
     ) 
    );
    
  2. The value you want inserted.
  3. $form_state
Support from Acquia helps fund testing for Drupal Acquia logo

Comments

jhodgdon’s picture

I took a look at this example... So I'm sorry, but I am unsure what you are trying to accomplish here, and which documentation you would like to see changed. Can you please explain?

a) What is your hook_form() implementation really doing? I don't see that being used anywhere else in your example.

b) The documenation on http://api.drupal.org/api/function/form_set_value already says:

Since $form_state['values'] can either be a flat array of values, or a tree of nested values, some care must be taken when using this function. Specifically, $form_item['#parents'] is an array that describes the branch of the tree whose value should be updated. For example, if we wanted to update $form_state['values']['one']['two'] to 'new value', we'd pass in $form_item['#parents'] = array('one', 'two') and $value = 'new value'.

It looks to me like it explains how to set $parents... what more is your example doing that needs to be explained better? Is it just that you think it should explain how to add a validation function using hook_form_alter? If so, that's probably a good idea.

jhodgdon’s picture

Title: Documentation problem with form_set_value » form_set_value() documentation needs more detail
Version: 6.x-dev » 7.x-dev
Status: Active » Needs review
FileSize
2.79 KB

Assuming that what is wanted is more detail added on how to define a validation function, here's a patch, which I think also explains better how/where to call form_set_value.

Patch is against Drupal 7. If accepted, should be back ported to Drupal 6.

I also recommend that the comment http://api.drupal.org/api/function/form_set_value#comment-49 be removed if this patch is committed (and maybe even if this patch isn't committed). (I don't have/want comment delete priveleges on api.drupal.org.)

jhodgdon requested that failed test be re-tested.

Dries’s picture

Status: Needs review » Fixed

Committed to CVS HEAD. Thanks.

sun’s picture

Status: Fixed » Needs work

We should additionally clarify that form_set_value() _only_ sets the value in $form_state['values']. Not in $element['#value'].

And we should clarify *why* it is that way.

jhodgdon’s picture

Ummm... I think the doc does imply that the value is stored in $form_state. I'm not sure it needs more clarification... sun, maybe you can propose a patch that would add the clarification you think is needed?

And as a note, we do need to port the above change (and any other changes in subsequent patches) to Drupal 6 once this is fixed in D7.

arhak’s picture

while you are at it
why keeping $element being recursively passed in _form_set_value while it isn't used at all?

its current signature

function _form_set_value(&$form_values, $element, $parents, $value) {

should be

function _form_set_value(&$form_values, $parents, $value) {

since $element is not needed in the helper function neither used, just passed through

arhak’s picture

BTW, with "just passed through" I meant "to it self" (which is silly)

jhodgdon’s picture

Status: Needs work » Needs review
FileSize
1017 bytes

Here's an update patch that addresses #5 (clarifies further that values are only set in $form_state).

As far as #7 and #8 -- I think it is way too late in the development cycle to change how form_set_value() is called for Drupal 7. If you feel strongly about it, please file a new issue for Drupal 8 with your suggestion. It might be a pain to patch, though, because you'd also have to find all the spots in the core Drupal code that call this function and update them.

arhak’s picture

@#9 is a private function for internal use of form_set_value (to do the recursive dirty work)

/**
 * Helper function for form_set_value().
 *
jhodgdon’s picture

I do not understand #10. ???

jhodgdon’s picture

Ah. I see what you are saying in #10: that only the internal recursive function _form_set_value() needs to be changed.

So yes, that is an OK idea. But please file it as a separate issue, and if possible, create a patch.

mr.baileys’s picture

Looks good, just one minor thing:

+++ includes/form.inc	5 Feb 2010 15:28:23 -0000
@@ -1738,11 +1738,13 @@
  * validation function, so that the changed value persists in $form_state
+ * through to the submission handlers. It does not change the values that may

The value is also persisted in $form_state through to any additional validation handlers if there are any left. Maybe this should just read "handlers" instead of "submission handlers"?

144 critical left. Go review some!

jhodgdon’s picture

Status: Needs review » Needs work

Good point.

jhodgdon’s picture

Status: Needs work » Needs review

Actually, it says "through to the submission handlers", indicating it should persist and keep persisting up through the submission handlers, so I think it's OK?

jhodgdon’s picture

FileSize
1.02 KB

On second thought, I think your idea is good to include validation handlers in there. Here's some revised language.

Status: Needs review » Needs work

The last submitted patch, 570314new.patch, failed testing.

mr.baileys’s picture

Status: Needs work » Needs review

#16: 570314new.patch queued for re-testing.

jhodgdon’s picture

#16: 570314new.patch queued for re-testing.

jhodgdon’s picture

#16: 570314new.patch queued for re-testing.

jhodgdon’s picture

#16: 570314new.patch queued for re-testing.

jhodgdon’s picture

#16: 570314new.patch queued for re-testing.

jhodgdon’s picture

Version: 7.x-dev » 8.x-dev
Issue tags: +Needs backport to D7

updating, will click retest in a sec...

jhodgdon’s picture

Issue tags: -Needs backport to D7

#16: 570314new.patch queued for re-testing.

Status: Needs review » Needs work
Issue tags: +Needs backport to D7

The last submitted patch, 570314new.patch, failed testing.

jhodgdon’s picture

Issue tags: +Novice

Needs a re-roll. Probably a good novice project?

Mac_Weber’s picture

Status: Needs work » Needs review
FileSize
1.24 KB

re-rolled patch #16

jhodgdon’s picture

Thanks for the patch re-roll! I wrote the original so I cannot mark it "reviewed". Anyone else?

sun’s picture

Status: Needs review » Needs work
+++ b/includes/form.inc
@@ -2403,11 +2403,13 @@ function form_type_token_value($element, $input = FALSE) {
+ * Changes submitted form values (in $form_state) during form validation.

Let's remove the parenthesis.

Also, I think the limitation to "during form validation" is not necessarily needed; technically it's also valid to use in submission handlers. However, we can also leave it as is...

+++ b/includes/form.inc
@@ -2403,11 +2403,13 @@ function form_type_token_value($element, $input = FALSE) {
+ * through the remaining validation and submission handlers. It does not change
+ * the values that may be present in the $element array, but only in
+ * $form_state, which is where the submitted values are always stored.

It does not change the value in $element['#value'], only in $form_state['values'], which is where submitted values are always stored.

-16 days to next Drupal core point release.

Mac_Weber’s picture

Status: Needs work » Needs review
FileSize
1.12 KB

I put myself in the shoes of who might be reading it with no past knowledge (in fact, that's me). Then, I decided to get rid of "during form validation." to avoid misleading.

I feel I like learning about the API sending patches.

Mac_Weber’s picture

wrong path sent in #30
sending the correct one

jhodgdon’s picture

This looks quite reasonable to me. Any comments sun?

sun’s picture

Status: Needs review » Reviewed & tested by the community

Thanks!

chx’s picture

Looks good.

webchick’s picture

Status: Reviewed & tested by the community » Fixed

Committed and pushed to 8.x and 7.x. Thanks!

Status: Fixed » Closed (fixed)
Issue tags: -Novice, -Needs backport to D7

Automatically closed -- issue fixed for 2 weeks with no activity.