Newer
Older

Dries Buytaert
committed
/**
* @file
* Functions for form and batch generation and processing.
*/

Dries Buytaert
committed
use Drupal\Component\Utility\NestedArray;

catch
committed
use Drupal\Component\Utility\Number;

Angie Byron
committed
use Drupal\Component\Utility\String;

Angie Byron
committed
use Drupal\Component\Utility\Url;
use Drupal\Core\Database\Database;
use Drupal\Core\Language\Language;
use Drupal\Core\Template\Attribute;
use Drupal\Core\Utility\Color;
use Symfony\Component\HttpFoundation\RedirectResponse;

Angie Byron
committed
* @defgroup forms Form builder functions
* @{
* Functions that build an abstract representation of a HTML form.
*
* All modules should declare their form builder functions to be in this
* group and each builder function should reference its validate and submit
* functions using \@see. Conversely, validate and submit functions should
* reference the form builder function using \@see. For examples, of this see
* system_modules_uninstall() or user_pass(), the latter of which has the
* following in its doxygen documentation:

Jennifer Hodgdon
committed
* - \@ingroup forms
* - \@see user_pass_validate()
* - \@see user_pass_submit()

Jennifer Hodgdon
committed
* @}
*/
/**
* @defgroup form_api Form generation

Dries Buytaert
committed
* Functions to enable the processing and display of HTML forms.

Dries Buytaert
committed
* Drupal uses these functions to achieve consistency in its form processing and
* presentation, while simplifying code and reducing the amount of HTML that
* must be explicitly generated by modules.
*

Dries Buytaert
committed
* The primary function used with forms is drupal_get_form(), which is
* used for forms presented interactively to a user. Forms can also be built and
* submitted programmatically without any user input using the
* drupal_form_submit() function.

Dries Buytaert
committed
*

Dries Buytaert
committed
* drupal_get_form() handles retrieving, processing, and displaying a rendered
* HTML form for modules automatically.
*
* Here is an example of how to use drupal_get_form() and a form builder
* function:

Dries Buytaert
committed
* $form = drupal_get_form('my_module_example_form');
* ...
* function my_module_example_form($form, &$form_state) {
* $form['submit'] = array(
* '#type' => 'submit',
* '#value' => t('Submit'),
* );

Dries Buytaert
committed
* }
* function my_module_example_form_validate($form, &$form_state) {
* // Validation logic.
* }
* function my_module_example_form_submit($form, &$form_state) {
* // Submission logic.
* }

Dries Buytaert
committed
*

Dries Buytaert
committed
* Or with any number of additional arguments:
* @code
* $extra = "extra";
* $form = drupal_get_form('my_module_example_form', $extra);
* ...
* function my_module_example_form($form, &$form_state, $extra) {
* $form['submit'] = array(
* '#type' => 'submit',
* '#value' => $extra,
* );

Dries Buytaert
committed
* }
* @endcode

Dries Buytaert
committed
*

Dries Buytaert
committed
* The $form argument to form-related functions is a structured array containing
* the elements and properties of the form. For information on the array
* components and format, and more detailed explanations of the Form API
* workflow, see the

Jennifer Hodgdon
committed
* @link forms_api_reference.html Form API reference @endlink

Dries Buytaert
committed
* and the
* @link http://drupal.org/node/37775 Form API documentation section. @endlink

Dries Buytaert
committed
* In addition, there is a set of Form API tutorials in
* @link form_example_tutorial.inc the Form Example Tutorial @endlink which
* provide basics all the way up through multistep forms.
*
* In the form builder, validation, submission, and other form functions,
* $form_state is the primary influence on the processing of the form and is
* passed by reference to most functions, so they use it to communicate with
* the form system and each other.
*
* See drupal_build_form() for documentation of $form_state keys.

Dries Buytaert
committed
* Returns a renderable form array for a given form ID.
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->getForm().
*
* @see \Drupal\Core\Form\FormBuilderInterface::getForm().

Dries Buytaert
committed
*/
function drupal_get_form($form_arg) {

Alex Pott
committed
return call_user_func_array(array(\Drupal::formBuilder(), 'getForm'), func_get_args());
}

Dries Buytaert
committed
/**

Dries Buytaert
committed
* Builds and processes a form for a given form ID.

Dries Buytaert
committed
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->buildForm().
*
* @see \Drupal\Core\Form\FormBuilderInterface::buildForm().

Dries Buytaert
committed
*/
function drupal_build_form($form_id, &$form_state) {

Alex Pott
committed
return \Drupal::formBuilder()->buildForm($form_id, $form_state);

Dries Buytaert
committed
}

