Creating Model
==============

Before writing the HTML code needed by a form, we should decide what kind
of data we are expecting from end users and what rules these data should
comply with. A model class can be used to record these information. A
model, as defined in the [Model](/doc/guide/basics.model) subsection, is
the central place for keeping user inputs and validating them.

Depending on how we make use of the user input, we can create two types of
model. If the user input is collected, used and then discarded, we would
create a [form model](/doc/guide/basics.model); if the user input is
collected and saved into database, we would use an [active
record](/doc/guide/database.ar) instead. Both types of model share the same
base class [CModel] which defines the common interface needed by form.

> Note: We are mainly using form models in the examples of this section.
However, the same can also be applied to [active
record](/doc/guide/database.ar) models.

Defining Model Class
--------------------

Below we create a `LoginForm` model class used to collect user input on a
login page. Because the login information is only used to authenticate the
user and does not need to be saved, we create `LoginForm` as a form model.

~~~
[php]
class LoginForm extends CFormModel
{
	public $username;
	public $password;
	public $rememberMe=false;
}
~~~

Three attributes are declared in `LoginForm`: `$username`, `$password` and
`$rememberMe`. They are used to keep the user-entered username and
password, and the option whether the user wants to remember his login.
Because `$rememberMe` has a default value `false`, the corresponding option
when initially displayed in the login form will be unchecked.

> Info: Instead of calling these member variables properties, we use the
name *attributes* to differentiate them from normal properties. An
attribute is a property that is mainly used to store data coming from user
input or database.

Declaring Validation Rules
--------------------------

Once a user submits his inputs and the model gets populated, we need to
make sure the inputs are valid before using them. This is done by
performing validation of the inputs against a set of rules. We specify the
validation rules in the `rules()` method which should return an array of
rule configurations.

~~~
[php]
class LoginForm extends CFormModel
{
	public $username;
	public $password;
	public $rememberMe=false;

	private $_identity;

	public function rules()
	{
		return array(
			array('username, password', 'required'),
			array('rememberMe', 'boolean'),
			array('password', 'authenticate'),
		);
	}

	public function authenticate($attribute,$params)
	{
		$this->_identity=new UserIdentity($this->username,$this->password);
		if(!$this->_identity->authenticate())
			$this->addError('password','Incorrect username or password.');
	}
}
~~~

The above code specifies that `username` and `password` are both required,
`password` should be authenticated, and `rememberMe` should be a boolean.

Each rule returned by `rules()` must be of the following format:

~~~
[php]
array('AttributeList', 'Validator', 'on'=>'ScenarioList', ...additional options)
~~~

where `AttributeList` is a string of comma-separated attribute names which
need to be validated according to the rule; `Validator` specifies what kind of
validation should be performed; the `on` parameter is optional which specifies
a list of scenarios where the rule should be applied; and additional options
are name-value pairs which are used to initialize the corresponding validator [component's
property values](/doc/guide/basics.component).

Since version 1.1.11 it is possible to blacklist scenarios. If you don't
want to perform validation for some rule when particular scenarios are active
you could specify `except` parameter containing their names. Syntax is the same
as for `on` parameter.

List of scenarios (`on` and `except` parameters) could be specified in two
different forms which means the same:

~~~
[php]
// arbitrary array with scenario names
'on'=>array('update', 'create'),
// string with scenario names separated with commas (spaces are ignored)
'except'=>'ignore, this, scenarios, at-all',
~~~

There are three ways to specify `Validator` in a validation rule. First,
`Validator` can be the name of a method in the model class, like
`authenticate` in the above example. The validator method must be of the
following signature:

~~~
[php]
/**
 * @param string $attribute the name of the attribute to be validated
 * @param array $params options specified in the validation rule
 */
public function ValidatorName($attribute,$params) { ... }
~~~

Second, `Validator` can be the name of a validator class. When the rule is
applied, an instance of the validator class will be created to perform the
actual validation. The additional options in the rule are used to
initialize the instance's attribute values. A validator class must extend
from [CValidator].

Third, `Validator` can be a predefined alias to a validator class. In the
above example, the name `required` is the alias to [CRequiredValidator]
which ensures the attribute value being validated is not empty. Below is
the complete list of predefined validator aliases:

   - `boolean`: alias of [CBooleanValidator], ensuring the attribute has
a value that is either [CBooleanValidator::trueValue] or
[CBooleanValidator::falseValue].

   - `captcha`: alias of [CCaptchaValidator], ensuring the attribute is
