• No results found

MODELS 81 a permission attribute which determines the permission assigned

In document yii2-guide.en.pdf (Page 87-93)

Application Structure

3.6. MODELS 81 a permission attribute which determines the permission assigned

to the user, you would like this attribute to be modiable by administrators through a backend interface only.

Because the default implementation of yii\base\Model::scenarios() will return all scenarios and attributes found in yii\base\Model::rules(), if you do not override this method, it means an attribute is safe as long as it appears in one of the active validation rules.

For this reason, a special validator aliasedsafeis provided so that you can declare an attribute to be safe without actually validating it. For example, the following rules declare that bothtitleanddescriptionare safe attributes.

public function rules() { return [

[['title', 'description'], 'safe'], ];

}

Unsafe Attributes

As described above, the yii\base\Model::scenarios() method serves for two purposes: determining which attributes should be validated, and de-termining which attributes are safe. In some rare cases, you may want to validate an attribute but do not want to mark it safe. You can do so by prexing an exclamation mark!to the attribute name when declaring it in

scenarios(), like thesecret attribute in the following:

public function scenarios() {

return [

'login' => ['username', 'password', '!secret'], } ];

When the model is in theloginscenario, all three attributes will be validated.

However, only theusernameandpasswordattributes can be massively assigned.

To assign an input value to thesecret attribute, you have to do it explicitly as follows,

$model->secret = $secret;

3.6.5 Data Exporting

Models often need to be exported in dierent formats. For example, you may want to convert a collection of models into JSON or Excel format. The exporting process can be broken down into two independent steps. In the

rst step, models are converted into arrays; in the second step, the arrays are converted into target formats. You may just focus on the rst step, because

82 CHAPTER 3. APPLICATION STRUCTURE the second step can be achieved by generic data formatters, such as yii\web

\JsonResponseFormatter.

The simplest way of converting a model into an array is to use the yii

\base\Model::$attributes property. For example,

$post = \app\models\Post::findOne(100);

$array = $post->attributes;

By default, the yii\base\Model::$attributes property will return the val-ues of all attributes declared in yii\base\Model::attributes().

A more exible and powerful way of converting a model into an array is to use the yii\base\Model::toArray() method. Its default behavior is the same as that of yii\base\Model::$attributes. However, it allows you to choose which data items, called elds, to be put in the resulting array and how they should be formatted. In fact, it is the default way of exporting models in RESTful Web service development, as described in the Response Formatting.

Fields

A eld is simply a named element in the array that is obtained by calling the yii\base\Model::toArray() method of a model.

By default, eld names are equivalent to attribute names. However, you can change this behavior by overriding the fields() and/or extraFields() methods. Both methods should return a list of eld denitions. The elds dened byfields()are default elds, meaning thattoArray()will return these

elds by default. The extraFields() method denes additionally available

elds which can also be returned by toArray() as long as you specify them via the $expand parameter. For example, the following code will return all

elds dened infields()and theprettyNameand fullAddresselds if they are dened inextraFields().

$array = $model->toArray([], ['prettyName', 'fullAddress']);

You can override fields() to add, remove, rename or redene elds. The return value of fields() should be an array. The array keys are the eld names, and the array values are the corresponding eld denitions which can be either property/attribute names or anonymous functions returning the corresponding eld values. In the special case when a eld name is the same as its dening attribute name, you can omit the array key. For example,

// explicitly list every field, best used when you want to make sure the changes

// in your DB table or model attributes do not cause your field changes (to keep API backward compatibility).

public function fields() {

return [

// field name is the same as the attribute name

3.6. MODELS 83

'id',

// field name is "email", the corresponding attribute name is "

email_address"

'email' => 'email_address',

// field name is "name", its value is defined by a PHP callback 'name' => function () {

return $this->first_name . ' ' . $this->last_name;

}, } ];

// filter out some fields, best used when you want to inherit the parent implementation

// and blacklist some sensitive fields.

public function fields() { $fields = parent::fields();

// remove fields that contain sensitive information

unset($fields['auth_key'], $fields['password_hash'], $fields[' password_reset_token']);

return $fields;

}

Warning: Because by default all attributes of a model will be included in the exported array, you should examine your data to make sure they do not contain sensitive information. If there is such information, you should override fields() to lter them out. In the above example, we choose to lter out auth_key,

password_hashand password_reset_token. 3.6.6 Best Practices

Models are the central places to represent business data, rules and logic.

They often need to be reused in dierent places. In a well-designed applica-tion, models are usually much fatter than controllers.

In summary, models

• may contain attributes to represent business data;

• may contain validation rules to ensure the data validity and integrity;

• may contain methods implementing business logic;

• should NOT directly access request, session, or any other environmen-tal data. These data should be injected by controllers into models;

• should avoid embedding HTML or other presentational code - this is better done in views;

• avoid having too many scenarios in a single model.

