Hi all,

I am new to Drupal module development. What I am searching for, is a way,
to output my form submission results.

Of course I could manage with for example:

function form_example_submissions() {
	drupal_set_message($form_state['values']['mytext']);
}

But I want to have an output I can theme. Is there a tutorial or
specific example on the drupal.org website? Couldn't
find something understandable when I looked at the
theme()-function.

Any help is greatly appreciated!

Thank you

Best wishes
Soezkan

Comments

jaypan’s picture

What do you want the workflow to be?

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

selimoezkan’s picture

Thanks for the reply.

I want to do something like, the way it can be done with simple HTML and PHP.
But I want the output to be placed in a themed way.

Supposing my file is called myscript.php - it has a form
that sends the results to itself like this:

<form action="myscript.php" method="post">
<input type="text" name="var1">
<input type="text" name="var2">
<input type="submit" name="submit">
</form>

<?php
if(isset($_POST['submit'])) {
   $result = $_POST['var1'] + $_POST['var2'];
   echo $result;
}
?>

How can I do that with my drupal 7 module?

Many thanks.

Best wishes
Soezkan

jaypan’s picture

What do you want the workflow to be?

Edit: Workflow means, what page should the user start on? Where should they go when the form has been submitted? Any more details that follow that.

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

selimoezkan’s picture

1. Page: User enters birthday (numbers in three input fields for example)
2. Submit
3. Calculations, save to database or similiar, and Output of the results (other than with drupal_set_message).

That's it.

Example:

function birthday_form_submit($form, &$form_state) {
	$output = $form_state['values']['day'].".".$form_state['values']['month'].".".$form_state['values']['year'];

        print theme( 'page', $output ); ?????????????????
}

Thanks for your help!

jaypan’s picture

Do you want the form to be visible with the themed results? And do you need to be able to link to the results page? The method changes according to your answers.

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

selimoezkan’s picture

Hello Jaypan,

Do you want the form to be visible with the themed results?

yes, it would be great to have such a way for doing this.

And it would also help me alot, if I knew the other way of doing so:
namely submitting the form, and getting the results on the result page
without the form.

Many thanks for your help.

Best wishes
Soezkan

jaypan’s picture

Ok, here's a simple example:

function some_form($form, &$form_state)
{
  $form['some_value'] = array
  (
    '#type' => 'textfield',
    '#title' => t('Enter some value'),
    // $form_state['storage']['some_value'] will only be set after
    // the form has been submitted and rebuilt
    '#default_value' => isset($form_state['storage']['some_value']) ? $form_state['storage']['some_value'] : '',
  );
  $form['submit'] = array
  (
    '#type' => 'submit',
    '#value' => t('Submit'),
  );

  // $form_state['storage']['some_value'] will only be set after
  // the form has been submitted and rebuilt
  if(isset($form_state['storage']['some_value']))
  {
    // We pass a theme, and the submitted value
    $form['some_value_display'] = array
    (
      '#theme' => 'some_theme',
      '#value' => $form_state['storage']['some_value'],
    );
  }

  return $form;
}

function some_form_submit($form, &$form_state)
{
  // we return the submitted value to the form
  // by storing it in $form_state['storage'] and rebuilding
  $form_state['storage']['some_value'] = $form_state['values']['some_value'];
  $form_state['rebuild'] = TRUE;
}

// We need to register our theme function using hook_theme()
function my_module_theme()
{
  return array
  (
    'some_theme' => array
    (
      'render element' => 'form',
    ),
  );
}

// Finally we define our theme function
function theme_some_theme($variables)
{
  $element = $variables['form'];
  $output = '<h2>' . t('This is the value that was submitted') . '</h2>';
  $output .= '<p>' . $element['#value'] . '</p>';

  return $output;
}

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

selimoezkan’s picture

Thank you very much.

Please allow me one more question.
You write:

function some_form($form, &$form_state)
{
  $form['some_value'] = array
  (
    '#type' => 'textfield',
    '#title' => t('Enter some value'),
    // $form_state['storage']['some_value'] will only be set after
    // the form has been submitted and rebuilt
    '#default_value' => isset($form_state['storage']['some_value']) ? $form_state['storage']['some_value'] : '',
  );
  $form['submit'] = array
  (
    '#type' => 'submit',
    '#value' => t('Submit'),
  );
  // $form_state['storage']['some_value'] will only be set after
  // the form has been submitted and rebuilt
  if(isset($form_state['storage']['some_value']))
  {
    // We pass a theme, and the submitted value
    $form['some_value_display'] = array
    (
      '#theme' => 'some_theme',
      '#value' => $form_state['storage']['some_value'],
    );
  }
  return $form;
}
function some_form($form, &$form_state)
{
  // we return the submitted value to the form
  // by storing it in $form_state['storage'] and rebuilding
  $form_state['storage']['some_value'] = $form_state['values']['some_value'];
  $form_state['rebuild'] = TRUE;
}

