model.md 9.06 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

Larry Ullman committed
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. The validation rules greatly simply the generation of models from complex web forms.
The Model class is also the base for more advanced models with additional functionality such as [Active Record](active-record.md).
Alexander Makarov committed
13 14 15 16 17 18 19 20 21 22

Attributes
----------

Attributes store the actual data represented by a model and can
be accessed like object member variables. For example, a `Post` model
may contain a `title` attribute and a `content` attribute which may be
accessed as follows:

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

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

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

Qiang Xue committed
41 42 43
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
44 45 46 47 48 49 50 51 52 53

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

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


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

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

Qiang Xue committed
66 67 68 69
To declare attribute labels, you should override the [[\yii\base\Model::attributeLabels()]] method and return
a mapping from attribute names to attribute labels, like 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, which
in many cases, will generate reasonable labels (e.g. `username` to `Username`, `orderNumber` to `Order Number`).
Alexander Makarov committed
70 71 72 73 74 75 76 77 78 79

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

	public function attributeLabels()
	{
Qiang Xue committed
80
		return array(
Carsten Brandt committed
81
			'username' => 'Your name',
Alexander Makarov committed
82 83 84 85 86 87 88 89 90 91 92 93
			'password' => 'Your password',
		);
	}
}
```

Scenarios
---------

A model may be used in different scenarios. For example, a `User` model may be used to collect user login inputs,
and it may also be used for user registration purpose. For this reason, each model has a property named `scenario`
which stores the name of the scenario that the model is currently being used in. As we will explain in the next
Qiang Xue committed
94
few sections, the concept of scenario is mainly used for data validation and massive attribute assignment.
Alexander Makarov committed
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115

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*.

Possible scenarios should be listed in the `scenarios()` method which returns an array whose keys are the scenario
names and whose values are the corresponding active attribute lists. Below is an example:

```php
class User extends \yii\db\ActiveRecord
{
	public function scenarios()
	{
		return array(
			'login' => array('username', 'password'),
			'register' => array('username', 'email', 'password'),
		);
	}
}
```

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

```php
array('username', 'password', '!secret')
```

123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
Active model scenario could be set using one of the following ways:

```php
class EmployeeController extends \yii\web\Controller
{
	public function actionCreate($id = null)
	{
		// first way
		$employee = new Employee(array('scenario' => 'managementPanel'));

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

		// third way
		$employee = Employee::find()->where('id = :id', array(':id' => $id))->one();
		if ($employee !== null) {
			$employee->setScenario('managementPanel');
		}
	}
}
```

146 147 148
In the example above we are using [Active Record](active-record.md). For basic form models it's rarely needed to
use scenarios since form model is typically used for a single form.

Alexander Makarov committed
149 150 151 152 153 154 155 156 157 158 159 160 161
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
162
	// ... login the user ...
Alexander Makarov committed
163 164
} else {
	$errors = $model->getErrors();
Carsten Brandt committed
165
	// ... display the errors to the end user ...
Alexander Makarov committed
166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
}
```

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
array(
	'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
181 182 183 184
	// to initialize the validator properties
	'property1' => 'value1',
	'property2' => 'value2',
	// ...
Alexander Makarov committed
185 186 187 188 189
)
```

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

Carsten Brandt committed
190 191
- the rule must be associated with at least one active attribute;
- the rule must be active for the current scenario.
Alexander Makarov committed
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 217 218 219 220 221 222 223 224 225


### 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
$attributes = array(
	'title' => 'Model attributes',
	'create_time' => time(),
);
$post->attributes = $attributes;
```

Carsten Brandt committed
226
In the code above we're assigning corresponding data to model attributes named as array keys. The key difference from mass
Alexander Makarov committed
227 228 229
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
230

Alexander Makarov committed
231 232 233 234 235 236 237 238 239 240 241 242
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()
{
	return array(
		// rule applied when corresponding field is "safe"
243 244
		array('username', 'string', 'length' => array(4, 32)),
		array('first_name', 'string', 'max' => 128),
Alexander Makarov committed
245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263
		array('password', 'required'),

		// rule applied when scenario is "signup" no matter if field is "safe" or not
		array('hashcode', 'check', 'on' => 'signup'),
	);
}

function scenarios()
{
	return array(
		// on signup allow mass assignment of username
		'signup' => array('username', 'password'),
		'update' => array('username', 'first_name'),
	);
}
```

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

Carsten Brandt committed
264

Alexander Makarov committed
265 266 267 268 269
See also
--------

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