Not sure quite what's going on here, but this code seems straightforward and yet doesn't work:

function download_report() {

  if( $_POST['start_date']['date'] ) {

    $result = db_query(
     "SELECT count(tbl.uid) downloads, filename
      FROM (
      SELECT distinct uid, fid
          FROM downloads
          ) tbl
      JOIN files ON (tbl.fid = files.fid)
      GROUP BY tbl.fid"
    );

    $content = theme('download_report', $result);

  }

  $content .= drupal_get_form('song_date_range');
  return $content;
}

Basically when I call drupal_get_form, this function gets called again without the $_POST variables. All I'm trying to do is get the HTML for the report parameter form (start date, end date) with drupal_get_form. It's doing something much more than that!

Help!

Comments

tmetzger’s picture

Apparently if you get rid of the contents of $_POST, drupal_get_form will not try to process it. There might be a more elegant solution but here's the resulting code that works:

function download_report() {

  if( $_POST['start_date']['date'] ) {

    $result = db_query(
     "SELECT count(tbl.uid) downloads, filename
      FROM (
      SELECT distinct uid, fid
          FROM downloads
          ) tbl
      JOIN files ON (tbl.fid = files.fid)
      GROUP BY tbl.fid"
    );

    $report = theme('download_report', $result);

    // we need to do this so that drupal_get_form below doesn't use it and screw things up
    $_POST = array();
  } 

  $parameters = drupal_get_form('song_date_range');
  return $parameters . $report;
}

Can anyone improve on that?

nevets’s picture

My guess is $_POST['start_date']['date'] does not match up with the form song_data_range() produces. Without seeing the code I would guess $form['start_date'] does not have '#tree' set to true.

And a suggestion. The recommendation is not to use $_POST, but instead declare the function as download_report($form_state) and use $form_state['values'] instead of $_POST.

tmetzger’s picture

Excellent tip about declaring the function to accept $form_values! Had no clue that was an option. I suppose it does the same thing, under the covers? Where are these recommendations documented, if I may inquire? I'd like to read the rest of them!

I don't fully understand the first part of your comment though. What are the implications of the two not matching up? Does that cause the reloading behavior?

Tom

tmetzger’s picture

I should add that the $form_values['start_date']['date'] is what comes back from date_popup... so if it doesn't match I'm not sure how to fix it!

nevets’s picture

What does the code look like where you construct the form?

tmetzger’s picture

It looks like this!

/**
 * form for the date ranges on the download form
 */
function song_date_range() {

  $d = date_array(date_now());
  $default_start = date_make_date($d['year']."-01-01");
  $default_end = date_make_date(($d['year']+1)."-01-01");

  $form['start_date'] = array(
    '#type' => 'date_popup',
    '#title' => t('Start Date'),
    '#default_value' => date_format_date($default_start, 'custom', 'Y-m-d'),
    '#date_format' => 'Y-m-d',
    '#prefix' => '<table><tbody style="border-top:0;">' .
                 '<tr><td>',
    '#suffix' => '</td>',
  );

  $form['end_date'] = array(
    '#type' => 'date_popup',
    '#title' => t('End Date'),
    '#default_value' => date_format_date($default_end, 'custom', 'Y-m-d'),
    '#date_format' => 'Y-m-d',
    '#prefix' => '<td>',
    '#suffix' => '</td>',
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Generate Report'),
    '#prefix' => '<td>',
    '#suffix' => '</td></tr></table>',
  );


  return $form;

}
nevets’s picture

Once you change your function declaration to