function some_form() ist defined twice - is this a typo or the two versions of handling the results?

Many thanks!

Best wishes
Soezkan

jaypan’s picture

Sorry, that was a typo. I've edited the code to fix it.

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

selimoezkan’s picture

Hi Jaypan,

I don't understand the code. As it is not an example one can copy paste and try out
I tried with my small knowledge about module development, but failed :(

After trying to add hook_menu() withj an appropriate link (i.e. "some-form")
I get the form, but when I submit something nothing happens.
Very hard to understand for me.

Thank you.

Best wishes
Soezkan

jaypan’s picture

What does your code look like?

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

selimoezkan’s picture

Hi Jaypan,

this is my module:


/**
 * Implements hook_menu
 */
function myownform_menu() {
	$items = array();
	$items['myownform'] = array(
		'title' => 'My Own Form',
		'type' => MENU_NORMAL_ITEM,
		'access arguments' => array('submit myownform'),
		'page callback' => 'drupal_get_form',
		'page arguments' => array('myownform_form'),
	);

	return $items;
}

/**
 * Implements hook_form
 */
function myownform_form($form, &$form_state) {

	$form['myowntext'] = array(
		'#type' => 'textfield',
		'#title' => t('My own Text'),
		'#size' => 50,
		'#maxlength' => 50,
		'#required' => TRUE,
		'#description' => t('Please enter a small text'),
	);

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

	return $form;
}

/**
 * Validation handler for the myownform_form
 */
function myownform_form_validate($form, &$form_state) {
	if (!isset($form_state['values']['myowntext'])) {
		form_set_error('myowntext', t('You must enter a value.'));
		return FALSE;
	}

	return TRUE;
}

/**
 * Submission handler for the myownform_form
 */
function myownform_form_submit($form, &$form_state) {
	$form_state['rebuild'] = TRUE;
	print($_POST['myowntext']);
}

The results are printed out with $_POST['myowntext'] on the very top of the page, are not themed and even outside the HTML-Body.

My question: How can I place the $_POST['myowntext'] right below
the submitbutton of my form after submitting.

Many thanks
Soezkan

jaypan’s picture

Well, you're getting close.

Note that in Drupal, we don't use $_POST data, as it is unsanitized, and therefore dangerous. The sanitized form values are stored in $form_state['values'], and these are what you should use. You can then store data in $form_state['storage'], and if you set $form_state['rebuild'] to TRUE, the values you saved in $form_state['storage'] will be available in your form definition:

/**
* Implements hook_menu
*/
function myownform_menu() {
    $items = array();
    $items['myownform'] = array(
        'title' => 'My Own Form',
        'type' => MENU_NORMAL_ITEM,
        'access arguments' => array('submit myownform'),
        'page callback' => 'drupal_get_form',
        'page arguments' => array('myownform_form'),
    );
    return $items;
}
/**
* Implements hook_form
*/
function myownform_form($form, &$form_state) {
    $form['myowntext'] = array(
        '#type' => 'textfield',
        '#title' => t('My own Text'),
        '#size' => 50,
        '#maxlength' => 50,
        '#required' => TRUE,
        '#description' => t('Please enter a small text'),
    );
    $form['submit'] = array(
        '#type' => 'submit',
        '#value' => t('Submit')
    );

    // $form_state['storage'] is only set when the form
    // as been submitted (see the _submit() function for
    // more details)
    if(isset($form_state['storage'], $form_state['storage']['myowntext']))
    {
        // The form has been submitted, so we display the submitted
        // value to the user:
        $form['myowntext_display'] = array
        (
            '#markup' => t('The value you submitted was: @value', array('@value' => $form_state['storage']['myowntext'])),
            '#prefix' => '<p>',
            '#suffix' => '</p>',
        );
    }
    return $form;
}

/**
* Submission handler for the myownform_form
*/
function myownform_form_submit($form, &$form_state) {
    // First we save the submitted data to $form_state['storage']
    $form_state['storage']['myowntext'] = $form_state['values']['myowntext'];
    // Then we set $form_state['rebuild'] to TRUE, so that the values stored in
    // $form_state['storage'] are available in the form definition.
    $form_state['rebuild'] = TRUE;
}

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

selimoezkan’s picture

Great - thank you!

Soezkan

selimoezkan’s picture

Two other options could be:
placing the results above the form - this is something I think I will manage.

But what, if I want to output the results on a, let's call it "result page", without
showing the form?

Thank you.

Best wishes
Soezkan

jaypan’s picture

First, I just noticed this:

/**
* Implements hook_form
*/

The above is incorrect. This is not a hook, and hook_form(), which existed in D6 (but not D7) was different. This is simply a form definition.

Anyways, regarding your second question, you can do this:

function myownform_form($form, &$form_state) {
    if(!isset($form_state['storage'], $form_state['storage']['myowntext']))
      $form['myowntext'] = array(
          '#type' => 'textfield',
          '#title' => t('My own Text'),
          '#size' => 50,
          '#maxlength' => 50,
          '#required' => TRUE,
          '#description' => t('Please enter a small text'),
      );
      $form['submit'] = array(
          '#type' => 'submit',
          '#value' => t('Submit')
      );
    }
    else
    {
        // The form has been submitted, so we display the submitted
        // value to the user:
        $form['myowntext_display'] = array
        (
            '#markup' => t('The value you submitted was: @value', array('@value' => $form_state['storage']['myowntext'])),
            '#prefix' => '<p>',
            '#suffix' => '</p>',
        );
    }
    return $form;
}

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

