Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Apress.Pro.Drupal.7.Development.3rd.Edition.Dec.2010.pdf
Скачиваний:
63
Добавлен:
14.03.2016
Размер:
12.64 Mб
Скачать

CHAPTER 11 THE FORM API

//Optionally stash a value in the form that the validator will need

//by creating a unique key in the form.

$form['#value_for_foo_validate'] = 'baz';

If there is no property named #validate in the form, the next step is to look for a function with the name of the form ID plus _validate. So if the form ID is user_register, the form’s #validate property will be set to user_register_validate.

Looking for a Submit Function

The function that handles form submission can be assigned by setting the #submit property in the form to an array with the name of the function that will handle form submission:

//Call my_special_submit_function() on form submission. $form['#submit'][] = 'my_special_submit_function';

//Also call my_second_submit_function().

$form['#submit'][] = 'my_second_submit_function';

If there is no property named #submit, Drupal tests to see if a function named with the form ID plus _submit exists. So if the form ID is user_register, Drupal sets the #submit property to the form processor function it found—that is, user_register_submit.

Allowing Modules to Alter the Form Before It’s Built

Before building the form, modules have two chances to alter the form. Modules can implement a function named from the form_id plus _alter, or they may simply implement hook_form_alter(). Any module that implements either of these can modify anything in the form. This is the primary way to change, override, and munge forms that are created by modules other than your own.

Building the Form

The form is now passed to form_builder(), which processes through the form tree recursively and adds standard required values. This function also checks the #access key for each element and denies access to form elements and their children if #access is FALSE for the element.

Allowing Functions to Alter the Form After It’s Built

Each time form_builder() encounters a new branch in the $form tree (for example, a new fieldset or form element), it looks for a property called #after_build. This is an optional array of functions to be called once the current form element has been built. When the entire form has been built, a final call is made to the optional functions whose names may be defined in $form['#after_build']. All #after_build functions receive $form and $form_state as parameters. An example of its use in core is during the display of the file system path at Configuration -> File system. An #after_build function (in this case system_check_directory()) runs to determine if the directory does not exist or is not writable and sets an error against the form element if problems are encountered.

243

CHAPTER 11 THE FORM API

Checking If the Form Has Been Submitted

If you’ve been following along in Figure 11-1, you’ll see that we have come to a branch point. If the form is being displayed for the first time, Drupal will go on to create the HTML for the form. If the form is being submitted, Drupal will go on to process the data that was entered in the form; we’ll come back to that case in a moment (see the “Validating the Form” section later in the chapter). We’ll assume for now the form is being displayed for the first time. It is important to realize that Drupal does all of the work described previously both when a form is being displayed for the first time and when a form is being submitted.

Finding a Theme Function for the Form

If $form['#theme'] has been set to an existing function, Drupal simply uses that function to theme the form. If not, the theme registry is checked for an entry that corresponds with the form ID of this form. If such an entry is found, the form ID is assigned to $form['#theme'], so later when Drupal renders the form, it will look for a theme function based on the form ID. For example, if the form ID is taxonomy_overview_terms, Drupal will call the corresponding theme function theme_taxonomy_overview_terms(). Of course, that theme function could be overridden by a theme function or template file in a custom theme; see Chapter 8 for details on how themable items are themed.

Allowing Modules to Modify the Form Before It’s Rendered

The only thing left to do is to transform the form from a data structure to HTML. But just before that happens, modules have a last chance to tweak things. This can be useful for multipage form wizards or other approaches that need to modify the form at the last minute. Any function defined in the $form['#pre_render'] property is called and passed the form being rendered.

Rendering the Form

To convert the form tree from a nested array to HTML code, the form builder calls drupal_render(). This recursive function goes through each level of the form tree, and with each, it performs the following actions:

1.Determine if the #children element has been defined (synonymous with content having been generated for this element); if not, render the children of this tree node as follows:

Determine if a #theme function has been defined for this element.

If so, temporarily set the #type of this element to markup. Next, pass this element to the #theme function, and reset the element back to what it was.

