Creating Forms with the Yii Framework

January 20, 2011
The Yii Book If you like my writing on the Yii framework, you'll love "The Yii Book"!

HTML forms are one of the key pieces of any Web site, providing an easy way to get data from the user. But, as is the case with many things, creating forms while using a framework such as Yii is significantly different than creating forms using standard HTML alone. In this post, you’ll learn what you need to know to get started creating HTML forms when using the Yii framework.

Before getting into the code, let’s take a minute to think about the MVC architecture. A form itself is found in the View, as a form is part of the user interface. More specifically, when Yii auto-generates a form as part of CRUD creation, the framework writes the form in a file named _form.php. This file in turn gets included by other View files (any View file in Yii that starts with an underscore is intended to be an include). Also understand that the same _form.php file is intended to be used whether the form is for creating new records or updating existing ones. Naturally, the Controller dictates which primary View file gets rendered.

Forms, though, are associated with specific Models. A contact form may have its own Model, not tied to a database table (in which case the Model extends CFormModel), whereas a form for employees or departments will be based upon a Model that is tied to a database table (in which case the Model extends CActiveRecord, most likely). Whether the Model extends CFormModel or CActiveRecord, the important thing to remember is that the form is tied to a Model. This is significant because it’s the Model that dictates what elements exist, controls validation of the form, and defines the form’s labels (e.g., First Name for the firstName attribute), and so forth.

Tip: There are instances where you might have a form not associated with a Model, but that is rare. The most common such instance would be a search form.

Before getting to the View and its form, let’s be clear as to how the View accesses the specific Model. A Controller may have this code:

public function actionCreate() {

    $model=new Employee;

    /* Code for validation and redirect upon save. */

    // If not saved, render the create View:
    $this->render('create',array(
        'model'=>$model, // Model is passed to create.php View!
    ));
}

The create.php View file will include _form.php, passing along the Model instance in the process:

<?php echo $this->renderPartial('_form', array('model'=>$model)); ?>

So now _form.php has access to the Model instance and can create the form tied to that Model.

Of course, to be fair, you could create an HTML form using raw HTML, without Yii at all. The downside to that approach is it creates no tie-in between the Model’s validation rules, errors, labels, etc., and the form. By creating the form using Yii, labels will be based upon the Model definitions (meaning that changing just the Model changes reference to attributes everywhere), invalid form values can automatically be highlighted, and much, much more. Plus, it’s not hard to use Yii to create a form, once you understand how.

The older Yii method for creating a form was simply a matter of invoking the appropriate CHtml methods: activeLabel(), activeTextField(), activeDropDownList(), and so forth:

<div class="row">
     <?php echo CHtml::activeLabel($model,'username'); ?>
     <?php echo CHtml::activeTextField($model,'username') ?>
</div>

The CHtml::activeLabel() method creates the label. The other methods create other form elements. Each method takes the Model involved as its first argument and the Model’s corresponding attribute as its second, thereby tying the form to the Model.

And here’s another reason to use Yii’s system of creating forms: if the form is being used for an update, the values will automatically be prepopulated/pre-selected/pre-checked based upon the existing Model! As you should know, that alone requires a lot of code and logic.

As of Yii 1.1.1, forms can be created using the CActiveForm widget. Among other benefits, CActiveForm is capable of enabling client-side form validation using Ajax. You always start by invoking beginWidget():

$form = $this->beginWidget('CActiveForm');

(This code goes in the _form.php file.) Now $form is an object of the CActiveForm widget type and it can be used to generate the form itself:

<div>
    <?php echo $form->labelEx($model,'firstName'); ?>
    <?php echo $form->textField($model,'firstName',array('size'=>20,'maxlength'=>20)); ?>
    <?php echo $form->error($model,'firstName'); ?>
</div>

You’ll see that whereas CHtml has the activeTextField() method, CActiveForm has just textField(). The same goes for activeLabel() becoming just labelEx(). You’ll see this pattern—dropping the active part—repeated. Still, the Model is passed as the first argument and the attribute involved as the second.

Returning to the widget itself, you can customize the behavior of the form by passing an array of values when creating it:

<?php $form = $this->beginWidget('CActiveForm', array(
    'id'=>'user-form',
    'enableAjaxValidation'=>true,
    'focus'=>array($model,'firstName'),
)); ?>

Note: I’ll address Ajax form validation in a separate post.

The various CActiveForm properties can be found in the documentation. Commonly you won’t need to customize any properties, but you can change the form’s method and action attributes, or add additional HTML to the opening form tag.

Finally, the form needs a submit button. Unlike the other form elements, this isn’t tied to a Model; it is created with just the CHtml class:

<div>
    <?php echo CHtml::submitButton($model->isNewRecord ? 'Create' : 'Save'); ?>
</div>

The submitButton()‘s argument is the textual label for the button.

Then the form is closed by “ending” the widget:

<?php $this->endWidget(); ?>

So those are the basics for using CActiveForm. Once you’ve taken the above steps, form elements will be prepopulated when updating a record, errors will be clearly indicated upon form submission, and so forth.

The most important information involves creating the form elements. For the most part, doing so is simple and direct, as shown in the above. By associating the Model instance with the form, Yii will do the rest. Sometimes you’ll need to customize the look and behavior of an element. I’ve discussed this in many separate posts, which I’d recommend you read:

And my Basic View Edits post, part of my Learning the Yii Framework series, demonstrates how to use CHtml::listData() to populate a drop down menu. I’ll no doubt post more threads particular to forms in Yii, as its such a critical topic. Potential subjects include: Ajax validation and handling file uploads.

In a separate post, I’ll talk about Form Builder, added to Yii in version 1.1.0. It allows you to create forms in a different way, primarily in the Controller (not unlike using the PEAR HTML_QuickForm class).