Altering forms without hook_form_alter

Sometimes you might want to alter a $form array in a systematic and declarative manner. For example, say you want to change all of the #title elements to "foo". Here's a function that Adrian Rossouw and I just wrote that does just that. It recurses through all of the children elements of the form sending them (by reference) to a callback function of your choice. That callback can then alter them in any way it wants.

<?php
/**
* Take a form element or whole form array, and a callback, and
* recurse through all children elements, passing them to
* the callback function for processing.
*/
function step_form(&$element, $callback) {
  foreach (
element_children($element) as $child) {
   
step_form($element[$child], $callback);
  }
 
$callback($element);
}

/**
* A callback function to change #title elements to the value "foo"
*/
function change_title(&$element) {
  if (isset(
$element['#title'])) {
   
$element['#title'] = 'foo';
  }
}

/**
* A fictional module's hook_form_alter implementation that sends the form
* to step_form() specifying change_title() as the callback function.
*/
function foo_form_alter(&$form, $form_state, $form_id) {
 
step_form($form, 'change_title');
}
?>

Comments

#process

#process is a better alternative.

Both Wysiwyg API module as well as #translatable module contain advanced examples of recursing into forms goodness.

That's why I post these!

Thanks for the better idea. I'll check it out right away!

-Rob

great idea (again)

This is a great idea! I never looked at the code behind it, but I think http://drupal.org/project/fquery provides a very similar feature

Yes it does

But I wanted something lightweight enough that I can just copy it into my module and not stress if it is duplicated code. I think the 5 lines are light enough for that. Sun's idea is even better. Will try it =)

-Rob

#process

Interestingly, #process isn’t included in the grid at the top of the API page, but it is documented lower on the page.

I am not sure that #process is a better replacement for the code I show above. It’s handy for telling the form system to do something with an element during processing, but to get the #process callback on every element I’d still have to use the recursive code from above. Remember that my goal here is to modify existing forms with my 3rd party contrib module (ie I don’t have the luxury of adding #process to the original form definition). Plus, it’s not exactly clear from the API docs at what point in the form processing the #process callback gets invoked. With the code above I at least know that it gets invoked before any processing has happened (aside from other form_alter hooks). I may be overlooking something, but I think I’ll stick with my code for now.

-Rob

Many moons ago, I took this

Many moons ago, I took this technique to an extreme in drupal 5. My takeaway was that with drupal's pseudo-object-alterable-array-anti-pattern the only sane thing to do was to minimize the number of functions you can possibly forget about, and only use helper functions with form alters in extreme circumstances [ this holds true for any of drupal's many pass an array by reference, and hope to god you're module weights are in order ] apis.

Then again -- I created a rather extreme, flexibile, feature-rich recursive mutant horror compared to this code snippet. #title is an innocent enough property... My implementation was in some ways a textbook example of the innerplatform effect.
[google "inner platform effect"]

But one must admit -- drupal's current php4 era array by reference madness does encourage inner platforms!

Lately, I've tended to do form altering the old fashioned way, using $form[#theme] whenever possible... $form[#theme] is a terrible trouble causing goblin -- but less so than the other root level "#foo" properties I've messed with that don't merely handle validate, or submit, or multistep, or all those other #bug_goblins I'm forgetting.

I can't help but think of Walkah's [google "why i hate drupal"] presentation at drupalcon... its true -- no one else tries to do this... If we can't improve the API -- then I think Boulton's 80% rule will certainly go a long way in ensuring we don't have override so many bloody things in order to make our sites presentable!

This is a Very good Idea

This is a Very good Idea

Thank you very much for sharing this useful Info.

Its an excellent tutorial about altering the titles of the form

Thanks
theme designer

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Allowed HTML tags: <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd> <blockquote>
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.
  • Lines and paragraphs break automatically.

More information about formatting options