diff --git a/docs/guide-zh-CN/db-active-record.md b/docs/guide-zh-CN/db-active-record.md
index 36b3df3..109b264 100644
--- a/docs/guide-zh-CN/db-active-record.md
+++ b/docs/guide-zh-CN/db-active-record.md
@@ -16,7 +16,7 @@ Active Record
```php
$customer = new Customer();
-$customer->name = '李狗蛋';
+$customer->name = 'Qiang';
$customer->save(); // 一行新数据插入 customer 表
```
@@ -25,7 +25,7 @@ $customer->save(); // 一行新数据插入 customer 表
```php
$db->createCommand('INSERT INTO customer (name) VALUES (:name)', [
- ':name' => '李狗蛋',
+ ':name' => 'Qiang',
])->execute();
```
@@ -87,7 +87,7 @@ $email = $customer->email;
要改变列值,只要给关联属性赋新值并保存对象即可:
```php
-$customer->email = '哪吒@example.com';
+$customer->email = 'james@example.com';
$customer->save();
```
@@ -429,7 +429,7 @@ class Customer extends \yii\db\ActiveRecord
`hasMany()` 返回 [[yii\db\ActiveQuery]] 对象,该对象允许你通过
[[yii\db\ActiveQuery]] 方法定制查询。
-如上声明后,执行`$customer->bigOrders` 就返回
+如上声明后,执行 `$customer->bigOrders` 就返回
总额大于100的订单。使用以下代码更改设定值:
```php
diff --git a/docs/guide-zh-CN/db-dao.md b/docs/guide-zh-CN/db-dao.md
index 1fb8e2a..72e50e9 100644
--- a/docs/guide-zh-CN/db-dao.md
+++ b/docs/guide-zh-CN/db-dao.md
@@ -43,9 +43,9 @@ return [
请参考PHP manual获取更多有关 DSN 格式信息。
配置连接组件后可以使用以下语法访问:
-```$connection = \Yii::$app->db;```
+`$connection = \Yii::$app->db;`
-请参考```[[yii\db\Connection]]```获取可配置的属性列表。
+请参考`[[yii\db\Connection]]`获取可配置的属性列表。
如果你想通过ODBC连接数据库,则需要配置[[yii\db\Connection::driverName]] 属性,例如:
```
@@ -129,12 +129,14 @@ $command = $connection->createCommand('SELECT * FROM post');
$posts = $command->queryAll();
```
返回单行:
+
```
$command = $connection->createCommand('SELECT * FROM post WHERE id=1');
$post = $command->queryOne();
```
查询多行单值:
+
```
$command = $connection->createCommand('SELECT title FROM post');
$titles = $command->queryColumn();
diff --git a/docs/guide-zh-CN/helper-array.md b/docs/guide-zh-CN/helper-array.md
index 357a2e7..a2a69ef 100755
--- a/docs/guide-zh-CN/helper-array.md
+++ b/docs/guide-zh-CN/helper-array.md
@@ -1,12 +1,15 @@
-ArrayHelper(数组辅助类)
+数组助手类
===========
-除了[PHP中丰富的数组函数集](http://php.net/manual/zh/book.array.php),Yii 数组辅助类提供了额外的静态方法,让你更高效地处理数组。
+除了[PHP中丰富的数组函数集](http://php.net/manual/zh/book.array.php),
+Yii 数组助手类提供了额外的静态方法,让你更高效地处理数组。
## 获取值
-用原生PHP从一个对象、数组、或者包含这两者的一个复杂数据结构中获取数据是非常繁琐的。你首先得使用`isset` 检查key是否存在, 然后如果存在你就获取它,如果不存在,则提供一个默认返回值:
+用原生PHP从一个对象、数组、或者包含这两者的一个复杂数据结构中获取数据是非常繁琐的。
+你首先得使用`isset` 检查 key 是否存在, 然后如果存在你就获取它,如果不存在,
+则提供一个默认返回值:
```php
class User
@@ -23,13 +26,14 @@ $array = [
$value = isset($array['foo']['bar']->name) ? $array['foo']['bar']->name : null;
```
-Yii 提供了一个非常方便的方法来做这件事:
+Yii 提供了一个非常方便的方法来做这件事:
```php
$value = ArrayHelper::getValue($array, 'foo.bar.name');
```
-方法的第一个参数是我们从哪里获取值。第二个参数指定了如何获取数据,它可以是下述几种类型中的一个:
+方法的第一个参数是我们从哪里获取值。第二个参数指定了如何获取数据,
+它可以是下述几种类型中的一个:
- 数组键名或者欲从中取值的对象的属性名称;
- 以点号分割的数组键名或者对象属性名称组成的字符串,上例中使用的参数类型就是该类型;
@@ -43,7 +47,7 @@ $fullName = ArrayHelper::getValue($user, function ($user, $defaultValue) {
});
```
-第三个可选的参数如果没有给定值,则默认为`null` ,如下例所示:
+第三个可选的参数如果没有给定值,则默认为 `null`,如下例所示:
```php
$username = ArrayHelper::getValue($comment, 'user.username', 'Unknown');
@@ -56,7 +60,8 @@ $array = ['type' => 'A', 'options' => [1, 2]];
$type = ArrayHelper::remove($array, 'type');
```
-执行了上述代码之后, `$array` 将包含 `['options' => [1, 2]]` 并且 `$type` 将会是 `A` 。注意和 `getValue` 方法不同的是, `remove` 方法只支持简单键名。
+执行了上述代码之后, `$array` 将包含 `['options' => [1, 2]]` 并且 `$type` 将会是 `A` 。
+注意和 `getValue` 方法不同的是,`remove` 方法只支持简单键名。
## 检查键名的存在
@@ -90,9 +95,10 @@ $data = [
$ids = ArrayHelper::getColumn($array, 'id');
```
-结果将是 `['123', '345']`.
+结果将是 `['123', '345']`。
-如果需要额外的转换或者取值的方法比较复杂,第二参数可以指定一个匿名函数:
+如果需要额外的转换或者取值的方法比较复杂,
+第二参数可以指定一个匿名函数:
```php
$result = ArrayHelper::getColumn($array, function ($element) {
@@ -103,10 +109,11 @@ $result = ArrayHelper::getColumn($array, function ($element) {
## 重建数组索引
-按一个指定的键名重新索引一个数组,可以用 `index` 方法。输入的数组应该是多维数组或者是一个对象数组。键名(译者注:第二个参数)可以是子数组
-的键名、对象的属性名,也可以是一个返回给定元素数组键值的匿名函数。
+按一个指定的键名重新索引一个数组,可以用 `index` 方法。输入的数组应该是多维数组或者是一个对象数组。
+键名(译者注:第二个参数)可以是子数组的键名、对象的属性名,
+也可以是一个返回给定元素数组键值的匿名函数。
-如果一个键值(译者注:第二个参数对应的值)是null,相应的数组元素将被丢弃并且不会放入到结果中,例如,
+如果一个键值(译者注:第二个参数对应的值)是 null,相应的数组元素将被丢弃并且不会放入到结果中,例如,
```php
$array = [
@@ -129,8 +136,8 @@ $result = ArrayHelper::index($array, function ($element) {
## 建立哈希表
-
-为了从一个多维数组或者一个对象数组中建立一个映射表(键值对),你可以使用`map`方法.`$from` 和 `$to` 参数分别指定了欲构建的映射表的键名和属性名。
+为了从一个多维数组或者一个对象数组中建立一个映射表(键值对),你可以使用
+`map`方法.`$from` 和 `$to` 参数分别指定了欲构建的映射表的键名和属性名。
根据需要,你可以按照一个分组字段 `$group` 将映射表进行分组,例如。
```php
@@ -185,7 +192,8 @@ ArrayHelper::multisort($data, ['age', 'name'], [SORT_ASC, SORT_DESC]);
];
```
-第二个参数指定排序的键名,如果是单键名的话可以是字符串,如果是多键名则是一个数组,或者是如下例所示的一个匿名函数:
+第二个参数指定排序的键名,如果是单键名的话可以是字符串,如果是多键名则是一个数组,
+或者是如下例所示的一个匿名函数:
```php
ArrayHelper::multisort($data, function($item) {
@@ -193,13 +201,16 @@ ArrayHelper::multisort($data, function($item) {
});
```
-第三个参数表示增降顺序。单键排序时,它可以是`SORT_ASC`或者`SORT_DESC`之一。如果是按多个键名排序,你可以用一个数组为各个键指定不同的顺序。
+第三个参数表示增降顺序。单键排序时,它可以是 `SORT_ASC` 或者 `SORT_DESC` 之一。
+如果是按多个键名排序,你可以用一个数组为各个键指定不同的顺序。
-最后一个参数(译者注:第四个参数)是PHP的排序标识(sort flag),可使用的值和调用PHP[sort()](http://php.net/manual/zh/function.sort.php) 函数时传递的值一样。
-## 检测数组类型
+最后一个参数(译者注:第四个参数)是PHP的排序标识(sort flag),可使用的值和调用PHP
+[sort()](http://php.net/manual/zh/function.sort.php) 函数时传递的值一样。
+## 检测数组类型
+
想知道一个数组是索引数组还是联合数组很方便,这有个例子:
```php
@@ -222,29 +233,34 @@ $encoded = ArrayHelper::htmlEncode($data);
$decoded = ArrayHelper::htmlDecode($data);
```
-默认情况只会对值做编码(译者注:原文中是编码,应为编解码)。通过给第二个参数传 `false` ,你也可以对键名做编码。编码将默认使用应用程序的字符集,
-你可以通过第三个参数指定该字符集。
+默认情况只会对值做编码(译者注:原文中是编码,应为编解码)。通过给第二个参数传 `false` ,你也可以对键名做编码。
+编码将默认使用应用程序的字符集,你可以通过第三个参数指定该字符集。
-## 合并数组
+## 合并数组
```php
/**
- * 将两个或者多个数组递归式的合并为要贯彻。
- * 如果每个数组有一个元素的键名相同,那么后面元素的将覆盖前面的元素(不同于 array_merge_recursive)。
- * 如果两个数组都有相同键名的数组元素(译者注:嵌套数组)则将引发递归合并。
+ * 将两个或者多个数组递归式的合并为一个数组。
+ * 如果每个数组有一个元素的键名相同,
+ * 那么后面元素的将覆盖前面的元素(不同于 array_merge_recursive)。
+ * 如果两个数组都有相同键名的数组元素(译者注:嵌套数组)
+ * 则将引发递归合并。
* 对数值型键名的元素,后面数组中的这些元素会被追加到前面数组中。
* @param array $a 被合并的数组
- * @param array $b 合并的数组,你可以在第三、第四个参数中指定另外的合并数组,等等
+ * @param array $b 合并的数组,你可以在第三、第四个
+ * 参数中指定另外的合并数组,等等
* @return 合并的结果数组 (原始数组不会被改变)
*/
public static function merge($a, $b)
```
+
## 对象转换为数组
-你经常要将一个对象或者对象的数组转换成一个数组,常见的情形是,为了通过REST API提供数据数组(或其他使用方式),将AR模型(活动记录模型)转换成数组。如下代码可完成这个工作:
+你经常要将一个对象或者对象的数组转换成一个数组,常见的情形是,为了通过REST API提供数据数组(或其他使用方式),
+将AR模型(活动记录模型)转换成数组。如下代码可完成这个工作:
```php
$posts = Post::find()->limit(10)->all();
@@ -262,16 +278,17 @@ $data = ArrayHelper::toArray($posts, [
]);
```
-第一个参数包含我们想要转换的数据,在本例中,我们要转换一个叫 `Post` 的 AR 模型.
+第一个参数包含我们想要转换的数据,在本例中,我们要转换一个叫 `Post` 的 AR 模型。
-第二个参数是每个类的转换映射表,我们在此设置了一个`Post` 模型的映射.
-每个映射数组包含一组的映射,每个映射可以是:
+第二个参数是每个类的转换映射表,我们在此设置了一个`Post` 模型的映射。
+每个映射数组包含一组的映射,每个映射可以是:
- 一个要包含的照原样的字段名(和类中属性的名称一致);
- 一个由你可随意取名的键名和你想从中取值的模型列名组成的键值对;
- 一个由你可随意取名的键名和有返回值的回调函数组成的键值对;
-这上面的转换结果将会是:
+这上面的转换结果将会是:
+
```php
[
@@ -281,4 +298,6 @@ $data = ArrayHelper::toArray($posts, [
'length' => 301,
]
```
-也可以在一个特定的类中实现[[yii\base\Arrayable|Arrayable]]接口,从而为其对象提供默认的转换成数组的方法。
+
+也可以在一个特定的类中实现[[yii\base\Arrayable|Arrayable]]接口,
+从而为其对象提供默认的转换成数组的方法。
diff --git a/docs/guide-zh-CN/input-file-upload.md b/docs/guide-zh-CN/input-file-upload.md
new file mode 100755
index 0000000..eabbed5
--- /dev/null
+++ b/docs/guide-zh-CN/input-file-upload.md
@@ -0,0 +1,204 @@
+文件上传
+============
+
+在Yii里上传文件通常使用[[yii\web\UploadedFile]]类,
+它把每个上传的文件封装成 `UploadedFile` 对象。
+结合[[yii\widgets\ActiveForm]]和[models](structure-models.md),你可以轻松实现安全的上传文件机制。
+
+
+##创建模型
+
+和普通的文本输入框类似,当要上传一个文件时,你需要创建一个模型类并且用其中的某个属性来接收上传的文件实例。
+你还需要声明一条验证规则以验证上传的文件。
+举例来讲,
+
+```php
+namespace app\models;
+
+use yii\base\Model;
+use yii\web\UploadedFile;
+
+class UploadForm extends Model
+{
+ /**
+ * @var UploadedFile
+ */
+ public $imageFile;
+
+ public function rules()
+ {
+ return [
+ [['imageFile'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg'],
+ ];
+ }
+
+ public function upload()
+ {
+ if ($this->validate()) {
+ $this->imageFile->saveAs('uploads/' . $this->imageFile->baseName . '.' . $this->imageFile->extension);
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
+```
+
+在以上代码里,`imageFile` 属性用于接收上传的文件实例。它对应一条`file` 验证规则,
+该规则使用 [[yii\validators\FileValidator]] 来确保只上传扩展名为 `png` 或 `jpg` 的文件。
+`upload()` 方法会执行该验证并且把上传的文件保存在服务器上。
+
+通过 `file` 验证器,你可以检查文件的扩展名,大小,MIME类型等等。详情请查阅
+[Core Validatators](tutorial-core-validators.md#file) 章节。
+
+>提示: 如果你要上传的是一张图片,可以考虑使用`image`验证器。
+`image` 验证器是通过[[yii\validators\ImageValidator]]实现验证的,确保对应的模型属性
+收到的文件是有效的图片文件,然后才保存,或者使用扩展类[Imagine Extension](https://github.com/yiisoft/yii2-imagine)进行处理.
+
+
+##渲染文件输入
+
+接下来,在视图里创建一个文件输入控件
+
+```php
+
+
+ ['enctype' => 'multipart/form-data']]) ?>
+
+ = $form->field($model, 'imageFile')->fileInput() ?>
+
+
+
+
+```
+
+需要注意的是要记得在表单选项里加入 `enctype` 属性以确保文件能被正常上传。
+`fileInput()` 方法会渲染一个 `` 标签,让用户可以选择一个文件上传。
+
+
+## 视图和模型的连接
+
+现在,在控制器方法里编写连接模型和视图的代码以实现文件上传。
+
+```php
+namespace app\controllers;
+
+use Yii;
+use yii\web\Controller;
+use app\models\UploadForm;
+use yii\web\UploadedFile;
+
+class SiteController extends Controller
+{
+ public function actionUpload()
+ {
+ $model = new UploadForm();
+
+ if (Yii::$app->request->isPost) {
+ $model->imageFile = UploadedFile::getInstance($model, 'imageFile');
+ if ($model->upload()) {
+ // 文件上传成功
+ return;
+ }
+ }
+
+ return $this->render('upload', ['model' => $model]);
+ }
+}
+```
+
+在上面的代码里,当提交表单的时候,[[yii\web\UploadedFile::getInstance()]]方法就被调用,
+上传的文件用一个 `UploadedFile` 实例表示。然后,我们依靠模型的验证规则确保上传的文件是有效的,
+并将文件保存在服务器上。
+
+
+## 上传多个文件
+
+将前面所述的代码做一些调整,也可以一次性上传多个文件。
+
+首先你得调整模型类,在 `file` 验证规则里增加一个 `maxFiles` 选项,用以限制一次上传文件的最大数量。
+`upload()`方法也得修改,
+以便一个一个地保存上传的文件。
+
+```php
+namespace app\models;
+
+use yii\base\Model;
+use yii\web\UploadedFile;
+
+class UploadForm extends Model
+{
+ /**
+ * @var UploadedFile[]
+ */
+ public $imageFiles;
+
+ public function rules()
+ {
+ return [
+ [['imageFiles'], 'file', 'skipOnEmpty' => false, 'extensions' => 'png, jpg', 'maxFiles' => 4],
+ ];
+ }
+
+ public function upload()
+ {
+ if ($this->validate()) {
+ foreach ($this->imageFiles as $file) {
+ $file->saveAs('uploads/' . $file->baseName . '.' . $file->extension);
+ }
+ return true;
+ } else {
+ return false;
+ }
+ }
+}
+```
+
+在视图文件里,你需要把 `multiple` 选项添加到`fileInput()`函数调用里,
+这样文件输入控件就可以接收多个文件。
+
+```php
+
+
+ ['enctype' => 'multipart/form-data']]) ?>
+
+ = $form->field($model, 'imageFiles[]')->fileInput(['multiple' => true, 'accept' => 'image/*']) ?>
+
+
+
+
+```
+
+最后,在控制器的 action 方法中,你应该调用 `UploadedFile::getInstances()` 而不是 `UploadedFile::getInstance()` 来把
+`UploadedFile` 实例数组赋值给 `UploadForm::imageFiles`。
+
+```php
+namespace app\controllers;
+
+use Yii;
+use yii\web\Controller;
+use app\models\UploadForm;
+use yii\web\UploadedFile;
+
+class SiteController extends Controller
+{
+ public function actionUpload()
+ {
+ $model = new UploadForm();
+
+ if (Yii::$app->request->isPost) {
+ $model->imageFiles = UploadedFile::getInstances($model, 'imageFiles');
+ if ($model->upload()) {
+ // 文件上传成功
+ return;
+ }
+ }
+
+ return $this->render('upload', ['model' => $model]);
+ }
+}
+```
diff --git a/docs/guide-zh-CN/input-validation.md b/docs/guide-zh-CN/input-validation.md
index ef9f3a5..78b2794 100644
--- a/docs/guide-zh-CN/input-validation.md
+++ b/docs/guide-zh-CN/input-validation.md
@@ -300,7 +300,7 @@ class MyForm extends Model
// 以匿名函数形式定义的行内验证器
['token', function ($attribute, $params) {
if (!ctype_alnum($this->$attribute)) {
- $this->addError($attribute, '令牌本身必须包含字母或数字。');
+ $this->addError($attribute, 'token 本身必须包含字母或数字。');
}
}],
];
@@ -308,8 +308,8 @@ class MyForm extends Model
public function validateCountry($attribute, $params)
{
- if (!in_array($this->$attribute, ['兲朝', '墙外'])) {
- $this->addError($attribute, '国家必须为 "兲朝" 或 "墙外" 中的一个。');
+ if (!in_array($this->$attribute, ['USA', 'Web'])) {
+ $this->addError($attribute, 'The country must be either "USA" or "Web".');
}
}
}
@@ -339,8 +339,8 @@ class CountryValidator extends Validator
{
public function validateAttribute($model, $attribute)
{
- if (!in_array($model->$attribute, ['兲朝', '墙外'])) {
- $this->addError($attribute, '国家必须为 "兲朝" 或 "墙外" 中的一个。');
+ if (!in_array($model->$attribute, ['USA', 'Web'])) {
+ $this->addError($attribute, 'The country must be either "USA" or "Web".');
}
}
}
diff --git a/docs/guide-zh-CN/security-authentication.md b/docs/guide-zh-CN/security-authentication.md
new file mode 100755
index 0000000..c5ba69e
--- /dev/null
+++ b/docs/guide-zh-CN/security-authentication.md
@@ -0,0 +1,215 @@
+认证
+==============
+
+认证是鉴定用户身份的过程。它通常使用一个标识符
+(如用户名或电子邮件地址)和一个加密令牌(比如密码或者存取令牌)来
+鉴别用户身份。认证是登录功能的基础。
+
+Yii提供了一个认证框架,它连接了不同的组件以支持登录。欲使用这个框架,
+你主要需要做以下工作:
+
+* 设置用户组件 [[yii\web\User|user]] ;
+* 创建一个类实现 [[yii\web\IdentityInterface]] 接口。
+
+
+## 配置 [[yii\web\User]]
+
+用户组件 [[yii\web\User|user]] 用来管理用户的认证状态。这需要你
+指定一个含有实际认证逻辑的认证类 [[yii\web\User::identityClass|identity class]]。
+在以下web应用的配置项中,将用户用户组件 [[yii\web\User|user]] 的
+认证类 [[yii\web\User::identityClass|identity class]] 配置成
+模型类 `app\models\User`, 它的实现将在下一节中讲述。
+
+```php
+return [
+ 'components' => [
+ 'user' => [
+ 'identityClass' => 'app\models\User',
+ ],
+ ],
+];
+```
+
+
+## 认证接口 [[yii\web\IdentityInterface]] 的实现
+
+认证类 [[yii\web\User::identityClass|identity class]] 必须实现包含以下方法的
+认证接口 [[yii\web\IdentityInterface]]:
+
+* [[yii\web\IdentityInterface::findIdentity()|findIdentity()]]:根据指定的用户ID查找
+ 认证模型类的实例,当你需要使用session来维持登录状态的时候会用到这个方法。
+* [[yii\web\IdentityInterface::findIdentityByAccessToken()|findIdentityByAccessToken()]]:根据指定的存取令牌查找
+ 认证模型类的实例,该方法用于
+ 通过单个加密令牌认证用户的时候(比如无状态的RESTful应用)。
+* [[yii\web\IdentityInterface::getId()|getId()]]:获取该认证实例表示的用户的ID。
+* [[yii\web\IdentityInterface::getAuthKey()|getAuthKey()]]:获取基于 cookie 登录时使用的认证密钥。
+ 认证密钥储存在 cookie 里并且将来会与服务端的版本进行比较以确保
+ cookie的有效性。
+* [[yii\web\IdentityInterface::validateAuthKey()|validateAuthKey()]] :是基于 cookie 登录密钥的
+验证的逻辑的实现。
+
+用不到的方法可以空着,例如,你的项目只是一个
+无状态的 RESTful 应用,只需实现 [[yii\web\IdentityInterface::findIdentityByAccessToken()|findIdentityByAccessToken()]]
+和 [[yii\web\IdentityInterface::getId()|getId()]] ,其他的方法的函数体留空即可。
+
+下面的例子是一个通过结合了 `user` 数据表的
+AR 模型 [Active Record](db-active-record.md) 实现的一个认证类 [[yii\web\User::identityClass|identity class]]。
+
+```php
+ $token]);
+ }
+
+ /**
+ * @return int|string 当前用户ID
+ */
+ public function getId()
+ {
+ return $this->id;
+ }
+
+ /**
+ * @return string 当前用户的(cookie)认证密钥
+ */
+ public function getAuthKey()
+ {
+ return $this->auth_key;
+ }
+
+ /**
+ * @param string $authKey
+ * @return boolean if auth key is valid for current user
+ */
+ public function validateAuthKey($authKey)
+ {
+ return $this->getAuthKey() === $authKey;
+ }
+}
+```
+
+如上所述,如果你的应用利用 cookie 登录,
+你只需要实现 `getAuthKey()` 和 `validateAuthKey()` 方法。这样的话,你可以使用下面的代码在
+`user` 表中生成和存储每个用户的认证密钥。
+
+```php
+class User extends ActiveRecord implements IdentityInterface
+{
+ ......
+
+ public function beforeSave($insert)
+ {
+ if (parent::beforeSave($insert)) {
+ if ($this->isNewRecord) {
+ $this->auth_key = \Yii::$app->security->generateRandomString();
+ }
+ return true;
+ }
+ return false;
+ }
+}
+```
+
+> 注意:不要混淆 `user` 认证类和用户组件 [[yii\web\User]]。前者是实现
+ 认证逻辑的类,通常用关联了
+ 持久性存储的用户信息的AR模型 [Active Record](db-active-record.md) 实现。后者是负责管理用户认证状态的
+ 应用组件。
+
+
+## 使用用户组件 [[yii\web\User]]
+
+在 `user` 应用组件方面,你主要用到 [[yii\web\User]] 。
+
+你可以使用表达式 `Yii::$app->user->identity` 检测当前用户身份。它返回
+一个表示当前登录用户的认证类 [[yii\web\User::identityClass|identity class]] 的实例,
+未认证用户(游客)则返回 null。下面的代码展示了如何从 [[yii\web\User]]
+获取其他认证相关信息:
+
+```php
+// 当前用户的身份实例。未认证用户则为 Null 。
+$identity = Yii::$app->user->identity;
+
+// 当前用户的ID。 未认证用户则为 Null 。
+$id = Yii::$app->user->id;
+
+// 判断当前用户是否是游客(未认证的)
+$isGuest = Yii::$app->user->isGuest;
+```
+
+你可以使用下面的代码登录用户:
+
+```php
+// 使用指定用户名获取用户身份实例。
+// 请注意,如果需要的话您可能要检验密码
+$identity = User::findOne(['username' => $username]);
+
+// 登录用户
+Yii::$app->user->login($identity);
+```
+
+[[yii\web\User::login()]] 方法将当前用户的身份登记到 [[yii\web\User]]。如果 session 设置为
+[[yii\web\User::enableSession|enabled]],则使用 session 记录用户身份,用户的
+认证状态将在整个会话中得以维持。如果开启自动登录 [[yii\web\User::enableAutoLogin|enabled]]
+则基于 cookie 登录(如:记住登录状态),它将使用 cookie 保存用户身份,这样
+只要 cookie 有效就可以恢复登录状态。
+
+为了使用 cookie 登录,你需要在应用配置文件中将 [[yii\web\User::enableAutoLogin]]
+设为 true。你还需要在 [[yii\web\User::login()]] 方法中
+传递有效期(记住登录状态的时长)参数。
+
+注销用户:
+
+```php
+Yii::$app->user->logout();
+```
+
+请注意,启用 session 时注销用户才有意义。该方法将从内存和 session 中
+同时清理用户认证状态。默认情况下,它还会注销所有的
+用户会话数据。如果你希望保留这些会话数据,可以换成 `Yii::$app->user->logout(false)` 。
+
+
+## 认证事件
+
+[[yii\web\User]] 类在登录和注销流程引发一些事件。
+
+* [[yii\web\User::EVENT_BEFORE_LOGIN|EVENT_BEFORE_LOGIN]]:在登录 [[yii\web\User::login()]] 时引发。
+ 如果事件句柄将事件对象的 [[yii\web\UserEvent::isValid|isValid]] 属性设为 false,
+ 登录流程将会被取消。
+* [[yii\web\User::EVENT_AFTER_LOGIN|EVENT_AFTER_LOGIN]]:登录成功后引发。
+* [[yii\web\User::EVENT_BEFORE_LOGOUT|EVENT_BEFORE_LOGOUT]]:注销 [[yii\web\User::logout()]] 前引发。
+ 如果事件句柄将事件对象的 [[yii\web\UserEvent::isValid|isValid]] 属性设为 false,
+ 注销流程将会被取消。
+* [[yii\web\User::EVENT_AFTER_LOGOUT|EVENT_AFTER_LOGOUT]]:成功注销后引发。
+
+你可以通过响应这些事件来实现一些类似登录统计、在线人数统计的功能。例如,
+在登录后 [[yii\web\User::EVENT_AFTER_LOGIN|EVENT_AFTER_LOGIN]] 的处理程序,你可以将用户的登录时间和IP记录到
+`user` 表中。
diff --git a/docs/guide-zh-CN/test-overview.md b/docs/guide-zh-CN/test-overview.md
index 96bc100..a5c93dc 100644
--- a/docs/guide-zh-CN/test-overview.md
+++ b/docs/guide-zh-CN/test-overview.md
@@ -2,8 +2,8 @@
=======
测试是软件开发的一个重要组成部分。不管我们是否意识到,我们一直在不断地进行测试。
-例如, 当我们在用PHP写一个类的时候, 我们可能用echo或者die语句一步一步简单的调试
-验证我们实现的代码是否按照最初的计划工作。在开发web应用的时候,我们在表单中输入
+例如,当我们在用 PHP 写一个类的时候,我们可能用 echo 或者 die 语句一步一步简单的调试
+验证我们实现的代码是否按照最初的计划工作。在开发 web 应用的时候,我们在表单中输入
一些测试数据来确保页面能够如预期那样和我们进行交互。
测试过程可能是自动的,所以每次我们需要验证的时候,我们只需要调用它就可以测试代码
@@ -27,7 +27,7 @@
- 运行所有测试确保所有测试都通过。
- 优化代码确保测试依然可以通过。
-走完上面的过程之后,为其他功能或者扩展重复上面测试过程.如果功能发生变化,测试也需
+走完上面的过程之后,为其他功能或者扩展重复上面测试过程。如果功能发生变化,测试也需
要跟着变化。
> **技巧**: 如果你觉得你做一些很小很简单的迭代是在浪费时间,请尝试覆盖更多的测试
@@ -51,7 +51,7 @@
------------------
在测试的时候,对于一些相对复杂的项目上面的内容是非常有意义的,但对于一些比较
-简单的项目就做的有些极端了. 适用场景如下:
+简单的项目就做的有些极端了。适用场景如下:
- 项目已经很大且复杂。
- 项目需求开始变得复杂起来。项目不断发展。
diff --git a/docs/guide-zh-CN/test-unit.md b/docs/guide-zh-CN/test-unit.md
index 55aeafd..45429cb 100644
--- a/docs/guide-zh-CN/test-unit.md
+++ b/docs/guide-zh-CN/test-unit.md
@@ -8,7 +8,7 @@
正确性。也就是说,单元测试验证了方法在给定不同的输入参数的情况下,该方法
是否能够返回预期的结果。单元测试通常由编写待测试类的人开发。
-Yii的单元测试框架 Codeception 基于 PHPUnit,Codeception 建议遵从PHPUnit的文档的进行开发:
+Yii的单元测试框架 Codeception 基于 PHPUnit,Codeception 建议遵从 PHPUnit 的文档的进行开发:
- [PHPUnit docs starting from chapter 2](http://phpunit.de/manual/current/en/writing-tests-for-phpunit.html)。
- [Codeception Unit Tests](http://codeception.com/docs/05-UnitTests)。
@@ -21,5 +21,5 @@ Yii的单元测试框架 Codeception 基于 PHPUnit,Codeception 建议遵从PH
框架单元测试
--------------------
-如果你想运行Yii框架的单元测试
+如果你想运行 Yii 框架的单元测试
“[Getting started with Yii 2 development](https://github.com/yiisoft/yii2/blob/master/docs/internals/getting-started.md)”。