After spending hours and hours online researching, I'm more confused than ever about something that seems like it should be a very straight-forward task - Using my module's custom form, How do I display the results of a form submission that queries the db?

Here on d.se, Clive and Kiamlaluno provide 2 approaches. Clive suggests using a multistep form, and Kiamlaluno suggests making values globally accessible by storing them in the $_SESSION variable.

Clive's approach doesn't make much sense to me. I'm not trying to print the value of a form field (after checking if it has been submitted), I'm trying to print a list of items retrieved from a database.

Kiamlaluno's approach seems a bit more workable. Indeed I could query a db, store the results in the session, and return those as the return value of a page callback on another page. Ultimately, however, this seems awfully convoluted. First, if this were indeed a best practices way, then why don't more tutorials discuss details about it? What logic would be used to set and unset the variable? PHP is horrible at handling large arrays - what if I have a large result set? How do I handle pagination if I want to divide up the result set across pages? Also, isn't the session variable available only to logged in users?

Looking at Views, Views exposed filters seem to use URL query strings. Is this the correct way? After a form submits redirect to another page, append the query string to that page, pass those parameters 'page arguments', and then query and return data in the page callback based on those arguments?

On Drupal.org there is a thread that has almost 4 years of activity from people confused about this very topic. This comment says that you have to create a $form_state['storage'] variable and "then print it in your form definition." What in the world does that mean?!?!?!?

So, I'll pose my question again. I want to query a database using a form in my custom module, and I want to return a list of results (preferably paginated).

How can I accomplish this? I'm looking for an extremely thorough answer that I can play with in practice.

  • I removed the request for tutorials/links as we don't allow those here - a multi-step form is the correct/accepted way to handle this situation, could you expand on why you can't/won't use that method? Did you receive any errors when trying it? Can you post your code? I can't see why this question isn't a duplicate of the other one, other than you not liking or agreeing with the answers. If you could clear up what's different about this question that would be great. Otherwise this should be closed as a dup of the other, and if you're looking for more thorough answers stick a bounty on it.
    – Clive
    Commented Jun 15, 2013 at 15:01
  • 2
    The best pre-written example might be to look at how Drupal's search module does this.
    – Jimajamma
    Commented Jun 15, 2013 at 15:27
  • @Clive Your response on that particular page was too basic and generic for me to understand or create a working example from. From what I can tell, you were indeed answering exactly what he asked which was how to print a value stored in the $form_state[values] array. My question is not about that - mine is about how to query the database and display those results on the page, preferably paginated, which, I think, necessitates understanding more about the page and arguments callbacks, whether or not redirects should be used, or how the form values should be stored and used to interact with db..
    – blue928
    Commented Jun 15, 2013 at 17:02
  • My bad I spaced on the pager part of the question, thanks for clarifying. A multi-step form would indeed not be suitable for a paged results page. When you click a link the form doesn't get submitted so the form state is lost; the parameters for the query will either need to be in the session or the URL as you rightly said. Personally I'd go for the URL, it's less messy. As @Jimajamma suggested the core search module is an excellent example - search_view() is where the magic happens. Basically a...
    – Clive
    Commented Jun 15, 2013 at 17:15
  • ...in fact this is going to be too long, I'll put an answer in
    – Clive
    Commented Jun 15, 2013 at 17:17

1 Answer 1


As JimaJamma noted in the comments the search module contains an excellent example of one way to do this. The search_view() function is where the magic happens, this is a custom version of that logic which should help explain the process:

function MYMODULE_menu() {
  $items['query'] = array(
    'title' => 'Query',
    'access arguments' => array('access content'),
    'page callback' => 'MYMODULE_results_page',

  return $items;

function MYMODULE_results_page($parameter = NULL) {
  // Even if 'page arguments' isn't defined in a hook_menu() item, Drupal breaks
  // up the URL and passes arguments through to the callback function implicitly.
  // So if the page requested is 'query/123', out item defined at
  // 'query' will be used, and '123' will be passed as the first argument, in
  // this case into the $parameter var.
  // If the parameter is empty, we need to check the GET/POST request to see if
  // the form has been submitted with a new search parameter.
  if (empty($parameter)) {
    if (!empty($_REQUEST['parameter'])) {
      // Build up a new path based on the submitted parameter.
      $path = 'query/' . $_REQUEST['parameter'];

      // And re-direct there. The request will come straight into this function
      // again, but this condition won't fire.

  // Now we're in a position to query for results if there's a non-empty
  // parameter. Otherwise we just show the form (like the search page we'll
  // show the form unconditionally).
  $results_build = array('#markup' => '');
  foreach (MYMODULE_get_results_by_parameter($parameter) as $result) {
    $results_build[] = MYMODULE_build_result_render_array($result);

  $build = array(
    'form' => drupal_get_form('MYMODULE_query_form'),
    'results' => $results_build,

  return $build;

function MYMODULE_query_form($form, &$form_state) {
  // Make we're submitting to the right path.
  $form['#action'] = 'query';

  $form['parameter'] = array(
    '#type' => 'textfield',
    '#title' => t('Enter query here'),

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),

  return $form;

I haven't tested that or anything so excuse any small bugs. If there are any bugs hopefully the comments, and the comments in the search_view() function, will do enough to help explain what should be happening :)

  • Great direction! works wonderfully. only small issue I had trouble with was $parameter = 'null' in the argument list. Using null, I kept getting WSOD when an argument was not in the path, but worked fine when a parameter was in the bath. Setting $pattern = '' fixed it. Thanks so much!
    – blue928
    Commented Jun 17, 2013 at 6:36

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.