Models are part of the MVC pattern and are objects that represent business data, rules, and logic.
The model is an instance of Cmodel or its subclasses. Models are used to maintain data and the business logic associated with it.
The model is a separate data object. It can be a row in a datasheet, or a form entered by a user. Each field in a data object corresponds to a property in the model. Each attribute has a label, and can be validated by a series of rules.
YII implements two types of models: the form model and the Active record. Both inherit from the same base class Cmodel.
The form model is an instance of Cformmodel. The form model is used to keep the data obtained from the user's input. These data are often fetched, used, and discarded. For example, in a login page, we can use the form model to represent the user name and password information provided by the end user.
Active Record (AR) is a design pattern for abstracting database access through an object-oriented style. Each AR object is an instance of a Cactiverecord or its subclasses. Represents a row in a datasheet. The fields in the row correspond to the properties in the AR object.
The model class can be defined by inheriting Yii\base\model or its subclasses, and the base class Yii\base\model supports many practical features:
- Properties: Represents business data that can be accessed like a normal class attribute or array;
- Property Label: Specifies the label that the property displays;
- Block assignment: Supports a step to assigning values to many attributes;
- Validation rules: Ensure that the input data conforms to the declared validation rules;
- Data export: Allows model data to be exported to an array of custom formats.
Property
The model represents business data through attributes, each of which is like a publicly accessible property of the model, yii\base\model::attributes () to specify the attributes owned by the model.
You can access the properties of a model as you would access an object property:
$model = new \app\models\contactform;
"Name" is the attribute of the Contactform model
$model->name = ' example ';
Echo $model->name;
You can also access properties like array cell items, thanks to Yii\base\model support for arrayaccess array access and Arrayiterator array iterators:
$model = new \app\models\contactform;
Access the property like an array cell item
$model [' name '] = ' example ';
echo $model [' name '];
Iterator Traversal Model
foreach ($model as $name => $value) {
echo "$name: $value \ n";
}
Defining attributes
By default, your model class inherits directly from the Yii\base\model, and all non-static public non-static publicly member variables are attributes. For example, the following Contactform model class has four property name, email, subject and body, and the Contactform model is used to represent input data obtained from an HTML form.
namespace App\models;
Use Yii\base\model;
Class Contactform extends Model
{public
$name;
public $email;
public $subject;
public $body;
}
Alternatively, you can override Yii\base\model::attributes () to define the property, which returns the property name of the model. For example, Yii\db\activerecord returns the corresponding datasheet column name as its property name, noting that it may be necessary to override the Magic method such as __get (), __set () to make the property accessible as a normal object property.
Property label
When a property displays or gets input, it is often necessary to display attribute-related labels, such as assuming a property name is FirstName, and in some places, such as form input or error messages, you may want to display a more user-friendly list of the name tags for the end user.
You can call Yii\base\model::getattributelabel () to get the label for the property, for example:
$model = new \app\models\contactform;
Display as "name"
Echo $model->getattributelabel (' name ');
By default, property labels are generated automatically from the property name by the Yii\base\model::generateattributelabel () method. It automatically converts the name of the Hump case variable to a number of first-letter words, such as username to username, and firstName to name.
If you do not want to use the automatically generated label, you can override the Yii\base\model::attributelabels () method to explicitly specify the attribute label, for example:
namespace App\models;
Use Yii\base\model;
Class Contactform extends Model
{public
$name;
public $email;
public $subject;
public $body;
Public Function Attributelabels ()
{return
[
' name ' => ' Your name ',
' email ' => ' Your email Address ',
' subject ' => ' subject ',
' body ' => ' Content ',
];
}
When applying support for multiple languages, you can translate attribute labels, which can be defined in the Yii\base\model::attributelabels () method, as follows:
Public Function Attributelabels ()
{return
[
' name ' => \yii::t (' app ', ' Your name '),
' email ' = > \yii::t (' app ', ' Your email address '),
' Subject ' => \yii::t (' app ', ' Subject '),
' body ' => \yii::t (' App ', ' Content '),
];
}
You can even define labels based on criteria, such as using the scenario scene of the model to return different labels to the same property.
Add: The attribute label is part of the view, but it is usually very convenient to declare the label in the model, and it can be very concise and reusable code.
Scene
The model may be used in multiple scenarios, such as user modules that may be collected from users, or may be used when the user registers. In different scenarios, the model may use different business rules and logic, for example, the email attribute is mandatory when registering, but not required when landing.
The model uses the Yii\base\model::scenario property to keep track of the use of the scene, by default, the model supports a scenario named default, which shows two ways to set up a scenario:
Scene as a property to set
$model = new User;
$model->scenario = ' login ';
The scenario is set
$model = new User ([' Scenario ' => ' login ') by constructing the initialization configuration;
By default, the scenario supported by the model is determined by the validation rules declared in the model, but you can customize the behavior by overriding the Yii\base\model::scenarios () method, as follows:
namespace App\models;
Use Yii\db\activerecord;
Class User extends ActiveRecord
{public
function scenarios ()
{return
[
' login ' => ['] Username ', ' password '],
' register ' => [' username ', ' email ', ' password '],
];
}
Add: In the above and the following examples, model classes are inherited Yii\db\activerecord because the use of multiple scenarios usually occurs in the active record class.
The scenarios () method returns an array whose key is the scene name, and the value is the corresponding active attributes activity property. Activity properties can be assigned to blocks and follow validation rules in the above example, username and password are enabled in the login scenario, and in the register scenario, the email is enabled except for username and password.
The default implementation of the scenarios () method returns the scene from all the validation rules declared by the Yii\base\model::rules () method, and when the scenarios () is overwritten, if you want to use the new scene outside the default scenario, you can write a code similar to the following:
namespace App\models;
Use Yii\db\activerecord;
Class User extends ActiveRecord
{public
function scenarios ()
{
$scenarios = Parent::scenarios ();
$scenarios [' login '] = [' username ', ' password '];
$scenarios [' register '] = [' username ', ' email ', ' password '];
return $scenarios;
}
Scene features are used primarily in validation and attribute block assignments. You can also use it for other purposes, for example, to define different attribute labels based on different scenarios.
Validation rules
When the model receives data entered by the end user, the data should satisfy a rule (called a validation rule, also known as a business rule). For example, assuming the Contactform model, you may want to make sure that all attributes are not empty and that the email attribute contains a valid mailbox address, and if the value of a property does not meet the corresponding business rules, the corresponding error message should be displayed to help the user fix the error.
You can call Yii\base\model::validate () to validate the received data, which validates each related property by using the validation rules of Yii\base\model::rules (), and returns True if no errors are found. Otherwise, it will save the error in the Yii\base\model::errors property and return False, for example:
$model = new \app\models\contactform;
The user input data is assigned to the Model property
$model->attributes = \yii:: $app->request->post (' contactform ');
if ($model->validate ()) {//
all input data is valid all inputs are valid
} else {
//validation failed: $errors is an array containing error messages
$err ORS = $model->errors;
}
Declare the model-related validation rules by overriding the Yii\base\model::rules () method to specify the rules that the model properties should meet. The following example shows the validation rules for the Contactform model declaration:
Public function rules ()
{return
[
//name, email, subject, and the Body property must have a value
[[' Name ', ' email ', ' subject ', ' bo Dy '], ' required '],
//Email attribute must be a valid email address
[' email ', ' email '],
];
}
A rule can be used to validate one or more properties, and one property may correspond to one or more rules. For more information on how to declare validation rules, please refer to the Validation input section.
Sometimes you want a rule to be applied only in a scenario, for which you can specify the on attribute of the rule, as follows:
Public function rules ()
{return
[
//username in the Register], email and password must have a value
[[' Username ', ' Email ', ' password '], ' required ', ' on ' => ' register ',
//In the "Login" scenario username and password must have a value
[[' Username '], ' Password '], ' required ', ' on ' => ' login ',
];
}
If the on attribute is not specified, the rule is applied in all scenarios, and the rules applied under the current Yii\base\model::scenario are called active rule activity rules.
A property belongs only to the activity attribute defined in scenarios () and is validated if the rules () affirm the corresponding one or more active rule.
Block Assignment
Block assignment fills all the input of a user into a model with just one line of code, and it is convenient to fill the input data directly into the Yii\base\model::attributes property. The following two snippets of code are the same, assigning the form data entered by the end-user to the properties of the Contactform model, and the code that is obviously assigned to the previous block is simpler and less error-prone than the latter piece of code.
$model = new \app\models\contactform;
$model->attributes = \yii:: $app->request->post (' contactform ');
$model = new \app\models\contactform;
$data = \yii:: $app->request->post (' contactform ', []);
$model->name = isset ($data [' name '])? $data [' name ']: null;
$model->email = isset ($data [' email '])? $data [' email ']: null;
$model->subject = isset ($data [' Subject '])? $data [' subject ']: null;
$model->body = isset ($data [' body '])? $data [' body ']: null;
Security properties
Block assignment applies only to attributes that are called security attributes listed in the model's current Yii\base\model::scenario scenario Yii\base\model::scenarios () method, for example, if the user model affirms the following scenario, When the current scene is login, only username and password can be assigned to the block, and other properties are not assigned values.
Public function Scenarios ()
{return
['
login ' => [' username ', ' password '],
' register ' => [' Username ', ' email ', ' password '],
];
Supplemental: Block assignment applies only to security attributes, because you want to control which properties are modified by the end-user input data, for example, if the user model has a permission attribute that corresponds to the users ' permissions, you may want to allow this property to be modified by the administrator in the background interface.
Because the default Yii\base\model::scenarios () implementation returns all properties and data for Yii\base\model::rules (), if this method is not overridden, all properties that appear in the active validation rule are safe.
To do this, provide a special alias for safe Validator to declare which properties are safe and do not need to be validated, and the following example rules declare title and description as security attributes.
Public Function rules () {return [[
' title ', ' description '], ' safe '],
];
}
Non-security properties
As mentioned above, the Yii\base\model::scenarios () method provides two uses: Define which properties should be validated, and which attributes are safe to define. In some cases, you may want to verify a property but do not want him to be safe, and add an exclamation point to the attribute name in the scenarios () Method!. For example, secret properties like the following.
Public function Scenarios ()
{return
[
' login ' => [' username ', ' password ', '!secret '],
];
}
When the model is in the login scenario, three properties are validated, but only the username and password attributes are assigned to the block, and assigning values to the Secret property must be explicitly assigned to it as shown in the following example.
$model->secret = $secret;
Data export
Models are usually exported into different formats, for example, you might want to convert a collection of models into JSON or Excel format, and the export process can be decomposed into two steps, the first step, the model to transform the array, and the second step, the arrays are converted to the desired format. You only need to focus on the first step, because the second step can be done by a general-purpose data converter such as Yii\web\jsonresponseformatter.
The easiest way to convert a model to an array is to use the Yii\base\model::attributes property, for example:
$post = \app\models\post::findone (m);
$array = $post->attributes;
The Yii\base\model::attributes property returns the value of all yii\base\model::attributes () declared properties.
A more flexible and powerful way to convert a model to an array is to use the Yii\base\model::toarray () method, which defaults to the same behavior as Yii\base\model::attributes, But it allows you to select which items, called fields, are put into the result array and formatted at the same time. In fact, it is the default method for exporting the model to RESTful Web service development, see the response format.
Field
A field is the cell name of an array that the model generates by calling Yii\base\model::toarray ().
By default, the field name corresponds to the property name, but you can change this behavior by overwriting the Yii\base\model::fields () and/or Yii\base\model::extrafields () methods, and two methods return a list of field definitions. The field defined by the fields () method is the default field, which means that the ToArray () method returns these fields by default. The Extrafields () method defines the additional available fields, and the ToArray () method specifies the $expand parameter to return these additional fields. For example, the following code returns all the fields defined by the fields () method and the Prettyname and Fulladdress fields defined by the Extrafields () method.
$array = $model->toarray ([], [' Prettyname ', ' fulladdress ']);
You can add, delete, rename, and fields by overriding fields (), fields () method return values should be arrays, the array's keys are field names, and the values of the array are corresponding values for the fields that can be returned for the property name or anonymous function. In the case of a special envoy, you can omit the array key if the field name and the property definition name are the same, for example:
Explicitly list each field, especially if you want to make sure that the data table or model attribute changes do not cause your field to change (ensure backend API compatibility).
Public function fields ()
{return
[
//Field name and property name same
' id ',
//Field name ' email ', corresponding property name ' Email_address '
' email ' => ' email_address ',
//Field name ' name ', value returned through PHP code
' name ' => function () {return
$this-> First_Name. ' ' . $this->last_name;
},
];
}
Filter out some fields, especially if you want to inherit the parent class implementation does not want to use some sensitive fields public
function fields ()
{
$fields = Parent::fields ();
Remove some fields that contain sensitive information
unset ($fields [' Auth_key '], $fields [' Password_hash '], $fields [' Password_reset_token ']);
return $fields;
}
Warning: Because all properties of the model are included in the exported array, it is best to check the data to ensure that no sensitive data is included, and if sensitive data should be covered by the fields () method to filter it out, in the above Liezi we choose to filter out Auth_key, Password_hash and password _reset_token.
Best Practices
A model is a central place that represents business data, rules, and logic, and is often reused in many places, and in a well-designed application, the model is usually more than the controller code.
To sum up, the model:
- Can contain attributes to show business data;
- Validation rules can be included to ensure that the data is valid and complete;
- Can include methods to implement business logic;
- Requests, sessions, and other environmental data should not be directly accessed, which should be passed into the model by the Controller;
- Avoid embedding HTML or other presentation code, which is best handled in the view;
- Avoid too many scenes in a single model.
The last piece of advice should always be considered when developing large and complex systems, in these systems, the model will be large and used in many places, so it will contain the need for rule sets and business logic, and finally maintain the model code as a nightmare, because a simple modification can affect many places, and to ensure that the model is well maintained, it is best to use the following strategies:
Defines a collection of model base classes that can be shared by multiple application principals or modules. These model classes should contain a common minimum set of rules and logic.
In each application body or module that uses the model, the specific model class is defined by inheriting the corresponding model base class, which contains the rules and logic specified by the application principal or module.
For example, in the Advanced application template, you can define a model base class Common\models\post, and then in the foreground application, define and use a specific model class Frontend\models\post that inherits Common\models\post, Backend\models\post can be defined similarly in a background application. With this strategy, you know that frontend\models\post only corresponds to the foreground application, and if you modify it, there is no need to worry that the changes will affect the background application.