model.md 9.35 KB
Newer Older
Alexander Makarov committed
1 2 3
Model
=====

Larry Ullman committed
4
In keeping with the MVC approach, a model in Yii is intended for storing or temporarily representing application data. Yii models have the following basic features:
Alexander Makarov committed
5

Larry Ullman committed
6 7 8 9
- Attribute declaration: a model defines what is considered an attribute.
- Attribute labels: each attribute may be associated with a label for display purpose.
- Massive attribute assignment: the ability to populate multiple model attributes in one step.
- Scenario-based data validation.
Alexander Makarov committed
10

11 12
Models in Yii extend from the [[\yii\base\Model]] class. Models are typically used to both hold data and define the validation rules for that data (aka, the business logic). The business logic greatly simplifies the generation of models from complex web forms by providing validation and error reporting.
The Model class is also the base class for more advanced models with additional functionality, such as [Active Record](active-record.md).
Alexander Makarov committed
13 14 15 16

Attributes
----------

17 18 19
The actual data represented by a model is stored in the model's *attributes*. Model attributes can
be accessed like the member variables of any object. For example, a `Post` model
may contain a `title` attribute and a `content` attribute, accessible as follows:
Alexander Makarov committed
20 21

```php
Carsten Brandt committed
22
$post = new Post;
Alexander Makarov committed
23 24 25 26 27 28
$post->title = 'Hello, world';
$post->content = 'Something interesting is happening';
echo $post->title;
echo $post->content;
```