equal to the verification code displayed in a
[CAPTCHA](http://en.wikipedia.org/wiki/Captcha).

   - `compare`: alias of [CCompareValidator], ensuring the attribute is
equal to another attribute or constant.

   - `email`: alias of [CEmailValidator], ensuring the attribute is a
valid email address.

   - `date`: alias of [CDateValidator], ensuring the attribute represents
a valid date, time, or datetime value.

   - `default`: alias of [CDefaultValueValidator], assigning a default value
to the specified attributes.

   - `exist`: alias of [CExistValidator], ensuring the attribute value
can be found in the specified table column.

   - `file`: alias of [CFileValidator], ensuring the attribute contains
the name of an uploaded file.

   - `filter`: alias of [CFilterValidator], transforming the attribute
with a filter.

   - `in`: alias of [CRangeValidator], ensuring the data is among a
pre-specified list of values.

   - `length`: alias of [CStringValidator], ensuring the length of the
data is within certain range.

   - `match`: alias of [CRegularExpressionValidator], ensuring the data
matches a regular expression.

   - `numerical`: alias of [CNumberValidator], ensuring the data is a
valid number.

   - `required`: alias of [CRequiredValidator], ensuring the attribute is
not empty.

   - `type`: alias of [CTypeValidator], ensuring the attribute is of
specific data type.

   - `unique`: alias of [CUniqueValidator], ensuring the data is unique in
a database table column.

   - `url`: alias of [CUrlValidator], ensuring the data is a valid URL.

Below we list some examples of using the predefined validators:

~~~
[php]
// username is required
array('username', 'required'),
// username must be between 3 and 12 characters
array('username', 'length', 'min'=>3, 'max'=>12),
// when in register scenario, password must match password2
array('password', 'compare', 'compareAttribute'=>'password2', 'on'=>'register'),
// when in login scenario, password must be authenticated
array('password', 'authenticate', 'on'=>'login'),
~~~


Securing Attribute Assignments
------------------------------

After a model instance is created, we often need to populate its
attributes with the data submitted by end-users. This can be done
conveniently using the following massive assignment:

~~~
[php]
$model=new LoginForm;
if(isset($_POST['LoginForm']))
	$model->attributes=$_POST['LoginForm'];
~~~

The last statement is called *massive assignment* which assigns every entry
in `$_POST['LoginForm']` to the corresponding model attribute.
It is equivalent to the following assignments:

~~~
[php]
foreach($_POST['LoginForm'] as $name=>$value)
{
	if($name is a safe attribute)
		$model->$name=$value;
}
~~~

It is crucial to determine which attributes are safe. For example, if we
expose the primary key of a table to be safe, then an attacker could
get a chance to modify the primary key of the given record and thus tamper
the data he is not authorized to.


###Declaring Safe Attributes

An attribute is considered safe if it appears in a validation
rule that is applicable in the given scenario. For example,

~~~
[php]
array('username, password', 'required', 'on'=>'login, register'),
array('email', 'required', 'on'=>'register'),
~~~

In the above, the `username` and `password` attributes are required in `login`
scenario, while the `username`, `password` and `email` attributes are required
in `register` scenario. As a result, if we perform a massive assign when in
`login` scenario, only `username` and `password` will be massively assigned
since they are the only attributes appearing in the validation rules for `login`.
On the other hand, if the scenario is `register`, the three attributes can
all be massively assigned.

~~~
[php]
// in login scenario
$model=new User('login');
if(isset($_POST['User']))
	$model->attributes=$_POST['User'];

// in register scenario
$model=new User('register');
if(isset($_POST['User']))
	$model->attributes=$_POST['User'];
~~~

So why do we use such a policy to determine if an attribute is safe or not?
The rationale behind is that if an attribute already has one or several validation rules
to check its validity, what else should we worry about it?

It is important to remember that validation rules are used to check user input data
rather than the data that we generate in the code (e.g. timestamp, auto-generated primary key).
Therefore, DO NOT add validation rules for those attributes which do not expect inputs
from end-users.

Sometimes, we want to declare an attribute to be safe, even though we do not really have
any specific rule for it. An example is an article's content attribute which can take any
user input. We can use the special `safe` rule to achieve this goal:

~~~
[php]
array('content', 'safe')
~~~

For completeness, there is also an `unsafe` rule which is used to explicitly declare an
attribute to be unsafe:

~~~
[php]
array('permission', 'unsafe')
~~~

The `unsafe` rule is rarely used, and it is an exception to our previous definition of safe
attributes.


For data entries that are not safe, we need to assign them to the corresponding
attributes using individual assign statements, like the following:

~~~
[php]
$model->permission='admin';
$model->id=1;
~~~


Triggering Validation
---------------------

Once a model is populated with user-submitted data, we can call [CModel::validate()]
to trigger the data validation process. The method returns a value
indicating whether the validation is successful or not. For [CActiveRecord] models,
validation may also be automatically triggered when we call its [CActiveRecord::save()]
method.

We can set a scenario with the [scenario|CModel::scenario] property and
therewith indicate which set of validation rules should be applied.


Validation is performed in a scenario basis. The [scenario|CModel::scenario]
property specifies which scenario the model is being used in and which set
of validation rules should be used. For example, in the `login` scenario, we only want to
validate the `username` and `password` inputs of a user model; while in the `register`
scenario, we need to validate more inputs, such as `email`, `address`, etc.
The following example shows how to perform validation in the `register` scenario:

~~~
[php]
// creates a User model in register scenario. It is equivalent to:
// $model=new User;
// $model->scenario='register';
$model=new User('register');

// populates the input values into the model
$model->attributes=$_POST['User'];

// performs the validation
if($model->validate())   // if the inputs are valid
    ...
else
    ...
~~~

The applicable scenarios that a rule is associated can be specified via
the `on` option in the rule. If the `on` option is not set, it means the
rule will be used for all scenarios. For example,

~~~
[php]
public function rules()
{
	return array(
		array('username, password', 'required'),
		array('password_repeat', 'required', 'on'=>'register'),
		array('password', 'compare', 'on'=>'register'),
	);
}
~~~

The first rule will be applied in all scenarios, while the
next two rules will only be applied in the `register` scenario.


Retrieving Validation Errors
----------------------------

Once validation is done, any possible errors will be stored in the model
object. We can retrieve the error messages by calling [CModel::getErrors()]
and [CModel::getError()]. The difference between the two methods is that
the first method will return *all* errors for the specified model attribute
while the second method will only return the *first* error.

Attribute Labels
----------------

When designing a form, we often need to display a label for each input
field. The label tells a user what kind of information he is expected to
enter into the field. Although we can hardcode a label in a view, it would
offer more flexibility and convenience if we specify it in the
corresponding model.

By default, [CModel] will simply return the name of an attribute as its
label. This can be customized by overriding the
[attributeLabels()|CModel::attributeLabels] method. As we will see in the
following subsections, specifying labels in the model allows us to create a
form more quickly and powerful.

<div class="revision">$Id$</div>