Dries Buytaert
committed

Dries Buytaert
committed
/**

Dries Buytaert
committed
* Retrieves default values for the $form_state array.

Alex Pott
committed
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->getFormStateDefaults().
*
* @see \Drupal\Core\Form\FormBuilderInterface::getFormStateDefaults().

Dries Buytaert
committed
*/
function form_state_defaults() {

Alex Pott
committed
return \Drupal::formBuilder()->getFormStateDefaults();

Dries Buytaert
committed
}

Gábor Hojtsy
committed
/**

Dries Buytaert
committed
* Constructs a new $form from the information in $form_state.
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->rebuildForm().
*
* @see \Drupal\Core\Form\FormBuilderInterface::rebuildForm().

Gábor Hojtsy
committed
*/

Dries Buytaert
committed
function drupal_rebuild_form($form_id, &$form_state, $old_form = NULL) {

Alex Pott
committed
return \Drupal::formBuilder()->rebuildForm($form_id, $form_state, $old_form);

Gábor Hojtsy
committed
}
/**

Dries Buytaert
committed
* Fetches a form from the cache.

Alex Pott
committed
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->getCache().
*
* @see \Drupal\Core\Form\FormBuilderInterface::getCache().
*/
function form_get_cache($form_build_id, &$form_state) {

Alex Pott
committed
return \Drupal::formBuilder()->getCache($form_build_id, $form_state);
}
/**

Dries Buytaert
committed
* Stores a form in the cache.

Alex Pott
committed
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->setCache().
*
* @see \Drupal\Core\Form\FormBuilderInterface::setCache().
*/
function form_set_cache($form_build_id, $form, $form_state) {

Alex Pott
committed
\Drupal::formBuilder()->setCache($form_build_id, $form, $form_state);

Dries Buytaert
committed
}

Dries Buytaert
committed
/**
* Ensures an include file is loaded whenever the form is processed.

Dries Buytaert
committed
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
*
* Example:
* @code
* // Load node.admin.inc from Node module.
* form_load_include($form_state, 'inc', 'node', 'node.admin');
* @endcode
*
* Use this function instead of module_load_include() from inside a form
* constructor or any form processing logic as it ensures that the include file
* is loaded whenever the form is processed. In contrast to using
* module_load_include() directly, form_load_include() makes sure the include
* file is correctly loaded also if the form is cached.
*
* @param $form_state
* The current state of the form.
* @param $type
* The include file's type (file extension).
* @param $module
* The module to which the include file belongs.
* @param $name
* (optional) The base file name (without the $type extension). If omitted,
* $module is used; i.e., resulting in "$module.$type" by default.
*
* @return
* The filepath of the loaded include file, or FALSE if the include file was
* not found or has been loaded already.
*
* @see module_load_include()
*/
function form_load_include(&$form_state, $type, $module, $name = NULL) {
if (!isset($name)) {
$name = $module;
}
if (!isset($form_state['build_info']['files']["$module:$name.$type"])) {
// Only add successfully included files to the form state.
if ($result = module_load_include($type, $module, $name)) {
$form_state['build_info']['files']["$module:$name.$type"] = array(
'type' => $type,
'module' => $module,
'name' => $name,
);
return $result;
}
}
return FALSE;
}
/**

Dries Buytaert
committed
* Retrieves, populates, and processes a form.
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->submitForm().
*
* @see \Drupal\Core\Form\FormBuilderInterface::submitForm().
*/

Angie Byron
committed
function drupal_form_submit($form_arg, &$form_state) {

Alex Pott
committed
\Drupal::formBuilder()->submitForm($form_arg, $form_state);
}

Dries Buytaert
committed
/**
* Retrieves the structured array that defines a given form.
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->retrieveForm().
*
* @see \Drupal\Core\Form\FormBuilderInterface::retrieveForm().

Dries Buytaert
committed
*/

Dries Buytaert
committed
function drupal_retrieve_form($form_id, &$form_state) {

Alex Pott
committed
return \Drupal::formBuilder()->retrieveForm($form_id, $form_state);

Dries Buytaert
committed
}
/**

Dries Buytaert
committed
* Processes a form submission.
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->processForm().
*
* @see \Drupal\Core\Form\FormBuilderInterface::processForm().

Dries Buytaert
committed
function drupal_process_form($form_id, &$form, &$form_state) {

Alex Pott
committed
\Drupal::formBuilder()->processForm($form_id, $form, $form_state);

Dries Buytaert
committed
}
/**

Dries Buytaert
committed
* Prepares a structured form array.
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->prepareForm().
*
* @see \Drupal\Core\Form\FormBuilderInterface::prepareForm().

Dries Buytaert
committed
*/