84 CHAPTER 3. APPLICATION STRUCTURE You may usually consider the last recommendation above when you are de-veloping large complex systems. In these systems, models could be very fat because they are used in many places and may thus contain many sets of rules and business logic. This often ends up in a nightmare in maintaining the model code because a single touch of the code could aect several dier-ent places. To make the model code more maintainable, you may take the following strategy:

• Dene a set of base model classes that are shared by dierent applica-tions or modules. These model classes should contain minimal sets of rules and logic that are common among all their usages.

• In each application or module that uses a model, dene a concrete model class by extending from the corresponding base model class.

The concrete model classes should contain rules and logic that are specic for that application or module.

For example, in the Advanced Project Template12, you may dene a base model classcommon\models\Post. Then for the front end application, you

de-ne and use a concrete model classfrontend\models\Postwhich extends from

common\models\Post. And similarly for the back end application, you dene

backend\models\Post. With this strategy, you will be sure that the code in

frontend\models\Post is only specic to the front end application, and if you make any change to it, you do not need to worry if the change may break the back end application.

3.7 Views

Views are part of the MVC13 architecture. They are code responsible for presenting data to end users. In a Web application, views are usually created in terms of view templates which are PHP script les containing mainly HTML code and presentational PHP code. They are managed by the view application component which provides commonly used methods to facilitate view composition and rendering. For simplicity, we often call view templates or view template les as views.

3.7.1 Creating Views

As aforementioned, a view is simply a PHP script mixed with HTML and PHP code. The following is the view that presents a login form. As you can see, PHP code is used to generate the dynamic content, such as the page title and the form, while HTML code organizes them into a presentable HTML page.

12https://github.com/yiisoft/yii2-app-advanced/blob/master/docs/guide/

README.md

13http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller

3.7. VIEWS 85

<?php

use yii\helpers\Html;

use yii\widgets\ActiveForm;

/* @var $this yii\web\View */

/* @var $form yii\widgets\ActiveForm */

/* @var $model app\models\LoginForm */

$this->title = 'Login';

?>

<h1><?= Html::encode($this->title) ?></h1>

<p>Please fill out the following fields to login:</p>

<?php $form = ActiveForm::begin(); ?>

<?= $form->field($model, 'username') ?>

<?= $form->field($model, 'password')->passwordInput() ?>

<?= Html::submitButton('Login') ?>

<?php ActiveForm::end(); ?>

Within a view, you can access $this which refers to the view component managing and rendering this view template.

Besides $this, there may be other predened variables in a view, such as$model in the above example. These variables represent the data that are pushed into the view by controllers or other objects which trigger the view rendering.

Tip: The predened variables are listed in a comment block at beginning of a view so that they can be recognized by IDEs. It is also a good way of documenting your views.

Security

When creating views that generate HTML pages, it is important that you encode and/or lter the data coming from end users before presenting them.

Otherwise, your application may be subject to cross-site scripting14 attacks.

To display a plain text, encode it rst by calling yii\helpers\Html::

encode(). For example, the following code encodes the user name before displaying it:

<?php

use yii\helpers\Html;

?>

<div class="username">

<?= Html::encode($user->name) ?>

</div>

14http://en.wikipedia.org/wiki/Cross-site_scripting

86 CHAPTER 3. APPLICATION STRUCTURE To display HTML content, use yii\helpers\HtmlPurifier to lter the con-tent rst. For example, the following code lters the post concon-tent before displaying it:

<?php

use yii\helpers\HtmlPurifier;

?>

<div class="post">

<?= HtmlPurifier::process($post->text) ?>

</div>

Tip: While HTMLPurier does excellent job in making output safe, it is not fast. You should consider caching the ltering result if your application requires high performance.

Organizing Views

Like controllers and models, there are conventions to organize views.

• For views rendered by a controller, they should be put under the di-rectory@app/views/ControllerIDby default, whereControllerIDrefers to the controller ID. For example, if the controller class isPostController, the directory would be @app/views/post; If it is PostCommentController, the directory would be @app/views/post-comment. In case the controller belongs to a module, the directory would beviews/ControllerID under the module directory.

• For views rendered in a widget, they should be put under theWidgetPath /views directory by default, where WidgetPath stands for the directory containing the widget class le.

• For views rendered by other objects, it is recommended that you follow the similar convention as that for widgets.

You may customize these default view directories by overriding the yii\base

\ViewContextInterface::getViewPath() method of controllers or widgets.

3.7.2 Rendering Views

You can render views in controllers, widgets, or any other places by calling view rendering methods. These methods share a similar signature shown as follows,

/*** @param string $view view name or file path, depending on the actual rendering method

* @param array $params the data to be passed to the view

* @return string rendering result

*/

methodName($view, $params = [])

3.7. VIEWS 87

In document yii2-guide.en.pdf (Page 87-93)