<commit_before>Using Form Builder
==================

When creating HTML forms, we often find that we are writing a lot of repetitive view code
which is difficult to be reused in a different project. For example, for every
input field, we need to associate it with a text label and display possible validation errors.
To improve the reusability of these code, we can use the form builder feature which has
been available since Yii version 1.1.0.


Basic Concepts
--------------

The Yii form builder uses a [CForm] object to represent the specifications needed to describe
an HTML form, including which data models are associated with the form,
what kind of input fields there are in the form, and how to render the whole form. Developers mainly
need to create and configure this [CForm] object, and then call its rendering method to display
the form.

Form input specifications are organized in terms of a form element hierarchy.
At the root of the hierarchy, it is the [CForm] object. The root form object maintains
its children in two collections: [CForm::buttons] and [CForm::elements]. The former
contains the button elements (such as submit buttons, reset buttons), while the latter
contains the input elements, static text and sub-forms. A sub-form is a [CForm] object contained
in the [CForm::elements] collection of another form. It can have its own data model,
[CForm::buttons] and [CForm::elements] collections.

When users submit a form, the data entered into the input fields of the whole form hierarchy are submitted,
including those input fields that belong to the sub-forms. [CForm] provides convenient methods
that can automatically assign the input data to the corresponding model attributes and perform
data validation.


Creating a Simple Form
----------------------

In the following, we show how to use the form builder to create a login form.

First, we write the login action code:

~~~
[php]
public function actionLogin()
{
	$model = new LoginForm;
	$form = new CForm('application.views.site.loginForm', $model);
	if($form->submitted('login') && $form->validate())
		$this->redirect(array('site/index'));
	else
		$this->render('login', array('form'=>$form));
}
~~~

In the above code, we create a [CForm] object using the specifications pointed to
by the path alias `application.views.site.loginForm` (to be explained shortly).
The [CForm] object is associated with the `LoginForm` model as described in
[Creating Model](/doc/guide/form.model).

As the code reads, if the form is submitted and all inputs are validated without
any error, we would redirect the user browser to the `site/index` page. Otherwise,
we render the `login` view with the form.

The path alias `application.views.site.loginForm` actually refers to the PHP file
`protected/views/site/loginForm.php`. The file should return a PHP array representing
the configuration needed by [CForm], as shown in the following:

~~~
[php]
return array(
	'title'=>'Please provide your login credential',

    'elements'=>array(
        'username'=>array(
            'type'=>'text',
            'maxlength'=>32,
        ),
        'password'=>array(
            'type'=>'password',
            'maxlength'=>32,
        ),
        'rememberMe'=>array(
            'type'=>'checkbox',
        )
    ),

    'buttons'=>array(
        'login'=>array(
            'type'=>'submit',
            'label'=>'Login',
        ),
    ),
);
~~~

The configuration is an associative array consisting of name-value pairs that are
used to initialize the corresponding properties of [CForm]. The most important properties
to configure, as we aformentioned, are [CForm::elements] and [CForm::buttons]. Each
of them takes an array specifying a list of form elements. We will give more details on
how to configure form elements in the next sub-section.

Finally, we write the `login` view script, which can be as simple as follows,

~~~
[php]
<h1>Login</h1>

<div class="form">
<?php echo $form; ?>
</div>
~~~

> Tip: The above code `echo $form;` is equivalent to `echo $form->render();`.
> This is because [CForm] implements `__toString` magic method which calls
> `render()` and returns its result as the string representation of the form object.


Specifying Form Elements
------------------------

Using the form builder, the majority of our effort is shifted from writing view script code
to specifying the form elements. In this sub-section, we describe how to specify the [CForm::elements]
property. We are not going to describe [CForm::buttons] because its configuration is nearly
the same as [CForm::elements].

The [CForm::elements] property accepts an array as its value. Each array element specifies a single
form element which can be an input element, a static text string or a sub-form.

### Specifying Input Element

