Drupal Forms

Written by James Mansson on February 9, 2013 Categories: AJAX, Drupal, HTML

Because of Drupal’s structured nature it is not immediately obvious how to implement forms in it. In this post I am going to look at how I used Drupal’s various built-in functions to implement a form used in one of my Drupal modules.

The module in question is the chess_results module which feature in my previous post on rendering  HTML tables dynamically in Drupal. The administrative section of the module allows authorised users to add events and add/update results within those events. Both of these functions have their own form. In this article, I shall be looking at the form used to enter results, as it demonstrates a wider range of features.

The first function that I added to the module was one that generates the form:

function chess_results_enter_result_form($form, &$form_state) {
	// Get all the active events
	$result = _get_events(true);

	$events = array();

	foreach ($result as $record) {
		$events[$record->event_id] = $record->description;
	}

	$event_id = isset($form_state['values']['event_id']) ? $form_state['values']['event_id'] : key($events);

	$form['event_id'] = array(
		'#type' => 'select',
		'#title' => t('Event'),
		'#description' => t('The event.'),
		'#options' => $events,
		'#default_value' => $event_id,
		'#ajax' => array(
			'event' => 'change',
			'callback' => 'chess_results_enter_result_form_event_callback',
			'wrapper' => 'game_replace',
        ),
	);

	$form['game'] = array(
		'#type' => 'select',
		'#title' => t('Game'),
		'#description' => t('The game from the event.'),
		'#prefix' => '<div id="game_replace">',
		'#suffix' => '</div>',
		'#options' => chess_results_enter_result_form_game_options($event_id),
		'#default_value' => isset($form_state['values']['game']) ? $form_state['values']['game'] : '',
	);

	$form['date'] = array(
		'#type' => 'date',
		'#title' => t('Date'),
		'#description' => t('The date of the game.'),
		'#required' => true,
	);

	$form['result'] = array(
		'#type' => 'radios',
		'#title' => t('Result'),
		'#description' => t('The result of the game.'),
		'#default_value' =>  '1-0',
		'#options' => array(
			'1-0' => t('1-0'), 
			'1/2' => t('Drawn'), 
			'0-1' => t('0-1'), 
			'adjourned' => t('Adjourned'), 
			'adjudicated' => t('Adjudicated'), 
		),
	);

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

	return $form;
}

The function is passed two parameters: $form and $form_state. The first of these is an array of form elements and their properties. The second represents the current state of the form. If the user has submitted the form, this will be populated with values entered by the user.

The form has five elements:

  • event_id: a select element that allows the user to specify the event in which the game was played.
  • game: a select element that allows the user to select the game from that event.
  • date: a date element that allows the user to specify the date on which the game was played.
  • result: a set of radio buttons that allows the user to specify the result of the game.
  • submit: a submit button.

The event_id element is populated by obtaining a list of active events from the database by calling the _get_events function.

The list of options in the game element is dependent on the value selected in the event_id element. In this function, we use the current event_id selection to populate the game element. The function used to generate the list of options for the game element is implemented as follows:

function chess_results_enter_result_form_game_options($event_id) {
	$results = _get_results($event_id);
	$competitors = _get_competitors($event_id);
	
	$games = array();
	
	foreach ($results as $result) {
		$key = $result['white_id'] . ':' . $result['black_id'];
		
		$white = $result['white_id'];
		$black = $result['black_id'];
		
		foreach ($competitors as $competitor)
		{
			if ($result['white_id'] == $competitor['competitor_id']) {
				$white = $competitor['name'];
			} else if ($result['black_id'] == $competitor['competitor_id']) {
				$black = $competitor['name'];
			}
		}
		
		$value =  $white . ' - ' . $black;
		
		$games[$key] = $value;
	}
	
	return $games;
}

However, we also need to be able to handle the situation when the user changes the event_id selection, because then the options in the game element need to be updated. This is done by using the AJAX functionality built into Drupal.

First, we set the #prefix and #suffix parameters for the game element as follows:

		'#prefix' => '<div id="game_replace">',
		'#suffix' => '</div>',

This allows the current game element to be replaced by an updated version.

Second, we set the event_id element to update the game element using AJAX when its value is changed:

		'#ajax' => array(
			'event' => 'change',
			'callback' => 'chess_results_enter_result_form_event_callback',
			'wrapper' => 'game_replace',
        ),

The callback function is defined as follows:

function chess_results_enter_result_form_event_callback($form, $form_state) {
	return $form['game'];
}

The wrapper parameter contains the ID of the div placed around the game element.

Now the system knows that whenever the event selection changes, it needs to download a new version of the game element.

The other controls are pretty straightforward.

The form is rendered using the following command:

drupal_render(drupal_get_form('chess_results_enter_result_form'));

This is called as part of the function used to render the admin page.

The above described how the form is generated. In order to handle the submission of the form, we add the following function:

function chess_results_enter_result_form_submit($form, &$form_state) {
	$event_id = $form_state['values']['event_id'];
	$game = $form_state['values']['game'];
	$date = $form_state['values']['date'];
	$result = $form_state['values']['result'];

	$competitor_ids = explode(':', $game);
	$white_id = $competitor_ids[0];
	$black_id = $competitor_ids[1];

	$formattedDate = sprintf('%4d-%02d-%02d', $date['year'], $date['month'], $date['day']);

	_update_result($event_id, $white_id, $black_id, $formattedDate, $result);

	drupal_set_message(t(
		'Entered result into database.<br>' .
		' Event: ' . $event_id . '<br> ' .
		' White: ' . $white_id . '<br>' .
		' Black: ' . $black_id . '<br>' .
		' Date: ' . $formattedDate . '<br>' .
		' Result: ' . $result . '<br>'
	));
}

Again, the function is passed two parameters: $form and $form_state. The values in these are then passed to the _update_result function, which is used to update the database. Finally, there is a call to drupal_set_message, which displays a confirmation that the update has been successful at the top of the admin page.

No Comments on Drupal Forms

Leave a Reply

Your email address will not be published. Required fields are marked *