selimoezkan’s picture

Many thanks for all your good advices.

Best wishes
Soezkan

selimoezkan’s picture

Did alot of work on module development so far.

I always output the results of my form submissions below the form, and automatically collapse it after submit with $form['myform']['#collapsed'] = TRUE;

The following code I use in my mymodule_form in order to search for firstname and lastname in my database:

function mymodule_form($form, &$form_state) {

 [...]

    $form['myform']['submit'] = array(
	'#prefix' => '',
	'#suffix' => '',
        '#type' => 'submit',
        '#value' => t('Search')
    );

    if( isset($form_state['storage'], $form_state['storage']['searchterm']) ) {
        
		$searchterm = $form_state['storage']['searchterm'];
		
		# configure the table header columns
		$header = array(
			array('data' => t('First name'), 'field' => 'firstname', 'sort' => 'ASC'),
			array('data' => t('Lastname'), 'field' => 'lastname', 'sort' => 'ASC')),
		);
		
		$select = db_select('my_addresses', 'p')
			->extend('PagerDefault')
			->extend('TableSort')
			->condition('firstname', $searchterm,'LIKE');
		
		$select->fields('p', array('firstname', 'lastname'))
			 ->limit(10)
			 ->orderByHeader($header)
			 ->orderBy('amount', 'ASC');
		
		$results = $select->execute();
		
		$rows = array();
		foreach ($results as $row) {
			$rows[] = array(
				$row->firstname,
				$row->lastname
			);
		}
		
		$output = theme('table', array('header' => $header, 'rows' => $rows )).theme('pager');
		
		$form['searchresults_display'] = array(
		    '#markup' => $output,
		    '#prefix' => '<p>',
		    '#suffix' => '</p>',
		);
    }
	
    return $form;
}


My problem:

if I use the pager links, the results got lost, since the module (and hence the form) will be loaded again, without submission.

How can I handle this with submission?

Many thanks for help!

Best wishes
Soezkan

jaypan’s picture

In this case, you have to do things differently. I actually just explained it in a different thread the other day, so please read through my explanations there: https://drupal.org/node/2183643

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

selimoezkan’s picture

Thanks. I looked at your other thread and I think I almost made it.

The only thing I don't know is how I could place my $searchterm
within the pager links. If I'd make that, I could pass the original
$searchterm to provide in mymodule_form($form, &$form_state)
and use it for the SQL-query.

Any idea?

jaypan’s picture

I believe you'll have to override theme_pager() to do that.

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

selimoezkan’s picture

Thanks so far.

I output my search results with:

$output = theme('table', array('header' => $header, 'rows' => $rows )).theme('pager');

...

The easiest thing would be to append the last part of the call with $searchterm like this:

$output = theme('table', array('header' => $header, 'rows' => $rows )).theme('pager', $searchterm);

...

Where (what file) do I do the theme_pager()-override you suggest? And, what is it? I mean: how can I do such an override?

Many many thanks for more help on this!

Best wishes
Soezkan

jaypan’s picture

An override means you take the original function, copy it to template.php in your theme folder, and make your edits there.

If your theme is named 'ninja', then you would copy theme_pager() to template.php in the ninja folder, and rename it to ninja_pager(). Then, you would check to see if $_GET['whatever'] is set, and add that to all the links if it is.

This is how you override theme functions.