function download_report($form_state) {

If you add as the first line

drupal_set_message('Values:<pre>' . print_r($form_state['values'] . '</pre>');

when you submit the form what shows for the values?

tmetzger’s picture

If I change my function to take that argument, it complains thusly:

warning: Missing argument 1 for download_report() in /Users/tmetzger/Documents/Groupanizer2009/htdocs/sites/all/modules/groupanizer/song/song.module on line 335.

So I must be calling it wrong, huh?

Anyway here are the contents of $_POST:


      Array
      (
          [start_date] => Array
              (
                  [date] => 2010-01-01
              )

          [end_date] => Array
              (
                  [date] => 2011-01-01
              )

          [op] => Generate Report
          [form_build_id] => form-39386784be7ac5990e414774468735f5
          [form_token] => 980b0aadcfdc052078914c56d5bf121e
          [form_id] => download_report_date_range
      )

    *

      Array
      (
      )

Note how dpm(print_r($_POST,true)) actually prints twice, and the second time the array is empty...

T

jaypan’s picture

Mate, ignore $_POST. You NEVER use it in Drupal. Ever. Or if you do, by then you will know exactly why you should be using it and not something else.

In the meantime, how are you calling your form?

Contact me to contract me for D7 -> D10/11 migrations.

tmetzger’s picture

Totally agree about ignoring $_POST - just need to figure out how to do that. My function is a page callback. Takes no arguments.

lorinpda’s picture

Hi,
Drupal's request dispatcher mechanism is referred to as a "menu". The "menu" accepts/translates a user request like http://my_drupal_site/request_report and then dispatches that request to your application code.
.....
Drupal performs all sorts of infrastructure processing to make sure you form and application logic is secure. All you have to do is request Drupal to perform the infrastructure processing. You are very close. See code example below (call drupal_get_form from your "menu").
.....
Drupal also makes heavy use of naming convention to identify modules and functions. Therefore, it's critical that you use the correct naming pattern for Drupal to identify, and thus call your application code.
.....
The acronym you are looking for (in the the Drupal documentation jargon) is FAPI.
http://api.drupal.org/api/drupal/developer--topics--forms_api_reference....

Naming examples:
.....
Module: my_download_report
Menu: my_download_report_menu
Form: my_download_report_form
Form Validation: my_download_report_validation (not demonstrated here)
Form Submission: my_download_report_submit
......
Use the submission phase to save the user's date selection. It's a hack, since you aren't persisting anything. We'll persist the user's selection in the session object.
......
Your sql is not using the date values?? Why have the user's set date values if you report doesn't use them????
....
If you want to display the report results and form on the same page, you can use the form's #prefix and #suffix attributes. Or, you can add a new display only form element ('#type'=>'markup', '#value'=>$YOUR_HTML_MARKUP).
.....
You are also missing some logic in your database processsing. After you call "db_query()", you need to extract the results into a php variable for storage and/or output:

$out = '<table cellspacing="3" cellpadding="3">';

// NOTE! We have to loop through the results

while($my_result = db_fetch_object($result)) {
     $num_downloads = $my_result->downloads;
     $file_name = $my_result->filename;
     $out .= '<tr><td>'.$num_downloads.'</td><td>'.$file_name.'</td></tr>';
} 
$out .='</table>';

..............................
Here's the whole hack:

Note! You have to use the adminstration pages and clear all cache to get drupal to recognize the new "menu". Once cache is cleared, request your report with the web browser set to http://my_drupal_site/my_download/request_report

function my_download_report_menu() {
    $items['my_download/request_report'] = array(
         'type' => MENU_CALLBACK,
         'access arguments' => array('access content'),
         'page callback' => 'drupal_get_form',
        'page arguments' => array('my_download_song_date_range'),

      );
     return $items;
}


function my_download_report_form_submit($node, &$form) {
   // Drupal sets all submit buttons to name=op 
   
   $operation=  $form['values']['op'];
   switch($operation) {
        case 'submit':
            $_SESSION['my_download_report_start_date']  = $form['values']['start_date'];
            $_SESSION['my_download_report_end_date']  = $form['values']['end_date'];
        break;
        case 'reset':
            unset( $_SESSION['my_download_report_start_date']);
            unset( $_SESSION['my_download_report_end_date']);
        break;
   }
}

function my_download_report_form($node, &$form) {

     if ($_SESSION['my_download_report_start_date']) {
	  $default_start = $_SESSION['my_download_report_start_date'];
    } else {
	  $d = date_array(date_now());
	  $default_start = date_make_date($d['year']."-01-01");
    }

     if ($_SESSION['my_download_report_end_date']) {
	  $default_end = $_SESSION['my_download_report_end_date'];
     } else {
	  $d = date_array(date_now());
	  $e = date_make_date(($d['year']+1)."-01-01");
          $default_end= date_format_date($e, 'custom', 'Y-m-d');
     }
  
     $output = '';

     if ($_SESSION['my_download_report_start_date'] && $_SESSION['my_download_report_end_date'])
     {
           // if the user clicked submit run the report 
           // it appears as thouh the date values above aren't used in the database query?? That seems like another bug.
          $output = _run_report();
  }
 
    $form['report'] = array(
         '#type='=>'markup',
         '#value'=>$output,
         '#weight'=>1,
  };

    $form['start_date'] = array(
       '#type' => 'date_popup',
       '#title' => t('Start Date'),
       '#default_value' => $default_start,
       ' #date_format' => 'Y-m-d',
       '#prefix' => '<table><tbody style="border-top:0;">' . '<tr><td>',
        '#suffix' => '</td>', 
   );

   $form['end_date'] = array(
      '#type' => 'date_popup',
       '#title' => t('End Date'),
       '#default_value' => $default_end,
       '#date_format' => 'Y-m-d',
       '#prefix' => '<td>',
      '#suffix' => '</td>',
    );

    $form['submit'] = array(
        '#type' => 'submit',
       '#value' => t('Generate Report'),
       '#prefix' => '<td>',
       '#suffix' => '</td></tr></table>',
     );
   
   // allow the users to clear the session values 
     $form['reset'] = array(
         '#type' => 'submit',
         '#value' => t('reset'),
       );

      return $form;

}

// Note! Verify the sql works outside of this code. I can't tell without the actual data or schema 

function  _run_report() {

    $result = db_query( "SELECT count(tbl.uid) downloads, filename
      FROM ( SELECT distinct uid, fid FROM downloads ) tbl
      JOIN files ON (tbl.fid = files.fid) GROUP BY tbl.fid"
    );
  
   $out = '<table cellspacing="3" cellpadding="3">';
    while($my_result = db_fetch_object($result)) {
      $num_downloads = $my_result->downloads;
      $file_name = $my_result->filename;
      $out .= '<tr><td>'.$num_downloads.'</td><td>'.$file_name.'</td></tr>';
    } 
    $out .='</table>';
  
    return $out;
}

.
....
Hope that helps.

tmetzger’s picture

That was extremely helpful! And thank you for spending the time to make that detailed suggestion.

Persisting the form values was the trick I was missing - I expected them to be there when the form redisplayed after the post, but I guess drupal doesn't work that way. It clears all the form values when you call drupal_get_form(). So I had to put them somewhere else. You suggested the session and what I actually came up with was to use the query string - same idea.

I'll play around with the #markup tag to see if that simplifies what I'm doing.

Thanks again! Really appreciate your help.

Best regards,
Tom