Commit 4c776ab7 by Qiang Xue

guide WIP [skip ci]

parent d34e3c32
Model Models
===== ======
> Note: This section is under development. Models are objects representing business data, rules and logic. They are part of
the [MVC](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) architecture.
In keeping with the MVC approach, a model in Yii is intended for storing or temporarily representing application data, as well as defining the busines rules by which the data must abide. You can create model classes by extending [[yii\base\Model]] or its child classes. The base class
[[yii\base\Model]] supports many useful features:
Yii models have the following basic features: * Attributes: represent the business data;
* Attribute labels: specify the display labels for attributes;
* Massive attribute assignment: supports populating multiple attributes in a single step;
* Data validation: validates input data based on the declared validation rules;
* Data export: allows exporting model data in terms of arrays without customizable formats;
* Array access: supports accessing model data like an associative array.
- Attribute declaration: a model defines what is considered an attribute. The `Model` class is also the base class for more advanced models, such as [Active Record](db-active-record.md).
- Attribute labels: each attribute may be associated with a label for display purpose. Please refer to the relevant documentation for more details about these advanced models.
- Massive attribute assignment: the ability to populate multiple model attributes in one step.
- Scenario-based data validation.
Models in Yii extend from the [[yii\base\Model]] class. Models are typically used to both hold data and define > Info: You are not required to base your model classes on [[yii\base\Model]]. However, because there are many Yii
the validation rules for that data (aka, the business logic). The business logic greatly simplifies the generation components built to support [[yii\base\Model]], it is usually the preferable base model classes.
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).
Attributes ## Attributes
----------
The actual data represented by a model is stored in the model's *attributes*. Model attributes can Attributes are the properties that represent business data. By default, attributes are *non-static public*
be accessed like the member variables of any object. For example, a `Post` model member variables if your model class extends directly from [[yii\base\Model]].
may contain a `title` attribute and a `content` attribute, accessible as follows:
The following code creates a `ContactForm` model class with four attributes: `name`, `email`, `subject` and `body`.
```php ```php
$post = new Post(); namespace app\models;
$post->title = 'Hello, world';
$post->content = 'Something interesting is happening.'; use yii\base\Model;
echo $post->title;
echo $post->content; class ContactForm extends Model
{
public $name;
public $email;
public $subject;
public $body;
}
``` ```
Since [[yii\base\Model|Model]] implements the [ArrayAccess](http://php.net/manual/en/class.arrayaccess.php) interface, Naturally, you can access an attribute like accessing a normal object property:
you can also access the attributes as if they were array elements:
```php ```php
$post = new Post(); $model = new \app\models\ContactForm;
$post['title'] = 'Hello, world'; $model->name = 'example';
$post['content'] = 'Something interesting is happening'; echo $model->name;
echo $post['title'];
echo $post['content'];
``` ```
By default, [[yii\base\Model|Model]] requires that attributes be declared as *public* and *non-static* You can also access attributes like accessing array elements, thanks to the support for
class member variables. In the following example, the `LoginForm` model class declares two attributes: [ArrayAccess](http://php.net/manual/en/class.arrayaccess.php) and [ArrayIterator](http://php.net/manual/en/class.arrayiterator.php)
`username` and `password`. by [[yii\base\Model]]:
```php ```php
// LoginForm has two attributes: username and password $model = new \app\models\ContactForm;
class LoginForm extends \yii\base\Model
{ // accessing attributes like array elements
public $username; $model['name'] = 'example';
public $password; echo $model['name'];
// iterate attributes
foreach ($model as $name => $value) {
echo "$name: $value\n";
} }
``` ```
Derived model classes may declare attributes in different ways, by overriding the [[yii\base\Model::attributes()|attributes()]] You may override [[yii\base\Model::attributes()]] if you want to support different ways of defining attributes.
method. For example, [[yii\db\ActiveRecord]] defines attributes using the column names of the database table For example, [[yii\db\ActiveRecord]] does so and defines attributes according to table columns. Note that you
that is associated with the class. may also need to override the magic methods such as `__get()`, `__set()` so that the attributes can be accessed
like normal object properties.
## Attribute Labels
Attribute Labels When displaying values or getting input for attributes, you often need to display some labels associated
---------------- with attributes. For example, given an attribute named `firstName`, you may want to display a label `First Name`
which is more user-friendly when displayed to end users in places such as form inputs and error messages.
Attribute labels are mainly used for display purpose. For example, given an attribute `firstName`, we can declare By default, attribute labels are automatically generated from attribute names. The generation is done by
a label `First Name` that is more user-friendly when displayed to end users in places such as form labels and the method [[yii\base\Model::generateAttributeLabel()]]. It will turn camel-case variable names into
error messages. Given an attribute name, you can obtain its label by calling [[yii\base\Model::getAttributeLabel()]]. multiple words with the first letter in each word in upper case. For example, `username` becomes `Username`,
and `firstName` becomes `First Name`.
To declare attribute labels, override the [[yii\base\Model::attributeLabels()]] method. The overridden method returns If you do not want to use automatically generated labels, you may override [[yii\base\Model::attributeLabels()]]
a mapping of attribute names to attribute labels, as shown in the example below. If an attribute is not found to explicitly declare attribute labels. For example,
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`).
```php ```php
// LoginForm has two attributes: username and password namespace app\models;
class LoginForm extends \yii\base\Model
use yii\base\Model;
class ContactForm extends Model
{ {
public $username; public $name;
public $password; public $email;
public $subject;
public $body;
public function attributeLabels() public function attributeLabels()
{ {
return [ return [
'username' => 'Your name', 'name' => 'Your name',
'password' => 'Your password', 'email' => 'Your email address',
'subject' => 'Subject',
'body' => 'Content',
]; ];
} }
} }
``` ```
Scenarios For applications supporting multiple languages, you may want to translate attribute labels. This can be done
--------- in the [[yii\base\Model::attributeLabels()|attributeLabels()]] method as well, like the following:
A model may be used in different *scenarios*. For example, a `User` model may be used to collect user login inputs, ```php
but it may also be used for user registration purposes. In the one scenario, every piece of data is required; public function attributeLabels()
in the other, only the username and password would be. {
return [
'name' => \Yii::t('app', 'Your name'),
'email' => \Yii::t('app', 'Your email address'),
'subject' => \Yii::t('app', 'Subject'),
'body' => \Yii::t('app', 'Content'),
];
}
```
> Info: Strictly speaking, attribute labels are part of [views](structure-views.md). But declaring labels
in models is often very convenient and can result in very clean and reusable code.
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.
Associated with each scenario is a list of attributes that are *active* in that particular scenario. For example, ## Scenarios
in the `login` scenario, only the `username` and `password` attributes are active; while in the `register` scenario,
additional attributes such as `email` are *active*. When an attribute is *active* this means that it is subject to validation.
Possible scenarios should be listed in the `scenarios()` method. This method returns an array whose keys are the scenario A model may be used in different *scenarios*. For example, a `User` model may be used to collect user login inputs,
names and whose values are lists of attributes that should be active in that scenario: but it may also be used for the user registration purpose. In different scenarios, a model may use different
business rules and logic. For example, the `email` attribute may be required during user registration,
but not so during user login.
A model uses the [[yii\base\Model::scenario]] property to keep track of the scenario it is being used in.
By default, a model supports only a single scenario named `default`.
To support multiple scenarios, you may override the [[yii\base\Model::scenarios()]] method, like the following:
```php ```php
class User extends \yii\db\ActiveRecord namespace app\models;
use yii\db\ActiveRecord;
class User extends ActiveRecord
{ {
public function scenarios() public function scenarios()
{ {
...@@ -124,13 +159,24 @@ class User extends \yii\db\ActiveRecord ...@@ -124,13 +159,24 @@ class User extends \yii\db\ActiveRecord
} }
``` ```
If `scenarios` method is not defined, default scenario is applied. That means attributes with validation rules are > Info: In the above and following examples, the model classes are extending from [[yii\db\ActiveRecord]]
considered *active*. because the usage of multiple scenarios usually happens to [Active Record](db-active-record.md) classes.
The `scenarios()` method returns an array whose keys are the scenario names and values the corresponding
*active attributes*. An active attribute can be [massively assigned](#massive-assignment) and is subject
to [validation](#validation). In the above example, the `username` and `password` attributes are active
in the `login` scenario; while in the `register` scenario, `email` is also active besides `username` and `password`.
If you want to keep the default scenario available besides your own scenarios, use inheritance to include it: The default implementation of `scenarios()` will return all scenarios found in the validation rule declaration
method [[yii\base\Model::rules()]]. When overriding `scenarios()`, if you want to introduce new scenarios
in addition to the default ones, you may write code like the following:
```php ```php
class User extends \yii\db\ActiveRecord namespace app\models;
use yii\db\ActiveRecord;
class User extends ActiveRecord
{ {
public function scenarios() public function scenarios()
{ {
...@@ -142,48 +188,12 @@ class User extends \yii\db\ActiveRecord ...@@ -142,48 +188,12 @@ class User extends \yii\db\ActiveRecord
} }
``` ```
The scenario feature is primarily used by [validation](#validation) and [massive attribute assignment](#massive-assignment).
Sometimes, we want to mark an attribute as not safe for massive assignment (but we still want the attribute to be validated). You can, however, use it for other purposes. For example, you may declare [attribute labels](#attribute-labels)
We may do so by prefixing an exclamation character to the attribute name when declaring it in `scenarios()`. For example: differently based on the current scenario.
```php
['username', 'password', '!secret']
```
In this example `username`, `password` and `secret` are *active* attributes but only `username` and `password` are
considered safe for massive assignment.
Identifying the active model scenario can be done using one of the following approaches:
```php
class EmployeeController extends \yii\web\Controller
{
public function actionCreate($id = null)
{
// first way
$employee = new Employee(['scenario' => 'managementPanel']);
// second way
$employee = new Employee();
$employee->scenario = 'managementPanel';
// third way
$employee = Employee::find()->where('id = :id', [':id' => $id])->one();
if ($employee !== null) {
$employee->scenario = 'managementPanel';
}
}
}
```
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 and, as noted above,
the default implementation of the `scenarios()` returns every property with active validation rule making it always
available for mass assignment and validation.
Validation ## Validation <a name="validation"></a>
----------
When a model is used to collect user input data via its attributes, it usually needs to validate the affected attributes 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 to make sure they satisfy certain requirements, such as an attribute cannot be empty, an attribute must contain letters
...@@ -308,8 +318,7 @@ public function rules() ...@@ -308,8 +318,7 @@ public function rules()
``` ```
Massive Attribute Retrieval and Assignment ## Massive Attribute Assignment <a name="massive-assignment"></a>
------------------------------------------
Attributes can be massively retrieved via the `attributes` property. Attributes can be massively retrieved via the `attributes` property.
The following code will return *all* attributes in the `$post` model The following code will return *all* attributes in the `$post` model
...@@ -340,6 +349,46 @@ retrieval that always works for all attributes is that in order to be assigned a ...@@ -340,6 +349,46 @@ retrieval that always works for all attributes is that in order to be assigned a
it will be ignored. it will be ignored.
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:
```php
['username', 'password', '!secret']
```
In this example `username`, `password` and `secret` are *active* attributes but only `username` and `password` are
considered safe for massive assignment.
Identifying the active model scenario can be done using one of the following approaches:
```php
class EmployeeController extends \yii\web\Controller
{
public function actionCreate($id = null)
{
// first way
$employee = new Employee(['scenario' => 'managementPanel']);
// second way
$employee = new Employee();
$employee->scenario = 'managementPanel';
// third way
$employee = Employee::find()->where('id = :id', [':id' => $id])->one();
if ($employee !== null) {
$employee->scenario = 'managementPanel';
}
}
}
```
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 and, as noted above,
the default implementation of the `scenarios()` returns every property with active validation rule making it always
available for mass assignment and validation.
Validation rules and mass assignment Validation rules and mass assignment
------------------------------------ ------------------------------------
...@@ -494,8 +543,10 @@ array( ...@@ -494,8 +543,10 @@ array(
) )
``` ```
See also ## Data Exporting
--------
## Best Practices
- [Model validation reference](validation.md) scenarios
- [[yii\base\Model]] validation rules
labels
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment