Hi,
I am writing a custom module and I've stepped into this "issue". I need to put a form on page so I mapped a menu item of type MENU_CALBACK, and as callback function I call a function wich generates the output that I need on the page, form included, built with FAPI and drupal_get_form().
I need that some code is executed before form generation. (this is why I am not calling directly drupal_get_form() as callback function of the page)
I found out however that drupal executes the callback function twice!!! The first time when I go to the path and it renders the page (and this is ok to me). And a second time when I submit the form.
But this way it executes my code twice, and this is a problem.
How can I avoid this?
I've included the code of the simple form I am using to test it.

/**
* Implements hook_menu().
*/
function test_menu() {
  $items = array();

  $items['testform'] = array(
    'title' => 'Test form page',
    'description' => 'Test form',
    'page callback' => 'testform_page',
//    'page callback' => 'drupal_get_form',
//    'page arguments' => array('exampleform'),
    'access arguments' => array('access content'),
    'type' => MENU_CALLBACK,
  );

  return $items;
}

function testform_page() {
  watchdog('test', 'Execution at ' . microtime());

  /* I need some code executed here */

  $output = t('My test form');
  $form = drupal_render(drupal_get_form('exampleform'));
  $output .= $form;
  return $output;
}

function exampleform($form, &$form_state) {
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit')
  );
  return $form;
}

function exampleform_submit($form, &$form_state) {
  drupal_goto('node');
}

Comments

Anonymous’s picture

That behaviour is completely correct, if you check the action attribute of the form it'll be '/testform'; so when the form is submitted it will be submitted to '/testform', and your page callback will run again, as it should do.

Drupal forms are clever enough to know whether or not they've been submitted in the current page call and can react accordingly. Your best bet would be to move your code logic to inside the form function, where I think you can check for $form_state['#submitted'] to decide whether or not that code should run. Alternatively you could check for the existence of $_POST variables in the testform_page() function.

Hope that helps.

gp.mazzola’s picture

Thanks iSOS. I understood, Infact the action of the form was the page itself.
Providing a different path for $form['#action'] does not work as doing this, when submitting the form, the function testform_submit() is not called.
So I think the only way is moving, as you say, the code inside the form fucntion and check if the form has been submitted or not.

tomas.teicher’s picture

this solution doesn' work for me. I have my form in sidebar block and result of the form in main region.

When I test whether isset $_POST, it behaves little strangely. In page callback I have this test code:

<?php
  if (empty($_POST)) {
       dpm('empty post');
        return t('no results found');
       } 
 else {
      dpm('not empty post'); 
      return 'results found';
   }
?>

When I submit the form, page callback calls twice. As I see from dpm outputs, first time is empty $_POST, the second time with the values. But the text output is not overwritten. The output is still 'no result found'.
Can anybody help why it doesn't overwrite output when calling callback second time?

silkAdmin’s picture

Though it's an old thread it might be usefull to someone to know that if your module name is identical to the current theme name all hooks and preprocess function will run twice!

jordisan’s picture

I would never have figured this out!!!

dave bruns’s picture

Me neither. Great information, thanks!

My theme and utility module had the same name and I kept seeing the devel function dpm () output the same message twice. I was also see strange duplication when using hook_views_post_render...the function I was calling there was also being called twice. Once I renamed the utility module, problem disappeared.

drupalshrek’s picture

If you really don't want the code executed twice, you can test the $form_state['input'] array, which will be empty first time through:

  function my_page_callback($form, &$form_state) {

    // Only do this first time
    if (count($form_state['input']) == 0) {
  	// unique stuff
    }
  }

drupalshrek

amar.deokar’s picture

Set $form_state['cache'] = true;

https://api.drupal.org/api/drupal/includes!form.inc/function/drupal_buil...

cache: If set to TRUE the original, unprocessed form structure will be cached, which allows the entire form to be rebuilt from cache. A typical form workflow involves two page requests; first, a form is built and rendered for the user to fill in. Then, the user fills the form in and submits it, triggering a second page request in which the form must be built and processed. By default, $form and $form_state are built from scratch during each of these page requests. Often, it is necessary or desired to persist the $form and $form_state variables from the initial page request to the one that processes the submission. 'cache' can be set to TRUE to do this. A prominent example is an Ajax-enabled form, in which ajax_process_form() enables form caching for all forms that include an element with the #ajax property. (The Ajax handler has no way to build the form itself, so must rely on the cached version.) Note that the persistence of $form and $form_state happens automatically for (multi-step) forms having the 'rebuild' flag set, regardless of the value for 'cache'.