2005-10-07 06:11:12 +00:00
< ? php
2005-11-01 09:58:01 +00:00
2012-02-19 03:41:24 +00:00
/**
* @ file
* Functions for form and batch generation and processing .
*/
2012-12-17 21:54:13 +00:00
use Drupal\Component\Utility\NestedArray ;
2013-10-16 11:04:31 +00:00
use Drupal\Component\Utility\Number ;
2013-10-07 05:34:09 +00:00
use Drupal\Component\Utility\String ;
2013-10-09 04:42:16 +00:00
use Drupal\Component\Utility\Url ;
2013-01-15 15:35:31 +00:00
use Drupal\Core\Database\Database ;
2013-05-25 20:12:45 +00:00
use Drupal\Core\Language\Language ;
2012-09-04 13:32:47 +00:00
use Drupal\Core\Template\Attribute ;
2013-01-15 15:35:31 +00:00
use Drupal\Core\Utility\Color ;
Issue #1668866 by ParisLiakos, aspilicious, tim.plunkett, pdrake, g.oechsler, dawehner, Berdir, corvus_ch, damiankloip, disasm, marcingy, neclimdul: Replace drupal_goto() with RedirectResponse.
2013-06-19 16:07:30 +00:00
use Symfony\Component\HttpFoundation\RedirectResponse ;
2012-07-07 20:21:18 +00:00
2005-10-07 06:11:12 +00:00
/**
2008-01-21 15:17:01 +00:00
* @ 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
2008-02-06 19:38:28 +00:00
* functions using \ @ see . Conversely , validate and submit functions should
2008-01-21 15:17:01 +00:00
* reference the form builder function using \ @ see . For examples , of this see
2008-02-06 19:38:28 +00:00
* system_modules_uninstall () or user_pass (), the latter of which has the
2008-01-21 15:17:01 +00:00
* following in its doxygen documentation :
2013-06-06 16:21:59 +00:00
* - \ @ ingroup forms
* - \ @ see user_pass_validate ()
* - \ @ see user_pass_submit ()
2008-01-21 15:17:01 +00:00
*
2013-06-06 16:21:59 +00:00
* @ }
2008-01-21 15:17:01 +00:00
*/
/**
* @ defgroup form_api Form generation
2005-10-07 06:11:12 +00:00
* @ {
2006-08-18 18:58:47 +00:00
* Functions to enable the processing and display of HTML forms .
2005-10-07 06:11:12 +00:00
*
2006-08-18 18:58:47 +00:00
* 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 .
*
2010-06-15 15:52:04 +00:00
* 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 .
2006-08-18 18:58:47 +00:00
*
2010-06-15 15:52:04 +00:00
* 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 :
2007-11-09 07:40:55 +00:00
* @ code
2010-06-15 15:52:04 +00:00
* $form = drupal_get_form ( 'my_module_example_form' );
* ...
* function my_module_example_form ( $form , & $form_state ) {
* $form [ 'submit' ] = array (
* '#type' => 'submit' ,
* '#value' => t ( 'Submit' ),
* );
2010-06-16 05:06:15 +00:00
* return $form ;
2010-06-15 15:52:04 +00:00
* }
* function my_module_example_form_validate ( $form , & $form_state ) {
* // Validation logic.
* }
* function my_module_example_form_submit ( $form , & $form_state ) {
* // Submission logic.
* }
2007-11-09 07:40:55 +00:00
* @ endcode
2006-08-18 18:58:47 +00:00
*
2010-06-15 15:52:04 +00:00
* 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 ,
* );
2010-06-16 05:06:15 +00:00
* return $form ;
2010-06-15 15:52:04 +00:00
* }
* @ endcode
2006-08-18 18:58:47 +00:00
*
2010-06-15 15:52:04 +00:00
* 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
2012-05-04 20:07:43 +00:00
* @ link forms_api_reference . html Form API reference @ endlink
2010-06-15 15:52:04 +00:00
* and the
2011-09-27 17:39:34 +00:00
* @ link http :// drupal . org / node / 37775 Form API documentation section . @ endlink
2010-06-15 15:52:04 +00:00
* 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 .
*
2011-09-27 17:39:34 +00:00
* See drupal_build_form () for documentation of $form_state keys .
2005-10-07 06:11:12 +00:00
*/
/**
2012-02-19 03:41:24 +00:00
* Returns a renderable form array for a given form ID .
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> getForm () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: getForm () .
2006-08-18 18:58:47 +00:00
*/
2013-02-13 17:17:55 +00:00
function drupal_get_form ( $form_arg ) {
2013-10-25 22:54:34 +00:00
return call_user_func_array ( array ( \Drupal :: formBuilder (), 'getForm' ), func_get_args ());
2013-02-06 14:00:25 +00:00
}
2009-03-14 20:13:27 +00:00
/**
2012-02-19 03:41:24 +00:00
* Builds and processes a form for a given form ID .
2009-03-14 20:13:27 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> buildForm () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: buildForm () .
2009-03-14 20:13:27 +00:00
*/
function drupal_build_form ( $form_id , & $form_state ) {
2013-10-25 22:54:34 +00:00
return \Drupal :: formBuilder () -> buildForm ( $form_id , $form_state );
2007-05-14 13:43:38 +00:00
}
2006-12-06 15:49:45 +00:00
2009-03-14 20:13:27 +00:00
/**
2012-02-19 03:41:24 +00:00
* Retrieves default values for the $form_state array .
2013-10-25 22:54:34 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> getFormStateDefaults () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: getFormStateDefaults () .
2009-03-14 20:13:27 +00:00
*/
function form_state_defaults () {
2013-10-25 22:54:34 +00:00
return \Drupal :: formBuilder () -> getFormStateDefaults ();
2009-03-14 20:13:27 +00:00
}
2007-11-19 19:23:28 +00:00
/**
2010-09-13 01:09:26 +00:00
* Constructs a new $form from the information in $form_state .
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> rebuildForm () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: rebuildForm () .
2007-11-19 19:23:28 +00:00
*/
2010-03-31 19:34:56 +00:00
function drupal_rebuild_form ( $form_id , & $form_state , $old_form = NULL ) {
2013-10-25 22:54:34 +00:00
return \Drupal :: formBuilder () -> rebuildForm ( $form_id , $form_state , $old_form );
2007-11-19 19:23:28 +00:00
}
2007-07-29 17:28:23 +00:00
/**
2012-02-19 03:41:24 +00:00
* Fetches a form from the cache .
2013-10-25 22:54:34 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> getCache () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: getCache () .
2007-07-29 17:28:23 +00:00
*/
function form_get_cache ( $form_build_id , & $form_state ) {
2013-10-25 22:54:34 +00:00
return \Drupal :: formBuilder () -> getCache ( $form_build_id , $form_state );
2007-07-29 17:28:23 +00:00
}
/**
2012-02-19 03:41:24 +00:00
* Stores a form in the cache .
2013-10-25 22:54:34 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> setCache () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: setCache () .
2007-07-29 17:28:23 +00:00
*/
function form_set_cache ( $form_build_id , $form , $form_state ) {
2013-10-25 22:54:34 +00:00
\Drupal :: formBuilder () -> setCache ( $form_build_id , $form , $form_state );
2009-12-05 14:33:55 +00:00
}
2010-11-27 19:12:56 +00:00
/**
2012-07-30 18:31:47 +00:00
* Ensures an include file is loaded whenever the form is processed .
2010-11-27 19:12:56 +00:00
*
* 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 ;
}
2006-08-31 14:59:28 +00:00
/**
2010-03-04 09:07:27 +00:00
* Retrieves , populates , and processes a form .
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> submitForm () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: submitForm () .
2006-08-31 14:59:28 +00:00
*/
2013-02-27 22:30:50 +00:00
function drupal_form_submit ( $form_arg , & $form_state ) {
2013-10-25 22:54:34 +00:00
\Drupal :: formBuilder () -> submitForm ( $form_arg , $form_state );
2006-08-31 14:59:28 +00:00
}
2006-08-18 18:58:47 +00:00
/**
* Retrieves the structured array that defines a given form .
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> retrieveForm () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: retrieveForm () .
2006-08-18 18:58:47 +00:00
*/
2007-06-04 07:22:23 +00:00
function drupal_retrieve_form ( $form_id , & $form_state ) {
2013-10-25 22:54:34 +00:00
return \Drupal :: formBuilder () -> retrieveForm ( $form_id , $form_state );
2012-08-16 11:30:43 +00:00
2006-08-18 18:58:47 +00:00
}
/**
2009-09-21 06:44:14 +00:00
* Processes a form submission .
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> processForm () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: processForm () .
2005-10-07 06:11:12 +00:00
*/
2007-05-14 13:43:38 +00:00
function drupal_process_form ( $form_id , & $form , & $form_state ) {
2013-10-25 22:54:34 +00:00
\Drupal :: formBuilder () -> processForm ( $form_id , $form , $form_state );
2006-07-22 19:26:58 +00:00
}
/**
2012-02-19 03:41:24 +00:00
* Prepares a structured form array .
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> prepareForm () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: prepareForm () .
2006-07-22 19:26:58 +00:00
*/
2007-05-14 13:43:38 +00:00
function drupal_prepare_form ( $form_id , & $form , & $form_state ) {
2013-10-25 22:54:34 +00:00
\Drupal :: formBuilder () -> prepareForm ( $form_id , $form , $form_state );
2005-10-07 06:11:12 +00:00
}
2006-07-22 19:26:58 +00:00
/**
2012-02-19 03:41:24 +00:00
* Validates user - submitted form data in the $form_state array .
2006-07-22 19:26:58 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> validateForm () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: validateForm () .
2006-07-22 19:26:58 +00:00
*/
2009-11-28 14:39:31 +00:00
function drupal_validate_form ( $form_id , & $form , & $form_state ) {
2013-10-25 22:54:34 +00:00
\Drupal :: formBuilder () -> validateForm ( $form_id , $form , $form_state );
2005-10-07 06:11:12 +00:00
}
2006-07-22 19:26:58 +00:00
/**
2009-09-21 06:44:14 +00:00
* Redirects the user to a URL after a form has been processed .
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> redirectForm () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: redirectForm () .
2006-07-22 19:26:58 +00:00
*/
2009-09-21 06:44:14 +00:00
function drupal_redirect_form ( $form_state ) {
2013-10-25 22:54:34 +00:00
return \Drupal :: formBuilder () -> redirectForm ( $form_state );
2005-10-07 06:11:12 +00:00
}
2007-05-14 13:43:38 +00:00
/**
2012-02-19 03:41:24 +00:00
* Executes custom validation and submission handlers for a given form .
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> executeHandlers () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: executeHandlers () .
2007-05-14 13:43:38 +00:00
*/
function form_execute_handlers ( $type , & $form , & $form_state ) {
2013-10-25 22:54:34 +00:00
\Drupal :: formBuilder () -> executeHandlers ( $type , $form , $form_state );
2007-05-14 13:43:38 +00:00
}
2005-10-13 10:02:31 +00:00
/**
2009-12-04 16:29:15 +00:00
* Files an error against a form element .
2007-12-23 12:33:13 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> setErrorByName () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: setErrorByName () .
2005-10-13 10:02:31 +00:00
*/
2013-11-23 20:57:04 +00:00
function form_set_error ( $name , array & $form_state , $message = '' ) {
\Drupal :: formBuilder () -> setErrorByName ( $name , $form_state , $message );
2005-10-13 10:02:31 +00:00
}
2009-06-02 13:47:26 +00:00
/**
2012-02-19 03:41:24 +00:00
* Clears all errors against all form elements made by form_set_error () .
2013-10-25 22:54:34 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> clearErrors () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: clearErrors () .
2009-06-02 13:47:26 +00:00
*/
2013-11-23 20:57:04 +00:00
function form_clear_error ( array & $form_state ) {
\Drupal :: formBuilder () -> clearErrors ( $form_state );
2009-06-02 13:47:26 +00:00
}
2005-10-13 10:02:31 +00:00
/**
2012-02-19 03:41:24 +00:00
* Returns an associative array of all errors .
2013-10-25 22:54:34 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> getErrors () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: getErrors () .
2005-10-13 10:02:31 +00:00
*/
2013-11-23 20:57:04 +00:00
function form_get_errors ( array & $form_state ) {
return \Drupal :: formBuilder () -> getErrors ( $form_state );
2005-10-13 10:02:31 +00:00
}
/**
2010-09-16 20:14:49 +00:00
* Returns the error message filed against the given form element .
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> getError () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: getError () .
2005-10-13 10:02:31 +00:00
*/
2013-11-23 20:57:04 +00:00
function form_get_error ( $element , array & $form_state ) {
return \Drupal :: formBuilder () -> getError ( $element , $form_state );
2005-10-13 10:02:31 +00:00
}
2005-10-07 06:11:12 +00:00
/**
2012-02-19 03:41:24 +00:00
* Flags an element as having an error .
2013-10-25 22:54:34 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> setError () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: setError () .
2005-10-07 06:11:12 +00:00
*/
2013-11-23 20:57:04 +00:00
function form_error ( & $element , array & $form_state , $message = '' ) {
\Drupal :: formBuilder () -> setError ( $element , $form_state , $message );
2005-10-07 06:11:12 +00:00
}
/**
2012-02-19 03:41:24 +00:00
* Builds and processes all elements in the structured form array .
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> doBuildForm () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: doBuildForm () .
2005-10-07 06:11:12 +00:00
*/
2010-10-13 13:43:21 +00:00
function form_builder ( $form_id , & $element , & $form_state ) {
2013-10-25 22:54:34 +00:00
return \Drupal :: formBuilder () -> doBuildForm ( $form_id , $element , $form_state );
2007-07-29 17:28:23 +00:00
}
2009-10-15 11:47:25 +00:00
/**
* 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
*
2011-05-08 19:50:38 +00:00
* @ param $form_state
2009-10-15 11:47:25 +00:00
* 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.
2010-03-26 18:58:12 +00:00
// 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 );
2011-11-03 07:32:28 +00:00
$key_exists = NULL ;
2012-12-17 21:54:13 +00:00
$values = & NestedArray :: getValue ( $form_state [ 'values' ], $parents , $key_exists );
2011-11-03 07:32:28 +00:00
if ( $key_exists && is_array ( $values )) {
unset ( $values [ $last_parent ]);
2009-10-15 11:47:25 +00:00
}
}
}
2007-08-10 10:51:17 +00:00
/**
2012-02-19 03:41:24 +00:00
* Determines the value for an image button form element .
2007-08-10 10:51:17 +00:00
*
* @ param $form
* The form element whose value is being populated .
2009-07-06 13:31:47 +00:00
* @ param $input
* The incoming input to populate the form element . If this is FALSE ,
2007-08-10 10:51:17 +00:00
* the element ' s default value should be returned .
2009-06-29 17:27:58 +00:00
* @ param $form_state
2009-03-14 20:13:27 +00:00
* A keyed array containing the current state of the form .
2012-02-19 03:41:24 +00:00
*
2007-08-10 10:51:17 +00:00
* @ return
* The data that will appear in the $form_state [ 'values' ] collection
* for this element . Return nothing to use the default .
*/
2009-07-06 13:31:47 +00:00
function form_type_image_button_value ( $form , $input , $form_state ) {
if ( $input !== FALSE ) {
if ( ! empty ( $input )) {
2007-08-10 10:51:17 +00:00
// 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'.
2009-07-06 13:31:47 +00:00
$input = $form_state [ 'input' ];
2009-06-29 17:27:58 +00:00
foreach ( explode ( '[' , $form [ '#name' ]) as $element_name ) {
2007-08-10 10:51:17 +00:00
// chop off the ] that may exist.
if ( substr ( $element_name , - 1 ) == ']' ) {
$element_name = substr ( $element_name , 0 , - 1 );
}
2009-07-06 13:31:47 +00:00
if ( ! isset ( $input [ $element_name ])) {
if ( isset ( $input [ $element_name . '_x' ])) {
2007-08-10 10:51:17 +00:00
return $form [ '#return_value' ];
}
return NULL ;
}
2009-07-06 13:31:47 +00:00
$input = $input [ $element_name ];
2007-08-10 10:51:17 +00:00
}
return $form [ '#return_value' ];
}
}
}
2007-07-04 15:45:37 +00:00
/**
2012-02-19 03:41:24 +00:00
* Determines the value for a checkbox form element .
2007-07-04 15:45:37 +00:00
*
* @ param $form
2007-07-14 15:23:29 +00:00
* The form element whose value is being populated .
2012-02-19 03:41:24 +00:00
* @ param $input
2009-07-06 13:31:47 +00:00
* The incoming input to populate the form element . If this is FALSE ,
2007-07-14 15:23:29 +00:00
* the element ' s default value should be returned .
2012-02-19 03:41:24 +00:00
*
2007-07-04 15:45:37 +00:00
* @ return
2009-07-06 13:31:47 +00:00
* The data that will appear in the $element_state [ 'values' ] collection
2007-07-14 15:23:29 +00:00
* for this element . Return nothing to use the default .
2007-07-04 15:45:37 +00:00
*/
2009-07-06 13:31:47 +00:00
function form_type_checkbox_value ( $element , $input = FALSE ) {
2010-10-28 02:20:14 +00:00
if ( $input === FALSE ) {
// Use #default_value as the default value of a checkbox, except change
2013-10-25 22:54:34 +00:00
// NULL to 0, because FormBuilder::handleInputElement() would otherwise
2010-10-28 02:20:14 +00:00
// 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
2013-10-25 22:54:34 +00:00
// FormBuilder::handleInputElement() detects this, and calls this
2010-10-28 02:20:14 +00:00
// 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.
2010-04-11 19:00:27 +00:00
return isset ( $input ) ? $element [ '#return_value' ] : 0 ;
2007-07-04 15:45:37 +00:00
}
}
/**
2012-02-19 03:41:24 +00:00
* Determines the value for a checkboxes form element .
2007-07-04 15:45:37 +00:00
*
2009-07-06 13:31:47 +00:00
* @ param $element
2007-07-14 15:23:29 +00:00
* The form element whose value is being populated .
2009-07-06 13:31:47 +00:00
* @ param $input
* The incoming input to populate the form element . If this is FALSE ,
2007-07-14 15:23:29 +00:00
* the element ' s default value should be returned .
2012-02-19 03:41:24 +00:00
*
2007-07-04 15:45:37 +00:00
* @ return
2009-07-06 13:31:47 +00:00
* The data that will appear in the $element_state [ 'values' ] collection
2007-07-14 15:23:29 +00:00
* for this element . Return nothing to use the default .
2007-07-04 15:45:37 +00:00
*/
2009-07-06 13:31:47 +00:00
function form_type_checkboxes_value ( $element , $input = FALSE ) {
if ( $input === FALSE ) {
2007-07-04 15:45:37 +00:00
$value = array ();
2009-07-06 13:31:47 +00:00
$element += array ( '#default_value' => array ());
foreach ( $element [ '#default_value' ] as $key ) {
2010-03-13 22:33:05 +00:00
$value [ $key ] = $key ;
2007-07-04 15:45:37 +00:00
}
return $value ;
}
2010-07-26 13:07:59 +00:00
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
2013-12-05 18:02:36 +00:00
// form submissions, since all values in \Drupal::request()->request are
// strings.
2010-07-26 13:07:59 +00:00
foreach ( $input as $key => $value ) {
2010-09-26 23:31:36 +00:00
if ( ! isset ( $value )) {
2010-07-26 13:07:59 +00:00
unset ( $input [ $key ]);
}
}
return drupal_map_assoc ( $input );
}
2010-06-05 13:18:09 +00:00
else {
2010-07-26 13:07:59 +00:00
return array ();
2007-09-25 11:29:10 +00:00
}
2007-07-04 15:45:37 +00:00
}
2012-12-26 18:15:32 +00:00
/**
* 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 ();
}
}
}
2012-03-10 21:01:23 +00:00
/**
* 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 ) {
2012-07-26 11:56:58 +00:00
// When there's user input (including NULL), return it as the value.
2013-10-25 22:54:34 +00:00
// However, if NULL is submitted, FormBuilder::handleInputElement() will
2012-07-26 11:56:58 +00:00
// 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' ])) {
2012-03-10 21:01:23 +00:00
$element [ '#needs_validation' ] = TRUE ;
}
return $input ;
}
2012-07-26 11:56:58 +00:00
else {
// For default value handling, simply return #default_value. Additionally,
// for a NULL default value, set #has_garbage_value to prevent
2013-10-25 22:54:34 +00:00
// FormBuilder::handleInputElement() converting the NULL to an empty
2012-07-26 11:56:58 +00:00
// 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 ;
2012-03-10 21:01:23 +00:00
}
}
2010-10-21 20:46:58 +00:00
/**
2012-02-19 03:41:24 +00:00
* Determines the value for a tableselect form element .
2010-10-21 20:46:58 +00:00
*
* @ 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 .
2012-02-19 03:41:24 +00:00
*
2010-10-21 20:46:58 +00:00
* @ 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 ();
}
}
}
2007-07-04 15:45:37 +00:00
/**
2012-02-19 03:41:24 +00:00
* Determines the value for a password_confirm form element .
2007-07-04 15:45:37 +00:00
*
2009-07-06 13:31:47 +00:00
* @ param $element
2007-07-14 15:23:29 +00:00
* The form element whose value is being populated .
2009-07-06 13:31:47 +00:00
* @ param $input
* The incoming input to populate the form element . If this is FALSE ,
2007-07-14 15:23:29 +00:00
* the element ' s default value should be returned .
2012-02-19 03:41:24 +00:00
*
2007-07-04 15:45:37 +00:00
* @ return
2009-07-06 13:31:47 +00:00
* The data that will appear in the $element_state [ 'values' ] collection
2007-07-14 15:23:29 +00:00
* for this element . Return nothing to use the default .
2007-07-04 15:45:37 +00:00
*/
2009-07-06 13:31:47 +00:00
function form_type_password_confirm_value ( $element , $input = FALSE ) {
if ( $input === FALSE ) {
$element += array ( '#default_value' => array ());
return $element [ '#default_value' ] + array ( 'pass1' => '' , 'pass2' => '' );
2007-07-04 15:45:37 +00:00
}
}
/**
2012-02-19 03:41:24 +00:00
* Determines the value for a select form element .
2007-07-04 15:45:37 +00:00
*
2009-07-06 13:31:47 +00:00
* @ param $element
2007-07-14 15:23:29 +00:00
* The form element whose value is being populated .
2009-07-06 13:31:47 +00:00
* @ param $input
* The incoming input to populate the form element . If this is FALSE ,
2007-07-14 15:23:29 +00:00
* the element ' s default value should be returned .
2012-02-19 03:41:24 +00:00
*
2007-07-04 15:45:37 +00:00
* @ return
2009-07-06 13:31:47 +00:00
* The data that will appear in the $element_state [ 'values' ] collection
2007-07-14 15:23:29 +00:00
* for this element . Return nothing to use the default .
2007-07-04 15:45:37 +00:00
*/
2009-07-06 13:31:47 +00:00
function form_type_select_value ( $element , $input = FALSE ) {
if ( $input !== FALSE ) {
if ( isset ( $element [ '#multiple' ]) && $element [ '#multiple' ]) {
2010-03-12 14:38:37 +00:00
// 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 ();
}
2007-07-04 15:45:37 +00:00
}
2010-10-04 18:00:46 +00:00
// 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' ];
}
2007-07-04 15:45:37 +00:00
else {
2009-07-06 13:31:47 +00:00
return $input ;
2007-07-04 15:45:37 +00:00
}
}
}
/**
2012-02-19 03:41:24 +00:00
* Determines the value for a textfield form element .
2007-07-04 15:45:37 +00:00
*
2009-07-06 13:31:47 +00:00
* @ param $element
2007-07-14 15:23:29 +00:00
* The form element whose value is being populated .
2009-07-06 13:31:47 +00:00
* @ param $input
* The incoming input to populate the form element . If this is FALSE ,
2007-07-14 15:23:29 +00:00
* the element ' s default value should be returned .
2012-02-19 03:41:24 +00:00
*
2007-07-04 15:45:37 +00:00
* @ return
2009-07-06 13:31:47 +00:00
* The data that will appear in the $element_state [ 'values' ] collection
2007-07-14 15:23:29 +00:00
* for this element . Return nothing to use the default .
2007-07-04 15:45:37 +00:00
*/
2009-07-06 13:31:47 +00:00
function form_type_textfield_value ( $element , $input = FALSE ) {
2010-03-12 14:38:37 +00:00
if ( $input !== FALSE && $input !== NULL ) {
2009-07-06 13:31:47 +00:00
// Equate $input to the form value to ensure it's marked for
2007-07-04 15:45:37 +00:00
// validation.
2009-07-06 13:31:47 +00:00
return str_replace ( array ( " \r " , " \n " ), '' , $input );
2007-07-04 15:45:37 +00:00
}
}
/**
2012-02-19 03:41:24 +00:00
* Determines the value for form ' s token value .
2007-07-04 15:45:37 +00:00
*
2009-07-06 13:31:47 +00:00
* @ param $element
2007-07-14 15:23:29 +00:00
* The form element whose value is being populated .
2009-07-06 13:31:47 +00:00
* @ param $input
* The incoming input to populate the form element . If this is FALSE ,
2007-07-14 15:23:29 +00:00
* the element ' s default value should be returned .
2012-02-19 03:41:24 +00:00
*
2007-07-04 15:45:37 +00:00
* @ return
2009-07-06 13:31:47 +00:00
* The data that will appear in the $element_state [ 'values' ] collection
2007-07-14 15:23:29 +00:00
* for this element . Return nothing to use the default .
2007-07-04 15:45:37 +00:00
*/
2009-07-06 13:31:47 +00:00
function form_type_token_value ( $element , $input = FALSE ) {
if ( $input !== FALSE ) {
2010-05-06 05:59:31 +00:00
return ( string ) $input ;
2007-07-04 15:45:37 +00:00
}
}
2006-04-15 21:52:44 +00:00
/**
2012-02-19 03:41:24 +00:00
* Changes submitted form values during form validation .
2006-04-15 21:52:44 +00:00
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> setValue () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: setValue () .
2006-04-15 21:52:44 +00:00
*/
2009-07-06 13:31:47 +00:00
function form_set_value ( $element , $value , & $form_state ) {
2013-10-25 22:54:34 +00:00
\Drupal :: formBuilder () -> setValue ( $element , $value , $form_state );
2006-04-15 21:52:44 +00:00
}
2010-06-26 18:11:27 +00:00
/**
* 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 .
*
2014-02-20 13:49:37 +00:00
* @ deprecated in Drupal 8. x - dev , will be removed before Drupal 8.0 .
* Use \Drupal :: formBuilder () -> flattenOptions () .
*
* @ see \Drupal\Core\Form\FormBuilderInterface :: flattenOptions () .
2010-06-26 18:11:27 +00:00
*/
2013-11-23 05:13:32 +00:00
function form_options_flatten ( $array ) {
return \Drupal :: formBuilder () -> flattenOptions ( $array );
2006-01-06 07:15:47 +00:00
}
2010-09-24 21:36:22 +00:00
/**
* 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)
2010-10-04 18:00:46 +00:00
* or not ( FALSE ) . Defaults to FALSE .
2010-09-24 21:36:22 +00:00
* - #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
2010-10-04 18:00:46 +00:00
* 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 .
2010-09-24 21:36:22 +00:00
*
* @ 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 {
2013-03-24 18:54:56 +00:00
// If the element is set to #required through #states, override the
// element's #required setting.
$required = isset ( $element [ '#states' ][ 'required' ]) ? TRUE : $element [ '#required' ];
2010-10-04 18:00:46 +00:00
// 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' ])) {
2010-09-24 21:36:22 +00:00
$element += array (
'#empty_value' => '' ,
2011-01-18 18:23:40 +00:00
'#empty_option' => $required ? t ( '- Select -' ) : t ( '- None -' ),
2010-09-24 21:36:22 +00:00
);
// 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 ;
}
2005-10-07 06:11:12 +00:00
/**
2010-04-13 15:23:03 +00:00
* 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 .
2005-10-07 06:11:12 +00:00
*
2009-10-09 01:00:08 +00:00
* @ 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.
*
2007-12-06 09:58:34 +00:00
* @ ingroup themeable
2005-10-07 06:11:12 +00:00
*/
2009-10-09 01:00:08 +00:00
function theme_select ( $variables ) {
$element = $variables [ 'element' ];
2010-09-16 20:14:49 +00:00
element_set_attributes ( $element , array ( 'id' , 'name' , 'size' ));
2012-10-23 22:43:41 +00:00
_form_set_attributes ( $element , array ( 'form-select' ));
2010-09-16 20:14:49 +00:00
2012-09-04 13:32:47 +00:00
return '<select' . new Attribute ( $element [ '#attributes' ]) . '>' . form_select_options ( $element ) . '</select>' ;
2006-01-19 09:22:16 +00:00
}
2009-08-19 08:15:36 +00:00
/**
2012-02-19 03:41:24 +00:00
* Converts a select form element ' s options array into HTML .
2009-08-19 08:15:36 +00:00
*
* @ 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 .
2012-02-19 03:41:24 +00:00
*
2009-08-19 08:15:36 +00:00
* @ return
* An HTML string of options for the select form element .
*/
2006-01-19 09:22:16 +00:00
function form_select_options ( $element , $choices = NULL ) {
if ( ! isset ( $choices )) {
2013-02-06 12:03:07 +00:00
if ( empty ( $element [ '#options' ])) {
return '' ;
}
2006-01-19 09:22:16 +00:00
$choices = $element [ '#options' ];
}
2006-04-11 11:33:15 +00:00
// array_key_exists() accommodates the rare event where $element['#value'] is NULL.
2006-01-13 07:44:59 +00:00
// isset() fails in this situation.
$value_valid = isset ( $element [ '#value' ]) || array_key_exists ( '#value' , $element );
2010-09-16 20:14:49 +00:00
$value_is_array = $value_valid && is_array ( $element [ '#value' ]);
2014-02-14 17:05:59 +00:00
// Check if the element is multiple select and no value has been selected.
$empty_value = ( empty ( $element [ '#value' ]) && ! empty ( $element [ '#multiple' ]));
2006-01-19 09:22:16 +00:00
$options = '' ;
foreach ( $choices as $key => $choice ) {
2005-10-07 06:11:12 +00:00
if ( is_array ( $choice )) {
2008-04-14 17:48:46 +00:00
$options .= '<optgroup label="' . $key . '">' ;
2006-01-19 09:22:16 +00:00
$options .= form_select_options ( $element , $choice );
$options .= '</optgroup>' ;
2005-10-07 06:11:12 +00:00
}
2006-10-20 20:55:03 +00:00
elseif ( is_object ( $choice )) {
$options .= form_select_options ( $element , $choice -> option );
}
2005-10-07 06:11:12 +00:00
else {
2010-05-06 05:59:31 +00:00
$key = ( string ) $key ;
2014-02-14 17:05:59 +00:00
$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 )) {
2006-01-06 07:15:47 +00:00
$selected = ' selected="selected"' ;
}
else {
$selected = '' ;
}
2013-10-07 05:34:09 +00:00
$options .= '<option value="' . String :: checkPlain ( $key ) . '"' . $selected . '>' . String :: checkPlain ( $choice ) . '</option>' ;
2005-10-07 06:11:12 +00:00
}
}
2006-01-19 09:22:16 +00:00
return $options ;
2005-10-07 06:11:12 +00:00
}
2006-12-29 00:19:58 +00:00
/**
2012-02-19 03:41:24 +00:00
* Returns the indexes of a select element ' s options matching a given key .
2007-01-05 19:08:30 +00:00
*
* This function is useful if you need to modify the options that are
2007-01-23 19:17:55 +00:00
* already in a form element ; for example , to remove choices which are
2007-01-05 19:08:30 +00:00
* 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 .
2006-12-29 00:19:58 +00:00
*
* @ param $element
2007-01-05 19:08:30 +00:00
* The select element to search .
2006-12-29 00:19:58 +00:00
* @ param $key
* The key to look for .
2012-02-19 03:41:24 +00:00
*
2006-12-29 00:19:58 +00:00
* @ return
2007-01-05 19:08:30 +00:00
* An array of indexes that match the given $key . Array will be
* empty if no elements were found . FALSE if optgroups were found .
2006-12-29 00:19:58 +00:00
*/
2007-01-05 19:08:30 +00:00
function form_get_options ( $element , $key ) {
$keys = array ();
foreach ( $element [ '#options' ] as $index => $choice ) {
if ( is_array ( $choice )) {
return FALSE ;
}
2008-10-12 04:30:09 +00:00
elseif ( is_object ( $choice )) {
2007-01-05 19:08:30 +00:00
if ( isset ( $choice -> option [ $key ])) {
$keys [] = $index ;
}
}
2008-10-12 04:30:09 +00:00
elseif ( $index == $key ) {
2007-01-05 19:08:30 +00:00
$keys [] = $index ;
2006-12-29 00:19:58 +00:00
}
}
2007-01-05 19:08:30 +00:00
return $keys ;
2006-12-29 00:19:58 +00:00
}
2005-10-07 06:11:12 +00:00
/**
2010-04-13 15:23:03 +00:00
* Returns HTML for a fieldset form element and its children .
2005-10-07 06:11:12 +00:00
*
2009-10-09 01:00:08 +00:00
* @ param $variables
* An associative array containing :
* - element : An associative array containing the properties of the element .
2013-05-29 21:08:39 +00:00
* Properties used : #attributes, #children, #collapsed, #description, #id,
* #title, #value.
2009-10-09 01:00:08 +00:00
*
2007-12-06 09:58:34 +00:00
* @ ingroup themeable
2005-10-07 06:11:12 +00:00
*/
2009-10-09 01:00:08 +00:00
function theme_fieldset ( $variables ) {
$element = $variables [ 'element' ];
2010-09-16 20:14:49 +00:00
element_set_attributes ( $element , array ( 'id' ));
2012-10-23 22:43:41 +00:00
_form_set_attributes ( $element , array ( 'form-wrapper' ));
2009-11-16 05:11:01 +00:00
2014-02-20 11:40:28 +00:00
$element [ '#attributes' ][ 'class' ][] = 'form-item' ;
2012-11-29 07:16:36 +00:00
if ( ! empty ( $element [ '#description' ])) {
$description_id = $element [ '#attributes' ][ 'id' ] . '--description' ;
$element [ '#attributes' ][ 'aria-describedby' ] = $description_id ;
}
2014-02-20 11:40:28 +00:00
// If the element is required, a required marker is appended to the label.
// @see theme_form_element_label()
$required = '' ;
if ( ! empty ( $element [ '#required' ])) {
$marker = array (
'#theme' => 'form_required_marker' ,
'#element' => $element ,
);
$required = drupal_render ( $marker );
}
2013-01-17 20:43:29 +00:00
$legend_attributes = array ();
if ( isset ( $element [ '#title_display' ]) && $element [ '#title_display' ] == 'invisible' ) {
2013-06-17 19:58:27 +00:00
$legend_attributes [ 'class' ][] = 'visually-hidden' ;
2013-01-17 20:43:29 +00:00
}
2012-09-04 13:32:47 +00:00
$output = '<fieldset' . new Attribute ( $element [ '#attributes' ]) . '>' ;
2014-02-20 11:40:28 +00:00
if (( isset ( $element [ '#title' ]) && $element [ '#title' ] !== '' ) || ! empty ( $element [ '#required' ])) {
2010-03-03 19:46:26 +00:00
// Always wrap fieldset legends in a SPAN for CSS positioning.
2014-02-20 11:40:28 +00:00
$output .= '<legend' . new Attribute ( $legend_attributes ) . '><span class="fieldset-legend">' ;
$output .= t ( '!title!required' , array ( '!title' => $element [ '#title' ], '!required' => $required ));
$output .= '</span></legend>' ;
2009-11-16 05:11:01 +00:00
}
2010-03-03 19:46:26 +00:00
$output .= '<div class="fieldset-wrapper">' ;
2012-11-29 07:16:36 +00:00
2014-02-20 11:40:28 +00:00
if ( isset ( $element [ '#field_prefix' ])) {
$output .= '<span class="field-prefix">' . $element [ '#field_prefix' ] . '</span> ' ;
2009-11-16 05:11:01 +00:00
}
$output .= $element [ '#children' ];
2014-02-20 11:40:28 +00:00
if ( isset ( $element [ '#field_suffix' ])) {
$output .= ' <span class="field-suffix">' . $element [ '#field_suffix' ] . '</span>' ;
}
if ( ! empty ( $element [ '#description' ])) {
$attributes = array ( 'class' => 'description' , 'id' => $description_id );
$output .= '<div' . new Attribute ( $attributes ) . '>' . $element [ '#description' ] . '</div>' ;
2009-11-16 05:11:01 +00:00
}
2010-03-03 19:46:26 +00:00
$output .= '</div>' ;
2009-11-16 05:11:01 +00:00
$output .= " </fieldset> \n " ;
return $output ;
2005-10-07 06:11:12 +00:00
}
2012-11-27 07:06:47 +00:00
/**
Issue #2152207 by steveoliver, joelpittet, gnuget, idflood, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_details() to Twig
2014-02-07 04:26:52 +00:00
* Prepares variables for details element templates .
2012-11-27 07:06:47 +00:00
*
Issue #2152207 by steveoliver, joelpittet, gnuget, idflood, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_details() to Twig
2014-02-07 04:26:52 +00:00
* Default template : details . html . twig .
*
* @ param array $variables
2012-11-27 07:06:47 +00:00
* An associative array containing :
* - element : An associative array containing the properties of the element .
Issue #2152207 by steveoliver, joelpittet, gnuget, idflood, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_details() to Twig
2014-02-07 04:26:52 +00:00
* Properties used : #attributes, #children, #collapsed, #collapsible,
2014-02-21 17:36:27 +00:00
* #description, #id, #title, #value, #optional.
2012-11-27 07:06:47 +00:00
*
* @ ingroup themeable
*/
Issue #2152207 by steveoliver, joelpittet, gnuget, idflood, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_details() to Twig
2014-02-07 04:26:52 +00:00
function template_preprocess_details ( & $variables ) {
2012-11-27 07:06:47 +00:00
$element = $variables [ 'element' ];
Issue #2152207 by steveoliver, joelpittet, gnuget, idflood, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_details() to Twig
2014-02-07 04:26:52 +00:00
$variables [ 'attributes' ] = $element [ '#attributes' ];
$variables [ 'summary_attributes' ] = new Attribute ();
2012-11-27 07:06:47 +00:00
if ( ! empty ( $element [ '#title' ])) {
Issue #2152207 by steveoliver, joelpittet, gnuget, idflood, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_details() to Twig
2014-02-07 04:26:52 +00:00
$variables [ 'summary_attributes' ][ 'role' ] = 'button' ;
2013-01-03 01:58:48 +00:00
if ( ! empty ( $element [ '#attributes' ][ 'id' ])) {
Issue #2152207 by steveoliver, joelpittet, gnuget, idflood, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_details() to Twig
2014-02-07 04:26:52 +00:00
$variables [ 'summary_attributes' ][ 'aria-controls' ] = $element [ '#attributes' ][ 'id' ];
2013-01-03 01:58:48 +00:00
}
Issue #2152207 by steveoliver, joelpittet, gnuget, idflood, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_details() to Twig
2014-02-07 04:26:52 +00:00
$variables [ 'summary_attributes' ][ 'aria-expanded' ] = empty ( $element [ '#attributes' ][ 'open' ]) ? FALSE : TRUE ;
$variables [ 'summary_attributes' ][ 'aria-pressed' ] = $variables [ 'summary_attributes' ][ 'aria-expanded' ];
2012-11-27 07:06:47 +00:00
}
Issue #2152207 by steveoliver, joelpittet, gnuget, idflood, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_details() to Twig
2014-02-07 04:26:52 +00:00
$variables [ 'title' ] = ( ! empty ( $element [ '#title' ])) ? $element [ '#title' ] : '' ;
$variables [ 'description' ] = ( ! empty ( $element [ '#description' ])) ? $element [ '#description' ] : '' ;
$variables [ 'children' ] = ( isset ( $element [ '#children' ])) ? $element [ '#children' ] : '' ;
$variables [ 'value' ] = ( isset ( $element [ '#value' ])) ? $element [ '#value' ] : '' ;
2012-11-27 07:06:47 +00:00
}
2005-10-07 06:11:12 +00:00
/**
2013-01-10 05:45:55 +00:00
* Prepares a #type 'radio' render element for theme_input().
*
* @ param array $element
* An associative array containing the properties of the element .
* Properties used : #required, #return_value, #value, #attributes, #title,
* #description.
2005-10-07 06:11:12 +00:00
*
2010-12-30 22:52:24 +00:00
* Note : The input " name " attribute needs to be sanitized before output , which
2012-09-04 13:32:47 +00:00
* is currently done by initializing Drupal\Core\Template\Attribute with
* all the attributes .
2010-12-30 22:52:24 +00:00
*
2013-01-10 05:45:55 +00:00
* @ return array
* The $element with prepared variables ready for theme_input () .
2005-10-07 06:11:12 +00:00
*/
2013-01-10 05:45:55 +00:00
function form_pre_render_radio ( $element ) {
2010-07-31 04:01:51 +00:00
$element [ '#attributes' ][ 'type' ] = 'radio' ;
2010-09-16 20:14:49 +00:00
element_set_attributes ( $element , array ( 'id' , 'name' , '#return_value' => 'value' ));
2010-12-30 22:52:24 +00:00
if ( isset ( $element [ '#return_value' ]) && $element [ '#value' ] !== FALSE && $element [ '#value' ] == $element [ '#return_value' ]) {
2010-07-31 04:01:51 +00:00
$element [ '#attributes' ][ 'checked' ] = 'checked' ;
}
2012-10-23 22:43:41 +00:00
_form_set_attributes ( $element , array ( 'form-radio' ));
2009-11-16 05:11:01 +00:00
2013-01-10 05:45:55 +00:00
return $element ;
2005-10-07 06:11:12 +00:00
}
/**
2010-04-13 15:23:03 +00:00
* Returns HTML for a set of radio button form elements .
2005-10-07 06:11:12 +00:00
*
2009-10-09 01:00:08 +00:00
* @ param $variables
* An associative array containing :
* - element : An associative array containing the properties of the element .
* Properties used : #title, #value, #options, #description, #required,
* #attributes, #children.
*
2007-12-06 09:58:34 +00:00
* @ ingroup themeable
2005-10-07 06:11:12 +00:00
*/
2009-10-09 01:00:08 +00:00
function theme_radios ( $variables ) {
$element = $variables [ 'element' ];
2010-03-26 12:16:18 +00:00
$attributes = array ();
2010-09-16 20:14:49 +00:00
if ( isset ( $element [ '#id' ])) {
2010-03-26 12:16:18 +00:00
$attributes [ 'id' ] = $element [ '#id' ];
}
$attributes [ 'class' ] = 'form-radios' ;
2009-08-22 14:34:23 +00:00
if ( ! empty ( $element [ '#attributes' ][ 'class' ])) {
2010-03-26 12:16:18 +00:00
$attributes [ 'class' ] .= ' ' . implode ( ' ' , $element [ '#attributes' ][ 'class' ]);
2006-12-12 10:01:38 +00:00
}
2012-04-12 07:29:31 +00:00
if ( isset ( $element [ '#attributes' ][ 'title' ])) {
$attributes [ 'title' ] = $element [ '#attributes' ][ 'title' ];
}
2012-09-04 13:32:47 +00:00
return '<div' . new Attribute ( $attributes ) . '>' . ( ! empty ( $element [ '#children' ]) ? $element [ '#children' ] : '' ) . '</div>' ;
2006-01-02 08:35:59 +00:00
}
2007-12-31 08:54:37 +00:00
/**
2006-04-20 16:35:29 +00:00
* Expand a password_confirm field into two text boxes .
*/
2008-07-18 07:06:24 +00:00
function form_process_password_confirm ( $element ) {
2006-08-03 14:08:30 +00:00
$element [ 'pass1' ] = array (
'#type' => 'password' ,
'#title' => t ( 'Password' ),
2007-05-14 13:43:38 +00:00
'#value' => empty ( $element [ '#value' ]) ? NULL : $element [ '#value' ][ 'pass1' ],
2007-05-31 12:36:18 +00:00
'#required' => $element [ '#required' ],
2009-08-22 14:34:23 +00:00
'#attributes' => array ( 'class' => array ( 'password-field' )),
2006-08-03 14:08:30 +00:00
);
$element [ 'pass2' ] = array (
'#type' => 'password' ,
'#title' => t ( 'Confirm password' ),
2007-05-14 13:43:38 +00:00
'#value' => empty ( $element [ '#value' ]) ? NULL : $element [ '#value' ][ 'pass2' ],
2007-05-31 12:36:18 +00:00
'#required' => $element [ '#required' ],
2009-08-22 14:34:23 +00:00
'#attributes' => array ( 'class' => array ( 'password-confirm' )),
2006-08-03 14:08:30 +00:00
);
2007-05-14 13:43:38 +00:00
$element [ '#element_validate' ] = array ( 'password_confirm_validate' );
2006-04-20 16:35:29 +00:00
$element [ '#tree' ] = TRUE ;
2007-01-11 03:24:42 +00:00
if ( isset ( $element [ '#size' ])) {
$element [ 'pass1' ][ '#size' ] = $element [ 'pass2' ][ '#size' ] = $element [ '#size' ];
}
2006-04-20 16:35:29 +00:00
return $element ;
}
2006-01-02 08:35:59 +00:00
/**
2012-02-19 03:41:24 +00:00
* Validates a password_confirm element .
2006-01-02 08:35:59 +00:00
*/
2009-07-06 13:31:47 +00:00
function password_confirm_validate ( $element , & $element_state ) {
$pass1 = trim ( $element [ 'pass1' ][ '#value' ]);
2010-05-07 14:48:10 +00:00
$pass2 = trim ( $element [ 'pass2' ][ '#value' ]);
if ( ! empty ( $pass1 ) || ! empty ( $pass2 )) {
2009-05-22 07:39:09 +00:00
if ( strcmp ( $pass1 , $pass2 )) {
2013-11-23 20:57:04 +00:00
form_error ( $element , $element_state , t ( 'The specified passwords do not match.' ));
2006-01-02 08:35:59 +00:00
}
2006-01-24 10:15:03 +00:00
}
2009-07-06 13:31:47 +00:00
elseif ( $element [ '#required' ] && ! empty ( $element_state [ 'input' ])) {
2013-11-23 20:57:04 +00:00
form_error ( $element , $element_state , t ( 'Password field is required.' ));
2006-01-02 08:35:59 +00:00
}
2006-04-20 16:35:29 +00:00
2006-04-25 20:44:00 +00:00
// Password field must be converted from a two-element array into a single
// string regardless of validation results.
2009-07-06 13:31:47 +00:00
form_set_value ( $element [ 'pass1' ], NULL , $element_state );
form_set_value ( $element [ 'pass2' ], NULL , $element_state );
form_set_value ( $element , $pass1 , $element_state );
2006-04-25 20:44:00 +00:00
2009-07-06 13:31:47 +00:00
return $element ;
2007-05-28 06:08:47 +00:00
2006-01-02 08:35:59 +00:00
}
2005-10-07 06:11:12 +00:00
/**
2013-02-16 23:29:53 +00:00
* Returns HTML for an #date form element.
2005-10-07 06:11:12 +00:00
*
2013-02-16 23:29:53 +00:00
* Supports HTML5 types of 'date' , 'datetime' , 'datetime-local' , and 'time' .
* Falls back to a plain textfield . Used as a sub - element by the datetime
* element type .
*
* @ param array $variables
2009-10-09 01:00:08 +00:00
* An associative array containing :
* - element : An associative array containing the properties of the element .
* Properties used : #title, #value, #options, #description, #required,
2013-02-16 23:29:53 +00:00
* #attributes, #id, #name, #type, #min, #max, #step, #value, #size.
2009-10-09 01:00:08 +00:00
*
2007-12-06 09:58:34 +00:00
* @ ingroup themeable
2005-10-07 06:11:12 +00:00
*/
2009-10-09 01:00:08 +00:00
function theme_date ( $variables ) {
$element = $variables [ 'element' ];
2013-02-16 23:29:53 +00:00
if ( empty ( $element [ 'attribute' ][ 'type' ])) {
$element [ 'attribute' ][ 'type' ] = 'date' ;
2011-09-05 19:08:11 +00:00
}
2013-02-16 23:29:53 +00:00
element_set_attributes ( $element , array ( 'id' , 'name' , 'type' , 'min' , 'max' , 'step' , 'value' , 'size' ));
_form_set_attributes ( $element , array ( 'form-' . $element [ 'attribute' ][ 'type' ]));
2011-09-05 19:08:11 +00:00
2013-02-16 23:29:53 +00:00
return '<input' . new Attribute ( $element [ '#attributes' ]) . ' />' ;
2005-11-21 09:42:14 +00:00
}
2005-10-07 06:11:12 +00:00
2006-01-26 13:39:48 +00:00
/**
2012-02-19 03:41:24 +00:00
* Sets the value for a weight element , with zero as a default .
2006-01-26 13:39:48 +00:00
*/
function weight_value ( & $form ) {
if ( isset ( $form [ '#default_value' ])) {
$form [ '#value' ] = $form [ '#default_value' ];
}
else {
$form [ '#value' ] = 0 ;
}
}
2005-10-07 06:11:12 +00:00
/**
2012-02-19 03:41:24 +00:00
* Expands a radios element into individual radio elements .
2005-10-07 06:11:12 +00:00
*/
2008-07-18 07:06:24 +00:00
function form_process_radios ( $element ) {
2005-10-11 19:44:35 +00:00
if ( count ( $element [ '#options' ]) > 0 ) {
2010-11-07 21:46:09 +00:00
$weight = 0 ;
2005-10-11 19:44:35 +00:00
foreach ( $element [ '#options' ] as $key => $choice ) {
2010-11-07 21:46:09 +00:00
// Maintain order of options as defined in #options, in case the element
// defines custom option sub-elements, but does not define all option
// sub-elements.
$weight += 0.001 ;
$element += array ( $key => array ());
// Generate the parents as the autogenerator does, so we will have a
// unique id for each radio button.
$parents_for_id = array_merge ( $element [ '#parents' ], array ( $key ));
$element [ $key ] += array (
'#type' => 'radio' ,
'#title' => $choice ,
2012-09-04 13:32:47 +00:00
// The key is sanitized in Drupal\Core\Template\Attribute during output
// from the theme function.
2010-12-30 22:52:24 +00:00
'#return_value' => $key ,
2012-03-10 21:01:23 +00:00
// Use default or FALSE. A value of FALSE means that the radio button is
// not 'checked'.
'#default_value' => isset ( $element [ '#default_value' ]) ? $element [ '#default_value' ] : FALSE ,
2010-11-07 21:46:09 +00:00
'#attributes' => $element [ '#attributes' ],
'#parents' => $element [ '#parents' ],
'#id' => drupal_html_id ( 'edit-' . implode ( '-' , $parents_for_id )),
'#ajax' => isset ( $element [ '#ajax' ]) ? $element [ '#ajax' ] : NULL ,
'#weight' => $weight ,
);
2005-10-07 06:11:12 +00:00
}
}
return $element ;
}
/**
2013-01-10 05:45:55 +00:00
* Prepares a #type 'checkbox' render element for theme_input().
2005-10-07 06:11:12 +00:00
*
2013-01-10 05:45:55 +00:00
* @ param array $element
* An associative array containing the properties of the element .
* Properties used : #title, #value, #return_value, #description, #required,
* #attributes, #checked.
2009-10-09 01:00:08 +00:00
*
2013-01-10 05:45:55 +00:00
* @ return array
* The $element with prepared variables ready for theme_input () .
2005-10-07 06:11:12 +00:00
*/
2013-01-10 05:45:55 +00:00
function form_pre_render_checkbox ( $element ) {
2010-07-31 04:01:51 +00:00
$element [ '#attributes' ][ 'type' ] = 'checkbox' ;
2010-09-16 20:14:49 +00:00
element_set_attributes ( $element , array ( 'id' , 'name' , '#return_value' => 'value' ));
2010-04-11 19:00:27 +00:00
// Unchecked checkbox has #value of integer 0.
2010-10-28 02:20:14 +00:00
if ( ! empty ( $element [ '#checked' ])) {
2010-07-31 04:01:51 +00:00
$element [ '#attributes' ][ 'checked' ] = 'checked' ;
2009-11-15 21:36:06 +00:00
}
2012-10-23 22:43:41 +00:00
_form_set_attributes ( $element , array ( 'form-checkbox' ));
2005-10-11 19:44:35 +00:00
2013-01-10 05:45:55 +00:00
return $element ;
2005-10-07 06:11:12 +00:00
}
/**
2010-04-13 15:23:03 +00:00
* Returns HTML for a set of checkbox form elements .
2005-10-07 06:11:12 +00:00
*
2009-10-09 01:00:08 +00:00
* @ param $variables
* An associative array containing :
* - element : An associative array containing the properties of the element .
* Properties used : #children, #attributes.
*
2007-12-06 09:58:34 +00:00
* @ ingroup themeable
2005-10-07 06:11:12 +00:00
*/
2009-10-09 01:00:08 +00:00
function theme_checkboxes ( $variables ) {
$element = $variables [ 'element' ];
2010-03-26 12:16:18 +00:00
$attributes = array ();
2010-09-16 20:14:49 +00:00
if ( isset ( $element [ '#id' ])) {
2010-03-26 12:16:18 +00:00
$attributes [ 'id' ] = $element [ '#id' ];
}
2010-09-16 20:14:49 +00:00
$attributes [ 'class' ][] = 'form-checkboxes' ;
2009-08-22 14:34:23 +00:00
if ( ! empty ( $element [ '#attributes' ][ 'class' ])) {
2010-09-16 20:14:49 +00:00
$attributes [ 'class' ] = array_merge ( $attributes [ 'class' ], $element [ '#attributes' ][ 'class' ]);
2006-12-12 10:01:38 +00:00
}
2012-04-12 07:29:31 +00:00
if ( isset ( $element [ '#attributes' ][ 'title' ])) {
$attributes [ 'title' ] = $element [ '#attributes' ][ 'title' ];
}
2012-09-04 13:32:47 +00:00
return '<div' . new Attribute ( $attributes ) . '>' . ( ! empty ( $element [ '#children' ]) ? $element [ '#children' ] : '' ) . '</div>' ;
2009-02-03 18:55:32 +00:00
}
/**
2012-02-19 03:41:24 +00:00
* Adds form element theming to an element if its title or description is set .
2009-02-03 18:55:32 +00:00
*
* This is used as a pre render function for checkboxes and radios .
*/
function form_pre_render_conditional_form_element ( $element ) {
2009-12-02 15:09:16 +00:00
// Set the element's title attribute to show #title as a tooltip, if needed.
if ( isset ( $element [ '#title' ]) && $element [ '#title_display' ] == 'attribute' ) {
$element [ '#attributes' ][ 'title' ] = $element [ '#title' ];
if ( ! empty ( $element [ '#required' ])) {
// Append an indication that this field is required.
2013-06-17 13:35:07 +00:00
$element [ '#attributes' ][ 'title' ] .= ' (' . t ( 'Required' ) . ')' ;
2009-12-02 15:09:16 +00:00
}
}
2009-11-16 05:11:01 +00:00
if ( isset ( $element [ '#title' ]) || isset ( $element [ '#description' ])) {
2014-02-20 11:40:28 +00:00
// @see #type 'fieldgroup'
$element [ '#theme_wrappers' ][] = 'fieldset' ;
$element [ '#attributes' ][ 'class' ][] = 'fieldgroup' ;
$element [ '#attributes' ][ 'class' ][] = 'form-composite' ;
2005-10-07 06:11:12 +00:00
}
2009-02-03 18:55:32 +00:00
return $element ;
2005-10-07 06:11:12 +00:00
}
2012-03-27 06:23:35 +00:00
/**
* Processes a form button element .
*/
function form_process_button ( $element , $form_state ) {
// If this is a button intentionally allowing incomplete form submission
// (e.g., a "Previous" or "Add another item" button), then also skip
// client-side validation.
if ( isset ( $element [ '#limit_validation_errors' ]) && $element [ '#limit_validation_errors' ] !== FALSE ) {
$element [ '#attributes' ][ 'formnovalidate' ] = 'formnovalidate' ;
}
return $element ;
}
2010-10-28 02:20:14 +00:00
/**
* Sets the #checked property of a checkbox element.
*/
function form_process_checkbox ( $element , $form_state ) {
$value = $element [ '#value' ];
$return_value = $element [ '#return_value' ];
// On form submission, the #value of an available and enabled checked
// checkbox is #return_value, and the #value of an available and enabled
// unchecked checkbox is integer 0. On not submitted forms, and for
// checkboxes with #access=FALSE or #disabled=TRUE, the #value is
// #default_value (integer 0 if #default_value is NULL). Most of the time,
// a string comparison of #value and #return_value is sufficient for
// determining the "checked" state, but a value of TRUE always means checked
// (even if #return_value is 'foo'), and a value of FALSE or integer 0 always
// means unchecked (even if #return_value is '' or '0').
if ( $value === TRUE || $value === FALSE || $value === 0 ) {
$element [ '#checked' ] = ( bool ) $value ;
}
else {
// Compare as strings, so that 15 is not considered equal to '15foo', but 1
// is considered equal to '1'. This cast does not imply that either #value
// or #return_value is expected to be a string.
$element [ '#checked' ] = (( string ) $value === ( string ) $return_value );
}
return $element ;
}
2012-02-19 03:41:24 +00:00
/**
* Processes a checkboxes form element .
*/
2008-07-18 07:06:24 +00:00
function form_process_checkboxes ( $element ) {
2005-10-11 19:44:35 +00:00
$value = is_array ( $element [ '#value' ]) ? $element [ '#value' ] : array ();
2005-10-26 01:24:09 +00:00
$element [ '#tree' ] = TRUE ;
2005-10-11 19:44:35 +00:00
if ( count ( $element [ '#options' ]) > 0 ) {
if ( ! isset ( $element [ '#default_value' ]) || $element [ '#default_value' ] == 0 ) {
$element [ '#default_value' ] = array ();
2005-10-07 06:11:12 +00:00
}
2010-11-07 21:46:09 +00:00
$weight = 0 ;
2005-10-11 19:44:35 +00:00
foreach ( $element [ '#options' ] as $key => $choice ) {
2010-11-07 21:46:09 +00:00
// Integer 0 is not a valid #return_value, so use '0' instead.
// @see form_type_checkbox_value().
// @todo For Drupal 8, cast all integer keys to strings for consistency
// with form_process_radios().
if ( $key === 0 ) {
$key = '0' ;
2005-10-07 06:11:12 +00:00
}
2010-11-07 21:46:09 +00:00
// Maintain order of options as defined in #options, in case the element
// defines custom option sub-elements, but does not define all option
// sub-elements.
$weight += 0.001 ;
$element += array ( $key => array ());
$element [ $key ] += array (
'#type' => 'checkbox' ,
'#title' => $choice ,
'#return_value' => $key ,
'#default_value' => isset ( $value [ $key ]) ? $key : NULL ,
'#attributes' => $element [ '#attributes' ],
'#ajax' => isset ( $element [ '#ajax' ]) ? $element [ '#ajax' ] : NULL ,
'#weight' => $weight ,
);
2005-10-07 06:11:12 +00:00
}
}
return $element ;
}
2010-04-24 14:49:14 +00:00
/**
* Processes a form actions container element .
*
* @ param $element
* An associative array containing the properties and children of the
* form actions container .
* @ param $form_state
* The $form_state array for the form this element belongs to .
*
* @ return
* The processed element .
*/
function form_process_actions ( $element , & $form_state ) {
$element [ '#attributes' ][ 'class' ][] = 'form-actions' ;
return $element ;
}
2013-01-30 03:30:40 +00:00
/**
* #pre_render callback for #type 'actions'.
*
* This callback iterates over all child elements of the #type 'actions'
* container to look for elements with a #dropbutton property, so as to group
* those elements into dropbuttons . As such , it works similar to #group, but is
* specialized for dropbuttons .
*
* The value of #dropbutton denotes the dropbutton to group the child element
* into . For example , two different values of 'foo' and 'bar' on child elements
* would generate two separate dropbuttons , which each contain the corresponding
* buttons .
*
* @ param array $element
* The #type 'actions' element to process.
*
* @ return array
* The processed #type 'actions' element, including individual buttons grouped
* into new #type 'dropbutton' elements.
*/
function form_pre_render_actions_dropbutton ( array $element ) {
$dropbuttons = array ();
foreach ( element_children ( $element , TRUE ) as $key ) {
if ( isset ( $element [ $key ][ '#dropbutton' ])) {
$dropbutton = $element [ $key ][ '#dropbutton' ];
// If there is no dropbutton for this button group yet, create one.
if ( ! isset ( $dropbuttons [ $dropbutton ])) {
$dropbuttons [ $dropbutton ] = array (
'#type' => 'dropbutton' ,
);
}
// Add this button to the corresponding dropbutton.
// @todo Change #type 'dropbutton' to be based on theme_item_list()
2014-02-07 04:28:14 +00:00
// instead of links.html.twig to avoid this preemptive rendering.
2013-01-30 03:30:40 +00:00
$button = drupal_render ( $element [ $key ]);
$dropbuttons [ $dropbutton ][ '#links' ][ $key ] = array (
'title' => $button ,
'html' => TRUE ,
);
}
}
// @todo For now, all dropbuttons appear first. Consider to invent a more
// fancy sorting/injection algorithm here.
return $dropbuttons + $element ;
}
2012-05-08 03:00:06 +00:00
/**
* #process callback for #pattern form element property.
*
* @ param $element
* An associative array containing the properties and children of the
* generic input element .
* @ param $form_state
* The $form_state array for the form this element belongs to .
*
* @ return
* The processed element .
*
* @ see form_validate_pattern ()
*/
function form_process_pattern ( $element , & $form_state ) {
if ( isset ( $element [ '#pattern' ]) && ! isset ( $element [ '#attributes' ][ 'pattern' ])) {
$element [ '#attributes' ][ 'pattern' ] = $element [ '#pattern' ];
$element [ '#element_validate' ][] = 'form_validate_pattern' ;
}
return $element ;
}
/**
* #element_validate callback for #pattern form element property.
*
* @ param $element
* An associative array containing the properties and children of the
* generic form element .
* @ param $form_state
* The $form_state array for the form this element belongs to .
*
* @ see form_process_pattern ()
*/
function form_validate_pattern ( $element , & $form_state ) {
if ( $element [ '#value' ] !== '' ) {
// The pattern must match the entire string and should have the same
// behavior as the RegExp object in ECMA 262.
// - Use bracket-style delimiters to avoid introducing a special delimiter
// character like '/' that would have to be escaped.
// - Put in brackets so that the pattern can't interfere with what's
// prepended and appended.
$pattern = '{^(?:' . $element [ '#pattern' ] . ')$}' ;
if ( ! preg_match ( $pattern , $element [ '#value' ])) {
2013-11-23 20:57:04 +00:00
form_error ( $element , $form_state , t ( '%name field is not in the right format.' , array ( '%name' => $element [ '#title' ])));
2012-05-08 03:00:06 +00:00
}
}
}
2009-10-16 19:20:34 +00:00
/**
* Processes a container element .
*
* @ param $element
* An associative array containing the properties and children of the
* container .
* @ param $form_state
* The $form_state array for the form this element belongs to .
2012-02-19 03:41:24 +00:00
*
2009-10-16 19:20:34 +00:00
* @ return
* The processed element .
*/
function form_process_container ( $element , & $form_state ) {
2010-01-03 21:01:04 +00:00
// Generate the ID of the element if it's not explicitly given.
if ( ! isset ( $element [ '#id' ])) {
$element [ '#id' ] = drupal_html_id ( implode ( '-' , $element [ '#parents' ]) . '-wrapper' );
}
2009-10-16 19:20:34 +00:00
return $element ;
}
2009-01-28 07:43:26 +00:00
/**
2010-04-13 15:23:03 +00:00
* Returns HTML for a table with radio buttons or checkboxes .
2009-01-28 07:43:26 +00:00
*
2010-04-13 15:23:03 +00:00
* @ param $variables
* An associative array containing :
* - element : An associative array containing the properties and children of
* the tableselect element . Properties used : #header, #options, #empty,
* and #js_select. The #options property is an array of selection options;
* each array element of #options is an array of properties. These
* properties can include #attributes, which is added to the
2012-08-29 18:02:40 +00:00
* table row ' s HTML attributes ; see theme_table () . An example of per - row
* options :
* @ code
* $options = array (
* array (
* 'title' => 'How to Learn Drupal' ,
* 'content_type' => 'Article' ,
* 'status' => 'published' ,
* '#attributes' => array ( 'class' => array ( 'article-row' )),
* ),
* array (
* 'title' => 'Privacy Policy' ,
* 'content_type' => 'Page' ,
* 'status' => 'published' ,
* '#attributes' => array ( 'class' => array ( 'page-row' )),
* ),
* );
* $header = array (
* 'title' => t ( 'Title' ),
* 'content_type' => t ( 'Content type' ),
* 'status' => t ( 'Status' ),
* );
* $form [ 'table' ] = array (
* '#type' => 'tableselect' ,
* '#header' => $header ,
* '#options' => $options ,
* '#empty' => t ( 'No content available.' ),
* );
* @ endcode
2010-01-30 07:54:01 +00:00
*
2009-01-28 07:43:26 +00:00
* @ ingroup themeable
*/
2009-10-09 01:00:08 +00:00
function theme_tableselect ( $variables ) {
$element = $variables [ 'element' ];
2014-02-05 10:56:05 +00:00
$table = array (
'#theme' => 'table' ,
);
2009-01-28 07:43:26 +00:00
$rows = array ();
2009-12-02 14:56:32 +00:00
$header = $element [ '#header' ];
2009-01-28 07:43:26 +00:00
if ( ! empty ( $element [ '#options' ])) {
// Generate a table row for each selectable item in #options.
2010-10-07 17:31:39 +00:00
foreach ( element_children ( $element ) as $key ) {
2009-01-28 07:43:26 +00:00
$row = array ();
2009-07-07 22:32:17 +00:00
$row [ 'data' ] = array ();
2010-10-07 17:31:39 +00:00
if ( isset ( $element [ '#options' ][ $key ][ '#attributes' ])) {
$row += $element [ '#options' ][ $key ][ '#attributes' ];
2009-07-07 22:32:17 +00:00
}
2009-01-28 07:43:26 +00:00
// Render the checkbox / radio element.
2009-07-07 22:32:17 +00:00
$row [ 'data' ][] = drupal_render ( $element [ $key ]);
2009-01-28 07:43:26 +00:00
// As theme_table only maps header and row columns by order, create the
// correct order by iterating over the header fields.
foreach ( $element [ '#header' ] as $fieldname => $title ) {
2012-04-06 05:38:32 +00:00
// A row cell can span over multiple headers, which means less row cells
// than headers could be present.
if ( isset ( $element [ '#options' ][ $key ][ $fieldname ])) {
// A header can span over multiple cells and in this case the cells
// are passed in an array. The order of this array determines the
// order in which they are added.
if ( ! isset ( $element [ '#options' ][ $key ][ $fieldname ][ 'data' ]) && is_array ( $element [ '#options' ][ $key ][ $fieldname ])) {
foreach ( $element [ '#options' ][ $key ][ $fieldname ] as $cell ) {
$row [ 'data' ][] = $cell ;
}
}
else {
$row [ 'data' ][] = $element [ '#options' ][ $key ][ $fieldname ];
}
}
2009-01-28 07:43:26 +00:00
}
$rows [] = $row ;
}
// Add an empty header or a "Select all" checkbox to provide room for the
// checkboxes/radios in the first table column.
2010-05-19 19:22:24 +00:00
if ( $element [ '#js_select' ]) {
2010-10-03 01:04:51 +00:00
// Add a "Select all" checkbox.
2014-02-05 10:56:05 +00:00
$table [ '#attached' ][ 'library' ][] = array ( 'system' , 'drupal.tableselect' );
2010-05-19 19:22:24 +00:00
array_unshift ( $header , array ( 'class' => array ( 'select-all' )));
}
2010-08-30 17:07:49 +00:00
else {
2010-10-03 01:04:51 +00:00
// Add an empty header when radio buttons are displayed or a "Select all"
// checkbox is not desired.
2010-08-30 17:07:49 +00:00
array_unshift ( $header , '' );
}
2009-01-28 07:43:26 +00:00
}
2014-02-05 10:56:05 +00:00
$table += array (
'#header' => $header ,
'#rows' => $rows ,
'#empty' => $element [ '#empty' ],
'#attributes' => $element [ '#attributes' ],
);
return drupal_render ( $table );
2009-01-28 07:43:26 +00:00
}
/**
2012-02-19 03:41:24 +00:00
* Creates checkbox or radio elements to populate a tableselect table .
2009-01-28 07:43:26 +00:00
*
* @ param $element
* An associative array containing the properties and children of the
* tableselect element .
2012-02-19 03:41:24 +00:00
*
2009-01-28 07:43:26 +00:00
* @ return
* The processed element .
*/
function form_process_tableselect ( $element ) {
if ( $element [ '#multiple' ]) {
$value = is_array ( $element [ '#value' ]) ? $element [ '#value' ] : array ();
}
else {
2012-04-20 19:51:35 +00:00
// Advanced selection behavior makes no sense for radios.
2009-01-28 07:43:26 +00:00
$element [ '#js_select' ] = FALSE ;
}
$element [ '#tree' ] = TRUE ;
if ( count ( $element [ '#options' ]) > 0 ) {
if ( ! isset ( $element [ '#default_value' ]) || $element [ '#default_value' ] === 0 ) {
$element [ '#default_value' ] = array ();
}
// Create a checkbox or radio for each item in #options in such a way that
// the value of the tableselect element behaves as if it had been of type
// checkboxes or radios.
foreach ( $element [ '#options' ] as $key => $choice ) {
// Do not overwrite manually created children.
if ( ! isset ( $element [ $key ])) {
if ( $element [ '#multiple' ]) {
2010-10-20 01:31:07 +00:00
$title = '' ;
if ( ! empty ( $element [ '#options' ][ $key ][ 'title' ][ 'data' ][ '#title' ])) {
$title = t ( 'Update @title' , array (
'@title' => $element [ '#options' ][ $key ][ 'title' ][ 'data' ][ '#title' ],
));
}
2009-01-28 07:43:26 +00:00
$element [ $key ] = array (
'#type' => 'checkbox' ,
2010-10-20 01:31:07 +00:00
'#title' => $title ,
'#title_display' => 'invisible' ,
2009-01-28 07:43:26 +00:00
'#return_value' => $key ,
2009-11-15 21:36:06 +00:00
'#default_value' => isset ( $value [ $key ]) ? $key : NULL ,
2009-01-28 07:43:26 +00:00
'#attributes' => $element [ '#attributes' ],
);
}
else {
// Generate the parents as the autogenerator does, so we will have a
// unique id for each radio button.
$parents_for_id = array_merge ( $element [ '#parents' ], array ( $key ));
$element [ $key ] = array (
'#type' => 'radio' ,
'#title' => '' ,
'#return_value' => $key ,
'#default_value' => ( $element [ '#default_value' ] == $key ) ? $key : NULL ,
'#attributes' => $element [ '#attributes' ],
'#parents' => $element [ '#parents' ],
2009-10-05 01:18:26 +00:00
'#id' => drupal_html_id ( 'edit-' . implode ( '-' , $parents_for_id )),
2010-07-10 00:03:37 +00:00
'#ajax' => isset ( $element [ '#ajax' ]) ? $element [ '#ajax' ] : NULL ,
2009-01-28 07:43:26 +00:00
);
}
2010-10-07 17:31:39 +00:00
if ( isset ( $element [ '#options' ][ $key ][ '#weight' ])) {
$element [ $key ][ '#weight' ] = $element [ '#options' ][ $key ][ '#weight' ];
}
2009-01-28 07:43:26 +00:00
}
}
}
else {
$element [ '#value' ] = array ();
}
return $element ;
}
2012-12-26 18:15:32 +00:00
/**
* #process callback for #type 'table' to add tableselect support.
*
* @ param array $element
* An associative array containing the properties and children of the
* table element .
* @ param array $form_state
* The current state of the form .
*
* @ return array
* The processed element .
*
* @ see form_process_tableselect ()
* @ see theme_tableselect ()
*/
function form_process_table ( $element , & $form_state ) {
if ( $element [ '#tableselect' ]) {
if ( $element [ '#multiple' ]) {
$value = is_array ( $element [ '#value' ]) ? $element [ '#value' ] : array ();
}
2014-01-24 06:08:18 +00:00
// Advanced selection behavior makes no sense for radios.
2012-12-26 18:15:32 +00:00
else {
$element [ '#js_select' ] = FALSE ;
}
// Add a "Select all" checkbox column to the header.
// @todo D8: Rename into #select_all?
if ( $element [ '#js_select' ]) {
$element [ '#attached' ][ 'library' ][] = array ( 'system' , 'drupal.tableselect' );
array_unshift ( $element [ '#header' ], array ( 'class' => array ( 'select-all' )));
}
// Add an empty header column for radio buttons or when a "Select all"
// checkbox is not desired.
else {
array_unshift ( $element [ '#header' ], '' );
}
if ( ! isset ( $element [ '#default_value' ]) || $element [ '#default_value' ] === 0 ) {
$element [ '#default_value' ] = array ();
}
// Create a checkbox or radio for each row in a way that the value of the
// tableselect element behaves as if it had been of #type checkboxes or
// radios.
foreach ( element_children ( $element ) as $key ) {
// Do not overwrite manually created children.
if ( ! isset ( $element [ $key ][ 'select' ])) {
// Determine option label; either an assumed 'title' column, or the
// first available column containing a #title or #markup.
// @todo Consider to add an optional $element[$key]['#title_key']
// defaulting to 'title'?
$title = '' ;
if ( ! empty ( $element [ $key ][ 'title' ][ '#title' ])) {
$title = $element [ $key ][ 'title' ][ '#title' ];
}
else {
foreach ( element_children ( $element [ $key ]) as $column ) {
if ( isset ( $element [ $key ][ $column ][ '#title' ])) {
$title = $element [ $key ][ $column ][ '#title' ];
break ;
}
if ( isset ( $element [ $key ][ $column ][ '#markup' ])) {
$title = $element [ $key ][ $column ][ '#markup' ];
break ;
}
}
}
if ( $title !== '' ) {
$title = t ( 'Update !title' , array ( '!title' => $title ));
}
// Prepend the select column to existing columns.
$element [ $key ] = array ( 'select' => array ()) + $element [ $key ];
$element [ $key ][ 'select' ] += array (
'#type' => $element [ '#multiple' ] ? 'checkbox' : 'radio' ,
'#title' => $title ,
'#title_display' => 'invisible' ,
// @todo If rows happen to use numeric indexes instead of string keys,
// this results in a first row with $key === 0, which is always FALSE.
'#return_value' => $key ,
'#attributes' => $element [ '#attributes' ],
);
$element_parents = array_merge ( $element [ '#parents' ], array ( $key ));
if ( $element [ '#multiple' ]) {
$element [ $key ][ 'select' ][ '#default_value' ] = isset ( $value [ $key ]) ? $key : NULL ;
$element [ $key ][ 'select' ][ '#parents' ] = $element_parents ;
}
else {
$element [ $key ][ 'select' ][ '#default_value' ] = ( $element [ '#default_value' ] == $key ? $key : NULL );
$element [ $key ][ 'select' ][ '#parents' ] = $element [ '#parents' ];
$element [ $key ][ 'select' ][ '#id' ] = drupal_html_id ( 'edit-' . implode ( '-' , $element_parents ));
}
}
}
}
return $element ;
}
/**
* #element_validate callback for #type 'table'.
*
* @ param array $element
* An associative array containing the properties and children of the
* table element .
* @ param array $form_state
* The current state of the form .
*/
function form_validate_table ( $element , & $form_state ) {
// Skip this validation if the button to submit the form does not require
// selected table row data.
if ( empty ( $form_state [ 'triggering_element' ][ '#tableselect' ])) {
return ;
}
if ( $element [ '#multiple' ]) {
if ( ! is_array ( $element [ '#value' ]) || ! count ( array_filter ( $element [ '#value' ]))) {
2013-11-23 20:57:04 +00:00
form_error ( $element , $form_state , t ( 'No items selected.' ));
2012-12-26 18:15:32 +00:00
}
}
elseif ( ! isset ( $element [ '#value' ]) || $element [ '#value' ] === '' ) {
2013-11-23 20:57:04 +00:00
form_error ( $element , $form_state , t ( 'No item selected.' ));
2012-12-26 18:15:32 +00:00
}
}
2010-10-13 13:43:21 +00:00
/**
* Processes a machine - readable name form element .
*
* @ param $element
* The form element to process . Properties used :
* - #machine_name: An associative array containing:
2013-05-12 23:23:30 +00:00
* - exists : A callable to invoke for checking whether a submitted machine
* name value already exists . The submitted value is passed as an
2010-10-13 13:43:21 +00:00
* argument . In most cases , an existing API or menu argument loader
* function can be re - used . The callback is only invoked , if the submitted
* value differs from the element ' s #default_value.
* - source : ( optional ) The #array_parents of the form element containing
* the human - readable name ( i . e . , as contained in the $form structure ) to
2012-10-24 02:28:41 +00:00
* use as source for the machine name . Defaults to array ( 'label' ) .
2010-10-13 13:43:21 +00:00
* - label : ( optional ) A text to display as label for the machine name value
* after the human - readable name form element . Defaults to " Machine name " .
* - replace_pattern : ( optional ) A regular expression ( without delimiters )
* matching disallowed characters in the machine name . Defaults to
* '[^a-z0-9_]+' .
* - replace : ( optional ) A character to replace disallowed characters in the
* machine name via JavaScript . Defaults to '_' ( underscore ) . When using a
* different character , 'replace_pattern' needs to be set accordingly .
* - error : ( optional ) A custom form error message string to show , if the
* machine name contains disallowed characters .
2012-03-12 03:00:51 +00:00
* - standalone : ( optional ) Whether the live preview should stay in its own
* form element rather than in the suffix of the source element . Defaults
* to FALSE .
2010-10-13 13:43:21 +00:00
* - #maxlength: (optional) Should be set to the maximum allowed length of the
* machine name . Defaults to 64.
* - #disabled: (optional) Should be set to TRUE in case an existing machine
* name must not be changed after initial creation .
*/
function form_process_machine_name ( $element , & $form_state ) {
2013-05-02 07:51:45 +00:00
// We need to pass the langcode to the client.
2013-05-25 20:12:45 +00:00
$language = language ( Language :: TYPE_INTERFACE );
2013-05-02 07:51:45 +00:00
2010-10-13 13:43:21 +00:00
// Apply default form element properties.
$element += array (
'#title' => t ( 'Machine-readable name' ),
'#description' => t ( 'A unique machine-readable name. Can only contain lowercase letters, numbers, and underscores.' ),
'#machine_name' => array (),
2012-03-12 03:00:51 +00:00
'#field_prefix' => '' ,
'#field_suffix' => '' ,
'#suffix' => '' ,
2010-10-13 13:43:21 +00:00
);
// A form element that only wants to set one #machine_name property (usually
// 'source' only) would leave all other properties undefined, if the defaults
// were defined in hook_element_info(). Therefore, we apply the defaults here.
$element [ '#machine_name' ] += array (
2012-10-24 02:28:41 +00:00
'source' => array ( 'label' ),
2010-10-13 13:43:21 +00:00
'target' => '#' . $element [ '#id' ],
'label' => t ( 'Machine name' ),
'replace_pattern' => '[^a-z0-9_]+' ,
'replace' => '_' ,
2012-03-12 03:00:51 +00:00
'standalone' => FALSE ,
'field_prefix' => $element [ '#field_prefix' ],
'field_suffix' => $element [ '#field_suffix' ],
2010-10-13 13:43:21 +00:00
);
2011-12-08 03:29:13 +00:00
// By default, machine names are restricted to Latin alphanumeric characters.
// So, default to LTR directionality.
if ( ! isset ( $element [ '#attributes' ])) {
$element [ '#attributes' ] = array ();
}
$element [ '#attributes' ] += array ( 'dir' => 'ltr' );
2010-10-13 13:43:21 +00:00
// The source element defaults to array('name'), but may have been overidden.
if ( empty ( $element [ '#machine_name' ][ 'source' ])) {
return $element ;
}
// Retrieve the form element containing the human-readable name from the
2012-03-12 03:00:51 +00:00
// complete form in $form_state. By reference, because we may need to append
2010-10-13 13:43:21 +00:00
// a #field_suffix that will hold the live preview.
$key_exists = NULL ;
2012-12-17 21:54:13 +00:00
$source = NestedArray :: getValue ( $form_state [ 'complete_form' ], $element [ '#machine_name' ][ 'source' ], $key_exists );
2010-10-13 13:43:21 +00:00
if ( ! $key_exists ) {
return $element ;
}
$suffix_id = $source [ '#id' ] . '-machine-name-suffix' ;
2012-03-12 03:00:51 +00:00
$element [ '#machine_name' ][ 'suffix' ] = '#' . $suffix_id ;
2010-10-13 13:43:21 +00:00
2012-03-12 03:00:51 +00:00
if ( $element [ '#machine_name' ][ 'standalone' ]) {
$element [ '#suffix' ] .= ' <small id="' . $suffix_id . '"> </small>' ;
}
else {
// Append a field suffix to the source form element, which will contain
// the live preview of the machine name.
$source += array ( '#field_suffix' => '' );
$source [ '#field_suffix' ] .= ' <small id="' . $suffix_id . '"> </small>' ;
2010-10-13 13:43:21 +00:00
2012-03-12 03:00:51 +00:00
$parents = array_merge ( $element [ '#machine_name' ][ 'source' ], array ( '#field_suffix' ));
2012-12-17 21:54:13 +00:00
NestedArray :: setValue ( $form_state [ 'complete_form' ], $parents , $source [ '#field_suffix' ]);
2012-03-12 03:00:51 +00:00
}
2010-10-13 13:43:21 +00:00
$js_settings = array (
'type' => 'setting' ,
'data' => array (
'machineName' => array (
'#' . $source [ '#id' ] => $element [ '#machine_name' ],
),
2013-06-29 10:56:53 +00:00
'langcode' => $language -> id ,
2010-10-13 13:43:21 +00:00
),
);
2012-08-30 19:24:38 +00:00
$element [ '#attached' ][ 'library' ][] = array ( 'system' , 'drupal.machine-name' );
2010-10-13 13:43:21 +00:00
$element [ '#attached' ][ 'js' ][] = $js_settings ;
return $element ;
}
/**
2012-02-19 03:41:24 +00:00
* Form element validation handler for machine_name elements .
2010-10-13 13:43:21 +00:00
*
* Note that #maxlength is validated by _form_validate() already.
*/
function form_validate_machine_name ( & $element , & $form_state ) {
// Verify that the machine name not only consists of replacement tokens.
if ( preg_match ( '@^' . $element [ '#machine_name' ][ 'replace' ] . '+$@' , $element [ '#value' ])) {
2013-11-23 20:57:04 +00:00
form_error ( $element , $form_state , t ( 'The machine-readable name must contain unique characters.' ));
2010-10-13 13:43:21 +00:00
}
// Verify that the machine name contains no disallowed characters.
if ( preg_match ( '@' . $element [ '#machine_name' ][ 'replace_pattern' ] . '@' , $element [ '#value' ])) {
if ( ! isset ( $element [ '#machine_name' ][ 'error' ])) {
// Since a hyphen is the most common alternative replacement character,
// a corresponding validation error message is supported here.
if ( $element [ '#machine_name' ][ 'replace' ] == '-' ) {
2013-11-23 20:57:04 +00:00
form_error ( $element , $form_state , t ( 'The machine-readable name must contain only lowercase letters, numbers, and hyphens.' ));
2010-10-13 13:43:21 +00:00
}
// Otherwise, we assume the default (underscore).
else {
2013-11-23 20:57:04 +00:00
form_error ( $element , $form_state , t ( 'The machine-readable name must contain only lowercase letters, numbers, and underscores.' ));
2010-10-13 13:43:21 +00:00
}
}
else {
2013-11-23 20:57:04 +00:00
form_error ( $element , $form_state , $element [ '#machine_name' ][ 'error' ]);
2010-10-13 13:43:21 +00:00
}
}
// Verify that the machine name is unique.
if ( $element [ '#default_value' ] !== $element [ '#value' ]) {
$function = $element [ '#machine_name' ][ 'exists' ];
2013-05-12 23:23:30 +00:00
if ( call_user_func ( $function , $element [ '#value' ], $element , $form_state )) {
2013-11-23 20:57:04 +00:00
form_error ( $element , $form_state , t ( 'The machine-readable name is already in use. It must be unique.' ));
2010-10-13 13:43:21 +00:00
}
}
}
2009-04-11 22:19:46 +00:00
/**
2013-01-17 08:06:42 +00:00
* Arranges elements into groups .
2009-04-11 22:19:46 +00:00
*
2011-05-08 19:50:38 +00:00
* @ param $element
2009-04-11 22:19:46 +00:00
* An associative array containing the properties and children of the
2013-01-17 08:06:42 +00:00
* element . Note that $element must be taken by reference here , so processed
2009-12-14 13:32:53 +00:00
* child elements are taken over into $form_state .
2009-04-11 22:19:46 +00:00
* @ param $form_state
2013-01-17 08:06:42 +00:00
* The $form_state array for the form this element belongs to .
2012-02-19 03:41:24 +00:00
*
2009-04-11 22:19:46 +00:00
* @ return
* The processed element .
*/
2013-01-17 08:06:42 +00:00
function form_process_group ( & $element , & $form_state ) {
2009-04-11 22:19:46 +00:00
$parents = implode ( '][' , $element [ '#parents' ]);
2012-11-27 07:06:47 +00:00
// Each details element forms a new group. The #type 'vertical_tabs' basically
// only injects a new details element.
2009-04-11 22:19:46 +00:00
$form_state [ 'groups' ][ $parents ][ '#group_exists' ] = TRUE ;
2009-12-14 13:32:53 +00:00
$element [ '#groups' ] = & $form_state [ 'groups' ];
2012-11-27 07:06:47 +00:00
// Process vertical tabs group member details elements.
2009-12-14 13:32:53 +00:00
if ( isset ( $element [ '#group' ])) {
2012-11-27 07:06:47 +00:00
// Add this details element to the defined group (by reference).
2009-12-14 13:32:53 +00:00
$group = $element [ '#group' ];
$form_state [ 'groups' ][ $group ][] = & $element ;
2009-04-11 22:19:46 +00:00
}
2012-04-24 01:52:29 +00:00
return $element ;
}
/**
2013-01-17 08:06:42 +00:00
* Adds form element theming to details .
2012-04-24 01:52:29 +00:00
*
* @ param $element
* An associative array containing the properties and children of the
2012-11-27 07:06:47 +00:00
* details .
2012-04-24 01:52:29 +00:00
*
* @ return
2013-01-17 08:06:42 +00:00
* The modified element .
2012-04-24 01:52:29 +00:00
*/
2012-11-27 07:06:47 +00:00
function form_pre_render_details ( $element ) {
Issue #2152207 by steveoliver, joelpittet, gnuget, idflood, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_details() to Twig
2014-02-07 04:26:52 +00:00
element_set_attributes ( $element , array ( 'id' ));
2012-11-27 07:06:47 +00:00
// The .form-wrapper class is required for #states to treat details like
2010-04-29 03:34:00 +00:00
// containers.
Issue #2152207 by steveoliver, joelpittet, gnuget, idflood, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_details() to Twig
2014-02-07 04:26:52 +00:00
_form_set_attributes ( $element , array ( 'form-wrapper' ));
2010-04-29 03:34:00 +00:00
2012-11-27 07:06:47 +00:00
// Collapsible details.
2013-02-01 21:48:05 +00:00
$element [ '#attached' ][ 'library' ][] = array ( 'system' , 'drupal.collapse' );
2013-05-29 21:08:39 +00:00
if ( empty ( $element [ '#collapsed' ])) {
2012-11-27 07:06:47 +00:00
$element [ '#attributes' ][ 'open' ] = 'open' ;
2009-08-29 16:30:14 +00:00
}
2009-04-11 22:19:46 +00:00
2014-02-21 17:36:27 +00:00
// Do not render optional details elements if there are no children.
if ( isset ( $element [ '#parents' ])) {
$group = implode ( '][' , $element [ '#parents' ]);
if ( ! empty ( $element [ '#optional' ]) && ! element_get_visible_children ( $element [ '#groups' ][ $group ])) {
$element [ '#printed' ] = TRUE ;
}
}
2013-01-17 08:06:42 +00:00
return $element ;
}
/**
* Adds members of this group as actual elements for rendering .
*
* @ param $element
* An associative array containing the properties and children of the
* element .
*
* @ return
* The modified element with all group members .
*/
function form_pre_render_group ( $element ) {
// The element may be rendered outside of a Form API context.
2010-09-16 20:14:49 +00:00
if ( ! isset ( $element [ '#parents' ]) || ! isset ( $element [ '#groups' ])) {
return $element ;
}
2013-01-17 08:06:42 +00:00
2009-12-14 13:32:53 +00:00
// Inject group member elements belonging to this group.
$parents = implode ( '][' , $element [ '#parents' ]);
$children = element_children ( $element [ '#groups' ][ $parents ]);
if ( ! empty ( $children )) {
foreach ( $children as $key ) {
// Break references and indicate that the element should be rendered as
// group member.
$child = ( array ) $element [ '#groups' ][ $parents ][ $key ];
2012-11-27 07:06:47 +00:00
$child [ '#group_details' ] = TRUE ;
2009-12-14 13:32:53 +00:00
// Inject the element as new child element.
$element [] = $child ;
$sort = TRUE ;
}
// Re-sort the element's children if we injected group member elements.
if ( isset ( $sort )) {
$element [ '#sorted' ] = FALSE ;
}
}
if ( isset ( $element [ '#group' ])) {
2014-02-21 17:36:27 +00:00
// Contains form element summary functionalities.
$element [ '#attached' ][ 'library' ][] = array ( 'system' , 'drupal.form' );
2009-12-14 13:32:53 +00:00
$group = $element [ '#group' ];
// If this element belongs to a group, but the group-holding element does
// not exist, we need to render it (at its original location).
if ( ! isset ( $element [ '#groups' ][ $group ][ '#group_exists' ])) {
// Intentionally empty to clarify the flow; we simply return $element.
}
// If we injected this element into the group, then we want to render it.
2012-11-27 07:06:47 +00:00
elseif ( ! empty ( $element [ '#group_details' ])) {
2009-12-14 13:32:53 +00:00
// Intentionally empty to clarify the flow; we simply return $element.
}
// Otherwise, this element belongs to a group and the group exists, so we do
// not render it.
elseif ( element_children ( $element [ '#groups' ][ $group ])) {
$element [ '#printed' ] = TRUE ;
2009-04-11 22:19:46 +00:00
}
}
return $element ;
}
/**
* Creates a group formatted as vertical tabs .
*
* @ param $element
* An associative array containing the properties and children of the
2012-11-27 07:06:47 +00:00
* details element .
2009-04-11 22:19:46 +00:00
* @ param $form_state
* The $form_state array for the form this vertical tab widget belongs to .
2012-02-19 03:41:24 +00:00
*
2009-04-11 22:19:46 +00:00
* @ return
* The processed element .
*/
function form_process_vertical_tabs ( $element , & $form_state ) {
2012-11-27 07:06:47 +00:00
// Inject a new details as child, so that form_process_details() processes
// this details element like any other details.
2009-04-11 22:19:46 +00:00
$element [ 'group' ] = array (
2012-11-27 07:06:47 +00:00
'#type' => 'details' ,
2009-08-04 06:38:57 +00:00
'#theme_wrappers' => array (),
2009-04-11 22:19:46 +00:00
'#parents' => $element [ '#parents' ],
);
2013-01-11 08:45:49 +00:00
// Add an invisible label for accessibility.
if ( ! isset ( $element [ '#title' ])) {
$element [ '#title' ] = t ( 'Vertical Tabs' );
$element [ '#title_display' ] = 'invisible' ;
}
$element [ '#attached' ][ 'library' ][] = array ( 'system' , 'drupal.vertical-tabs' );
2009-04-11 22:19:46 +00:00
// The JavaScript stores the currently selected tab in this hidden
// field so that the active tab can be restored the next time the
// form is rendered, e.g. on preview pages or when form validation
// fails.
$name = implode ( '__' , $element [ '#parents' ]);
if ( isset ( $form_state [ 'values' ][ $name . '__active_tab' ])) {
$element [ '#default_tab' ] = $form_state [ 'values' ][ $name . '__active_tab' ];
}
$element [ $name . '__active_tab' ] = array (
'#type' => 'hidden' ,
'#default_value' => $element [ '#default_tab' ],
2009-08-22 14:34:23 +00:00
'#attributes' => array ( 'class' => array ( 'vertical-tabs-active-tab' )),
2009-04-11 22:19:46 +00:00
);
return $element ;
}
2013-01-11 08:45:49 +00:00
/**
* Prepares a vertical_tabs element for rendering .
*
* @ param array $element
* An associative array containing the properties and children of the
* vertical tabs element .
*
* @ return array
* The modified element .
*/
function form_pre_render_vertical_tabs ( $element ) {
// Do not render the vertical tabs element if it is empty.
$group = implode ( '][' , $element [ '#parents' ]);
if ( ! element_get_visible_children ( $element [ 'group' ][ '#groups' ][ $group ])) {
$element [ '#printed' ] = TRUE ;
}
return $element ;
}
2009-04-11 22:19:46 +00:00
/**
Issue #2152231 by rteijeiro, steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_vertical_tabs() to Twig
2014-01-26 05:13:33 +00:00
* Prepares variables for vertical tabs templates .
2009-04-11 22:19:46 +00:00
*
Issue #2152231 by rteijeiro, steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_vertical_tabs() to Twig
2014-01-26 05:13:33 +00:00
* Default template : vertical - tabs . html . twig .
*
* @ param array $variables
2009-10-09 01:00:08 +00:00
* An associative array containing :
2012-02-19 03:41:24 +00:00
* - element : An associative array containing the properties and children of
2012-11-27 07:06:47 +00:00
* the details element . Properties used : #children.
2009-10-09 01:00:08 +00:00
*
2009-04-11 22:19:46 +00:00
*/
Issue #2152231 by rteijeiro, steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_vertical_tabs() to Twig
2014-01-26 05:13:33 +00:00
function template_preprocess_vertical_tabs ( & $variables ) {
2009-10-09 01:00:08 +00:00
$element = $variables [ 'element' ];
Issue #2152231 by rteijeiro, steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_vertical_tabs() to Twig
2014-01-26 05:13:33 +00:00
$variables [ 'children' ] = ( ! empty ( $element [ '#children' ])) ? $element [ '#children' ] : '' ;
2009-04-11 22:19:46 +00:00
}
2012-03-30 16:17:26 +00:00
/**
2013-10-15 11:54:21 +00:00
* Adds autocomplete functionality to elements with a valid
* #autocomplete_route_name.
2012-03-30 16:17:26 +00:00
*
2013-10-15 11:54:21 +00:00
* Suppose your autocomplete route name is 'mymodule.autocomplete' and its path
* is : '/mymodule/autocomplete/{a}/{b}'
2012-04-17 03:40:10 +00:00
* In your form you have :
* @ code
2013-10-15 11:54:21 +00:00
* '#autocomplete_route_name' => 'mymodule.autocomplete' ,
2013-08-21 07:34:21 +00:00
* '#autocomplete_route_parameters' => array ( 'a' => $some_key , 'b' => $some_id ),
* @ endcode
2012-04-17 03:40:10 +00:00
* The user types in " keywords " so the full path called is :
2012-12-03 03:23:33 +00:00
* 'mymodule_autocomplete/$some_key/$some_id?q=keywords'
2012-04-17 03:40:10 +00:00
*
2013-08-21 07:34:21 +00:00
* @ param array $element
2012-03-30 16:17:26 +00:00
* The form element to process . Properties used :
2013-08-21 07:34:21 +00:00
* - #autocomplete_route_name: A route to be used as callback URL by the
* autocomplete JavaScript library .
* - #autocomplete_route_parameters: The parameters to be used in conjunction
* with the route name .
* @ param array $form_state
* An associative array containing the current state of the form .
*
* @ return array
* The form element .
2012-03-30 16:17:26 +00:00
*/
function form_process_autocomplete ( $element , & $form_state ) {
2013-08-21 07:34:21 +00:00
$access = FALSE ;
if ( ! empty ( $element [ '#autocomplete_route_name' ])) {
$parameters = isset ( $element [ '#autocomplete_route_parameters' ]) ? $element [ '#autocomplete_route_parameters' ] : array ();
2013-09-16 03:58:06 +00:00
$path = \Drupal :: urlGenerator () -> generate ( $element [ '#autocomplete_route_name' ], $parameters );
2013-10-30 17:31:44 +00:00
$access = \Drupal :: service ( 'access_manager' ) -> checkNamedRoute ( $element [ '#autocomplete_route_name' ], $parameters , \Drupal :: currentUser ());
2013-08-21 07:34:21 +00:00
}
if ( $access ) {
2012-03-30 16:17:26 +00:00
$element [ '#attributes' ][ 'class' ][] = 'form-autocomplete' ;
$element [ '#attached' ][ 'library' ][] = array ( 'system' , 'drupal.autocomplete' );
Issue #675446 by mgifford, RobLoach, amateescu, nod_, longwave, oxyc, rteijeiro, tomyouds, Jelle_S, mcrittenden, Sutharsan, hansyg, Angry Dan, clemens.tolboom, droplet | Dave Reid: Change notice: Use jQuery UI Autocomplete.
2013-11-24 20:26:30 +00:00
// Provide a data attribute for the JavaScript behavior to bind to.
$element [ '#attributes' ][ 'data-autocomplete-path' ] = $path ;
2012-03-30 16:17:26 +00:00
}
return $element ;
}
2007-12-06 09:58:34 +00:00
/**
2013-01-10 05:45:55 +00:00
* Preprocesses variables for theme_input () .
2009-08-19 08:15:36 +00:00
*
2013-01-10 05:45:55 +00:00
* @ param array $variables
2009-10-09 01:00:08 +00:00
* An associative array containing :
* - element : An associative array containing the properties of the element .
*
2007-12-06 09:58:34 +00:00
* @ ingroup themeable
*/
2013-01-10 05:45:55 +00:00
function template_preprocess_input ( & $variables ) {
$element = $variables [ 'element' ];
$variables [ 'attributes' ] = new Attribute ( $element [ '#attributes' ]);
2005-10-07 06:11:12 +00:00
}
2007-12-06 09:58:34 +00:00
/**
2013-01-10 05:45:55 +00:00
* Returns HTML for an input form element .
2009-08-19 08:15:36 +00:00
*
2013-01-10 05:45:55 +00:00
* @ param array $variables
2009-10-09 01:00:08 +00:00
* An associative array containing :
* - element : An associative array containing the properties of the element .
2013-01-10 05:45:55 +00:00
* Properties used : #attributes.
2012-11-21 19:37:44 +00:00
*
2007-12-06 09:58:34 +00:00
* @ ingroup themeable
*/
2013-01-10 05:45:55 +00:00
function theme_input ( $variables ) {
2009-10-09 01:00:08 +00:00
$element = $variables [ 'element' ];
2013-01-10 05:45:55 +00:00
$attributes = $variables [ 'attributes' ];
return '<input' . $attributes . ' />' . drupal_render_children ( $element );
}
/**
* Prepares a #type 'button' render element for theme_input().
*
* @ param array $element
* An associative array containing the properties of the element .
* Properties used : #attributes, #button_type, #name, #value.
*
* The #button_type property accepts any value, though core themes have CSS that
* styles the following button_types appropriately : 'primary' , 'danger' .
*
* @ return array
* The $element with prepared variables ready for theme_input () .
*/
function form_pre_render_button ( $element ) {
2010-07-31 04:01:51 +00:00
$element [ '#attributes' ][ 'type' ] = 'submit' ;
2010-09-16 20:14:49 +00:00
element_set_attributes ( $element , array ( 'id' , 'name' , 'value' ));
2013-01-02 12:00:25 +00:00
$element [ '#attributes' ][ 'class' ][] = 'button' ;
2012-11-21 19:37:44 +00:00
if ( ! empty ( $element [ '#button_type' ])) {
2013-11-23 00:23:37 +00:00
$element [ '#attributes' ][ 'class' ][] = 'button--' . $element [ '#button_type' ];
2012-11-21 19:37:44 +00:00
}
// @todo Various JavaScript depends on this button class.
$element [ '#attributes' ][ 'class' ][] = 'form-submit' ;
2010-07-31 04:01:51 +00:00
if ( ! empty ( $element [ '#attributes' ][ 'disabled' ])) {
2013-11-23 00:23:37 +00:00
$element [ '#attributes' ][ 'class' ][] = 'is-disabled' ;
2010-07-31 04:01:51 +00:00
}
2006-03-29 23:29:41 +00:00
2013-01-10 05:45:55 +00:00
return $element ;
2005-10-07 06:11:12 +00:00
}
2007-07-29 17:28:23 +00:00
/**
2013-01-10 05:45:55 +00:00
* Prepares a #type 'image_button' render element for theme_input().
2007-12-06 09:58:34 +00:00
*
2013-01-10 05:45:55 +00:00
* @ param array $element
* An associative array containing the properties of the element .
* Properties used : #attributes, #button_type, #name, #value, #title, #src.
2009-10-09 01:00:08 +00:00
*
2012-11-21 19:37:44 +00:00
* The #button_type property accepts any value, though core themes have css that
* styles the following button_types appropriately : 'primary' , 'danger' .
*
2013-01-10 05:45:55 +00:00
* @ return array
* The $element with prepared variables ready for theme_input () .
2007-07-29 17:28:23 +00:00
*/
2013-01-10 05:45:55 +00:00
function form_pre_render_image_button ( $element ) {
2010-08-20 01:08:18 +00:00
$element [ '#attributes' ][ 'type' ] = 'image' ;
2010-09-16 20:14:49 +00:00
element_set_attributes ( $element , array ( 'id' , 'name' , 'value' ));
2010-07-31 04:01:51 +00:00
$element [ '#attributes' ][ 'src' ] = file_create_url ( $element [ '#src' ]);
if ( ! empty ( $element [ '#title' ])) {
$element [ '#attributes' ][ 'alt' ] = $element [ '#title' ];
$element [ '#attributes' ][ 'title' ] = $element [ '#title' ];
}
2012-11-21 19:37:44 +00:00
$element [ '#attributes' ][ 'class' ][] = 'image-button' ;
if ( ! empty ( $element [ '#button_type' ])) {
2013-11-23 00:23:37 +00:00
$element [ '#attributes' ][ 'class' ][] = 'image-button--' . $element [ '#button_type' ];
2012-11-21 19:37:44 +00:00
}
// @todo Various JavaScript depends on this button class.
$element [ '#attributes' ][ 'class' ][] = 'form-submit' ;
2010-07-31 04:01:51 +00:00
if ( ! empty ( $element [ '#attributes' ][ 'disabled' ])) {
2013-11-23 00:23:37 +00:00
$element [ '#attributes' ][ 'class' ][] = 'is-disabled' ;
2010-07-31 04:01:51 +00:00
}
2007-07-29 17:28:23 +00:00
2013-01-10 05:45:55 +00:00
return $element ;
2007-07-29 17:28:23 +00:00
}
2005-10-07 06:11:12 +00:00
/**
2013-01-10 05:45:55 +00:00
* Prepares a #type 'hidden' render element for theme_input().
2005-10-07 06:11:12 +00:00
*
2013-01-10 05:45:55 +00:00
* @ param array $element
* An associative array containing the properties of the element .
* Properties used : #name, #value, #attributes.
2009-10-09 01:00:08 +00:00
*
2013-01-10 05:45:55 +00:00
* @ return array
* The $element with prepared variables ready for theme_input () .
2005-10-07 06:11:12 +00:00
*/
2013-01-10 05:45:55 +00:00
function form_pre_render_hidden ( $element ) {
2010-07-31 04:01:51 +00:00
$element [ '#attributes' ][ 'type' ] = 'hidden' ;
2010-09-22 03:34:57 +00:00
element_set_attributes ( $element , array ( 'name' , 'value' ));
2013-01-10 05:45:55 +00:00
return $element ;
2005-10-07 06:11:12 +00:00
}
/**
2013-01-10 05:45:55 +00:00
* Prepares a #type 'textfield' render element for theme_input().
2005-10-07 06:11:12 +00:00
*
2013-01-10 05:45:55 +00:00
* @ param array $element
* An associative array containing the properties of the element .
* Properties used : #title, #value, #description, #size, #maxlength,
* #placeholder, #required, #attributes.
2009-10-09 01:00:08 +00:00
*
2013-01-10 05:45:55 +00:00
* @ return array
* The $element with prepared variables ready for theme_input () .
2005-10-07 06:11:12 +00:00
*/
2013-01-10 05:45:55 +00:00
function form_pre_render_textfield ( $element ) {
2010-07-31 04:01:51 +00:00
$element [ '#attributes' ][ 'type' ] = 'text' ;
2011-08-06 22:03:31 +00:00
element_set_attributes ( $element , array ( 'id' , 'name' , 'value' , 'size' , 'maxlength' , 'placeholder' ));
2012-10-23 22:43:41 +00:00
_form_set_attributes ( $element , array ( 'form-text' ));
2006-08-26 09:56:17 +00:00
2013-01-10 05:45:55 +00:00
return $element ;
2012-01-19 12:55:48 +00:00
}
2012-03-02 07:29:16 +00:00
/**
2013-01-10 05:45:55 +00:00
* Prepares a #type 'email' render element for theme_input().
2012-03-02 07:29:16 +00:00
*
2013-01-10 05:45:55 +00:00
* @ param array $element
* An associative array containing the properties of the element .
* Properties used : #title, #value, #description, #size, #maxlength,
* #placeholder, #required, #attributes.
2012-03-02 07:29:16 +00:00
*
2013-01-10 05:45:55 +00:00
* @ return array
* The $element with prepared variables ready for theme_input () .
2012-03-02 07:29:16 +00:00
*/
2013-01-10 05:45:55 +00:00
function form_pre_render_email ( $element ) {
2012-03-02 07:29:16 +00:00
$element [ '#attributes' ][ 'type' ] = 'email' ;
element_set_attributes ( $element , array ( 'id' , 'name' , 'value' , 'size' , 'maxlength' , 'placeholder' ));
2012-10-23 22:43:41 +00:00
_form_set_attributes ( $element , array ( 'form-email' ));
2012-03-02 07:29:16 +00:00
2013-01-10 05:45:55 +00:00
return $element ;
2012-03-02 07:29:16 +00:00
}
/**
* Form element validation handler for #type 'email'.
*
* Note that #maxlength and #required is validated by _form_validate() already.
*/
function form_validate_email ( & $element , & $form_state ) {
$value = trim ( $element [ '#value' ]);
form_set_value ( $element , $value , $form_state );
if ( $value !== '' && ! valid_email_address ( $value )) {
2013-11-23 20:57:04 +00:00
form_error ( $element , $form_state , t ( 'The e-mail address %mail is not valid.' , array ( '%mail' => $value )));
2012-03-02 07:29:16 +00:00
}
}
2012-01-19 12:55:48 +00:00
/**
2013-01-10 05:45:55 +00:00
* Prepares a #type 'tel' render element for theme_input().
2012-01-19 12:55:48 +00:00
*
2013-01-10 05:45:55 +00:00
* @ param array $element
* An associative array containing the properties of the element .
* Properties used : #title, #value, #description, #size, #maxlength,
* #placeholder, #required, #attributes.
2012-01-19 12:55:48 +00:00
*
2013-01-10 05:45:55 +00:00
* @ return array
* The $element with prepared variables ready for theme_input () .
2012-01-19 12:55:48 +00:00
*/
2013-01-10 05:45:55 +00:00
function form_pre_render_tel ( $element ) {
2012-01-19 12:55:48 +00:00
$element [ '#attributes' ][ 'type' ] = 'tel' ;
element_set_attributes ( $element , array ( 'id' , 'name' , 'value' , 'size' , 'maxlength' , 'placeholder' ));
2012-10-23 22:43:41 +00:00
_form_set_attributes ( $element , array ( 'form-tel' ));
2012-01-19 12:55:48 +00:00
2013-01-10 05:45:55 +00:00
return $element ;
2005-10-07 06:11:12 +00:00
}
2012-04-07 02:35:00 +00:00
/**
2013-01-10 05:45:55 +00:00
* Prepares a #type 'number' render element for theme_input().
2012-04-07 02:35:00 +00:00
*
2013-01-10 05:45:55 +00:00
* @ param array $element
* An associative array containing the properties of the element .
* Properties used : #title, #value, #description, #min, #max, #placeholder,
2013-05-19 17:37:19 +00:00
* #required, #attributes, #step, #size.
2012-04-07 02:35:00 +00:00
*
2013-01-10 05:45:55 +00:00
* @ return array
* The $element with prepared variables ready for theme_input () .
2012-04-07 02:35:00 +00:00
*/
2013-01-10 05:45:55 +00:00
function form_pre_render_number ( $element ) {
2012-04-07 02:35:00 +00:00
$element [ '#attributes' ][ 'type' ] = 'number' ;
2013-05-19 17:37:19 +00:00
element_set_attributes ( $element , array ( 'id' , 'name' , 'value' , 'step' , 'min' , 'max' , 'placeholder' , 'size' ));
2012-10-23 22:43:41 +00:00
_form_set_attributes ( $element , array ( 'form-number' ));
2012-04-07 02:35:00 +00:00
2013-01-10 05:45:55 +00:00
return $element ;
2012-04-07 02:35:00 +00:00
}
2012-04-19 03:07:55 +00:00
/**
2013-01-10 05:45:55 +00:00
* Prepares a #type 'range' render element for theme_input().
2012-04-19 03:07:55 +00:00
*
2013-01-10 05:45:55 +00:00
* @ param array $element
* An associative array containing the properties of the element .
* Properties used : #title, #value, #description, #min, #max, #attributes,
* #step.
2012-04-19 03:07:55 +00:00
*
2013-01-10 05:45:55 +00:00
* @ return array
* The $element with prepared variables ready for theme_input () .
2012-04-19 03:07:55 +00:00
*/
2013-01-10 05:45:55 +00:00
function form_pre_render_range ( $element ) {
2012-04-19 03:07:55 +00:00
$element [ '#attributes' ][ 'type' ] = 'range' ;
element_set_attributes ( $element , array ( 'id' , 'name' , 'value' , 'step' , 'min' , 'max' ));
2012-10-23 22:43:41 +00:00
_form_set_attributes ( $element , array ( 'form-range' ));
2012-04-19 03:07:55 +00:00
2013-01-10 05:45:55 +00:00
return $element ;
2012-04-19 03:07:55 +00:00
}
2012-04-07 02:35:00 +00:00
/**
* Form element validation handler for #type 'number'.
*
* Note that #required is validated by _form_validate() already.
*/
function form_validate_number ( & $element , & $form_state ) {
$value = $element [ '#value' ];
if ( $value === '' ) {
return ;
}
$name = empty ( $element [ '#title' ]) ? $element [ '#parents' ][ 0 ] : $element [ '#title' ];
// Ensure the input is numeric.
if ( ! is_numeric ( $value )) {
2013-11-23 20:57:04 +00:00
form_error ( $element , $form_state , t ( '%name must be a number.' , array ( '%name' => $name )));
2012-04-07 02:35:00 +00:00
return ;
}
// Ensure that the input is greater than the #min property, if set.
if ( isset ( $element [ '#min' ]) && $value < $element [ '#min' ]) {
2013-11-23 20:57:04 +00:00
form_error ( $element , $form_state , t ( '%name must be higher than or equal to %min.' , array ( '%name' => $name , '%min' => $element [ '#min' ])));
2012-04-07 02:35:00 +00:00
}
// Ensure that the input is less than the #max property, if set.
if ( isset ( $element [ '#max' ]) && $value > $element [ '#max' ]) {
2013-11-23 20:57:04 +00:00
form_error ( $element , $form_state , t ( '%name must be lower than or equal to %max.' , array ( '%name' => $name , '%max' => $element [ '#max' ])));
2012-04-07 02:35:00 +00:00
}
if ( isset ( $element [ '#step' ]) && strtolower ( $element [ '#step' ]) != 'any' ) {
// Check that the input is an allowed multiple of #step (offset by #min if
// #min is set).
$offset = isset ( $element [ '#min' ]) ? $element [ '#min' ] : 0.0 ;
2013-10-16 11:04:31 +00:00
if ( ! Number :: validStep ( $value , $element [ '#step' ], $offset )) {
2013-11-23 20:57:04 +00:00
form_error ( $element , $form_state , t ( '%name is not a valid number.' , array ( '%name' => $name )));
2012-04-07 02:35:00 +00:00
}
}
}
2012-05-08 02:53:23 +00:00
/**
* Determines the value for a range element .
*
* Make sure range elements always have a value . The 'required' attribute is not
* allowed for range elements .
*
* @ 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 .
*
* @ return
* The data that will appear in the $form_state [ 'values' ] collection for
* this element . Return nothing to use the default .
*/
function form_type_range_value ( $element , $input = FALSE ) {
if ( $input === '' ) {
$offset = ( $element [ '#max' ] - $element [ '#min' ]) / 2 ;
// Round to the step.
if ( strtolower ( $element [ '#step' ]) != 'any' ) {
$steps = round ( $offset / $element [ '#step' ]);
$offset = $element [ '#step' ] * $steps ;
}
return $element [ '#min' ] + $offset ;
}
}
2012-03-08 15:13:41 +00:00
/**
2013-01-10 05:45:55 +00:00
* Prepares a #type 'url' render element for theme_input().
2012-03-08 15:13:41 +00:00
*
2013-01-10 05:45:55 +00:00
* @ param array $element
* An associative array containing the properties of the element .
* Properties used : #title, #value, #description, #size, #maxlength,
* #placeholder, #required, #attributes.
2012-03-08 15:13:41 +00:00
*
2013-01-10 05:45:55 +00:00
* @ return array
* The $element with prepared variables ready for theme_input () .
2012-03-08 15:13:41 +00:00
*/
2013-01-10 05:45:55 +00:00
function form_pre_render_url ( $element ) {
2012-03-08 15:13:41 +00:00
$element [ '#attributes' ][ 'type' ] = 'url' ;
element_set_attributes ( $element , array ( 'id' , 'name' , 'value' , 'size' , 'maxlength' , 'placeholder' ));
2012-10-23 22:43:41 +00:00
_form_set_attributes ( $element , array ( 'form-url' ));
2012-03-08 15:13:41 +00:00
2013-01-10 05:45:55 +00:00
return $element ;
2012-03-27 06:17:38 +00:00
}
/**
2013-01-10 05:45:55 +00:00
* Prepares a #type 'search' render element for theme_input().
2012-03-27 06:17:38 +00:00
*
2013-01-10 05:45:55 +00:00
* @ param array $element
* An associative array containing the properties of the element .
* Properties used : #title, #value, #description, #size, #maxlength,
* #placeholder, #required, #attributes.
2012-03-27 06:17:38 +00:00
*
2013-01-10 05:45:55 +00:00
* @ return array
* The $element with prepared variables ready for theme_input () .
2012-03-27 06:17:38 +00:00
*/
2013-01-10 05:45:55 +00:00
function form_pre_render_search ( $element ) {
2012-03-27 06:17:38 +00:00
$element [ '#attributes' ][ 'type' ] = 'search' ;
element_set_attributes ( $element , array ( 'id' , 'name' , 'value' , 'size' , 'maxlength' , 'placeholder' ));
2012-10-23 22:43:41 +00:00
_form_set_attributes ( $element , array ( 'form-search' ));
2012-03-27 06:17:38 +00:00
2013-01-10 05:45:55 +00:00
return $element ;
2012-03-08 15:13:41 +00:00
}
/**
* Form element validation handler for #type 'url'.
*
* Note that #maxlength and #required is validated by _form_validate() already.
*/
function form_validate_url ( & $element , & $form_state ) {
$value = trim ( $element [ '#value' ]);
form_set_value ( $element , $value , $form_state );
if ( $value !== '' && ! valid_url ( $value , TRUE )) {
2013-11-23 20:57:04 +00:00
form_error ( $element , $form_state , t ( 'The URL %url is not valid.' , array ( '%url' => $value )));
2012-03-08 15:13:41 +00:00
}
}
2012-07-07 20:21:18 +00:00
/**
* Form element validation handler for #type 'color'.
*/
function form_validate_color ( & $element , & $form_state ) {
$value = trim ( $element [ '#value' ]);
// Default to black if no value is given.
// @see http://www.w3.org/TR/html5/number-state.html#color-state
if ( $value === '' ) {
form_set_value ( $element , '#000000' , $form_state );
}
else {
// Try to parse the value and normalize it.
try {
form_set_value ( $element , Color :: rgbToHex ( Color :: hexToRgb ( $value )), $form_state );
}
catch ( InvalidArgumentException $e ) {
2013-11-23 20:57:04 +00:00
form_error ( $element , $form_state , t ( '%name must be a valid color.' , array ( '%name' => empty ( $element [ '#title' ]) ? $element [ '#parents' ][ 0 ] : $element [ '#title' ])));
2012-07-07 20:21:18 +00:00
}
}
}
/**
2013-01-10 05:45:55 +00:00
* Prepares a #type 'color' render element for theme_input().
2012-07-07 20:21:18 +00:00
*
2013-01-10 05:45:55 +00:00
* @ param array $element
* An associative array containing the properties of the element .
* Properties used : #title, #value, #description, #attributes.
2012-07-07 20:21:18 +00:00
*
2013-01-10 05:45:55 +00:00
* @ return array
* The $element with prepared variables ready for theme_input () .
2012-07-07 20:21:18 +00:00
*/
2013-01-10 05:45:55 +00:00
function form_pre_render_color ( $element ) {
2012-07-07 20:21:18 +00:00
$element [ '#attributes' ][ 'type' ] = 'color' ;
element_set_attributes ( $element , array ( 'id' , 'name' , 'value' ));
2012-10-23 22:43:41 +00:00
_form_set_attributes ( $element , array ( 'form-color' ));
2012-07-07 20:21:18 +00:00
2013-01-10 05:45:55 +00:00
return $element ;
2012-07-07 20:21:18 +00:00
}
2005-10-07 06:11:12 +00:00
/**
2010-04-13 15:23:03 +00:00
* Returns HTML for a form .
2005-10-07 06:11:12 +00:00
*
2009-10-09 01:00:08 +00:00
* @ param $variables
* An associative array containing :
* - element : An associative array containing the properties of the element .
* Properties used : #action, #method, #attributes, #children
*
2007-12-06 09:58:34 +00:00
* @ ingroup themeable
2005-10-07 06:11:12 +00:00
*/
2009-10-09 01:00:08 +00:00
function theme_form ( $variables ) {
$element = $variables [ 'element' ];
2010-09-16 20:14:49 +00:00
if ( isset ( $element [ '#action' ])) {
2013-10-09 04:42:16 +00:00
$element [ '#attributes' ][ 'action' ] = Url :: stripDangerousProtocols ( $element [ '#action' ]);
2010-07-31 04:01:51 +00:00
}
2010-09-16 20:14:49 +00:00
element_set_attributes ( $element , array ( 'method' , 'id' ));
2010-06-25 20:19:13 +00:00
if ( empty ( $element [ '#attributes' ][ 'accept-charset' ])) {
$element [ '#attributes' ][ 'accept-charset' ] = " UTF-8 " ;
}
2010-07-31 04:01:51 +00:00
// Anonymous DIV to satisfy XHTML compliance.
2012-09-04 13:32:47 +00:00
return '<form' . new Attribute ( $element [ '#attributes' ]) . '><div>' . $element [ '#children' ] . '</div></form>' ;
2005-10-07 06:11:12 +00:00
}
/**
Issue #2152229 by steveoliver, rteijeiro, joelpittet, JeroenT, InternetDevels, michamilz, burgerboydaddy, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_textarea() to Twig
2014-02-04 17:28:23 +00:00
* Prepares variables for textarea templates .
2005-10-07 06:11:12 +00:00
*
Issue #2152229 by steveoliver, rteijeiro, joelpittet, JeroenT, InternetDevels, michamilz, burgerboydaddy, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_textarea() to Twig
2014-02-04 17:28:23 +00:00
* Default template : textarea . html . twig .
*
* @ param array $variables
2009-10-09 01:00:08 +00:00
* An associative array containing :
* - element : An associative array containing the properties of the element .
2011-08-06 22:03:31 +00:00
* Properties used : #title, #value, #description, #rows, #cols,
2012-03-02 06:28:37 +00:00
* #placeholder, #required, #attributes, #resizable
2009-10-09 01:00:08 +00:00
*
2005-10-07 06:11:12 +00:00
*/
Issue #2152229 by steveoliver, rteijeiro, joelpittet, JeroenT, InternetDevels, michamilz, burgerboydaddy, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_textarea() to Twig
2014-02-04 17:28:23 +00:00
function template_preprocess_textarea ( & $variables ) {
2009-10-09 01:00:08 +00:00
$element = $variables [ 'element' ];
2011-08-06 22:03:31 +00:00
element_set_attributes ( $element , array ( 'id' , 'name' , 'rows' , 'cols' , 'placeholder' ));
2012-10-23 22:43:41 +00:00
_form_set_attributes ( $element , array ( 'form-textarea' ));
Issue #2152229 by steveoliver, rteijeiro, joelpittet, JeroenT, InternetDevels, michamilz, burgerboydaddy, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_textarea() to Twig
2014-02-04 17:28:23 +00:00
$variables [ 'wrapper_attributes' ] = new Attribute ( array (
2010-03-09 11:45:37 +00:00
'class' => array ( 'form-textarea-wrapper' ),
Issue #2152229 by steveoliver, rteijeiro, joelpittet, JeroenT, InternetDevels, michamilz, burgerboydaddy, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_textarea() to Twig
2014-02-04 17:28:23 +00:00
));
2007-04-09 13:58:03 +00:00
2010-03-09 11:45:37 +00:00
// Add resizable behavior.
if ( ! empty ( $element [ '#resizable' ])) {
2012-03-02 06:28:37 +00:00
$element [ '#attributes' ][ 'class' ][] = 'resize-' . $element [ '#resizable' ];
2005-12-29 03:59:30 +00:00
}
Issue #2152229 by steveoliver, rteijeiro, joelpittet, JeroenT, InternetDevels, michamilz, burgerboydaddy, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_textarea() to Twig
2014-02-04 17:28:23 +00:00
$variables [ 'attributes' ] = new Attribute ( $element [ '#attributes' ]);
$variables [ 'value' ] = String :: checkPlain ( $element [ '#value' ]);
2005-10-07 06:11:12 +00:00
}
/**
2013-01-10 05:45:55 +00:00
* Prepares a #type 'password' render element for theme_input().
2007-05-04 09:41:37 +00:00
*
2013-01-10 05:45:55 +00:00
* @ param array $element
* An associative array containing the properties of the element .
* Properties used : #title, #value, #description, #size, #maxlength,
* #placeholder, #required, #attributes.
2009-10-09 01:00:08 +00:00
*
2013-01-10 05:45:55 +00:00
* @ return array
* The $element with prepared variables ready for theme_input () .
2007-05-04 09:41:37 +00:00
*/
2013-01-10 05:45:55 +00:00
function form_pre_render_password ( $element ) {
2010-07-31 04:01:51 +00:00
$element [ '#attributes' ][ 'type' ] = 'password' ;
2011-08-06 22:03:31 +00:00
element_set_attributes ( $element , array ( 'id' , 'name' , 'size' , 'maxlength' , 'placeholder' ));
2012-10-23 22:43:41 +00:00
_form_set_attributes ( $element , array ( 'form-text' ));
2010-07-31 04:01:51 +00:00
2013-01-10 05:45:55 +00:00
return $element ;
2005-10-07 06:11:12 +00:00
}
/**
2012-02-19 03:41:24 +00:00
* Expands a weight element into a select element .
2005-10-07 06:11:12 +00:00
*/
2008-07-18 07:06:24 +00:00
function form_process_weight ( $element ) {
2006-05-04 09:57:14 +00:00
$element [ '#is_weight' ] = TRUE ;
2011-12-02 05:05:37 +00:00
// If the number of options is small enough, use a select field.
2013-09-16 03:58:06 +00:00
$max_elements = \Drupal :: config ( 'system.site' ) -> get ( 'weight_select_max' );
2011-12-02 05:05:37 +00:00
if ( $element [ '#delta' ] <= $max_elements ) {
$element [ '#type' ] = 'select' ;
for ( $n = ( - 1 * $element [ '#delta' ]); $n <= $element [ '#delta' ]; $n ++ ) {
$weights [ $n ] = $n ;
}
$element [ '#options' ] = $weights ;
$element += element_info ( 'select' );
}
// Otherwise, use a text field.
else {
2012-04-09 18:11:07 +00:00
$element [ '#type' ] = 'number' ;
2011-12-02 05:05:37 +00:00
// Use a field big enough to fit most weights.
$element [ '#size' ] = 10 ;
2012-04-09 18:11:07 +00:00
$element += element_info ( 'number' );
2011-12-02 05:05:37 +00:00
}
2006-05-04 09:57:14 +00:00
return $element ;
2005-10-07 06:11:12 +00:00
}
/**
2013-01-10 05:45:55 +00:00
* Prepares a #type 'file' render element for theme_input().
2010-04-13 15:23:03 +00:00
*
* For assistance with handling the uploaded file correctly , see the API
* provided by file . inc .
2005-10-07 06:11:12 +00:00
*
2013-01-10 05:45:55 +00:00
* @ param array $element
* An associative array containing the properties of the element .
* Properties used : #title, #name, #size, #description, #required,
* #attributes.
2009-10-09 01:00:08 +00:00
*
2013-01-10 05:45:55 +00:00
* @ return array
* The $element with prepared variables ready for theme_input () .
2005-10-07 06:11:12 +00:00
*/
2013-01-10 05:45:55 +00:00
function form_pre_render_file ( $element ) {
2010-07-31 04:01:51 +00:00
$element [ '#attributes' ][ 'type' ] = 'file' ;
2010-09-16 20:14:49 +00:00
element_set_attributes ( $element , array ( 'id' , 'name' , 'size' ));
2012-10-23 22:43:41 +00:00
_form_set_attributes ( $element , array ( 'form-file' ));
2010-07-31 04:01:51 +00:00
2013-01-10 05:45:55 +00:00
return $element ;
2006-05-02 09:26:33 +00:00
}
2013-04-20 03:34:14 +00:00
/**
* Processes a file upload element , make use of #multiple if present.
*/
function form_process_file ( $element ) {
if ( $element [ '#multiple' ]) {
$element [ '#attributes' ] = array ( 'multiple' => 'multiple' );
$element [ '#name' ] .= '[]' ;
}
return $element ;
}
2006-05-02 09:26:33 +00:00
/**
2010-04-13 15:23:03 +00:00
* Returns HTML for a form element .
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
* Prepares variables for form element templates .
*
* Default template : form - element . html . twig .
2006-05-02 09:26:33 +00:00
*
2010-07-31 04:01:51 +00:00
* Each form element is wrapped in a DIV container having the following CSS
* classes :
* - form - item : Generic for all form elements .
* - form - type - #type: The internal element #type.
* - form - item - #name: The internal form element #name (usually derived from the
* $form structure and set via form_builder ()) .
* - form - disabled : Only set if the form element is #disabled.
*
* In addition to the element itself , the DIV contains a label for the element
* based on the optional #title_display property, and an optional #description.
2009-12-02 15:09:16 +00:00
*
* The optional #title_display property can have these values:
* - before : The label is output before the element . This is the default .
* The label includes the #title and the required marker, if #required.
* - after : The label is output after the element . For example , this is used
* for radio and checkbox #type elements as set in system_element_info().
* If the #title is empty but the field is #required, the label will
* contain only the required marker .
2010-04-07 04:39:59 +00:00
* - invisible : Labels are critical for screen readers to enable them to
* properly navigate through forms but can be visually distracting . This
* property hides the label for everyone except screen readers .
2009-12-02 15:09:16 +00:00
* - attribute : Set the title attribute on the element to create a tooltip
* but output no label element . This is supported only for checkboxes
* and radios in form_pre_render_conditional_form_element () . It is used
* where a visual label is not needed , such as a table of checkboxes where
* the row and column provide the context . The tooltip will include the
* title and required marker .
*
* If the #title property is not set, then the label and any required marker
* will not be output , regardless of the #title_display or #required values.
* This can be useful in cases such as the password_confirm element , which
* creates children elements that have their own labels and required markers ,
* but the parent element should have neither . Use this carefully because a
* field without an associated label can cause accessibility challenges .
*
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
* @ param array $variables
2009-10-09 01:00:08 +00:00
* An associative array containing :
* - element : An associative array containing the properties of the element .
2009-12-02 15:09:16 +00:00
* Properties used : #title, #title_display, #description, #id, #required,
* #children, #type, #name.
2009-10-09 01:00:08 +00:00
*
2007-12-06 09:58:34 +00:00
* @ ingroup themeable
2006-05-02 09:26:33 +00:00
*/
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
function template_preprocess_form_element ( & $variables ) {
2010-09-16 20:14:49 +00:00
$element = & $variables [ 'element' ];
2007-11-13 14:04:08 +00:00
2010-09-16 20:14:49 +00:00
// This function is invoked as theme wrapper, but the rendered form element
// may not necessarily have been processed by form_builder().
$element += array (
'#title_display' => 'before' ,
);
2013-01-17 20:43:29 +00:00
// Take over any #wrapper_attributes defined by the element.
// @todo Temporary hack for #type 'item'.
// @see http://drupal.org/node/1829202
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
$variables [ 'attributes' ] = array ();
2013-01-17 20:43:29 +00:00
if ( isset ( $element [ '#wrapper_attributes' ])) {
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
$variables [ 'attributes' ] = $element [ '#wrapper_attributes' ];
2013-01-17 20:43:29 +00:00
}
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
2010-05-01 00:19:35 +00:00
// Add element #id for #type 'item'.
if ( isset ( $element [ '#markup' ]) && ! empty ( $element [ '#id' ])) {
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
$variables [ 'attributes' ][ 'id' ] = $element [ '#id' ];
2010-05-01 00:19:35 +00:00
}
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
2009-06-14 08:04:25 +00:00
// Add element's #type and #name as class to aid with JS/CSS selectors.
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
$variables [ 'attributes' ][ 'class' ][] = 'form-item' ;
2009-06-14 08:04:25 +00:00
if ( ! empty ( $element [ '#type' ])) {
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
$variables [ 'attributes' ][ 'class' ][] = 'form-type-' . strtr ( $element [ '#type' ], '_' , '-' );
2009-06-14 08:04:25 +00:00
}
if ( ! empty ( $element [ '#name' ])) {
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
$variables [ 'attributes' ][ 'class' ][] = 'form-item-' . strtr ( $element [ '#name' ], array ( ' ' => '-' , '_' => '-' , '[' => '-' , ']' => '' ));
2009-06-14 08:04:25 +00:00
}
2010-07-31 04:01:51 +00:00
// Add a class for disabled elements to facilitate cross-browser styling.
if ( ! empty ( $element [ '#attributes' ][ 'disabled' ])) {
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
$variables [ 'attributes' ][ 'class' ][] = 'form-disabled' ;
2010-07-31 04:01:51 +00:00
}
2009-06-14 08:04:25 +00:00
2009-12-02 15:09:16 +00:00
// If #title is not set, we don't display any label or required marker.
if ( ! isset ( $element [ '#title' ])) {
$element [ '#title_display' ] = 'none' ;
}
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
$variables [ 'prefix' ] = isset ( $element [ '#field_prefix' ]) ? $element [ '#field_prefix' ] : NULL ;
$variables [ 'suffix' ] = isset ( $element [ '#field_suffix' ]) ? $element [ '#field_suffix' ] : NULL ;
2006-05-02 09:26:33 +00:00
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
$variables [ 'description' ] = NULL ;
2006-05-02 09:26:33 +00:00
if ( ! empty ( $element [ '#description' ])) {
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
$description_attributes = array ( 'class' => 'description' );
2012-04-05 07:09:10 +00:00
if ( ! empty ( $element [ '#id' ])) {
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
$description_attributes [ 'id' ] = $element [ '#id' ] . '--description' ;
2012-04-05 07:09:10 +00:00
}
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
$variables [ 'description' ][ 'attributes' ] = new Attribute ( $description_attributes );
$variables [ 'description' ][ 'content' ] = $element [ '#description' ];
2006-05-02 09:26:33 +00:00
}
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
// Add label_display and label variables to template.
$variables [ 'label_display' ] = $element [ '#title_display' ];
$variables [ 'label' ] = array ( '#theme' => 'form_element_label' );
$variables [ 'label' ] += array_intersect_key ( $element , array_flip ( array ( '#id' , '#required' , '#title' , '#title_display' )));
2006-05-02 09:26:33 +00:00
Issue #2152213 by steveoliver, joelpittet, hussainweb, shanethehat, jenlampton, kpa, AnythonyR, EVIIILJ, kgoel, Cottser, dsdeiz, hanpersand: Convert theme_form_element() to Twig
2014-02-04 13:24:34 +00:00
$variables [ 'children' ] = $element [ '#children' ];
2005-10-07 06:11:12 +00:00
}
2006-01-24 10:15:03 +00:00
2009-11-02 03:00:28 +00:00
/**
2010-04-13 15:23:03 +00:00
* Returns HTML for a marker for required form elements .
2009-11-02 03:00:28 +00:00
*
* @ param $variables
* An associative array containing :
* - element : An associative array containing the properties of the element .
*
* @ ingroup themeable
*/
function theme_form_required_marker ( $variables ) {
$attributes = array (
'class' => 'form-required' ,
2013-12-02 03:41:57 +00:00
'aria-hidden' => 'true' ,
2009-11-02 03:00:28 +00:00
);
2013-12-02 03:41:57 +00:00
return '<span' . new Attribute ( $attributes ) . '>*</span>' ;
2009-11-02 03:00:28 +00:00
}
2009-12-02 15:09:16 +00:00
/**
2010-04-13 15:23:03 +00:00
* Returns HTML for a form element label and required marker .
2009-12-02 15:09:16 +00:00
*
* Form element labels include the #title and a #required marker. The label is
* associated with the element itself by the element #id. Labels may appear
2012-02-19 03:41:24 +00:00
* before or after elements , depending on theme_form_element () and
* #title_display.
2009-12-02 15:09:16 +00:00
*
* This function will not be called for elements with no labels , depending on
* #title_display. For elements that have an empty #title and are not required,
* this function will output no label ( '' ) . For required elements that have an
* empty #title, this will output the required marker alone within the label.
* The label will use the #id to associate the marker with the field that is
* required . That is especially important for screenreader users to know
* which field is required .
*
* @ param $variables
* An associative array containing :
* - element : An associative array containing the properties of the element .
* Properties used : #required, #title, #id, #value, #description.
*
* @ ingroup themeable
*/
function theme_form_element_label ( $variables ) {
$element = $variables [ 'element' ];
// If title and required marker are both empty, output no label.
2011-12-12 16:21:23 +00:00
if (( ! isset ( $element [ '#title' ]) || $element [ '#title' ] === '' ) && empty ( $element [ '#required' ])) {
2009-12-02 15:09:16 +00:00
return '' ;
}
// If the element is required, a required marker is appended to the label.
2014-02-07 04:01:25 +00:00
$required = '' ;
if ( ! empty ( $element [ '#required' ])) {
$marker = array (
'#theme' => 'form_required_marker' ,
'#element' => $element ,
);
$required = drupal_render ( $marker );
}
2009-12-02 15:09:16 +00:00
$title = filter_xss_admin ( $element [ '#title' ]);
$attributes = array ();
2010-04-07 04:39:59 +00:00
// Style the label as class option to display inline with the element.
2009-12-02 15:09:16 +00:00
if ( $element [ '#title_display' ] == 'after' ) {
$attributes [ 'class' ] = 'option' ;
}
2010-04-07 04:39:59 +00:00
// Show label only to screen readers to avoid disruption in visual flows.
elseif ( $element [ '#title_display' ] == 'invisible' ) {
2013-06-17 19:58:27 +00:00
$attributes [ 'class' ] = 'visually-hidden' ;
2010-04-07 04:39:59 +00:00
}
2009-12-02 15:09:16 +00:00
if ( ! empty ( $element [ '#id' ])) {
$attributes [ 'for' ] = $element [ '#id' ];
}
2013-06-17 13:35:07 +00:00
return '<label' . new Attribute ( $attributes ) . '>' . t ( '!title!required' , array ( '!title' => $title , '!required' => $required )) . '</label>' ;
2009-12-02 15:09:16 +00:00
}
2006-04-05 18:12:48 +00:00
/**
* Sets a form element ' s class attribute .
*
* Adds 'required' and 'error' classes as needed .
*
2011-05-08 19:50:38 +00:00
* @ param $element
2007-01-23 19:17:55 +00:00
* The form element .
2006-04-05 18:12:48 +00:00
* @ param $name
2007-01-23 19:17:55 +00:00
* Array of new class names to be added .
2006-04-05 18:12:48 +00:00
*/
2012-10-23 22:43:41 +00:00
function _form_set_attributes ( & $element , $class = array ()) {
2009-08-22 14:34:23 +00:00
if ( ! empty ( $class )) {
if ( ! isset ( $element [ '#attributes' ][ 'class' ])) {
$element [ '#attributes' ][ 'class' ] = array ();
}
$element [ '#attributes' ][ 'class' ] = array_merge ( $element [ '#attributes' ][ 'class' ], $class );
}
2010-09-16 20:14:49 +00:00
// This function is invoked from form element theme functions, but the
// rendered form element may not necessarily have been processed by
// form_builder().
if ( ! empty ( $element [ '#required' ])) {
2009-08-22 14:34:23 +00:00
$element [ '#attributes' ][ 'class' ][] = 'required' ;
2012-03-27 06:23:35 +00:00
$element [ '#attributes' ][ 'required' ] = 'required' ;
$element [ '#attributes' ][ 'aria-required' ] = 'true' ;
2006-04-05 18:12:48 +00:00
}
2013-11-23 20:57:04 +00:00
if ( isset ( $element [ '#parents' ]) && isset ( $element [ '#errors' ]) && ! empty ( $element [ '#validated' ])) {
2009-08-22 14:34:23 +00:00
$element [ '#attributes' ][ 'class' ][] = 'error' ;
2013-08-10 08:46:10 +00:00
$element [ '#attributes' ][ 'aria-invalid' ] = 'true' ;
2006-04-05 18:12:48 +00:00
}
2005-10-07 06:11:12 +00:00
}
/**
2008-01-21 15:17:01 +00:00
* @ } End of " defgroup form_api " .
2005-10-07 06:11:12 +00:00
*/
2007-05-04 09:41:37 +00:00
/**
* @ defgroup batch Batch operations
* @ {
2012-02-19 03:41:24 +00:00
* Creates and processes batch operations .
2011-01-03 18:03:54 +00:00
*
2007-05-04 09:41:37 +00:00
* Functions allowing forms processing to be spread out over several page
* requests , thus ensuring that the processing does not get interrupted
* because of a PHP timeout , while allowing the user to receive feedback
* on the progress of the ongoing operations .
*
* The API is primarily designed to integrate nicely with the Form API
2010-06-15 15:52:04 +00:00
* workflow , but can also be used by non - Form API scripts ( like update . php )
2007-05-04 09:41:37 +00:00
* or even simple page callbacks ( which should probably be used sparingly ) .
*
* Example :
* @ code
* $batch = array (
* 'title' => t ( 'Exporting' ),
* 'operations' => array (
2013-07-11 17:29:02 +00:00
* array ( 'my_function_1' , array ( $account -> id (), 'story' )),
2007-05-04 09:41:37 +00:00
* array ( 'my_function_2' , array ()),
* ),
* 'finished' => 'my_finished_callback' ,
2009-11-07 14:44:04 +00:00
* 'file' => 'path_to_file_containing_myfunctions' ,
2007-05-04 09:41:37 +00:00
* );
* batch_set ( $batch );
2011-07-28 19:29:53 +00:00
* // Only needed if not inside a form _submit handler.
* // Setting redirect in batch_process.
* batch_process ( 'node/1' );
2007-05-04 09:41:37 +00:00
* @ endcode
*
2009-11-07 14:44:04 +00:00
* Note : if the batch 'title' , 'init_message' , 'progress_message' , or
* 'error_message' could contain any user input , it is the responsibility of
2008-10-14 11:01:08 +00:00
* the code calling batch_set () to sanitize them first with a function like
2013-10-07 05:34:09 +00:00
* \Drupal\Component\Utility\String :: checkPlain () or filter_xss () . Furthermore ,
* if the batch operation returns any user input in the 'results' or 'message'
* keys of $context , it must also sanitize them first .
2008-10-14 11:01:08 +00:00
*
2014-02-13 00:46:08 +00:00
* Sample callback_batch_operation () :
2007-05-04 09:41:37 +00:00
* @ code
* // Simple and artificial: load a node of a given type for a given user
* function my_function_1 ( $uid , $type , & $context ) {
* // The $context array gathers batch context information about the execution (read),
* // as well as 'return values' for the current operation (write)
* // The following keys are provided :
* // 'results' (read / write): The array of results gathered so far by
2007-07-02 14:41:37 +00:00
* // the batch processing, for the current operation to append its own.
2007-05-04 09:41:37 +00:00
* // 'message' (write): A text message displayed in the progress page.
* // The following keys allow for multi-step operations :
* // 'sandbox' (read / write): An array that can be freely used to
* // store persistent data between iterations. It is recommended to
* // use this instead of $_SESSION, which is unsafe if the user
* // continues browsing in a separate window while the batch is processing.
* // 'finished' (write): A float number between 0 and 1 informing
* // the processing engine of the completion level for the operation.
2007-05-07 10:15:57 +00:00
* // 1 (or no value explicitly set) means the operation is finished
* // and the batch processing can continue to the next operation.
*
2012-08-21 15:38:04 +00:00
* $nodes = entity_load_multiple_by_properties ( 'node' , array ( 'uid' => $uid , 'type' => $type ));
* $node = reset ( $nodes );
2013-10-07 05:34:09 +00:00
* $context [ 'results' ][] = $node -> id () . ' : ' . String :: checkPlain ( $node -> label ());
* $context [ 'message' ] = String :: checkPlain ( $node -> label ());
2007-05-04 09:41:37 +00:00
* }
*
2013-05-26 20:18:10 +00:00
* // A more advanced example is a multi-step operation that loads all rows,
* // five by five.
2007-05-04 09:41:37 +00:00
* function my_function_2 ( & $context ) {
* if ( empty ( $context [ 'sandbox' ])) {
* $context [ 'sandbox' ][ 'progress' ] = 0 ;
2013-05-26 20:18:10 +00:00
* $context [ 'sandbox' ][ 'current_id' ] = 0 ;
* $context [ 'sandbox' ][ 'max' ] = db_query ( 'SELECT COUNT(DISTINCT id) FROM {example}' ) -> fetchField ();
2007-05-04 09:41:37 +00:00
* }
* $limit = 5 ;
2013-05-26 20:18:10 +00:00
* $result = db_select ( 'example' )
* -> fields ( 'example' , array ( 'id' ))
* -> condition ( 'id' , $context [ 'sandbox' ][ 'current_id' ], '>' )
* -> orderBy ( 'id' )
2009-03-14 16:27:58 +00:00
* -> range ( 0 , $limit )
* -> execute ();
* foreach ( $result as $row ) {
2013-11-06 02:12:47 +00:00
* $context [ 'results' ][] = $row -> id . ' : ' . String :: checkPlain ( $row -> title );
2007-05-04 09:41:37 +00:00
* $context [ 'sandbox' ][ 'progress' ] ++ ;
2013-05-26 20:18:10 +00:00
* $context [ 'sandbox' ][ 'current_id' ] = $row -> id ;
2013-11-06 02:12:47 +00:00
* $context [ 'message' ] = String :: checkPlain ( $row -> title );
2007-05-04 09:41:37 +00:00
* }
* if ( $context [ 'sandbox' ][ 'progress' ] != $context [ 'sandbox' ][ 'max' ]) {
* $context [ 'finished' ] = $context [ 'sandbox' ][ 'progress' ] / $context [ 'sandbox' ][ 'max' ];
* }
* }
* @ endcode
*
2014-02-13 00:46:08 +00:00
* Sample callback_batch_finished () :
2007-05-04 09:41:37 +00:00
* @ code
* function batch_test_finished ( $success , $results , $operations ) {
2011-06-01 08:39:51 +00:00
* // The 'success' parameter means no fatal PHP errors were detected. All
* // other error management should be handled using 'results'.
2007-05-04 09:41:37 +00:00
* if ( $success ) {
2007-11-12 19:06:33 +00:00
* $message = format_plural ( count ( $results ), 'One post processed.' , '@count posts processed.' );
2007-05-04 09:41:37 +00:00
* }
* else {
* $message = t ( 'Finished with an error.' );
* }
* drupal_set_message ( $message );
2007-07-02 14:41:37 +00:00
* // Providing data for the redirected page is done through $_SESSION.
2007-05-04 09:41:37 +00:00
* foreach ( $results as $result ) {
* $items [] = t ( 'Loaded node %title.' , array ( '%title' => $result ));
* }
2009-06-02 06:58:17 +00:00
* $_SESSION [ 'my_batch_results' ] = $items ;
2007-05-04 09:41:37 +00:00
* }
* @ endcode
*/
/**
2012-04-10 17:58:43 +00:00
* Adds a new batch .
*
* Batch operations are added as new batch sets . Batch sets are used to spread
* processing ( primarily , but not exclusively , forms processing ) over several
* page requests . This helps to ensure that the processing is not interrupted
* due to PHP timeouts , while users are still able to receive feedback on the
* progress of the ongoing operations . Combining related operations into
* distinct batch sets provides clean code independence for each batch set ,
* ensuring that two or more batches , submitted independently , can be processed
* without mutual interference . Each batch set may specify its own set of
* operations and results , produce its own UI messages , and trigger its own
* 'finished' callback . Batch sets are processed sequentially , with the progress
* bar starting afresh for each new set .
*
* @ param $batch_definition
* An associative array defining the batch , with the following elements ( all
* are optional except as noted ) :
2014-02-13 00:46:08 +00:00
* - operations : ( required ) Array of operations to be performed , where each
* item is an array consisting of the name of an implementation of
* callback_batch_operation () and an array of parameter .
2009-11-07 14:44:04 +00:00
* Example :
* @ code
* array (
2014-02-13 00:46:08 +00:00
* array ( 'callback_batch_operation_1' , array ( $arg1 )),
* array ( 'callback_batch_operation_2' , array ( $arg2_1 , $arg2_2 )),
2009-11-07 14:44:04 +00:00
* )
* @ endcode
2012-04-10 17:58:43 +00:00
* - title : A safe , translated string to use as the title for the progress
* page . Defaults to t ( 'Processing' ) .
* - init_message : Message displayed while the processing is initialized .
2009-11-07 14:44:04 +00:00
* Defaults to t ( 'Initializing.' ) .
2012-04-10 17:58:43 +00:00
* - progress_message : Message displayed while processing the batch . Available
* placeholders are @ current , @ remaining , @ total , @ percentage , @ estimate and
* @ elapsed . Defaults to t ( 'Completed @current of @total.' ) .
* - error_message : Message displayed if an error occurred while processing
2009-11-07 14:44:04 +00:00
* the batch . Defaults to t ( 'An error has occurred.' ) .
2014-02-13 00:46:08 +00:00
* - finished : Name of an implementation of callback_batch_finished () . This is
* executed after the batch has completed . This should be used to perform
* any result massaging that may be needed , and possibly save data in
* $_SESSION for display after final page redirection .
2012-04-10 17:58:43 +00:00
* - file : Path to the file containing the definitions of the 'operations' and
* 'finished' functions , for instance if they don ' t reside in the main
* . module file . The path should be relative to base_path (), and thus should
* be built using drupal_get_path () .
* - css : Array of paths to CSS files to be used on the progress page .
* - url_options : options passed to url () when constructing redirect URLs for
* the batch .
2007-05-04 09:41:37 +00:00
*/
function batch_set ( $batch_definition ) {
if ( $batch_definition ) {
$batch =& batch_get ();
2010-01-08 06:36:34 +00:00
// Initialize the batch if needed.
2007-05-04 09:41:37 +00:00
if ( empty ( $batch )) {
$batch = array (
'sets' => array (),
2010-01-08 06:36:34 +00:00
'has_form_submits' => FALSE ,
2007-05-04 09:41:37 +00:00
);
}
2010-01-08 06:36:34 +00:00
// Base and default properties for the batch set.
2007-05-04 09:41:37 +00:00
$init = array (
'sandbox' => array (),
'results' => array (),
'success' => FALSE ,
2010-01-08 06:36:34 +00:00
'start' => 0 ,
2009-01-12 06:23:57 +00:00
'elapsed' => 0 ,
2007-05-04 09:41:37 +00:00
);
$defaults = array (
2013-06-17 13:35:07 +00:00
'title' => t ( 'Processing' ),
'init_message' => t ( 'Initializing.' ),
'progress_message' => t ( 'Completed @current of @total.' ),
'error_message' => t ( 'An error has occurred.' ),
2008-06-24 21:51:03 +00:00
'css' => array (),
2007-05-04 09:41:37 +00:00
);
$batch_set = $init + $batch_definition + $defaults ;
2010-01-08 06:36:34 +00:00
// Tweak init_message to avoid the bottom of the page flickering down after
// init phase.
2007-05-04 09:41:37 +00:00
$batch_set [ 'init_message' ] .= '<br/> ' ;
2010-01-08 06:36:34 +00:00
// The non-concurrent workflow of batch execution allows us to save
// numberOfItems() queries by handling our own counter.
2007-05-04 09:41:37 +00:00
$batch_set [ 'total' ] = count ( $batch_set [ 'operations' ]);
2010-01-08 06:36:34 +00:00
$batch_set [ 'count' ] = $batch_set [ 'total' ];
2007-05-04 09:41:37 +00:00
2010-01-08 06:36:34 +00:00
// Add the set to the batch.
if ( empty ( $batch [ 'id' ])) {
// The batch is not running yet. Simply add the new set.
$batch [ 'sets' ][] = $batch_set ;
2007-05-04 09:41:37 +00:00
}
else {
2010-01-08 06:36:34 +00:00
// The set is being added while the batch is running. Insert the new set
// right after the current one to ensure execution order, and store its
// operations in a queue.
$index = $batch [ 'current_set' ] + 1 ;
$slice1 = array_slice ( $batch [ 'sets' ], 0 , $index );
$slice2 = array_slice ( $batch [ 'sets' ], $index );
$batch [ 'sets' ] = array_merge ( $slice1 , array ( $batch_set ), $slice2 );
_batch_populate_queue ( $batch , $index );
2007-05-04 09:41:37 +00:00
}
}
}
/**
2009-11-07 14:44:04 +00:00
* Processes the batch .
2007-05-06 05:47:52 +00:00
*
2008-10-15 14:17:27 +00:00
* This function is generally not needed in form submit handlers ;
* Form API takes care of batches that were set during form submission .
2007-05-04 09:41:37 +00:00
*
* @ param $redirect
* ( optional ) Path to redirect to when the batch has finished processing .
* @ param $url
2007-07-02 14:41:37 +00:00
* ( optional - should only be used for separate scripts like update . php )
2007-05-04 09:41:37 +00:00
* URL of the batch processing page .
2009-10-03 20:17:46 +00:00
* @ param $redirect_callback
* ( optional ) Specify a function to be called to redirect to the progressive
Issue #1668866 by ParisLiakos, aspilicious, tim.plunkett, pdrake, g.oechsler, dawehner, Berdir, corvus_ch, damiankloip, disasm, marcingy, neclimdul: Replace drupal_goto() with RedirectResponse.
2013-06-19 16:07:30 +00:00
* processing page .
*
* @ return \Symfony\Component\HttpFoundation\RedirectResponse | null
* A redirect response if the batch is progressive . No return value otherwise .
2007-05-04 09:41:37 +00:00
*/
Issue #1668866 by ParisLiakos, aspilicious, tim.plunkett, pdrake, g.oechsler, dawehner, Berdir, corvus_ch, damiankloip, disasm, marcingy, neclimdul: Replace drupal_goto() with RedirectResponse.
2013-06-19 16:07:30 +00:00
function batch_process ( $redirect = NULL , $url = 'batch' , $redirect_callback = NULL ) {
2007-05-04 09:41:37 +00:00
$batch =& batch_get ();
2009-09-11 04:09:26 +00:00
drupal_theme_initialize ();
2010-01-02 23:30:53 +00:00
2007-05-04 09:41:37 +00:00
if ( isset ( $batch )) {
// Add process information
$process_info = array (
'current_set' => 0 ,
'progressive' => TRUE ,
2009-10-03 20:17:46 +00:00
'url' => $url ,
2009-10-27 04:12:39 +00:00
'url_options' => array (),
2012-04-29 15:16:27 +00:00
'source_url' => current_path (),
2007-05-04 09:41:37 +00:00
'redirect' => $redirect ,
2009-09-11 04:09:26 +00:00
'theme' => $GLOBALS [ 'theme_key' ],
2009-10-03 20:17:46 +00:00
'redirect_callback' => $redirect_callback ,
2007-05-04 09:41:37 +00:00
);
$batch += $process_info ;
2010-01-08 06:36:34 +00:00
// The batch is now completely built. Allow other modules to make changes
// to the batch so that it is easier to reuse batch processes in other
2010-01-25 10:38:35 +00:00
// environments.
2009-10-03 20:17:46 +00:00
drupal_alter ( 'batch' , $batch );
2010-01-08 06:36:34 +00:00
// Assign an arbitrary id: don't rely on a serial column in the 'batch'
// table, since non-progressive batches skip database storage completely.
$batch [ 'id' ] = db_next_id ();
// Move operations to a job queue. Non-progressive batches will use a
// memory-based queue.
foreach ( $batch [ 'sets' ] as $key => $batch_set ) {
_batch_populate_queue ( $batch , $key );
}
// Initiate processing.
2007-05-04 09:41:37 +00:00
if ( $batch [ 'progressive' ]) {
2010-01-08 06:36:34 +00:00
// Now that we have a batch id, we can generate the redirection link in
// the generic error message.
2013-06-17 13:35:07 +00:00
$batch [ 'error_message' ] = t ( 'Please continue to <a href="@error_url">the error page</a>' , array ( '@error_url' => url ( $url , array ( 'query' => array ( 'id' => $batch [ 'id' ], 'op' => 'finished' )))));
2010-01-08 06:36:34 +00:00
Issue #1668866 by ParisLiakos, aspilicious, tim.plunkett, pdrake, g.oechsler, dawehner, Berdir, corvus_ch, damiankloip, disasm, marcingy, neclimdul: Replace drupal_goto() with RedirectResponse.
2013-06-19 16:07:30 +00:00
// Clear the way for the redirection to the batch processing page, by
// saving and unsetting the 'destination', if there is any.
2013-09-16 03:58:06 +00:00
$request = \Drupal :: request ();
Issue #1668866 by ParisLiakos, aspilicious, tim.plunkett, pdrake, g.oechsler, dawehner, Berdir, corvus_ch, damiankloip, disasm, marcingy, neclimdul: Replace drupal_goto() with RedirectResponse.
2013-06-19 16:07:30 +00:00
if ( $request -> query -> has ( 'destination' )) {
$batch [ 'destination' ] = $request -> query -> get ( 'destination' );
$request -> query -> remove ( 'destination' );
2007-05-04 09:41:37 +00:00
}
2007-07-20 05:44:13 +00:00
2010-01-08 06:36:34 +00:00
// Store the batch.
2013-09-16 03:58:06 +00:00
\Drupal :: service ( 'batch.storage' ) -> create ( $batch );
2007-07-20 05:44:13 +00:00
2009-06-02 06:58:17 +00:00
// Set the batch number in the session to guarantee that it will stay alive.
$_SESSION [ 'batches' ][ $batch [ 'id' ]] = TRUE ;
2010-01-08 06:36:34 +00:00
// Redirect for processing.
Issue #1668866 by ParisLiakos, aspilicious, tim.plunkett, pdrake, g.oechsler, dawehner, Berdir, corvus_ch, damiankloip, disasm, marcingy, neclimdul: Replace drupal_goto() with RedirectResponse.
2013-06-19 16:07:30 +00:00
$options = array ( 'query' => array ( 'op' => 'start' , 'id' => $batch [ 'id' ]));
if (( $function = $batch [ 'redirect_callback' ]) && function_exists ( $function )) {
$function ( $batch [ 'url' ], $options );
}
else {
$options [ 'absolute' ] = TRUE ;
return new RedirectResponse ( url ( $batch [ 'url' ], $options ));
}
2007-05-04 09:41:37 +00:00
}
else {
// Non-progressive execution: bypass the whole progressbar workflow
// and execute the batch in one pass.
2013-05-09 09:25:10 +00:00
require_once __DIR__ . '/batch.inc' ;
2007-05-04 09:41:37 +00:00
_batch_process ();
}
}
}
/**
2009-11-07 14:44:04 +00:00
* Retrieves the current batch .
2007-05-04 09:41:37 +00:00
*/
function & batch_get () {
2009-11-21 14:06:46 +00:00
// Not drupal_static(), because Batch API operates at a lower level than most
// use-cases for resetting static variables, and we specifically do not want a
// global drupal_static_reset() resetting the batch information. Functions
// that are part of the Batch API and need to reset the batch information may
// call batch_get() and manipulate the result by reference. Functions that are
// not part of the Batch API can also do this, but shouldn't.
static $batch = array ();
2007-05-04 09:41:37 +00:00
return $batch ;
}
2010-01-08 06:36:34 +00:00
/**
* Populates a job queue with the operations of a batch set .
*
2012-03-12 03:07:39 +00:00
* Depending on whether the batch is progressive or not , the
* Drupal\Core\Queue\Batch or Drupal\Core\Queue\BatchMemory handler classes will
* be used .
2010-01-08 06:36:34 +00:00
*
* @ param $batch
* The batch array .
* @ param $set_id
* The id of the set to process .
2012-02-19 03:41:24 +00:00
*
2010-01-08 06:36:34 +00:00
* @ return
* The name and class of the queue are added by reference to the batch set .
*/
function _batch_populate_queue ( & $batch , $set_id ) {
$batch_set = & $batch [ 'sets' ][ $set_id ];
if ( isset ( $batch_set [ 'operations' ])) {
$batch_set += array (
'queue' => array (
'name' => 'drupal_batch:' . $batch [ 'id' ] . ':' . $set_id ,
2012-03-12 03:07:39 +00:00
'class' => $batch [ 'progressive' ] ? 'Drupal\Core\Queue\Batch' : 'Drupal\Core\Queue\BatchMemory' ,
2010-01-08 06:36:34 +00:00
),
);
$queue = _batch_queue ( $batch_set );
$queue -> createQueue ();
foreach ( $batch_set [ 'operations' ] as $operation ) {
$queue -> createItem ( $operation );
}
unset ( $batch_set [ 'operations' ]);
}
}
/**
* Returns a queue object for a batch set .
*
* @ param $batch_set
* The batch set .
2012-02-19 03:41:24 +00:00
*
2010-01-08 06:36:34 +00:00
* @ return
* The queue object .
*/
function _batch_queue ( $batch_set ) {
static $queues ;
2010-09-26 23:31:36 +00:00
if ( ! isset ( $queues )) {
2010-01-08 06:36:34 +00:00
$queues = array ();
}
if ( isset ( $batch_set [ 'queue' ])) {
$name = $batch_set [ 'queue' ][ 'name' ];
$class = $batch_set [ 'queue' ][ 'class' ];
if ( ! isset ( $queues [ $class ][ $name ])) {
2013-01-15 15:35:31 +00:00
$queues [ $class ][ $name ] = new $class ( $name , Database :: getConnection ());
2010-01-08 06:36:34 +00:00
}
return $queues [ $class ][ $name ];
}
}
2007-05-04 09:41:37 +00:00
/**
* @ } End of " defgroup batch " .
*/