If no content was generated (either because no #theme function was defined for this element or because the call to the #theme function was not found in the theme registry or returned nothing), each of the children of this element is rendered in turn (i.e., by passing the child element to drupal_render()).

244

CHAPTER 11 THE FORM API

On the other hand, if content was generated by the #theme function, store the content in the #children property of this element.

2.If the element itself has not yet been rendered, call the default theme function for the #type of this element. For example, if this element is a text field in a form (i.e., the #type property has been set to textfield in the form definition), the default theme function will be theme_textfield(). If the #type of this element has not been set, default to markup. Default theme functions for core elements such as text fields are found in includes/form.inc.

3.If content was generated for this element and one or more function names are found in the #post_render property, call each of them, and pass the content and the element. The #post_render function(s) must return the final content.

4.Prepend #prefix and append #suffix to the content, and return it from the function.

The effect of this recursive iteration is that HTML is generated for every level of the form tree. For example, in a form with a fieldset with two fields, the #children element of the fieldset will contain HTML for the fields inside it, and the #children element of the form will contain all of the HTML for the form (including the fieldset’s HTML).

This generated array, ready to be rendered, is then returned to the caller of drupal_get_form(). That’s all it takes! We’ve reached the “Return HTML” endpoint in Figure 11-1.

Validating the Form

Now let’s go back in Figure 11-1, to the place where we branched off in the section “Checking If the Form Has Been Submitted.” Let’s assume that the form has been submitted and contains some data; we’ll take the other branch and look at that case. Drupal’s form processing engine determines whether a form has been submitted based on $_POST being nonempty and the presence of a string value in $_POST['form_id'] that matches the ID of the form definition that was just built (see the “Setting an ID” section). When a match is found, Drupal validates the form.

The purpose of validation is to check that the values that are being submitted are reasonable. Validation will either pass or fail. If validation fails at any point, the form will be redisplayed with the validation errors shown to the user. If all validation passes, Drupal will move on to the actual processing of the submitted values.

Token Validation

The first check in validation is to determine whether this form uses Drupal’s token mechanism (see the “Setting a Token” section). All Drupal forms that use tokens have a unique token that is sent out with the form and expected to be submitted along with other form values. If the token in the submitted data does not match the token that was set when the form was built, or if the token is absent, validation fails (though the rest of validation is still carried out so that other validation errors can also be flagged).

245

CHAPTER 11 THE FORM API

Built-In Validation

Next, required fields are checked to see if the user left them empty. Fields with a #maxlength property are checked to make sure the maximum number of characters has not been exceeded. Elements with options (check boxes, radio buttons, and drop-down selection fields) are examined to see if the selected value is actually in the original list of options present when the form was built.

Element-Specific Validation

If there is an #element_validate property defined for an individual form element, the functions defined in the property are called and passed the $form_state and $element.

Validation Callbacks

Finally, the form ID and form values are handed over to the validation function(s) specified for the form (usually the name of the form ID plus _validate).

Submitting the Form

If validation passes, it’s time to pass the form and its values to a function that will finally do something as a result of the form’s submission. Actually, more than one function could process the form, since the #submit property can contain an array of function names. Each function is called and passed $form and $form_state.

Redirecting the User

The function that processes the form should set $form_state['redirect'] to a Drupal path to which the user will be redirected, such as node/1234. If there are multiple functions in the #submit property, the last function to set $form_state['redirect'] will win. If no function sets $form_state['redirect'] to a Drupal path, the user is returned to the same page (that is, the value of $_GET['q']).

The redirect set in $form_state['redirect'] by a submit function can be overridden by defining a value such as

$form_state['redirect'] = 'node/1'

or

$form_state['redirect'] = array('node/1', $query_string, $named_anchor)

Using the parameter terms used in drupal_goto(), the last example could be rewritten as follows: $form_state['redirect'] = array('node/1', $query, 302)

Determination of form redirection is carried out by drupal_redirect_form() in includes/form.inc. The actual redirection is carried out by drupal_goto(), which returns a Location header to the web server. The parameters that drupal_goto() takes correspond to the members of the array in the latter example: drupal_goto($path = '', $options = array(), $http_response_code = 302).

246

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]