An input element mainly consists of a label, an input field, a hint text and an error display.
It must be associated with a model attribute. The specification for an input element is represented
as a [CFormInputElement] instance. The following code in the [CForm::elements] array
specifies a single input element:

~~~
[php]
'username'=>array(
    'type'=>'text',
    'maxlength'=>32,
),
~~~

It states that the model attribute is named as `username`, and the input field type is `text` whose
`maxlength` attribute is 32. We can specify other options in the above array as long as they are writable
properties of [CFormInputElement]. For example, we may specify the [hint|CFormInputElement::hint] option
in order to display a hint text, or we may specify the [items|CFormInputElement::items] option if
the input field is a list box, a drop-down list, a check-box list or a radio-button list.

The [type|CFormInputElement::type] option deserves additional attention. It specifies the type of the input
field to be rendered. For example, the `text` type means a normal text input field should be rendered;
the `password` type means a password input field should be rendered. [CFormInputElement] recognizes the following
built-in types:

 - text
 - hidden
 - password
 - textarea
 - file
 - radio
 - checkbox
 - listbox
 - dropdownlist
 - checkboxlist
 - radiolist

Besides these built-in types, the [type|CFormInputElement::type] option can also take a widget class name
or the path alias to it. The widget class must extend from [CInputWidget]. When rendering the input element,
an instance of the specified widget class will be created and rendered. The widget will be configured using
the specification as given for the input element.


### Specifying Static Text

In many cases, a form may contain some decorational HTML code besides the input fields. For example, a horizontal
line may be needed to separate different portions of the form; an image may be needed at certain places to
enhance the visual appearance of the form. We may specify these HTML code as static text in the [CForm::elements]
collection. To do so, we simply specify a static text string as an array element in the appropriate position in
[CForm::elements]. For example,

~~~<commit_msg>(Fixes issue 1472)<commit_after>Using Form Builder
==================

When creating HTML forms, we often find that we are writing a lot of repetitive view code
which is difficult to be reused in a different project. For example, for every
input field, we need to associate it with a text label and display possible validation errors.
To improve the reusability of these code, we can use the form builder feature which has
been available since Yii version 1.1.0.


Basic Concepts
--------------

The Yii form builder uses a [CForm] object to represent the specifications needed to describe
an HTML form, including which data models are associated with the form,
what kind of input fields there are in the form, and how to render the whole form. Developers mainly
need to create and configure this [CForm] object, and then call its rendering method to display
the form.

Form input specifications are organized in terms of a form element hierarchy.
At the root of the hierarchy, it is the [CForm] object. The root form object maintains
its children in two collections: [CForm::buttons] and [CForm::elements]. The former
contains the button elements (such as submit buttons, reset buttons), while the latter
contains the input elements, static text and sub-forms. A sub-form is a [CForm] object contained
in the [CForm::elements] collection of another form. It can have its own data model,
[CForm::buttons] and [CForm::elements] collections.

When users submit a form, the data entered into the input fields of the whole form hierarchy are submitted,
including those input fields that belong to the sub-forms. [CForm] provides convenient methods
that can automatically assign the input data to the corresponding model attributes and perform
data validation.


Creating a Simple Form
----------------------

In the following, we show how to use the form builder to create a login form.

First, we write the login action code:

~~~
[php]
public function actionLogin()
{
	$model = new LoginForm;
	$form = new CForm('application.views.site.loginForm', $model);
	if($form->submitted('login') && $form->validate())
		$this->redirect(array('site/index'));
	else
		$this->render('login', array('form'=>$form));
}
~~~

In the above code, we create a [CForm] object using the specifications pointed to
by the path alias `application.views.site.loginForm` (to be explained shortly).
The [CForm] object is associated with the `LoginForm` model as described in
[Creating Model](/doc/guide/form.model).

As the code reads, if the form is submitted and all inputs are validated without
any error, we would redirect the user browser to the `site/index` page. Otherwise,
we render the `login` view with the form.