Qiang Xue committed
29
Since [[\yii\base\Model|Model]] implements the [ArrayAccess](http://php.net/manual/en/class.arrayaccess.php) interface,
30
you can also access the attributes as if they were array elements:
Alexander Makarov committed
31 32

```php
Carsten Brandt committed
33
$post = new Post;
Alexander Makarov committed
34 35 36 37 38 39
$post['title'] = 'Hello, world';
$post['content'] = 'Something interesting is happening';
echo $post['title'];
echo $post['content'];
```

Qiang Xue committed
40 41 42
By default, [[\yii\base\Model|Model]] requires that attributes be declared as *public* and *non-static*
class member variables. In the following example, the `LoginForm` model class declares two attributes:
`username` and `password`.
Alexander Makarov committed
43 44 45 46 47 48 49 50 51 52

```php
// LoginForm has two attributes: username and password
class LoginForm extends \yii\base\Model
{
	public $username;
	public $password;
}
```

53 54
Derived model classes may declare attributes in different ways, by overriding the [[\yii\base\Model::attributes()|attributes()]]
method. For example, [[\yii\db\ActiveRecord]] defines attributes using the column names of the database table
Qiang Xue committed
55
that is associated with the class.
Alexander Makarov committed
56 57


Qiang Xue committed
58
Attribute Labels
Carsten Brandt committed
59
----------------
Alexander Makarov committed
60 61

Attribute labels are mainly used for display purpose. For example, given an attribute `firstName`, we can declare
62
a label `First Name` that is more user-friendly when displayed to end users in places such as form labels and 
Qiang Xue committed
63
error messages. Given an attribute name, you can obtain its label by calling [[\yii\base\Model::getAttributeLabel()]].
Alexander Makarov committed
64

65 66
To declare attribute labels, override the [[\yii\base\Model::attributeLabels()]] method. The overridden method returns a mapping of attribute names to attribute labels, as shown in the example below. If an attribute is not found
in this mapping, its label will be generated using the [[\yii\base\Model::generateAttributeLabel()]] method. In many cases, [[\yii\base\Model::generateAttributeLabel()]] will generate reasonable labels (e.g. `username` to `Username`, `orderNumber` to `Order Number`).
Alexander Makarov committed
67 68 69 70 71 72 73 74 75 76

```php
// LoginForm has two attributes: username and password
class LoginForm extends \yii\base\Model
{
	public $username;
	public $password;

	public function attributeLabels()
	{
Alexander Makarov committed
77
		return [
Carsten Brandt committed
78
			'username' => 'Your name',
Alexander Makarov committed
79
			'password' => 'Your password',
Alexander Makarov committed
80
		];
Alexander Makarov committed
81 82 83 84 85 86 87
	}
}
```

Scenarios
---------

88 89 90 91 92 93
A model may be used in different *scenarios*. For example, a `User` model may be used to collect user login inputs,
but it may also be used for user registration purposes. In the one scenario, every piece of data is required; in the other, only the username and password would be. 

To easily implement the business logic for different scenarios, each model has a property named `scenario`
that stores the name of the scenario that the model is currently being used in. As will be explained in the next
few sections, the concept of scenarios is mainly used for data validation and massive attribute assignment.
Alexander Makarov committed
94 95 96 97 98

Associated with each scenario is a list of attributes that are *active* in that particular scenario. For example,
in the `login` scenario, only the `username` and `password` attributes are active; while in the `register` scenario,
additional attributes such as `email` are *active*.

99 100
Possible scenarios should be listed in the `scenarios()` method. This method returns an array whose keys are the scenario
names and whose values are lists of attributes that should be active in that scenario:
Alexander Makarov committed
101 102 103 104 105 106

```php
class User extends \yii\db\ActiveRecord
{
	public function scenarios()
	{
Alexander Makarov committed
107 108 109 110
		return [
			'login' => ['username', 'password'],
			'register' => ['username', 'email', 'password'],
		];
Alexander Makarov committed
111 112 113 114
	}
}
```

115 116
Sometimes, we want to mark an attribute as not safe for massive assignment (but we still want the attribute to be validated).
We may do so by prefixing an exclamation character to the attribute name when declaring it in `scenarios()`. For example:
Alexander Makarov committed
117 118

```php
Alexander Makarov committed
119
['username', 'password', '!secret']
Alexander Makarov committed
120 121
```

122
Identifying the active model scenario can be done using one of the following approaches:
123 124 125 126 127 128 129

```php
class EmployeeController extends \yii\web\Controller
{
	public function actionCreate($id = null)
	{
		// first way
Alexander Makarov committed
130
		$employee = new Employee(['scenario' => 'managementPanel']);
131 132 133 134 135 136

		// second way
		$employee = new Employee;
		$employee->scenario = 'managementPanel';

		// third way
Alexander Makarov committed
137
		$employee = Employee::find()->where('id = :id', [':id' => $id])->one();
138 139 140 141 142 143 144
		if ($employee !== null) {
			$employee->setScenario('managementPanel');
		}
	}
}
```

145
The example above presumes that the model is based upon [Active Record](active-record.md). For basic form models, scenarios are rarely needed, as the basic form model is normally tied directly to a single form.
146

Alexander Makarov committed
147 148 149 150 151 152 153 154 155 156 157 158 159
Validation
----------

When a model is used to collect user input data via its attributes, it usually needs to validate the affected attributes
to make sure they satisfy certain requirements, such as an attribute cannot be empty, an attribute must contain letters
only, etc. If errors are found in validation, they may be presented to the user to help him fix the errors.
The following example shows how the validation is performed:

```php
$model = new LoginForm;
$model->username = $_POST['username'];
$model->password = $_POST['password'];
if ($model->validate()) {
Carsten Brandt committed
160
	// ... login the user ...
Alexander Makarov committed
161 162
} else {
	$errors = $model->getErrors();
Carsten Brandt committed
163
	// ... display the errors to the end user ...
Alexander Makarov committed
164 165 166 167 168 169 170 171
}
```

The possible validation rules for a model should be listed in its `rules()` method. Each validation rule applies to one
or several attributes and is effective in one or several scenarios. A rule can be specified using a validator object - an
instance of a [[\yii\validators\Validator]] child class, or an array with the following format:

```php
Alexander Makarov committed
172
[
Alexander Makarov committed
173 174 175 176 177 178
	'attribute1, attribute2, ...',
	'validator class or alias',
	// specifies in which scenario(s) this rule is active.
	// if not given, it means it is active in all scenarios
	'on' => 'scenario1, scenario2, ...',
	// the following name-value pairs will be used
Carsten Brandt committed
179 180 181 182
	// to initialize the validator properties
	'property1' => 'value1',
	'property2' => 'value2',
	// ...
Alexander Makarov committed
183
]
Alexander Makarov committed
184 185 186 187
```

When `validate()` is called, the actual validation rules executed are determined using both of the following criteria:

Carsten Brandt committed
188 189
- the rule must be associated with at least one active attribute;
- the rule must be active for the current scenario.
Alexander Makarov committed
190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216


### Active Attributes

An attribute is *active* if it is subject to some validations in the current scenario.


### Safe Attributes

An attribute is *safe* if it can be massively assigned in the current scenario.


Massive Attribute Retrieval and Assignment
------------------------------------------

Attributes can be massively retrieved via the `attributes` property.
The following code will return *all* attributes in the `$post` model
as an array of name-value pairs.

```php
$attributes = $post->attributes;
var_dump($attributes);
```

Using the same `attributes` property you can massively assign data from associative array to model attributes:

```php
Alexander Makarov committed
217
$attributes = [
Alexander Makarov committed
218 219
	'title' => 'Model attributes',
	'create_time' => time(),
Alexander Makarov committed
220
];
Alexander Makarov committed
221 222 223
$post->attributes = $attributes;
```

Carsten Brandt committed
224
In the code above we're assigning corresponding data to model attributes named as array keys. The key difference from mass
Alexander Makarov committed
225 226 227
retrieval that always works for all attributes is that in order to be assigned an attribute should be **safe** else
it will be ignored.

Carsten Brandt committed
228

Alexander Makarov committed
229 230 231 232 233 234 235 236 237 238
Validation rules and mass assignment
------------------------------------

In Yii2 unlike Yii 1.x validation rules are separated from mass assignment. Validation
rules are described in `rules()` method of the model while what's safe for mass
assignment is described in `scenarios` method:

```php
function rules()
{
Alexander Makarov committed
239
	return [
Alexander Makarov committed
240
		// rule applied when corresponding field is "safe"
Alexander Makarov committed
241 242 243
		['username', 'string', 'length' => [4, 32]],
		['first_name', 'string', 'max' => 128],
		['password', 'required'],
Alexander Makarov committed
244 245

		// rule applied when scenario is "signup" no matter if field is "safe" or not
Alexander Makarov committed
246 247
		['hashcode', 'check', 'on' => 'signup'],
	];
Alexander Makarov committed
248 249 250 251
}

function scenarios()
{
Alexander Makarov committed
252
	return [
Alexander Makarov committed
253
		// on signup allow mass assignment of username
Alexander Makarov committed
254 255 256
		'signup' => ['username', 'password'],
		'update' => ['username', 'first_name'],
	];
Alexander Makarov committed
257 258 259 260 261
}
```

Note that everything is unsafe by default and you can't make field "safe" without specifying scenario.

Carsten Brandt committed
262

Alexander Makarov committed
263 264 265 266 267
See also
--------

- [Model validation reference](validation.md)
- [[\yii\base\Model]]