Dries Buytaert
committed
function drupal_prepare_form($form_id, &$form, &$form_state) {

Alex Pott
committed
\Drupal::formBuilder()->prepareForm($form_id, $form, $form_state);

Dries Buytaert
committed
/**

Dries Buytaert
committed
* Validates user-submitted form data in the $form_state array.

Dries Buytaert
committed
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->validateForm().
*
* @see \Drupal\Core\Form\FormBuilderInterface::validateForm().

Dries Buytaert
committed
*/
function drupal_validate_form($form_id, &$form, &$form_state) {

Alex Pott
committed
\Drupal::formBuilder()->validateForm($form_id, $form, $form_state);

Dries Buytaert
committed
/**

Dries Buytaert
committed
* Redirects the user to a URL after a form has been processed.
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->redirectForm().
*
* @see \Drupal\Core\Form\FormBuilderInterface::redirectForm().

Dries Buytaert
committed
*/

Dries Buytaert
committed
function drupal_redirect_form($form_state) {

Alex Pott
committed
return \Drupal::formBuilder()->redirectForm($form_state);

Dries Buytaert
committed
/**

Dries Buytaert
committed
* Executes custom validation and submission handlers for a given form.
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->executeHandlers().
*
* @see \Drupal\Core\Form\FormBuilderInterface::executeHandlers().

Dries Buytaert
committed
*/
function form_execute_handlers($type, &$form, &$form_state) {

Alex Pott
committed
\Drupal::formBuilder()->executeHandlers($type, $form, $form_state);

Dries Buytaert
committed
}
/**

Dries Buytaert
committed
* Files an error against a form element.
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->setErrorByName().
*
* @see \Drupal\Core\Form\FormBuilderInterface::setErrorByName().
*/

Angie Byron
committed
function form_set_error($name, array &$form_state, $message = '') {
\Drupal::formBuilder()->setErrorByName($name, $form_state, $message);
}

Dries Buytaert
committed
/**

Dries Buytaert
committed
* Clears all errors against all form elements made by form_set_error().

Alex Pott
committed
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->clearErrors().
*
* @see \Drupal\Core\Form\FormBuilderInterface::clearErrors().

Dries Buytaert
committed
*/

Angie Byron
committed
function form_clear_error(array &$form_state) {
\Drupal::formBuilder()->clearErrors($form_state);

Dries Buytaert
committed
}
/**

Dries Buytaert
committed
* Returns an associative array of all errors.

Alex Pott
committed
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->getErrors().
*
* @see \Drupal\Core\Form\FormBuilderInterface::getErrors().
*/

Angie Byron
committed
function form_get_errors(array &$form_state) {
return \Drupal::formBuilder()->getErrors($form_state);
}
/**

Dries Buytaert
committed
* Returns the error message filed against the given form element.
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->getError().
*
* @see \Drupal\Core\Form\FormBuilderInterface::getError().
*/

Angie Byron
committed
function form_get_error($element, array &$form_state) {
return \Drupal::formBuilder()->getError($element, $form_state);
}

Dries Buytaert
committed
* Flags an element as having an error.

Alex Pott
committed
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->setError().
*
* @see \Drupal\Core\Form\FormBuilderInterface::setError().

Angie Byron
committed
function form_error(&$element, array &$form_state, $message = '') {
\Drupal::formBuilder()->setError($element, $form_state, $message);

Dries Buytaert
committed
* Builds and processes all elements in the structured form array.
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->doBuildForm().
*
* @see \Drupal\Core\Form\FormBuilderInterface::doBuildForm().

Dries Buytaert
committed
function form_builder($form_id, &$element, &$form_state) {

Alex Pott
committed
return \Drupal::formBuilder()->doBuildForm($form_id, $element, $form_state);
}
/**
* Removes internal Form API elements and buttons from submitted form values.
*
* This function can be used when a module wants to store all submitted form
* values, for example, by serializing them into a single database column. In
* such cases, all internal Form API values and all form button elements should
* not be contained, and this function allows to remove them before the module
* proceeds to storage. Next to button elements, the following internal values
* are removed:
* - form_id
* - form_token
* - form_build_id
* - op
*
* @param $form_state
* A keyed array containing the current state of the form, including
* submitted form values; altered by reference.
*/
function form_state_values_clean(&$form_state) {
// Remove internal Form API values.
unset($form_state['values']['form_id'], $form_state['values']['form_token'], $form_state['values']['form_build_id'], $form_state['values']['op']);
// Remove button values.
// form_builder() collects all button elements in a form. We remove the button
// value separately for each button element.
foreach ($form_state['buttons'] as $button) {
// Remove this button's value from the submitted form values by finding
// the value corresponding to this button.
// We iterate over the #parents of this button and move a reference to
// each parent in $form_state['values']. For example, if #parents is:
// array('foo', 'bar', 'baz')
// then the corresponding $form_state['values'] part will look like this:
// array(
// 'foo' => array(
// 'bar' => array(
// 'baz' => 'button_value',
// ),
// ),
// )
// We start by (re)moving 'baz' to $last_parent, so we are able unset it
// at the end of the iteration. Initially, $values will contain a
// reference to $form_state['values'], but in the iteration we move the
// reference to $form_state['values']['foo'], and finally to
// $form_state['values']['foo']['bar'], which is the level where we can
// unset 'baz' (that is stored in $last_parent).
$parents = $button['#parents'];
$last_parent = array_pop($parents);
$key_exists = NULL;

Dries Buytaert
committed
$values = &NestedArray::getValue($form_state['values'], $parents, $key_exists);
if ($key_exists && is_array($values)) {
unset($values[$last_parent]);
}
}
}

Gábor Hojtsy
committed
/**

Dries Buytaert
committed
* Determines the value for an image button form element.

Gábor Hojtsy
committed
*
* @param $form
* The form element whose value is being populated.
* @param $input
* The incoming input to populate the form element. If this is FALSE,

Gábor Hojtsy
committed
* the element's default value should be returned.
* @param $form_state

Dries Buytaert
committed
* A keyed array containing the current state of the form.

Dries Buytaert
committed
*

Gábor Hojtsy
committed
* @return
* The data that will appear in the $form_state['values'] collection
* for this element. Return nothing to use the default.
*/
function form_type_image_button_value($form, $input, $form_state) {
if ($input !== FALSE) {
if (!empty($input)) {

Gábor Hojtsy
committed
// If we're dealing with Mozilla or Opera, we're lucky. It will
// return a proper value, and we can get on with things.
return $form['#return_value'];
}
else {
// Unfortunately, in IE we never get back a proper value for THIS
// form element. Instead, we get back two split values: one for the
// X and one for the Y coordinates on which the user clicked the
// button. We'll find this element in the #post data, and search
// in the same spot for its name, with '_x'.
$input = $form_state['input'];
foreach (explode('[', $form['#name']) as $element_name) {

Gábor Hojtsy
committed
// chop off the ] that may exist.
if (substr($element_name, -1) == ']') {
$element_name = substr($element_name, 0, -1);
}
if (!isset($input[$element_name])) {
if (isset($input[$element_name . '_x'])) {

Gábor Hojtsy
committed
return $form['#return_value'];
}
return NULL;
}
$input = $input[$element_name];

Gábor Hojtsy
committed
}
return $form['#return_value'];
}
}
}

Dries Buytaert
committed
/**

Dries Buytaert
committed
* Determines the value for a checkbox form element.

Dries Buytaert
committed
*
* @param $form

Dries Buytaert
committed
* The form element whose value is being populated.

Dries Buytaert
committed
* @param $input
* The incoming input to populate the form element. If this is FALSE,

Dries Buytaert
committed
* the element's default value should be returned.

Dries Buytaert
committed
*

Dries Buytaert
committed
* @return
* The data that will appear in the $element_state['values'] collection

Dries Buytaert
committed
* for this element. Return nothing to use the default.

Dries Buytaert
committed
*/
function form_type_checkbox_value($element, $input = FALSE) {

Dries Buytaert
committed
if ($input === FALSE) {
// Use #default_value as the default value of a checkbox, except change

Alex Pott
committed
// NULL to 0, because FormBuilder::handleInputElement() would otherwise

Dries Buytaert
committed
// replace NULL with empty string, but an empty string is a potentially
// valid value for a checked checkbox.
return isset($element['#default_value']) ? $element['#default_value'] : 0;
}
else {
// Checked checkboxes are submitted with a value (possibly '0' or ''):
// http://www.w3.org/TR/html401/interact/forms.html#successful-controls.
// For checked checkboxes, browsers submit the string version of
// #return_value, but we return the original #return_value. For unchecked
// checkboxes, browsers submit nothing at all, but

Alex Pott
committed
// FormBuilder::handleInputElement() detects this, and calls this

Dries Buytaert
committed
// function with $input=NULL. Returning NULL from a value callback means to
// use the default value, which is not what is wanted when an unchecked
// checkbox is submitted, so we use integer 0 as the value indicating an
// unchecked checkbox. Therefore, modules must not use integer 0 as a
// #return_value, as doing so results in the checkbox always being treated
// as unchecked. The string '0' is allowed for #return_value. The most
// common use-case for setting #return_value to either 0 or '0' is for the
// first option within a 0-indexed array of checkboxes, and for this,
// form_process_checkboxes() uses the string rather than the integer.

Dries Buytaert
committed
return isset($input) ? $element['#return_value'] : 0;

Dries Buytaert
committed
}
}
/**

Dries Buytaert
committed
* Determines the value for a checkboxes form element.

Dries Buytaert
committed
*

Dries Buytaert
committed
* The form element whose value is being populated.
* @param $input
* The incoming input to populate the form element. If this is FALSE,

Dries Buytaert
committed
* the element's default value should be returned.

Dries Buytaert
committed
*

Dries Buytaert
committed
* @return
* The data that will appear in the $element_state['values'] collection

Dries Buytaert
committed
* for this element. Return nothing to use the default.

Dries Buytaert
committed
*/
function form_type_checkboxes_value($element, $input = FALSE) {
if ($input === FALSE) {

Dries Buytaert
committed
$value = array();
$element += array('#default_value' => array());
foreach ($element['#default_value'] as $key) {
$value[$key] = $key;

Dries Buytaert
committed
}
return $value;
}

Dries Buytaert
committed
elseif (is_array($input)) {
// Programmatic form submissions use NULL to indicate that a checkbox
// should be unchecked; see drupal_form_submit(). We therefore remove all
// NULL elements from the array before constructing the return value, to
// simulate the behavior of web browsers (which do not send unchecked
// checkboxes to the server at all). This will not affect non-programmatic

Angie Byron
committed
// form submissions, since all values in \Drupal::request()->request are
// strings.

Dries Buytaert
committed
foreach ($input as $key => $value) {
if (!isset($value)) {

Dries Buytaert
committed
unset($input[$key]);
}
}
return drupal_map_assoc($input);
}

Dries Buytaert
committed
else {

Dries Buytaert
committed
return array();
}

Dries Buytaert
committed
}
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
/**
* Determines the value of a table form element.
*
* @param array $element
* The form element whose value is being populated.
* @param array|false $input
* The incoming input to populate the form element. If this is FALSE,
* the element's default value should be returned.
*
* @return array
* The data that will appear in the $form_state['values'] collection
* for this element. Return nothing to use the default.
*/
function form_type_table_value(array $element, $input = FALSE) {
// If #multiple is FALSE, the regular default value of radio buttons is used.
if (!empty($element['#tableselect']) && !empty($element['#multiple'])) {
// Contrary to #type 'checkboxes', the default value of checkboxes in a
// table is built from the array keys (instead of array values) of the
// #default_value property.
// @todo D8: Remove this inconsistency.
if ($input === FALSE) {
$element += array('#default_value' => array());
return drupal_map_assoc(array_keys(array_filter($element['#default_value'])));
}
else {
return is_array($input) ? drupal_map_assoc($input) : array();
}
}
}
/**
* Form value callback: Determines the value for a #type radios form element.
*
* @param $element
* The form element whose value is being populated.
* @param $input
* (optional) The incoming input to populate the form element. If FALSE, the
* element's default value is returned. Defaults to FALSE.
*
* @return
* The data that will appear in the $element_state['values'] collection for
* this element.
*/
function form_type_radios_value(&$element, $input = FALSE) {
if ($input !== FALSE) {

Angie Byron
committed
// When there's user input (including NULL), return it as the value.

Alex Pott
committed
// However, if NULL is submitted, FormBuilder::handleInputElement() will

Angie Byron
committed
// apply the default value, and we want that validated against #options
// unless it's empty. (An empty #default_value, such as NULL or FALSE, can
// be used to indicate that no radio button is selected by default.)
if (!isset($input) && !empty($element['#default_value'])) {
$element['#needs_validation'] = TRUE;
}
return $input;
}

Angie Byron
committed
else {
// For default value handling, simply return #default_value. Additionally,
// for a NULL default value, set #has_garbage_value to prevent

Alex Pott
committed
// FormBuilder::handleInputElement() converting the NULL to an empty

Angie Byron
committed
// string, so that code can distinguish between nothing selected and the
// selection of a radio button whose value is an empty string.
$value = isset($element['#default_value']) ? $element['#default_value'] : NULL;
if (!isset($value)) {
$element['#has_garbage_value'] = TRUE;
}
return $value;
}
}

Angie Byron
committed
/**

Dries Buytaert
committed
* Determines the value for a tableselect form element.

Angie Byron
committed
*
* @param $element
* The form element whose value is being populated.
* @param $input
* The incoming input to populate the form element. If this is FALSE,
* the element's default value should be returned.

Dries Buytaert
committed
*

Angie Byron
committed
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
* @return
* The data that will appear in the $element_state['values'] collection
* for this element. Return nothing to use the default.
*/
function form_type_tableselect_value($element, $input = FALSE) {
// If $element['#multiple'] == FALSE, then radio buttons are displayed and
// the default value handling is used.
if (isset($element['#multiple']) && $element['#multiple']) {
// Checkboxes are being displayed with the default value coming from the
// keys of the #default_value property. This differs from the checkboxes
// element which uses the array values.
if ($input === FALSE) {
$value = array();
$element += array('#default_value' => array());
foreach ($element['#default_value'] as $key => $flag) {
if ($flag) {
$value[$key] = $key;
}
}
return $value;
}
else {
return is_array($input) ? drupal_map_assoc($input) : array();
}
}
}

Dries Buytaert
committed
/**

Dries Buytaert
committed
* Determines the value for a password_confirm form element.

Dries Buytaert
committed
*

Dries Buytaert
committed
* The form element whose value is being populated.
* @param $input
* The incoming input to populate the form element. If this is FALSE,

Dries Buytaert
committed
* the element's default value should be returned.

Dries Buytaert
committed
*

Dries Buytaert
committed
* @return
* The data that will appear in the $element_state['values'] collection

Dries Buytaert
committed
* for this element. Return nothing to use the default.

Dries Buytaert
committed
*/
function form_type_password_confirm_value($element, $input = FALSE) {
if ($input === FALSE) {
$element += array('#default_value' => array());
return $element['#default_value'] + array('pass1' => '', 'pass2' => '');

Dries Buytaert
committed
}
}
/**

Dries Buytaert
committed
* Determines the value for a select form element.

Dries Buytaert
committed
*

Dries Buytaert
committed
* The form element whose value is being populated.
* @param $input
* The incoming input to populate the form element. If this is FALSE,

Dries Buytaert
committed
* the element's default value should be returned.

Dries Buytaert
committed
*

Dries Buytaert
committed
* @return
* The data that will appear in the $element_state['values'] collection

Dries Buytaert
committed
* for this element. Return nothing to use the default.

Dries Buytaert
committed
*/
function form_type_select_value($element, $input = FALSE) {
if ($input !== FALSE) {
if (isset($element['#multiple']) && $element['#multiple']) {

Dries Buytaert
committed
// If an enabled multi-select submits NULL, it means all items are
// unselected. A disabled multi-select always submits NULL, and the
// default value should be used.
if (empty($element['#disabled'])) {
return (is_array($input)) ? drupal_map_assoc($input) : array();
}
else {
return (isset($element['#default_value']) && is_array($element['#default_value'])) ? $element['#default_value'] : array();
}

Dries Buytaert
committed
}

Dries Buytaert
committed
// Non-multiple select elements may have an empty option preprended to them
// (see form_process_select()). When this occurs, usually #empty_value is
// an empty string, but some forms set #empty_value to integer 0 or some
// other non-string constant. PHP receives all submitted form input as
// strings, but if the empty option is selected, set the value to match the
// empty value exactly.
elseif (isset($element['#empty_value']) && $input === (string) $element['#empty_value']) {
return $element['#empty_value'];
}

Dries Buytaert
committed
else {

Dries Buytaert
committed
}
}
}
/**

Dries Buytaert
committed
* Determines the value for a textfield form element.

Dries Buytaert
committed
*

Dries Buytaert
committed
* The form element whose value is being populated.
* @param $input
* The incoming input to populate the form element. If this is FALSE,

Dries Buytaert
committed
* the element's default value should be returned.

Dries Buytaert
committed
*

Dries Buytaert
committed
* @return
* The data that will appear in the $element_state['values'] collection

Dries Buytaert
committed
* for this element. Return nothing to use the default.

Dries Buytaert
committed
*/
function form_type_textfield_value($element, $input = FALSE) {

Dries Buytaert
committed
if ($input !== FALSE && $input !== NULL) {
// Equate $input to the form value to ensure it's marked for

Dries Buytaert
committed
// validation.
return str_replace(array("\r", "\n"), '', $input);

Dries Buytaert
committed
}
}
/**

Dries Buytaert
committed
* Determines the value for form's token value.

Dries Buytaert
committed
*

Dries Buytaert
committed
* The form element whose value is being populated.
* @param $input
* The incoming input to populate the form element. If this is FALSE,

Dries Buytaert
committed
* the element's default value should be returned.

Dries Buytaert
committed
*

Dries Buytaert
committed
* @return
* The data that will appear in the $element_state['values'] collection

Dries Buytaert
committed
* for this element. Return nothing to use the default.

Dries Buytaert
committed
*/
function form_type_token_value($element, $input = FALSE) {
if ($input !== FALSE) {
return (string) $input;

Dries Buytaert
committed
}
}

Dries Buytaert
committed
* Changes submitted form values during form validation.
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->setValue().
*
* @see \Drupal\Core\Form\FormBuilderInterface::setValue().
function form_set_value($element, $value, &$form_state) {

Alex Pott
committed
\Drupal::formBuilder()->setValue($element, $value, $form_state);
/**
* Allows PHP array processing of multiple select options with the same value.
*
* Used for form select elements which need to validate HTML option groups
* and multiple options which may return the same value. Associative PHP arrays
* cannot handle these structures, since they share a common key.
*
* @param $array
* The form options array to process.
*
* @return
* An array with all hierarchical elements flattened to a single array.
*
* @deprecated in Drupal 8.x-dev, will be removed before Drupal 8.0.
* Use \Drupal::formBuilder()->flattenOptions().
*
* @see \Drupal\Core\Form\FormBuilderInterface::flattenOptions().

Angie Byron
committed
function form_options_flatten($array) {
return \Drupal::formBuilder()->flattenOptions($array);

Dries Buytaert
committed
/**
* Processes a select list form element.
*
* This process callback is mandatory for select fields, since all user agents
* automatically preselect the first available option of single (non-multiple)
* select lists.
*
* @param $element
* The form element to process. Properties used:
* - #multiple: (optional) Indicates whether one or more options can be
* selected. Defaults to FALSE.
* - #default_value: Must be NULL or not set in case there is no value for the
* element yet, in which case a first default option is inserted by default.
* Whether this first option is a valid option depends on whether the field
* is #required or not.
* - #required: (optional) Whether the user needs to select an option (TRUE)

Dries Buytaert
committed
* or not (FALSE). Defaults to FALSE.

Dries Buytaert
committed
* - #empty_option: (optional) The label to show for the first default option.
* By default, the label is automatically set to "- Please select -" for a
* required field and "- None -" for an optional field.
* - #empty_value: (optional) The value for the first default option, which is

Dries Buytaert
committed
* used to determine whether the user submitted a value or not.
* - If #required is TRUE, this defaults to '' (an empty string).
* - If #required is not TRUE and this value isn't set, then no extra option
* is added to the select control, leaving the control in a slightly
* illogical state, because there's no way for the user to select nothing,
* since all user agents automatically preselect the first available
* option. But people are used to this being the behavior of select
* controls.
* @todo Address the above issue in Drupal 8.
* - If #required is not TRUE and this value is set (most commonly to an
* empty string), then an extra option (see #empty_option above)
* representing a "non-selection" is added with this as its value.

Dries Buytaert
committed
*
* @see _form_validate()
*/
function form_process_select($element) {
// #multiple select fields need a special #name.
if ($element['#multiple']) {
$element['#attributes']['multiple'] = 'multiple';
$element['#attributes']['name'] = $element['#name'] . '[]';
}
// A non-#multiple select needs special handling to prevent user agents from
// preselecting the first option without intention. #multiple select lists do
// not get an empty option, as it would not make sense, user interface-wise.
else {

Angie Byron
committed
// If the element is set to #required through #states, override the
// element's #required setting.
$required = isset($element['#states']['required']) ? TRUE : $element['#required'];

Dries Buytaert
committed
// If the element is required and there is no #default_value, then add an
// empty option that will fail validation, so that the user is required to
// make a choice. Also, if there's a value for #empty_value or
// #empty_option, then add an option that represents emptiness.
if (($required && !isset($element['#default_value'])) || isset($element['#empty_value']) || isset($element['#empty_option'])) {

Dries Buytaert
committed
$element += array(
'#empty_value' => '',
'#empty_option' => $required ? t('- Select -') : t('- None -'),

Dries Buytaert
committed
);
// The empty option is prepended to #options and purposively not merged
// to prevent another option in #options mistakenly using the same value
// as #empty_value.
$empty_option = array($element['#empty_value'] => $element['#empty_option']);
$element['#options'] = $empty_option + $element['#options'];
}
}
return $element;
}
* Returns HTML for a select form element.
*
* It is possible to group options together; to do this, change the format of
* $options to an associative array in which the keys are group labels, and the
* values are associative arrays in the normal $options format.

Dries Buytaert
committed
* @param $variables
* An associative array containing:
* - element: An associative array containing the properties of the element.
* Properties used: #title, #value, #options, #description, #extra,
* #multiple, #required, #name, #attributes, #size.
*

Gábor Hojtsy
committed
* @ingroup themeable

Dries Buytaert
committed
function theme_select($variables) {
$element = $variables['element'];

Dries Buytaert
committed
element_set_attributes($element, array('id', 'name', 'size'));
_form_set_attributes($element, array('form-select'));

Dries Buytaert
committed
return '<select' . new Attribute($element['#attributes']) . '>' . form_select_options($element) . '</select>';

Dries Buytaert
committed
}

Angie Byron
committed
/**

Dries Buytaert
committed
* Converts a select form element's options array into HTML.

Angie Byron
committed
*
* @param $element
* An associative array containing the properties of the element.
* @param $choices
* Mixed: Either an associative array of items to list as choices, or an
* object with an 'option' member that is an associative array. This
* parameter is only used internally and should not be passed.

Dries Buytaert
committed
*

Angie Byron
committed
* @return
* An HTML string of options for the select form element.
*/

Dries Buytaert
committed
function form_select_options($element, $choices = NULL) {
if (!isset($choices)) {
if (empty($element['#options'])) {
return '';
}

Dries Buytaert
committed
$choices = $element['#options'];
}
// array_key_exists() accommodates the rare event where $element['#value'] is NULL.
// isset() fails in this situation.
$value_valid = isset($element['#value']) || array_key_exists('#value', $element);

Dries Buytaert
committed
$value_is_array = $value_valid && is_array($element['#value']);
// Check if the element is multiple select and no value has been selected.
$empty_value = (empty($element['#value']) && !empty($element['#multiple']));

Dries Buytaert
committed
$options = '';
foreach ($choices as $key => $choice) {
$options .= '<optgroup label="' . $key . '">';

Dries Buytaert
committed
$options .= form_select_options($element, $choice);
$options .= '</optgroup>';

Neil Drumm
committed
elseif (is_object($choice)) {
$options .= form_select_options($element, $choice->option);
}
$key = (string) $key;
$empty_choice = $empty_value && $key == '_none';
if ($value_valid && ((!$value_is_array && (string) $element['#value'] === $key || ($value_is_array && in_array($key, $element['#value']))) || $empty_choice)) {
$selected = ' selected="selected"';
}
else {
$selected = '';
}

Angie Byron
committed
$options .= '<option value="' . String::checkPlain($key) . '"' . $selected . '>' . String::checkPlain($choice) . '</option>';

Dries Buytaert
committed
return $options;

Steven Wittens
committed
/**

Dries Buytaert
committed
* Returns the indexes of a select element's options matching a given key.
*
* This function is useful if you need to modify the options that are
* already in a form element; for example, to remove choices which are
* not valid because of additional filters imposed by another module.
* One example might be altering the choices in a taxonomy selector.
* To correctly handle the case of a multiple hierarchy taxonomy,
* #options arrays can now hold an array of objects, instead of a
* direct mapping of keys to labels, so that multiple choices in the
* selector can have the same key (and label). This makes it difficult
* to manipulate directly, which is why this helper function exists.
*
* This function does not support optgroups (when the elements of the
* #options array are themselves arrays), and will return FALSE if
* arrays are found. The caller must either flatten/restore or
* manually do their manipulations in this case, since returning the
* index is not sufficient, and supporting this would make the
* "helper" too complicated and cumbersome to be of any help.
*
* As usual with functions that can return array() or FALSE, do not
* forget to use === and !== if needed.

Steven Wittens
committed
*
* @param $element
* The select element to search.

Steven Wittens
committed
* @param $key
* The key to look for.

Dries Buytaert
committed
*

Steven Wittens
committed
* @return
* An array of indexes that match the given $key. Array will be
* empty if no elements were found. FALSE if optgroups were found.

Steven Wittens
committed
*/
function form_get_options($element, $key) {
$keys = array();
foreach ($element['#options'] as $index => $choice) {
if (is_array($choice)) {
return FALSE;
}

Angie Byron
committed
elseif (is_object($choice)) {
if (isset($choice->option[$key])) {
$keys[] = $index;
}
}

Angie Byron
committed
elseif ($index == $key) {
$keys[] = $index;

Steven Wittens
committed
}
}
return $keys;