The path alias `application.views.site.loginForm` actually refers to the PHP file
`protected/views/site/loginForm.php`. The file should return a PHP array representing
the configuration needed by [CForm], as shown in the following:

~~~
[php]
return array(
	'title'=>'Please provide your login credential',

    'elements'=>array(
        'username'=>array(
            'type'=>'text',
            'maxlength'=>32,
        ),
        'password'=>array(
            'type'=>'password',
            'maxlength'=>32,
        ),
        'rememberMe'=>array(
            'type'=>'checkbox',
        )
    ),

    'buttons'=>array(
        'login'=>array(
            'type'=>'submit',
            'label'=>'Login',
        ),
    ),
);
~~~

The configuration is an associative array consisting of name-value pairs that are
used to initialize the corresponding properties of [CForm]. The most important properties
to configure, as we aformentioned, are [CForm::elements] and [CForm::buttons]. Each
of them takes an array specifying a list of form elements. We will give more details on
how to configure form elements in the next sub-section.

Finally, we write the `login` view script, which can be as simple as follows,

~~~
[php]
<h1>Login</h1>

<div class="form">
<?php echo $form; ?>
</div>
~~~

> Tip: The above code `echo $form;` is equivalent to `echo $form->render();`.
> This is because [CForm] implements `__toString` magic method which calls
> `render()` and returns its result as the string representation of the form object.


Specifying Form Elements
------------------------

Using the form builder, the majority of our effort is shifted from writing view script code
to specifying the form elements. In this sub-section, we describe how to specify the [CForm::elements]
property. We are not going to describe [CForm::buttons] because its configuration is nearly
the same as [CForm::elements].

The [CForm::elements] property accepts an array as its value. Each array element specifies a single
form element which can be an input element, a static text string or a sub-form.

### Specifying Input Element

An input element mainly consists of a label, an input field, a hint text and an error display.
It must be associated with a model attribute. The specification for an input element is represented
as a [CFormInputElement] instance. The following code in the [CForm::elements] array
specifies a single input element:

~~~
[php]
'username'=>array(
    'type'=>'text',
    'maxlength'=>32,
),
~~~

It states that the model attribute is named as `username`, and the input field type is `text` whose
`maxlength` attribute is 32. We can specify other options in the above array as long as they are writable
properties of [CFormInputElement]. For example, we may specify the [hint|CFormInputElement::hint] option
in order to display a hint text, or we may specify the [items|CFormInputElement::items] option if
the input field is a list box, a drop-down list, a check-box list or a radio-button list.

The [type|CFormInputElement::type] option deserves additional attention. It specifies the type of the input
field to be rendered. For example, the `text` type means a normal text input field should be rendered;
the `password` type means a password input field should be rendered. [CFormInputElement] recognizes the following
built-in types:

 - text
 - hidden
 - password
 - textarea
 - file
 - radio
 - checkbox
 - listbox
 - dropdownlist
 - checkboxlist
 - radiolist

Besides these built-in types, the [type|CFormInputElement::type] option can also take a widget class name
or the path alias to it. The widget class must extend from [CInputWidget] or [CJuiInputWidget]. When rendering the input element,
an instance of the specified widget class will be created and rendered. The widget will be configured using
the specification as given for the input element.


### Specifying Static Text

In many cases, a form may contain some decorational HTML code besides the input fields. For example, a horizontal
line may be needed to separate different portions of the form; an image may be needed at certain places to
enhance the visual appearance of the form. We may specify these HTML code as static text in the [CForm::elements]
collection. To do so, we simply specify a static text string as an array element in the appropriate position in
[CForm::elements]. For example,

~~~
{'fraction_non_alphanumeric': 0.08716569973114476, 'fraction_numerical': 0.0021225413895570966, 'mean_word_length': 4.035625222657641, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 65, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1850851', 'n_tokens_mistral': 3619, 'n_tokens_neox': 3518, 'n_words': 1948}