But before you do that, are you accessing the form at a page (path) or in a block?

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

selimoezkan’s picture

Hello Jaypan,

I will try this out later.

The form access takes place at a page.
Would it be much different with blocks?

When I do that as you suggested, could I then perform this call:

$output = theme('table', array('header' => $header, 'rows' => $rows )).theme('pager', $searchterm);
...

??

Many thanks!
Soezkan

jaypan’s picture

If it's on a page, you don't need to use $_GET queries. See my first example on that page I linked to. You will append your value onto the path.

So if the path to your form is /path/to/form and the selected value is 'ninja', you would redirect the user to /path/to/form/ninja

Your links should automatically pick this up, and you don't need to override theme_pager().

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

selimoezkan’s picture

Hi Jaypan,

wow, so many ways to handle form submissions. Always good to
choose the shortest path to the solution. It works fine with your
suggestion!

I resolved it with exploding the $_GET['q'] by '/' and took the last
record of the array [2] to use it for my db-query-pager in my
mymodule_form().

Many thanks for your help.

Best wishes
Soezkan

BHAVIK PARGEE’s picture

Thanks you saved my a lot of time...

Abbass’s picture

@jaypan how would you use form storage if you have more than one value in your form, say you had field myowntext1,myowntext2 and myowntext3 ?

pushpinderchauhan’s picture

Jaypan, Thank you for this example.

$form['#value'] replaced with $element['#value'] .

// Finally we define our theme function
function theme_some_theme($variables)
{
  $element = $variables['form'];
  $output = '<h2>' . t('This is the value that was submitted') . '</h2>';
  $output .= '<p>' . $element['#value'] . '</p>'; // Corrected this TYPO.
  return $output;
}

Pushpinder Rana #pushpinderdrupal
Acquia Certified Drupal Expert

jaypan’s picture

Thanks, I've gone in an edited the original code to fix the typo.

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

ilclaudio’s picture

Hi Jaypan,
if I define the block containing the results in a template on the file system in this way:

function myModule_theme(){
  return array(
    'viewlogresults' => array
    (
      'variables' => array('results'=>null, 'headers'=>null),
      'template' => 'themes/viewlogresults',
    ),
  );
}

How can I change this code:

  if(isset($form_state['storage']['some_value']))
  {
    // We pass a theme, and the submitted value
    $form['some_value_display'] = array
    (
      '#theme' => 'some_theme',
      '#value' => $form_state['storage']['some_value'],
    );
  }

so that I can pass the arrays:

 $form_state['storage']['headers']
 $form_state['storage']['results']

to the viewlogresults.tpl.php page?
Now I can see this template after the submission of the form, but the arrays variables['headers'] and variables['results'] are empty.

What is the difference between the "#value" variable and "variables" ?

Thank you very much

cld

ilclaudio’s picture

I've solved in this way and works:

function myModule_theme(){
  return array(
    'viewlogresults' => array
    (
        'variables' => array('results'=>null, 'headers'=>null),
        'template' => 'themes/viewlogresults',
    ),
  );
}

During the form creation:

    $l_Form['results'] = array
    (
        '#theme' => 'viewlogresults',
        '#headers'=>$form_state['storage']['headers'],
        '#results'=>$form_state['storage']['results'],
    );
ggeeoorggee’s picture

Hi guys,

based on this solution is it possible to make something like this: (click to start)
http://www.reisswolf.net/services/physical-rms/reisswolf-abc/

User inputs 4 numbers and then get the results

So, can I make something like this based on your solution?

elusivemind’s picture

I wanted to return a fully themed page as part of a form submit. Since you can't really do this all that well, I have come up with this work around using theme functions.

The first part is my custom HTML I wanted to display within the confines of my theme. This was all calculated based on the results of form input (in this case, a quiz --- note this is not related to the contrib quizzler module).

$output = theme('quizzler_answer', array(
      'question' => $question['question'], 
      'question_number' => $current_question,
      'total_questions' => $form_state['input']['total_questions'], 
      'answers' => $question['answers'],
      'answer' => $form_state['input']['question_answers'],
      'post_question_text' => $question['post_question'],
      'correct_incorrect' => $answer_disposition,
      'next_url' => $form_state['input']['next_question_url'],
      'previous_url' => $form_state['input']['previous_question_url'],
      )
  );

  $page = theme('page', array('page' => array('content' => $output)));
  $html = theme('html', array('page' => array('#children' => $page)));
  print $html;
  exit();

The result of this is it takes the HTML in my quizzler-answer.tpl.php file and places it within my general page wrapper. This so I do not have to re-direct after the form is submitted. I hope this helps someone.