Now we will see the creation and working of basic forms in Yii. We will use the Gii tool to automatically generate CRUD operations and a form.
Yii creates some new files and folders, as follows:
protected/models/User.php
: This is a model class file. It deals with database-related tasks such as fetching and storing data, updating, and deleting. The User
class is extended from the base class CActiveRecord
.
protected/controllers/UserController.php
: This is a controller class extended from the base class Controller
. This class holds all the code for fetching data using models, data manipulation according to requirements, and sending data to the respective views.
protected/views/user
: This folder holds views for all CRUD operations; names starting with _
are partial views that are used in multiple places. The remaining files are views for their respective action names in UserController.php
.
Let's take a look at the generated controller
file. Change access rules to enable any user to access our form as follows:
All we need to do is add actionCreate()
to the actions that all users can access.
Now move to actionCreate()
. This is the action when we access the form with the URL ?r=user/create
. At the first line of actionCreate
, we instantiate the User
model. As the POST
variables are not set, the if
block is skipped and the form is rendered with the view file create
, with model
passed to it as a parameter.
In the view of create.php
, we simply render the partial view with the following lines:
This uses the file _form.php
, which contains all the form elements and passes to it the model that we received from actionCreate
. As we need the same form elements in actionCreate
and actionUpdate
, Yii has created a single file, _form.php
, that contains all the form elements. This file is used by both the actions to render the form.
In _form.php
, we start with creating an instance of the CActiveForm
widget.
The HTML code in the following screenshot is created by this widget:
Next we create a space to render error details, if any, with following line:
This adds a DIV
element to the page if there are any errors in the form fields.
Next we render all necessary input elements as follows:
The HTML code generated can be seen in the following screenshot:
The $form->labelEx()
method renders the label. It takes the parameter name from the model's attributeLabels
function. If no label is set for this attribute, the attribute name is used as the label.
The $form->textField()
method renders the actual form field. We use textField
for input with the type set to text
; dropDownList
to select boxes, textArea
to render text areas, hiddenField
to render hidden fields respectively.
Note
Look at the name of the input field. It has the format User[last_name]
; this enables us to get all related form fields in a single User
array, which can be directly assigned to the models' attributes with a single line of code, $model->attributes = $_POST['User']
, thereby reducing the number of lines of code.
The $form->error()
method adds error messages in a separate div
element if there is any error with the data in this field.
Finally, we have added a submit button with the echo CHtml::submitButton('Create')
. It creates an input element with type set to submit
and is attached to the parent form by default. We can end the form widget with $this->endWidget();
.
When the user clicks on the create button, the form data is submitted to the same actionCreate
function as POST
data.
Now as the $_POST['User']
field is set, the code enters the if
block. We assign all attributes marked as safe
in the User
variable of type POST
to model with $model->attributes = $_POST['User']
. This is called Mass Assignment.
Then on the next line, we save the model with $model->save()
. The method save()
internally validates the model to check if the user has entered the valid data. Here, the rules specified in the method rules under the User
model are used to validate the form data.
public function rules()
{
return array(
array(
'first_name, last_name, gender, dob, address_1,
city, state, country, phone_number_1, email_1,
created', 'required'
),
array(
'first_name, last_name, city, state, country,
phone_number_1, phone_number_2',
'length', 'max'=>50
),
array('gender', 'length', 'max'=>6),
array(
'address_1, address_2, email_1, email_2',
'length', 'max'=>255
),
array('modified, dob', 'safe'),
array(
'id, first_name, last_name, gender, dob, address_1,
address_2, city, state, country, phone_number_1,
phone_number_2, email_1, email_2, created,
modified', 'safe', 'on'=>'search'
),
);
}
In the first array, we specify all the required fields; in the next three arrays, we set the maximum length of data for each field. In the fourth array, additionally, we mark the attributes dob
and modified
as safe
. We also make several attributes as safe
when the scenario is set to search
.
If the validation is successful, the form data is persisted to the database and the page is redirected to the action view
, which displays all the captured data.
If the validation fails, the same model is passed to the view but now with the respective validation errors set in it. The line $form->errorSummary($model)
renders the summary of all errors in the form and the line $form->error()
adds the error line below the respective fields.