Browse Source

merge from xiaoliushifu

tags/2.0.16
cuileon 7 years ago
parent
commit
3ed0fea789
  1. 217
      docs/guide-zh-CN/caching-data.md
  2. 87
      docs/guide-zh-CN/caching-fragment.md
  3. 88
      docs/guide-zh-CN/caching-http.md
  4. 16
      docs/guide-zh-CN/caching-overview.md
  5. 24
      docs/guide-zh-CN/caching-page.md
  6. 66
      docs/guide-zh-CN/concept-aliases.md
  7. 44
      docs/guide-zh-CN/concept-autoloading.md
  8. 40
      docs/guide-zh-CN/concept-behaviors.md
  9. 27
      docs/guide-zh-CN/concept-components.md
  10. 100
      docs/guide-zh-CN/concept-configurations.md
  11. 299
      docs/guide-zh-CN/concept-di-container.md
  12. 169
      docs/guide-zh-CN/concept-events.md
  13. 38
      docs/guide-zh-CN/concept-properties.md
  14. 29
      docs/guide-zh-CN/concept-service-locator.md
  15. 2
      docs/guide-zh-CN/db-dao.md
  16. 16
      docs/guide-zh-CN/input-multiple-models.md
  17. 149
      docs/guide-zh-CN/intro-upgrade-from-v1.md
  18. 31
      docs/guide-zh-CN/intro-yii.md
  19. 20
      docs/guide-zh-CN/rest-authentication.md
  20. 83
      docs/guide-zh-CN/rest-controllers.md
  21. 9
      docs/guide-zh-CN/rest-error-handling.md
  22. 10
      docs/guide-zh-CN/rest-quick-start.md
  23. 26
      docs/guide-zh-CN/rest-rate-limiting.md
  24. 98
      docs/guide-zh-CN/rest-resources.md
  25. 34
      docs/guide-zh-CN/rest-response-formatting.md
  26. 25
      docs/guide-zh-CN/rest-routing.md
  27. 4
      docs/guide-zh-CN/rest-versioning.md
  28. 8
      docs/guide-zh-CN/runtime-bootstrapping.md
  29. 37
      docs/guide-zh-CN/runtime-handling-errors.md
  30. 4
      docs/guide-zh-CN/runtime-overview.md
  31. 49
      docs/guide-zh-CN/runtime-responses.md
  32. 47
      docs/guide-zh-CN/runtime-sessions-cookies.md
  33. 52
      docs/guide-zh-CN/start-databases.md
  34. 70
      docs/guide-zh-CN/start-forms.md
  35. 18
      docs/guide-zh-CN/start-gii.md
  36. 92
      docs/guide-zh-CN/start-hello.md
  37. 8
      docs/guide-zh-CN/start-installation.md
  38. 28
      docs/guide-zh-CN/start-looking-ahead.md
  39. 18
      docs/guide-zh-CN/start-workflow.md
  40. 34
      docs/guide-zh-CN/structure-application-components.md
  41. 102
      docs/guide-zh-CN/structure-applications.md
  42. 54
      docs/guide-zh-CN/structure-assets.md
  43. 156
      docs/guide-zh-CN/structure-controllers.md
  44. 9
      docs/guide-zh-CN/structure-entry-scripts.md
  45. 44
      docs/guide-zh-CN/structure-filters.md
  46. 75
      docs/guide-zh-CN/structure-models.md
  47. 45
      docs/guide-zh-CN/structure-modules.md
  48. 82
      docs/guide-zh-CN/structure-views.md
  49. 50
      docs/guide-zh-CN/structure-widgets.md
  50. 99
      docs/guide-zh-CN/tutorial-core-validators.md
  51. 64
      docs/guide-zh-CN/tutorial-yii-integration.md

217
docs/guide-zh-CN/caching-data.md

@ -5,8 +5,8 @@
它也是更高级缓存特性的基础,例如[查询缓存](#query-caching) 它也是更高级缓存特性的基础,例如[查询缓存](#query-caching)
和[内容缓存](caching-content.md)。 和[内容缓存](caching-content.md)。
如下代码是一个典型的数据缓存使用模式。其中 `$cache` 指向 如下代码是一个典型的数据缓存使用模式。
[缓存组件](#cache-components): 其中 `$cache` 指向[缓存组件](#cache-components):
```php ```php
// 尝试从缓存中取回 $data // 尝试从缓存中取回 $data
@ -23,16 +23,35 @@ if ($data === false) {
// 这儿 $data 可以使用了。 // 这儿 $data 可以使用了。
``` ```
从2.0.11版本开始, [缓存组件](#cache-components) 提供了[[yii\caching\Cache::getOrSet()|getOrSet()]] 方法来简化数据的取回、计算和存储。下面的代码逻辑和上一个例子是完全一样的:
```php
$data = $cache->getOrSet($key, function () {
return $this->calculateSomething();
});
```
当缓存中有关联$key的数据时,将返回这个缓存的值。否则就执行匿名函数来计算出将要缓存的数据并返回它。
如果匿名函数需要作用域外的数据时,可以使用`use`语句把这些数据传递到匿名函数中。例如:
```php
$user_id = 42;
$data = $cache->getOrSet($key, function () use ($user_id) {
return $this->calculateSomething($user_id);
});
```
> 注意: [[yii\caching\Cache::getOrSet()|getOrSet()]] 方法也支持缓存持续性和缓存依赖。请看[缓存过期](#cache-expiration) 和 [缓存依赖](#cache-dependencies) 来了解详细信息。
## 缓存组件 <span id="cache-components"></span> ## 缓存组件 <span id="cache-components"></span>
数据缓存需要**缓存组件**提供支持,它代表各种缓存存储器, 数据缓存需要**缓存组件**提供支持,它代表各种缓存存储器,
例如内存,文件,数据库。 例如内存,文件,数据库。
缓存组件通常注册为应用程序组件,这样 缓存组件通常注册为应用程序组件,这样它们就可以
它们就可以在全局进行配置与访问。 在全局进行配置与访问。如下代码演示了如何配置应用程序组件
如下代码演示了如何配置应用程序组件 `cache` 使用 `cache` 使用两个 [memcached](http://memcached.org/)
两个 [memcached](http://memcached.org/) 服务器: 服务器:
```php ```php
'components' => [ 'components' => [
@ -56,8 +75,8 @@ if ($data === false) {
然后就可以通过 `Yii::$app->cache` 访问上面的缓存组件了。 然后就可以通过 `Yii::$app->cache` 访问上面的缓存组件了。
由于所有缓存组件都支持同样的一系列 API ,并不需要修改使用缓存的 由于所有缓存组件都支持同样的一系列 API ,并不需要修改使用缓存的业务代码
业务代码就能直接替换为其他底层缓存组件,只需在应用配置中重新配置一下就可以。 就能直接替换为其他底层缓存组件,只需在应用配置中重新配置一下就可以。
例如,你可以将上述配置修改为使用 [[yii\caching\ApcCache|APC cache]]: 例如,你可以将上述配置修改为使用 [[yii\caching\ApcCache|APC cache]]:
@ -69,7 +88,7 @@ if ($data === false) {
], ],
``` ```
> Tip: 你可以注册多个缓存组件,很多依赖缓存的类默认调用 > 提示: 你可以注册多个缓存组件,很多依赖缓存的类默认调用
名为 `cache` 的组件(例如 [[yii\web\UrlManager]])。 名为 `cache` 的组件(例如 [[yii\web\UrlManager]])。
@ -77,66 +96,65 @@ if ($data === false) {
Yii 支持一系列缓存存储器,概况如下: Yii 支持一系列缓存存储器,概况如下:
* [[yii\caching\ApcCache]]:使用 PHP [APC](http://php.net/manual/en/book.apc.php) 扩展。这个选项可以 * [[yii\caching\ApcCache]]:使用 PHP [APC](http://php.net/manual/en/book.apc.php) 扩展。
认为是集中式应用程序环境中(例如:单一服务器, 这个选项可以认为是集中式应用程序环境中
没有独立的负载均衡器等)最快的缓存方案。 (例如:单一服务器,没有独立的负载均衡器等)最快的缓存方案。
* [[yii\caching\DbCache]]:使用一个数据库的表存储缓存数据。要使用这个缓存,你必须 * [[yii\caching\DbCache]]:使用一个数据库的表存储缓存数据。要使用这个缓存,
创建一个与 [[yii\caching\DbCache::cacheTable]] 对应的表。 你必须创建一个与 [[yii\caching\DbCache::cacheTable]] 对应的表。
* [[yii\caching\DummyCache]]: 仅作为一个缓存占位符,不实现任何真正的缓存功能。 * [[yii\caching\DummyCache]]: 仅作为一个缓存占位符,不实现任何真正的缓存功能。
这个组件的目的是为了简化那些需要查询缓存有效性的代码。 这个组件的目的是为了简化那些需要查询缓存有效性的代码。例如,
例如,在开发中如果服务器没有实际的缓存支持,用它配置 在开发中如果服务器没有实际的缓存支持,用它配置一个缓存组件。
一个缓存组件。一个真正的缓存服务启用后,可以再切换为使用相应的缓存组件。 一个真正的缓存服务启用后,可以再切换为使用相应的缓存组件。
两种条件下你都可以使用同样的代码 两种条件下你都可以使用同样的代码
`Yii::$app->cache->get($key)` 尝试从缓存中取回数据而不用担心 `Yii::$app->cache->get($key)` 尝试从缓存中取回数据而不用担心
`Yii::$app->cache` 可能是 `null` `Yii::$app->cache` 可能是 `null`
* [[yii\caching\FileCache]]:使用标准文件存储缓存数据。这个特别适用于 * [[yii\caching\FileCache]]:使用标准文件存储缓存数据。
缓存大块数据,例如一个整页的内容。 这个特别适用于缓存大块数据,例如一个整页的内容。
* [[yii\caching\MemCache]]:使用 PHP [memcache](http://php.net/manual/en/book.memcache.php) * [[yii\caching\MemCache]]:使用 PHP [memcache](http://php.net/manual/en/book.memcache.php)
和 [memcached](http://php.net/manual/en/book.memcached.php) 扩展。 和 [memcached](http://php.net/manual/en/book.memcached.php) 扩展。
这个选项被看作分布式应用环境中(例如:多台服务器, 这个选项被看作分布式应用环境中(例如:多台服务器,有负载均衡等)
有负载均衡等)最快的缓存方案。 最快的缓存方案。
* [[yii\redis\Cache]]:实现了一个基于 [Redis](http://redis.io/) 键值对存储器 * [[yii\redis\Cache]]:实现了一个基于 [Redis](http://redis.io/) 键值对存储器的缓存组件
的缓存组件(需要 redis 2.6.12 及以上版本的支持 )。 (需要 redis 2.6.12 及以上版本的支持 )。
* [[yii\caching\WinCache]]:使用 PHP [WinCache](http://iis.net/downloads/microsoft/wincache-extension) * [[yii\caching\WinCache]]:使用 PHP [WinCache](http://iis.net/downloads/microsoft/wincache-extension)
([另可参考](http://php.net/manual/en/book.wincache.php) )扩展。 ([另可参考](http://php.net/manual/en/book.wincache.php))扩展.
* [[yii\caching\XCache]]:使用 PHP [XCache](http://xcache.lighttpd.net/)扩展。 * [[yii\caching\XCache]]:使用 PHP [XCache](http://xcache.lighttpd.net/)扩展。
* [[yii\caching\ZendDataCache]]:使用 * [[yii\caching\ZendDataCache]]:使用
[Zend Data Cache](http://files.zend.com/help/Zend-Server-6/zend- server.htm#data_cache_component.htm) [Zend Data Cache](http://files.zend.com/help/Zend-Server-6/zend- server.htm#data_cache_component.htm)
作为底层缓存媒介。 作为底层缓存媒介。
> Tip: 你可以在同一个应用程序中使用不同的缓存存储器。一个常见的策略是使用基于内存的缓存存储器 > 提示: 你可以在同一个应用程序中使用不同的缓存存储器。一个常见的策略是使用基于内存的缓存存储器
存储小而常用的数据(例如:统计数据),使用基于文件 存储小而常用的数据(例如:统计数据),使用基于文件或数据库的缓存存储器
或数据库的缓存存储器存储大而不太常用的数据(例如:网页内容)。 存储大而不太常用的数据(例如:网页内容)。
## 缓存 API <span id="cache-apis"></span> ## 缓存 API <span id="cache-apis"></span>
所有缓存组件都有同样的基类 [[yii\caching\Cache]] ,因此都支持如下 API: 所有缓存组件都有同样的基类 [[yii\caching\Cache]] ,因此都支持如下 API:
* [[yii\caching\Cache::get()|get()]]:通过一个指定的键(key)从缓存中取回一项数据。如果该项数据 * [[yii\caching\Cache::get()|get()]]:通过一个指定的键(key)从缓存中取回一项数据。
不存在于缓存中或者已经过期/失效,则返回值 false。 如果该项数据不存在于缓存中或者已经过期/失效,则返回值 false。
* [[yii\caching\Cache::set()|set()]]:将一项数据指定一个键,存放到缓存中。 * [[yii\caching\Cache::set()|set()]]:将一个由键指定的数据项存放到缓存中。
* [[yii\caching\Cache::add()|add()]]:如果缓存中未找到该键,则将指定数据存放到缓存中。 * [[yii\caching\Cache::add()|add()]]:如果缓存中未找到该键,则将指定数据存放到缓存中。
* [[yii\caching\Cache::mget()|mget()]]:通过指定的多个键从缓存中取回多项数据。 * [[yii\caching\Cache::getOrSet()|getOrSet()]]:返回由键指定的缓存项,或者执行回调函数,把函数的返回值用键来关联存储到缓存中,最后返回这个函数的返回值。
* [[yii\caching\Cache::mset()|mset()]]:将多项数据存储到缓存中,每项数据对应一个键 * [[yii\caching\Cache::multiGet()|multiGet()]]:由指定的键获取多个缓存数据项
* [[yii\caching\Cache::madd()|madd()]]:将多项数据存储到缓存中,每项数据对应一个键 * [[yii\caching\Cache::multiSet()|multiSet()]]:一次存储多个数据项到缓存中,每个数据都由一个键来指明
如果某个键已经存在于缓存中,则该项数据会被跳过 * [[yii\caching\Cache::multiAdd()|multiAdd()]]:一次存储多个数据项到缓存中,每个数据都由一个键来指明。如果某个键已经存在,则略过该数据项不缓存
* [[yii\caching\Cache::exists()|exists()]]:返回一个值,指明某个键是否存在于缓存中。 * [[yii\caching\Cache::exists()|exists()]]:返回一个值,指明某个键是否存在于缓存中。
* [[yii\caching\Cache::delete()|delete()]]:通过一个键,删除缓存中对应的值。 * [[yii\caching\Cache::delete()|delete()]]:通过一个键,删除缓存中对应的值。
* [[yii\caching\Cache::flush()|flush()]]:删除缓存中的所有数据。 * [[yii\caching\Cache::flush()|flush()]]:删除缓存中的所有数据。
> Note: Do not cache a `false` boolean value directly because the [[yii\caching\Cache::get()|get()]] method uses > 注意: 千万别直接用`false`布尔值当做数据项缓存,因为[[yii\caching\Cache::get()|get()]]方法用
`false` return value to indicate the data item is not found in the cache. You may put `false` in an array and cache `false`作为返回值来表名对应的缓存项不存在。你可以把`false`放到一个数组里然后缓存这个数组来避免上述的混淆问题。
this array instead to avoid this problem.
有些缓存存储器如 MemCache,APC 支持以批量模式取回缓存值,这样可以节省取回 有些缓存存储器如 MemCache,APC 支持以批量模式取回缓存值,这样可以节省取回缓存数据的开支。
缓存数据的开支。[[yii\caching\Cache::mget()|mget()]] 和 [[yii\caching\Cache::multiGet()|multiGet()]]
[[yii\caching\Cache::madd()|madd()]] API提供对该特性的支持。 和 [[yii\caching\Cache::multiAdd()|multiAdd()]] API提供对该特性的支持。
如果底层缓存存储器不支持该特性,Yii 也会模拟实现。 如果底层缓存存储器不支持该特性,Yii 也会模拟实现。
由于 [[yii\caching\Cache]] 实现了 PHP `ArrayAccess` 接口,缓存组件也可以像数组那样使用, 由于 [[yii\caching\Cache]] 实现了 PHP `ArrayAccess` 接口,
下面是几个例子: 缓存组件也可以像数组那样使用,下面是几个例子:
```php ```php
$cache['var1'] = $value1; // 等价于: $cache->set('var1', $value1); $cache['var1'] = $value1; // 等价于: $cache->set('var1', $value1);
@ -146,12 +164,12 @@ $value2 = $cache['var2']; // 等价于: $value2 = $cache->get('var2');
### 缓存键 <span id="cache-keys"></span> ### 缓存键 <span id="cache-keys"></span>
存储在缓存中的每项数据都通过键作唯一识别。当你在缓存中存储一项 存储在缓存中的每项数据都通过键作唯一识别。
数据时,必须为它指定一个键,稍后从缓存中取回数据时,也需要提供 当你在缓存中存储一项数据时,必须为它指定一个键,
相应的键。 稍后从缓存中取回数据时,也需要提供相应的键。
你可以使用一个字符串或者任意值作为一个缓存键。当键不是一个字符串时,它将会自动 你可以使用一个字符串或者任意值作为一个缓存键。当键不是一个字符串时,
被序列化为一个字符串。 它将会自动被序列化为一个字符串。
定义一个缓存键常见的一个策略就是在一个数组中包含所有的决定性因素。 定义一个缓存键常见的一个策略就是在一个数组中包含所有的决定性因素。
例如,[[yii\db\Schema]] 使用如下键存储一个数据表的结构信息。 例如,[[yii\db\Schema]] 使用如下键存储一个数据表的结构信息。
@ -167,9 +185,13 @@ $value2 = $cache['var2']; // 等价于: $value2 = $cache->get('var2');
如你所见,该键包含了可唯一指定一个数据库表所需的所有必要信息。 如你所见,该键包含了可唯一指定一个数据库表所需的所有必要信息。
当同一个缓存存储器被用于多个不同的应用时,应该为每个应用指定一个唯一的缓存键前缀 > 注意: 通过[[yii\caching\Cache::multiSet()|multiSet()]]或者[[yii\caching\Cache::multiAdd()|multiAdd()]]方法缓存的数据项的键,它的类型只能是字符串或整型,
以避免缓存键冲突。可以通过配置 [[yii\caching\Cache::keyPrefix]] 如果你想使用较为复杂的键,可以通过
属性实现。例如,在应用配置中可以编写如下代码: [[yii\caching\Cache::set()|set()]]或者[[yii\caching\Cache::add()|add()]]方法来存储。
当同一个缓存存储器被用于多个不同的应用时,应该为每个应用指定一个唯一的缓存键前缀以避免缓存键冲突。
可以通过配置 [[yii\caching\Cache::keyPrefix]] 属性实现。
例如,在应用配置中可以编写如下代码:
```php ```php
'components' => [ 'components' => [
@ -185,12 +207,12 @@ $value2 = $cache['var2']; // 等价于: $value2 = $cache->get('var2');
### 缓存过期 <span id="cache-expiration"></span> ### 缓存过期 <span id="cache-expiration"></span>
默认情况下,缓存中的数据会永久存留,除非它被某些缓存策略强制移除(例如: 默认情况下,缓存中的数据会永久存留,除非它被某些缓存策略强制移除(例如:缓存空间已满,最老的数据会被移除)。
缓存空间已满,最老的数据会被移除)。要改变此特性,你可以在调用 要改变此特性,你可以在调用 [[yii\caching\Cache::set()|set()]] 存储一项数据时提供一个过期时间参数。
[[yii\caching\Cache::set()|set()]] 存储一项数据时提供一个过期时间参数 该参数代表这项数据在缓存中可保持有效多少秒
该参数代表这项数据在缓存中可保持有效多少秒。当你调用 当你调用 [[yii\caching\Cache::get()|get()]] 取回数据时,
[[yii\caching\Cache::get()|get()]] 取回数据时,如果它已经过了超时时间, 如果它已经过了超时时间,该方法将返回 false,表明在缓存中找不到这项数据。
该方法将返回 false,表明在缓存中找不到这项数据。例如: 例如:
```php ```php
// 将数据在缓存中保留 45 秒 // 将数据在缓存中保留 45 秒
@ -204,6 +226,9 @@ if ($data === false) {
} }
``` ```
从2.0.11开始,如果想自定义缓存的持续时间,你可以在缓存组件配置中设置[[yii\caching\Cache::$defaultDuration|defaultDuration]]成员属性的值。
这样设置会覆盖默认的缓存持续时间,且在使用[[yii\caching\Cache::set()|set()]]方法时不必每次都传递$duration参数。
### 缓存依赖 <span id="cache-dependencies"></span> ### 缓存依赖 <span id="cache-dependencies"></span>
@ -213,8 +238,8 @@ if ($data === false) {
因此,缓存中任何过期的文件内容都应该被置为失效状态, 因此,缓存中任何过期的文件内容都应该被置为失效状态,
对 [[yii\caching\Cache::get()|get()]] 的调用都应该返回 false。 对 [[yii\caching\Cache::get()|get()]] 的调用都应该返回 false。
缓存依赖用 [[yii\caching\Dependency]] 的派生类所表示。当调用 缓存依赖用 [[yii\caching\Dependency]] 的派生类所表示。
[[yii\caching\Cache::set()|set()]] 在缓存中存储一项数据时, 当调用 [[yii\caching\Cache::set()|set()]] 在缓存中存储一项数据时,
可以同时传递一个关联的缓存依赖对象。例如: 可以同时传递一个关联的缓存依赖对象。例如:
```php ```php
@ -237,12 +262,10 @@ $data = $cache->get($key);
- [[yii\caching\DbDependency]]:如果指定 SQL 语句的查询结果发生了变化,则依赖改变。 - [[yii\caching\DbDependency]]:如果指定 SQL 语句的查询结果发生了变化,则依赖改变。
- [[yii\caching\ExpressionDependency]]:如果指定的 PHP 表达式执行结果发生变化,则依赖改变。 - [[yii\caching\ExpressionDependency]]:如果指定的 PHP 表达式执行结果发生变化,则依赖改变。
- [[yii\caching\FileDependency]]:如果文件的最后修改时间发生变化,则依赖改变。 - [[yii\caching\FileDependency]]:如果文件的最后修改时间发生变化,则依赖改变。
- [[yii\caching\GroupDependency]]:将一项缓存数据标记到一个组名,你可以通过调用 - [[yii\caching\TagDependency]]: associates a cached data item with one or multiple tags. You may invalidate
[[yii\caching\GroupDependency::invalidate()]] 一次性将相同组名的缓存全部置为失效状态。 the cached data items with the specified tag(s) by calling [[yii\caching\TagDependency::invalidate()]].
> Note: Avoid using [[yii\caching\Cache::exists()|exists()]] method along with dependencies. It does not check whether > 注意:避免对带有缓存依赖的缓存项使用 [[yii\caching\Cache::exists()|exists()]] 方法,因为它不检测缓存依赖(如果有的话)是否有效,所以调用[[yii\caching\Cache::get()|get()]]可能返回`false`而调用[[yii\caching\Cache::exists()|exists()]]却返回`true`。
the dependency associated with the cached data, if there is any, has changed. So a call to
[[yii\caching\Cache::get()|get()]] may return `false` while [[yii\caching\Cache::exists()|exists()]] returns `true`.
## 查询缓存 <span id="query-caching"></span> ## 查询缓存 <span id="query-caching"></span>
@ -263,7 +286,7 @@ $result = $db->cache(function ($db) {
}); });
``` ```
查询缓存可以用于 [ActiveRecord](db-active-record.md) 和 [DAO](db-dao.md)。 查询缓存可以用在[DAO](db-dao.md)和[ActiveRecord](db-active-record.md)上:
```php ```php
$result = Customer::getDb()->cache(function ($db) { $result = Customer::getDb()->cache(function ($db) {
@ -272,23 +295,21 @@ $result = Customer::getDb()->cache(function ($db) {
``` ```
> Info: 有些 DBMS (例如:[MySQL](http://dev.mysql.com/doc/refman/5.1/en/query-cache.html)) > Info: 有些 DBMS (例如:[MySQL](http://dev.mysql.com/doc/refman/5.1/en/query-cache.html))
也支持数据库服务器端的查询缓存。你可以选择使用任一查询缓存机制 也支持数据库服务器端的查询缓存。
上文所述的查询缓存的好处在于你可以指定更灵活的缓存 你可以选择使用任一查询缓存机制。
依赖因此可能更加高效。 上文所述的查询缓存的好处在于你可以指定更灵活的缓存依赖因此可能更加高效。
### Cache Flushing <span id="cache-flushing"> ### 缓存冲刷 <span id="cache-flushing">
When you need to invalidate all the stored cache data, you can call [[yii\caching\Cache::flush()]]. 当你想让所有的缓存数据失效时,可以调用[[yii\caching\Cache::flush()]]。
You can flush the cache from the console by calling `yii cache/flush` as well. 冲刷缓存数据,你还可以从控制台调用`yii cache/flush`。
- `yii cache`: lists the available caches in application - `yii cache`: 列出应用中可用的缓存组件
- `yii cache/flush cache1 cache2`: flushes the cache components `cache1`, `cache2` (you can pass multiple component - `yii cache/flush cache1 cache2`: 冲刷缓存组件`cache1`, `cache2` (可以传递多个用空格分开的缓存组件)
names separated with space) - `yii cache/flush-all`: 冲刷应用中所有的缓存组件
- `yii cache/flush-all`: flushes all cache components in the application
> Info: Console application uses a separate configuration file by default. Ensure, that you have the same caching > Info: 默认情况下,控制台应用使用独立的配置文件。所以,为了上述命令发挥作用,请确保Web应用和控制台应用配置相同的缓存组件。
components in your web and console application configs to reach the proper effect.
### 配置 <span id="query-caching-configs"></span> ### 配置 <span id="query-caching-configs"></span>
@ -329,8 +350,33 @@ If the result of a query is found valid in the cache, the query will be skipped
from the cache instead. If you do not specify the `$duration` parameter, the value of from the cache instead. If you do not specify the `$duration` parameter, the value of
[[yii\db\Connection::queryCacheDuration|queryCacheDuration]] will be used instead. [[yii\db\Connection::queryCacheDuration|queryCacheDuration]] will be used instead.
Sometimes within `cache()`, you may want to disable query caching for some particular queries. You can use * [[yii\db\Connection::enableQueryCache|enableQueryCache]]:是否开启或关闭查询缓存,默认是`true`。注意,为了有效的开启查询缓存,你还需要配置一个由[[yii\db\Connection::queryCache|queryCache]]属性指定的缓存组件。
[[yii\db\Connection::noCache()]] in this case. * [[yii\db\Connection::queryCacheDuration|queryCacheDuration]]: 这表示查询结果能够保持有效的秒数,设置为0的话,则会在缓存组件中永久缓存。这也是调用[[yii\db\Connection::cache()]]而没有指明缓存持续时间时的默认值。
* [[yii\db\Connection::queryCache|queryCache]]: 缓存应用组件的 ID。默认为 `'cache'`
只有在设置了一个有效的缓存应用组件时,查询缓存才会有效。
### 用法 <span id="query-caching-usages"></span>
如果一次有多个SQL查询想利用查询缓存,你可以用[[yii\db\Connection::cache()]] 。用法如下,
```php
$duration = 60; // cache query results for 60 seconds.
$dependency = ...; // optional dependency
$result = $db->cache(function ($db) {
// ... perform SQL queries here ...
return $result;
}, $duration, $dependency);
```
在匿名函数里的任何一个SQL查询都会伴随指定的duration和dependency来生成缓存。
如果一个SQL查询的结果在缓存中有效,那么这个SQl语句将会被跳过而它的查询结果会直接从缓存中读取。如果你没有指明`$duration`参数,那么使用[[yii\db\Connection::queryCacheDuration|queryCacheDuration]]属性。
有时在`cache()`里,你可能不想缓存某些特殊的查询,这时你可以用[[yii\db\Connection::noCache()]]。
```php ```php
$result = $db->cache(function ($db) { $result = $db->cache(function ($db) {
@ -349,15 +395,14 @@ $result = $db->cache(function ($db) {
}); });
``` ```
If you just want to use query caching for a single query, you can call [[yii\db\Command::cache()]] when building 如果仅仅想缓存一个单独的查询,那么在建立查询命令时可以使用[[yii\db\Command::cache()]]。例如,
the command. For example,
```php ```php
// use query caching and set query cache duration to be 60 seconds // use query caching and set query cache duration to be 60 seconds
$customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->cache(60)->queryOne(); $customer = $db->createCommand('SELECT * FROM customer WHERE id=1')->cache(60)->queryOne();
``` ```
You can also use [[yii\db\Command::noCache()]] to disable query caching for a single command. For example, 也可以用[[yii\db\Command::noCache()]]来单独设置某些查询命令不缓存。例如,
```php ```php
$result = $db->cache(function ($db) { $result = $db->cache(function ($db) {
@ -376,11 +421,11 @@ $result = $db->cache(function ($db) {
### 限制条件 <span id="query-caching-limitations"></span> ### 限制条件 <span id="query-caching-limitations"></span>
当查询结果中含有资源句柄时,查询缓存无法使用。例如, 当查询结果中含有资源句柄时,查询缓存无法使用。
在有些 DBMS 中使用了 `BLOB` 列的时候,缓存结果会为 例如,在有些 DBMS 中使用了 `BLOB` 列的时候,
该数据列返回一个资源句柄。 缓存结果会为该数据列返回一个资源句柄。
有些缓存存储器有大小限制。例如,memcache 限制每条数据 有些缓存存储器有大小限制。例如,memcache 限制每条数据最大为 1MB。
最大为 1MB。因此,如果查询结果的大小超出了该限制, 因此,如果查询结果的大小超出了该限制,
则会导致缓存失败。 则会导致缓存失败。

87
docs/guide-zh-CN/caching-fragment.md

@ -2,8 +2,8 @@
================ ================
片段缓存指的是缓存页面内容中的某个片段。例如,一个页面显示了逐年销售额的摘要表格, 片段缓存指的是缓存页面内容中的某个片段。例如,一个页面显示了逐年销售额的摘要表格,
可以把表格缓存下来,以消除每次请求都要重新生成表格 可以把表格缓存下来,以消除每次请求都要重新生成表格的耗时。
的耗时。片段缓存是基于[数据缓存](caching-data.md)实现的。 片段缓存是基于[数据缓存](caching-data.md)实现的。
在[视图](structure-views.md)中使用以下结构启用片段缓存: 在[视图](structure-views.md)中使用以下结构启用片段缓存:
@ -16,27 +16,27 @@ if ($this->beginCache($id)) {
} }
``` ```
调用 [[yii\base\View::beginCache()|beginCache()]] 和 [[yii\base\View::endCache()|endcache()]] 调用 [[yii\base\View::beginCache()|beginCache()]] 和 [[yii\base\View::endCache()|endcache()]] 方法包裹内容生成逻辑。
方法包裹内容生成逻辑。如果缓存中存在该内容,[[yii\base\View::beginCache()|beginCache()]] 如果缓存中存在该内容,[[yii\base\View::beginCache()|beginCache()]] 方法将渲染内容并返回 false,
方法将渲染内容并返回 false,因此将跳过内容生成逻辑。否则, 因此将跳过内容生成逻辑。否则,内容生成逻辑被执行
内容生成逻辑被执行,一直执行到 [[yii\base\View::endCache()|endCache()]] 一直执行到[[yii\base\View::endCache()|endCache()]] 时,
时,生成的内容将被捕获并存储在缓存中。 生成的内容将被捕获并存储在缓存中。
和[[数据缓存]](caching-data.md)一样,每个片段缓存也需要全局唯一的 `$id` 标记。 和[[数据缓存]](caching-data.md)一样,每个片段缓存也需要全局唯一的 `$id` 标记。
## 缓存选项 <span id="caching-options"></span> ## 缓存选项 <span id="caching-options"></span>
如果要为片段缓存指定额外配置项,请通过向 [[yii\base\View::beginCache()|beginCache()]] 如果要为片段缓存指定额外配置项,
方法第二个参数传递配置数组。在框架内部, 请通过向 [[yii\base\View::beginCache()|beginCache()]]
该数组将被用来配置一个 [[yii\widget\FragmentCache]] 方法第二个参数传递配置数组。在框架内部,该数组将被用来配置一个 [[yii\widget\FragmentCache]]
小部件用以实现片段缓存功能。 小部件用以实现片段缓存功能。
### 过期时间(duration) <span id="duration"></span> ### 过期时间(duration) <span id="duration"></span>
或许片段缓存中最常用的一个配置选项就是 或许片段缓存中最常用的一个配置选项就是 [[yii\widgets\FragmentCache::duration|duration]] 了。
[[yii\widgets\FragmentCache::duration|duration]] 了 它指定了内容被缓存的秒数
它指定了内容被缓存的秒数。以下代码缓存内容最多一小时: 以下代码缓存内容最多一小时:
```php ```php
if ($this->beginCache($id, ['duration' => 3600])) { if ($this->beginCache($id, ['duration' => 3600])) {
@ -47,13 +47,13 @@ if ($this->beginCache($id, ['duration' => 3600])) {
} }
``` ```
如果该选项未设置,it will take the default value 60, which means the cached content will expire in 60 seconds. If the option is not set, it will take the default value 60, which means the cached content will expire in 60 seconds.
### 依赖 <span id="dependencies"></span> ### 依赖 <span id="dependencies"></span>
和[[数据缓存]](caching-data.md)一样,片段缓存的内容一样可以设置缓存依赖。例如 和[[数据缓存]](caching-data.md)一样,片段缓存的内容一样可以设置缓存依赖。
一段被缓存的文章,是否重新缓存取决于它是否被修改过。 例如一段被缓存的文章,是否重新缓存取决于它是否被修改过。
通过设置 [[yii\widgets\FragmentCache::dependency|dependency]] 选项来指定依赖, 通过设置 [[yii\widgets\FragmentCache::dependency|dependency]] 选项来指定依赖,
该选项的值可以是一个 [[yii\caching\Dependency]] 类的派生类,也可以是创建缓存对象的配置数组。 该选项的值可以是一个 [[yii\caching\Dependency]] 类的派生类,也可以是创建缓存对象的配置数组。
@ -76,8 +76,8 @@ if ($this->beginCache($id, ['dependency' => $dependency])) {
### 变化 <span id="variations"></span> ### 变化 <span id="variations"></span>
缓存的内容可能需要根据一些参数的更改而变化。例如一个 Web 应用 缓存的内容可能需要根据一些参数的更改而变化。
支持多语言,同一段视图代码也许需要生成多个语言的内容。 例如一个 Web 应用支持多语言,同一段视图代码也许需要生成多个语言的内容。
因此可以设置缓存根据应用当前语言而变化。 因此可以设置缓存根据应用当前语言而变化。
通过设置 [[yii\widgets\FragmentCache::variations|variations]] 选项来指定变化, 通过设置 [[yii\widgets\FragmentCache::variations|variations]] 选项来指定变化,
@ -96,10 +96,10 @@ if ($this->beginCache($id, ['variations' => [Yii::$app->language]])) {
### 开关 <span id="toggling-caching"></span> ### 开关 <span id="toggling-caching"></span>
有时你可能只想在特定条件下开启片段缓存。例如,一个显示表单的页面,可能只 有时你可能只想在特定条件下开启片段缓存。例如,一个显示表单的页面,可能只需要在初次请求时缓存表单(通过 GET 请求)。
需要在初次请求时缓存表单(通过 GET 请求)。随后请求所显示(通过 POST 请求) 随后请求所显示(通过 POST 请求)的表单不该使用缓存,因为此时表单中可能包含用户输入内容。
的表单不该使用缓存,因为此时表单中可能包含用户输入内容。鉴于此种情况,可以使用 鉴于此种情况,可以使用 [[yii\widgets\FragmentCache::enabled|enabled]] 选项来指定缓存开关,
[[yii\widgets\FragmentCache::enabled|enabled]] 选项来指定缓存开关,如下所示: 如下所示:
```php ```php
if ($this->beginCache($id, ['enabled' => Yii::$app->request->isGet])) { if ($this->beginCache($id, ['enabled' => Yii::$app->request->isGet])) {
@ -114,8 +114,8 @@ if ($this->beginCache($id, ['enabled' => Yii::$app->request->isGet])) {
## 缓存嵌套 <span id="nested-caching"></span> ## 缓存嵌套 <span id="nested-caching"></span>
片段缓存可以被嵌套使用。一个片段缓存可以被另一个包裹。 片段缓存可以被嵌套使用。一个片段缓存可以被另一个包裹。
例如,评论被缓存在里层,同时整个评论的片段又被缓存在 例如,评论被缓存在里层,同时整个评论的片段又被缓存在外层的文章中。
外层的文章中。以下代码展示了片段缓存的嵌套使用: 以下代码展示了片段缓存的嵌套使用:
```php ```php
if ($this->beginCache($id1)) { if ($this->beginCache($id1)) {
@ -135,28 +135,28 @@ if ($this->beginCache($id1)) {
} }
``` ```
可以为嵌套的缓存设置不同的配置项。例如,内层缓存和外层缓存使用 可以为嵌套的缓存设置不同的配置项。例如,内层缓存和外层缓存使用不同的过期时间。
不同的过期时间。甚至当外层缓存的数据过期失效了,内层缓存仍然 甚至当外层缓存的数据过期失效了,内层缓存仍然可能提供有效的片段缓存数据。
可能提供有效的片段缓存数据。但是,反之则不然。如果外层片段缓存 但是,反之则不然。如果外层片段缓存没有过期而被视为有效,
没有过期而被视为有效,此时即使内层片段缓存已经失效,它也将继续 此时即使内层片段缓存已经失效,它也将继续提供同样的缓存副本。
提供同样的缓存副本。因此,你必须谨慎处理缓存嵌套中的过期时间和 因此,你必须谨慎处理缓存嵌套中的过期时间和依赖,
依赖,否则外层的片段很有可能返回的是不符合你预期的失效数据。 否则外层的片段很有可能返回的是不符合你预期的失效数据。
> 译注:外层的失效时间应该短于内层,外层的依赖条件应该低于内层,以确保最小的片段,返回的是最新的数据。 > 译注:外层的失效时间应该短于内层,外层的依赖条件应该低于内层,以确保最小的片段,返回的是最新的数据。
## 动态内容 <span id="dynamic-content"></span> ## 动态内容 <span id="dynamic-content"></span>
使用片段缓存时,可能会遇到一大段较为静态的内容中有少许动态内 使用片段缓存时,可能会遇到一大段较为静态的内容中有少许动态内容的情况。
容的情况。例如,一个显示着菜单栏和当前用户名的页面头部。还有 例如,一个显示着菜单栏和当前用户名的页面头部。
一种可能是缓存的内容可能包含每次请求都需要执行的 PHP 代码 还有一种可能是缓存的内容可能包含每次请求
(例如注册资源包的代码)。这两个问题都可以 都需要执行的 PHP 代码(例如注册资源包的代码)。
使用 **动态内容** 功能解决。 这两个问题都可以使用**动态内容**功能解决。
动态内容的意思是这部分输出的内容不该被缓存,即便是它被包裹 动态内容的意思是这部分输出的内容不该被缓存,即便是它被包裹在片段缓存中。
在片段缓存中。为了使内容保持动态,每次请求都执行 PHP 代码 为了使内容保持动态,每次请求都执行 PHP 代码生成,
生成,即使这些代码已经被缓存了。 即使这些代码已经被缓存了。
可以在片段缓存中调用 [[yii\base\View::renderDynamic()]] 去 可以在片段缓存中调用 [[yii\base\View::renderDynamic()]] 去插入动态内容,
插入动态内容,如下所示: 如下所示:
```php ```php
if ($this->beginCache($id1)) { if ($this->beginCache($id1)) {
@ -171,6 +171,7 @@ if ($this->beginCache($id1)) {
} }
``` ```
[[yii\base\View::renderDynamic()|renderDynamic()]] 方法接受 [[yii\base\View::renderDynamic()|renderDynamic()]] 方法接受一段 PHP 代码作为参数。
一段 PHP 代码作为参数。代码的返回值被看作是动态内容。这段代 代码的返回值被看作是动态内容。这段代码将在每次请求时都执行,
码将在每次请求时都执行,无论其外层的片段缓存是否被存储。 无论其外层的片段缓存是否被存储。

88
docs/guide-zh-CN/caching-http.md

@ -1,12 +1,12 @@
HTTP 缓存 HTTP 缓存
============ ============
除了前面章节讲到的服务器端缓存外, Web 应用还可以利用客户端 除了前面章节讲到的服务器端缓存外, Web 应用还可以利用客户端缓存
缓存去节省相同页面内容的生成和传输时间。 去节省相同页面内容的生成和传输时间。
通过配置 [[yii\filters\HttpCache]] 过滤器,控制器动作渲染的内容就能 通过配置 [[yii\filters\HttpCache]] 过滤器,控制器操作渲染的内容就能缓存在客户端。
缓存在客户端。[[yii\filters\HttpCache|HttpCache]] 过滤器仅对 `GET` [[yii\filters\HttpCache|HttpCache]] 过滤器仅对 `GET``HEAD` 请求生效,
`HEAD` 请求生效,它能为这些请求设置三种与缓存有关的 HTTP 头。 它能为这些请求设置三种与缓存有关的 HTTP 头。
* [[yii\filters\HttpCache::lastModified|Last-Modified]] * [[yii\filters\HttpCache::lastModified|Last-Modified]]
* [[yii\filters\HttpCache::etagSeed|Etag]] * [[yii\filters\HttpCache::etagSeed|Etag]]
@ -17,9 +17,9 @@ HTTP 缓存
`Last-Modified` 头使用时间戳标明页面自上次客户端缓存后是否被修改过。 `Last-Modified` 头使用时间戳标明页面自上次客户端缓存后是否被修改过。
通过配置 [[yii\filters\HttpCache::lastModified]] 属性向客户端发送 通过配置 [[yii\filters\HttpCache::lastModified]] 属性向客户端发送 `Last-Modified` 头。
`Last-Modified` 头。该属性的值应该为 PHP callable 类型,返回的是页 该属性的值应该为 PHP callable 类型,返回的是页面修改时的 Unix 时间戳。
面修改时的 Unix 时间戳。该 callable 的参数和返回值应该如下: 该 callable 的参数和返回值应该如下:
```php ```php
/** /**
@ -48,23 +48,23 @@ public function behaviors()
} }
``` ```
上述代码表明 HTTP 缓存只在 `index` 动作时启用。它会基于页面 上述代码表明 HTTP 缓存只在 `index` 操作时启用。
最后修改时间生成一个 `Last-Modified` HTTP 头。当浏览器第一 它会基于页面最后修改时间生成一个 `Last-Modified` HTTP 头。
次访问 `index` 页时,服务器将会生成页面并发送至客户端浏览器。 当浏览器第一次访问 `index` 页时,服务器将会生成页面并发送至客户端浏览器。
之后客户端浏览器在页面没被修改期间访问该页,服务器将不会重新 之后客户端浏览器在页面没被修改期间访问该页,
生成页面,浏览器会使用之前客户端缓存下来的内容。因此服务端 服务器将不会重新生成页面,浏览器会使用之前客户端缓存下来的内容。
渲染和内容传输都将省去。 因此服务端渲染和内容传输都将省去。
## `ETag`<span id="etag"></span> ## `ETag`<span id="etag"></span>
“Entity Tag”(实体标签,简称 ETag)使用一个哈希值表示页面内容。如果页面 “Entity Tag”(实体标签,简称 ETag)使用一个哈希值表示页面内容。如果页面被修改过,
被修改过,哈希值也会随之改变。通过对比客户端的哈希值和服务器端生成的哈 哈希值也会随之改变。通过对比客户端的哈希值和服务器端生成的哈希值,
希值,浏览器就能判断页面是否被修改过,进而决定是否应该重新传输内容。 浏览器就能判断页面是否被修改过,进而决定是否应该重新传输内容。
通过配置 [[yii\filters\HttpCache::etagSeed]] 属性向客户端发送 通过配置 [[yii\filters\HttpCache::etagSeed]] 属性向客户端发送 `ETag` 头。
`ETag` 头。该属性的值应该为 PHP callable 类型,返回的是一段种 该属性的值应该为 PHP callable 类型,返回的是一段种子字符用来生成 ETag 哈希值。
子字符用来生成 ETag 哈希值。该 callable 的参数和返回值应该如下: 该 callable 的参数和返回值应该如下:
```php ```php
/** /**
@ -93,31 +93,31 @@ public function behaviors()
} }
``` ```
上述代码表明 HTTP 缓存只在 `view` 动作时启用。它会基于用户 上述代码表明 HTTP 缓存只在 `view` 操作时启用。
请求的标题和内容生成一个 `ETag` HTTP 头。当浏览器第一次访问 它会基于用户请求的标题和内容生成一个 `ETag` HTTP 头。
`view` 页时,服务器将会生成页面并发送至客户端浏览器。之后 当浏览器第一次访问 `view` 页时,服务器将会生成页面并发送至客户端浏览器。
客户端浏览器标题和内容没被修改在期间访问该页,服务器将不会 之后客户端浏览器标题和内容没被修改在期间访问该页,服务器将不会重新生成页面,
重新生成页面,浏览器会使用之前客户端缓存下来的内容。 浏览器会使用之前客户端缓存下来的内容。
因此服务端渲染和内容传输都将省去。 因此服务端渲染和内容传输都将省去。
ETag 相比 `Last-Modified` 能实现更复杂和更精确的缓存策略。 ETag 相比 `Last-Modified` 能实现更复杂和更精确的缓存策略。
例如,当站点切换到另一个主题时可以使 ETag 失效。 例如,当站点切换到另一个主题时可以使 ETag 失效。
复杂的 Etag 生成种子可能会违背使用 `HttpCache` 的初衷而引起 复杂的 Etag 生成种子可能会违背使用 `HttpCache` 的初衷而引起不必要的性能开销,
不必要的性能开销,因为响应每一次请求都需要重新计算 Etag。 因为响应每一次请求都需要重新计算 Etag。
请试着找出一个最简单的表达式去触发 Etag 失效。 请试着找出一个最简单的表达式去触发 Etag 失效。
> 注意:为了遵循 [RFC 7232(HTTP 1.1 协议)](http://tools.ietf.org/html/rfc7232#section-2.4) > Note: 为了遵循 [RFC 7232(HTTP 1.1 协议)](http://tools.ietf.org/html/rfc7232#section-2.4),
如果同时配置了 `ETag``Last-Modified` 头,`HttpCache` 将会同时 如果同时配置了 `ETag``Last-Modified` 头,`HttpCache` 将会同时发送它们。
发送它们。并且如果客户端同时发送 `If-None-Match` 并且如果客户端同时发送 `If-None-Match``If-Modified-Since` 头,
`If-Modified-Since` 头,则只有前者会被接受。 则只有前者会被接受。
## `Cache-Control`<span id="cache-control"></span> ## `Cache-Control`<span id="cache-control"></span>
`Cache-Control` 头指定了页面的常规缓存策略。可以通过配置 `Cache-Control` 头指定了页面的常规缓存策略。
[[yii\filters\HttpCache::cacheControlHeader]] 属性发送相 可以通过配置 [[yii\filters\HttpCache::cacheControlHeader]]
应的头信息。默认发送以下头: 属性发送相应的头信息。默认发送以下头:
``` ```
Cache-Control: public, max-age=3600 Cache-Control: public, max-age=3600
@ -125,19 +125,19 @@ Cache-Control: public, max-age=3600
## 会话缓存限制器 <span id="session-cache-limiter"></span> ## 会话缓存限制器 <span id="session-cache-limiter"></span>
当页面使 session 时,PHP 将会按照 PHP.INI 中所设置的`session.cache_limiter` 当页面使 session 时,PHP 将会按照 PHP.INI
值自动发送一些缓存相关的 HTTP 头。这些 HTTP 头有可能会干扰你原本设置的 中所设置的 `session.cache_limiter` 值自动发送一些缓存相关的 HTTP 头。
`HttpCache` 或让其失效。为了避免此问题,默认情况下 `HttpCache` 禁止 这些 HTTP 头有可能会干扰你原本设置的 `HttpCache` 或让其失效。
自动发送这些头。想改变这一行为,可以配置 为了避免此问题,默认情况下 `HttpCache` 禁止自动发送这些头。
[[yii\filters\HttpCache::sessionCacheLimiter]] 属性。该属性接受一个 想改变这一行为,可以配置 [[yii\filters\HttpCache::sessionCacheLimiter]] 属性。
字符串值,包括 `public`,`private`,`private_no_expire`, 该属性接受一个字符串值,包括 `public`,`private`,`private_no_expire`,`nocache`
`nocache`请参考 PHP 手册中的[缓存限制器](http://www.php.net/manual/en/function.session-cache-limiter.php) 请参考 PHP 手册中的[缓存限制器](http://www.php.net/manual/en/function.session-cache-limiter.php)
了解这些值的含义。 了解这些值的含义。
## SEO 影响 <span id="seo-implications"></span> ## SEO 影响 <span id="seo-implications"></span>
搜索引擎趋向于遵循站点的缓存头。因为一些爬虫的 搜索引擎趋向于遵循站点的缓存头。因为一些爬虫的抓取频率有限制,
抓取频率有限制,启用缓存头可以可以减少重复请求 启用缓存头可以可以减少重复请求数量,增加爬虫抓取效率
数量,增加爬虫抓取效率(译者:大意如此,但搜索引擎的排名规则不了解,好的缓存策略应该是可以为用户体验加分的)。 (译者:大意如此,但搜索引擎的排名规则不了解,好的缓存策略应该是可以为用户体验加分的)。

16
docs/guide-zh-CN/caching-overview.md

@ -1,15 +1,15 @@
缓存 缓存
======= =======
缓存是提升 Web 应用性能简便有效的方式。通过将相对静态的数据 缓存是提升 Web 应用性能简便有效的方式。
存储到缓存并在收到请求时取回缓存,应用程序便节省了每次重新生 通过将相对静态的数据存储到缓存并在收到请求时取回缓存,
成这些数据所需的时间。 应用程序便节省了每次重新生成这些数据所需的时间。
缓存可以应用在 Web 应用程序的任何层级任何位置。在服务器端, 缓存可以应用在 Web 应用程序的任何层级任何位置。
在较的低层面,缓存可能用于存储基础数据,例如从数据库中取 服务器端,在较的低层面,缓存可能用于存储基础数据,例如从数据库中取出的最新文章列表;
出的最新文章列表;在较高的层面,缓存可能用于存储一段或整 在较高的层面,缓存可能用于存储一段或整个 Web 页面,
个 Web 页面,例如最新文章的渲染结果。在客户端,HTTP 缓存 例如最新文章的渲染结果。在客户端,HTTP 缓存可能用于
可能用于将最近访问的页面内容存储到浏览器缓存中。 将最近访问的页面内容存储到浏览器缓存中。
Yii 支持如上所有缓存机制: Yii 支持如上所有缓存机制:

24
docs/guide-zh-CN/caching-page.md

@ -1,11 +1,11 @@
页面缓存 页面缓存
============ ============
页面缓存指的是在服务器端缓存整个页面的内容。随后当同一个页面 页面缓存指的是在服务器端缓存整个页面的内容。
被请求时,内容将从缓存中取出,而不是重新生成。 随后当同一个页面被请求时,内容将从缓存中取出,而不是重新生成。
页面缓存由 [[yii\filters\PageCache]] 类提供支持,该类是一个 页面缓存由 [[yii\filters\PageCache]] 类提供支持,该类是一个[过滤器](structure-filters.md)。
[过滤器](structure-filters.md)。它可以像这样在控制器类中使用: 它可以像这样在控制器类中使用:
```php ```php
public function behaviors() public function behaviors()
@ -27,14 +27,14 @@ public function behaviors()
} }
``` ```
上述代码表示页面缓存只在 `index` 动作时启用,页面内容最多被缓存 上述代码表示页面缓存只在 `index` 操作时启用,页面内容最多被缓存 60 秒,
60 秒,会随着当前应用的语言更改而变化。如果文章总数发生变化则缓 会随着当前应用的语言更改而变化。
存的页面会失效。 如果文章总数发生变化则缓存的页面会失效。
如你所见,页面缓存和[片段缓存](caching-fragment.md)极其相似。它们都支持 `duration`,`dependencies`, 如你所见,页面缓存和[片段缓存](caching-fragment.md)极其相似。
`variations``enabled` 配置选项。它们的主要区别是页面缓存是由[过滤器](structure-filters.md)实现, 它们都支持 `duration`,`dependencies`,`variations``enabled` 配置选项。
而片段缓存则是一个[小部件](structure-widgets.md)。 它们的主要区别是页面缓存是由[过滤器](structure-filters.md)实现,而片段缓存则是一个[小部件](structure-widgets.md)。
你可以在使用页面缓存的同时,使用[片段缓存](caching-fragment.md)和 你可以在使用页面缓存的同时,
[动态内容](caching-fragment.md#dynamic-content)。 使用[片段缓存](caching-fragment.md)和[动态内容](caching-fragment.md#dynamic-content)。

66
docs/guide-zh-CN/concept-aliases.md

@ -1,12 +1,12 @@
别名(Aliases) 别名(Aliases)
======= =======
别名用来表示文件路径和 URL,这样就避免了在代码中硬编码一些绝对路径 别名用来表示文件路径和 URL,这样就避免了在代码中硬编码一些绝对路径和 URL。
和 URL。一个别名必须以 `@` 字符开头,以区别于传统的文件路径和 URL。 一个别名必须以 `@` 字符开头,以区别于传统的文件路径和 URL。
Alias defined without leading `@` will be prefixed with `@` character. Yii 预定义了大量可用的别名。例如,别名 `@yii` 指的是 Yii 框架本身的安装目录,而 `@web` 表示的是当前运行应用的根 URL。
Yii 预定义了大量可用的别名。例如,别名 `@yii` 指的是 Yii 框架本身的安装 Yii has many pre-defined aliases already available. For example, the alias `@yii` represents the installation path of
目录,而 `@web` 表示的是当前运行应用的根 URL。 the Yii framework; `@web` represents the base URL for the currently running Web application.
定义别名 <span id="defining-aliases"></span> 定义别名 <span id="defining-aliases"></span>
---------------- ----------------
@ -23,10 +23,10 @@ Yii::setAlias('@bar', 'http://www.example.com');
> 注意:别名所指向的文件路径或 URL 不一定是真实存在的文件或资源。 > 注意:别名所指向的文件路径或 URL 不一定是真实存在的文件或资源。
可以通过在一个别名后面加斜杠 `/` 和一至多个路径分段生成新别名 可以通过在一个别名后面加斜杠 `/` 和一至多个路径分段生成新别名(无需调用 [[Yii::setAlias()]])。
(无需调用 [[Yii::setAlias()]])。我们把通过 [[Yii::setAlias()]] 们把通过 [[Yii::setAlias()]] 定义的别名称为**根别名**,
定义的别名称为**根别名**,而用他们衍生出去的别名成为**衍生别名**。 而用他们衍生出去的别名成为**衍生别名**。例如,`@foo` 就是根别名,
例如,`@foo` 就是根别名,`@foo/bar/file.php` 是一个衍生别名。 `@foo/bar/file.php` 是一个衍生别名。
你还可以用别名去定义新别名(根别名与衍生别名均可): 你还可以用别名去定义新别名(根别名与衍生别名均可):
@ -34,10 +34,10 @@ Yii::setAlias('@bar', 'http://www.example.com');
Yii::setAlias('@foobar', '@foo/bar'); Yii::setAlias('@foobar', '@foo/bar');
``` ```
根别名通常在[引导](runtime-bootstrapping.md)阶段定义。比如你可以在 根别名通常在[引导](runtime-bootstrapping.md)阶段定义。
[入口脚本](structure-entry-scripts.md)里调用 [[Yii::setAlias()]]。为 比如你可以在[入口脚本](structure-entry-scripts.md)里调用 [[Yii::setAlias()]]。为了方便起见,
了方便起见,[应用](structure-applications.md)提供了一个名为 `aliases` [应用](structure-applications.md)提供了一个名为 `aliases` 可写属性,
可写属性,你可以在应用[配置](concept-configurations.md)中设置它,就像这样: 你可以在应用[配置](concept-configurations.md)中设置它,就像这样:
```php ```php
return [ return [
@ -62,15 +62,15 @@ echo Yii::getAlias('@bar'); // 输出:http://www.example.com
echo Yii::getAlias('@foo/bar/file.php'); // 输出:/path/to/foo/bar/file.php echo Yii::getAlias('@foo/bar/file.php'); // 输出:/path/to/foo/bar/file.php
``` ```
由衍生别名所解析出的文件路径和 URL 是通过替换掉衍生别名 由衍生别名所解析出的文件路径和 URL
中的根别名部分得到的。 是通过替换掉衍生别名中的根别名部分得到的。
> 注意:[[Yii::getAlias()]] 并不检查结果路径/URL 所指向的资源是否真实存在。 > 注意:[[Yii::getAlias()]] 并不检查结果路径/URL 所指向的资源是否真实存在。
根别名可能也会包含斜杠 `/`[[Yii::getAlias()]] 根别名可能也会包含斜杠 `/`
足够智能到判断一个别名中的哪部分是根别名,因此 [[Yii::getAlias()]] 足够智能到判断一个别名中的哪部分是根别名,因此能正确解析文件路径/URL。
能正确解析文件路径/URL。例如: 例如:
```php ```php
Yii::setAlias('@foo', '/path/to/foo'); Yii::setAlias('@foo', '/path/to/foo');
@ -85,9 +85,9 @@ echo Yii::getAlias('@foo/bar/file.php'); // 输出:/path2/bar/file.php
使用别名 <span id="using-aliases"></span> 使用别名 <span id="using-aliases"></span>
------------- -------------
别名在 Yii 的很多地方都会被正确识别,无需调用 [[Yii::getAlias()]] 别名在 Yii 的很多地方都会被正确识别,
来把它们转换为路径/URL。例如,[[yii\caching\FileCache::cachePath]] 无需调用 [[Yii::getAlias()]] 来把它们转换为路径/URL。
能同时接受文件路径或是指向文件路径的别名, 例如,[[yii\caching\FileCache::cachePath]] 能同时接受文件路径或是指向文件路径的别名,
因为通过 `@` 前缀能区分它们。 因为通过 `@` 前缀能区分它们。
```php ```php
@ -106,15 +106,15 @@ $cache = new FileCache([
Yii 预定义了一系列别名来简化常用路径和 URL 的使用: Yii 预定义了一系列别名来简化常用路径和 URL 的使用:
- `@yii`, `BaseYii.php` 文件所在的目录(也被称为框架安装目录) - `@yii`,`BaseYii.php` 文件所在的目录(也被称为框架安装目录)
- `@app`, 当前运行的应用 [[yii\base\Application::basePath|根路径(base path)]] - `@app`,当前运行的应用 [[yii\base\Application::basePath|根路径(base path)]]。
- `@runtime`, 当前运行的应用的 [[yii\base\Application::runtimePath|运行环境(runtime)路径]]. Defaults to `@app/runtime`. - `@runtime`,当前运行的应用的 [[yii\base\Application::runtimePath|运行环境(runtime)路径]]。默认为 `@app/runtime`
- `@webroot`, the Web root directory of the currently running Web application. It is determined based on the directory - `@webroot`,当前运行的Web应用程序的Web根目录。
containing the [entry script](structure-entry-scripts.md). 它是根据包含 [入口脚本](structure-entry-scripts.md) 的目录确定的。
- `@web`,the base URL of the currently running Web application. It has the same value as [[yii\web\Request::baseUrl]]. - `@web`,当前运行的Web应用程序的 base URL。它的值与 [[yii\web\Request::baseUrl]] 相同。
- `@vendor`,[[yii\base\Application::vendorPath|Composer 供应商目录]]. Defaults to `@app/vendor`. - `@vendor`,[[yii\base\Application::vendorPath|Composer vendor 目录]]。
- `@bower`, the root directory that contains [bower packages](http://bower.io/). Defaults to `@vendor/bower`. - `@bower`,包含 [bower 包](http://bower.io/) 的根目录。默认为 `@vendor/bower`
- `@npm`, the root directory that contains [npm packages](https://www.npmjs.org/). Defaults to `@vendor/npm`. - `@npm`,包含 [npm 包](https://www.npmjs.org/) 的根目录。默认为 `@vendor/npm`
`@yii` 别名是在[入口脚本](structure-entry-scripts.md)里包含 `Yii.php` 文件时定义的, `@yii` 别名是在[入口脚本](structure-entry-scripts.md)里包含 `Yii.php` 文件时定义的,
其他的别名都是在[配置应用](concept-configurations.md)的时候, 其他的别名都是在[配置应用](concept-configurations.md)的时候,
@ -125,9 +125,9 @@ Yii 预定义了一系列别名来简化常用路径和 URL 的使用:
----------------- -----------------
每一个通过 Composer 安装的 [扩展](structure-extensions.md) 都自动添加了一个别名。 每一个通过 Composer 安装的 [扩展](structure-extensions.md) 都自动添加了一个别名。
该别名会以该扩展在 `composer.json` 文件中所声明的根命名空间为名,且他直接代指该包的根目录。 该别名会以该扩展在 `composer.json` 文件中所声明的根命名空间为名,
例如,如果你安装有 `yiisoft/yii2-jui` 扩展, 且他直接代指该包的根目录。例如,如果你安装有 `yiisoft/yii2-jui` 扩展,会自动得到 `@yii/jui` 别名
会自动得到 `@yii/jui` 别名,它定义于[引导启动](runtime-bootstrapping.md)阶段: 它定义于[引导启动](runtime-bootstrapping.md)阶段:
```php ```php
Yii::setAlias('@yii/jui', 'VendorPath/yiisoft/yii2-jui'); Yii::setAlias('@yii/jui', 'VendorPath/yiisoft/yii2-jui');

44
docs/guide-zh-CN/concept-autoloading.md

@ -2,11 +2,11 @@
================= =================
Yii 依靠[类自动加载机制](http://www.php.net/manual/en/language.oop5.autoload.php)来定位和包含所需的类文件。 Yii 依靠[类自动加载机制](http://www.php.net/manual/en/language.oop5.autoload.php)来定位和包含所需的类文件。
它提供一个高性能且完美支持[PSR-4 标准](https://github.com/php-fig/fig-standards/blob/master/proposed/psr-4-autoloader/psr-4-autoloader.md) 它提供一个高性能且完美支持[PSR-4 标准](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-4-autoloader.md)
([中文汉化](https://github.com/hfcorriez/fig-standards/blob/zh_CN/%E6%8E%A5%E5%8F%97/PSR-4-autoloader.md))的自动加载器。 ([中文汉化](https://github.com/hfcorriez/fig-standards/blob/zh_CN/%E6%8E%A5%E5%8F%97/PSR-4-autoloader.md))的自动加载器。
该自动加载器会在引入框架文件 `Yii.php` 时安装好。 该自动加载器会在引入框架文件 `Yii.php` 时安装好。
> 注意:为了简化叙述,本篇文档中我们只会提及类的自动加载。 > Note: 为了简化叙述,本篇文档中我们只会提及类的自动加载。
不过,要记得文中的描述同样也适用于接口和Trait(特质)的自动加载哦。 不过,要记得文中的描述同样也适用于接口和Trait(特质)的自动加载哦。
@ -27,9 +27,9 @@ $classFile = Yii::getAlias('@' . str_replace('\\', '/', $className) . '.php');
为了让该别名能被正确解析为文件路径,`@foo` 或 `@foo/bar` 为了让该别名能被正确解析为文件路径,`@foo` 或 `@foo/bar`
中的一个必须是[根别名](concept-aliases.md#defining-aliases)。 中的一个必须是[根别名](concept-aliases.md#defining-aliases)。
当我们使用[基本应用模版](start-installation.md)时,可以把你的类放置在顶级命名空间 `app` 下, 当我们使用[基本应用模版](start-installation.md)时,可以把你的类放置在顶级命名空间 `app` 下,这样它们就可以被 Yii 自动加载,
这样它们就可以被 Yii 自动加载,而无需定义一个新的别名。 而无需定义一个新的别名。这是因为 `@app` 本身是一个[预定义别名](concept-aliases.md#predefined-aliases),
这是因为 `@app` 本身是一个[预定义别名](concept-aliases.md#predefined-aliases),且类似于 `app\components\MyClass` 这样的类名, 且类似于 `app\components\MyClass` 这样的类名,
基于我们刚才所提到的算法,可以正确解析出 `AppBasePath/components/MyClass.php` 路径。 基于我们刚才所提到的算法,可以正确解析出 `AppBasePath/components/MyClass.php` 路径。
在[高级应用模版](tutorial-advanced-app.md)里,每一逻辑层级会使用他自己的根别名。 在[高级应用模版](tutorial-advanced-app.md)里,每一逻辑层级会使用他自己的根别名。
@ -37,14 +37,16 @@ $classFile = Yii::getAlias('@' . str_replace('\\', '/', $className) . '.php');
因此,你可以把前端的类放在 `frontend` 命名空间,而后端的类放在 `backend` 因此,你可以把前端的类放在 `frontend` 命名空间,而后端的类放在 `backend`
这样这些类就可以被 Yii 自动加载了。 这样这些类就可以被 Yii 自动加载了。
To add a custom namespace to the autoloader you need to define an alias for the base directory of the namespace using [[Yii::setAlias()]].
For example to load classes in the `foo` namespace that are located in the `path/to/foo` directory you will call `Yii::setAlias('@foo', 'path/to/foo')`.
类映射表(Class Map) <span id="class-map"></span> 类映射表(Class Map) <span id="class-map"></span>
--------- ---------
Yii 类自动加载器支持**类映射表**功能,该功能会建立一个从类的名字到类文件路径的映射。 Yii 类自动加载器支持**类映射表**功能,该功能会建立一个从类的名字到类文件路径的映射。
当自动加载器加载一个文件时,他首先检查映射表里有没有该类。 当自动加载器加载一个文件时,他首先检查映射表里有没有该类。
如果有,对应的文件路径就直接加载了,省掉了进一步的检查。 如果有,对应的文件路径就直接加载了,省掉了进一步的检查。这让类的自动加载变得超级快。
这让类的自动加载变得超级快。事实上所有的 Yii 核心类都是这样加载的。 事实上所有的 Yii 核心类都是这样加载的。
你可以用 `Yii::$classMap` 方法向映射表中添加类, 你可以用 `Yii::$classMap` 方法向映射表中添加类,
@ -52,22 +54,22 @@ Yii 类自动加载器支持**类映射表**功能,该功能会建立一个从
Yii::$classMap['foo\bar\MyClass'] = 'path/to/MyClass.php'; Yii::$classMap['foo\bar\MyClass'] = 'path/to/MyClass.php';
``` ```
[别名](concept-aliases.md)可以被用于指定类文件的路径。 [别名](concept-aliases.md)可以被用于指定类文件的路径。你应该在[引导启动](runtime-bootstrapping.md)的过程中设置类映射表,
你应该在[引导启动](runtime-bootstrapping.md)的过程中设置类映射表,这样映射表就可以在你使用具体类之前就准备好。 这样映射表就可以在你使用具体类之前就准备好。
用其他自动加载器 <span id="using-other-autoloaders"></span> 用其他自动加载器 <span id="using-other-autoloaders"></span>
----------------------- -----------------------
因为 Yii 完全支持 Composer 管理依赖包, 因为 Yii 完全支持 Composer 管理依赖包,所以推荐你也同时安装 Composer 的自动加载器,
所以推荐你也同时安装 Composer 的自动加载器,如果你用了一些自带自动加载器的第三方类库, 如果你用了一些自带自动加载器的第三方类库,
你应该也安装下它们。 你应该也安装下它们。
当你同时使用其他自动加载器和 Yii 自动加载器时,应该在其他自动加载器安装成功**之后**,再包含 `Yii.php` 文件。 当你同时使用其他自动加载器和 Yii 自动加载器时,应该在其他自动加载器安装成功**之后**,
这将使 Yii 成为第一个响应任何类自动加载请求的自动加载器。 再包含 `Yii.php` 文件。这将使 Yii 成为第一个响应任何类自动加载请求的自动加载器。
举例来说,以下代码提取自[基本应用模版](start-installation.md)的[入口脚本](structure-entry-scripts.md) 。 举例来说,以下代码提取自[基本应用模版](start-installation.md)的
第一行安装了 Composer 的自动加载器, [入口脚本](structure-entry-scripts.md) 。
第二行才是 Yii 的自动加载器: 一行安装了 Composer 的自动加载器,第二行才是 Yii 的自动加载器:
```php ```php
require(__DIR__ . '/../vendor/autoload.php'); require(__DIR__ . '/../vendor/autoload.php');
@ -75,18 +77,18 @@ require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
``` ```
你也可以只使用 Composer 的自动加载,而不用 Yii 的自动加载。 你也可以只使用 Composer 的自动加载,而不用 Yii 的自动加载。
不过这样做的话,类的加载效率会下降,且你必须遵循 Composer 所设定的规则, 不过这样做的话,类的加载效率会下降,
从而让你的类满足可以被自动加载的要求。 且你必须遵循 Composer 所设定的规则,从而让你的类满足可以被自动加载的要求。
> 补充:若你不想要使用 Yii 的自动加载器,你必须创建一个你自己版本的 `Yii.php` 文件, > Info: 若你不想要使用 Yii 的自动加载器,你必须创建一个你自己版本的 `Yii.php` 文件,
并把它包含进你的[入口脚本](structure-entry-scripts.md)里。 并把它包含进你的[入口脚本](structure-entry-scripts.md)里。
自动加载扩展类 <span id="autoloading-extension-classes"></span> 自动加载扩展类 <span id="autoloading-extension-classes"></span>
----------------------------- -----------------------------
Yii 自动加载器支持自动加载[扩展](structure-extensions.md)的类。唯一的要求是它需要在 `composer.json` Yii 自动加载器支持自动加载[扩展](structure-extensions.md)的类。唯一的要求是它需要在 `composer.json` 文件里正确地定义 `autoload` 部分。
文件里正确地定义 `autoload` 部分。请参考 [Composer 文档(英文)](https://getcomposer.org/doc/04-schema.md#autoload) 请参考 [Composer 文档(英文)](https://getcomposer.org/doc/04-schema.md#autoload)
([中文汉化](https://github.com/5-say/composer-doc-cn/blob/master/cn-introduction/04-schema.md#autoload)),来了解如何正确描述 `autoload` 的更多细节。 ([中文汉化](https://github.com/5-say/composer-doc-cn/blob/master/cn-introduction/04-schema.md#autoload)),来了解如何正确描述 `autoload` 的更多细节。
在你不使用 Yii 的自动加载器时,Composer 的自动加载器仍然可以帮你自动加载扩展内的类。 在你不使用 Yii 的自动加载器时,Composer 的自动加载器仍然可以帮你自动加载扩展内的类。

40
docs/guide-zh-CN/concept-behaviors.md

@ -4,9 +4,9 @@
行为是 [[yii\base\Behavior]] 或其子类的实例。 行为是 [[yii\base\Behavior]] 或其子类的实例。
行为,也称为 [mixins](http://en.wikipedia.org/wiki/Mixin), 行为,也称为 [mixins](http://en.wikipedia.org/wiki/Mixin),
可以无须改变类继承关系即可增强一个已有的 [[yii\base\Component|组件]] 类功能。 可以无须改变类继承关系即可增强一个已有的 [[yii\base\Component|组件]] 类功能。
当行为附加到组件后,它将“注入”它的方法和属性到组件,然后可以像访问组件内定义的方法和属性一样访问它们。 当行为附加到组件后,它将“注入”它的方法和属性到组件,
此外,行为通过组件能响应被触发的[事件](basic-events.md), 然后可以像访问组件内定义的方法和属性一样访问它们。
从而自定义或调整组件正常执行的代码。 此外,行为通过组件能响应被触发的[事件](basic-events.md),从而自定义或调整组件正常执行的代码。
定义行为 定义行为
@ -197,8 +197,8 @@ $component->attachBehaviors([
使用行为,必须像前文描述的一样先把它附加到 [[yii\base\Component|component]] 类或其子类。一旦行为附加到组件,就可以直接使用它。 使用行为,必须像前文描述的一样先把它附加到 [[yii\base\Component|component]] 类或其子类。一旦行为附加到组件,就可以直接使用它。
行为附加到组件后,可以通过组件访问一个行为的**公共**成员变量或 getter 和 setter 方法定义的 行为附加到组件后,可以通过组件访问一个行为的**公共**成员变量
[属性](concept-properties.md): 或 getter 和 setter 方法定义的[属性](concept-properties.md):
```php ```php
// "prop1" 是定义在行为类的属性 // "prop1" 是定义在行为类的属性
@ -219,8 +219,8 @@ $component->foo();
如果两个行为都定义了一样的属性或方法,并且它们都附加到同一个组件, 如果两个行为都定义了一样的属性或方法,并且它们都附加到同一个组件,
那么**首先**附加上的行为在属性或方法被访问时有优先权。 那么**首先**附加上的行为在属性或方法被访问时有优先权。
附加行为到组件时的命名行为, 附加行为到组件时的命名行为,可以使用这个名称来访问行为对象,
可以使用这个名称来访问行为对象,如下所示: 如下所示:
```php ```php
$behavior = $component->getBehavior('myBehavior'); $behavior = $component->getBehavior('myBehavior');
@ -287,14 +287,14 @@ class User extends ActiveRecord
以上指定的行为数组: 以上指定的行为数组:
* 当记录插入时, * 当记录插入时,行为将当前时间戳赋值给
行为将当前的 UNIX 时间戳赋值给 `created_at``updated_at` 属性; `created_at``updated_at` 属性;
* 当记录更新时,行为将当前的 UNIX 时间戳赋值给 `updated_at` 属性。 * 当记录更新时,行为将当前时间戳赋值给 `updated_at` 属性。
> Note: For the above implementation to work with MySQL database, please declare the columns(`created_at`, `updated_at`) as int(11) for being UNIX timestamp. > Note: For the above implementation to work with MySQL database, please declare the columns(`created_at`, `updated_at`) as int(11) for being UNIX timestamp.
保存 `User` 对象, With that code in place, if you have a `User` object and try to save it, you will find its `created_at` and `updated_at` are automatically
将会发现它的 `created_at``updated_at` 属性自动填充了当前时间戳: filled with the current UNIX timestamp:
```php ```php
$user = new User; $user = new User;
@ -311,7 +311,7 @@ echo $user->created_at; // 显示当前时间戳
$user->touch('login_time'); $user->touch('login_time');
``` ```
Other behaviors 其它行为
--------------- ---------------
There are several built-in and external behaviors available: There are several built-in and external behaviors available:
@ -326,7 +326,7 @@ There are several built-in and external behaviors available:
- [yii2tech\ar\position\PositionBehavior](https://github.com/yii2tech/ar-position) - allows managing records order in an - [yii2tech\ar\position\PositionBehavior](https://github.com/yii2tech/ar-position) - allows managing records order in an
integer field by providing reordering methods. integer field by providing reordering methods.
Comparing Behaviors with Traits <span id="comparison-with-traits"></span> 比较行为与 Traits <span id="comparison-with-traits"></span>
---------------------- ----------------------
While behaviors are similar to [traits](http://www.php.net/traits) in that they both "inject" their While behaviors are similar to [traits](http://www.php.net/traits) in that they both "inject" their
@ -334,13 +334,13 @@ properties and methods to the primary class, they differ in many aspects. As exp
both have pros and cons. They are more like complements to each other rather than alternatives. both have pros and cons. They are more like complements to each other rather than alternatives.
### Reasons to Use Behaviors <span id="pros-for-behaviors"></span> ### 使用行为的原因 <span id="pros-for-behaviors"></span>
Behavior classes, like normal classes, support inheritance. Traits, on the other hand, 行为类像普通类支持继承。另一方面,traits 可以视为 PHP 语言支持的复制粘贴功能,
can be considered as language-supported copy and paste. They do not support inheritance. 它不支持继承。
Behaviors can be attached and detached to a component dynamically without requiring modification of the component class. 行为无须修改组件类就可动态附加到组件或移除。
To use a trait, you must modify the code of the class using it. 要使用 traits,必须修改使用它的类。
Behaviors are configurable while traits are not. Behaviors are configurable while traits are not.
@ -352,7 +352,7 @@ Name conflicts caused by different traits requires manual resolution by renaming
properties or methods. properties or methods.
### Reasons to Use Traits <span id="pros-for-traits"></span> ### 使用 Traits 的原因 <span id="pros-for-traits"></span>
Traits are much more efficient than behaviors as behaviors are objects that take both time and memory. Traits are much more efficient than behaviors as behaviors are objects that take both time and memory.

27
docs/guide-zh-CN/concept-components.md

@ -26,10 +26,10 @@ echo DatePicker::widget([
这个小部件继承自 [[yii\base\Component]],它的各项属性改写起来会很容易。 这个小部件继承自 [[yii\base\Component]],它的各项属性改写起来会很容易。
正是因为组件功能的强大,他们比常规的对象(Object)稍微重量级一点, 正是因为组件功能的强大,他们比常规的对象(Object)稍微重量级一点,因为他们要使用额外的内存和 CPU 时间来处理
因为他们要使用额外的内存和 CPU 时间来处理 [事件](concept-events.md) 和 [行为](concept-behaviors.md) 。 [事件](concept-events.md) 和 [行为](concept-behaviors.md) 。
如果你不需要这两项功能,可以继承 [[yii\base\Object]] 而不是 [[yii\base\Component]]。 如果你不需要这两项功能,可以继承 [[yii\base\Object]]
这样组件可以像普通 PHP 对象一样高效, 而不是 [[yii\base\Component]]。这样组件可以像普通 PHP 对象一样高效,
同时还支持[属性(Property)](concept-properties.md)功能。 同时还支持[属性(Property)](concept-properties.md)功能。
当继承 [[yii\base\Component]] 或 [[yii\base\Object]] 时, 当继承 [[yii\base\Component]] 或 [[yii\base\Object]] 时,
@ -43,18 +43,20 @@ echo DatePicker::widget([
例子如下: 例子如下:
```php ```php
<?php
namespace yii\components\MyClass; namespace yii\components\MyClass;
use yii\base\Object; use yii\base\BaseObject;
class MyClass extends Object class MyClass extends BaseObject
{ {
public $prop1; public $prop1;
public $prop2; public $prop2;
public function __construct($param1, $param2, $config = []) public function __construct($param1, $param2, $config = [])
{ {
// ... 配置生效前的初始化过程 // ... initialization before configuration is applied
parent::__construct($config); parent::__construct($config);
} }
@ -63,7 +65,7 @@ class MyClass extends Object
{ {
parent::init(); parent::init();
// ... 配置生效后的初始化过程 // ... initialization after configuration is applied
} }
} }
``` ```
@ -80,8 +82,8 @@ $component = \Yii::createObject([
], [1, 2]); ], [1, 2]);
``` ```
> 补充:尽管调用 [[Yii::createObject()]] 的方法看起来更加复杂, > Info: 尽管调用 [[Yii::createObject()]] 的方法看起来更加复杂,但这主要因为它更加灵活强大
> 但这主要因为它更加灵活强大,它是基于[依赖注入容器](concept-di-container.md)实现的。 > 它是基于[依赖注入容器](concept-di-container.md)实现的。
[[yii\base\Object]] 类执行时的生命周期如下: [[yii\base\Object]] 类执行时的生命周期如下:
@ -91,5 +93,6 @@ $component = \Yii::createObject([
3. 在 [[yii\base\Object::init()|init()]] 方法内进行初始化后的收尾工作。你可以通过重写此方法,进行一些良品检验,属性的初始化之类的工作。 3. 在 [[yii\base\Object::init()|init()]] 方法内进行初始化后的收尾工作。你可以通过重写此方法,进行一些良品检验,属性的初始化之类的工作。
4. 对象方法调用。 4. 对象方法调用。
前三步都是在对象的构造方法内发生的。 前三步都是在对象的构造方法内发生的。这意味着一旦你获得了一个对象实例,
这意味着一旦你获得了一个对象实例,那么它就已经初始化就绪可供使用。 那么它就已经初始化就绪可供使用。

100
docs/guide-zh-CN/concept-configurations.md

@ -1,7 +1,11 @@
配置 配置
============= =============
在 Yii 中,创建新对象和初始化已存在对象时广泛使用配置。配置通常包含被创建对象的类名和一组将要赋值给对象[属性](concept-properties.md)的初始值。还可能包含一组将被附加到对象[事件](concept-events.md)上的句柄。和一组将被附加到对象上的[行为](concept-behaviors.md)。 在 Yii 中,创建新对象和初始化已存在对象时广泛使用配置。
配置通常包含被创建对象的类名和一组将要赋值给对象
[属性](concept-properties.md)的初始值。
还可能包含一组将被附加到对象[事件](concept-events.md)上的句柄。
和一组将被附加到对象上的[行为](concept-behaviors.md)。
以下代码中的配置被用来创建并初始化一个数据库连接: 以下代码中的配置被用来创建并初始化一个数据库连接:
@ -17,9 +21,12 @@ $config = [
$db = Yii::createObject($config); $db = Yii::createObject($config);
``` ```
[[Yii::createObject()]] 方法接受一个配置数组并根据数组中指定的类名创建对象。对象实例化后,剩余的参数被用来初始化对象的属性,事件处理和行为。 [[Yii::createObject()]] 方法接受一个配置数组并根据数组中指定的类名创建对象。
对象实例化后,剩余的参数被用来初始化对象的属性,
事件处理和行为。
对于已存在的对象,可以使用 [[Yii::configure()]] 方法根据配置去初始化其属性,就像这样: 对于已存在的对象,可以使用 [[Yii::configure()]] 方法根据配置去初始化其属性,
就像这样:
```php ```php
Yii::configure($object, $config); Yii::configure($object, $config);
@ -44,9 +51,14 @@ Yii::configure($object, $config);
其中 其中
* `class` 元素指定了将要创建的对象的完全限定类名。 * `class` 元素指定了将要创建的对象的完全限定类名。
* `propertyName` 元素指定了对象属性的初始值。键名是属性名,值是该属性对应的初始值。只有公共成员变量以及通过 getter/setter 定义的[属性](concept-properties.md)可以被配置。 * `propertyName` 元素指定了对象属性的初始值。键名是属性名,值是该属性对应的初始值。
* `on eventName` 元素指定了附加到对象[事件](concept-events.md)上的句柄是什么。请注意,数组的键名由 `on ` 前缀加事件名组成。请参考[事件](concept-events.md)章节了解事件句柄格式。 只有公共成员变量以及通过 getter/setter 定义的
* `as behaviorName` 元素指定了附加到对象的[行为](concept-behaviors.md)。请注意,数组的键名由 `as ` 前缀加行为名组成。`$behaviorConfig` [属性](concept-properties.md)可以被配置。
* `on eventName` 元素指定了附加到对象[事件](concept-events.md)上的句柄是什么。
请注意,数组的键名由 `on ` 前缀加事件名组成。
请参考[事件](concept-events.md)章节了解事件句柄格式。
* `as behaviorName` 元素指定了附加到对象的[行为](concept-behaviors.md)。
请注意,数组的键名由 `as ` 前缀加行为名组成。`$behaviorConfig`
值表示创建行为的配置信息,格式与我们之前描述的配置格式一样。 值表示创建行为的配置信息,格式与我们之前描述的配置格式一样。
下面是一个配置了初始化属性值,事件句柄和行为的示例: 下面是一个配置了初始化属性值,事件句柄和行为的示例:
@ -68,12 +80,18 @@ Yii::configure($object, $config);
## 使用配置 ## 使用配置
Yii 中的配置可以用在很多场景。本章开头我们展示了如何使用 [[Yii::creatObject()]] 根据配置信息创建对象。本小节将介绍配置的两种主要用法 —— 配置应用与配置小部件。 Yii 中的配置可以用在很多场景。本章开头我们展示了如何使用 [[Yii::creatObject()]]
根据配置信息创建对象。本小节将介绍配置的两种
主要用法 —— 配置应用与配置小部件。
### 应用的配置 <span id="application-configurations"></span> ### 应用的配置 <span id="application-configurations"></span>
[应用](structure-applications.md)的配置可能是最复杂的配置之一。因为 [[yii\web\Application|application]] 类拥有很多可配置的属性和事件。更重要的是它的 [[yii\web\Application::components|components]] 属性可以接收配置数组并通过应用注册为组件。以下是一个针对[基础应用模板](start-installation.md)的应用配置概要: [应用](structure-applications.md)的配置可能是最复杂的配置之一。
因为 [[yii\web\Application|application]] 类拥有很多可配置的属性和事件。
更重要的是它的 [[yii\web\Application::components|components]]
属性可以接收配置数组并通过应用注册为组件。
以下是一个针对[基础应用模板](start-installation.md)的应用配置概要:
```php ```php
$config = [ $config = [
@ -107,18 +125,44 @@ $config = [
]; ];
``` ```
配置中没有 `class` 键的原因是这段配置应用在下面的入口脚本中,类名已经指定了。 配置中没有 `class` 键的原因是这段配置应用在下面的入口脚本中,
类名已经指定了。
```php ```php
(new yii\web\Application($config))->run(); (new yii\web\Application($config))->run();
``` ```
更多关于应用 `components` 属性配置的信息可以查阅[应用](structure-applications.md)以及[服务定位器](concept-service-locator.md)章节。 更多关于应用 `components` 属性配置的信息可以查阅[应用](structure-applications.md)
以及[服务定位器](concept-service-locator.md)章节。
Since version 2.0.11, the application configuration supports [Dependency Injection Container](concept-di-container.md)
configuration using `container` property. For example:
```php
$config = [
'id' => 'basic',
'basePath' => dirname(__DIR__),
'extensions' => require __DIR__ . '/../vendor/yiisoft/extensions.php',
'container' => [
'definitions' => [
'yii\widgets\LinkPager' => ['maxButtonCount' => 5]
],
'singletons' => [
// Dependency Injection Container singletons configuration
]
]
];
```
To know more about the possible values of `definitions` and `singletons` configuration arrays and real-life examples,
please read [Advanced Practical Usage](concept-di-container.md#advanced-practical-usage) subsection of the
[Dependency Injection Container](concept-di-container.md) article.
### 小部件的配置 <span id="widget-configurations"></span> ### 小部件的配置 <span id="widget-configurations"></span>
使用[小部件](structure-widgets.md)时,常常需要配置以便自定义其属性。 [[yii\base\Widget::widget()]] 和 [[yii\base\Widget::begin()]] 方法都可以用来创建小部件。它们可以接受配置数组: 使用[小部件](structure-widgets.md)时,常常需要配置以便自定义其属性。
[[yii\base\Widget::widget()]] 和 [[yii\base\Widget::begin()]] 方法都可以用来创建小部件。
它们可以接受配置数组:
```php ```php
use yii\widgets\Menu; use yii\widgets\Menu;
@ -133,14 +177,17 @@ echo Menu::widget([
]); ]);
``` ```
上述代码创建了一个小部件 `Menu` 并将其 `activateItems` 属性初始化为 false。`item` 属性也配置成了将要显示的菜单条目。 上述代码创建了一个小部件 `Menu` 并将其 `activateItems` 属性初始化为 false。
`item` 属性也配置成了将要显示的菜单条目。
请注意,代码中已经给出了类名 `yii\widgets\Menu`,配置数组**不应该**再包含 `class` 键。 请注意,代码中已经给出了类名 `yii\widgets\Menu`,配置数组**不应该**再包含 `class` 键。
## 配置文件 <span id="configuration-files"></span> ## 配置文件 <span id="configuration-files"></span>
当配置的内容十分复杂,通用做法是将其存储在一或多个 PHP 文件中,这些文件被称为**配置文件**。一个配置文件返回的是 PHP 数组。例如,像这样把应用配置信息存储在名为 `web.php` 的文件中: 当配置的内容十分复杂,通用做法是将其存储在一或多个 PHP 文件中,
这些文件被称为**配置文件**。一个配置文件返回的是 PHP 数组。
例如,像这样把应用配置信息存储在名为 `web.php` 的文件中:
```php ```php
return [ return [
@ -151,7 +198,8 @@ return [
]; ];
``` ```
鉴于 `components` 配置也很复杂,上述代码把它们存储在单独的 `components.php` 文件中,并且包含在 `web.php` 里。`components.php` 的内容如下: 鉴于 `components` 配置也很复杂,上述代码把它们存储在单独的 `components.php` 文件中,并且包含在 `web.php` 里。
`components.php` 的内容如下:
```php ```php
return [ return [
@ -190,9 +238,13 @@ $config = require('path/to/web.php');
## 默认配置 <span id="default-configurations"></span> ## 默认配置 <span id="default-configurations"></span>
[[Yii::createObject()]] 方法基于[依赖注入容器](concept-di-container.md)实现。使用 [[Yii::creatObject()]] 创建对象时,可以附加一系列**默认配置**到指定类的任何实例。默认配置还可以在[入口脚本](runtime-bootstrapping.md)中调用 `Yii::$container->set()` 来定义。 [[Yii::createObject()]] 方法基于[依赖注入容器](concept-di-container.md)实现。
使用 [[Yii::creatObject()]] 创建对象时,可以附加一系列**默认配置**到指定类的任何实例。
默认配置还可以在[入口脚本](runtime-bootstrapping.md)
中调用 `Yii::$container->set()` 来定义。
例如,如果你想自定义 [[yii\widgets\LinkPager]] 小部件,以便让分页器最多只显示 5 个翻页按钮(默认是 10 个),你可以用下述代码实现: 例如,如果你想自定义 [[yii\widgets\LinkPager]] 小部件,以便让分页器最多只显示 5 个翻页按钮(默认是 10 个),
你可以用下述代码实现:
```php ```php
\Yii::$container->set('yii\widgets\LinkPager', [ \Yii::$container->set('yii\widgets\LinkPager', [
@ -200,12 +252,17 @@ $config = require('path/to/web.php');
]); ]);
``` ```
不使用默认配置的话,你就得在任何使用分页器的地方,都配置 `maxButtonCount` 的值。 不使用默认配置的话,你就得在任何使用分页器的地方,
都配置 `maxButtonCount` 的值。
## 环境常量 <span id="environment-constants"></span> ## 环境常量 <span id="environment-constants"></span>
配置经常要随着应用运行的不同环境更改。例如在开发环境中,你可能使用名为 `mydb_dev` 的数据库,而生产环境则使用 `mydb_prod` 数据库。为了便于切换使用环境,Yii 提供了一个定义在入口脚本中的 `YII_ENV` 常量。如下: 配置经常要随着应用运行的不同环境更改。例如在开发环境中,
你可能使用名为 `mydb_dev` 的数据库,
而生产环境则使用 `mydb_prod` 数据库。
为了便于切换使用环境,Yii 提供了一个定义在入口脚本中的 `YII_ENV` 常量。
如下:
```php ```php
defined('YII_ENV') or define('YII_ENV', 'dev'); defined('YII_ENV') or define('YII_ENV', 'dev');
@ -213,11 +270,14 @@ defined('YII_ENV') or define('YII_ENV', 'dev');
你可以把 `YII_ENV` 定义成以下任何一种值: 你可以把 `YII_ENV` 定义成以下任何一种值:
- `prod`:生产环境。常量 `YII_ENV_PROD` 将被看作 true。如果你没修改过,这就是 `YII_ENV` 的默认值。 - `prod`:生产环境。常量 `YII_ENV_PROD` 将被看作 true。
如果你没修改过,这就是 `YII_ENV` 的默认值。
- `dev`:开发环境。常量 `YII_ENV_DEV` 将被看作 true。 - `dev`:开发环境。常量 `YII_ENV_DEV` 将被看作 true。
- `test`:测试环境。常量 `YII_ENV_TEST` 将被看作 true。 - `test`:测试环境。常量 `YII_ENV_TEST` 将被看作 true。
有了这些环境常量,你就可以根据当下应用运行环境的不同,进行差异化配置。例如,应用可以包含下述代码只在开发环境中开启[调试工具](tool-debugger.md)。 有了这些环境常量,你就可以根据当下应用运行环境的不同,进行差异化配置。
例如,应用可以包含下述代码只在开发环境中开启
[调试工具](tool-debugger.md)。
```php ```php
$config = [...]; $config = [...];

299
docs/guide-zh-CN/concept-di-container.md

@ -1,22 +1,29 @@
依赖注入容器 依赖注入容器
============================== ==============================
依赖注入(Dependency Injection,DI)容器就是一个对象,它知道怎样初始化并配置对象及其依赖的所有对象。[Martin 的文章](http://martinfowler.com/articles/injection.html) 已经解释了 DI 容器为什么很有用。这里我们主要讲解 Yii 提供的 DI 容器的使用方法。 依赖注入(Dependency Injection,DI)容器就是一个对象,它知道怎样初始化并配置对象及其依赖的所有对象。
[Martin 的文章](http://martinfowler.com/articles/injection.html) 已经解释了 DI 容器为什么很有用。
这里我们主要讲解 Yii 提供的 DI 容器的使用方法。
依赖注入 <span id="dependency-injection"></span> 依赖注入 <span id="dependency-injection"></span>
-------------------- --------------------
Yii 通过 [[yii\di\Container]] 类提供 DI 容器特性。它支持如下几种类型的依赖注入: Yii 通过 [[yii\di\Container]] 类提供 DI 容器特性。
它支持如下几种类型的依赖注入:
* 构造方法注入; * 构造方法注入;
* Method injection;
* Setter 和属性注入; * Setter 和属性注入;
* PHP 回调注入. * PHP 回调注入.
### 构造方法注入 <span id="constructor-injection"></span> ### 构造方法注入 <span id="constructor-injection"></span>
在参数类型提示的帮助下,DI 容器实现了构造方法注入。当容器被用于创建一个新对象时,类型提示会告诉它要依赖什么类或接口。容器会尝试获取它所依赖的类或接口的实例,然后通过构造器将其注入新的对象。例如: 在参数类型提示的帮助下,DI 容器实现了构造方法注入。当容器被用于创建一个新对象时,
类型提示会告诉它要依赖什么类或接口。
容器会尝试获取它所依赖的类或接口的实例,
然后通过构造器将其注入新的对象。例如:
```php ```php
class Foo class Foo
@ -33,9 +40,42 @@ $foo = new Foo($bar);
``` ```
### Method Injection <span id="method-injection"></span>
Usually the dependencies of a class are passed to the constructor and are available inside of the class during the whole lifecycle.
With Method Injection it is possible to provide a dependency that is only needed by a single method of the class
and passing it to the constructor may not be possible or may cause too much overhead in the majority of use cases.
A class method can be defined like the `doSomething()` method in the following example:
```php
class MyClass extends \yii\base\Component
{
public function __construct(/*Some lightweight dependencies here*/, $config = [])
{
// ...
}
public function doSomething($param1, \my\heavy\Dependency $something)
{
// do something with $something
}
}
```
You may call that method either by passing an instance of `\my\heavy\Dependency` yourself or using [[yii\di\Container::invoke()]] like the following:
```php
$obj = new MyClass(/*...*/);
Yii::$container->invoke([$obj, 'doSomething'], ['param1' => 42]); // $something will be provided by the DI container
```
### Setter 和属性注入 <span id="setter-and-property-injection"></span> ### Setter 和属性注入 <span id="setter-and-property-injection"></span>
Setter 和属性注入是通过[配置](concept-configurations.md)提供支持的。当注册一个依赖或创建一个新对象时,你可以提供一个配置,该配置会提供给容器用于通过相应的 Setter 或属性注入依赖。例如: Setter 和属性注入是通过[配置](concept-configurations.md)提供支持的。
当注册一个依赖或创建一个新对象时,你可以提供一个配置,
该配置会提供给容器用于通过相应的 Setter 或属性注入依赖。
例如:
```php ```php
use yii\base\Object; use yii\base\Object;
@ -63,24 +103,56 @@ $container->get('Foo', [], [
]); ]);
``` ```
> Info: The [[yii\di\Container::get()]] method takes its third parameter as a configuration array that should
be applied to the object being created. If the class implements the [[yii\base\Configurable]] interface (e.g.
[[yii\base\BaseObject]]), the configuration array will be passed as the last parameter to the class constructor;
otherwise, the configuration will be applied *after* the object is created.
### PHP 回调注入 <span id="php-callable-injection"></span> ### PHP 回调注入 <span id="php-callable-injection"></span>
这种情况下,容器将使用一个注册过的 PHP 回调创建一个类的新实例。回调负责解决依赖并将其恰当地注入新创建的对象。例如: In this case, the container will use a registered PHP callable to build new instances of a class.
Each time when [[yii\di\Container::get()]] is called, the corresponding callable will be invoked.
The callable is responsible to resolve the dependencies and inject them appropriately to the newly
created objects. For example,
```php ```php
$container->set('Foo', function () { $container->set('Foo', function () {
return new Foo(new Bar); $foo = new Foo(new Bar);
// ... other initializations ...
return $foo;
}); });
$foo = $container->get('Foo'); $foo = $container->get('Foo');
``` ```
To hide the complex logic for building a new object, you may use a static class method as callable. For example,
```php
class FooBuilder
{
public static function build()
{
$foo = new Foo(new Bar);
// ... other initializations ...
return $foo;
}
}
$container->set('Foo', ['app\helper\FooBuilder', 'build']);
$foo = $container->get('Foo');
```
By doing so, the person who wants to configure the `Foo` class no longer needs to be aware of how it is built.
注册依赖关系 <span id="registering-dependencies"></span> 注册依赖关系 <span id="registering-dependencies"></span>
------------------------ ------------------------
可以用 [[yii\di\Container::set()]] 注册依赖关系。注册会用到一个依赖关系名称和一个依赖关系的定义。依赖关系名称可以是一个类名,一个接口名或一个别名。依赖关系的定义可以是一个类名,一个配置数组,或者一个 PHP 回调。 可以用 [[yii\di\Container::set()]] 注册依赖关系。注册会用到一个依赖关系名称和一个依赖关系的定义。
依赖关系名称可以是一个类名,一个接口名或一个别名。
依赖关系的定义可以是一个类名,一个配置数组,或者一个 PHP 回调。
```php ```php
$container = new \yii\di\Container; $container = new \yii\di\Container;
@ -89,7 +161,8 @@ $container = new \yii\di\Container;
$container->set('yii\db\Connection'); $container->set('yii\db\Connection');
// 注册一个接口 // 注册一个接口
// 当一个类依赖这个接口时,相应的类会被初始化作为依赖对象。 // 当一个类依赖这个接口时,
//相应的类会被初始化作为依赖对象。
$container->set('yii\mail\MailInterface', 'yii\swiftmailer\Mailer'); $container->set('yii\mail\MailInterface', 'yii\swiftmailer\Mailer');
// 注册一个别名。 // 注册一个别名。
@ -126,9 +199,12 @@ $container->set('db', function ($container, $params, $config) {
$container->set('pageCache', new FileCache); $container->set('pageCache', new FileCache);
``` ```
> Tip: 如果依赖关系名称和依赖关系的定义相同,则不需要通过 DI 容器注册该依赖关系。 > Tip: 如果依赖关系名称和依赖关系的定义相同,
则不需要通过 DI 容器注册该依赖关系。
通过 `set()` 注册的依赖关系,在每次使用时都会产生一个新实例。可以使用 [[yii\di\Container::setSingleton()]] 注册一个单例的依赖关系: 通过 `set()` 注册的依赖关系,在每次使用时都会产生一个新实例。
可以使用 [[yii\di\Container::setSingleton()]]
注册一个单例的依赖关系:
```php ```php
$container->setSingleton('yii\db\Connection', [ $container->setSingleton('yii\db\Connection', [
@ -143,9 +219,18 @@ $container->setSingleton('yii\db\Connection', [
解决依赖关系 <span id="resolving-dependencies"></span> 解决依赖关系 <span id="resolving-dependencies"></span>
---------------------- ----------------------
注册依赖关系后,就可以使用 DI 容器创建新对象了。容器会自动解决依赖关系,将依赖实例化并注入新创建的对象。依赖关系的解决是递归的,如果一个依赖关系中还有其他依赖关系,则这些依赖关系都会被自动解决。 注册依赖关系后,就可以使用 DI 容器创建新对象了。容器会自动解决依赖关系,
将依赖实例化并注入新创建的对象。依赖关系的解决是递归的,
如果一个依赖关系中还有其他依赖关系,
则这些依赖关系都会被自动解决。
可以使用 [[yii\di\Container::get()]] 创建新的对象。该方法接收一个依赖关系名称,它可以是一个类名,一个接口名或一个别名。依赖关系名或许是通过 `set()``setSingleton()` 注册的。你可以随意地提供一个类的构造器参数列表和一个[configuration](concept-configurations.md) 用于配置新创建的对象。例如: 可以使用 [[yii\di\Container::get()]] 创建新的对象。
该方法接收一个依赖关系名称,它可以是一个类名,
一个接口名或一个别名。依赖关系名或许是通过 `set()``setSingleton()` 注册的。
你可以随意地提供一个类的构造器参数列表和一个
[configuration](concept-configurations.md) 用于配置新创建的对象。
例如:
```php ```php
// "db" 是前面定义过的一个别名 // "db" 是前面定义过的一个别名
@ -155,9 +240,15 @@ $db = $container->get('db');
$engine = $container->get('app\components\SearchEngine', [$apiKey], ['type' => 1]); $engine = $container->get('app\components\SearchEngine', [$apiKey], ['type' => 1]);
``` ```
代码背后,DI 容器做了比创建对象多的多的工作。容器首先将检查类的构造方法,找出依赖的类或接口名,然后自动递归解决这些依赖关系。 代码背后,DI 容器做了比创建对象多的多的工作。
容器首先将检查类的构造方法,找出依赖的类或接口名,
然后自动递归解决这些依赖关系。
如下代码展示了一个更复杂的示例。`UserLister` 类依赖一个实现了 `UserFinderInterface` 接口的对象;`UserFinder` 类实现了这个接口,并依赖于一个 `Connection` 对象。所有这些依赖关系都是通过类构造器参数的类型提示定义的。通过属性依赖关系的注册,DI 容器可以自动解决这些依赖关系并能通过一个简单的 `get('userLister')` 调用创建一个新的 `UserLister` 实例。 如下代码展示了一个更复杂的示例。`UserLister` 类依赖一个实现了 `UserFinderInterface` 接口的对象;
`UserFinder` 类实现了这个接口,并依赖于一个 `Connection` 对象。
所有这些依赖关系都是通过类构造器参数的类型提示定义的。
通过属性依赖关系的注册,DI 容器可以自动解决这些依赖关系并能通过一个
简单的 `get('userLister')` 调用创建一个新的 `UserLister` 实例。
```php ```php
namespace app\models; namespace app\models;
@ -219,8 +310,12 @@ $lister = new UserLister($finder);
实践中的运用 <span id="practical-usage"></span> 实践中的运用 <span id="practical-usage"></span>
--------------- ---------------
当在应用程序的[入口脚本](structure-entry-scripts.md)中引入 `Yii.php` 文件时,Yii 就创建了一个 DI 容器。这个 DI 容器可以通过 [[Yii::$container]] 访问。当调用 [[Yii::createObject()]] 时,此方法实际上会调用这个容器的 [[yii\di\Container::get()|get()]] 方法创建新对象。如上所述,DI 容器会自动解决依赖关系(如果有)并将其注入新创建的对象中。因为 Yii 在其多数核心代码中都使用了 当在应用程序的[入口脚本](structure-entry-scripts.md)中引入 `Yii.php` 文件时,
[[Yii::createObject()]] 创建新对象,所以你可以通过 [[Yii::$container]] 全局性地自定义这些对象。 Yii 就创建了一个 DI 容器。这个 DI 容器可以通过 [[Yii::$container]] 访问。
当调用 [[Yii::createObject()]] 时,此方法实际上会调用这个容器的 [[yii\di\Container::get()|get()]] 方法创建新对象。
如上所述,DI 容器会自动解决依赖关系(如果有)并将其注入新创建的对象中。
因为 Yii 在其多数核心代码中都使用了[[Yii::createObject()]] 创建新对象,
所以你可以通过 [[Yii::$container]] 全局性地自定义这些对象。
例如,你可以全局性自定义 [[yii\widgets\LinkPager]] 中分页按钮的默认数量: 例如,你可以全局性自定义 [[yii\widgets\LinkPager]] 中分页按钮的默认数量:
@ -228,7 +323,8 @@ $lister = new UserLister($finder);
\Yii::$container->set('yii\widgets\LinkPager', ['maxButtonCount' => 5]); \Yii::$container->set('yii\widgets\LinkPager', ['maxButtonCount' => 5]);
``` ```
这样如果你通过如下代码在一个视图里使用这个挂件,它的 `maxButtonCount` 属性就会被初始化为 5 而不是类中定义的默认值 10。 这样如果你通过如下代码在一个视图里使用这个挂件,
它的 `maxButtonCount` 属性就会被初始化为 5 而不是类中定义的默认值 10。
```php ```php
echo \yii\widgets\LinkPager::widget(); echo \yii\widgets\LinkPager::widget();
@ -240,7 +336,13 @@ echo \yii\widgets\LinkPager::widget();
echo \yii\widgets\LinkPager::widget(['maxButtonCount' => 20]); echo \yii\widgets\LinkPager::widget(['maxButtonCount' => 20]);
``` ```
另一个例子是借用 DI 容器中自动构造方法注入带来的好处。假设你的控制器类依赖一些其他对象,例如一个旅馆预订服务。你可以通过一个构造器参数声明依赖关系,然后让 DI 容器帮你自动解决这个依赖关系。 > Note: Properties given in the widget call will always override the definition in the DI container.
> Even if you specify an array, e.g. `'options' => ['id' => 'mypager']` these will not be merged
> with other options but replace them.
另一个例子是借用 DI 容器中自动构造方法注入带来的好处。
假设你的控制器类依赖一些其他对象,例如一个旅馆预订服务。
你可以通过一个构造器参数声明依赖关系,然后让 DI 容器帮你自动解决这个依赖关系。
```php ```php
namespace app\controllers; namespace app\controllers;
@ -260,28 +362,175 @@ class HotelController extends Controller
} }
``` ```
如果你从浏览器中访问这个控制器,你将看到一个报错信息,提醒你 `BookingInterface` 无法被实例化。这是因为你需要告诉 DI 容器怎样处理这个依赖关系。 如果你从浏览器中访问这个控制器,你将看到一个报错信息,提醒你 `BookingInterface` 无法被实例化。
这是因为你需要告诉 DI 容器怎样处理这个依赖关系。
```php ```php
\Yii::$container->set('app\components\BookingInterface', 'app\components\BookingService'); \Yii::$container->set('app\components\BookingInterface', 'app\components\BookingService');
``` ```
现在如果你再次访问这个控制器,一个 `app\components\BookingService` 的实例就会被创建并被作为第三个参数注入到控制器的构造器中。 现在如果你再次访问这个控制器,一个 `app\components\BookingService`
的实例就会被创建并被作为第三个参数注入到控制器的构造器中。
Advanced Practical Usage <span id="advanced-practical-usage"></span>
---------------
Say we work on API application and have:
- `app\components\Request` class that extends `yii\web\Request` and provides additional functionality
- `app\components\Response` class that extends `yii\web\Response` and should have `format` property
set to `json` on creation
- `app\storage\FileStorage` and `app\storage\DocumentsReader` classes that implement some logic on
working with documents that are located in some file storage:
```php
class FileStorage
{
public function __construct($root) {
// whatever
}
}
class DocumentsReader
{
public function __construct(FileStorage $fs) {
// whatever
}
}
```
It is possible to configure multiple definitions at once, passing configuration array to
[[yii\di\Container::setDefinitions()|setDefinitions()]] or [[yii\di\Container::setSingletons()|setSingletons()]] method.
Iterating over the configuration array, the methods will call [[yii\di\Container::set()|set()]]
or [[yii\di\Container::setSingleton()|setSingleton()]] respectively for each item.
The configuration array format is:
- `key`: class name, interface name or alias name. The key will be passed to the
[[yii\di\Container::set()|set()]] method as a first argument `$class`.
- `value`: the definition associated with `$class`. Possible values are described in [[yii\di\Container::set()|set()]]
documentation for the `$definition` parameter. Will be passed to the [[set()]] method as
the second argument `$definition`.
For example, let's configure our container to follow the aforementioned requirements:
```php
$container->setDefinitions([
'yii\web\Request' => 'app\components\Request',
'yii\web\Response' => [
'class' => 'app\components\Response',
'format' => 'json'
],
'app\storage\DocumentsReader' => function () {
$fs = new app\storage\FileStorage('/var/tempfiles');
return new app\storage\DocumentsReader($fs);
}
]);
$reader = $container->get('app\storage\DocumentsReader);
// Will create DocumentReader object with its dependencies as described in the config
```
> Tip: Container may be configured in declarative style using application configuration since version 2.0.11.
Check out the [Application Configurations](concept-configurations.md#application-configurations) subsection of
the [Configurations](concept-configurations.md) guide article.
Everything works, but in case we need to create `DocumentWriter` class,
we shall copy-paste the line that creates `FileStorage` object, that is not the smartest way, obviously.
As described in the [Resolving Dependencies](#resolving-dependencies) subsection, [[yii\di\Container::set()|set()]]
and [[yii\di\Container::setSingleton()|setSingleton()]] can optionally take dependency's constructor parameters as
a third argument. To set the constructor parameters, you may use the following configuration array format:
- `key`: class name, interface name or alias name. The key will be passed to the
[[yii\di\Container::set()|set()]] method as a first argument `$class`.
- `value`: array of two elements. The first element will be passed to the [[yii\di\Container::set()|set()]] method as the
second argument `$definition`, the second one — as `$params`.
Let's modify our example:
```php
$container->setDefinitions([
'tempFileStorage' => [ // we've created an alias for convenience
['class' => 'app\storage\FileStorage'],
['/var/tempfiles'] // could be extracted from some config files
],
'app\storage\DocumentsReader' => [
['class' => 'app\storage\DocumentsReader'],
[Instance::of('tempFileStorage')]
],
'app\storage\DocumentsWriter' => [
['class' => 'app\storage\DocumentsWriter'],
[Instance::of('tempFileStorage')]
]
]);
$reader = $container->get('app\storage\DocumentsReader);
// Will behave exactly the same as in the previous example.
```
You might notice `Instance::of('tempFileStorage')` notation. It means, that the [[yii\di\Container|Container]]
will implicitly provide a dependency registered with the name of `tempFileStorage` and pass it as the first argument
of `app\storage\DocumentsWriter` constructor.
> Note: [[yii\di\Container::setDefinitions()|setDefinitions()]] and [[yii\di\Container::setSingletons()|setSingletons()]]
methods are available since version 2.0.11.
Another step on configuration optimization is to register some dependencies as singletons.
A dependency registered via [[yii\di\Container::set()|set()]] will be instantiated each time it is needed.
Some classes do not change the state during runtime, therefore they may be registered as singletons
in order to increase the application performance.
A good example could be `app\storage\FileStorage` class, that executes some operations on file system with a simple
API (e.g. `$fs->read()`, `$fs->write()`). These operations do not change the internal class state, so we can
create its instance once and use it multiple times.
```php
$container->setSingletons([
'tempFileStorage' => [
['class' => 'app\storage\FileStorage'],
['/var/tempfiles']
],
]);
$container->setDefinitions([
'app\storage\DocumentsReader' => [
['class' => 'app\storage\DocumentsReader'],
[Instance::of('tempFileStorage')]
],
'app\storage\DocumentsWriter' => [
['class' => 'app\storage\DocumentsWriter'],
[Instance::of('tempFileStorage')]
]
]);
$reader = $container->get('app\storage\DocumentsReader');
什么时候注册依赖关系 <span id="when-to-register-dependencies"></span> 什么时候注册依赖关系 <span id="when-to-register-dependencies"></span>
----------------------------- -----------------------------
由于依赖关系在创建新对象时需要解决,因此它们的注册应该尽早完成。如下是推荐的实践: 由于依赖关系在创建新对象时需要解决,因此它们的注册应该尽早完成。
如下是推荐的实践:
* 如果你是一个应用程序的开发者,你可以在应用程序的[入口脚本](structure-entry-scripts.md)或者被入口脚本引入的脚本中注册依赖关系。 * 如果你是一个应用程序的开发者,
* 如果你是一个可再分发[扩展](structure-extensions.md)的开发者,你可以将依赖关系注册到扩展的引导类中。 你可以在应用程序的[入口脚本](structure-entry-scripts.md)
或者被入口脚本引入的脚本中注册依赖关系。
* 如果你是一个可再分发[扩展](structure-extensions.md)的开发者,
你可以将依赖关系注册到扩展的引导类中。
总结 <span id="summary"></span> 总结 <span id="summary"></span>
------- -------
依赖注入和[服务定位器](concept-service-locator.md)都是流行的设计模式,它们使你可以用充分解耦且更利于测试的风格构建软件。强烈推荐你阅读 [Martin 的文章](http://martinfowler.com/articles/injection.html) ,对依赖注入和服务定位器有个更深入的理解。 依赖注入和[服务定位器](concept-service-locator.md)都是流行的设计模式,
它们使你可以用充分解耦且更利于测试的风格构建软件。
强烈推荐你阅读 [Martin 的文章](http://martinfowler.com/articles/injection.html) ,
对依赖注入和服务定位器有个更深入的理解。
Yii 在依赖住入(DI)容器之上实现了它的[服务定位器](concept-service-locator.md)。
当一个服务定位器尝试创建一个新的对象实例时,它会把调用转发到 DI 容器。
后者将会像前文所述那样自动解决依赖关系。
Yii 在依赖住入(DI)容器之上实现了它的[服务定位器](concept-service-locator.md)。当一个服务定位器尝试创建一个新的对象实例时,它会把调用转发到 DI 容器。后者将会像前文所述那样自动解决依赖关系。

169
docs/guide-zh-CN/concept-events.md

@ -1,15 +1,20 @@
事件 事件
====== ======
事件可以将自定义代码“注入”到现有代码中的特定执行点。附加自定义代码到某个事件,当这个事件被触发时,这些代码就会自动执行。例如,邮件程序对象成功发出消息时可触发 `messageSent` 事件。如想追踪成功发送的消息,可以附加相应追踪代码到 `messageSent` 事件。 事件可以将自定义代码“注入”到现有代码中的特定执行点。
附加自定义代码到某个事件,当这个事件被触发时,这些代码就会自动执行。
例如,邮件程序对象成功发出消息时可触发 `messageSent` 事件。
如想追踪成功发送的消息,可以附加相应追踪代码到 `messageSent` 事件。
Yii 引入了名为 [[yii\base\Component]] 的基类以支持事件。如果一个类需要触发事件就应该继承 [[yii\base\Component]] 或其子类。 Yii 引入了名为 [[yii\base\Component]] 的基类以支持事件。
如果一个类需要触发事件就应该继承 [[yii\base\Component]] 或其子类。
事件处理器(Event Handlers) 事件处理器 <span id="event-handlers"></span>
-------------- --------------
事件处理器是一个[PHP 回调函数](http://www.php.net/manual/en/language.types.callable.php),当它所附加到的事件被触发时它就会执行。可以使用以下回调函数之一: 事件处理器是一个[PHP 回调函数](http://www.php.net/manual/en/language.types.callable.php),
当它所附加到的事件被触发时它就会执行。可以使用以下回调函数之一:
- 字符串形式指定的 PHP 全局函数,如 `'trim'` - 字符串形式指定的 PHP 全局函数,如 `'trim'`
- 对象名和方法名数组形式指定的对象方法,如 `[$object, $method]` - 对象名和方法名数组形式指定的对象方法,如 `[$object, $method]`
@ -54,21 +59,29 @@ $foo->on(Foo::EVENT_HELLO, function ($event) {
}); });
``` ```
附加事件处理器时可以提供额外数据作为 [[yii\base\Component::on()]] 方法的第三个参数。数据在事件被触发和处理器被调用时能被处理器使用。如: You may also attach event handlers through [configurations](concept-configurations.md). For more details, please
refer to the [Configurations](concept-configurations.md#configuration-format) section.
附加事件处理器时可以提供额外数据作为 [[yii\base\Component::on()]] 方法的第三个参数。
数据在事件被触发和处理器被调用时能被处理器使用。如:
```php ```php
// 当事件被触发时以下代码显示 "abc" // 当事件被触发时以下代码显示 "abc"
// 因为 $event->data 包括被传递到 "on" 方法的数据 // 因为 $event->data 包括被传递到 "on" 方法的数据
$foo->on(Foo::EVENT_HELLO, function ($event) { $foo->on(Foo::EVENT_HELLO, 'function_name', 'abc');
function function_name($event) {
echo $event->data; echo $event->data;
}, 'abc'); }
``` ```
事件处理器顺序 事件处理器顺序
----------------- -----------------
可以附加一个或多个处理器到一个事件。当事件被触发,已附加的处理器将按附加次序依次调用。如果某个处理器需要停止其后的处理器调用,可以设置 `$event` 参数的 [[yii\base\Event::handled]] 属性为真,如下: 可以附加一个或多个处理器到一个事件。当事件被触发,已附加的处理器将按附加次序依次调用。
如果某个处理器需要停止其后的处理器调用,可以设置 `$event` 参数的 [[yii\base\Event::handled]] 属性为真,
如下:
```php ```php
$foo->on(Foo::EVENT_HELLO, function ($event) { $foo->on(Foo::EVENT_HELLO, function ($event) {
@ -76,7 +89,9 @@ $foo->on(Foo::EVENT_HELLO, function ($event) {
}); });
``` ```
默认新附加的事件处理器排在已存在处理器队列的最后。因此,这个处理器将在事件被触发时最后一个调用。在处理器队列最前面插入新处理器将使该处理器最先调用,可以传递第四个参数 `$append` 为假并调用 [[yii\base\Component::on()]] 方法实现: 默认新附加的事件处理器排在已存在处理器队列的最后。
因此,这个处理器将在事件被触发时最后一个调用。
在处理器队列最前面插入新处理器将使该处理器最先调用,可以传递第四个参数 `$append` 为假并调用 [[yii\base\Component::on()]] 方法实现:
```php ```php
$foo->on(Foo::EVENT_HELLO, function ($event) { $foo->on(Foo::EVENT_HELLO, function ($event) {
@ -84,11 +99,11 @@ $foo->on(Foo::EVENT_HELLO, function ($event) {
}, $data, false); }, $data, false);
``` ```
触发事件 <span id="triggering-events"></span>
触发事件
---------- ----------
事件通过调用 [[yii\base\Component::trigger()]] 方法触发,此方法须传递**事件名**,还可以传递一个事件对象,用来传递参数到事件处理器。如: 事件通过调用 [[yii\base\Component::trigger()]] 方法触发,此方法须传递**事件名**,
还可以传递一个事件对象,用来传递参数到事件处理器。如:
```php ```php
namespace app\components; namespace app\components;
@ -109,9 +124,15 @@ class Foo extends Component
以上代码当调用 `bar()` ,它将触发名为 `hello` 的事件。 以上代码当调用 `bar()` ,它将触发名为 `hello` 的事件。
> 提示:推荐使用类常量来表示事件名。上例中,常量 `EVENT_HELLO` 用来表示 `hello` 。这有两个好处。第一,它可以防止拼写错误并支持 IDE 的自动完成。第二,只要简单检查常量声明就能了解一个类支持哪些事件。 > Tip: 推荐使用类常量来表示事件名。上例中,常量 `EVENT_HELLO` 用来表示 `hello`
这有两个好处。第一,它可以防止拼写错误并支持 IDE 的自动完成。
第二,只要简单检查常量声明就能了解一个类支持哪些事件。
有时想要在触发事件时同时传递一些额外信息到事件处理器。例如,邮件程序要传递消息信息到 `messageSent` 事件的处理器以便处理器了解哪些消息被发送了。为此,可以提供一个事件对象作为 [[yii\base\Component::trigger()]] 方法的第二个参数。这个事件对象必须是 [[yii\base\Event]] 类或其子类的实例。如: 有时想要在触发事件时同时传递一些额外信息到事件处理器。
例如,邮件程序要传递消息信息到 `messageSent` 事件的处理器以便处理器了解哪些消息被发送了。
为此,可以提供一个事件对象作为 [[yii\base\Component::trigger()]] 方法的第二个参数。
这个事件对象必须是 [[yii\base\Event]] 类或其子类的实例。
如:
```php ```php
namespace app\components; namespace app\components;
@ -139,7 +160,8 @@ class Mailer extends Component
} }
``` ```
当 [[yii\base\Component::trigger()]] 方法被调用时,它将调用所有附加到命名事件(trigger 方法第一个参数)的事件处理器。 当 [[yii\base\Component::trigger()]] 方法被调用时,
它将调用所有附加到命名事件(trigger 方法第一个参数)的事件处理器。
移除事件处理器 移除事件处理器
@ -161,7 +183,9 @@ $foo->off(Foo::EVENT_HELLO, ['app\components\Bar', 'methodName']);
$foo->off(Foo::EVENT_HELLO, $anonymousFunction); $foo->off(Foo::EVENT_HELLO, $anonymousFunction);
``` ```
注意当匿名函数附加到事件后一般不要尝试移除匿名函数,除非你在某处存储了它。以上示例中,假设匿名函数存储为变量 `$anonymousFunction` 注意当匿名函数附加到事件后一般不要尝试移除匿名函数,
除非你在某处存储了它。以上示例中,
假设匿名函数存储为变量 `$anonymousFunction`
移除事件的全部处理器,简单调用 [[yii\base\Component::off()]] 即可,不需要第二个参数: 移除事件的全部处理器,简单调用 [[yii\base\Component::off()]] 即可,不需要第二个参数:
@ -169,12 +193,18 @@ $foo->off(Foo::EVENT_HELLO, $anonymousFunction);
$foo->off(Foo::EVENT_HELLO); $foo->off(Foo::EVENT_HELLO);
``` ```
类级别的事件处理器 类级别的事件处理器
------------------- -------------------
以上部分,我们叙述了在**实例级别**如何附加处理器到事件。有时想要一个类的所有实例而不是一个指定的实例都响应一个被触发的事件,并不是一个个附加事件处理器到每个实例,而是通过调用静态方法 [[yii\base\Event::on()]] 在**类级别**附加处理器。 以上部分,我们叙述了在**实例级别**如何附加处理器到事件。
有时想要一个类的所有实例而不是一个指定的实例都响应一个被触发的事件,
并不是一个个附加事件处理器到每个实例,
而是通过调用静态方法 [[yii\base\Event::on()]] 在**类级别**附加处理器。
例如,[活动记录](db-active-record.md)对象要在每次往数据库新增一条新记录时触发一个 [[yii\db\BaseActiveRecord::EVENT_AFTER_INSERT|EVENT_AFTER_INSERT]] 事件。要追踪每个[活动记录](db-active-record.md)对象的新增记录完成情况,应如下写代码: 例如,[活动记录](db-active-record.md)对象要在每次往数据库新增一条新记录时触发一个
[[yii\db\BaseActiveRecord::EVENT_AFTER_INSERT|EVENT_AFTER_INSERT]] 事件。
要追踪每个[活动记录](db-active-record.md)对象的新增记录完成情况,应如下写代码:
```php ```php
use Yii; use Yii;
@ -186,11 +216,15 @@ Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function
}); });
``` ```
每当 [[yii\db\BaseActiveRecord|ActiveRecord]] 或其子类的实例触发 [[yii\db\BaseActiveRecord::EVENT_AFTER_INSERT|EVENT_AFTER_INSERT]] 事件时,这个事件处理器都会执行。在这个处理器中,可以通过 `$event->sender` 获取触发事件的对象。 每当 [[yii\db\BaseActiveRecord|ActiveRecord]] 或其子类的实例触发
[[yii\db\BaseActiveRecord::EVENT_AFTER_INSERT|EVENT_AFTER_INSERT]] 事件时,
这个事件处理器都会执行。在这个处理器中,可以通过 `$event->sender` 获取触发事件的对象。
当对象触发事件时,它首先调用实例级别的处理器,然后才会调用类级别处理器。 当对象触发事件时,它首先调用实例级别的处理器,然后才会调用类级别处理器。
可调用静态方法[[yii\base\Event::trigger()]]来触发一个**类级别**事件。类级别事件不与特定对象相关联。因此,它只会引起类级别事件处理器的调用。如: 可调用静态方法[[yii\base\Event::trigger()]]来触发一个**类级别**事件。
类级别事件不与特定对象相关联。因此,它只会引起类级别事件处理器的调用。
如:
```php ```php
use yii\base\Event; use yii\base\Event;
@ -204,7 +238,8 @@ Event::trigger(Foo::className(), Foo::EVENT_HELLO);
注意这种情况下 `$event->sender` 指向触发事件的类名而不是对象实例。 注意这种情况下 `$event->sender` 指向触发事件的类名而不是对象实例。
> 注意:因为类级别的处理器响应类和其子类的所有实例触发的事件,必须谨慎使用,尤其是底层的基类,如 [[yii\base\Object]]。 > Note: 因为类级别的处理器响应类和其子类的所有实例触发的事件,
必须谨慎使用,尤其是底层的基类,如 [[yii\base\Object]]。
移除类级别的事件处理器只需调用[[yii\base\Event::off()]],如: 移除类级别的事件处理器只需调用[[yii\base\Event::off()]],如:
@ -217,12 +252,90 @@ Event::off(Foo::className(), Foo::EVENT_HELLO);
``` ```
Events using interfaces <span id="interface-level-event-handlers"></span>
-------------
There is even more abstract way to deal with events. You can create a separated interface for the special event and
implement it in classes, where you need it.
For example, we can create the following interface:
```php
namespace app\interfaces;
interface DanceEventInterface
{
const EVENT_DANCE = 'dance';
}
```
And two classes, that implement it:
```php
class Dog extends Component implements DanceEventInterface
{
public function meetBuddy()
{
echo "Woof!";
$this->trigger(DanceEventInterface::EVENT_DANCE);
}
}
class Developer extends Component implements DanceEventInterface
{
public function testsPassed()
{
echo "Yay!";
$this->trigger(DanceEventInterface::EVENT_DANCE);
}
}
```
To handle the `EVENT_DANCE`, triggered by any of these classes, call [[yii\base\Event::on()|Event::on()]] and
pass the interface class name as the first argument:
```php
Event::on('app\interfaces\DanceEventInterface', DanceEventInterface::EVENT_DANCE, function ($event) {
Yii::trace(get_class($event->sender) . ' just danced'); // Will log that Dog or Developer danced
});
```
You can trigger the event of those classes:
```php
// trigger event for Dog class
Event::trigger(Dog::className(), DanceEventInterface::EVENT_DANCE);
// trigger event for Developer class
Event::trigger(Developer::className(), DanceEventInterface::EVENT_DANCE);
```
But please notice, that you can not trigger all the classes, that implement the interface:
```php
// DOES NOT WORK. Classes that implement this interface will NOT be triggered.
Event::trigger('app\interfaces\DanceEventInterface', DanceEventInterface::EVENT_DANCE);
```
To detach event handler, call [[yii\base\Event::off()|Event::off()]]. For example:
```php
// detaches $handler
Event::off('app\interfaces\DanceEventInterface', DanceEventInterface::EVENT_DANCE, $handler);
// detaches all handlers of DanceEventInterface::EVENT_DANCE
Event::off('app\interfaces\DanceEventInterface', DanceEventInterface::EVENT_DANCE);
```
全局事件 全局事件
------------- -------------
所谓**全局事件**实际上是一个基于以上叙述的事件机制的戏法。它需要一个全局可访问的单例,如[应用](structure-applications.md)实例。 所谓**全局事件**实际上是一个基于以上叙述的事件机制的戏法。它需要一个全局可访问的单例,
如[应用](structure-applications.md)实例。
事件触发者不调用其自身的 `trigger()` 方法,而是调用单例的 `trigger()` 方法来触发全局事件。类似地,事件处理器被附加到单例的事件。如: 事件触发者不调用其自身的 `trigger()` 方法,而是调用单例的 `trigger()` 方法来触发全局事件。
类似地,事件处理器被附加到单例的事件。如:
```php ```php
use Yii; use Yii;
@ -236,6 +349,10 @@ Yii::$app->on('bar', function ($event) {
Yii::$app->trigger('bar', new Event(['sender' => new Foo])); Yii::$app->trigger('bar', new Event(['sender' => new Foo]));
``` ```
全局事件的一个好处是当附加处理器到一个对象要触发的事件时,不需要产生该对象。相反,处理器附加和事件触发都通过单例(如应用实例)完成。 全局事件的一个好处是当附加处理器到一个对象要触发的事件时,
不需要产生该对象。相反,处理器附加和事件触发都通过单例
(如应用实例)完成。
然而,因为全局事件的命名空间由各方共享,应合理命名全局事件,
如引入一些命名空间(例:"frontend.mail.sent", "backend.mail.sent")。
然而,因为全局事件的命名空间由各方共享,应合理命名全局事件,如引入一些命名空间(例:"frontend.mail.sent", "backend.mail.sent")。

38
docs/guide-zh-CN/concept-properties.md

@ -1,8 +1,8 @@
属性(Property) 属性(Property)
========== ==========
在 PHP 中,类的成员变量也被称为**属性(properties)**。 在 PHP 中,类的成员变量也被称为**属性(properties)**。它们是类定义的一部分,
它们是类定义的一部分,用来表现一个实例的状态(也就是区分类的不同实例)。 用来表现一个实例的状态(也就是区分类的不同实例)。
在具体实践中,常常会想用一个稍微特殊些的方法实现属性的读写。 在具体实践中,常常会想用一个稍微特殊些的方法实现属性的读写。
例如,如果有需求每次都要对 `label` 属性执行 trim 操作, 例如,如果有需求每次都要对 `label` 属性执行 trim 操作,
就可以用以下代码实现: 就可以用以下代码实现:
@ -13,19 +13,19 @@ $object->label = trim($label);
上述代码的缺点是只要修改 `label` 属性就必须再次调用 `trim()` 函数。 上述代码的缺点是只要修改 `label` 属性就必须再次调用 `trim()` 函数。
若将来需要用其它方式处理 `label` 属性,比如首字母大写, 若将来需要用其它方式处理 `label` 属性,比如首字母大写,
就不得不修改所有给 `label` 属性赋值的代码。 就不得不修改所有给 `label` 属性赋值的代码。这种代码的重复会导致 bug,
这种代码的重复会导致 bug,这种实践显然需要尽可能避免。 这种实践显然需要尽可能避免。
为解决该问题,Yii 引入了一个名为 [[yii\base\Object]] 的基类, 为解决该问题,Yii 引入了一个名为 [[yii\base\Object]] 的基类,
它支持基于类内的 **getter****setter**(读取器和设定器)方法来定义属性。 它支持基于类内的 **getter****setter**(读取器和设定器)方法来定义属性。
如果某类需要支持这个特性,只需要继承 [[yii\base\Object]] 或其子类即可。 如果某类需要支持这个特性,只需要继承 [[yii\base\Object]] 或其子类即可。
> 补充:几乎每个 Yii 框架的核心类都继承自 [[yii\base\Object]] 或其子类。 > Info: 几乎每个 Yii 框架的核心类都继承自 [[yii\base\Object]] 或其子类。
这意味着只要在核心类中见到 getter 或 setter 方法,就可以像调用属性一样调用它。 这意味着只要在核心类中见到 getter 或 setter 方法,就可以像调用属性一样调用它。
getter 方法是名称以 `get` 开头的方法,而 setter 方法名以 `set` 开头。 getter 方法是名称以 `get` 开头的方法,而 setter 方法名以 `set` 开头。
方法名中 `get``set` 后面的部分就定义了该属性的名字。 方法名中 `get``set` 后面的部分就定义了该属性的名字。如下面代码所示,
如下面代码所示,getter 方法 `getLabel()` 和 setter 方法 `setLabel()` 操作的是 `label` 属性,: getter 方法 `getLabel()` 和 setter 方法 `setLabel()` 操作的是 `label` 属性,:
```php ```php
namespace app\components; namespace app\components;
@ -48,12 +48,12 @@ class Foo extend Object
} }
``` ```
详细解释:getter 和 setter 方法创建了一个名为 `label` 的属性, 详细解释:getter 和 setter 方法创建了一个名为 `label` 的属性,
在这个例子里,它指向一个私有的内部属性 `_label` 在这个例子里,它指向一个私有的内部属性 `_label`
getter/setter 定义的属性用法与类成员变量一样。 getter/setter 定义的属性用法与类成员变量一样。两者主要的区别是:
两者主要的区别是:当这种属性被读取时,对应的 getter 方法将被调用; 当这种属性被读取时,对应的 getter 方法将被调用;而当属性被赋值时,
而当属性被赋值时,对应的 setter 方法就调用。如: 对应的 setter 方法就调用。如:
```php ```php
// 等效于 $label = $object->getLabel(); // 等效于 $label = $object->getLabel();
@ -65,20 +65,20 @@ $object->label = 'abc';
只定义了 getter 没有 setter 的属性是**只读属性**。 只定义了 getter 没有 setter 的属性是**只读属性**。
尝试赋值给这样的属性将导致 [[yii\base\InvalidCallException|InvalidCallException]] (无效调用)异常。 尝试赋值给这样的属性将导致 [[yii\base\InvalidCallException|InvalidCallException]] (无效调用)异常。
类似的,只有 setter 方法而没有 getter 方法定义的属性是**只写属性**,尝试读取这种属性也会触发异常。 类似的,只有 setter 方法而没有 getter 方法定义的属性是**只写属性**,
使用只写属性的情况几乎没有。 尝试读取这种属性也会触发异常。使用只写属性的情况几乎没有。
通过 getter 和 setter 定义的属性也有一些特殊规则和限制: 通过 getter 和 setter 定义的属性也有一些特殊规则和限制:
* 这类属性的名字是**不区分大小写**的。如,`$object->label` 和 `$object->Label` 是同一个属性。 * 这类属性的名字是**不区分大小写**的。如,`$object->label` 和 `$object->Label` 是同一个属性。
因为 PHP 方法名是不区分大小写的。 因为 PHP 方法名是不区分大小写的。
* 如果此类属性名和类成员变量相同,以后者为准。 * 如果此类属性名和类成员变量相同,以后者为准。例如,
例如,假设以上 `Foo` 类有个 `label` 成员变量, 假设以上 `Foo` 类有个 `label` 成员变量,然后给 `$object->label = 'abc'` 赋值
然后给 `$object->label = 'abc'` 赋值,将赋给成员变量而不是 setter `setLabel()` 方法。 将赋给成员变量而不是 setter `setLabel()` 方法。
* 这类属性不支持可见性(访问限制)。定义属性的 getter 和 setter 方法是 public、protected 还是 private 对属性的可见性没有任何影响。 * 这类属性不支持可见性(访问限制)。定义属性的 getter 和 setter 方法是 public、protected 还是 private 对属性的可见性没有任何影响。
* 这类属性的 getter 和 setter 方法只能定义为**非静态**的,若定义为静态方法(static)则不会以相同方式处理。 * 这类属性的 getter 和 setter 方法只能定义为**非静态**的,若定义为静态方法(static)则不会以相同方式处理。
* `property_exists()` 不能确定魔术属性的正常调用。你应该调用 [[yii\base\Object::canGetProperty()|canGetProperty()]] * A normal call to `property_exists()` does not work to determine magic properties. You should call [[yii\base\BaseObject::canGetProperty()|canGetProperty()]]
或 [[yii\base\Object::canSetProperty()|canSetProperty()]]。 or [[yii\base\BaseObject::canSetProperty()|canSetProperty()]] respectively.
回到开头提到的问题,与其处处要调用 `trim()` 函数, 回到开头提到的问题,与其处处要调用 `trim()` 函数,
现在我们只需在 setter `setLabel()` 方法内调用一次。 现在我们只需在 setter `setLabel()` 方法内调用一次。

29
docs/guide-zh-CN/concept-service-locator.md

@ -1,21 +1,21 @@
服务定位器 服务定位器
=============== ===============
服务定位器是一个了解如何提供各种应用所需的服务(或组件)的对象。 服务定位器是一个了解如何提供各种应用所需的服务(或组件)的对象。在服务定位器中,
在服务定位器中,每个组件都只有一个单独的实例,并通过ID 唯一地标识。 每个组件都只有一个单独的实例,并通过ID 唯一地标识。
用这个 ID 就能从服务定位器中得到这个组件。 用这个 ID 就能从服务定位器中得到这个组件。
在 Yii 中,服务定位器是 [[yii\di\ServiceLocator]] 或其子类的一个实例。 在 Yii 中,服务定位器是 [[yii\di\ServiceLocator]] 或其子类的一个实例。
最常用的服务定位器是**application(应用)**对象,可以通过 `\Yii::$app` 访问。 最常用的服务定位器是**application(应用)**对象,可以通过 `\Yii::$app` 访问。
它所提供的服务被称为**application components(应用组件)**,比如:`request`、`response`、`urlManager` 组件。 它所提供的服务被称为**application components(应用组件)**,
可以通过服务定位器所提供的功能,非常容易地配置这些组件 比如:`request`、`response`、`urlManager` 组件。可以通过服务定位器所提供的功能,
或甚至是用你自己的实现替换掉他们。 非常容易地配置这些组件,或甚至是用你自己的实现替换掉他们。
除了 application 对象,每个模块对象本身也是一个服务定位器。 除了 application 对象,每个模块对象本身也是一个服务定位器。
要使用服务定位器,第一步是要注册相关组件。 要使用服务定位器,第一步是要注册相关组件。组件可以通过 [[yii\di\ServiceLocator::set()]] 方法进行注册。
组件可以通过 [[yii\di\ServiceLocator::set()]] 方法进行注册。以下的方法展示了注册组件的不同方法: 以下的方法展示了注册组件的不同方法:
```php ```php
use yii\di\ServiceLocator; use yii\di\ServiceLocator;
@ -52,8 +52,8 @@ $cache = $locator->cache;
``` ```
如上所示, [[yii\di\ServiceLocator]] 允许通过组件 ID 像访问一个属性值那样访问一个组件。 如上所示, [[yii\di\ServiceLocator]] 允许通过组件 ID 像访问一个属性值那样访问一个组件。
当你第一次访问某组件时, 当你第一次访问某组件时,[[yii\di\ServiceLocator]]
[[yii\di\ServiceLocator]] 会通过该组件的注册信息创建一个该组件的实例,并返回它。 会通过该组件的注册信息创建一个该组件的实例,并返回它。
之后,如果再次访问,则服务定位器会返回同一个实例。 之后,如果再次访问,则服务定位器会返回同一个实例。
你可以通过 [[yii\di\ServiceLocator::has()]] 检查某组件 ID 是否被注册。 你可以通过 [[yii\di\ServiceLocator::has()]] 检查某组件 ID 是否被注册。
@ -61,10 +61,10 @@ $cache = $locator->cache;
因为服务定位器,经常会在创建时附带[配置信息](concept-configurations.md), 因为服务定位器,经常会在创建时附带[配置信息](concept-configurations.md),
因此我们提供了一个可写的属性, 因此我们提供了一个可写的属性,名为 [[yii\di\ServiceLocator::setComponents()|components]],
名为 [[yii\di\ServiceLocator::setComponents()|components]],
这样就可以配置该属性,或一次性注册多个组件。 这样就可以配置该属性,或一次性注册多个组件。
下面的代码展示了如何用一个配置数组,配置一个应用并注册"db","cache" 和 "search" 三个组件: 下面的代码展示了如何用一个配置数组,配置一个应用并注册
"db","cache" 和 "search" 三个组件:
```php ```php
return [ return [
@ -77,6 +77,9 @@ return [
'password' => '', 'password' => '',
], ],
'cache' => 'yii\caching\ApcCache', 'cache' => 'yii\caching\ApcCache',
'tz' => function() {
return new \DateTimeZone(Yii::$app->formatter->defaultTimeZone);
},
'search' => function () { 'search' => function () {
$solr = new app\components\SolrService('127.0.0.1'); $solr = new app\components\SolrService('127.0.0.1');
// ... other initializations ... // ... other initializations ...
@ -86,7 +89,7 @@ return [
]; ];
``` ```
在上面的代码中,有一个替代方法来配置“搜索”组件。 在上面的代码中,有一个替代方法来配置 `search` 组件。
而不是直接写一个 PHP 回调建立 `SolrService`实例,你可以使用一个静态类方法来返回这样的回调, 而不是直接写一个 PHP 回调建立 `SolrService`实例,你可以使用一个静态类方法来返回这样的回调,
如下所示: 如下所示:

2
docs/guide-zh-CN/db-dao.md

@ -2,7 +2,7 @@
======== ========
Yii 包含了一个建立在 PHP PDO 之上的数据访问层 (DAO)。DAO为不同的数据库提供了一套统一的API。 Yii 包含了一个建立在 PHP PDO 之上的数据访问层 (DAO)。DAO为不同的数据库提供了一套统一的API。
其中```ActiveRecord``` 提供了数据库与模型(MVC 中的 M,Model) 的交互,```QueryBuilder``` 用于创建动态的查询语句。 其中 `ActiveRecord` 提供了数据库与模型(MVC 中的 M,Model) 的交互,`QueryBuilder` 用于创建动态的查询语句。
DAO提供了简单高效的SQL查询,可以用在与数据库交互的各个地方. DAO提供了简单高效的SQL查询,可以用在与数据库交互的各个地方.
使用 Yii DAO 时,你主要需要处理纯 SQL 语句和 PHP 数组。因此,这是访问数据库最高效的方法。 使用 Yii DAO 时,你主要需要处理纯 SQL 语句和 PHP 数组。因此,这是访问数据库最高效的方法。

16
docs/guide-zh-CN/input-multiple-models.md

@ -27,12 +27,16 @@ class UserController extends Controller
public function actionUpdate($id) public function actionUpdate($id)
{ {
$user = User::findOne($id); $user = User::findOne($id);
$profile = Profile::findOne($id); if (!$user) {
if (!isset($user, $profile)) {
throw new NotFoundHttpException("The user was not found."); throw new NotFoundHttpException("The user was not found.");
} }
$profile = Profile::findOne($user->profile_id);
if (!$profile) {
throw new NotFoundHttpException("The user has no profile.");
}
$user->scenario = 'update'; $user->scenario = 'update';
$profile->scenario = 'update'; $profile->scenario = 'update';
@ -55,8 +59,10 @@ class UserController extends Controller
``` ```
In the `update` action, we first load the `$user` and `$profile` models to be updated from the database. We then call In the `update` action, we first load the `$user` and `$profile` models to be updated from the database. We then call
[[yii\base\Model::load()]] to populate these two models with the user input. If successful we will validate [[yii\base\Model::load()]] to populate these two models with the user input. If loading is successful, we will validate
the two models and save them. Otherwise we will render the `update` view which has the following content: the two models and then save them &mdash; please note that we use `save(false)` to skip over validations inside the models
as the user input data have already been validated. If loading is not successful, we will render the `update` view which
has the following content:
```php ```php
<?php <?php

149
docs/guide-zh-CN/intro-upgrade-from-v1.md

@ -2,24 +2,24 @@
=============== ===============
2.0 版框架是完全重写的,在 1.1 和 2.0 两个版本之间存在相当多差异。 2.0 版框架是完全重写的,在 1.1 和 2.0 两个版本之间存在相当多差异。
因此从 1.1 版升级并不像小版本间的跨越那么简单,通过本指南你将会 因此从 1.1 版升级并不像小版本间的跨越那么简单,
了解两个版本间主要的不同之处。 通过本指南你将会了解两个版本间主要的不同之处。
如果你之前没有用过 Yii 1.1,可以跳过本章,直接从"[入门篇](start-installation.md)"开始读起。 如果你之前没有用过 Yii 1.1,可以跳过本章,直接从"[入门篇](start-installation.md)"开始读起。
请注意,Yii 2.0 引入了很多本章并没有涉及到的新功能。强烈建议你通读整部权威指南 请注意,Yii 2.0 引入了很多本章并没有涉及到的新功能。
来了解所有新特性。这样有可能会发现一些以前你要自己开发的功能,而现在已经被包含 强烈建议你通读整部权威指南来了解所有新特性。
在核心代码中了。 这样有可能会发现一些以前你要自己开发的功能,而现在已经被包含在核心代码中了。
安装 安装
------------ ------------
Yii 2.0 完全拥抱 [Composer](https://getcomposer.org/),它是事实上的 PHP 依赖管理工具。 Yii 2.0 完全拥抱 [Composer](https://getcomposer.org/),它是事实上的 PHP 依赖管理工具。
核心框架以及扩展的安装都通过 Composer 来处理。想要了解更多如何安装 Yii 2.0 请参阅本 核心框架以及扩展的安装都通过 Composer 来处理。想要了解更多如何安装 Yii 2.0 请参阅本指南的
指南的 [安装 Yii](start-installation.md) 章节。如果你想创建新扩展,或者把你已有的 [安装 Yii](start-installation.md) 章节。如果你想创建新扩展,
Yii 1.1 的扩展改写成兼容 2.0 的版本,你可以参考 或者把你已有的 Yii 1.1 的扩展改写成兼容 2.0 的版本,
[创建扩展](structure-extensions.md#creating-extensions) 章节。 你可以参考 [创建扩展](structure-extensions.md#creating-extensions) 章节。
PHP 需求 PHP 需求
@ -45,24 +45,24 @@ Yii 2.0 需要 PHP 5.4 或更高版本,该版本相对于 Yii 1.1 所需求的
--------- ---------
Yii 2.0 里最明显的改动就数命名空间的使用了。几乎每一个核心类都引入了命名空间, Yii 2.0 里最明显的改动就数命名空间的使用了。几乎每一个核心类都引入了命名空间,
比如 `yii\web\Request`。1.1 版类名前缀 “C” 已经不再使用。当前的命名方案与目录结构相吻合。 比如 `yii\web\Request`。1.1 版类名前缀 “C” 已经不再使用。
例如,`yii\web\Request` 就表明对应的类文件是 当前的命名方案与目录结构相吻合。例如,`yii\web\Request`
Yii 框架文件夹下的 `web/Request.php` 文件。 就表明对应的类文件是 Yii 框架文件夹下的 `web/Request.php` 文件。
(有了 Yii 的类自动加载器,你可以直接使用全部核心类而不需要显式包含 (有了 Yii 的类自动加载器,
具体文件。) 你可以直接使用全部核心类而不需要显式包含具体文件。)
组件(Component)与对象(Object) 组件(Component)与对象(Object)
-------------------- --------------------
Yii 2.0 把 1.1 中的 `CComponent` 类拆分成了两个类:[[yii\base\Object]] 和 [[yii\base\Component]]。 Yii 2.0 把 1.1 中的 `CComponent` 类拆分成了两个类:[[yii\base\Object]] 和 [[yii\base\Component]]。
[[yii\base\Object|Object]] 类是一个轻量级的基类,你可以通过 getters 和 setters 来定义 [[yii\base\Object|Object]] 类是一个轻量级的基类,你可以通过 getters 和 setters 来定义[对象的属性](concept-properties.md)。
[对象的属性](concept-properties.md)。[[yii\base\Component|Component]] 类继承自 [[yii\base\Object|Object]], [[yii\base\Component|Component]] 类继承自 [[yii\base\Object|Object]],
同时进一步支持 [事件](concept-events.md) 和 [行为](concept-behaviors.md)。 同时进一步支持 [事件](concept-events.md) 和 [行为](concept-behaviors.md)。
如果你不需要用到事件或行为,应该考虑使用 如果你不需要用到事件或行为,
[[yii\base\Object|Object]] 类作为基类。 应该考虑使用 [[yii\base\Object|Object]] 类作为基类。
这种类通常用来表示基本的数据结构。 这种类通常用来表示基本的数据结构。
@ -70,8 +70,8 @@ Yii 2.0 把 1.1 中的 `CComponent` 类拆分成了两个类:[[yii\base\Object
-------------------- --------------------
[[yii\base\Object|Object]] 类引入了一种统一对象配置的方法。 [[yii\base\Object|Object]] 类引入了一种统一对象配置的方法。
所有 [[yii\base\Object|Object]] 的子类都应该用以下方法声明 所有 [[yii\base\Object|Object]] 的子类都应该用以下方法声明它的构造方法(如果需要的话),
它的构造方法(如果需要的话),以正确配置它自身: 以正确配置它自身:
```php ```php
class MyClass extends \yii\base\Object class MyClass extends \yii\base\Object
@ -93,9 +93,9 @@ class MyClass extends \yii\base\Object
``` ```
在上面的例子里,构造方法的最后一个参数必须传入一个配置数组, 在上面的例子里,构造方法的最后一个参数必须传入一个配置数组,
包含一系列用于在方法结尾初始化相关属性的键值对。你可以重写 包含一系列用于在方法结尾初始化相关属性的键值对。
[[yii\base\Object::init()|init()]] 方法来执行一些需要在配置 你可以重写 [[yii\base\Object::init()|init()]]
生效后进行的初始化工作。 方法来执行一些需要在配置生效后进行的初始化工作。
你可以通过遵循以下约定俗成的编码习惯, 你可以通过遵循以下约定俗成的编码习惯,
来使用配置数组创建并配置新的对象: 来使用配置数组创建并配置新的对象:
@ -114,8 +114,8 @@ $object = Yii::createObject([
事件(Event) 事件(Event)
------ ------
在 Yii 1 中,通常通过定义 `on` 开头的方法(例如 `onBeforeSave`)来创建事件。而在 Yii 2 中,你可以使用任意的事件名了。 在 Yii 1 中,通常通过定义 `on` 开头的方法(例如 `onBeforeSave`)来创建事件。
同时通过调用 [[yii\base\Component::trigger()|trigger()]] 方法来触发相关事件: 而在 Yii 2 中,你可以使用任意的事件名了。同时通过调用 [[yii\base\Component::trigger()|trigger()]] 方法来触发相关事件:
```php ```php
$event = new \yii\base\Event; $event = new \yii\base\Event;
@ -136,18 +136,18 @@ $component->on($eventName, $handler);
路径别名(Path Alias) 路径别名(Path Alias)
------------ ------------
Yii 2.0 将路径别名的应用扩大至文件/目录路径和 URL。 Yii 2.0 将路径别名的应用扩大至文件/目录路径和 URL。Yii 2.0 中路径别名必须以 `@` 符号开头,
Yii 2.0 中路径别名必须以 `@` 符号开头,
以区别于普通文件目录路径或 URL。例如 `@yii` 就是指向 Yii 安装目录的别名。 以区别于普通文件目录路径或 URL。例如 `@yii` 就是指向 Yii 安装目录的别名。
绝大多数 Yii 核心代码都支持别名。例如 [[yii\caching\FileCache::cachePath]] 绝大多数 Yii 核心代码都支持别名。
例如 [[yii\caching\FileCache::cachePath]]
就同时支持路径别名或普通的目录地址。 就同时支持路径别名或普通的目录地址。
路径别名也和类的命名空间密切相关。建议给每一个根命名空间定义一个路径别名, 路径别名也和类的命名空间密切相关。建议给每一个根命名空间定义一个路径别名,
从而无须额外配置,便可启动 Yii 的类自动加载机制。 从而无须额外配置,便可启动 Yii 的类自动加载机制。
例如,因为有 `@yii` 指向 Yii 安装目录,那类似 `yii\web\Request` 例如,因为有 `@yii` 指向 Yii 安装目录,
的类就能被 Yii 自动加载。同理,若你用了一个第三方的类库, 那类似 `yii\web\Request` 的类就能被 Yii 自动加载。同理,若你用了一个第三方的类库,
如 Zend Framework,你只需定义一个名为 `@Zend` 的路径别名指向该 如 Zend Framework,你只需定义一个名为 `@Zend` 的路径别名指向该框架的安装目录。
框架的安装目录。之后 Yii 就可以自动加载任意 Zend Framework 中的类了。 之后 Yii 就可以自动加载任意 Zend Framework 中的类了。
更多路径别名信息请参阅[路径别名](concept-aliases.md)章节。 更多路径别名信息请参阅[路径别名](concept-aliases.md)章节。
@ -156,9 +156,9 @@ Yii 2.0 中路径别名必须以 `@` 符号开头,
----- -----
Yii 2 中视图最明显的改动是视图内的特殊变量 `$this` 不再指向当前控制器或小部件, Yii 2 中视图最明显的改动是视图内的特殊变量 `$this` 不再指向当前控制器或小部件,
而是指向**视图**对象,它是 2.0 中引入的全新概念。**视图**对象为 而是指向**视图**对象,它是 2.0 中引入的全新概念。**视图**对象为 [[yii\web\View]] 的实例,
[[yii\web\View]] 的实例,他代表了 MVC 模式中的视图部分。 他代表了 MVC 模式中的视图部分。如果你想要在视图中访问一个控制器或小部件,
如果你想要在视图中访问一个控制器或小部件,可以使用 `$this->context` 可以使用 `$this->context`
要在其他视图里渲染一个局部视图,使用 `$this->render()`,而不是 `$this->renderPartial()` 要在其他视图里渲染一个局部视图,使用 `$this->render()`,而不是 `$this->renderPartial()`
`render()` 现在只返回渲染结果,而不是直接显示它,所以现在你必须显式地把它 **echo** 出来。像这样: `render()` 现在只返回渲染结果,而不是直接显示它,所以现在你必须显式地把它 **echo** 出来。像这样:
@ -167,18 +167,18 @@ Yii 2 中视图最明显的改动是视图内的特殊变量 `$this` 不再指
echo $this->render('_item', ['item' => $item]); echo $this->render('_item', ['item' => $item]);
``` ```
除了使用 PHP 作为主要的模板语言,Yii 2.0 也装备了两种流行模板引擎的官方支持: 除了使用 PHP 作为主要的模板语言,Yii 2.0 也装备了两种流行模板引擎的官方支持:Smarty 和 Twig。
Smarty 和 Twig。过去的 Prado 模板引擎不再被支持。要使用这些模板引擎, 过去的 Prado 模板引擎不再被支持。要使用这些模板引擎,
你需要配置 `view` 应用组件,给它设置 你需要配置 `view` 应用组件,
[[yii\base\View::$renderers|View::$renderers]] 属性。 给它设置 [[yii\base\View::$renderers|View::$renderers]] 属性。
具体请参阅[模板引擎](tutorial-template-engines.md)章节。 具体请参阅[模板引擎](tutorial-template-engines.md)章节。
模型(Model) 模型(Model)
------ ------
Yii 2.0 使用 [[yii\base\Model]] 作为模型基类,类似于 1.1 的 `CModel``CFormModel` 被完全弃用了, Yii 2.0 使用 [[yii\base\Model]] 作为模型基类,类似于 1.1 的 `CModel`
现在要创建表单模型类,可以通过继承 [[yii\base\Model]] 类来实现。 `CFormModel` 被完全弃用了,现在要创建表单模型类,可以通过继承 [[yii\base\Model]] 类来实现。
Yii 2.0 引进了名为 [[yii\base\Model::scenarios()|scenarios()]] 的新方法来声明支持的场景, Yii 2.0 引进了名为 [[yii\base\Model::scenarios()|scenarios()]] 的新方法来声明支持的场景,
并指明在哪个场景下某属性必须经过验证,可否被视为安全值等等。如: 并指明在哪个场景下某属性必须经过验证,可否被视为安全值等等。如:
@ -193,9 +193,9 @@ public function scenarios()
} }
``` ```
上面的代码声明了两个场景:`backend` 和 `frontend` 。对于 `backend` 场景, 上面的代码声明了两个场景:`backend` 和 `frontend` 。对于 `backend` 场景,`email` 和 `role` 属性值都是安全的,
`email``role` 属性值都是安全的,且能进行批量赋值。对于 `frontend` 场景, 且能进行批量赋值。对于 `frontend` 场景,`email` 能批量赋值而 `role` 不能。
`email` 能批量赋值而 `role` 不能。 `email` `role` 都必须通过规则验证。 `email``role` 都必须通过规则验证。
[[yii\base\Model::rules()|rules()]] 方法仍用于声明验证规则。注意,由于引入了 [[yii\base\Model::scenarios()|scenarios()]],现在已经没有 `unsafe` 验证器了。 [[yii\base\Model::rules()|rules()]] 方法仍用于声明验证规则。注意,由于引入了 [[yii\base\Model::scenarios()|scenarios()]],现在已经没有 `unsafe` 验证器了。
@ -209,8 +209,8 @@ public function scenarios()
控制器(Controller) 控制器(Controller)
----------- -----------
Yii 2.0 使用 [[yii\web\Controller]] 作为控制器的基类,它类似于 1.1 的 `CController` Yii 2.0 使用 [[yii\web\Controller]] 作为控制器的基类,
使用 [[yii\base\Action]] 作为操作类的基类。 它类似于 1.1 的 `CController`使用 [[yii\base\Action]] 作为操作类的基类。
这些变化最明显的影响是,当你在写控制器操作的代码时, 这些变化最明显的影响是,当你在写控制器操作的代码时,
应该返回(return)要渲染的内容而不是输出(echo)它: 应该返回(return)要渲染的内容而不是输出(echo)它:
@ -261,14 +261,14 @@ ActiveForm::end();
主题(Theme) 主题(Theme)
------ ------
2.0 主题的运作方式跟以往完全不同了。它们现在基于**路径映射机制**, 2.0 主题的运作方式跟以往完全不同了。它们现在基于**路径映射机制**,该机制会把一个源视图文件的路径映射到一个主题视图文件路径。
该机制会把一个源视图文件的路径映射到一个主题视图文件路径。
举例来说,如果路径映射为 `['/web/views' => '/web/themes/basic']` 举例来说,如果路径映射为 `['/web/views' => '/web/themes/basic']`
那么 `/web/views/site/index.php` 视图经过主题修饰的版本就会是 `/web/themes/basic/site/index.php` 那么 `/web/views/site/index.php` 视图经过主题修饰的版本就会是 `/web/themes/basic/site/index.php`
也因此让主题现在可以应用在任何视图文件之上,甚至是渲染控制器上下文环境之外的视图文件或小部件。 也因此让主题现在可以应用在任何视图文件之上,
甚至是渲染控制器上下文环境之外的视图文件或小部件。
同样,`CThemeManager` 组件已经被移除了。取而代之的 `theme` 成为了 `view` 同样,`CThemeManager` 组件已经被移除了。
应用组件的一个可配置属性。 取而代之的 `theme` 成为了 `view` 应用组件的一个可配置属性。
更多细节请参考[主题](output-theming.md)章节。 更多细节请参考[主题](output-theming.md)章节。
@ -276,13 +276,13 @@ ActiveForm::end();
控制台应用(Console Application) 控制台应用(Console Application)
-------------------- --------------------
控制台应用现在如普通的 Web 应用程序一样,由控制器组成,控制台的控制器继承自 [[yii\console\Controller]], 控制台应用现在如普通的 Web 应用程序一样,由控制器组成,
类似于 1.1 的 `CConsoleCommand` 控制台的控制器继承自 [[yii\console\Controller]],类似于 1.1 的 `CConsoleCommand`
运行控制台命令使用 `yii <route>`其中 `<route>` 运行控制台命令使用 `yii <route>`
代表控制器的路由(如 `sitemap/index`)。 其中 `<route>` 代表控制器的路由(如 `sitemap/index`)。
额外的匿名参数传递到对应的控制器操作方法,而有名的参数根据 额外的匿名参数传递到对应的控制器操作方法,
[[yii\console\Controller::options()]] 的声明来解析。 而有名的参数根据 [[yii\console\Controller::options()]] 的声明来解析。
Yii 2.0 支持基于代码注释自动生成相的关命令行帮助(help)信息。 Yii 2.0 支持基于代码注释自动生成相的关命令行帮助(help)信息。
@ -304,8 +304,8 @@ Yii 2.0 移除了原来内置的日期格式器和数字格式器,为了支持
动作过滤器(Action Filters) 动作过滤器(Action Filters)
-------------- --------------
作的过滤现在通过行为(behavior)来实现。要定义一个新的,自定义的过滤器, 作的过滤现在通过行为(behavior)来实现。要定义一个新的,自定义的过滤器,请继承 [[yii\base\ActionFilter]] 类。
请继承 [[yii\base\ActionFilter]] 类。要使用一个过滤器,需要把过滤器类作为一个 `behavior` 绑定到控制器上。 要使用一个过滤器,需要把过滤器类作为一个 `behavior` 绑定到控制器上。
例如,要使用 [[yii\filters\AccessControl]] 过滤器,你需要在控制器内添加如下代码: 例如,要使用 [[yii\filters\AccessControl]] 过滤器,你需要在控制器内添加如下代码:
```php ```php
@ -400,11 +400,11 @@ $rows = $command->queryAll();
活动记录(Active Record) 活动记录(Active Record)
------------- -------------
Yii 2.0 的[活动记录](db-active-record.md)改动了很多。两个最显而易见的改动分别涉及查询语句的生成 Yii 2.0 的[活动记录](db-active-record.md)改动了很多。
(query building)和关联查询的处理(relational query handling)。 两个最显而易见的改动分别涉及查询语句的生成(query building)和关联查询的处理(relational query handling)。
1.1 中的 `CDbCriteria` 类在 Yii 2 中被 [[yii\db\ActiveQuery]] 所替代。这个类是继承自 [[yii\db\Query]], 1.1 中的 `CDbCriteria` 类在 Yii 2 中被 [[yii\db\ActiveQuery]] 所替代。
因此也继承了所有查询生成方法。开始拼装一个查询可以调用 [[yii\db\ActiveRecord::find()]] 方法进行: 这个类是继承自 [[yii\db\Query]],因此也继承了所有查询生成方法。开始拼装一个查询可以调用 [[yii\db\ActiveRecord::find()]] 方法进行:
```php ```php
// 检索所有“活动的”客户和订单,并以 ID 排序: // 检索所有“活动的”客户和订单,并以 ID 排序:
@ -415,8 +415,8 @@ $customers = Customer::find()
``` ```
要声明一个关联关系,只需简单地定义一个 getter 方法来返回一个 [[yii\db\ActiveQuery|ActiveQuery]] 对象。 要声明一个关联关系,只需简单地定义一个 getter 方法来返回一个 [[yii\db\ActiveQuery|ActiveQuery]] 对象。
getter 方法定义的属性名代表关联表名称。如,以下代码声明了一个名为 `orders` 的关系 getter 方法定义的属性名代表关联表名称。
(1.1 中必须在 `relations()` 方法内声明关系): 如,以下代码声明了一个名为 `orders` 的关系(1.1 中必须在 `relations()` 方法内声明关系):
```php ```php
class Customer extends \yii\db\ActiveRecord class Customer extends \yii\db\ActiveRecord
@ -431,7 +431,6 @@ class Customer extends \yii\db\ActiveRecord
现在你就可以通过调用 `$customer->orders` 来访问关联表中某用户的订单了。 现在你就可以通过调用 `$customer->orders` 来访问关联表中某用户的订单了。
你还可以用以下代码进行一场指定条件的实时关联查询: 你还可以用以下代码进行一场指定条件的实时关联查询:
```php ```php
$orders = $customer->getOrders()->andWhere('status=1')->all(); $orders = $customer->getOrders()->andWhere('status=1')->all();
``` ```
@ -441,8 +440,8 @@ $orders = $customer->getOrders()->andWhere('status=1')->all();
第二条通过主表记录经主键筛选后查询关联表记录。 第二条通过主表记录经主键筛选后查询关联表记录。
当生成返回大量记录的查询时,可以链式书写 [[yii\db\ActiveQuery::asArray()|asArray()]] 方法, 当生成返回大量记录的查询时,可以链式书写 [[yii\db\ActiveQuery::asArray()|asArray()]] 方法,
这样会以数组的形式返回查询结果,而不必返回[[yii\db\ActiveRecord|ActiveRecord]] 对象, 这样会以数组的形式返回查询结果,而不必返回
这能显著降低因大量记录读取所消耗的 CPU 时间和内存。如: [[yii\db\ActiveRecord|ActiveRecord]] 对象,这能显著降低因大量记录读取所消耗的 CPU 时间和内存。如:
```php ```php
$customers = Customer::find()->asArray()->all(); $customers = Customer::find()->asArray()->all();
@ -459,8 +458,8 @@ public function init()
} }
``` ```
曾几何时,在 1.1 中重写一个活动记录类的构造方法会导致一些问题。 曾几何时,在 1.1 中重写一个活动记录类的构造方法会导致一些问题。它们不会在 2.0 中出现了。
它们不会在 2.0 中出现了。需要注意的是,如果你需要在构造方法中添加一些参数,恐怕必须重写 [[yii\db\ActiveRecord::instantiate()]] 方法。 需要注意的是,如果你需要在构造方法中添加一些参数,恐怕必须重写 [[yii\db\ActiveRecord::instantiate()]] 方法。
活动记录方面还有很多其他的变化与改进, 活动记录方面还有很多其他的变化与改进,
请参考[活动记录](db-active-record.md)章节以了解更多细节。 请参考[活动记录](db-active-record.md)章节以了解更多细节。
@ -501,8 +500,8 @@ class MyBehavior extends Behavior
用户及身份验证接口(IdentityInterface) 用户及身份验证接口(IdentityInterface)
------------------------------------- -------------------------------------
1.1 中的 `CWebUser` 类现在被 [[yii\web\User]] 所取代,随之 `CUserIdentity` 类也不在了。与之相对的, 1.1 中的 `CWebUser` 类现在被 [[yii\web\User]] 所取代,随之 `CUserIdentity` 类也不在了。
为达到相同目的,你可以实现 [[yii\web\IdentityInterface]] 接口,它使用起来更直观。 与之相对的,为达到相同目的,你可以实现 [[yii\web\IdentityInterface]] 接口,它使用起来更直观。
在高级应用模版里提供了一个这样的一个例子。 在高级应用模版里提供了一个这样的一个例子。
要了解更多细节请参考[认证(Authentication)](security-authentication.md),[授权(Authorization)](security-authorization.md)以及[高级应用模版](tutorial-advanced-app.md) 这三个章节。 要了解更多细节请参考[认证(Authentication)](security-authentication.md),[授权(Authorization)](security-authorization.md)以及[高级应用模版](tutorial-advanced-app.md) 这三个章节。
@ -512,9 +511,9 @@ URL 管理
-------- --------
Yii 2.0 的 URL 管理跟 1.1 中很像。一个主要的改进是现在的 URL 管理支持**可选参数**了。 Yii 2.0 的 URL 管理跟 1.1 中很像。一个主要的改进是现在的 URL 管理支持**可选参数**了。
比如,如果你在 2.0 中定义了一个下面这样的规则,那么它可以同时匹配 `post/popular` 比如,如果你在 2.0 中定义了一个下面这样的规则,那么它可以同时匹配
`post/1/popular` 两种 URL。而在 1.1 中为达成相同效果, `post/popular` `post/1/popular` 两种 URL。
必须要使用两条规则。 而在 1.1 中为达成相同效果,必须要使用两条规则。
```php ```php
[ [

31
docs/guide-zh-CN/intro-yii.md

@ -11,8 +11,8 @@ Yii 最适合做什么?
Yii 是一个通用的 Web 编程框架,即可以用于开发各种用 PHP 构建的 Web 应用。 Yii 是一个通用的 Web 编程框架,即可以用于开发各种用 PHP 构建的 Web 应用。
因为基于组件的框架结构和设计精巧的缓存支持,它特别适合开发大型应用, 因为基于组件的框架结构和设计精巧的缓存支持,它特别适合开发大型应用,
如门户网站、社区、内容管理系统(CMS)、电子商务项目 如门户网站、社区、内容管理系统(CMS)、
和 RESTful Web 服务等。 电子商务项目和 RESTful Web 服务等。
Yii 和其他框架相比呢? Yii 和其他框架相比呢?
@ -22,8 +22,8 @@ Yii 和其他框架相比呢?
- 和其他 PHP 框架类似,Yii 实现了 MVC(Model-View-Controller) - 和其他 PHP 框架类似,Yii 实现了 MVC(Model-View-Controller)
设计模式并基于该模式组织代码。 设计模式并基于该模式组织代码。
- Yii 的代码简洁优雅,这是它的编程哲学。它永远不会为了刻板地 - Yii 的代码简洁优雅,这是它的编程哲学。
遵照某种设计模式而对代码进行过度的设计。 它永远不会为了刻板地遵照某种设计模式而对代码进行过度的设计。
- Yii 是一个全栈框架,提供了大量久经考验,开箱即用的特性: - Yii 是一个全栈框架,提供了大量久经考验,开箱即用的特性:
对关系型和 NoSQL 数据库都提供了查询生成器和 对关系型和 NoSQL 数据库都提供了查询生成器和
ActiveRecord;RESTful API 的开发支持;多层缓存支持,等等。 ActiveRecord;RESTful API 的开发支持;多层缓存支持,等等。
@ -31,9 +31,9 @@ Yii 和其他框架相比呢?
坚实可靠的扩展架构,使用、再开发或再发布扩展。 坚实可靠的扩展架构,使用、再开发或再发布扩展。
- 高性能始终是 Yii 的首要目标之一。 - 高性能始终是 Yii 的首要目标之一。
Yii 不是一场独角戏,它由一个[强大的开发者团队](http://www.yiiframework.com/about/) Yii 不是一场独角戏,它由一个[强大的开发者团队](http://www.yiiframework.com/about/)提供支持,
提供支持,也有一个庞大的专家社区,持续不断地对 Yii 的开发作出贡献。Yii 开发者团队 也有一个庞大的专家社区,持续不断地对 Yii 的开发作出贡献。
始终对 Web 开发趋势和其他框架及项目中的最佳实践和特性保持密切关注, Yii 开发者团队始终对 Web 开发趋势和其他框架及项目中的最佳实践和特性保持密切关注,
那些有意义的最佳实践及特性会被不定期的整合进核心框架中, 那些有意义的最佳实践及特性会被不定期的整合进核心框架中,
并提供简单优雅的接口。 并提供简单优雅的接口。
@ -43,18 +43,19 @@ Yii 版本
------------ ------------
Yii 当前有两个主要版本:1.1 和 2.0。 1.1 版是上代的老版本,现在处于维护状态。 Yii 当前有两个主要版本:1.1 和 2.0。 1.1 版是上代的老版本,现在处于维护状态。
2.0 版是一个完全重写的版本,采用了最新的技术和协议,包括依赖包管理器 2.0 版是一个完全重写的版本,采用了最新的技术和协议,包括依赖包管理器 Composer、PHP 代码规范 PSR、命名空间、Traits(特质)等等。
Composer、PHP 代码规范 PSR、命名空间、Traits(特质)等等。 2.0 版代表新一代框架, 2.0 版代表新一代框架,是未来几年中我们的主要开发版本。
是未来几年中我们的主要开发版本。本指南主要基于 2.0 版编写。 本指南主要基于 2.0 版编写。
系统要求和先决条件 系统要求和先决条件
------------------------------ ------------------------------
Yii 2.0 需要 PHP 5.4.0 或以上版本支持。你可以通过运行任何 Yii 发行包 Yii 2.0 需要 PHP 5.4.0 或以上版本支持。你可以通过运行任何
中附带的系统要求检查器查看每个具体特性所需的 PHP 配置。 Yii 发行包中附带的系统要求检查器查看每个具体特性所需的 PHP 配置。
使用 Yii 需要对面向对象编程(OOP)有基本了解,因为 Yii 是一个纯面向对象的框架。 使用 Yii 需要对面向对象编程(OOP)有基本了解,因为 Yii 是一个纯面向对象的框架。Yii 2.0 还使用了 PHP 的最新特性,
Yii 2.0 还使用了 PHP 的最新特性,例如[命名空间](http://www.php.net/manual/en/language.namespaces.php) 例如[命名空间](http://www.php.net/manual/en/language.namespaces.php)
和[Trait(特质)](http://www.php.net/manual/en/language.oop5.traits.php) 。理解这些概念将有助于你更快地掌握 Yii 2.0。 和[Trait(特质)](http://www.php.net/manual/en/language.oop5.traits.php)。
理解这些概念将有助于你更快地掌握 Yii 2.0。

20
docs/guide-zh-CN/rest-authentication.md

@ -17,9 +17,9 @@
`https://example.com/users?access-token=xxxxxxxx` `https://example.com/users?access-token=xxxxxxxx`
由于大多数服务器都会保存请求参数到日志, 由于大多数服务器都会保存请求参数到日志,
这种方式应主要用于`JSONP` 请求,因为它不能使用HTTP头来发送access token 这种方式应主要用于`JSONP` 请求,因为它不能使用HTTP头来发送access token
* [OAuth 2](http://oauth.net/2/): 使用者从认证服务器上获取基于 * [OAuth 2](http://oauth.net/2/): 使用者从认证服务器上获取基于OAuth2协议的access token,
OAuth2协议的access token,然后通过 然后通过[HTTP Bearer Tokens](http://tools.ietf.org/html/rfc6750)
[HTTP Bearer Tokens](http://tools.ietf.org/html/rfc6750) 发送到API 服务器。 发送到API 服务器。
Yii 支持上述的认证方式,你也可很方便的创建新的认证方式。 Yii 支持上述的认证方式,你也可很方便的创建新的认证方式。
@ -36,8 +36,8 @@ Yii 支持上述的认证方式,你也可很方便的创建新的认证方式
当[[yii\web\User::enableSession|enableSession]]为false, 当[[yii\web\User::enableSession|enableSession]]为false,
请求中的用户认证状态就不能通过session来保持,每个请求的认证通过步骤2和3来实现。 请求中的用户认证状态就不能通过session来保持,每个请求的认证通过步骤2和3来实现。
> 提示: 如果你将RESTful APIs作为应用开发,可以设置应用配置中 > Tip: 如果你将RESTful APIs作为应用开发,可以设置应用配置中 `user` 组件的
> `user` 组件的[[yii\web\User::enableSession|enableSession]], > [[yii\web\User::enableSession|enableSession]],
> 如果将RESTful APIs作为模块开发,可以在模块的 `init()` 方法中增加如下代码,如下所示: > 如果将RESTful APIs作为模块开发,可以在模块的 `init()` 方法中增加如下代码,如下所示:
> ```php > ```php
@ -106,19 +106,19 @@ class User extends ActiveRecord implements IdentityInterface
} }
``` ```
在上述认证启用后,对于每个API请求,请求控制器都会在它的`beforeAction()` 在上述认证启用后,对于每个API请求,
步骤中对用户进行认证。 请求控制器都会在它的`beforeAction()`步骤中对用户进行认证。
如果认证成功,控制器再执行其他检查(如频率限制,操作权限),然后再执行动作, 如果认证成功,控制器再执行其他检查(如频率限制,操作权限),然后再执行动作,
授权用户信息可使用`Yii::$app->user->identity`获取. 授权用户信息可使用`Yii::$app->user->identity`获取.
如果认证失败,会发送一个HTTP状态码为401的响应,并带有其他相关信息头 如果认证失败,会发送一个HTTP状态码为401的响应,
(如HTTP 基本认证会有`WWW-Authenticate` 头信息). 并带有其他相关信息头(如HTTP 基本认证会有`WWW-Authenticate` 头信息).
## 授权 <a name="authorization"></a> ## 授权 <a name="authorization"></a>
在用户认证成功后,你可能想要检查他是否有权限执行对应的作来获取资源, 在用户认证成功后,你可能想要检查他是否有权限执行对应的作来获取资源,
这个过程称为 *authorization* 这个过程称为 *authorization*
详情请参考 [Authorization section](security-authorization.md). 详情请参考 [Authorization section](security-authorization.md).

83
docs/guide-zh-CN/rest-controllers.md

@ -1,14 +1,14 @@
控制器 控制器
=========== ===========
在创建资源类和指定资源格输出式化后,下一步就是创建控制器动作将资源 在创建资源类和指定资源格输出式化后,
通过RESTful APIs展现给终端用户。 下一步就是创建控制器操作将资源通过RESTful APIs展现给终端用户。
Yii 提供两个控制器基类来简化创建 RESTful 动作的工作: Yii 提供两个控制器基类来简化创建RESTful
[[yii\rest\Controller]] 和 [[yii\rest\ActiveController]], 操作的工作:[[yii\rest\Controller]] 和 [[yii\rest\ActiveController]],
两个类的差别是后者提供一系列将资源处理成[Active Record](db-active-record.md) 两个类的差别是后者提供一系列将资源处理成[Active Record](db-active-record.md)的操作。
的动作。因此如果使用[Active Record](db-active-record.md) 因此如果使用[Active Record](db-active-record.md)内置的操作会比较方便,可考虑将控制器类
内置的动作会比较方便,可考虑将控制器类继承[[yii\rest\ActiveController]], 继承[[yii\rest\ActiveController]],
它会让你用最少的代码完成强大的RESTful APIs. 它会让你用最少的代码完成强大的RESTful APIs.
[[yii\rest\Controller]] 和 [[yii\rest\ActiveController]] 提供以下功能, [[yii\rest\Controller]] 和 [[yii\rest\ActiveController]] 提供以下功能,
@ -27,15 +27,15 @@ Yii 提供两个控制器基类来简化创建 RESTful 动作的工作:
## 创建控制器类 <span id="creating-controller"></span> ## 创建控制器类 <span id="creating-controller"></span>
当创建一个新的控制器类,控制器类的命名最好使用资源 当创建一个新的控制器类,控制器类的命名最好使用资源名称的单数格式,
名称的单数格式,例如,提供用户信息的控制器 例如,提供用户信息的控制器
可命名为`UserController`. 可命名为`UserController`.
创建新的动作和Web应用中创建操作类似,唯一的差别是Web应用中 创建新的操作和Web应用中创建操作类似,
调用`render()`方法渲染一个视图作为返回值,对于RESTful动作 唯一的差别是Web应用中调用`render()`方法渲染一个视图作为返回值,
直接返回数据,[[yii\rest\Controller::serializer|serializer]] 和 对于RESTful操作直接返回数据,
[[yii\web\Response|response object]] 会处理原始数据到请求格式的转换, [[yii\rest\Controller::serializer|serializer]] 和[[yii\web\Response|response object]]
例如 会处理原始数据到请求格式的转换,例如
```php ```php
public function actionView($id) public function actionView($id)
@ -52,7 +52,7 @@ public function actionView($id)
* [[yii\filters\ContentNegotiator|contentNegotiator]]: 支持内容协商, * [[yii\filters\ContentNegotiator|contentNegotiator]]: 支持内容协商,
在 [响应格式化](rest-response-formatting.md) 一节描述; 在 [响应格式化](rest-response-formatting.md) 一节描述;
* [[yii\filters\VerbFilter|verbFilter]]: 支持HTTP 方法验证;the [Authentication](rest-authentication.md) section; * [[yii\filters\VerbFilter|verbFilter]]: 支持HTTP 方法验证;
* [[yii\filters\auth\AuthMethod|authenticator]]: 支持用户认证, * [[yii\filters\auth\AuthMethod|authenticator]]: 支持用户认证,
在[认证](rest-authentication.md)一节描述; 在[认证](rest-authentication.md)一节描述;
* [[yii\filters\RateLimiter|rateLimiter]]: 支持频率限制, * [[yii\filters\RateLimiter|rateLimiter]]: 支持频率限制,
@ -75,11 +75,46 @@ public function behaviors()
} }
``` ```
### CORS <span id="cors"></span>
Adding the [Cross-Origin Resource Sharing](structure-filters.md#cors) filter to a controller is a bit more complicated
than adding other filters described above, because the CORS filter has to be applied before authentication methods
and thus needs a slightly different approach compared to other filters. Also authentication has to be disabled for the
[CORS Preflight requests](https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS#Preflighted_requests)
so that a browser can safely determine whether a request can be made beforehand without the need for sending
authentication credentials. The following shows the code that is needed to add the [[yii\filters\Cors]] filter
to an existing controller that extends from [[yii\rest\ActiveController]]:
```php
use yii\filters\auth\HttpBasicAuth;
public function behaviors()
{
$behaviors = parent::behaviors();
// remove authentication filter
$auth = $behaviors['authenticator'];
unset($behaviors['authenticator']);
// add CORS filter
$behaviors['corsFilter'] = [
'class' => \yii\filters\Cors::className(),
];
// re-add authentication filter
$behaviors['authenticator'] = $auth;
// avoid authentication on CORS-pre-flight requests (HTTP OPTIONS method)
$behaviors['authenticator']['except'] = ['options'];
return $behaviors;
}
```
## 继承 `ActiveController` <span id="extending-active-controller"></span> ## 继承 `ActiveController` <span id="extending-active-controller"></span>
如果你的控制器继承[[yii\rest\ActiveController]],应设置 如果你的控制器继承[[yii\rest\ActiveController]],
[[yii\rest\ActiveController::modelClass|modelClass]] 属性 应设置[[yii\rest\ActiveController::modelClass|modelClass]] 属性
为通过该控制器返回给用户的资源类名,该类必须继承[[yii\db\ActiveRecord]]. 为通过该控制器返回给用户的资源类名,该类必须继承[[yii\db\ActiveRecord]].
@ -122,9 +157,9 @@ public function prepareDataProvider()
### 执行访问检查 <span id="performing-access-check"></span> ### 执行访问检查 <span id="performing-access-check"></span>
通过RESTful APIs显示数据时,经常需要检查当前用户是否有权限访问和作所请求的资源, 通过RESTful APIs显示数据时,经常需要检查当前用户是否有权限访问和作所请求的资源,
在[[yii\rest\ActiveController]]中,可覆盖[[yii\rest\ActiveController::checkAccess()|checkAccess()]] 在[[yii\rest\ActiveController]]中,
方法来完成权限检查。 可覆盖[[yii\rest\ActiveController::checkAccess()|checkAccess()]]方法来完成权限检查。
```php ```php
/** /**
@ -135,14 +170,14 @@ public function prepareDataProvider()
* If the user does not have access, a [[ForbiddenHttpException]] should be thrown. * If the user does not have access, a [[ForbiddenHttpException]] should be thrown.
* *
* @param string $action the ID of the action to be executed * @param string $action the ID of the action to be executed
* @param \yii\base\Model $model the model to be accessed. If null, it means no specific model is being accessed. * @param \yii\base\Model $model the model to be accessed. If `null`, it means no specific model is being accessed.
* @param array $params additional parameters * @param array $params additional parameters
* @throws ForbiddenHttpException if the user does not have access * @throws ForbiddenHttpException if the user does not have access
*/ */
public function checkAccess($action, $model = null, $params = []) public function checkAccess($action, $model = null, $params = [])
{ {
// 检查用户能否访问 $action 和 $model // check if the user can access $action and $model
// 访问被拒绝应抛出ForbiddenHttpException // throw ForbiddenHttpException if access should be denied
if ($action === 'update' || $action === 'delete') { if ($action === 'update' || $action === 'delete') {
if ($model->author_id !== \Yii::$app->user->id) if ($model->author_id !== \Yii::$app->user->id)
throw new \yii\web\ForbiddenHttpException(sprintf('You can only %s articles that you\'ve created.', $action)); throw new \yii\web\ForbiddenHttpException(sprintf('You can only %s articles that you\'ve created.', $action));

9
docs/guide-zh-CN/rest-error-handling.md

@ -4,10 +4,11 @@
处理一个 RESTful API 请求时, 如果有一个用户请求错误或服务器发生意外时, 处理一个 RESTful API 请求时, 如果有一个用户请求错误或服务器发生意外时,
你可以简单地抛出一个异常来通知用户出错了。 你可以简单地抛出一个异常来通知用户出错了。
如果你能找出错误的原因 (例如,所请求的资源不存在),你应该 如果你能找出错误的原因 (例如,所请求的资源不存在),你应该
考虑抛出一个适当的HTTP状态代码的异常 (例如, [[yii\web\NotFoundHttpException]] 考虑抛出一个适当的HTTP状态代码的异常
意味着一个404 HTTP状态代码)。 Yii 将通过HTTP状态码和文本 (例如, [[yii\web\NotFoundHttpException]]意味着一个404 HTTP状态代码)。
发送相应的响应。 它还将包括在响应主体异常的 Yii 将通过HTTP状态码和文本发送相应的响应。
序列化表示形式。 例如, 它还将包括在响应主体异常的序列化表示形式。
例如,
``` ```
HTTP/1.1 404 Not Found HTTP/1.1 404 Not Found

10
docs/guide-zh-CN/rest-quick-start.md

@ -37,8 +37,8 @@ class UserController extends ActiveController
} }
``` ```
控制器类扩展自 [[yii\rest\ActiveController]]。通过指定 控制器类扩展自 [[yii\rest\ActiveController]]。
[[yii\rest\ActiveController::modelClass|modelClass]] 通过指定 [[yii\rest\ActiveController::modelClass|modelClass]]
作为 `app\models\User`, 控制器就能知道使用哪个模型去获取和处理数据。 作为 `app\models\User`, 控制器就能知道使用哪个模型去获取和处理数据。
@ -60,6 +60,9 @@ class UserController extends ActiveController
上面的配置主要是为`user`控制器增加一个 URL 规则。这样, 上面的配置主要是为`user`控制器增加一个 URL 规则。这样,
用户的数据就能通过美化的 URL 和有意义的 http 动词进行访问和操作。 用户的数据就能通过美化的 URL 和有意义的 http 动词进行访问和操作。
> Note: Yii will automatically pluralize controller names for use in endpoints (see [Trying it Out](#trying-it-out) section below).
> You can configure this using the [[yii\rest\UrlRule::$pluralize]] property.
## 启用 JSON 输入 <span id="enabling-json-input"></span> ## 启用 JSON 输入 <span id="enabling-json-input"></span>
@ -93,9 +96,6 @@ class UserController extends ActiveController
* `OPTIONS /users`: 显示关于末端 `/users` 支持的动词 * `OPTIONS /users`: 显示关于末端 `/users` 支持的动词
* `OPTIONS /users/123`: 显示有关末端 `/users/123` 支持的动词 * `OPTIONS /users/123`: 显示有关末端 `/users/123` 支持的动词
> 提示: Yii 将在末端使用的控制器的名称自动变为复数。(译注:个人感觉这里应该变为注意)
> 你可以用 [[yii\rest\UrlRule::$pluralize]]-属性来配置此项。
你可以访问你的API用 `curl` 命令如下, 你可以访问你的API用 `curl` 命令如下,
``` ```

26
docs/guide-zh-CN/rest-rate-limiting.md

@ -9,14 +9,14 @@
这个接口需要实现以下三个方法: 这个接口需要实现以下三个方法:
* `getRateLimit()`: 返回允许的请求的最大数目及时间,例如,`[100, 600]` 表示在 600 秒内最多 100 次的 API 调用。 * `getRateLimit()`: 返回允许的请求的最大数目及时间,例如,`[100, 600]` 表示在 600 秒内最多 100 次的 API 调用。
* `loadAllowance()`: 返回剩余的允许的请求和相应的UNIX时间戳数 * `loadAllowance()`: 返回剩余的允许的请求和最后一次速率限制检查时
当最后一次速率限制检查时 相应的 UNIX 时间戳数
* `saveAllowance()`: 保存允许剩余的请求数和当前的UNIX时间戳。 * `saveAllowance()`: 保存剩余的允许请求数和当前的 UNIX 时间戳。
你可以在 user 表中使用两列来记录容差和时间戳信息。 你可以在 user 表中使用两列来记录容差和时间戳信息。
`loadAllowance()``saveAllowance()` 可以通过实现对符合当前身份验证的用户 `loadAllowance()``saveAllowance()`
的这两列值的读和保存。为了提高性能,你也可以 可以通过实现对符合当前身份验证的用户的这两列值的读和保存。
考虑使用缓存或NoSQL存储这些信息。 为了提高性能,你也可以考虑使用缓存或 NoSQL 存储这些信息。
Implementation in the `User` model could look like the following: Implementation in the `User` model could look like the following:
@ -39,12 +39,12 @@ public function saveAllowance($request, $action, $allowance, $timestamp)
} }
``` ```
一旦 identity 实现所需的接口, Yii 会自动使用 [[yii\filters\RateLimiter]]为 [[yii\rest\Controller]] 一旦 identity 实现所需的接口, Yii 会自动使用 [[yii\filters\RateLimiter]]
配置一个行为过滤器来执行速率限制检查。 如果速度超出限制该速率限制器将抛出一个 [[yii\web\TooManyRequestsHttpException]]。 为 [[yii\rest\Controller]] 配置一个行为过滤器来执行速率限制检查。如果速度超出限制,
你可以在你的 REST 控制器类里配置速率限制, 该速率限制器将抛出一个 [[yii\web\TooManyRequestsHttpException]]。你可以参考以下代码在你的 REST 控制器类里配置速率限制:
你可以在 user 表中使用两列来记录容差和时间戳信息。`loadAllowance()` 和 `saveAllowance()` 可以通过实现对符合当前身份 You may configure the rate limiter
验证的用户的这两列值的读和保存。为了提高性能,你也可以考虑使用缓存或 NoSQL 存储这些信息。 as follows in your REST controller classes:
```php ```php
public function behaviors() public function behaviors()
@ -55,8 +55,8 @@ public function behaviors()
} }
``` ```
当速率限制被激活,默认情况下每个响应将包含以下 HTTP 当速率限制被激活,默认情况下每个响应将包含以下
头发送目前的速率限制信息: HTTP 头发送目前的速率限制信息:
* `X-Rate-Limit-Limit`: 同一个时间段所允许的请求的最大数目; * `X-Rate-Limit-Limit`: 同一个时间段所允许的请求的最大数目;
* `X-Rate-Limit-Remaining`: 在当前时间段内剩余的请求的数量; * `X-Rate-Limit-Remaining`: 在当前时间段内剩余的请求的数量;

98
docs/guide-zh-CN/rest-resources.md

@ -4,19 +4,19 @@
RESTful 的 API 都是关于访问和操作 *资源*,可将资源看成MVC模式中的 RESTful 的 API 都是关于访问和操作 *资源*,可将资源看成MVC模式中的
[模型](structure-models.md) [模型](structure-models.md)
在如何代表一个资源没有固定的限定,在Yii中通常使用 [[yii\base\Model]] 在如何代表一个资源没有固定的限定,在Yii中通常使用
或它的子类(如 [[yii\db\ActiveRecord]]) [[yii\base\Model]] 或它的子类(如 [[yii\db\ActiveRecord]])
代表资源,是为以下原因: 代表资源,是为以下原因:
* [[yii\base\Model]] 实现了 [[yii\base\Arrayable]] 接口,它允许你通过RESTful API * [[yii\base\Model]] 实现了 [[yii\base\Arrayable]] 接口,
自定义你想要公开的资源数据。 它允许你通过RESTful API自定义你想要公开的资源数据。
* [[yii\base\Model]] 支持 [输入验证](input-validation.md), 在你的RESTful API * [[yii\base\Model]] 支持 [输入验证](input-validation.md),
需要支持数据输入时非常有用。 在你的RESTful API需要支持数据输入时非常有用。
* [[yii\db\ActiveRecord]] 提供了强大的数据库访问和操作方面的支持, * [[yii\db\ActiveRecord]] 提供了强大的数据库访问和操作方面的支持,
如资源数据需要存到数据库它提供了完美的支持。 如资源数据需要存到数据库它提供了完美的支持。
本节主要描述资源类如何从 [[yii\base\Model]] (或它的子类) 本节主要描述资源类如何从 [[yii\base\Model]] (或它的子类) 继承
继承并指定哪些数据可通过RESTful API返回,如果资源类没有 并指定哪些数据可通过RESTful API返回,如果资源类没有
继承 [[yii\base\Model]] 会将它所有的公开成员变量返回。 继承 [[yii\base\Model]] 会将它所有的公开成员变量返回。
@ -30,9 +30,9 @@ Yii将这个过程分成两步,首先,资源会被[[yii\rest\Serializer]]转
通过覆盖 [[yii\base\Model::fields()|fields()]] 和/或 通过覆盖 [[yii\base\Model::fields()|fields()]] 和/或
[[yii\base\Model::extraFields()|extraFields()]] 方法, [[yii\base\Model::extraFields()|extraFields()]] 方法,
可指定资源中称为 *字段* 的数据放入展现数组中,两个方法的差别为前者指定默认包含到展现数组的字段集合, 可指定资源中称为 *字段* 的数据放入展现数组中,
后者指定由于终端用户的请求包含 `expand` 参数哪些额外的字段应被包含到展现数组 两个方法的差别为前者指定默认包含到展现数组的字段集合
例如, 后者指定由于终端用户的请求包含 `expand` 参数哪些额外的字段应被包含到展现数组,例如,
``` ```
// 返回fields()方法中申明的所有字段 // 返回fields()方法中申明的所有字段
@ -54,15 +54,15 @@ http://localhost/users?fields=id,email&expand=profile
[[yii\base\Model::fields()]] 默认返回模型的所有属性作为字段, [[yii\base\Model::fields()]] 默认返回模型的所有属性作为字段,
[[yii\db\ActiveRecord::fields()]] 只返回和数据表关联的属性作为字段。 [[yii\db\ActiveRecord::fields()]] 只返回和数据表关联的属性作为字段。
可覆盖 `fields()` 方法来增加、删除、重命名、重定义字段,`fields()` 的返回值应为数组, 可覆盖 `fields()` 方法来增加、删除、重命名、重定义字段,
数组的键为字段名数组的值为对应的字段定义, `fields()` 的返回值应为数组,数组的键为字段名
可为属性名或返回对应的字段值的匿名函数, 数组的值为对应的字段定义,可为属性名或返回对应的字段值的匿名函数,
特殊情况下,如果字段名和属性名相同, 特殊情况下,如果字段名和属性名相同,
可省略数组的键,例如 可省略数组的键,例如
```php ```php
// 明确列出每个字段,适用于你希望数据表或模型属性 // 明确列出每个字段,适用于你希望数据表或
//修改时不导致你的字段修改(保持后端API兼容性) // 模型属性修改时不导致你的字段修改(保持后端API兼容性)
public function fields() public function fields()
{ {
return [ return [
@ -77,8 +77,8 @@ public function fields()
]; ];
} }
// 过滤掉一些字段,适用于你希望继承父类 // 过滤掉一些字段,适用于你希望继承
//实现同时你想屏蔽掉一些敏感字段 // 父类实现同时你想屏蔽掉一些敏感字段
public function fields() public function fields()
{ {
$fields = parent::fields(); $fields = parent::fields();
@ -90,7 +90,7 @@ public function fields()
} }
``` ```
> 警告: 模型的所有属性默认会被包含到API结果中, > Warning: 模型的所有属性默认会被包含到API结果中,
> 应检查数据确保没包含敏感数据,如果有敏感数据, > 应检查数据确保没包含敏感数据,如果有敏感数据,
> 应覆盖`fields()`过滤掉,在上述例子中,我们选择过滤掉 `auth_key`, > 应覆盖`fields()`过滤掉,在上述例子中,我们选择过滤掉 `auth_key`,
> `password_hash``password_reset_token`. > `password_hash``password_reset_token`.
@ -98,11 +98,11 @@ public function fields()
### 覆盖 `extraFields()` 方法 <span id="overriding-extra-fields"></span> ### 覆盖 `extraFields()` 方法 <span id="overriding-extra-fields"></span>
[[yii\base\Model::extraFields()]] 默认返回空值,[[yii\db\ActiveRecord::extraFields()]] [[yii\base\Model::extraFields()]] 默认返回空值,
返回和数据表关联的属性。 [[yii\db\ActiveRecord::extraFields()]] 返回和数据表关联的属性。
`extraFields()` 返回的数据格式和 `fields()` 相同,一般`extraFields()` `extraFields()` 返回的数据格式和 `fields()` 相同,
主要用于指定哪些值为对象的字段, 一般`extraFields()` 主要用于指定哪些值为对象的字段,
例如,给定以下字段申明 例如,给定以下字段申明
```php ```php
@ -136,34 +136,52 @@ public function extraFields()
## 链接 <span id="links"></span> ## 链接 <span id="links"></span>
[HATEOAS](http://en.wikipedia.org/wiki/HATEOAS), [HATEOAS](http://en.wikipedia.org/wiki/HATEOAS),
Hypermedia as the Engine of Application State的缩写, Hypermedia as the Engine of Application State的缩写,
提升RESTful API 应返回允许终端用户访问的资源操作的信息, 提升RESTful API 应返回允许终端用户访问的资源操作的信息,
HATEOAS 的目的是在API中返回包含相关链接信息的资源数据。 HATEOAS 的目的是在API中返回包含相关链接信息的资源数据。
资源类通过实现[[yii\web\Linkable]] 接口来支持HATEOAS, 资源类通过实现[[yii\web\Linkable]] 接口来支持HATEOAS,
该接口包含方法 [[yii\web\Linkable::getLinks()|getLinks()]] 来返回 该接口包含方法 [[yii\web\Linkable::getLinks()|getLinks()]] 来返回
[[yii\web\Link|links]] 列表,典型情况下应返回包含代表本资源对象URL的 `self` 链接,例如 [[yii\web\Link|links]] 列表,典型情况下应返回包含代表本资源对象URL的 `self` 链接,例如
```php ```php
use yii\db\ActiveRecord; use yii\base\Model;
use yii\web\Link; use yii\web\Link; // represents a link object as defined in JSON Hypermedia API Language.
use yii\web\Linkable; use yii\web\Linkable;
use yii\helpers\Url; use yii\helpers\Url;
class User extends ActiveRecord implements Linkable class UserResource extends Model implements Linkable
{ {
public $id;
public $email;
//...
public function fields()
{
return ['id', 'email'];
}
public function extraFields()
{
return ['profile'];
}
public function getLinks() public function getLinks()
{ {
return [ return [
Link::REL_SELF => Url::to(['user/view', 'id' => $this->id], true), Link::REL_SELF => Url::to(['user/view', 'id' => $this->id], true),
'edit' => Url::to(['user/view', 'id' => $this->id], true),
'profile' => Url::to(['user/profile/view', 'id' => $this->id], true),
'index' => Url::to(['users'], true),
]; ];
} }
} }
``` ```
当响应中返回一个`User` 对象,它会包含一个 `_links` 当响应中返回一个`User` 对象,
单元表示和用户相关的链接,例如 它会包含一个 `_links` 单元表示和用户相关的链接,例如
``` ```
{ {
@ -173,6 +191,15 @@ class User extends ActiveRecord implements Linkable
"_links" => { "_links" => {
"self": { "self": {
"href": "https://example.com/users/100" "href": "https://example.com/users/100"
},
"edit": {
"href": "https://example.com/users/100"
},
"profile": {
"href": "https://example.com/users/profile/100"
},
"index": {
"href": "https://example.com/users"
} }
} }
} }
@ -181,8 +208,8 @@ class User extends ActiveRecord implements Linkable
## 集合 <span id="collections"></span> ## 集合 <span id="collections"></span>
资源对象可以组成 *集合*每个集合包含一组相同 资源对象可以组成 *集合*
类型的资源对象。 每个集合包含一组相同类型的资源对象。
集合可被展现成数组,更多情况下展现成 [data providers](output-data-providers.md). 集合可被展现成数组,更多情况下展现成 [data providers](output-data-providers.md).
因为data providers支持资源的排序和分页,这个特性在 RESTful API 返回集合时也用到, 因为data providers支持资源的排序和分页,这个特性在 RESTful API 返回集合时也用到,
@ -207,8 +234,8 @@ class PostController extends Controller
} }
``` ```
当在RESTful API响应中发送data provider 时, [[yii\rest\Serializer]] 当在RESTful API响应中发送data provider 时,
会取出资源的当前页并组装成资源对象数组, [[yii\rest\Serializer]] 会取出资源的当前页并组装成资源对象数组,
[[yii\rest\Serializer]] 也通过如下HTTP头包含页码信息: [[yii\rest\Serializer]] 也通过如下HTTP头包含页码信息:
* `X-Pagination-Total-Count`: 资源所有数量; * `X-Pagination-Total-Count`: 资源所有数量;
@ -218,3 +245,4 @@ class PostController extends Controller
* `Link`: 允许客户端一页一页遍历资源的导航链接集合. * `Link`: 允许客户端一页一页遍历资源的导航链接集合.
可在[快速入门](rest-quick-start.md#trying-it-out) 一节中找到样例. 可在[快速入门](rest-quick-start.md#trying-it-out) 一节中找到样例.

34
docs/guide-zh-CN/rest-response-formatting.md

@ -10,8 +10,8 @@
通过 [[yii\rest\Serializer]] 来完成。 通过 [[yii\rest\Serializer]] 来完成。
3. 通过内容协商步骤将数组转换成字符串。 3. 通过内容协商步骤将数组转换成字符串。
[[yii\web\ResponseFormatterInterface|response formatters]] 通过 [[yii\web\ResponseFormatterInterface|response formatters]] 通过
[[yii\web\Response::formatters|response]] [[yii\web\Response::formatters|response]] 应用程序
[应用程序组件]((structure-application-components.md))来注册完成。 组件来注册完成。
## 内容协商 <span id="content-negotiation"></span> ## 内容协商 <span id="content-negotiation"></span>
@ -155,3 +155,33 @@ Content-Type: application/json; charset=UTF-8
} }
} }
``` ```
### Controlling JSON output
The JSON response is generated by the [[yii\web\JsonResponseFormatter|JsonResponseFormatter]] class which will
use the [[yii\helpers\Json|JSON helper]] internally. This formatter can be configured with different options like
for example the [[yii\web\JsonResponseFormatter::$prettyPrint|$prettyPrint]] option, which is useful on development for
better readable responses, or [[yii\web\JsonResponseFormatter::$encodeOptions|$encodeOptions]] to control the output
of the JSON encoding.
The formatter can be configured in the [[yii\web\Response::formatters|formatters]] property of the `response` application
component in the application [configuration](concept-configuration.md) like the following:
```php
'response' => [
// ...
'formatters' => [
\yii\web\Response::FORMAT_JSON => [
'class' => 'yii\web\JsonResponseFormatter',
'prettyPrint' => YII_DEBUG, // use "pretty" output in debug mode
'encodeOptions' => JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE,
// ...
],
],
],
```
When returning data from a database using the [DAO](db-dao.md) database layer all data will be represented
as strings, which is not always the expected result especially numeric values should be represented as
numbers in JSON. When using the ActiveRecord layer for retrieving data from the database, the values for numeric
columns will be converted to integers when data is fetched from the database in [[yii\db\ActiveRecord::populateRecord()]].

25
docs/guide-zh-CN/rest-routing.md

@ -73,9 +73,9 @@
] ]
``` ```
您可能已经注意到控制器ID`user`以复数形式出现在`users`末端。这是因为 [[yii\rest\UrlRule]] 您可能已经注意到控制器ID`user`以复数形式出现在`users`末端。这是因为 [[yii\rest\UrlRule]] 能够为他们使用的末端全自动复数化控制器ID。
能够为他们使用的末端全自动复数化控制器ID。您可以通过设置 [[yii\rest\UrlRule::pluralize]] 您可以通过设置 [[yii\rest\UrlRule::pluralize]] 为false 来禁用此行为,如果您想
为false 来禁用此行为,如果您想使用一些特殊的名字您可以通过配置 [[yii\rest\UrlRule::controller]] 属性。 使用一些特殊的名字您可以通过配置 [[yii\rest\UrlRule::controller]] 属性。
> Info: The pluralization of controller IDs is done by [[yii\helpers\Inflector::pluralize()]]. The method respects > Info: The pluralization of controller IDs is done by [[yii\helpers\Inflector::pluralize()]]. The method respects
special pluralization rules. For example, the word `box` will be pluralized as `boxes` instead of `boxs`. special pluralization rules. For example, the word `box` will be pluralized as `boxes` instead of `boxs`.
@ -90,3 +90,22 @@ a controller ID. For example, the following code maps the name `u` to the contro
'controller' => ['u' => 'user'], 'controller' => ['u' => 'user'],
] ]
``` ```
## Extra configuration for contained rules
It could be useful to specify extra configuration that is applied to each rule contained within [[yii\rest\UrlRule]].
A good example would be specifying defaults for `expand` parameter:
```php
[
'class' => 'yii\rest\UrlRule',
'controller' => ['user'],
'ruleConfig' => [
'class' => 'yii\web\UrlRule',
'defaults' => [
'expand' => 'profile',
]
],
],
```

4
docs/guide-zh-CN/rest-versioning.md

@ -70,10 +70,10 @@ api/
return [ return [
'modules' => [ 'modules' => [
'v1' => [ 'v1' => [
'basePath' => '@app/modules/v1', 'class' => 'app\modules\v1\Module',
], ],
'v2' => [ 'v2' => [
'basePath' => '@app/modules/v2', 'class' => 'app\modules\v2\Module',
], ],
], ],
'components' => [ 'components' => [

8
docs/guide-zh-CN/runtime-bootstrapping.md

@ -25,14 +25,14 @@
以及在应用的 [Bootstrap 属性](structure-applications.md#bootstrap)中声明的各个 以及在应用的 [Bootstrap 属性](structure-applications.md#bootstrap)中声明的各个
[模块(modules)组件](structure-modules.md)(如果有)。 [模块(modules)组件](structure-modules.md)(如果有)。
因为引导工作必须在处理**每一次**请求之前都进行一遍, 因为引导工作必须在处理**每一次**请求之前都进行一遍,因此让该过程尽可能轻量化就异常重要,
因此让该过程尽可能轻量化就异常重要,请尽可能地优化这一步骤。 请尽可能地优化这一步骤。
请尽量不要注册太多引导组件。只有他需要在 HTTP 请求处理的全部生命周期中都作用时才需要使用它。 请尽量不要注册太多引导组件。只有他需要在 HTTP 请求处理的全部生命周期中都作用时才需要使用它。
举一个用到它的范例:一个模块需要注册额外的 URL 解析规则,就应该把它列在应用的 举一个用到它的范例:一个模块需要注册额外的 URL 解析规则,就应该把它列在应用的
[bootstrap 属性](structure-applications.md#bootstrap)之中, [bootstrap 属性](structure-applications.md#bootstrap)之中,
这样该 URL 解析规则才能在解析请求之前生效。 这样该 URL 解析规则才能在解析请求之前生效。(译注:换言之,为了性能需要,除了 URL
(译注:换言之,为了性能需要,除了 URL 解析等少量操作之外,绝大多数组件都应该按需加载,而不是都放在引导过程中。) 解析等少量操作之外,绝大多数组件都应该按需加载,而不是都放在引导过程中。)
在生产环境中,可以开启字节码缓存,比如 APC, 在生产环境中,可以开启字节码缓存,比如 APC,
来进一步最小化加载和解析 PHP 文件所需的时间。 来进一步最小化加载和解析 PHP 文件所需的时间。

37
docs/guide-zh-CN/runtime-handling-errors.md

@ -7,7 +7,7 @@ Yii错误处理器做以下工作来提升错误处理效果:
* 所有非致命PHP错误(如,警告,提示)会转换成可获取异常; * 所有非致命PHP错误(如,警告,提示)会转换成可获取异常;
* 异常和致命的PHP错误会被显示, * 异常和致命的PHP错误会被显示,
在调试模式会显示详细的函数调用栈和源代码行数。 在调试模式会显示详细的函数调用栈和源代码行数。
* 支持使用专用的 [控制器](structure-controllers.md#actions) 来显示错误; * 支持使用专用的 [控制器](structure-controllers.md#actions) 来显示错误;
* 支持不同的错误响应格式; * 支持不同的错误响应格式;
[[yii\web\ErrorHandler|error handler]] 错误处理器默认启用, [[yii\web\ErrorHandler|error handler]] 错误处理器默认启用,
@ -48,10 +48,10 @@ try {
``` ```
如果你想显示一个错误页面告诉用户请求是无效的或无法处理的, 如果你想显示一个错误页面告诉用户请求是无效的或无法处理的,
可简单地抛出一个 [[yii\web\HttpException|HTTP exception]]异常,如 [[yii\web\NotFoundHttpException]]。 可简单地抛出一个 [[yii\web\HttpException|HTTP exception]]异常,
如 [[yii\web\NotFoundHttpException]]。
错误处理器会正确地设置响应的HTTP状态码并使用合适的错误视图页面来显示错误信息。 错误处理器会正确地设置响应的HTTP状态码并使用合适的错误视图页面来显示错误信息。
```php ```php
use yii\web\NotFoundHttpException; use yii\web\NotFoundHttpException;
@ -61,8 +61,8 @@ throw new NotFoundHttpException();
## 自定义错误显示 <span id="customizing-error-display"></span> ## 自定义错误显示 <span id="customizing-error-display"></span>
[[yii\web\ErrorHandler|error handler]]错误处理器根据常量 [[yii\web\ErrorHandler|error handler]]错误处理器根据常量`YII_DEBUG`的值来调整错误显示,
`YII_DEBUG`的值来调整错误显示,当`YII_DEBUG` 为 true (表示在调试模式), 当`YII_DEBUG` 为 true (表示在调试模式),
错误处理器会显示异常以及详细的函数调用栈和源代码行数来帮助调试, 错误处理器会显示异常以及详细的函数调用栈和源代码行数来帮助调试,
当`YII_DEBUG` 为 false,只有错误信息会被显示以防止应用的敏感信息泄漏。 当`YII_DEBUG` 为 false,只有错误信息会被显示以防止应用的敏感信息泄漏。
@ -82,7 +82,7 @@ throw new NotFoundHttpException();
### 使用错误动作 <span id="using-error-actions"></span> ### 使用错误动作 <span id="using-error-actions"></span>
使用指定的错误[作](structure-controllers.md) 来自定义错误显示更方便, 使用指定的错误[作](structure-controllers.md) 来自定义错误显示更方便,
为此,首先配置`errorHandler`组件的 [[yii\web\ErrorHandler::errorAction|errorAction]] 属性, 为此,首先配置`errorHandler`组件的 [[yii\web\ErrorHandler::errorAction|errorAction]] 属性,
类似如下: 类似如下:
@ -97,8 +97,8 @@ return [
``` ```
[[yii\web\ErrorHandler::errorAction|errorAction]] 属性使用 [[yii\web\ErrorHandler::errorAction|errorAction]] 属性使用
[路由](structure-controllers.md#routes)到一个作, [路由](structure-controllers.md#routes)到一个作,
上述配置表示不用显示函数调用栈信息的错误会通过执行`site/error`作来显示。 上述配置表示不用显示函数调用栈信息的错误会通过执行`site/error`作来显示。
可以创建 `site/error` 动作如下所示: 可以创建 `site/error` 动作如下所示:
@ -121,7 +121,7 @@ class SiteController extends Controller
} }
``` ```
上述代码定义 `error` 动作使用 [[yii\web\ErrorAction]] 类, 上述代码定义`error` 操作使用[[yii\web\ErrorAction]] 类,
该类渲染名为`error`视图来显示错误。 该类渲染名为`error`视图来显示错误。
除了使用[[yii\web\ErrorAction]], 可定义`error` 动作使用类似如下的操作方法: 除了使用[[yii\web\ErrorAction]], 可定义`error` 动作使用类似如下的操作方法:
@ -141,8 +141,8 @@ public function actionError()
* `name`: 错误名称 * `name`: 错误名称
* `message`: 错误信息 * `message`: 错误信息
* `exception`: 更多详细信息的异常对象,如HTTP 状态码,错误码, * `exception`: 更多详细信息的异常对象,如HTTP 状态码,
错误调用栈等。 错误码,错误调用栈等。
> Info: 如果你使用 [基础应用模板](start-installation.md) 或 [高级应用模板](tutorial-advanced-app.md), > Info: 如果你使用 [基础应用模板](start-installation.md) 或 [高级应用模板](tutorial-advanced-app.md),
错误动作和错误视图已经定义好了。 错误动作和错误视图已经定义好了。
@ -153,14 +153,21 @@ public function actionError()
> return; > return;
> ``` > ```
> Note: If you need to redirect in an error handler, do it the following way:
>
> ```php
> Yii::$app->getResponse()->redirect($url)->send();
> return;
> ```
### 自定义错误格式 <span id="error-format"></span> ### 自定义错误格式 <span id="error-format"></span>
错误处理器根据[响应](runtime-responses.md)设置的格式来显示错误, 错误处理器根据[响应](runtime-responses.md)设置的格式来显示错误,
如果[[yii\web\Response::format|response format]] 响应格式为`html`, 如果[[yii\web\Response::format|response format]] 响应格式为`html`,
会使用错误或异常视图来显示错误信息,如上一小节所述。 会使用错误或异常视图来显示错误信息,如上一小节所述。
对于其他的响应格式,错误处理器会错误信息作为数组赋值给[[yii\web\Response::data]]属性, 对于其他的响应格式,错误处理器会错误信息作为数组赋值
然后转换到对应的格式, 给[[yii\web\Response::data]]属性,然后转换到对应的格式,
例如,如果响应格式为`json`,可以看到如下响应信息: 例如,如果响应格式为`json`,可以看到如下响应信息:
``` ```
@ -178,8 +185,8 @@ Content-Type: application/json; charset=UTF-8
} }
``` ```
可在应用配置中响应`response`组件的`beforeSend` 可在应用配置中响应`response`组件的
事件来自定义错误响应格式。 `beforeSend`事件来自定义错误响应格式。
```php ```php
return [ return [

4
docs/guide-zh-CN/runtime-overview.md

@ -6,8 +6,8 @@
1. 用户提交指向 [入口脚本](structure-entry-scripts.md) `web/index.php` 的请求。 1. 用户提交指向 [入口脚本](structure-entry-scripts.md) `web/index.php` 的请求。
2. 入口脚本会加载 [配置数组](concept-configurations.md) 并创建一个 2. 入口脚本会加载 [配置数组](concept-configurations.md) 并创建一个
[应用](structure-applications.md) 实例用于处理该请求。 [应用](structure-applications.md) 实例用于处理该请求。
3. 应用会通过 [request(请求)](runtime-requests.md) 3. 应用会通过 [request(请求)](runtime-requests.md) 应用组件
应用组件解析被请求的 [路由](runtime-routing.md)。 解析被请求的 [路由](runtime-routing.md)。
4. 应用创建一个 [controller(控制器)](structure-controllers.md) 实例具体处理请求。 4. 应用创建一个 [controller(控制器)](structure-controllers.md) 实例具体处理请求。
5. 控制器会创建一个 [action(动作)](structure-controllers.md) 实例并为该动作执行相关的 Filters(访问过滤器)。 5. 控制器会创建一个 [action(动作)](structure-controllers.md) 实例并为该动作执行相关的 Filters(访问过滤器)。
6. 如果任何一个过滤器验证失败,该动作会被取消。 6. 如果任何一个过滤器验证失败,该动作会被取消。

49
docs/guide-zh-CN/runtime-responses.md

@ -5,7 +5,7 @@
响应对象包含的信息有HTTP状态码,HTTP头和主体内容等, 响应对象包含的信息有HTTP状态码,HTTP头和主体内容等,
网页应用开发的最终目的本质上就是根据不同的请求构建这些响应对象。 网页应用开发的最终目的本质上就是根据不同的请求构建这些响应对象。
在大多情况下主要处理继承自 [[yii\web\Response]] 的 在大多情况下主要处理继承自 [[yii\web\Response]] 的
`response` [应用组件](structure-application-components.md), `response` [应用组件](structure-application-components.md),
尽管如此,Yii也允许你创建你自己的响应对象并发送给终端用户,这方面后续会阐述。 尽管如此,Yii也允许你创建你自己的响应对象并发送给终端用户,这方面后续会阐述。
@ -73,8 +73,8 @@ $headers->set('Pragma', 'no-cache');
$values = $headers->remove('Pragma'); $values = $headers->remove('Pragma');
``` ```
> Info: 头名称是大小写敏感的,在[[yii\web\Response::send()]] > Info: 头名称是大小写敏感的,在[[yii\web\Response::send()]]方法
方法调用前新注册的头信息并不会发送给用户。 调用前新注册的头信息并不会发送给用户。
## 响应主体 <span id="response-body"></span> ## 响应主体 <span id="response-body"></span>
@ -107,8 +107,8 @@ Yii支持以下可直接使用的格式,每个实现了[[yii\web\ResponseForma
* [[yii\web\Response::FORMAT_JSONP|JSONP]]: 通过 [[yii\web\JsonResponseFormatter]]来实现. * [[yii\web\Response::FORMAT_JSONP|JSONP]]: 通过 [[yii\web\JsonResponseFormatter]]来实现.
* [[yii\web\Response::FORMAT_RAW|RAW]]: use this format if you want to send the response directly without applying any formatting. * [[yii\web\Response::FORMAT_RAW|RAW]]: use this format if you want to send the response directly without applying any formatting.
上述响应主体可明确地被设置,但是在大多数情况下是通过 [操作](structure-controllers.md) 方法的返回值隐式地设置, 上述响应主体可明确地被设置,但是在大多数情况下是通过 [操作](structure-controllers.md)
常用场景如下所示: 方法的返回值隐式地设置,常用场景如下所示:
```php ```php
public function actionIndex() public function actionIndex()
@ -117,12 +117,12 @@ public function actionIndex()
} }
``` ```
上述的 `index` 作返回 `index` 视图渲染结果, 上述的 `index` 作返回 `index` 视图渲染结果,
返回值会被 `response` 组件格式化后发送给终端用户。 返回值会被 `response` 组件格式化后发送给终端用户。
因为响应格式默认为[[yii\web\Response::FORMAT_HTML|HTML]], 因为响应格式默认为[[yii\web\Response::FORMAT_HTML|HTML]], 只需要在操作方法中返回一个字符串,
只需要在动作方法中返回一个字符串 如果想使用其他响应格式,应在返回数据前先设置格式
如果想使用其他响应格式,应在返回数据前先设置格式,例如: 例如:
```php ```php
public function actionInfo() public function actionInfo()
@ -136,7 +136,7 @@ public function actionInfo()
``` ```
如上所述,触雷使用默认的 `response` 应用组件,也可创建自己的响应对象并发送给终端用户, 如上所述,触雷使用默认的 `response` 应用组件,也可创建自己的响应对象并发送给终端用户,
可在作方法中返回该响应对象,如下所示: 可在作方法中返回该响应对象,如下所示:
```php ```php
public function actionInfo() public function actionInfo()
@ -159,12 +159,12 @@ public function actionInfo()
## 浏览器跳转 <span id="browser-redirection"></span> ## 浏览器跳转 <span id="browser-redirection"></span>
浏览器跳转依赖于发送一个`Location` HTTP 头, 浏览器跳转依赖于发送一个`Location` HTTP 头,因为该功能通常被使用,
因为该功能通常被使用,Yii提供对它提供了特别的支持。 Yii提供对它提供了特别的支持。
可调用[[yii\web\Response::redirect()]] 方法将用户浏览器跳转到一个URL地址,该方法设置合适的 可调用[[yii\web\Response::redirect()]] 方法将用户浏览器跳转到一个URL地址,该方法设置合适的
带指定URL的 `Location` 头并返回它自己为响应对象, 带指定URL的 `Location` 头并返回它自己为响应对象,在操作的方法中,
在动作的方法中,可调用缩写版[[yii\web\Controller::redirect()]],例如: 可调用缩写版[[yii\web\Controller::redirect()]],例如:
```php ```php
public function actionOld() public function actionOld()
@ -173,8 +173,8 @@ public function actionOld()
} }
``` ```
在如上代码中,作的方法返回`redirect()` 方法的结果,如前所述, 在如上代码中,作的方法返回`redirect()` 方法的结果,如前所述,
作的方法返回的响应对象会被当总响应发送给终端用户。 作的方法返回的响应对象会被当总响应发送给终端用户。
除了动作方法外,可直接调用[[yii\web\Response::redirect()]] 再调用 除了动作方法外,可直接调用[[yii\web\Response::redirect()]] 再调用
[[yii\web\Response::send()]] 方法来确保没有其他内容追加到响应中。 [[yii\web\Response::send()]] 方法来确保没有其他内容追加到响应中。
@ -184,19 +184,20 @@ public function actionOld()
``` ```
> Info: [[yii\web\Response::redirect()]] 方法默认会设置响应状态码为302,该状态码会告诉浏览器请求的资源 > Info: [[yii\web\Response::redirect()]] 方法默认会设置响应状态码为302,该状态码会告诉浏览器请求的资源
*临时* 放在另一个URI地址上, *临时* 放在另一个URI地址上,可传递一个301状态码告知浏览器请求
可传递一个301状态码告知浏览器请求的资源已经 *永久* 重定向到新的URId地址。 的资源已经 *永久* 重定向到新的URId地址。
如果当前请求为AJAX 请求, 如果当前请求为AJAX 请求,
发送一个 `Location` 头不会自动使浏览器跳转,为解决这个问题, 发送一个 `Location` 头不会自动使浏览器跳转,为解决这个问题,
[[yii\web\Response::redirect()]] 方法设置一个值为要跳转的URL的`X-Redirect` 头, [[yii\web\Response::redirect()]] 方法设置一个值为要跳转的URL的`X-Redirect` 头,
在客户端可编写JavaScript 代码读取该头部值然后让浏览器跳转对应的URL。 在客户端可编写JavaScript
代码读取该头部值然后让浏览器跳转对应的URL。
> Info: Yii 配备了一个`yii.js` JavaScript 文件提供常用JavaScript功能,包括基于`X-Redirect`头的浏览器跳转, > Info: Yii 配备了一个`yii.js` JavaScript 文件提供常用JavaScript功能,
包括基于`X-Redirect`头的浏览器跳转,
因此,如果你使用该JavaScript 文件(通过[[yii\web\YiiAsset]] 资源包注册), 因此,如果你使用该JavaScript 文件(通过[[yii\web\YiiAsset]] 资源包注册),
就不需要编写AJAX跳转的代码。 就不需要编写AJAX跳转的代码。
## 发送文件 <span id="sending-files"></span> ## 发送文件 <span id="sending-files"></span>
和浏览器跳转类似,文件发送是另一个依赖指定HTTP头的功能, 和浏览器跳转类似,文件发送是另一个依赖指定HTTP头的功能,
@ -208,7 +209,7 @@ Yii提供方法集合来支持各种文件发送需求,它们对HTTP头都有
这些方法都将响应对象作为返回值,如果要发送的文件非常大,应考虑使用 这些方法都将响应对象作为返回值,如果要发送的文件非常大,应考虑使用
[[yii\web\Response::sendStreamAsFile()]] 因为它更节约内存, [[yii\web\Response::sendStreamAsFile()]] 因为它更节约内存,
以下示例显示在控制器作中如何发送文件: 以下示例显示在控制器作中如何发送文件:
```php ```php
public function actionDownload() public function actionDownload()
@ -217,8 +218,8 @@ public function actionDownload()
} }
``` ```
如果不是在动作方法中调用文件发送方法, 如果不是在操作方法中调用文件发送方法,在后面还应调用
在后面还应调用 [[yii\web\Response::send()]] 没有其他内容追加到响应中。 [[yii\web\Response::send()]] 没有其他内容追加到响应中。
```php ```php
\Yii::$app->response->sendFile('path/to/file.txt')->send(); \Yii::$app->response->sendFile('path/to/file.txt')->send();

47
docs/guide-zh-CN/runtime-sessions-cookies.md

@ -69,7 +69,7 @@ foreach ($session as $name => $value) ...
foreach ($_SESSION as $name => $value) ... foreach ($_SESSION as $name => $value) ...
``` ```
> 注意: 当使用`session`组件访问session数据时候, > Info: 当使用`session`组件访问session数据时候,
如果session没有开启会自动开启, 如果session没有开启会自动开启,
这和通过`$_SESSION`不同,`$_SESSION`要求先执行`session_start()`。 这和通过`$_SESSION`不同,`$_SESSION`要求先执行`session_start()`。
@ -137,7 +137,7 @@ Yii提供以下session类实现不同的session存储方式:
所有这些session类支持相同的API方法集,因此, 所有这些session类支持相同的API方法集,因此,
切换到不同的session存储介质不需要修改项目使用session的代码。 切换到不同的session存储介质不需要修改项目使用session的代码。
> 注意: 如果通过`$_SESSION`访问使用自定义存储介质的session, > Note: 如果通过`$_SESSION`访问使用自定义存储介质的session,
需要确保session已经用[[yii\web\Session::open()]] 开启, 需要确保session已经用[[yii\web\Session::open()]] 开启,
这是因为在该方法中注册自定义session存储处理器。 这是因为在该方法中注册自定义session存储处理器。
@ -174,10 +174,35 @@ CREATE TABLE session
- PostgreSQL: BYTEA - PostgreSQL: BYTEA
- MSSQL: BLOB - MSSQL: BLOB
> 注意: 根据php.ini 设置的 `session.hash_function`,你需要调整`id`列的长度, > Note: 根据 php.ini 设置的 `session.hash_function`,你需要调整`id`列的长度,
例如,如果 `session.hash_function=sha256` 例如,如果 `session.hash_function=sha256`
应使用长度为64而不是40的char类型。 应使用长度为64而不是40的char类型。
Alternatively, this can be accomplished with the following migration:
```php
<?php
use yii\db\Migration;
class m170529_050554_create_table_session extends Migration
{
public function up()
{
$this->createTable('{{%session}}', [
'id' => $this->char(64)->notNull(),
'expire' => $this->integer(),
'data' => $this->binary()
]);
$this->addPrimaryKey('pk-id', '{{%session}}', 'id');
}
public function down()
{
$this->dropTable('{{%session}}');
}
}
```
### Flash 数据 <span id="flash-data"></span> ### Flash 数据 <span id="flash-data"></span>
@ -242,9 +267,9 @@ $alerts = $session->getFlash('alerts');
## Cookies <span id="cookies"></span> ## Cookies <span id="cookies"></span>
Yii使用 [[yii\web\Cookie]]对象来代表每个cookie,[[yii\web\Request]] 和 [[yii\web\Response]] Yii使用 [[yii\web\Cookie]]对象来代表每个cookie,
通过名为'cookies'的属性维护一个cookie集合, [[yii\web\Request]] 和 [[yii\web\Response]]
前者的cookie 集合代表请求提交的cookies, 通过名为'cookies'的属性维护一个cookie集合,前者的cookie 集合代表请求提交的cookies,
后者的cookie集合表示发送给用户的cookies。 后者的cookie集合表示发送给用户的cookies。
The part of the application dealing with request and response directly is controller. Therefore, cookies should be The part of the application dealing with request and response directly is controller. Therefore, cookies should be
@ -302,7 +327,7 @@ unset($cookies['language']);
[[yii\web\Cookie::domain|domain]], [[yii\web\Cookie::expire|expire]] [[yii\web\Cookie::domain|domain]], [[yii\web\Cookie::expire|expire]]
可配置这些属性到cookie中并添加到响应的cookie集合中。 可配置这些属性到cookie中并添加到响应的cookie集合中。
> 注意: 为安全起见[[yii\web\Cookie::httpOnly]] 被设置为true, > Note: 为安全起见[[yii\web\Cookie::httpOnly]] 被设置为true,
这可减少客户端脚本访问受保护cookie(如果浏览器支持)的风险, 这可减少客户端脚本访问受保护cookie(如果浏览器支持)的风险,
更多详情可阅读 [httpOnly wiki article](https://www.owasp.org/index.php/HttpOnly) for more details. 更多详情可阅读 [httpOnly wiki article](https://www.owasp.org/index.php/HttpOnly) for more details.
@ -311,11 +336,11 @@ unset($cookies['language']);
在上两节中,当通过`request` 和 `response` 组件读取和发送cookie时, 在上两节中,当通过`request` 和 `response` 组件读取和发送cookie时,
你会喜欢扩展的cookie验证的保障安全功能,它能 你会喜欢扩展的cookie验证的保障安全功能,它能
使cookie不被客户端修改。该功能通过给每个cookie签发一个 使cookie不被客户端修改。该功能通过给每个cookie签发一个哈希字符串来告知服务端cookie是否在客户端被修改,
哈希字符串来告知服务端cookie是否在客户端被修改, 如果被修改,通过`request`组件的
如果被修改,通过`request`组件的[[yii\web\Request::cookies|cookie collection]]cookie集合访问不到该cookie。 [[yii\web\Request::cookies|cookie collection]]cookie集合访问不到该cookie。
> 注意: Cookie验证只保护cookie值被修改,如果一个cookie验证失败, > Note: Cookie验证只保护cookie值被修改,如果一个cookie验证失败,
仍然可以通过`$_COOKIE`来访问该cookie, 仍然可以通过`$_COOKIE`来访问该cookie,
因为这是第三方库对未通过cookie验证自定义的操作方式。 因为这是第三方库对未通过cookie验证自定义的操作方式。

52
docs/guide-zh-CN/start-databases.md

@ -1,10 +1,10 @@
使用数据库 使用数据库
====================== ======================
本章节将介绍如何创建一个从数据表 `country` 中读取国家数据并显示出来的页面。 本章节将介绍如何如何创建一个从数据表 `country` 中读取国家数据并显示出来的页面。
为了实现这个目标,你将会配置一个数据库连接,创建一个[活动记录](db-active-record.md)类, 为了实现这个目标,你将会配置一个数据库连接,
并且创建一个[动作](structure-controllers.md)及一个[视图](structure-views.md)。 创建一个[活动记录](db-active-record.md)类,
并且创建一个[操作](structure-controllers.md)及一个[视图](structure-views.md)。
贯穿整个章节,你将会学到: 贯穿整个章节,你将会学到:
@ -20,8 +20,8 @@
准备数据库 <span id="preparing-database"></span> 准备数据库 <span id="preparing-database"></span>
-------------------- --------------------
首先创建一个名为 `yii2basic` 的数据库,应用将从这个数据库中读取数据。你可以创建 SQLite,MySQL,PostregSQL,MSSQL 或 Oracle 数据库, 首先创建一个名为 `yii2basic` 的数据库,应用将从这个数据库中读取数据。
Yii 内置多种数据库支持。简单起见,后面的内容将以 MySQL 为例做演示。 你可以创建 SQLite,MySQL,PostregSQL,MSSQL 或 Oracle 数据库,Yii 内置多种数据库支持。简单起见,后面的内容将以 MySQL 为例做演示。
然后在数据库中创建一个名为 `country` 的表并插入简单的数据。可以执行下面的语句: 然后在数据库中创建一个名为 `country` 的表并插入简单的数据。可以执行下面的语句:
@ -51,7 +51,7 @@ INSERT INTO `country` VALUES ('US','United States',278357000);
开始之前,请确保你已经安装了 PHP [PDO](http://www.php.net/manual/en/book.pdo.php) 开始之前,请确保你已经安装了 PHP [PDO](http://www.php.net/manual/en/book.pdo.php)
扩展和你所使用的数据库的 PDO 驱动(例如 MySQL 的 `pdo_mysql`)。 扩展和你所使用的数据库的 PDO 驱动(例如 MySQL 的 `pdo_mysql`)。
假如你的程序是使用关系型数据库,这是基本要求。 对于使用关系型数据库来讲,这是基本要求。
驱动和扩展安装可用后,打开 `config/db.php` 修改里面的配置参数对应你的数据库配置。 驱动和扩展安装可用后,打开 `config/db.php` 修改里面的配置参数对应你的数据库配置。
该文件默认包含这些内容: 该文件默认包含这些内容:
@ -74,11 +74,11 @@ return [
上面配置的数据库连接可以在应用中通过 `Yii::$app->db` 表达式访问。 上面配置的数据库连接可以在应用中通过 `Yii::$app->db` 表达式访问。
> 补充:`config/db.php` 将被包含在应用配置文件 `config/web.php` 中, > Info: `config/db.php` 将被包含在应用配置文件 `config/web.php` 中,
后者指定了整个[应用](structure-applications.md)如何初始化。 后者指定了整个[应用](structure-applications.md)如何初始化。
请参考[配置](concept-configurations.md)章节了解更多信息。 请参考[配置](concept-configurations.md)章节了解更多信息。
如果你需要的不是Yii附带的数据库驱动,查阅以下的驱动: If you need to work with databases support for which isn't bundled with Yii, check the following extensions:
- [Informix](https://github.com/edgardmessias/yii2-informix) - [Informix](https://github.com/edgardmessias/yii2-informix)
- [IBM DB2](https://github.com/edgardmessias/yii2-ibm-db2) - [IBM DB2](https://github.com/edgardmessias/yii2-ibm-db2)
@ -106,8 +106,8 @@ class Country extends ActiveRecord
这个 `Country` 类继承自 [[yii\db\ActiveRecord]]。你不用在里面写任何代码。 这个 `Country` 类继承自 [[yii\db\ActiveRecord]]。你不用在里面写任何代码。
只需要像现在这样,Yii 就能根据类名去猜测对应的数据表名。 只需要像现在这样,Yii 就能根据类名去猜测对应的数据表名。
> 注意:如果类名和数据表名不能直接对应,可以覆写 [[yii\db\ActiveRecord::tableName()|tableName()]] > Info: 如果类名和数据表名不能直接对应,
方法去显式指定相关表名。 可以覆写 [[yii\db\ActiveRecord::tableName()|tableName()]] 方法去显式指定相关表名。
使用 `Country` 类可以很容易地操作 `country` 表数据,就像这段代码: 使用 `Country` 类可以很容易地操作 `country` 表数据,就像这段代码:
@ -128,17 +128,17 @@ $country->name = 'U.S.A.';
$country->save(); $country->save();
``` ```
> 补充:活动记录是面向对象、功能强大的访问和操作数据库数据的方式。你可以在[活动记录](db-active-record.md)章节了解更多信息。 > Info: 活动记录是面向对象、功能强大的访问和操作数据库数据的方式。你可以在[活动记录](db-active-record.md)章节了解更多信息。
除此之外你还可以使用另一种更原生的被称做[数据访问对象](db-dao)的方法操作数据库数据。 除此之外你还可以使用另一种更原生的被称做[数据访问对象](db-dao)的方法操作数据库数据。
创建动作 <span id="creating-action"></span> 创建动作 <span id="creating-action"></span>
------------------ ------------------
为了向最终用户显示国家数据,你需要创建一个动作。 为了向最终用户显示国家数据,你需要创建一个操作。相比之前小节掌握的在 `site` 控制器中创建操作,
相比之前小节掌握的在 `site` 控制器中创建动作,
在这里为所有和国家有关的数据新建一个控制器更加合理。 在这里为所有和国家有关的数据新建一个控制器更加合理。
新控制器名为 `CountryController`,并在其中创建一个 `index` 动作,如下: 新控制器名为 `CountryController`,并在其中创建一个 `index` 操作,
如下:
```php ```php
<?php <?php
@ -175,7 +175,7 @@ class CountryController extends Controller
把上面的代码保存在 `controllers/CountryController.php` 文件中。 把上面的代码保存在 `controllers/CountryController.php` 文件中。
`index` 作调用了活动记录 `Country::find()` 方法,去生成查询语句并从 `country` 表中取回所有数据。 `index` 作调用了活动记录 `Country::find()` 方法,去生成查询语句并从 `country` 表中取回所有数据。
为了限定每个请求所返回的国家数量,查询在 [[yii\data\Pagination]] 对象的帮助下进行分页。 为了限定每个请求所返回的国家数量,查询在 [[yii\data\Pagination]] 对象的帮助下进行分页。
`Pagination` 对象的使命主要有两点: `Pagination` 对象的使命主要有两点:
@ -184,16 +184,16 @@ class CountryController extends Controller
* 在视图中显示一个由页码列表组成的分页器, * 在视图中显示一个由页码列表组成的分页器,
这点将在后面的段落中解释。 这点将在后面的段落中解释。
在代码末尾,`index` 作渲染一个名为 `index` 的视图, 在代码末尾,`index` 作渲染一个名为 `index` 的视图,
并传递国家数据和分页信息进去。 并传递国家数据和分页信息进去。
创建视图 <span id="creating-view"></span> 创建视图 <span id="creating-view"></span>
--------------- ---------------
`views` 目录下先创建一个名为 `country` 的子目录。这个目录存储所有由 `country` 控制器渲染的视图。 `views` 目录下先创建一个名为 `country` 的子目录。
`views/country` 目录下创建一个名为 `index.php` 的视图文件, 这个目录存储所有由 `country` 控制器渲染的视图。在 `views/country` 目录下
内容如下: 创建一个名为 `index.php` 的视图文件,内容如下:
```php ```php
<?php <?php
@ -214,7 +214,7 @@ use yii\widgets\LinkPager;
``` ```
这个视图包含两部分用以显示国家数据。第一部分遍历国家数据并以无序 HTML 列表渲染出来。 这个视图包含两部分用以显示国家数据。第一部分遍历国家数据并以无序 HTML 列表渲染出来。
第二部分使用 [[yii\widgets\LinkPager]] 去渲染从作中传来的分页信息。 第二部分使用 [[yii\widgets\LinkPager]] 去渲染从作中传来的分页信息。
小部件 `LinkPager` 显示一个分页按钮的列表。 小部件 `LinkPager` 显示一个分页按钮的列表。
点击任何一个按钮都会跳转到对应的分页。 点击任何一个按钮都会跳转到对应的分页。
@ -230,8 +230,8 @@ http://hostname/index.php?r=country/index
![国家列表](images/start-country-list.png) ![国家列表](images/start-country-list.png)
首先你会看到显示着五个国家的列表页面。在国家下面, 首先你会看到显示着五个国家的列表页面。在国家下面,你还会看到一个包含四个按钮的分页器。
你还会看到一个包含四个按钮的分页器。如果你点击按钮 “2”,将会跳转到显示另外五个国家的页面, 如果你点击按钮 “2”,将会跳转到显示另外五个国家的页面,
也就是第二页记录。如果观察仔细点你还会看到浏览器的 URL 变成了: 也就是第二页记录。如果观察仔细点你还会看到浏览器的 URL 变成了:
``` ```
@ -246,9 +246,9 @@ http://hostname/index.php?r=country/index&page=2
[[yii\data\Pagination::createUrl()|Pagination::createUrl()]] 方法生成的 URL 去渲染翻页按钮。 [[yii\data\Pagination::createUrl()|Pagination::createUrl()]] 方法生成的 URL 去渲染翻页按钮。
URL 中包含必要的参数 `page` 才能查询不同的页面编号。 URL 中包含必要的参数 `page` 才能查询不同的页面编号。
* 如果你点击按钮 “2”,将会发起一个路由为 `country/index` 的新请求。 * 如果你点击按钮 “2”,将会发起一个路由为 `country/index` 的新请求。
[[yii\data\Pagination|Pagination]] 接收到 URL 中`page` 参数把当前的页码设为 2。 [[yii\data\Pagination|Pagination]] 接收到 URL 中
新的数据库请求将会以 `LIMIT 5 OFFSET 5` `page` 参数把当前的页码设为 2。
查询并显示。 新的数据库请求将会以 `LIMIT 5 OFFSET 5` 查询并显示。
总结 <span id="summary"></span> 总结 <span id="summary"></span>

70
docs/guide-zh-CN/start-forms.md

@ -5,7 +5,7 @@
该页将显示一个包含 name 输入框和 email 输入框的表单。 该页将显示一个包含 name 输入框和 email 输入框的表单。
当提交这两部分信息后,页面将会显示用户所输入的信息。 当提交这两部分信息后,页面将会显示用户所输入的信息。
为了实现这个目标,除了创建一个[作](structure-controllers.md)和两个[视图](structure-views)外, 为了实现这个目标,除了创建一个[作](structure-controllers.md)和两个[视图](structure-views)外,
还需要创建一个[模型](structure-models.md)。 还需要创建一个[模型](structure-models.md)。
通过本教程,你将会学到: 通过本教程,你将会学到:
@ -48,7 +48,7 @@ class EntryForm extends Model
该类继承自Yii 提供的一个基类 [[yii\base\Model]], 该类继承自Yii 提供的一个基类 [[yii\base\Model]],
该基类通常用来表示数据。 该基类通常用来表示数据。
> 补充:[[yii\base\Model]] 被用于普通模型类的父类并与数据表**无关**。[[yii\db\ActiveRecord]] > Info: [[yii\base\Model]] 被用于普通模型类的父类并与数据表**无关**。[[yii\db\ActiveRecord]]
通常是普通模型类的父类但与数据表有关联(译注:[[yii\db\ActiveRecord]] 类其实也是继承自 [[yii\base\Model]],增加了数据库处理)。 通常是普通模型类的父类但与数据表有关联(译注:[[yii\db\ActiveRecord]] 类其实也是继承自 [[yii\base\Model]],增加了数据库处理)。
`EntryForm` 类包含 `name``email` 两个公共成员, `EntryForm` 类包含 `name``email` 两个公共成员,
@ -59,8 +59,8 @@ class EntryForm extends Model
* `email` 的值必须满足email规则验证 * `email` 的值必须满足email规则验证
如果你有一个处理用户提交数据的 `EntryForm` 对象, 如果你有一个处理用户提交数据的 `EntryForm` 对象,
你可以调用它的 [[yii\base\Model::validate()|validate()]] 方法触发数据验证。如果有数据验证失败, 你可以调用它的 [[yii\base\Model::validate()|validate()]] 方法触发数据验证。
将把 [[yii\base\Model::hasErrors|hasErrors]] 属性设为 ture, 如果有数据验证失败,将把 [[yii\base\Model::hasErrors|hasErrors]] 属性设为 ture,
想要知道具体发生什么错误就调用 [[yii\base\Model::getErrors|getErrors]]。 想要知道具体发生什么错误就调用 [[yii\base\Model::getErrors|getErrors]]。
```php ```php
@ -80,8 +80,8 @@ if ($model->validate()) {
创建动作 <span id="creating-action"></span> 创建动作 <span id="creating-action"></span>
------------------ ------------------
下面你得在 `site` 控制器中创建一个 `entry` 作用于新建的模型。 下面你得在 `site` 控制器中创建一个 `entry` 作用于新建的模型。
作的创建和使用已经在[说一声你好](start-hello.md)小节中解释了。 作的创建和使用已经在[说一声你好](start-hello.md)小节中解释了。
```php ```php
<?php <?php
@ -114,30 +114,30 @@ class SiteController extends Controller
} }
``` ```
该动作首先创建了一个 `EntryForm` 对象。然后尝试从 `$_POST` 搜集用户提交的数据, 该操作首先创建了一个 `EntryForm` 对象。然后尝试从 `$_POST` 搜集用户提交的数据,
由 Yii 的 [[yii\web\Request::post()]] 方法负责搜集。如果模型被成功填充数据(比如:如果用户已经提交了 HTML 表单), 由 Yii 的 [[yii\web\Request::post()]] 方法负责搜集。
动作将调用 [[yii\base\Model::validate()|validate()]] 去确保用户提交的是有效数据。 如果模型被成功填充数据(也就是说用户已经提交了 HTML 表单),
操作将调用 [[yii\base\Model::validate()|validate()]] 去确保用户提交的是有效数据。
> Info: 表达式 `Yii::$app` 代表[应用](structure-applications.md)实例,它是一个全局可访问的单例。
> 补充:表达式 `Yii::$app` 代表[应用](structure-applications.md)实例, 同时它也是一个[服务定位器](concept-service-locator.md),
它是一个全局可访问的单例。同时它也是一个[服务定位器](concept-service-locator.md),
能提供 `request`,`response`,`db` 等等特定功能的组件。 能提供 `request`,`response`,`db` 等等特定功能的组件。
在上面的代码里就是使用 `request` 组件来访问应用实例收到的 `$_POST` 数据。 在上面的代码里就是使用 `request` 组件来访问应用实例收到的 `$_POST` 数据。
如果一切都准备好了,用户提交表单后,动作将会渲染一个名为 `entry-confirm` 的视图去确认用户输入的数据。 用户提交表单后,操作将会渲染一个名为 `entry-confirm` 的视图去确认用户输入的数据。
如果没填表单就提交,或数据包含错误(译者:如 email 格式不对),`entry` 视图将会渲染输出, 如果没填表单就提交,或数据包含错误(译者:如 email 格式不对),
连同表单一起输出的还有验证错误的详细信息。 `entry` 视图将会渲染输出,连同表单一起输出的还有验证错误的详细信息。
> 注意:在这个简单例子里我们只是呈现了有效数据的确认页面。 > Note: 在这个简单例子里我们只是呈现了有效数据的确认页面。
实践中你应该考虑使用 [[yii\web\Controller::refresh()|refresh()]] 或 [[yii\web\Controller::redirect()|redirect()]] 实践中你应该考虑使用 [[yii\web\Controller::refresh()|refresh()]]
去避免[表单重复提交问题](http://en.wikipedia.org/wiki/Post/Redirect/Get)。 或 [[yii\web\Controller::redirect()|redirect()]] 去避免[表单重复提交问题](http://en.wikipedia.org/wiki/Post/Redirect/Get)。
创建视图 <span id="creating-views"></span> 创建视图 <span id="creating-views"></span>
-------------- --------------
最后创建两个视图文件 `entry-confirm``entry` 最后创建两个视图文件 `entry-confirm``entry`
他们会被刚才创建的 `entry` 作渲染。 他们会被刚才创建的 `entry` 作渲染。
`entry-confirm` 视图简单地显示提交的 name 和 email 数据。视图文件应该保存在 `views/site/entry-confirm.php` `entry-confirm` 视图简单地显示提交的 name 和 email 数据。视图文件应该保存在 `views/site/entry-confirm.php`
@ -173,12 +173,12 @@ use yii\widgets\ActiveForm;
<?php ActiveForm::end(); ?> <?php ActiveForm::end(); ?>
``` ```
视图使用了一个功能强大的[小部件](structure-widgets.md) [[yii\widgets\ActiveForm|ActiveForm]] 去生成 HTML 表单。 视图使用了一个功能强大的[小部件](structure-widgets.md) [[yii\widgets\ActiveForm|ActiveForm]]
去生成 HTML 表单。
其中的 `begin()``end()` 分别用来渲染表单的开始和关闭标签。 其中的 `begin()``end()` 分别用来渲染表单的开始和关闭标签。
在这两个方法之间使用了 [[yii\widgets\ActiveForm::field()|field()]] 方法去创建输入框。 在这两个方法之间使用了 [[yii\widgets\ActiveForm::field()|field()]] 方法去创建输入框。
第一个输入框用于 “name”,第二个输入框用于 “email”。 第一个输入框用于 “name”,第二个输入框用于 “email”。
之后使用 [[yii\helpers\Html::submitButton()]] 之后使用 [[yii\helpers\Html::submitButton()]] 方法生成提交按钮。
方法生成提交按钮。
尝试下 <span id="trying-it-out"></span> 尝试下 <span id="trying-it-out"></span>
@ -196,7 +196,7 @@ http://hostname/index.php?r=site/entry
![验证错误的表单](images/start-form-validation.png) ![验证错误的表单](images/start-form-validation.png)
输入有效的 name 和 email 信息并提交后, 输入有效的 name 和 email 信息并提交后,
你将会看到一个显示你所提交数据的新页面。 将会看到一个显示你所提交数据的确认页面。
![输入数据的确认页](images/start-entry-confirmation.png) ![输入数据的确认页](images/start-entry-confirmation.png)
@ -204,31 +204,31 @@ http://hostname/index.php?r=site/entry
### 效果说明 <span id="magic-explained"></span> ### 效果说明 <span id="magic-explained"></span>
你可能会好奇 HTML 表单暗地里是如何工作的呢,看起来它可以为每个输入框显示文字标签, 你可能会好奇 HTML 表单暗地里是如何工作的呢,
而当你没输入正确的信息时又不需要刷新页面就能给出错误提示 看起来它可以为每个输入框显示文字标签
似乎有些神奇。 而当你没输入正确的信息时又不需要刷新页面就能给出错误提示,似乎有些神奇。
是的,其实数据首先由客户端 JavaScript 脚本验证,然后才会提交给服务器通过 PHP 验证。 是的,其实数据首先由客户端 JavaScript 脚本验证,然后才会提交给服务器通过 PHP 验证。
[[yii\widgets\ActiveForm]] 足够智能到把你在 `EntryForm` 模型中声明的验证规则转化成客户端 JavaScript 脚本去执行验证。 [[yii\widgets\ActiveForm]] 足够智能到把你在 `EntryForm`
模型中声明的验证规则转化成客户端 JavaScript 脚本去执行验证。
如果用户浏览器禁用了 JavaScript, 如果用户浏览器禁用了 JavaScript,
服务器端仍然会像 `actionEntry()` 方法里这样验证一遍数据。 服务器端仍然会像 `actionEntry()` 方法里这样验证一遍数据。这保证了任何情况下用户提交的数据都是有效的。
这保证了任何情况下用户提交的数据都是有效的。
> 警告:客户端验证是提高用户体验的手段。无论它是否正常启用, > Warning: 客户端验证是提高用户体验的手段。
服务端验证则都是必须的,请不要忽略它。 无论它是否正常启用,服务端验证则都是必须的,请不要忽略它。
输入框的文字标签是 `field()` 方法生成的,内容就是模型中该数据的属性名。 输入框的文字标签是 `field()` 方法生成的,内容就是模型中该数据的属性名。
例如模型中的 `name` 属性生成的标签就是 `Name` 例如模型中的 `name` 属性生成的标签就是 `Name`
你可以按如下方式 你可以在视图中自定义标签
在视图中自定义标签 按如下方法
```php ```php
<?= $form->field($model, 'name')->label('自定义 Name') ?> <?= $form->field($model, 'name')->label('自定义 Name') ?>
<?= $form->field($model, 'email')->label('自定义 Email') ?> <?= $form->field($model, 'email')->label('自定义 Email') ?>
``` ```
> 补充:Yii 提供了相当多类似的小部件去帮你生成复杂且动态的视图。 > Info: Yii 提供了相当多类似的小部件去帮你生成复杂且动态的视图。
在后面你还会了解到自己写小部件是多么简单。 在后面你还会了解到自己写小部件是多么简单。
你可能会把自己的很多视图代码转化成小部件以提高重用,加快开发效率。 你可能会把自己的很多视图代码转化成小部件以提高重用,加快开发效率。
@ -237,7 +237,7 @@ http://hostname/index.php?r=site/entry
------- -------
本章节指南中你接触了 MVC 设计模式的每个部分。 本章节指南中你接触了 MVC 设计模式的每个部分。
你已经学到了如何创建一个模型代表用户数据并验证它的有效性。 学到了如何创建一个模型代表用户数据并验证它的有效性。
你还学到了如何从用户那获取数据并在浏览器上回显给用户。 你还学到了如何从用户那获取数据并在浏览器上回显给用户。
这本来是开发应用的过程中比较耗时的任务, 这本来是开发应用的过程中比较耗时的任务,

18
docs/guide-zh-CN/start-gii.md

@ -15,8 +15,8 @@
开始 Gii <span id="starting-gii"></span> 开始 Gii <span id="starting-gii"></span>
------------ ------------
[Gii](tool-gii.md) 是 Yii 中的一个[模块](structure-modules.md)。可以通过配置应用的 [[yii\base\Application::modules|modules]] 属性开启它。 [Gii](tool-gii.md) 是 Yii 中的一个[模块](structure-modules.md)。
通常来讲在 `config/web.php` 文件中会有以下配置代码: 可以通过配置应用的 [[yii\base\Application::modules|modules]] 属性开启它。通常来讲在 `config/web.php` 文件中会有以下配置代码:
```php ```php
$config = [ ... ]; $config = [ ... ];
@ -45,7 +45,7 @@ defined('YII_ENV') or define('YII_ENV', 'dev');
http://hostname/index.php?r=gii http://hostname/index.php?r=gii
``` ```
> 补充: 如果你通过本机以外的机器访问 Gii,请求会被出于安全原因拒绝。 > Info: 如果你通过本机以外的机器访问 Gii,请求会被出于安全原因拒绝。
> 你可以配置 Gii 为其添加允许访问的 IP 地址: > 你可以配置 Gii 为其添加允许访问的 IP 地址:
> >
```php ```php
@ -70,9 +70,9 @@ http://hostname/index.php?r=gii
然后点击 “Preview” 按钮。你会看到 `models/Country.php` 被列在将要生成的文件列表中。可以点击文件名预览内容。 然后点击 “Preview” 按钮。你会看到 `models/Country.php` 被列在将要生成的文件列表中。可以点击文件名预览内容。
如果你已经创建过同样的文件, 如果你已经创建过同样的文件,使用 Gii 会覆写它,
使用 Gii 会覆写它, 点击文件名旁边的 `diff` 能查看现有文件与将要
点击文件名旁边的 `diff` 能查看现有文件与将要生成的文件的内容区别。 生成的文件的内容区别。
![模型生成器预览](images/start-gii-model-preview.png) ![模型生成器预览](images/start-gii-model-preview.png)
@ -110,8 +110,8 @@ CRUD 代表增,查,改,删操作,这是绝大多数 Web 站点常用的
http://hostname/index.php?r=country/index http://hostname/index.php?r=country/index
``` ```
可以看到一个栅格显示着从数据表中读取的国家数据。 可以看到一个栅格显示着从数据表中读取的国家数据。支持在列头对数据进行排序,
支持在列头对数据进行排序,输入筛选条件进行筛选。 输入筛选条件进行筛选。
可以浏览详情,编辑,或删除栅格中的每个国家。 可以浏览详情,编辑,或删除栅格中的每个国家。
还可以点击栅格上方的 “Create Country” 按钮通过表单创建新国家。 还可以点击栅格上方的 “Create Country” 按钮通过表单创建新国家。
@ -127,7 +127,7 @@ http://hostname/index.php?r=country/index
* 模型:`models/Country.php` 和 `models/CountrySearch.php` * 模型:`models/Country.php` 和 `models/CountrySearch.php`
* 视图:`views/country/*.php` * 视图:`views/country/*.php`
> 注意:Gii 被设计成高度可定制和可扩展的代码生成工具。 > Info: Gii 被设计成高度可定制和可扩展的代码生成工具。
使用它可以大幅提高应用开发速度。 使用它可以大幅提高应用开发速度。
请参考 [Gii](tool-gii.md) 章节了解更多内容。 请参考 [Gii](tool-gii.md) 章节了解更多内容。

92
docs/guide-zh-CN/start-hello.md

@ -1,9 +1,9 @@
说声 Hello 说声 Hello
============ ============
本章描述了如何在你的应用中创建一个新的 “Hello” 页面。 本章描述了如何在你的应用中创建一个新的 “Hello” 页面。为了实现这一目标,
为了实现这一目标, 将会创建一个[操作](structure-controllers.md#creating-actions)
将会创建一个[动作](structure-controllers.md#creating-actions)和一个[视图](structure-views.md): 和一个[视图](structure-views.md):
* 应用将会分派页面请求给动作 * 应用将会分派页面请求给动作
* 动作将会依次渲染视图呈现 “Hello” 给最终用户 * 动作将会依次渲染视图呈现 “Hello” 给最终用户
@ -18,17 +18,17 @@
创建动作 <span id="creating-action"></span> 创建动作 <span id="creating-action"></span>
------------------ ------------------
对于“Hello”任务,需要创建一个 `say` [](structure-controllers.md#creating-actions), 为了 “Hello”,需要创建一个 `say` [](structure-controllers.md#creating-actions),
从请求中接收 `message` 参数并显示给最终用户。如果请求没有提供 `message` 参数, 从请求中接收 `message` 参数并显示给最终用户。
作将显示默认参数 “Hello”。 如果请求没有提供 `message` 参数,操作将显示默认参数 “Hello”。
> 注意:[动作](structure-controllers.md#creating-actions)是最终用户可以直接访问并执行的对象。 > Info: [操作](structure-controllers.md#creating-actions)是最终用户可以直接访问并执行的对象。
作被组织在[控制器](structure-controllers.md)中。 作被组织在[控制器](structure-controllers.md)中。
一个作的执行结果就是最终用户收到的响应内容。 一个作的执行结果就是最终用户收到的响应内容。
作必须声明在[控制器](structure-controllers.md)中。为了简单起见, 作必须声明在[控制器](structure-controllers.md)中。为了简单起见,
你可以在现存的 `SiteController` 控制器里声明 `say` 动作。这个控制器定义在 `controllers/SiteController.php` 类文件中 你可以直接`SiteController` 控制器里声明 `say` 操作
以下是一个动作的声明: 这个控制器是由文件 `controllers/SiteController.php` 定义的。以下是一个操作的声明:
```php ```php
<?php <?php
@ -48,25 +48,25 @@ class SiteController extends Controller
} }
``` ```
在上述 `SiteController` 代码中,`say` 作被定义为 `actionSay` 方法。 在上述 `SiteController` 代码中,`say` 作被定义为 `actionSay` 方法。
Yii 使用 `action` 前缀区分普通方法和作。 Yii 使用 `action` 前缀区分普通方法和作。
`action` 前缀后面的名称被映射为作的 ID。 `action` 前缀后面的名称被映射为作的 ID。
涉及到给作命名时,你应该理解 Yii 如何处理操作 ID。 涉及到给作命名时,你应该理解 Yii 如何处理操作 ID。
作 ID 总是被以小写处理,如果一个操作 ID 由多个单词组成, 作 ID 总是被以小写处理,如果一个操作 ID 由多个单词组成,
单词之间将由破折号连接(如 `create-comment`)。动作 ID 映射为方法名时移除了破折号, 单词之间将由连字符连接(如 `create-comment`)。
将每个单词首字母大写,并加上 `action` 前缀。 操作 ID 映射为方法名时移除了连字符,将每个单词首字母大写,并加上 `action` 前缀。
比如:动作 ID `create-comment` 对应方法名 `actionCreateComment` 例子:操作 ID `create-comment` 相当于方法名 `actionCreateComment`
上述代码中的作方法接受一个参数 `$message` 上述代码中的作方法接受一个参数 `$message`
它的默认值是 `“Hello”`(就像你设置 PHP 中其它函数或方法的默认值一样)。 它的默认值是 `“Hello”`(就像你设置 PHP 中其它函数或方法的默认值一样)。
当应用接收到请求并确定由 `say` 作来响应请求时,应用将从请求的参数中寻找对应值传入进来。 当应用接收到请求并确定由 `say` 作来响应请求时,应用将从请求的参数中寻找对应值传入进来。
换句话说,如果请求包含一个 `message` 参数,它的值是 `“Goodybye”` 换句话说,如果请求包含一个 `message` 参数,
动作方法中的 `$message` 变量也将赋值`“Goodbye”` 它的值是 `“Goodybye”`, 操作方法中的 `$message` 变量也将被填充`“Goodbye”`
作方法中,[[yii\web\Controller::render()|render()]] 被用来渲染一个名为 作方法中,[[yii\web\Controller::render()|render()]] 被用来渲染一个
`say` 的[视图](structure-views.md)文件。 名为 `say` 的[视图](structure-views.md)文件。
`message` 参数也被传入视图,这样就可以在里面使用。作方法会返回渲染结果。 `message` 参数也被传入视图,这样就可以在里面使用。作方法会返回渲染结果。
结果会被应用接收并显示给最终用户的浏览器(作为整页 HTML 的一部分)。 结果会被应用接收并显示给最终用户的浏览器(作为整页 HTML 的一部分)。
@ -74,7 +74,7 @@ Yii 使用 `action` 前缀区分普通方法和动作。
--------------- ---------------
[视图](structure-views.md)是你用来生成响应内容的脚本。为了说 “Hello”, [视图](structure-views.md)是你用来生成响应内容的脚本。为了说 “Hello”,
你需要创建一个 `say` 视图,以便显示从作方法中传来的 `message` 参数。 你需要创建一个 `say` 视图,以便显示从作方法中传来的 `message` 参数。
```php ```php
<?php <?php
@ -83,12 +83,12 @@ use yii\helpers\Html;
<?= Html::encode($message) ?> <?= Html::encode($message) ?>
``` ```
`say` 视图应该存为 `views/site/say.php` 文件。当一个作中调用了 [[yii\web\Controller::render()|render()]] 方法时, `say` 视图应该存为 `views/site/say.php` 文件。当一个作中调用了 [[yii\web\Controller::render()|render()]] 方法时,
它将会寻找名为 `views/控制器 ID/视图名.php` 的PHP文件。 它将会`views/控制器 ID/视图名.php` 路径加载 PHP 文件
注意以上代码,`message` 参数在输出之前被 [[yii\helpers\Html::encode()|HTML-encoded]] 方法处理过。 注意以上代码,`message` 参数在输出之前被
这很有必要,当参数来自于最终用户时, [[yii\helpers\Html::encode()|HTML-encoded]] 方法处理过。
参数中可能隐含的恶意 JavaScript 代码会导致 这很有必要,当参数来自于最终用户时,参数中可能隐含的恶意 JavaScript 代码会导致
[跨站脚本(XSS)攻击](http://en.wikipedia.org/wiki/Cross-site_scripting)。 [跨站脚本(XSS)攻击](http://en.wikipedia.org/wiki/Cross-site_scripting)。
当然了,你大概会在 `say` 视图里放入更多内容。内容可以由 HTML 标签,纯文本, 当然了,你大概会在 `say` 视图里放入更多内容。内容可以由 HTML 标签,纯文本,
@ -112,31 +112,31 @@ http://hostname/index.php?r=site/say&message=Hello+World
如果你省略 URL 中的 `message` 参数,将会看到页面只显示 “Hello”。 如果你省略 URL 中的 `message` 参数,将会看到页面只显示 “Hello”。
这是因为 `message` 被作为一个参数传给 `actionSay()` 方法,当省略它时,参数将使用默认的 `“Hello”` 代替。 这是因为 `message` 被作为一个参数传给 `actionSay()` 方法,当省略它时,参数将使用默认的 `“Hello”` 代替。
> 注意:新页面和其它页面使用同样的头部和尾部是因为 [[yii\web\Controller::render()|render()]] 方法会 > Info: 新页面和其它页面使用同样的头部和尾部是因为 [[yii\web\Controller::render()|render()]]
自动把 `say` 视图执行的结果嵌入称为[布局](structure-views.md#layouts)的文件中, 方法会自动把 `say` 视图执行的结果嵌入称为[布局](structure-views.md#layouts)的文件中,
位于 `views/layouts/main.php` 本例中是 `views/layouts/main.php`
上面 URL 中的参数 `r` 需要更多解释。 上面 URL 中的参数 `r` 需要更多解释。
它代表[路由](runtime-routing.md),是整个应用级的, 它代表[路由](runtime-routing.md),是整个应用级的,
指向特定作的独立 ID。路由格式是 `控制器 ID/操作 ID`。应用接受请求的时候会检查参数, 指向特定作的独立 ID。路由格式是 `控制器 ID/操作 ID`。应用接受请求的时候会检查参数,
使用控制器 ID 去确定哪个控制器应该被用来处理请求。 使用控制器 ID 去确定哪个控制器应该被用来处理请求。
然后相应控制器将使用作 ID 去确定哪个操作方法将被用来做具体工作。 然后相应控制器将使用作 ID 去确定哪个操作方法将被用来做具体工作。
在本例子中,路由 `site/say` 将被解析至 `SiteController` 控制器和其中的 `say` 作。 上述例子中,路由 `site/say` 将被解析至 `SiteController` 控制器和其中的 `say` 作。
因此 `SiteController::actionSay()` 方法将被调用处理请求。 因此 `SiteController::actionSay()` 方法将被调用处理请求。
> 注意:与动作一样,一个应用中控制器同样有唯一的 ID。 > Info: 与操作一样,一个应用中控制器同样有唯一的 ID。
控制器 ID 和作 ID 使用同样的命名规则。 控制器 ID 和作 ID 使用同样的命名规则。
控制器的类名源自于控制器 ID,移除了破折号 控制器的类名源自于控制器 ID,
,每个单词首字母大写,并加上 `Controller` 后缀。 移除了连字符,每个单词首字母大写,并加上 `Controller` 后缀。
例子:控制器 ID `post-comment` 对应控制器类名 `PostCommentController` 例子:控制器 ID `post-comment` 相当于控制器类名 `PostCommentController`
总结 <span id="summary"></span> 总结 <span id="summary"></span>
------- -------
通过本章节你接触了 MVC 设计模式中的控制器和视图部分。 通过本章节你接触了 MVC 设计模式中的控制器和视图部分。
创建了一个作作为控制器的一部分去处理特定请求。然后又创建了一个视图去构造响应内容 创建了一个作作为控制器的一部分去处理特定请求。
在这个小例子中,没有模型调用,唯一涉及到数据的地方是 `message` 参数。 然后又创建了一个视图去构造响应内容。在这个小例子中,没有模型调用,唯一涉及到数据的地方是 `message` 参数。
你同样学习了 Yii 路由的相关内容,它是用户请求与控制器动作之间的桥梁。 你同样学习了 Yii 路由的相关内容,它是用户请求与控制器动作之间的桥梁。

8
docs/guide-zh-CN/start-installation.md

@ -21,8 +21,10 @@ Yii当然也提供了其它模板叫
通过 Composer 安装 <span id="installing-via-composer"></span> 通过 Composer 安装 <span id="installing-via-composer"></span>
----------------------- -----------------------
### Installing Composer
如果还没有安装 Composer,你可以按 [getcomposer.org](https://getcomposer.org/download/) 中的方法安装。 如果还没有安装 Composer,你可以按 [getcomposer.org](https://getcomposer.org/download/) 中的方法安装。
在 Linux 和 Mac OS X 中,你可以运行如下命令: 在 Linux 和 Mac OS X 中可以运行如下命令:
```bash ```bash
curl -sS https://getcomposer.org/installer | php curl -sS https://getcomposer.org/installer | php
@ -31,8 +33,8 @@ mv composer.phar /usr/local/bin/composer
在 Windows 中,你需要下载并运行 [Composer-Setup.exe](https://getcomposer.org/Composer-Setup.exe)。 在 Windows 中,你需要下载并运行 [Composer-Setup.exe](https://getcomposer.org/Composer-Setup.exe)。
如果遇到任何问题或者想更深入地学习 Composer, 如果遇到任何问题或者想更深入地学习 Composer,请参考 [Composer 文档(英文)](https://getcomposer.org/doc/),
请参考 [Composer 文档(英文)](https://getcomposer.org/doc/),[Composer 中文](https://github.com/5-say/composer-doc-cn)。 [Composer 中文](https://github.com/5-say/composer-doc-cn)。
如果你已经安装有 Composer 请确保使用的是最新版本, 如果你已经安装有 Composer 请确保使用的是最新版本,
你可以用 `composer self-update` 命令更新 Composer 为最新版本。 你可以用 `composer self-update` 命令更新 Composer 为最新版本。

28
docs/guide-zh-CN/start-looking-ahead.md

@ -1,29 +1,29 @@
更上一层楼 更上一层楼
============= =============
假如你已经阅读完整个“入门”部分,你就完成了一个完整 Yii 应用的创建。 通篇阅读完整个“入门”部分,你就完成了一个完整 Yii 应用的创建。在此过程中你学到了如何实现一些常用功能,
在此过程中你学到了如何实现一些常用功能,例如通过 HTML 表单从用户那获取数据, 例如通过 HTML 表单从用户那获取数据,从数据库中获取数据并以分页形式显示。
从数据库中获取数据并以分页形式显示。你还学到了如何通过 [Gii](tool-gii.md) 去自动生成代码。 你还学到了如何通过 [Gii](tool-gii.md) 去自动生成代码。
使用 Gii 生成代码把 Web 开发中多数繁杂的过程转化为仅仅填写几个表单就行。 使用 Gii 生成代码把 Web 开发中多数繁杂的过程转化为仅仅填写几个表单就行。
本章将介绍一些有助于更好使用 Yii 的资源: 本章将介绍一些有助于更好使用 Yii 的资源:
* 文档 * 文档
- 权威指南:顾名思义, - 权威指南:顾名思义,指南详细描述了 Yii 的工作原理
指南详细描述了 Yii 的工作原理并提供了如何使用它的常规引导。 并提供了如何使用它的常规引导。
这是最重要的 Yii 辅助资料, 这是最重要的 Yii 辅助资料,
强烈建议在开始写 Yii 代码之前阅读。 强烈建议在开始写 Yii 代码之前阅读。
- 类参考手册:描述了 Yii 中每个类的用法。在编码过程中这极为有用, - 类参考手册:描述了 Yii 中每个类的用法。
能够帮你理清某个特定类,方法,和属性的用法。 在编码过程中这极为有用,能够帮你理清某个特定类,
类参考手册最好在整个框架的语境下去理解。 方法,和属性的用法。类参考手册最好在整个框架的语境下去理解。
- [Wiki 文章](http://www.yiiframework.com/wiki/?tag=yii2):Wiki 文章是 Yii 用户在其自身经验基础上分享出来的。 - Wiki 文章:Wiki 文章是 Yii 用户在其自身经验基础上分享出来的。
大多数是使用教程或如何使用 Yii 解决特定问题。 大多数是使用教程或如何使用 Yii 解决特定问题。
虽然这些文章质量可能并不如权威指南, 虽然这些文章质量可能并不如权威指南,
但它们往往覆盖了更广泛的话题, 但它们往往覆盖了更广泛的话题,并常常提供解决方案,
并常常提供解决方案,所以它们也很有用。 所以它们也很有用。
- [书籍](http://www.yiiframework.com/doc/) - 书籍
* [扩展](http://www.yiiframework.com/extensions/):Yii 拥有数以千计用户提供的扩展, * [扩展](http://www.yiiframework.com/extensions/):Yii 拥有数以千计用户提供的扩展,这些扩展能非常方便的插入到应用中,
这些扩展能非常方便的插入到应用中,使你的应用开发过程更加方便快捷。 使你的应用开发过程更加方便快捷。
* 社区 * 社区
- 官方论坛:<http://www.yiiframework.com/forum/> - 官方论坛:<http://www.yiiframework.com/forum/>
- IRC 聊天室:Freenode 网络上的 #yii 频道 (<irc://irc.freenode.net/yii>) - IRC 聊天室:Freenode 网络上的 #yii 频道 (<irc://irc.freenode.net/yii>)

18
docs/guide-zh-CN/start-workflow.md

@ -32,7 +32,7 @@
在浏览器底部可以看到一个工具栏。这是 Yii 提供的很有用的[调试工具](tool-debugger.md), 在浏览器底部可以看到一个工具栏。这是 Yii 提供的很有用的[调试工具](tool-debugger.md),
可以记录并显示大量的调试信息,例如日志信息,响应状态,数据库查询等等。 可以记录并显示大量的调试信息,例如日志信息,响应状态,数据库查询等等。
除了web应用程序,还有一个控制台脚步`yii` ,它位于应用程序根目录。 除了 web 应用程序,还有一个控制台脚本`yii` ,它位于应用程序根目录。
它可以用于程序的后台运行和维护任务,在[控制台应用程序章节](tutorial-console.md) 它可以用于程序的后台运行和维护任务,在[控制台应用程序章节](tutorial-console.md)
中描述。 中描述。
@ -72,11 +72,11 @@ Yii 实现了[模型-视图-控制器 (MVC)](http://wikipedia.org/wiki/Model-vie
![应用静态结构](images/application-structure.png) ![应用静态结构](images/application-structure.png)
每个应用都有一个入口脚本 `web/index.php` 每个应用都有一个入口脚本 `web/index.php`,这是整个应用中唯一可以访问的 PHP 脚本。
这是整个应用中唯一可以访问的 PHP 脚本。
入口脚本接受一个 Web 请求并创建[应用](structure-application.md)实例去处理它。 入口脚本接受一个 Web 请求并创建[应用](structure-application.md)实例去处理它。
[应用](structure-applications.md)在它的[组件](concept-components.md)辅助下解析请求, [应用](structure-applications.md)在它的[组建](concept-components.md)辅助下解析请求,
并分派请求至 MVC 元素。[视图](structure-views.md)使用[小部件](structure-widgets.md)去创建复杂和动态的用户界面。 并分派请求至 MVC 元素。[视图](structure-views.md)使用[小部件](structure-widgets.md)
去创建复杂和动态的用户界面。
请求生命周期 <span id="request-lifecycle"></span> 请求生命周期 <span id="request-lifecycle"></span>
@ -87,10 +87,10 @@ Yii 实现了[模型-视图-控制器 (MVC)](http://wikipedia.org/wiki/Model-vie
![请求生命周期](images/request-lifecycle.png) ![请求生命周期](images/request-lifecycle.png)
1. 用户向[入口脚本](structure-entry-scripts.md) `web/index.php` 发起请求。 1. 用户向[入口脚本](structure-entry-scripts.md) `web/index.php` 发起请求。
2. 入口脚本加载应用[配置](concept-configurations.md) 2. 入口脚本加载应用[配置](concept-configurations.md)并创建一个[应用](structure-applications.md)
并创建一个[应用](structure-applications.md)实例去处理请求。 实例去处理请求。
3. 应用通过[请求](runtime-request.md)组件 3. 应用通过[请求](runtime-request.md)组件解析请求的
解析请求的[路由](runtime-routing.md)。 [路由](runtime-routing.md)。
4. 应用创建一个[控制器](structure-controllers.md)实例去处理请求。 4. 应用创建一个[控制器](structure-controllers.md)实例去处理请求。
5. 控制器创建一个[动作](structure-controllers.md)实例并针对操作执行过滤器。 5. 控制器创建一个[动作](structure-controllers.md)实例并针对操作执行过滤器。
6. 如果任何一个过滤器返回失败,则动作取消。 6. 如果任何一个过滤器返回失败,则动作取消。

34
docs/guide-zh-CN/structure-application-components.md

@ -19,8 +19,8 @@
第一次使用以上表达式时候会创建应用组件实例, 第一次使用以上表达式时候会创建应用组件实例,
后续再访问会返回此实例,无需再次创建。 后续再访问会返回此实例,无需再次创建。
应用组件可以是任意对象,可以在 应用组件可以是任意对象,可以在 [应用主体配置](structure-applications.md#application-configurations)配置
[应用主体配置](structure-applications.md#application-configurations)配置 [[yii\base\Application::components]] 属性 . [[yii\base\Application::components]] 属性 .
例如: 例如:
```php ```php
@ -45,7 +45,7 @@
] ]
``` ```
> 补充:请谨慎注册太多应用组件, > Info: 请谨慎注册太多应用组件,
应用组件就像全局变量, 应用组件就像全局变量,
使用太多可能加大测试和维护的难度。 使用太多可能加大测试和维护的难度。
一般情况下可以在需要时再创建本地组件。 一般情况下可以在需要时再创建本地组件。
@ -58,17 +58,26 @@
有时你想在每个请求处理过程都实例化某个组件即便它不会被访问, 有时你想在每个请求处理过程都实例化某个组件即便它不会被访问,
可以将该组件ID加入到应用主体的 [[yii\base\Application::bootstrap|bootstrap]] 属性中。 可以将该组件ID加入到应用主体的 [[yii\base\Application::bootstrap|bootstrap]] 属性中。
You can also use Closures to bootstrap customized components. Returning a instantiated component is not
required. A Closure can also be used simply for running code after [[yii\base\Application]] instantiation.
例如, 如下的应用主体配置保证了 `log` 组件一直被加载。 例如, 如下的应用主体配置保证了 `log` 组件一直被加载。
```php ```php
[ [
'bootstrap' => [ 'bootstrap' => [
// 将 log 组件 ID 加入引导让它始终载入
'log', 'log',
function($app){
return new ComponentX();
},
function($app){
// some code
return;
}
], ],
'components' => [ 'components' => [
'log' => [ 'log' => [
// "log" 组件的配置 // configuration for "log" component
], ],
], ],
] ]
@ -77,14 +86,15 @@
## 核心应用组件 <span id="core-application-components"></span> ## 核心应用组件 <span id="core-application-components"></span>
Yii 定义了一组固定ID和默认配置的 *核心* 组件,例如 [[yii\web\Application::request|request]] 组件 Yii 定义了一组固定ID和默认配置的 *核心* 组件,
例如 [[yii\web\Application::request|request]] 组件
用来收集用户请求并解析 [路由](runtime-routing.md); 用来收集用户请求并解析 [路由](runtime-routing.md);
[[yii\base\Application::db|db]] 代表一个可以执行数据库操作的数据库连接。 [[yii\base\Application::db|db]] 代表一个可以执行数据库操作的数据库连接。
通过这些组件,Yii应用主体能处理用户请求。 通过这些组件,Yii应用主体能处理用户请求。
下面是预定义的核心应用组件列表,可以和普通应用组件一样配置和自定义它们。 下面是预定义的核心应用组件列表,
当你配置一个核心组件, 可以和普通应用组件一样配置和自定义它们。
不指定它的类名的话就会使用Yii默认指定的类。 当你配置一个核心组件,不指定它的类名的话就会使用Yii默认指定的类。
* [[yii\web\AssetManager|assetManager]]: 管理资源包和资源发布, * [[yii\web\AssetManager|assetManager]]: 管理资源包和资源发布,
详情请参考 [管理资源](output-assets.md) 一节。 详情请参考 [管理资源](output-assets.md) 一节。
@ -94,9 +104,9 @@ Yii 定义了一组固定ID和默认配置的 *核心* 组件,例如 [[yii\web
详情请参考 [数据访问对象](db-dao.md) 一节。 详情请参考 [数据访问对象](db-dao.md) 一节。
* [[yii\base\Application::errorHandler|errorHandler]]: 处理 PHP 错误和异常, * [[yii\base\Application::errorHandler|errorHandler]]: 处理 PHP 错误和异常,
详情请参考 [错误处理](tutorial-handling-errors.md) 一节。 详情请参考 [错误处理](tutorial-handling-errors.md) 一节。
* [[yii\i18n\Formatter|formatter]]: 格式化输出显示给终端用户的数据, * [[yii\i18n\Formatter|formatter]]: 格式化输出显示给终端用户的数据,例如数字可能要带分隔符,
例如数字可能要带分隔符, 日期使用长格式。
日期使用长格式。详情请参考 [格式化输出数据](output-formatting.md) 一节。 详情请参考 [格式化输出数据](output-formatting.md) 一节。
* [[yii\i18n\I18N|i18n]]: 支持信息翻译和格式化。 * [[yii\i18n\I18N|i18n]]: 支持信息翻译和格式化。
详情请参考 [国际化](tutorial-i18n.md) 一节。 详情请参考 [国际化](tutorial-i18n.md) 一节。
* [[yii\log\Dispatcher|log]]: 管理日志对象。 * [[yii\log\Dispatcher|log]]: 管理日志对象。

102
docs/guide-zh-CN/structure-applications.md

@ -2,8 +2,8 @@
============ ============
应用主体是管理 Yii 应用系统整体结构和生命周期的对象。 应用主体是管理 Yii 应用系统整体结构和生命周期的对象。
每个Yii应用系统只能包含一个应用主体, 每个Yii应用系统只能包含一个应用主体,应用主体在
应用主体在 [入口脚本](structure-entry-scripts.md) 中创建并能通过表达式 `\Yii::$app` 全局范围内访问。 [入口脚本](structure-entry-scripts.md) 中创建并能通过表达式 `\Yii::$app` 全局范围内访问。
> Info: 当我们说"一个应用",它可能是一个应用主体对象,也可能是一个应用系统, > Info: 当我们说"一个应用",它可能是一个应用主体对象,也可能是一个应用系统,
是根据上下文来决定[译:中文为避免歧义,Application翻译为应用主体]。 是根据上下文来决定[译:中文为避免歧义,Application翻译为应用主体]。
@ -31,16 +31,16 @@ $config = require(__DIR__ . '/../config/web.php');
类似其他 [配置](concept-configurations.md) 文件, 类似其他 [配置](concept-configurations.md) 文件,
应用主体配置文件标明如何设置应用对象初始属性。 应用主体配置文件标明如何设置应用对象初始属性。
由于应用主体配置比较复杂, 由于应用主体配置比较复杂,一般保存在多个类似如上web.php的
一般保存在多个类似如上web.php的 [配置文件](concept-configurations.md#configuration-files) 当中。 [配置文件](concept-configurations.md#configuration-files) 当中。
## 应用主体属性 <span id="application-properties"></span> ## 应用主体属性 <span id="application-properties"></span>
应用主体配置文件中有许多重要的属性要配置, 应用主体配置文件中有许多重要的属性要配置,这些属性指定应用主体的运行环境。
这些属性指定应用主体的运行环境。
比如,应用主体需要知道如何加载 [控制器](structure-controllers.md) , 比如,应用主体需要知道如何加载 [控制器](structure-controllers.md) ,
临时文件保存到哪儿等等。以下我们简述这些属性。 临时文件保存到哪儿等等。
以下我们简述这些属性。
### 必要属性 <span id="required-properties"></span> ### 必要属性 <span id="required-properties"></span>
@ -51,8 +51,8 @@ $config = require(__DIR__ . '/../config/web.php');
#### [[yii\base\Application::id|id]] <span id="id"></span> #### [[yii\base\Application::id|id]] <span id="id"></span>
[[yii\base\Application::id|id]] 属性用来区分其他应用的唯一标识ID。 [[yii\base\Application::id|id]] 属性用来区分其他应用的唯一标识ID。主要给程序使用。
主要给程序使用。为了方便协作,最好使用数字作为应用主体ID, 为了方便协作,最好使用数字作为应用主体ID,
但不强制要求为数字。 但不强制要求为数字。
@ -99,9 +99,9 @@ $config = require(__DIR__ . '/../config/web.php');
#### [[yii\base\Application::bootstrap|bootstrap]] <span id="bootstrap"></span> #### [[yii\base\Application::bootstrap|bootstrap]] <span id="bootstrap"></span>
这个属性很实用,它允许你用数组指定启动阶段 这个属性很实用,它允许你用数组指定启动阶段[[yii\base\Application::bootstrap()|bootstrapping process]]需要运行的组件。
[[yii\base\Application::bootstrap()|bootstrapping process]]需要运行的组件。 比如,如果你希望一个 [模块](structure-modules.md)
比如,如果你希望一个 [模块](structure-modules.md) 自定义 [URL 规则](runtime-url-handling.md), 自定义 [URL 规则](runtime-url-handling.md),
你可以将模块ID加入到bootstrap数组中。 你可以将模块ID加入到bootstrap数组中。
属性中的每个组件需要指定以下一项: 属性中的每个组件需要指定以下一项:
@ -137,8 +137,8 @@ $config = require(__DIR__ . '/../config/web.php');
] ]
``` ```
> Info: 如果模块ID和应用组件ID同名, > Info: 如果模块ID和应用组件ID同名,优先使用应用组件ID,
> 优先使用应用组件ID,如果你想用模块ID, > 如果你想用模块ID,
> 可以使用如下无名称函数返回模块ID。 > 可以使用如下无名称函数返回模块ID。
> >
> ```php > ```php
@ -150,12 +150,12 @@ $config = require(__DIR__ . '/../config/web.php');
``` ```
在启动阶段,每个组件都会实例化。 在启动阶段,每个组件都会实例化。如果组件类实现接口
如果组件类实现接口 [[yii\base\BootstrapInterface]], [[yii\base\BootstrapInterface]],也会调用
也会调用 [[yii\base\BootstrapInterface::bootstrap()|bootstrap()]] 方法。 [[yii\base\BootstrapInterface::bootstrap()|bootstrap()]] 方法。
举一个实际的例子, 举一个实际的例子,[Basic Application Template](start-installation.md)
[Basic Application Template](start-installation.md) 应用主体配置中, 应用主体配置中,
开发环境下会在启动阶段运行 `debug``gii` 模块。 开发环境下会在启动阶段运行 `debug``gii` 模块。
```php ```php
@ -169,8 +169,8 @@ if (YII_ENV_DEV) {
} }
``` ```
> 注: 启动太多的组件会降低系统性能, > 注: 启动太多的组件会降低系统性能,因为每次请求都需要重新运行启动组件,
因为每次请求都需要重新运行启动组件,因此谨慎配置启动组件。 > 因此谨慎配置启动组件。
#### [[yii\web\Application::catchAll|catchAll]] <span id="catchAll"></span> #### [[yii\web\Application::catchAll|catchAll]] <span id="catchAll"></span>
@ -179,8 +179,8 @@ if (YII_ENV_DEV) {
它指定一个要处理所有用户请求的 [控制器方法](structure-controllers.md), 它指定一个要处理所有用户请求的 [控制器方法](structure-controllers.md),
通常在维护模式下使用,同一个方法处理所有用户请求。 通常在维护模式下使用,同一个方法处理所有用户请求。
该配置为一个数组,第一项指定动作的路由, 该配置为一个数组,第一项指定动作的路由,剩下的数组项(key-value 成对)指定传递给动作的参数,
剩下的数组项(key-value 成对)指定传递给动作的参数,例如: 例如:
```php ```php
[ [
@ -192,11 +192,11 @@ if (YII_ENV_DEV) {
] ]
``` ```
> Info: Debug panel on development environment will not work when this property is enabled > Info: Debug panel on development environment will not work when this property is enabled.
#### [[yii\base\Application::components|components]] <span id="components"></span> #### [[yii\base\Application::components|components]] <span id="components"></span>
这是最重要的属性,它允许你注册多个在其他地方使用的[应用组件](#structure-application-components.md) 这是最重要的属性,它允许你注册多个在其他地方使用的[应用组件](#structure-application-components.md).
例如 例如
```php ```php
@ -216,8 +216,8 @@ if (YII_ENV_DEV) {
每一个应用组件指定一个key-value对的数组,key代表组件ID, 每一个应用组件指定一个key-value对的数组,key代表组件ID,
value代表组件类名或 [配置](concept-configurations.md)。 value代表组件类名或 [配置](concept-configurations.md)。
在应用中可以任意注册组件, 在应用中可以任意注册组件,并可以通过表达式
并可以通过表达式 `\Yii::$app->ComponentID` 全局访问。 `\Yii::$app->ComponentID` 全局访问。
详情请阅读 [应用组件](structure-application-components.md) 一节. 详情请阅读 [应用组件](structure-application-components.md) 一节.
@ -256,8 +256,8 @@ Yii遵循一个默认的 [规则](#controllerNamespace)指定控制器ID到任
例如,控制器ID `admin/post` 对应的控制器类全名为 例如,控制器ID `admin/post` 对应的控制器类全名为
`app\controllers\admin\PostController` `app\controllers\admin\PostController`
控制器类全面能被 [自动加载](concept-autoloading.md),这点是非常重要的, 控制器类全面能被 [自动加载](concept-autoloading.md),
控制器类的实际命名空间对应这个属性, 这点是非常重要的,控制器类的实际命名空间对应这个属性,
否则,访问时你会收到"Page Not Found"[译:页面找不到]。 否则,访问时你会收到"Page Not Found"[译:页面找不到]。
如果你想打破上述的规则, 如果你想打破上述的规则,
@ -272,11 +272,11 @@ Yii遵循一个默认的 [规则](#controllerNamespace)指定控制器ID到任
该属性影响各种 [国际化](tutorial-i18n.md) , 该属性影响各种 [国际化](tutorial-i18n.md) ,
包括信息翻译、日期格式、数字格式等。 包括信息翻译、日期格式、数字格式等。
例如 [[yii\jui\DatePicker]] 小部件会 例如 [[yii\jui\DatePicker]] 小部件会根据该属性
根据该属性展示对应语言的日历以及日期格式。 展示对应语言的日历以及日期格式。
推荐遵循 [IETF language tag](http://en.wikipedia.org/wiki/IETF_language_tag) 来设置语言, 推荐遵循 [IETF language tag](http://en.wikipedia.org/wiki/IETF_language_tag) 来设置语言,
例如 `en` 代表英文, `en-US` 代表英文(美国) 例如 `en` 代表英文, `en-US` 代表英文(美国).
该属性的更多信息可参考 [国际化](tutorial-i18n.md) 一节. 该属性的更多信息可参考 [国际化](tutorial-i18n.md) 一节.
@ -285,8 +285,8 @@ Yii遵循一个默认的 [规则](#controllerNamespace)指定控制器ID到任
该属性指定应用所包含的 [模块](structure-modules.md)。 该属性指定应用所包含的 [模块](structure-modules.md)。
该属性使用数组包含多个模块类 [配置](concept-configurations.md), 该属性使用数组包含多个模块类 [配置](concept-configurations.md),数组的键为模块ID,
数组的键为模块ID,例: 例:
```php ```php
[ [
@ -346,8 +346,8 @@ $width = \Yii::$app->params['thumbnail.size'][0];
该属性指定应用代码的语言,默认为 `'en-US'` 标识英文(美国), 该属性指定应用代码的语言,默认为 `'en-US'` 标识英文(美国),
如果应用不是英文请修改该属性。 如果应用不是英文请修改该属性。
和 [语言](#language) 属性类似, 和 [语言](#language) 属性类似,配置该属性需遵循
配置该属性需遵循 [IETF language tag](http://en.wikipedia.org/wiki/IETF_language_tag). [IETF language tag](http://en.wikipedia.org/wiki/IETF_language_tag).
例如 `en` 代表英文, `en-US` 代表英文(美国)。 例如 `en` 代表英文, `en-US` 代表英文(美国)。
该属性的更多信息可参考 [国际化](tutorial-i18n.md) 一节. 该属性的更多信息可参考 [国际化](tutorial-i18n.md) 一节.
@ -404,7 +404,7 @@ $width = \Yii::$app->params['thumbnail.size'][0];
该属性用数组列表指定应用安装和使用的 [扩展](structure-extensions.md), 该属性用数组列表指定应用安装和使用的 [扩展](structure-extensions.md),
默认使用`@vendor/yiisoft/extensions.php`文件返回的数组。 默认使用`@vendor/yiisoft/extensions.php`文件返回的数组。
当你使用 [Composer](http://getcomposer.org) 安装扩展,`extensions.php` 会被自动生成和维护更新。 当你使用 [Composer](https://getcomposer.org) 安装扩展,`extensions.php` 会被自动生成和维护更新。
所以大多数情况下,不需要配置该属性。 所以大多数情况下,不需要配置该属性。
特殊情况下你想自己手动维护扩展,可以参照如下配置该属性: 特殊情况下你想自己手动维护扩展,可以参照如下配置该属性:
@ -446,9 +446,9 @@ $width = \Yii::$app->params['thumbnail.size'][0];
#### [[yii\base\Application::layoutPath|layoutPath]] <span id="layoutPath"></span> #### [[yii\base\Application::layoutPath|layoutPath]] <span id="layoutPath"></span>
该属性指定查找布局文件的路径, 该属性指定查找布局文件的路径,默认值为 [视图路径](#viewPath) 下的 `layouts` 子目录。
默认值为 [视图路径](#viewPath) 下的 `layouts` 子目录。 如果 [视图路径](#viewPath) 使用默认值,
如果 [视图路径](#viewPath) 使用默认值,默认的布局路径别名为`@app/views/layouts`。 默认的布局路径别名为`@app/views/layouts`。
该属性需要配置成一个目录或 路径 [别名](concept-aliases.md)。 该属性需要配置成一个目录或 路径 [别名](concept-aliases.md)。
@ -473,12 +473,12 @@ $width = \Yii::$app->params['thumbnail.size'][0];
#### [[yii\base\Application::vendorPath|vendorPath]] <span id="vendorPath"></span> #### [[yii\base\Application::vendorPath|vendorPath]] <span id="vendorPath"></span>
该属性指定 [Composer](http://getcomposer.org) 管理的供应商路径, 该属性指定 [Composer](https://getcomposer.org) 管理的供应商路径,
该路径包含应用使用的包括Yii框架在内的所有第三方库。 该路径包含应用使用的包括Yii框架在内的所有第三方库。
默认值为带别名的 `@app/vendor` 默认值为带别名的 `@app/vendor`
可以配置它为一个目录或者路径 [别名](concept-aliases.md),当你修改时, 可以配置它为一个目录或者路径 [别名](concept-aliases.md),
务必修改对应的 Composer 配置。 当你修改时,务必修改对应的 Composer 配置。
为了简化访问该路径,Yii预定义别名 `@vendor` 代表该路径。 为了简化访问该路径,Yii预定义别名 `@vendor` 代表该路径。
@ -491,8 +491,8 @@ $width = \Yii::$app->params['thumbnail.size'][0];
## 应用事件 <span id="application-events"></span> ## 应用事件 <span id="application-events"></span>
应用在处理请求过程中会触发事件, 应用在处理请求过程中会触发事件,可以在配置文件配置事件处理代码,
可以在配置文件配置事件处理代码,如下所示: 如下所示:
```php ```php
[ [
@ -581,10 +581,10 @@ $width = \Yii::$app->params['thumbnail.size'][0];
] ]
``` ```
注意 [模块](structure-modules.md) 和 [控制器](structure-controllers.md) 注意 [模块](structure-modules.md) 和
都会触发 `afterAction` 事件。 [控制器](structure-controllers.md) 都会触发 `afterAction` 事件。
这些对象的触发顺序和 `beforeAction` 相反,也就是说,控制器最先触发, 这些对象的触发顺序和 `beforeAction` 相反,也就是说,
然后是模块(如果有模块),最后为应用主体。 控制器最先触发,然后是模块(如果有模块),最后为应用主体。
## 应用主体生命周期 <span id="application-lifecycle"></span> ## 应用主体生命周期 <span id="application-lifecycle"></span>
@ -600,8 +600,8 @@ $width = \Yii::$app->params['thumbnail.size'][0];
比如[[yii\base\Application::basePath|basePath]]。 比如[[yii\base\Application::basePath|basePath]]。
* 注册 [[yii\base\Application::errorHandler|error handler]] 错误处理方法. * 注册 [[yii\base\Application::errorHandler|error handler]] 错误处理方法.
* 配置应用主体属性. * 配置应用主体属性.
* 调用 [[yii\base\Application::init()|init()]] 初始化, * 调用 [[yii\base\Application::init()|init()]] 初始化,该函数会调用 [[yii\base\Application::bootstrap()|bootstrap()]]
该函数会调用 [[yii\base\Application::bootstrap()|bootstrap()]] 运行引导启动组件. 运行引导启动组件.
3. 入口脚本调用 [[yii\base\Application::run()]] 运行应用主体: 3. 入口脚本调用 [[yii\base\Application::run()]] 运行应用主体:
* 触发 [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_BEFORE_REQUEST]] 事件。 * 触发 [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_BEFORE_REQUEST]] 事件。
* 处理请求:解析请求 [路由](runtime-routing.md) 和相关参数; * 处理请求:解析请求 [路由](runtime-routing.md) 和相关参数;

54
docs/guide-zh-CN/structure-assets.md

@ -4,9 +4,9 @@
Yii中的资源是和Web页面相关的文件,可为CSS文件,JavaScript文件,图片或视频等, Yii中的资源是和Web页面相关的文件,可为CSS文件,JavaScript文件,图片或视频等,
资源放在Web可访问的目录下,直接被Web服务器调用。 资源放在Web可访问的目录下,直接被Web服务器调用。
通过程序自动管理资源更好一点,例如, 通过程序自动管理资源更好一点,例如,当你在页面中使用 [[yii\jui\DatePicker]] 小部件时,
当你在页面中使用 [[yii\jui\DatePicker]] 小部件时 它会自动包含需要的CSS和JavaScript文件
它会自动包含需要的CSS和JavaScript文件,而不是要求你手工去找到这些文件并包含, 而不是要求你手工去找到这些文件并包含,
当你升级小部件时,它会自动使用新版本的资源文件, 当你升级小部件时,它会自动使用新版本的资源文件,
在本教程中,我们会详述Yii提供的强大的资源管理功能。 在本教程中,我们会详述Yii提供的强大的资源管理功能。
@ -65,50 +65,50 @@ class AppAsset extends AssetBundle
如果你的资源文件在一个Web可访问目录下,应设置该属性,这样就不用再发布了。 如果你的资源文件在一个Web可访问目录下,应设置该属性,这样就不用再发布了。
[路径别名](concept-aliases.md) 可在此处使用。 [路径别名](concept-aliases.md) 可在此处使用。
* [[yii\web\AssetBundle::baseUrl|baseUrl]]: 指定对应到[[yii\web\AssetBundle::basePath|basePath]]目录的URL, * [[yii\web\AssetBundle::baseUrl|baseUrl]]: 指定对应到[[yii\web\AssetBundle::basePath|basePath]]目录的URL,
和 [[yii\web\AssetBundle::basePath|basePath]] 类似,如果你指定 [[yii\web\AssetBundle::sourcePath|sourcePath]] 属性, 和 [[yii\web\AssetBundle::basePath|basePath]] 类似,
[资源管理器](#asset-manager) 会发布这些资源并覆盖该属性, 如果你指定 [[yii\web\AssetBundle::sourcePath|sourcePath]] 属性,
[路径别名](concept-aliases.md) 可在此处使用。 [资源管理器](#asset-manager) 会发布这些资源并覆盖该属性,[路径别名](concept-aliases.md) 可在此处使用。
* [[yii\web\AssetBundle::js|js]]: 一个包含该资源包JavaScript文件的数组, * [[yii\web\AssetBundle::js|js]]: 一个包含该资源包JavaScript文件的数组,
注意正斜杠"/"应作为目录分隔符, 注意正斜杠"/"应作为目录分隔符,
每个JavaScript文件可指定为以下两种格式之一: 每个JavaScript文件可指定为以下两种格式之一:
- 相对路径表示为本地JavaScript文件 (如 `js/main.js`), - 相对路径表示为本地JavaScript文件 (如 `js/main.js`),文件实际的路径在该相对路径前加上
文件实际的路径在该相对路径前加上 [[yii\web\AssetManager::basePath]],文件实际的URL
[[yii\web\AssetManager::basePath]],文件实际的URL在该路径前加上[[yii\web\AssetManager::baseUrl]]。 在该路径前加上[[yii\web\AssetManager::baseUrl]]。
- 绝对URL地址表示为外部JavaScript文件,如 - 绝对URL地址表示为外部JavaScript文件,如
`http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js` `http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js`
`//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js`. `//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js`.
* [[yii\web\AssetBundle::css|css]]: 一个包含该资源包CSS文件的数组, * [[yii\web\AssetBundle::css|css]]: 一个包含该资源包CSS文件的数组,
该数组格式和 [[yii\web\AssetBundle::js|js]] 相同。 该数组格式和 [[yii\web\AssetBundle::js|js]] 相同。
* [[yii\web\AssetBundle::depends|depends]]: 一个列出该资源包 * [[yii\web\AssetBundle::depends|depends]]: 一个列出该资源包依赖的
依赖的其他资源包(后两节有详细介绍)。 其他资源包(后两节有详细介绍)。
* [[yii\web\AssetBundle::jsOptions|jsOptions]]: 当调用[[yii\web\View::registerJsFile()]]注册该包 *每个* JavaScript文件时, * [[yii\web\AssetBundle::jsOptions|jsOptions]]: 当调用[[yii\web\View::registerJsFile()]]注册该包 *每个* JavaScript文件时,
指定传递到该方法的选项。 指定传递到该方法的选项。
* [[yii\web\AssetBundle::cssOptions|cssOptions]]: 当调用[[yii\web\View::registerCssFile()]]注册该包 *每个* css文件时, * [[yii\web\AssetBundle::cssOptions|cssOptions]]: 当调用[[yii\web\View::registerCssFile()]]注册该包 *每个* css文件时,
指定传递到该方法的选项。 指定传递到该方法的选项。
* [[yii\web\AssetBundle::publishOptions|publishOptions]]: 当调用[[yii\web\AssetManager::publish()]]发布该包资源文件到Web目录时 * [[yii\web\AssetBundle::publishOptions|publishOptions]]: 当调用[[yii\web\AssetManager::publish()]]发布该包资源文件到Web目录时
指定传递到该方法的选项, 指定传递到该方法的选项,仅在指定了
仅在指定了[[yii\web\AssetBundle::sourcePath|sourcePath]]属性时使用。 [[yii\web\AssetBundle::sourcePath|sourcePath]]属性时使用。
### 资源位置 <span id="asset-locations"></span> ### 资源位置 <span id="asset-locations"></span>
资源根据它们的位置可以分为: 资源根据它们的位置可以分为:
* 源资源: 资源文件和PHP源代码放在一起,不能被Web直接访问, * 源资源: 资源文件和PHP源代码放在一起,不能被Web直接访问,为了使用这些源资源,
为了使用这些源资源,它们要拷贝到一个可Web访问的Web目录中 它们要拷贝到一个可Web访问的Web目录中
成为发布的资源,这个过程称为*发布资源*,随后会详细介绍。 成为发布的资源,这个过程称为*发布资源*,随后会详细介绍。
* 发布资源: 资源文件放在可通过Web直接访问的Web目录中; * 发布资源: 资源文件放在可通过Web直接访问的Web目录中;
* 外部资源: 资源文件放在与你的Web应用不同 * 外部资源: 资源文件放在与你的Web应用不同
Web服务器上; Web服务器上;
当定义资源包类时候,如果你指定了[[yii\web\AssetBundle::sourcePath|sourcePath]] 属性, 当定义资源包类时候,如果你指定了[[yii\web\AssetBundle::sourcePath|sourcePath]] 属性,
就表示任何使用相对路径的资源会被当作源资源;如果没有指定该属性, 就表示任何使用相对路径的资源会被当作源资源;
就表示这些资源为发布资源(因此应指定[[yii\web\AssetBundle::basePath|basePath]] 和 如果没有指定该属性,就表示这些资源为发布资源(因此应指定[[yii\web\AssetBundle::basePath|basePath]] 和
[[yii\web\AssetBundle::baseUrl|baseUrl]] 让Yii知道它们的位置)。 [[yii\web\AssetBundle::baseUrl|baseUrl]] 让Yii知道它们的位置)。
推荐将资源文件放到Web目录以避免不必要的发布资源过程, 推荐将资源文件放到Web目录以避免不必要的发布资源过程,这就是之前的例子:指定
这就是之前的例子:指定 [[yii\web\AssetBundle::basePath|basePath]]
[[yii\web\AssetBundle::basePath|basePath]] 而不是 [[yii\web\AssetBundle::sourcePath|sourcePath]]. 而不是 [[yii\web\AssetBundle::sourcePath|sourcePath]].
对于 [扩展](structure-extensions.md)来说, 对于 [扩展](structure-extensions.md)来说,
由于它们的资源和源代码都在不能Web访问的目录下, 由于它们的资源和源代码都在不能Web访问的目录下,
@ -166,8 +166,8 @@ public $cssOptions = ['condition' => 'lte IE9'];
public $cssOptions = ['noscript' => true]; public $cssOptions = ['noscript' => true];
``` ```
为使JavaScript文件包含在页面head区域 为使JavaScript文件包含在页面head区域(JavaScript文件默认包含在body的结束处)
(JavaScript文件默认包含在body的结束处)使用以下选项: 使用以下选项:
```php ```php
public $jsOptions = ['position' => \yii\web\View::POS_HEAD]; public $jsOptions = ['position' => \yii\web\View::POS_HEAD];
@ -205,9 +205,9 @@ the `only` publishing option, only the `fonts` and `css` subdirectories will be
### Bower 和 NPM 资源 <span id="bower-npm-assets"></span> ### Bower 和 NPM 资源 <span id="bower-npm-assets"></span>
大多数 JavaScript/CSS 包通过[Bower](http://bower.io/) 和/或 [NPM](https://www.npmjs.org/)管理, 大多数 JavaScript/CSS 包通过[Bower](http://bower.io/) 和/或
如果你的应用或扩展使用这些包 [NPM](https://www.npmjs.org/)管理
推荐你遵循以下步骤来管理库中的资源: 如果你的应用或扩展使用这些包,推荐你遵循以下步骤来管理库中的资源:
1. 修改应用或扩展的 `composer.json` 文件将包列入`require` 中, 1. 修改应用或扩展的 `composer.json` 文件将包列入`require` 中,
应使用`bower-asset/PackageName` (Bower包) 应使用`bower-asset/PackageName` (Bower包)

156
docs/guide-zh-CN/structure-controllers.md

@ -3,15 +3,15 @@
控制器是 [MVC](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) 模式中的一部分, 控制器是 [MVC](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) 模式中的一部分,
是继承[[yii\base\Controller]]类的对象,负责处理请求和生成响应。 是继承[[yii\base\Controller]]类的对象,负责处理请求和生成响应。
具体来说,控制器从[应用主体](structure-applications.md)接管控制后会分析请求数据并传送到[模型](structure-models.md), 具体来说,控制器从[应用主体](structure-applications.md)
传送模型结果到[视图](structure-views.md), 接管控制后会分析请求数据并传送到[模型](structure-models.md),
最后生成输出响应信息。 传送模型结果到[视图](structure-views.md),最后生成输出响应信息。
## 动作 <span id="actions"></span> ## 动作 <span id="actions"></span>
控制器由 *作* 组成,它是执行终端用户请求的最基础的单元, 控制器由 *作* 组成,它是执行终端用户请求的最基础的单元,
一个控制器可有一个或多个作。 一个控制器可有一个或多个作。
如下示例显示包含两个动作`view` and `create` 的控制器`post`: 如下示例显示包含两个动作`view` and `create` 的控制器`post`:
@ -52,13 +52,13 @@ class PostController extends Controller
} }
``` ```
`view` (定义为 `actionView()` 方法)中, `view` (定义为 `actionView()` 方法)中,
代码首先根据请求模型ID加载 [模型](structure-models.md), 代码首先根据请求模型ID加载 [模型](structure-models.md),
如果加载成功,会渲染名称为`view`的[视图](structure-views.md)并显示,否则会抛出一个异常。 如果加载成功,会渲染名称为`view`的[视图](structure-views.md)并显示,否则会抛出一个异常。
`create` (定义为 `actionCreate()` 方法)中, 代码相似 `create` (定义为 `actionCreate()` 方法)中, 代码相似.
先将请求数据填入[模型](structure-models.md), 先将请求数据填入[模型](structure-models.md),
然后保存模型,如果两者都成功,会跳转到ID为新创建的模型的`view`作, 然后保存模型,如果两者都成功,会跳转到ID为新创建的模型的`view`作,
否则显示提供用户输入的`create`视图。 否则显示提供用户输入的`create`视图。
@ -66,10 +66,10 @@ class PostController extends Controller
终端用户通过所谓的*路由*寻找到动作,路由是包含以下部分的字符串: 终端用户通过所谓的*路由*寻找到动作,路由是包含以下部分的字符串:
* 模ID: 仅存在于控制器属于非应用的[模块](structure-modules.md); * 模ID: 仅存在于控制器属于非应用的[模块](structure-modules.md);
* 控制器ID: 同应用(或同模块如果为模块下的控制器) * 控制器ID: 同应用(或同模块如果为模块下的控制器)
下唯一标识控制器的字符串; 下唯一标识控制器的字符串;
* 作ID: 同控制器下唯一标识操作的字符串。 * 作ID: 同控制器下唯一标识操作的字符串。
路由使用如下格式: 路由使用如下格式:
@ -84,7 +84,7 @@ ModuleID/ControllerID/ActionID
``` ```
如果用户的请求地址为 `http://hostname/index.php?r=site/index`, 如果用户的请求地址为 `http://hostname/index.php?r=site/index`,
会执行`site` 控制器的`index` 作。 会执行`site` 控制器的`index` 作。
更多关于处理路由的详情请参阅 [路由](runtime-routing.md) 一节。 更多关于处理路由的详情请参阅 [路由](runtime-routing.md) 一节。
@ -112,13 +112,13 @@ class SiteController extends Controller
例如使用`article`作为处理文章的控制器ID。 例如使用`article`作为处理文章的控制器ID。
控制器ID应仅包含英文小写字母、数字、下划线、中横杠和正斜杠, 控制器ID应仅包含英文小写字母、数字、下划线、中横杠和正斜杠,
例如 `article``post-comment` 是真实的控制器 例如 `article``post-comment` 是真是的控制器ID,
ID,`article?`, `PostComment`, `admin\post`不是控制器ID。 `article?`, `PostComment`, `admin\post`不是控制器ID。
控制器Id可包含子目录前缀,例如 `admin/article` 代表 控制器Id可包含子目录前缀,例如 `admin/article` 代表
[[yii\base\Application::controllerNamespace|controller namespace]]控制器命名空间下 `admin`子目录中 `article` 控制器。 [[yii\base\Application::controllerNamespace|controller namespace]]
子目录前缀可为英文大小写字母、数字、下划线、正斜杠, 控制器命名空间下 `admin`子目录中 `article` 控制器。
其中正斜杠用来区分多级子目录(如 `panels/admin`)。 子目录前缀可为英文大小写字母、数字、下划线、正斜杠,其中正斜杠用来区分多级子目录(如 `panels/admin`)。
### 控制器类命名 <span id="controller-class-naming"></span> ### 控制器类命名 <span id="controller-class-naming"></span>
@ -176,10 +176,10 @@ ID,`article?`, `PostComment`, `admin\post`不是控制器ID。
### 默认控制器 <span id="default-controller"></span> ### 默认控制器 <span id="default-controller"></span>
每个应用有一个由[[yii\base\Application::defaultRoute]]属性指定的默认控制器;当请求没有指定 [路由](#ids-routes),该属性值作为路由使用。 每个应用有一个由[[yii\base\Application::defaultRoute]]属性指定的默认控制器;
对于[[yii\web\Application|Web applications]]网页应用,它的值为 `'site'` 当请求没有指定 [路由](#ids-routes),该属性值作为路由使用。
对于 [[yii\console\Application|console applications]]控制台应用,它的值为 `help` 对于[[yii\web\Application|Web applications]]网页应用,它的值为 `'site'`,对于 [[yii\console\Application|console applications]]
所以URL为 `http://hostname/index.php` 表示由 `site` 控制器来处理。 控制台应用,它的值为 `help`所以URL为 `http://hostname/index.php` 表示由 `site` 控制器来处理。
可以在 [应用配置](structure-applications.md#application-configurations) 中修改默认控制器,如下所示: 可以在 [应用配置](structure-applications.md#application-configurations) 中修改默认控制器,如下所示:
@ -192,9 +192,9 @@ ID,`article?`, `PostComment`, `admin\post`不是控制器ID。
## 创建动作 <span id="creating-actions"></span> ## 创建动作 <span id="creating-actions"></span>
创建作可简单地在控制器类中定义所谓的 *操作方法* 来完成,操作方法必须是以`action`开头的公有方法。 创建作可简单地在控制器类中定义所谓的 *操作方法* 来完成,操作方法必须是以`action`开头的公有方法。
作方法的返回值会作为响应数据发送给终端用户, 作方法的返回值会作为响应数据发送给终端用户,
如下代码定义了两个`index``hello-world`: 如下代码定义了两个`index``hello-world`:
```php ```php
namespace app\controllers; namespace app\controllers;
@ -218,17 +218,17 @@ class SiteController extends Controller
### 动作ID <span id="action-ids"></span> ### 动作ID <span id="action-ids"></span>
作通常是用来执行资源的特定操作,因此, 作通常是用来执行资源的特定操作,因此,
作ID通常为动词,如`view`, `update`等。 作ID通常为动词,如`view`, `update`等。
作ID应仅包含英文小写字母、数字、下划线和中横杠,操作ID中的中横杠用来分隔单词。 作ID应仅包含英文小写字母、数字、下划线和中横杠,操作ID中的中横杠用来分隔单词。
例如`view`, `update2`, `comment-post`是真实的动作 例如`view`, `update2`, `comment-post`是真实的操作ID,
ID,`view?`, `Update`不是动作ID. `view?`, `Update`不是操作ID.
可通过两种方式创建动作ID,内联动作和独立动作. An inline action is 可通过两种方式创建操作ID,内联操作和独立操作. An inline action is
内联动作在控制器类中定义为方法;独立动作是继承[[yii\base\Action]]或它的子类的类。 内联操作在控制器类中定义为方法;独立操作是继承[[yii\base\Action]]或它的子类的类。
内联作容易创建,在无需重用的情况下优先使用; 内联作容易创建,在无需重用的情况下优先使用;
独立作相反,主要用于多个控制器重用, 独立作相反,主要用于多个控制器重用,
或重构为[扩展](structure-extensions.md)。 或重构为[扩展](structure-extensions.md)。
@ -238,30 +238,30 @@ ID,`view?`, `Update`不是动作ID.
动作方法的名字是根据操作ID遵循如下规则衍生: 动作方法的名字是根据操作ID遵循如下规则衍生:
* 将每个单词的第一个字母转为大写; 1. 将每个单词的第一个字母转为大写;
* 去掉中横杠; 2. 去掉中横杠;
* 增加`action`前缀. 3. 增加`action`前缀.
例如`index` 转成 `actionIndex`, `hello-world` 转成 `actionHelloWorld` 例如`index` 转成 `actionIndex`, `hello-world` 转成 `actionHelloWorld`
> Note: 作方法的名字*大小写敏感*,如果方法名称为`ActionIndex`不会认为是操作方法, > Note: 作方法的名字*大小写敏感*,如果方法名称为`ActionIndex`不会认为是操作方法,
所以请求`index`作会返回一个异常, 所以请求`index`作会返回一个异常,
也要注意作方法必须是公有的, 也要注意作方法必须是公有的,
私有或者受保护的方法不能定义成内联作。 私有或者受保护的方法不能定义成内联作。
因为容易创建,内联作是最常用的操作, 因为容易创建,内联作是最常用的操作,
但是如果你计划在不同地方重用相同的作, 但是如果你计划在不同地方重用相同的作,
或者你想重新分配一个动作,需要考虑定义它为*独立动作*。 或者你想重新分配一个操作,需要考虑定义它为*独立操作*。
### 独立动作 <span id="standalone-actions"></span> ### 独立动作 <span id="standalone-actions"></span>
独立作通过继承[[yii\base\Action]]或它的子类来定义。 独立作通过继承[[yii\base\Action]]或它的子类来定义。
例如Yii发布的[[yii\web\ViewAction]]和[[yii\web\ErrorAction]] 例如Yii发布的[[yii\web\ViewAction]]
都是独立动作。 和[[yii\web\ErrorAction]]都是独立操作。
要使用独立作,需要通过控制器中覆盖[[yii\base\Controller::actions()]]方法在*action map*中申明, 要使用独立作,需要通过控制器中覆盖[[yii\base\Controller::actions()]]方法在*action map*中申明,
如下例所示: 如下例所示:
```php ```php
@ -280,12 +280,12 @@ public function actions()
} }
``` ```
如上所示, `actions()` 方法返回键为动作ID、值为对应操作类名或数组[configurations](concept-configurations.md) 的数组。 如上所示, `actions()` 方法返回键为操作ID、值为对应操作类名
和内联动作不同,独立动作ID可包含任意字符, 或数组[configurations](concept-configurations.md) 的数组。
只要在`actions()` 方法中申明. 和内联操作不同,独立操作ID可包含任意字符,只要在`actions()` 方法中申明.
为创建一个独立作类,需要继承[[yii\base\Action]] 或它的子类,并实现公有的名称为`run()`的方法, 为创建一个独立作类,需要继承[[yii\base\Action]] 或它的子类,并实现公有的名称为`run()`的方法,
`run()` 方法的角色和作方法类似,例如: `run()` 方法的角色和作方法类似,例如:
```php ```php
<?php <?php
@ -305,8 +305,8 @@ class HelloWorldAction extends Action
### 动作结果 <span id="action-results"></span> ### 动作结果 <span id="action-results"></span>
作方法或独立操作的`run()`方法的返回值非常重要, 作方法或独立操作的`run()`方法的返回值非常重要,
它表示对应作结果。 它表示对应作结果。
返回值可为 [响应](runtime-responses.md) 对象,作为响应发送给终端用户。 返回值可为 [响应](runtime-responses.md) 对象,作为响应发送给终端用户。
@ -315,8 +315,8 @@ class HelloWorldAction extends Action
* 对于[[yii\console\Application|console applications]]控制台应用,返回值可为整数, * 对于[[yii\console\Application|console applications]]控制台应用,返回值可为整数,
表示命令行下执行的 [[yii\console\Response::exitStatus|exit status]] 退出状态。 表示命令行下执行的 [[yii\console\Response::exitStatus|exit status]] 退出状态。
在上面的例子中,作结果都为字符串,作为响应数据发送给终端用户, 在上面的例子中,作结果都为字符串,作为响应数据发送给终端用户,
下例显示一个作通过 下例显示一个作通过
返回响应对象(因为[[yii\web\Controller::redirect()|redirect()]]方法返回一个响应对象) 返回响应对象(因为[[yii\web\Controller::redirect()|redirect()]]方法返回一个响应对象)
可将用户浏览器跳转到新的URL。 可将用户浏览器跳转到新的URL。
@ -356,8 +356,8 @@ class PostController extends Controller
* `http://hostname/index.php?r=post/view&id=123`: `$id` 会填入`'123'`, * `http://hostname/index.php?r=post/view&id=123`: `$id` 会填入`'123'`,
`$version` 仍为 null 空因为没有`version`请求参数; `$version` 仍为 null 空因为没有`version`请求参数;
* `http://hostname/index.php?r=post/view&id=123&version=2`: $id` 和 `$version` * `http://hostname/index.php?r=post/view&id=123&version=2`:
分别填入 `'123'``'2'` $id` 和 `$version` 分别填入 `'123'``'2'`
* `http://hostname/index.php?r=post/view`: 会抛出[[yii\web\BadRequestHttpException]] 异常 * `http://hostname/index.php?r=post/view`: 会抛出[[yii\web\BadRequestHttpException]] 异常
因为请求没有提供参数给必须赋值参数`$id`; 因为请求没有提供参数给必须赋值参数`$id`;
* `http://hostname/index.php?r=post/view&id[]=123`: 会抛出[[yii\web\BadRequestHttpException]] 异常 * `http://hostname/index.php?r=post/view&id[]=123`: 会抛出[[yii\web\BadRequestHttpException]] 异常
@ -376,18 +376,18 @@ public function actionView(array $id, $version = null)
如果请求为 `http://hostname/index.php?r=post/view&id=123` 如果请求为 `http://hostname/index.php?r=post/view&id=123`
参数 `$id` 会获取相同数组值,因为无类型的`'123'`会自动转成数组。 参数 `$id` 会获取相同数组值,因为无类型的`'123'`会自动转成数组。
上述例子主要描述网页应用的作参数,对于控制台应用, 上述例子主要描述网页应用的作参数,对于控制台应用,
更多详情请参阅[控制台命令](tutorial-console.md)。 更多详情请参阅[控制台命令](tutorial-console.md)。
### 默认动作 <span id="default-action"></span> ### 默认动作 <span id="default-action"></span>
每个控制器都有一个由 [[yii\base\Controller::defaultAction]] 属性指定的默认作, 每个控制器都有一个由 [[yii\base\Controller::defaultAction]] 属性指定的默认作,
当[路由](#ids-routes) 只包含控制器ID, 当[路由](#ids-routes) 只包含控制器ID,
会使用所请求的控制器的默认作。 会使用所请求的控制器的默认作。
默认动作默认为 `index`,如果想修改默认动作 默认操作默认为 `index`,如果想修改默认操作,只需简单地在控制器类中覆盖这个属性
只需简单地在控制器类中覆盖这个属性,如下所示: 如下所示:
```php ```php
namespace app\controllers; namespace app\controllers;
@ -408,33 +408,33 @@ class SiteController extends Controller
## 控制器生命周期 <span id="controller-lifecycle"></span> ## 控制器生命周期 <span id="controller-lifecycle"></span>
处理一个请求时, 处理一个请求时,[应用主体](structure-applications.md) 会根据请求
[应用主体](structure-applications.md) 会根据请求[路由](#routes)创建一个控制器, [路由](#routes)创建一个控制器,
控制器经过以下生命周期来完成请求: 控制器经过以下生命周期来完成请求:
1. 在控制器创建和配置后,[[yii\base\Controller::init()]] 方法会被调用。 1. 在控制器创建和配置后,[[yii\base\Controller::init()]] 方法会被调用。
2. 控制器根据请求作ID创建一个操作对象: 2. 控制器根据请求作ID创建一个操作对象:
* 如果作ID没有指定,会使用[[yii\base\Controller::defaultAction|default action ID]]默认操作ID; * 如果作ID没有指定,会使用[[yii\base\Controller::defaultAction|default action ID]]默认操作ID;
* 如果在[[yii\base\Controller::actions()|action map]]找到作ID, * 如果在[[yii\base\Controller::actions()|action map]]找到作ID,
会创建一个独立作; 会创建一个独立作;
* 如果作ID对应操作方法,会创建一个内联操作; * 如果作ID对应操作方法,会创建一个内联操作;
* 否则会抛出[[yii\base\InvalidRouteException]]异常。 * 否则会抛出[[yii\base\InvalidRouteException]]异常。
3. 控制器按顺序调用应用主体、模块(如果控制器属于模块)、 3. 控制器按顺序调用应用主体、模块(如果控制器属于模块)、
控制器的 `beforeAction()` 方法; 控制器的 `beforeAction()` 方法;
* 如果任意一个调用返回false,后面未调用的`beforeAction()`会跳过并且作执行会被取消; * 如果任意一个调用返回false,后面未调用的`beforeAction()`会跳过并且作执行会被取消;
action execution will be cancelled. action execution will be cancelled.
* 默认情况下每个 `beforeAction()` 方法会触发一个 `beforeAction` 事件,在事件中你可以追加事件处理作; * 默认情况下每个 `beforeAction()` 方法会触发一个 `beforeAction` 事件,在事件中你可以追加事件处理作;
4. 控制器执行作: 4. 控制器执行作:
* 请求数据解析和填入到作参数; * 请求数据解析和填入到作参数;
5. 控制器按顺序调用控制器、模块(如果控制器属于模块)、 5. 控制器按顺序调用控制器、模块(如果控制器属于模块)、应用主体的 `afterAction()` 方法;
应用主体的 `afterAction()` 方法; * 默认情况下每个 `afterAction()` 方法会触发一个 `afterAction` 事件,
* 默认情况下每个 `afterAction()` 方法会触发一个 `afterAction` 事件,在事件中你可以追加事件处理动作; 在事件中你可以追加事件处理操作;
6. 应用主体获取作结果并赋值给[响应](runtime-responses.md). 6. 应用主体获取作结果并赋值给[响应](runtime-responses.md).
## 最佳实践 <span id="best-practices"></span> ## 最佳实践 <span id="best-practices"></span>
在设计良好的应用中,控制器很精练,包含的作代码简短; 在设计良好的应用中,控制器很精练,包含的作代码简短;
如果你的控制器很复杂,通常意味着需要重构, 如果你的控制器很复杂,通常意味着需要重构,
转移一些代码到其他类中。 转移一些代码到其他类中。

9
docs/guide-zh-CN/structure-entry-scripts.md

@ -63,6 +63,7 @@ $config = require(__DIR__ . '/../config/web.php');
*/ */
defined('YII_DEBUG') or define('YII_DEBUG', true); defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');
// 注册 Composer 自动加载器 // 注册 Composer 自动加载器
require(__DIR__ . '/vendor/autoload.php'); require(__DIR__ . '/vendor/autoload.php');
@ -83,11 +84,11 @@ exit($exitCode);
入口脚本是定义全局常量的最好地方,Yii 支持以下三个常量: 入口脚本是定义全局常量的最好地方,Yii 支持以下三个常量:
* `YII_DEBUG`:标识应用是否运行在调试模式。当在调试模式下, * `YII_DEBUG`:标识应用是否运行在调试模式。当在调试模式下,应用会保留更多日志信息,
应用会保留更多日志信息,如果抛出异常,会显示详细的错误调用堆栈。 如果抛出异常,会显示详细的错误调用堆栈。
因此,调试模式主要适合在开发阶段使用,`YII_DEBUG` 默认值为 false。 因此,调试模式主要适合在开发阶段使用,`YII_DEBUG` 默认值为 false。
* `YII_ENV`:标识应用运行的环境, * `YII_ENV`:标识应用运行的环境,详情请查阅
详情请查阅[配置](concept-configurations.md#environment-constants)章节。 [配置](concept-configurations.md#environment-constants)章节。
`YII_ENV` 默认值为 `'prod'`,表示应用运行在线上产品环境。 `YII_ENV` 默认值为 `'prod'`,表示应用运行在线上产品环境。
* `YII_ENABLE_ERROR_HANDLER`:标识是否启用 Yii 提供的错误处理, * `YII_ENABLE_ERROR_HANDLER`:标识是否启用 Yii 提供的错误处理,
默认为 true。 默认为 true。

44
docs/guide-zh-CN/structure-filters.md

@ -11,9 +11,9 @@
## 使用过滤器 <span id="using-filters"></span> ## 使用过滤器 <span id="using-filters"></span>
过滤器本质上是一类特殊的 [行为](concept-behaviors.md),所以使用过滤器和 [使用 行为](concept-behaviors.md#attaching-behaviors)一样。 过滤器本质上是一类特殊的 [行为](concept-behaviors.md),
可以在控制器类中覆盖它的 [[yii\base\Controller::behaviors()|behaviors()]] 方法来申明过滤器, 所以使用过滤器和 [使用 行为](concept-behaviors.md#attaching-behaviors)一样。
如下所示: 可以在控制器类中覆盖它的 [[yii\base\Controller::behaviors()|behaviors()]] 方法来申明过滤器,如下所示:
```php ```php
public function behaviors() public function behaviors()
@ -33,9 +33,9 @@ public function behaviors()
控制器类的过滤器默认应用到该类的 *所有* 动作, 控制器类的过滤器默认应用到该类的 *所有* 动作,
你可以配置[[yii\base\ActionFilter::only|only]]属性明确指定控制器应用到哪些动作。 你可以配置[[yii\base\ActionFilter::only|only]]属性明确指定控制器应用到哪些动作。
在上述例子中, 在上述例子中,`HttpCache` 过滤器只应用到`index`和`view`动作。
`HttpCache` 过滤器只应用到`index`和`view`动作。 也可以配置[[yii\base\ActionFilter::except|except]]属性
也可以配置[[yii\base\ActionFilter::except|except]]属性使一些动作不执行过滤器。 使一些动作不执行过滤器。
除了控制器外,可在 [模块](structure-modules.md)或[应用主体](structure-applications.md) 中申明过滤器。 除了控制器外,可在 [模块](structure-modules.md)或[应用主体](structure-applications.md) 中申明过滤器。
申明之后,过滤器会应用到所属该模块或应用主体的 *所有* 控制器动作, 申明之后,过滤器会应用到所属该模块或应用主体的 *所有* 控制器动作,
@ -106,8 +106,8 @@ Yii提供了一组常用过滤器,在`yii\filters`命名空间下,
### [[yii\filters\AccessControl|AccessControl]] <span id="access-control"></span> ### [[yii\filters\AccessControl|AccessControl]] <span id="access-control"></span>
AccessControl提供基于[[yii\filters\AccessControl::rules|rules]]规则的访问控制。 AccessControl提供基于[[yii\filters\AccessControl::rules|rules]]规则的访问控制。
特别是在动作执行之前, 特别是在动作执行之前,访问控制会检测所有规则
访问控制会检测所有规则并找到第一个符合上下文的变量(比如用户IP地址、登录状态等等)的规则, 并找到第一个符合上下文的变量(比如用户IP地址、登录状态等等)的规则,
来决定允许还是拒绝请求动作的执行, 来决定允许还是拒绝请求动作的执行,
如果没有规则符合,访问就会被拒绝。 如果没有规则符合,访问就会被拒绝。
@ -141,9 +141,9 @@ public function behaviors()
### 认证方法过滤器 <span id="auth-method-filters"></span> ### 认证方法过滤器 <span id="auth-method-filters"></span>
认证方法过滤器通过[HTTP Basic Auth](http://en.wikipedia.org/wiki/Basic_access_authentication)或[OAuth 2](http://oauth.net/2/) 认证方法过滤器通过[HTTP Basic Auth](http://en.wikipedia.org/wiki/Basic_access_authentication)
来认证一个用户, 或[OAuth 2](http://oauth.net/2/)
认证方法过滤器类在 `yii\filters\auth` 命名空间下。 来认证一个用户,认证方法过滤器类在 `yii\filters\auth` 命名空间下。
如下示例表示可使用[[yii\filters\auth\HttpBasicAuth]]来认证一个用户, 如下示例表示可使用[[yii\filters\auth\HttpBasicAuth]]来认证一个用户,
它使用基于HTTP基础认证方法的令牌。 它使用基于HTTP基础认证方法的令牌。
@ -172,8 +172,8 @@ public function behaviors()
ContentNegotiator支持响应内容格式处理和语言处理。 ContentNegotiator支持响应内容格式处理和语言处理。
通过检查 `GET` 参数和 `Accept` HTTP头部来决定响应内容格式和语言。 通过检查 `GET` 参数和 `Accept` HTTP头部来决定响应内容格式和语言。
如下示例,配置ContentNegotiator支持JSON和XML响应格式 如下示例,配置ContentNegotiator支持JSON和XML
和英语(美国)和德语。 响应格式和英语(美国)和德语。
```php ```php
use yii\filters\ContentNegotiator; use yii\filters\ContentNegotiator;
@ -224,7 +224,7 @@ use yii\web\Response;
]; ];
``` ```
> 补充: 如果请求中没有检测到内容格式和语言, > Info: 如果请求中没有检测到内容格式和语言,
使用[[formats]]和[[languages]]第一个配置项。 使用[[formats]]和[[languages]]第一个配置项。
@ -290,8 +290,8 @@ public function behaviors()
### [[yii\filters\RateLimiter|RateLimiter]] <span id="rate-limiter"></span> ### [[yii\filters\RateLimiter|RateLimiter]] <span id="rate-limiter"></span>
RateLimiter 根据 [漏桶算法](http://en.wikipedia.org/wiki/Leaky_bucket) 来实现速率限制。 RateLimiter 根据 [漏桶算法](http://en.wikipedia.org/wiki/Leaky_bucket) 来实现速率限制。
主要用在实现RESTful APIs, 主要用在实现RESTful APIs,更多关于该过滤器详情请参阅
更多关于该过滤器详情请参阅 [Rate Limiting](rest-rate-limiting.md) 一节。 [Rate Limiting](rest-rate-limiting.md) 一节。
### [[yii\filters\VerbFilter|VerbFilter]] <span id="verb-filter"></span> ### [[yii\filters\VerbFilter|VerbFilter]] <span id="verb-filter"></span>
@ -322,7 +322,8 @@ public function behaviors()
### [[yii\filters\Cors|Cors]] <span id="cors"></span> ### [[yii\filters\Cors|Cors]] <span id="cors"></span>
跨域资源共享 [CORS](https://developer.mozilla.org/fr/docs/HTTP/Access_control_CORS) 机制允许一个网页的许多资源(例如字体、JavaScript等) 跨域资源共享 [CORS](https://developer.mozilla.org/fr/docs/HTTP/Access_control_CORS)
机制允许一个网页的许多资源(例如字体、JavaScript等)
这些资源可以通过其他域名访问获取。 这些资源可以通过其他域名访问获取。
特别是JavaScript's AJAX 调用可使用 XMLHttpRequest 机制, 特别是JavaScript's AJAX 调用可使用 XMLHttpRequest 机制,
由于同源安全策略该跨域请求会被网页浏览器禁止. 由于同源安全策略该跨域请求会被网页浏览器禁止.
@ -345,7 +346,10 @@ public function behaviors()
} }
``` ```
Cors 可转为使用 `cors` 属性。 Also check the section on [REST Controllers](rest-controllers.md#cors) if you want to add the CORS filter to an
[[yii\rest\ActiveController]] class in your API.
The Cors filtering could be tuned using the [[yii\filters\Cors::$cors|$cors]] property.
* `cors['Origin']`: 定义允许来源的数组,可为`['*']` (任何用户) 或 `['http://www.myserver.net', 'http://www.myotherserver.com']`. 默认为 `['*']`. * `cors['Origin']`: 定义允许来源的数组,可为`['*']` (任何用户) 或 `['http://www.myserver.net', 'http://www.myotherserver.com']`. 默认为 `['*']`.
* `cors['Access-Control-Request-Method']`: 允许动作数组如 `['GET', 'OPTIONS', 'HEAD']`. 默认为 `['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']`. * `cors['Access-Control-Request-Method']`: 允许动作数组如 `['GET', 'OPTIONS', 'HEAD']`. 默认为 `['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS']`.
@ -373,8 +377,8 @@ public function behaviors()
} }
``` ```
可以覆盖默认参数为每个动作调整CORS 头部。例如, 可以覆盖默认参数为每个动作调整CORS 头部。例如,为`login`动作
为`login`动作增加`Access-Control-Allow-Credentials`参数如下所示: 增加`Access-Control-Allow-Credentials`参数如下所示:
```php ```php
use yii\filters\Cors; use yii\filters\Cors;

75
docs/guide-zh-CN/structure-models.md

@ -36,8 +36,8 @@ $model->name = 'example';
echo $model->name; echo $model->name;
``` ```
也可像访问数组单元项一样访问属性,这要感谢 [[yii\base\Model]] 也可像访问数组单元项一样访问属性,这要感谢[[yii\base\Model]]支持
支持 [ArrayAccess 数组访问](http://php.net/manual/en/class.arrayaccess.php) [ArrayAccess 数组访问](http://php.net/manual/en/class.arrayaccess.php)
和 [ArrayIterator 数组迭代器](http://php.net/manual/en/class.arrayiterator.php): 和 [ArrayIterator 数组迭代器](http://php.net/manual/en/class.arrayiterator.php):
```php ```php
@ -75,8 +75,8 @@ class ContactForm extends Model
``` ```
另一种方式是可覆盖 [[yii\base\Model::attributes()]] 来定义属性, 另一种方式是可覆盖 [[yii\base\Model::attributes()]]
该方法返回模型的属性名。 来定义属性,该方法返回模型的属性名。
例如 [[yii\db\ActiveRecord]] 返回对应数据表列名作为它的属性名, 例如 [[yii\db\ActiveRecord]] 返回对应数据表列名作为它的属性名,
注意可能需要覆盖魔术方法如`__get()`, 注意可能需要覆盖魔术方法如`__get()`,
`__set()`使属性像普通对象属性被访问。 `__set()`使属性像普通对象属性被访问。
@ -84,9 +84,9 @@ class ContactForm extends Model
### 属性标签 <span id="attribute-labels"></span> ### 属性标签 <span id="attribute-labels"></span>
当属性显示或获取输入时,经常要显示属性相关标签,例如假定一个属性名为`firstName`, 当属性显示或获取输入时,经常要显示属性相关标签,
在某些地方如表单输入或错误信息处 例如假定一个属性名为`firstName`
你可能想显示对终端用户来说更友好的 `First Name` 标签。 在某些地方如表单输入或错误信息处,你可能想显示对终端用户来说更友好的 `First Name` 标签。
可以调用 [[yii\base\Model::getAttributeLabel()]] 获取属性的标签,例如: 可以调用 [[yii\base\Model::getAttributeLabel()]] 获取属性的标签,例如:
@ -102,8 +102,8 @@ echo $model->getAttributeLabel('name');
例如 `username` 转换为 `Username` 例如 `username` 转换为 `Username`
`firstName` 转换为 `First Name` `firstName` 转换为 `First Name`
如果你不想用自动生成的标签, 如果你不想用自动生成的标签,可以覆盖 [[yii\base\Model::attributeLabels()]] 方法明确指定属性标签,
可以覆盖 [[yii\base\Model::attributeLabels()]] 方法明确指定属性标签,例如: 例如:
```php ```php
namespace app\models; namespace app\models;
@ -147,8 +147,8 @@ public function attributeLabels()
甚至可以根据条件定义标签,例如通过使用模型的 [scenario场景](#scenarios), 甚至可以根据条件定义标签,例如通过使用模型的 [scenario场景](#scenarios),
可对相同的属性返回不同的标签。 可对相同的属性返回不同的标签。
> 注意:属性标签是 [视图](structure-views.md)一部分,但是在模型中申明标签通常非常方便 > Info: 属性标签是 [视图](structure-views.md)一部分,
并可行程非常简洁可重用代码。 但是在模型中申明标签通常非常方便,并可行程非常简洁可重用代码。
## 场景 <span id="scenarios"></span> ## 场景 <span id="scenarios"></span>
@ -234,9 +234,9 @@ class User extends ActiveRecord
## 验证规则 <span id="validation-rules"></span> ## 验证规则 <span id="validation-rules"></span>
当模型接收到终端用户输入的数据,数据应当满足某种规则(称为 *验证规则*, 也称为 *业务规则*)。 当模型接收到终端用户输入的数据,
例如假定`ContactForm`模型, 数据应当满足某种规则(称为 *验证规则*, 也称为 *业务规则*)。
你可能想确保所有属性不为空且 `email` 属性包含一个有效的邮箱地址, 例如假定`ContactForm`模型,你可能想确保所有属性不为空且 `email` 属性包含一个有效的邮箱地址,
如果某个属性的值不满足对应的业务规则, 如果某个属性的值不满足对应的业务规则,
相应的错误信息应显示,以帮助用户修正错误。 相应的错误信息应显示,以帮助用户修正错误。
@ -260,8 +260,8 @@ if ($model->validate()) {
``` ```
通过覆盖 [[yii\base\Model::rules()]] 方法指定 通过覆盖 [[yii\base\Model::rules()]] 方法指定模型
模型属性应该满足的规则来申明模型相关验证规则。 属性应该满足的规则来申明模型相关验证规则。
下述例子显示`ContactForm`模型申明的验证规则: 下述例子显示`ContactForm`模型申明的验证规则:
```php ```php
@ -279,10 +279,10 @@ public function rules()
一条规则可用来验证一个或多个属性,一个属性可对应一条或多条规则。 一条规则可用来验证一个或多个属性,一个属性可对应一条或多条规则。
更多关于如何申明验证规则的详情请参考 更多关于如何申明验证规则的详情请参考
[验证输入](input-validation.md) 一节 [验证输入](input-validation.md) 一节.
有时你想一条规则只在某个 [场景](#scenarios) 下应用, 有时你想一条规则只在某个 [场景](#scenarios) 下应用,为此你可以指定规则的 `on` 属性,
为此你可以指定规则的 `on` 属性,如下所示: 如下所示:
```php ```php
public function rules() public function rules()
@ -350,12 +350,12 @@ public function scenarios()
例如,如果 `User` 模型有一个`permission`属性对应用户的权限, 例如,如果 `User` 模型有一个`permission`属性对应用户的权限,
你可能只想让这个属性在后台界面被管理员修改。 你可能只想让这个属性在后台界面被管理员修改。
由于默认[[yii\base\Model::scenarios()]]的实现 由于默认[[yii\base\Model::scenarios()]]的实现会返回
会返回[[yii\base\Model::rules()]]所有属性和数据, [[yii\base\Model::rules()]]所有属性和数据,
如果不覆盖这个方法,表示所有只要出现在活动验证规则中的属性都是安全的。 如果不覆盖这个方法,表示所有只要出现在活动验证规则中的属性都是安全的。
为此,提供一个特别的别名为 `safe` 的验证器来 为此,提供一个特别的别名为 `safe` 的验证器来申明
申明哪些属性是安全的不需要被验证, 哪些属性是安全的不需要被验证,
如下示例的规则申明 `title``description` 都为安全属性。 如下示例的规则申明 `title``description` 都为安全属性。
```php ```php
@ -409,8 +409,11 @@ In this case attributes `username`, `password` and `secret` are required, but `s
## 数据导出 <span id="data-exporting"></span> ## 数据导出 <span id="data-exporting"></span>
模型通常要导出成不同格式,例如,你可能想将模型的一个集合转成JSON或Excel格式, 模型通常要导出成不同格式,例如,你可能想将模型的一个集合转成JSON或Excel格式,
导出过程可分解为两个步骤, 导出过程可分解为两个步骤:
第一步,模型转换成数组;第二步,数组转换成所需要的格式。
- 模型转换成数组;
- 数组转换成所需要的格式。
你只需要关注第一步,因为第二步可被通用的 你只需要关注第一步,因为第二步可被通用的
数据转换器如[[yii\web\JsonResponseFormatter]]来完成。 数据转换器如[[yii\web\JsonResponseFormatter]]来完成。
@ -438,12 +441,12 @@ $array = $post->attributes;
生成的数组的单元名。 生成的数组的单元名。
默认情况下,字段名对应属性名,但是你可以通过覆盖 默认情况下,字段名对应属性名,但是你可以通过覆盖
[[yii\base\Model::fields()|fields()]] 和/或 [[yii\base\Model::extraFields()|extraFields()]] 方法来改变这种行为, [[yii\base\Model::fields()|fields()]] 和/或
[[yii\base\Model::extraFields()|extraFields()]] 方法来改变这种行为,
两个方法都返回一个字段定义列表,`fields()` 方法定义的字段是默认字段, 两个方法都返回一个字段定义列表,`fields()` 方法定义的字段是默认字段,
表示`toArray()`方法默认会返回这些字段。 表示`toArray()`方法默认会返回这些字段。 `extraFields()`方法定义额外可用字段,
`extraFields()`方法定义额外可用字段,通过`toArray()`方法指定`$expand`参数来返回这些额外可用字段。 通过`toArray()`方法指定`$expand`参数来返回这些额外可用字段。
例如如下代码会返回`fields()`方法定义的所有字段 例如如下代码会返回`fields()`方法定义的所有字段和`extraFields()`方法定义的`prettyName` and `fullAddress`字段。
和`extraFields()`方法定义的`prettyName` and `fullAddress`字段。
```php ```php
$array = $model->toArray([], ['prettyName', 'fullAddress']); $array = $model->toArray([], ['prettyName', 'fullAddress']);
@ -474,8 +477,8 @@ public function fields()
]; ];
} }
// 过滤掉一些字段,特别用于你想 // 过滤掉一些字段,特别用于
// 继承父类实现并不想用一些敏感字段 // 你想继承父类实现并不想用一些敏感字段
public function fields() public function fields()
{ {
$fields = parent::fields(); $fields = parent::fields();
@ -496,8 +499,8 @@ public function fields()
## 最佳实践 <span id="best-practices"></span> ## 最佳实践 <span id="best-practices"></span>
模型是代表业务数据、规则和逻辑的中心地方,通常在很多地方重用, 模型是代表业务数据、规则和逻辑的中心地方,通常在很多地方重用,
在一个设计良好的应用中, 在一个设计良好的应用中,模型通常比
模型通常比[控制器](structure-controllers.md)代码多。 [控制器](structure-controllers.md)代码多。
归纳起来,模型 归纳起来,模型
@ -526,5 +529,5 @@ public function fields()
你可以定义一个模型基类`common\models\Post`, 你可以定义一个模型基类`common\models\Post`,
然后在前台应用中,定义并使用一个继承`common\models\Post`的具体模型类`frontend\models\Post`, 然后在前台应用中,定义并使用一个继承`common\models\Post`的具体模型类`frontend\models\Post`,
在后台应用中可以类似地定义`backend\models\Post`。 在后台应用中可以类似地定义`backend\models\Post`。
通过这种策略,你清楚`frontend\models\Post`只对应前台应用, 通过这种策略,你清楚`frontend\models\Post`只对应前台应用,如果你修改它,
如果你修改它,就无需担忧修改会影响后台应用。 就无需担忧修改会影响后台应用。

45
docs/guide-zh-CN/structure-modules.md

@ -31,8 +31,8 @@ forum/
每个模块都有一个继承[[yii\base\Module]]的模块类, 每个模块都有一个继承[[yii\base\Module]]的模块类,
该类文件直接放在模块的[[yii\base\Module::basePath|base path]]目录下, 该类文件直接放在模块的[[yii\base\Module::basePath|base path]]目录下,
并且能被 [自动加载](concept-autoloading.md)。 并且能被 [自动加载](concept-autoloading.md)。当一个模块被访问,
当一个模块被访问,和 [应用主体实例](structure-applications.md) 和 [应用主体实例](structure-applications.md)
类似会创建该模块类唯一实例,模块实例用来帮模块内代码共享数据和组件。 类似会创建该模块类唯一实例,模块实例用来帮模块内代码共享数据和组件。
以下示例一个模块类大致定义: 以下示例一个模块类大致定义:
@ -64,8 +64,8 @@ public function init()
} }
``` ```
`config.php`配置文件可能包含以下内容, `config.php`配置文件可能包含以下内容,类似
类似[应用主体配置](structure-applications.md#application-configurations). [应用主体配置](structure-applications.md#application-configurations).
```php ```php
<?php <?php
@ -122,10 +122,10 @@ class PostController extends Controller
您的模块也可以声明命令,这将通过 [控制台](tutorial-console.md) 模式可用。 您的模块也可以声明命令,这将通过 [控制台](tutorial-console.md) 模式可用。
当 Yii 在控制台模式下执行,并指向你的命令的命名空间,为了让命令行实用程序看到您的命令,您需要更改 [[yii\base\Module::controllerNamespace]] In order for the command line utility to see your commands, you will need to change the [[yii\base\Module::controllerNamespace]]
属性。 property, when Yii is executed in the console mode, and point it to your commands namespace.
一种实现方法是在模块的 `init` 方法中测试Yii应用程序的实例类型: 一种实现方法是在模块的 `init()` 方法中测试Yii应用程序的实例类型
```php ```php
public function init() public function init()
@ -137,7 +137,7 @@ public function init()
} }
``` ```
然后可以使用以下路由从命令行使用您的命令 然后您的命令将从命令行使用以下路由
``` ```
yii <module_id>/<command>/<sub_command> yii <module_id>/<command>/<sub_command>
@ -169,11 +169,11 @@ yii <module_id>/<command>/<sub_command>
和访问应用的控制器类似,[路由](structure-controllers.md#routes) 和访问应用的控制器类似,[路由](structure-controllers.md#routes)
也用在模块中控制器的寻址, 也用在模块中控制器的寻址,
模块中控制器的路由必须以模块ID开始,接下来为控制器ID和作ID。 模块中控制器的路由必须以模块ID开始,接下来为控制器ID和作ID。
例如,假定应用使用一个名为 `forum` 模块, 例如,假定应用使用一个名为 `forum` 模块,
路由`forum/post/index` 代表模块中 `post` 控制器的 `index` 作, 路由`forum/post/index` 代表模块中 `post` 控制器的 `index` 作,
如果路由只包含模块ID,默认为 `default` 如果路由只包含模块ID,默认为 `default`
[[yii\base\Module::defaultRoute]] 属性来决定使用哪个控制器/作, [[yii\base\Module::defaultRoute]] 属性来决定使用哪个控制器/作,
也就是说路由 `forum` 可能代表 `forum` 模块的 `default` 控制器。 也就是说路由 `forum` 可能代表 `forum` 模块的 `default` 控制器。
@ -191,7 +191,7 @@ $module = MyModuleClass::getInstance();
如果模块没有被请求,该方法会返回空,注意不需要手动创建一个模块类, 如果模块没有被请求,该方法会返回空,注意不需要手动创建一个模块类,
因为手动创建的和Yii处理请求时自动创建的不同。 因为手动创建的和Yii处理请求时自动创建的不同。
> 补充: 当开发模块时,你不能假定模块使用固定的ID, > Info: 当开发模块时,你不能假定模块使用固定的ID,
因为在应用或其他没模块中,模块可能会对应到任意的ID, 因为在应用或其他没模块中,模块可能会对应到任意的ID,
为了获取模块ID,应使用上述代码获取模块实例, 为了获取模块ID,应使用上述代码获取模块实例,
然后通过`$module->id`获取模块ID。 然后通过`$module->id`获取模块ID。
@ -238,9 +238,9 @@ $maxPostCount = $module->params['maxPostCount'];
## 模块嵌套 <span id="nested-modules"></span> ## 模块嵌套 <span id="nested-modules"></span>
模块可无限级嵌套,也就是说,模块可以包含另一个包含模块的模块, 模块可无限级嵌套,也就是说,模块可以包含另一个包含模块的模块,我们称前者为*父模块*,后者为*子模块*,
我们称前者为*父模块*,后者为*子模块* 子模块必须在父模块的[[yii\base\Module::modules|modules]]属性中申明
子模块必须在父模块的[[yii\base\Module::modules|modules]]属性中申明,例如: 例如:
```php ```php
namespace app\modules\forum; namespace app\modules\forum;
@ -263,11 +263,11 @@ class Module extends \yii\base\Module
在嵌套模块中的控制器,它的路由应包含它所有祖先模块的ID, 在嵌套模块中的控制器,它的路由应包含它所有祖先模块的ID,
例如`forum/admin/dashboard/index` 代表 例如`forum/admin/dashboard/index` 代表
在模块`forum`中子模块`admin`中`dashboard`控制器的`index`作。 在模块`forum`中子模块`admin`中`dashboard`控制器的`index`作。
> 注意:[[yii\base\Module::getModule()|getModule()]] 方法只返回属直接归属于其父级的子模块。 > Info: The [[yii\base\Module::getModule()|getModule()]] method only returns the child module directly belonging
[[yii\base\Application::loadedModules]] 属性保存加载模块的列表, to its parent. The [[yii\base\Application::loadedModules]] property keeps a list of loaded modules, including both
通过它们的类名索引,包含直接的子节点和嵌套节点。 direct children and nested ones, indexed by their class names.
## 最佳实践 <span id="best-practices"></span> ## 最佳实践 <span id="best-practices"></span>
@ -276,6 +276,7 @@ class Module extends \yii\base\Module
每个组包含一些强相关的特性, 每个组包含一些强相关的特性,
每个特性组可以做成一个模块由特定的开发人员和开发组来开发和维护。 每个特性组可以做成一个模块由特定的开发人员和开发组来开发和维护。
在特性组上,使用模块也是重用代码的好方式,一些常用特性, 在特性组上,使用模块也是重用代码的好方式,
如用户管理,评论管理,可以开发成模块, 一些常用特性,如用户管理,评论管理,可以开发成模块,
这样在相关项目中非常容易被重用。 这样在相关项目中非常容易被重用。

82
docs/guide-zh-CN/structure-views.md

@ -5,8 +5,8 @@
它是展示数据到终端用户的代码,在网页应用中, 它是展示数据到终端用户的代码,在网页应用中,
根据*视图模板*来创建视图,视图模板为PHP脚本文件, 根据*视图模板*来创建视图,视图模板为PHP脚本文件,
主要包含HTML代码和展示类PHP代码,通过[[yii\web\View|view]]应用组件来管理, 主要包含HTML代码和展示类PHP代码,通过[[yii\web\View|view]]应用组件来管理,
该组件主要提供通用方法帮助视图构造和渲染,简单起见, 该组件主要提供通用方法帮助视图构造和渲染,
我们称视图模板或视图模板文件为视图。 简单起见,我们称视图模板或视图模板文件为视图。
## 创建视图 <span id="creating-views"></span> ## 创建视图 <span id="creating-views"></span>
@ -41,18 +41,18 @@ $this->title = 'Login';
来管理和渲染这个视图文件。 来管理和渲染这个视图文件。
除了 `$this`之外,上述示例中的视图有其他预定义变量如 `$model` 除了 `$this`之外,上述示例中的视图有其他预定义变量如 `$model`
这些变量代表从[控制器](structure-controllers.md) 这些变量代表从[控制器](structure-controllers.md)
其他触发[视图渲染](#rendering-views)的对象 *传入* 到视图的数据。 其他触发[视图渲染](#rendering-views)的对象 *传入* 到视图的数据。
> 技巧: 将预定义变量列到视图文件头部注释处,这样可被IDE编辑器识别 > Tip: 将预定义变量列到视图文件头部注释处,
也是生成视图文档的好方法。 这样可被IDE编辑器识别,也是生成视图文档的好方法。
### 安全 <span id="security"></span> ### 安全 <span id="security"></span>
当创建生成HTML页面的视图时, 当创建生成HTML页面的视图时,在显示之前将用户输入数据进行转码和过滤非常重要,
在显示之前将用户输入数据进行转码和过滤非常重要, 否则,你的应用可能会被
否则,你的应用可能会被[跨站脚本](http://en.wikipedia.org/wiki/Cross-site_scripting) 攻击。 [跨站脚本](http://en.wikipedia.org/wiki/Cross-site_scripting) 攻击。
要显示纯文本,先调用 [[yii\helpers\Html::encode()]] 进行转码, 要显示纯文本,先调用 [[yii\helpers\Html::encode()]] 进行转码,
例如如下代码将用户名在显示前先转码: 例如如下代码将用户名在显示前先转码:
@ -230,9 +230,9 @@ echo \Yii::$app->view->renderFile('@app/views/site/license.php');
* 视图名以双斜杠 `//` 开头,对应的视图文件路径为 `@app/views/ViewName` * 视图名以双斜杠 `//` 开头,对应的视图文件路径为 `@app/views/ViewName`
也就是说视图文件在 [[yii\base\Application::viewPath|application's view path]] 路径下找, 也就是说视图文件在 [[yii\base\Application::viewPath|application's view path]] 路径下找,
例如 `//site/about` 对应到 `@app/views/site/about.php` 例如 `//site/about` 对应到 `@app/views/site/about.php`
* 视图名以单斜杠`/`开始,视图文件路径以当前使用[模块](structure-modules.md) 的[[yii\base\Module::viewPath|view path]]开始, * 视图名以单斜杠`/`开始,视图文件路径以当前使用[模块](structure-modules.md)
如果不存在模块,使用`@app/views/ViewName`开始, 的[[yii\base\Module::viewPath|view path]]开始,
例如,如果当前模块为`user`, `/user/create` 对应成 如果不存在模块,使用`@app/views/ViewName`开始,例如,如果当前模块为`user`, `/user/create` 对应成
`@app/modules/user/views/user/create.php`, `@app/modules/user/views/user/create.php`,
如果不在模块中,`/user/create`对应`@app/views/user/create.php`。 如果不在模块中,`/user/create`对应`@app/views/user/create.php`。
* 如果 [[yii\base\View::context|context]] 渲染视图 并且上下文实现了 [[yii\base\ViewContextInterface]], * 如果 [[yii\base\View::context|context]] 渲染视图 并且上下文实现了 [[yii\base\ViewContextInterface]],
@ -240,8 +240,8 @@ echo \Yii::$app->view->renderFile('@app/views/site/license.php');
这种主要用在控制器和小部件中渲染视图,例如 这种主要用在控制器和小部件中渲染视图,例如
如果上下文为控制器`SiteController`,`site/about` 对应到 `@app/views/site/about.php` 如果上下文为控制器`SiteController`,`site/about` 对应到 `@app/views/site/about.php`
* 如果视图渲染另一个视图,包含另一个视图文件的目录以当前视图的文件路径开始, * 如果视图渲染另一个视图,包含另一个视图文件的目录以当前视图的文件路径开始,
例如被视图`@app/views/post/index.php` 例如被视图`@app/views/post/index.php` 渲染的
渲染的 `item` 对应到 `@app/views/post/item` `item` 对应到 `@app/views/post/item`
根据以上规则,在控制器中 `app\controllers\PostController` 调用 `$this->render('view')` 根据以上规则,在控制器中 `app\controllers\PostController` 调用 `$this->render('view')`
实际上渲染 `@app/views/post/view.php` 视图文件,当在该视图文件中调用 `$this->render('_overview')` 实际上渲染 `@app/views/post/view.php` 视图文件,当在该视图文件中调用 `$this->render('_overview')`
@ -281,11 +281,11 @@ The controller ID is: <?= $this->context->id ?>
### 视图间共享数据 <span id="sharing-data-among-views"></span> ### 视图间共享数据 <span id="sharing-data-among-views"></span>
[[yii\base\View|view component]]视图组件提供[[yii\base\View::params|params]]参数 [[yii\base\View|view component]]视图组件提供[[yii\base\View::params|params]]
属性来让不同视图共享数据。 参数属性来让不同视图共享数据。
例如在`about`视图中,可使用如下代码指定当前 例如在`about`视图中,
breadcrumbs的当前部分。 可使用如下代码指定当前breadcrumbs的当前部分。
```php ```php
$this->params['breadcrumbs'][] = 'About Us'; $this->params['breadcrumbs'][] = 'About Us';
@ -314,8 +314,8 @@ $this->params['breadcrumbs'][] = 'About Us';
由于布局也是视图,它可像普通视图一样创建,布局默认存储在`@app/views/layouts`路径下, 由于布局也是视图,它可像普通视图一样创建,布局默认存储在`@app/views/layouts`路径下,
[模块](structure-modules.md)中使用的布局应存储在 [模块](structure-modules.md)中使用的布局应存储在
[[yii\base\Module::basePath|module directory]]模块目录 [[yii\base\Module::basePath|module directory]]模块目录
下的`views/layouts`路径下,可配置[[yii\base\Module::layoutPath]] 下的`views/layouts`路径下,
来自定义应用或模块的布局默认路径。 可配置[[yii\base\Module::layoutPath]]来自定义应用或模块的布局默认路径。
如下示例为一个布局大致内容,注意作为示例,简化了很多代码, 如下示例为一个布局大致内容,注意作为示例,简化了很多代码,
在实际中,你可能想添加更多内容,如头部标签,主菜单等。 在实际中,你可能想添加更多内容,如头部标签,主菜单等。
@ -383,9 +383,9 @@ use yii\helpers\Html;
### 使用布局 <span id="using-layouts"></span> ### 使用布局 <span id="using-layouts"></span>
如[控制器中渲染](#rendering-in-controllers)一节描述,当控制器调用[[yii\base\Controller::render()|render()]] 如[控制器中渲染](#rendering-in-controllers)一节描述,
方法渲染视图时,会同时使用布局到渲染结果中, 当控制器调用[[yii\base\Controller::render()|render()]]
默认会使用`@app/views/layouts/main.php`布局文件。 方法渲染视图时,会同时使用布局到渲染结果中,默认会使用`@app/views/layouts/main.php`布局文件。
可配置[[yii\base\Application::layout]] 或 [[yii\base\Controller::layout]] 使用其他布局文件, 可配置[[yii\base\Application::layout]] 或 [[yii\base\Controller::layout]] 使用其他布局文件,
前者管理所有控制器的布局,后者覆盖前者来控制单个控制器布局。 前者管理所有控制器的布局,后者覆盖前者来控制单个控制器布局。
@ -425,12 +425,12 @@ class PostController extends Controller
布局的值可为: 布局的值可为:
- 路径别名 (如 `@app/views/layouts/main`). - 路径别名 (如 `@app/views/layouts/main`).
- 绝对路径 (如 `/main`): 布局的值以斜杠开始,在应用的[[yii\base\Application::layoutPath|layout path] 布局路径 - 绝对路径 (如 `/main`): 布局的值以斜杠开始,
中查找实际的布局文件, 在应用的[[yii\base\Application::layoutPath|layout path]] 布局路径
布局路径默认为 `@app/views/layouts` 中查找实际的布局文件,布局路径默认为 `@app/views/layouts`
- 相对路径 (如 `main`): 在上下文模块的[[yii\base\Module::layoutPath|layout path]] - 相对路径 (如 `main`): 在上下文模块的[[yii\base\Module::layoutPath|layout path]]布局路径中查找实际的布局文件,
布局路径中查找实际的布局文件, 布局路径默认为[[yii\base\Module::basePath|module directory]]
布局路径默认为[[yii\base\Module::basePath|module directory]]模块目录下的`views/layouts` 目录。 模块目录下的`views/layouts` 目录。
- 布尔值 `false`: 不使用布局。 - 布尔值 `false`: 不使用布局。
布局的值没有包含文件扩展名,默认使用 `.php`作为扩展名。 布局的值没有包含文件扩展名,默认使用 `.php`作为扩展名。
@ -522,9 +522,9 @@ class PostController extends Controller
## 使用视图组件 <span id="using-view-components"></span> ## 使用视图组件 <span id="using-view-components"></span>
[[yii\base\View|View components]]视图组件提供许多视图相关特性, [[yii\base\View|View components]]视图组件提供许多视图相关特性,
可创建[[yii\base\View]]或它的子类实例来获取视图组件, 可创建[[yii\base\View]]或它的子类实例来获取视图组件,大多数情况下主要使用 `view` 应用组件,
大多数情况下主要使用 `view` 应用组件, 可在[应用配置](structure-applications.md#application-configurations)中配置该组件,
可在[应用配置](structure-applications.md#application-configurations)中配置该组件,如下所示: 如下所示:
```php ```php
[ [
@ -573,8 +573,8 @@ $this->title = 'My page title';
### 注册Meta元标签 <span id="registering-meta-tags"></span> ### 注册Meta元标签 <span id="registering-meta-tags"></span>
Web页面通常需要生成各种元标签提供给不同的浏览器,如`<head>`中的页面标题, Web页面通常需要生成各种元标签提供给不同的浏览器,
元标签通常在布局中生成。 如`<head>`中的页面标题,元标签通常在布局中生成。
如果想在内容视图中生成元标签,可在内容视图中调用[[yii\web\View::registerMetaTag()]]方法, 如果想在内容视图中生成元标签,可在内容视图中调用[[yii\web\View::registerMetaTag()]]方法,
如下所示: 如下所示:
@ -607,9 +607,9 @@ $this->registerMetaTag(['name' => 'description', 'content' => 'This website is a
### 注册链接标签 <span id="registering-link-tags"></span> ### 注册链接标签 <span id="registering-link-tags"></span>
和 [Meta标签](#adding-meta-tags) 类似,链接标签有时很实用, 和 [Meta标签](#adding-meta-tags) 类似,链接标签有时很实用,如自定义网站图标,指定Rss订阅,或授权OpenID到其他服务器。
如自定义网站图标,指定Rss订阅,或授权OpenID到其他服务器。 可以和元标签相似的方式调用[[yii\web\View::registerLinkTag()]],
可以和元标签相似的方式调用[[yii\web\View::registerLinkTag()]],例如,在内容视图中注册链接标签如下所示: 例如,在内容视图中注册链接标签如下所示:
```php ```php
$this->registerLinkTag([ $this->registerLinkTag([
@ -656,8 +656,8 @@ $this->registerLinkTag([
## 渲染静态页面 <span id="rendering-static-pages"></span> ## 渲染静态页面 <span id="rendering-static-pages"></span>
静态页面指的是大部分内容为静态的 静态页面指的是大部分内容为静态的不需要控制器传递
不需要控制器传递动态数据的Web页面。 动态数据的Web页面。
可将HTML代码放置在视图中,在控制器中使用以下代码输出静态页面: 可将HTML代码放置在视图中,在控制器中使用以下代码输出静态页面:
@ -716,8 +716,8 @@ http://localhost/index.php?r=site/page&view=about
可遵循以下方法达到这个目标: 可遵循以下方法达到这个目标:
* 使用 [布局](#layouts) 来展示公共代码(如,页面头部、尾部); * 使用 [布局](#layouts) 来展示公共代码(如,页面头部、尾部);
* 将复杂的视图分成几个小视图, * 将复杂的视图分成几个小视图,可使用上面描述的渲染方法将这些
可使用上面描述的渲染方法将这些小视图渲染并组装成大视图; 小视图渲染并组装成大视图;
* 创建并使用 [小部件](structure-widgets.md) 作为视图的数据块; * 创建并使用 [小部件](structure-widgets.md) 作为视图的数据块;
* 创建并使用助手类在视图中转换和格式化数据。 * 创建并使用助手类在视图中转换和格式化数据。

50
docs/guide-zh-CN/structure-widgets.md

@ -13,15 +13,16 @@ use yii\jui\DatePicker;
<?= DatePicker::widget(['name' => 'date']) ?> <?= DatePicker::widget(['name' => 'date']) ?>
``` ```
Yii提供许多优秀的小部件,比如[[yii\widgets\ActiveForm|active form]], [yii\widgets\Menu|menu]], Yii提供许多优秀的小部件,比如[[yii\widgets\ActiveForm|active form]], [[yii\widgets\Menu|menu]],
[jQuery UI widgets](widget-jui.md), [Twitter Bootstrap widgets](widget-bootstrap.md)。 [jQuery UI widgets](widget-jui.md),
接下来介绍小部件的基本知识, [Twitter Bootstrap widgets](widget-bootstrap.md)。
如果你想了解某个小部件请参考对应的类API文档。 接下来介绍小部件的基本知识,如果你想了解某个小部件请参考对应的类API文档。
## 使用小部件 <span id="using-widgets"></span> ## 使用小部件 <span id="using-widgets"></span>
小部件基本上在[views](structure-views.md)中使用,在视图中可调用 [[yii\base\Widget::widget()]] 方法使用小部件。 小部件基本上在[views](structure-views.md)中使用,
在视图中可调用 [[yii\base\Widget::widget()]] 方法使用小部件。
该方法使用 [配置](concept-configurations.md) 数组初始化小部件并返回小部件渲染后的结果。 该方法使用 [配置](concept-configurations.md) 数组初始化小部件并返回小部件渲染后的结果。
例如如下代码插入一个日期选择器小部件,它配置为使用俄罗斯语, 例如如下代码插入一个日期选择器小部件,它配置为使用俄罗斯语,
输入框内容为`$model`的`from_date`属性值。 输入框内容为`$model`的`from_date`属性值。
@ -34,14 +35,12 @@ use yii\jui\DatePicker;
'model' => $model, 'model' => $model,
'attribute' => 'from_date', 'attribute' => 'from_date',
'language' => 'ru', 'language' => 'ru',
'clientOptions' => [ 'dateFormat' => 'php:Y-m-d',
'dateFormat' => 'yy-mm-dd',
],
]) ?> ]) ?>
``` ```
一些小部件可在[[yii\base\Widget::begin()]] 一些小部件可在[[yii\base\Widget::begin()]]
[[yii\base\Widget::end()]] 调用中使用数据内容。 [[yii\base\Widget::end()]] 调用中使用数据内容。
例如如下代码使用[[yii\widgets\ActiveForm]]小部件生成一个登录表单, 例如如下代码使用[[yii\widgets\ActiveForm]]小部件生成一个登录表单,
小部件会在`begin()` 和0 `end()`执行处分别生成`<form>`的开始标签和结束标签, 小部件会在`begin()` 和0 `end()`执行处分别生成`<form>`的开始标签和结束标签,
中间的任何代码也会被渲染。 中间的任何代码也会被渲染。
@ -68,6 +67,23 @@ use yii\helpers\Html;
注意和调用 [[yii\base\Widget::widget()]] 返回渲染结果不同, 注意和调用 [[yii\base\Widget::widget()]] 返回渲染结果不同,
调用 [[yii\base\Widget::begin()]] 方法返回一个可组建小部件内容的小部件实例。 调用 [[yii\base\Widget::begin()]] 方法返回一个可组建小部件内容的小部件实例。
> Note: Some widgets will use [output buffering](http://php.net/manual/en/book.outcontrol.php) to adjust the enclosed
> content when [[yii\base\Widget::end()]] is called. For this reason calling [[yii\base\Widget::begin()]] and
> [[yii\base\Widget::end()]] is expected to happen in the same view file.
> Not following this rule may result in unexpected output.
### Configuring global defaults
Global defaults for a widget type could be configured via DI container:
```php
\Yii::$container->set('yii\widgets\LinkPager', ['maxButtonCount' => 5]);
```
See ["Practical Usage" section in Dependency Injection Container guide](concept-di-container.md#practical-usage) for
details.
### Configuring global defaults ### Configuring global defaults
@ -150,11 +166,11 @@ class HelloWidget extends Widget
} }
``` ```
如上所示,PHP输出缓冲在`init()`启动,所有在`init()` `run()`方法之间的输出内容都会被获取, 如上所示,PHP输出缓冲在`init()`启动,所有在`init()`
并在`run()`处理和返回。 `run()`方法之间的输出内容都会被获取,并在`run()`处理和返回。
> 注意: 当你调用 [[yii\base\Widget::begin()]] 时会创建一个 > Info: 当你调用 [[yii\base\Widget::begin()]] 时会创建一个新的小部件
新的小部件实例并在构造结束时调用`init()`方法, 实例并在构造结束时调用`init()`方法,
在`end()`时会调用`run()`方法并输出返回结果。 在`end()`时会调用`run()`方法并输出返回结果。
如下代码显示如何使用这种 `HelloWidget`: 如下代码显示如何使用这种 `HelloWidget`:
@ -170,9 +186,9 @@ use app\components\HelloWidget;
<?php HelloWidget::end(); ?> <?php HelloWidget::end(); ?>
``` ```
有时小部件需要渲染很多内容,一种更好的办法 有时小部件需要渲染很多内容,一种更好的办法是将内容放入一个[视图](structure-views.md)文件,
是将内容放入一个[视图](structure-views.md)文件, 然后调用[[yii\base\Widget::render()]]方法渲染该视图文件,
然后调用[[yii\base\Widget::render()]]方法渲染该视图文件,例如: 例如:
```php ```php
public function run() public function run()

99
docs/guide-zh-CN/tutorial-core-validators.md

@ -54,8 +54,8 @@ public function rules()
使用,以确保某一输入与 [[yii\captcha\Captcha|CAPTCHA]] 小部件所显示的验证代码(verification code)相同。 使用,以确保某一输入与 [[yii\captcha\Captcha|CAPTCHA]] 小部件所显示的验证代码(verification code)相同。
- `caseSensitive`:对验证代码的比对是否要求大小写敏感。默认为 false。 - `caseSensitive`:对验证代码的比对是否要求大小写敏感。默认为 false。
- `captchaAction`:指向用于渲染 CAPTCHA 图片的 [[yii\captcha\CaptchaAction|CAPTCHA action]] 的 [路由](structure-controllers.md#routes)。 - `captchaAction`:指向用于渲染 CAPTCHA 图片的 [[yii\captcha\CaptchaAction|CAPTCHA action]]
默认为 `'site/captcha'` 的 [路由](structure-controllers.md#routes)。默认为 `'site/captcha'`
- `skipOnEmpty`:当输入为空时,是否跳过验证。 - `skipOnEmpty`:当输入为空时,是否跳过验证。
默认为 false,也就是输入值为必需项。 默认为 false,也就是输入值为必需项。
@ -67,20 +67,23 @@ public function rules()
// 检查 "password" 特性的值是否与 "password_repeat" 的值相同 // 检查 "password" 特性的值是否与 "password_repeat" 的值相同
['password', 'compare'], ['password', 'compare'],
// same as above but with explicitly specifying the attribute to compare with
['password', 'compare', 'compareAttribute' => 'password_repeat'],
// 检查年龄是否大于等于 30 // 检查年龄是否大于等于 30
['age', 'compare', 'compareValue' => 30, 'operator' => '>='], ['age', 'compare', 'compareValue' => 30, 'operator' => '>='],
] ]
``` ```
该验证器比较两个特定输入值之间的关系是否与 `operator` 该验证器比较两个特定输入值之间的关系
属性所指定的相同。 是否与 `operator` 属性所指定的相同。
- `compareAttribute`:用于与原特性相比较的特性名称。 - `compareAttribute`:用于与原特性相比较的特性名称。
当该验证器被用于验证某目标特性时, 当该验证器被用于验证某目标特性时,
该属性会默认为目标属性加后缀 `_repeat` 该属性会默认为目标属性加后缀 `_repeat`
举例来说,若目标特性为 `password`,则该属性默认为 `password_repeat` 举例来说,若目标特性为 `password`,则该属性默认为 `password_repeat`
- `compareValue`:用于与输入值相比较的常量值。当该属性与 `compareAttribute` 属性同时被指定时, - `compareValue`:用于与输入值相比较的常量值。
该属性优先被使用。 当该属性与 `compareAttribute` 属性同时被指定时,该属性优先被使用。
- `operator`:比较操作符。默认为 `==`,意味着检查输入值是否与 `compareAttribute``compareValue` 的值相等。 - `operator`:比较操作符。默认为 `==`,意味着检查输入值是否与 `compareAttribute``compareValue` 的值相等。
该属性支持如下操作符: 该属性支持如下操作符:
* `==`:检查两值是否相等。比对为非严格模式。 * `==`:检查两值是否相等。比对为非严格模式。
@ -91,18 +94,48 @@ public function rules()
* `>=`:检查待测目标值是否大于等于给定被测值。 * `>=`:检查待测目标值是否大于等于给定被测值。
* `<`:检查待测目标值是否小于给定被测值。 * `<`:检查待测目标值是否小于给定被测值。
* `<=`:检查待测目标值是否小于等于给定被测值。 * `<=`:检查待测目标值是否小于等于给定被测值。
- `type`: The default comparison type is '[[yii\validators\CompareValidator::TYPE_STRING|string]]', which means the values are
compared byte by byte. When comparing numbers, make sure to set the [[yii\validators\CompareValidator::$type|$type]]
to '[[yii\validators\CompareValidator::TYPE_NUMBER|number]]' to enable numeric comparison.
### Comparing date values
The compare validator can only be used to compare strings and numbers. If you need to compare values
like dates you have two options. For comparing a date against a fixed value, you can simply use the
[[yii\validators\DateValidator|date]] validator and specify its
[[yii\validators\DateValidator::$min|$min]] or [[yii\validators\DateValidator::$max|$max]] property.
If you need to compare two dates entered in the form, e.g. a `fromDate` and a `toDate` field,
you can use a combination of compare and date validator like the following:
```php
['fromDate', 'date', 'timestampAttribute' => 'fromDate'],
['toDate', 'date', 'timestampAttribute' => 'toDate'],
['fromDate', 'compare', 'compareAttribute' => 'toDate', 'operator' => '<', 'enableClientValidation' => false],
```
As validators are executed in the order they are specified this will first validate that the values entered in
`fromDate` and `toDate` are valid date values and if so, they will be converted into a machine readable format.
Afterwards these two values are compared with the compare validator.
Client validation is not enabled as this will only work on the server-side because the date validator currently does not
provide client validation, so [[yii\validators\CompareValidator::$enableClientValidation|$enableClientValidation]]
is set to `false` on the compare validator too.
## [[yii\validators\DateValidator|date(日期)]] <span id="date"></span> ## [[yii\validators\DateValidator|date(日期)]] <span id="date"></span>
The [[yii\validators\DateValidator|date]] validator comes with three different
shortcuts:
```php ```php
[ [
[['from', 'to'], 'date'], [['from_date', 'to_date'], 'date'],
[['from_datetime', 'to_datetime'], 'datetime'],
[['some_time'], 'time'],
] ]
``` ```
该验证器检查输入值是否为适当格式的 date,time,或者 datetime。另外, 该验证器检查输入值是否为适当格式的 date,time,或者 datetime。
它还可以帮你把输入值转换为一个 UNIX 时间戳并保存到 另外,它还可以帮你把输入值转换为一个 UNIX 时间戳并保存到
[[yii\validators\DateValidator::timestampAttribute|timestampAttribute]] 属性所指定的特性里。 [[yii\validators\DateValidator::timestampAttribute|timestampAttribute]] 属性所指定的特性里。
- `format`: the date/time format that the value being validated should be in. - `format`: the date/time format that the value being validated should be in.
@ -121,11 +154,14 @@ public function rules()
[[yii\validators\DateValidator::$timestampAttributeFormat|$timestampAttributeFormat]] and [[yii\validators\DateValidator::$timestampAttributeFormat|$timestampAttributeFormat]] and
[[yii\validators\DateValidator::$timestampAttributeTimeZone|$timestampAttributeTimeZone]]. [[yii\validators\DateValidator::$timestampAttributeTimeZone|$timestampAttributeTimeZone]].
Note, that when using `timestampAttribute`, the input value will be converted to a unix timestamp, which by definition is in UTC, so
a conversion from the [[yii\validators\DateValidator::timeZone|input time zone]] to UTC will be performed.
- Since version 2.0.4 it is also possible to specify a [[yii\validators\DateValidator::$min|minimum]] or - Since version 2.0.4 it is also possible to specify a [[yii\validators\DateValidator::$min|minimum]] or
[[yii\validators\DateValidator::$max|maximum]] timestamp. [[yii\validators\DateValidator::$max|maximum]] timestamp.
In case the input is optional you may also want to add a [default value filter](#default) in addition to the date validator In case the input is optional you may also want to add a [default value filter](#default) in addition to the date validator
to ensure empty input is stored as `NULL`. Other wise you may end up with dates like `0000-00-00` in your database to ensure empty input is stored as `null`. Otherwise you may end up with dates like `0000-00-00` in your database
or `1970-01-01` in the input field of a date picker. or `1970-01-01` in the input field of a date picker.
```php ```php
@ -152,8 +188,8 @@ or `1970-01-01` in the input field of a date picker.
] ]
``` ```
该验证器并不进行数据验证。而是, 该验证器并不进行数据验证。
给为空的待测特性分配默认值。 而是,给为空的待测特性分配默认值。
- `value`:默认值,或一个返回默认值的 PHP Callable 对象(即回调函数)。 - `value`:默认值,或一个返回默认值的 PHP Callable 对象(即回调函数)。
它们会分配给检测为空的待测特性。PHP 回调方法的样式如下: 它们会分配给检测为空的待测特性。PHP 回调方法的样式如下:
@ -165,7 +201,8 @@ function foo($model, $attribute) {
} }
``` ```
> 补充:如何判断待测值是否为空,被写在另外一个话题的 > Info: 如何判断待测值是否为空,
被写在另外一个话题的
[处理空输入](input-validation.md#handling-empty-inputs)章节。 [处理空输入](input-validation.md#handling-empty-inputs)章节。
@ -201,8 +238,8 @@ and each array element will be validated by the `integer` validation rule.
- `rule`: an array specifying a validation rule. The first element in the array specifies the class name or - `rule`: an array specifying a validation rule. The first element in the array specifies the class name or
the alias of the validator. The rest of the name-value pairs in the array are used to configure the validator object. the alias of the validator. The rest of the name-value pairs in the array are used to configure the validator object.
- `allowMessageFromRule`: whether to use the error message returned by the embedded validation rule. Defaults to true. - `allowMessageFromRule`: whether to use the error message returned by the embedded validation rule. Defaults to `true`.
If false, it will use `message` as the error message. If `false`, it will use `message` as the error message.
> Note: If the attribute value is not an array, it is considered validation fails and the `message` will be returned > Note: If the attribute value is not an array, it is considered validation fails and the `message` will be returned
as the error message. as the error message.
@ -220,11 +257,11 @@ and each array element will be validated by the `integer` validation rule.
该验证器检查输入值是否为有效的邮箱地址。 该验证器检查输入值是否为有效的邮箱地址。
- `allowName`:检查是否允许带名称的电子邮件地址 (e.g. `张三 <John.san@example.com>`)。 默认为 false。 - `allowName`:检查是否允许带名称的电子邮件地址 (e.g. `张三 <John.san@example.com>`)。 默认为 false。
- `checkDNS`:检查邮箱域名是否存在,且有没有对应的 A 或 MX 记录。不过要知道, - `checkDNS`:检查邮箱域名是否存在,且有没有对应的 A 或 MX 记录。
有的时候该项检查可能会因为临时性 DNS 故障而失败,哪怕它其实是有效的。 不过要知道,有的时候该项检查可能会因为临时性 DNS 故障而失败,
默认为 false。 哪怕它其实是有效的。默认为 false。
- `enableIDN`:验证过程是否应该考虑 IDN(internationalized domain names,国际化域名, - `enableIDN`:验证过程是否应该考虑 IDN(internationalized domain names,国际化域名,也称多语种域名,比如中文域名)。
也称多语种域名,比如中文域名)。默认为 false。要注意但是为使用 IDN 验证功能, 默认为 false。要注意但是为使用 IDN 验证功能,
请先确保安装并开启 `intl` PHP 扩展,不然会导致抛出异常。 请先确保安装并开启 `intl` PHP 扩展,不然会导致抛出异常。
@ -252,28 +289,28 @@ and each array element will be validated by the `integer` validation rule.
] ]
``` ```
This validator checks if the input value can be found in a table column represented by 该验证器检查输入值是否在某表字段中存在。
an [Active Record](db-active-record.md) attribute. You can use `targetAttribute` to specify the 它只对[活动记录](db-active-record.md)
[Active Record](db-active-record.md) attribute and `targetClass` the corresponding [Active Record](db-active-record.md) 类型的模型类特性起作用,
class. If you do not specify them, they will take the values of the attribute and the model class being validated. 能支持对一个或多过字段的验证。
You can use this validator to validate against a single column or multiple columns (i.e., the combination of You can use this validator to validate against a single column or multiple columns (i.e., the combination of
multiple attribute values should exist). multiple attribute values should exist).
- `targetClass`:用于查找输入值的目标 [AR](db-active-record.md) 类。若不设置, - `targetClass`:用于查找输入值的目标 [AR](db-active-record.md) 类。
则会使用正在进行验证的当前模型类。 若不设置,则会使用正在进行验证的当前模型类。
- `targetAttribute`:用于检查输入值存在性的 `targetClass` 的模型特性。 - `targetAttribute`:用于检查输入值存在性的 `targetClass` 的模型特性。
若不设置,它会直接使用待测特性名(整个参数数组的首元素)。 若不设置,它会直接使用待测特性名(整个参数数组的首元素)。
除了指定为字符串以外,你也可以用数组的形式,同时指定多个用于验证的表字段,数组的键和值都是代表字段的特性名, 除了指定为字符串以外,你也可以用数组的形式,同时指定多个用于验证的表字段,
值表示 `targetClass` 的待测数据源字段,而键表示当前模型的待测特性名。 数组的键和值都是代表字段的特性名,值表示 `targetClass` 的待测数据源字段,而键表示当前模型的待测特性名。
若键和值相同,你可以只指定值。(如:`['a2']` 就代表 `['a2'=>'a2']` 若键和值相同,你可以只指定值。(如:`['a2']` 就代表 `['a2'=>'a2']`
- `filter`:用于检查输入值存在性必然会进行数据库查询,而该属性为用于进一步筛选该查询的过滤条件。 - `filter`:用于检查输入值存在性必然会进行数据库查询,而该属性为用于进一步筛选该查询的过滤条件。
可以为代表额外查询条件的字符串或数组(关于查询条件的格式,请参考 [[yii\db\Query::where()]]); 可以为代表额外查询条件的字符串或数组(关于查询条件的格式,请参考 [[yii\db\Query::where()]]);
或者样式为 `function ($query)` 的匿名函数, 或者样式为 `function ($query)` 的匿名函数,
`$query` 参数为你希望在该函数内进行修改的 [[yii\db\Query|Query]] 对象。 `$query` 参数为你希望在该函数内进行修改的 [[yii\db\Query|Query]] 对象。
- `allowArray`:是否允许输入值为数组。默认为 false。若该属性为 true 且输入值为数组,则数组的每个元素都必须在目标字段中存在。 - `allowArray`:是否允许输入值为数组。默认为 false。
值得注意的是,若用吧 `targetAttribute` 设为多元素数组来验证被测值在多字段中的存在性时, 若该属性为 true 且输入值为数组,则数组的每个元素都必须在目标字段中存在。
该属性不能设置为 true。 值得注意的是,若用吧 `targetAttribute` 设为多元素数组来验证被测值在多字段中的存在性时,该属性不能设置为 true。
## [[yii\validators\FileValidator|file(文件)]] <span id="file"></span> ## [[yii\validators\FileValidator|file(文件)]] <span id="file"></span>

64
docs/guide-zh-CN/tutorial-yii-integration.md

@ -1,8 +1,8 @@
引入第三方代码 引入第三方代码
============================= =============================
有时,你可能会需要在 Yii 应用中使用第三方的代码。又或者是你想要在第三方系统中把 Yii 作为类库引用。在下面这个板块中, 有时,你可能会需要在 Yii 应用中使用第三方的代码。又或者是你想要在第三方系统中把 Yii 作为类库引用。
我们向你展示如何实现这些目标。 在下面这个板块中,我们向你展示如何实现这些目标。
## 在 Yii 中使用第三方类库 <span id="using-libs-in-yii"></span> ## 在 Yii 中使用第三方类库 <span id="using-libs-in-yii"></span>
@ -20,8 +20,8 @@
2. 运行 `php composer.phar install` 安装这些包。 2. 运行 `php composer.phar install` 安装这些包。
这些Composer 包内的类库,可以通过 Composer 的自动加载器实现自动加载。 这些Composer 包内的类库,可以通过 Composer 的自动加载器实现自动加载。
不过请确保你应用的[入口脚本](structure-entry-scripts.md)包含以下 不过请确保你应用的[入口脚本](structure-entry-scripts.md)
几行用于加载 Composer 自动加载器的代码: 包含以下几行用于加载 Composer 自动加载器的代码:
```php ```php
// install Composer autoloader (安装 Composer 自动加载器) // install Composer autoloader (安装 Composer 自动加载器)
@ -34,8 +34,8 @@ require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
### 使用下载的类库 <span id="using-downloaded-libs"></span> ### 使用下载的类库 <span id="using-downloaded-libs"></span>
若你的类库并未发布为一个 Composer 包,你可以参考以下安装说明来安装它。 若你的类库并未发布为一个 Composer 包,你可以参考以下安装说明来安装它。
在大多数情况下,你需要预先下载一个发布文件,并把它解压缩到 在大多数情况下,你需要预先下载一个发布文件,并把它解压缩到`BasePath/vendor` 目录,
`BasePath/vendor` 目录,这里的 `BasePath` 代指你应用程序自身的 [base path(主目录)](structure-applications.md#basePath)。 这里的 `BasePath` 代指你应用程序自身的 [base path(主目录)](structure-applications.md#basePath)。
若该类库包含他自己的类自动加载器,你可以把它安装到你应用的[入口脚本](structure-entry-scripts.md)里。 若该类库包含他自己的类自动加载器,你可以把它安装到你应用的[入口脚本](structure-entry-scripts.md)里。
我们推荐你把它的安装代码置于`Yii.php` 的导入之前, 我们推荐你把它的安装代码置于`Yii.php` 的导入之前,
@ -55,15 +55,16 @@ require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
] ]
``` ```
若以上情形都不符合,最可能是这些类库需要依赖于 PHP 的 include_path 配置, 若以上情形都不符合,最可能是这些类库需要依赖于 PHP 的 include_path 配置,来正确定位并导入类文件。
来正确定位并导入类文件。只需参考它的安装说明简单地配置一下 PHP 导入路径即可。 只需参考它的安装说明简单地配置一下 PHP 导入路径即可。
最悲催的情形是,该类库需要显式导入每个类文件, 最悲催的情形是,该类库需要显式导入每个类文件,
你可以使用以下方法按需导入相关类文件: 你可以使用以下方法按需导入相关类文件:
* 找出该库内包含哪些类。 * 找出该库内包含哪些类。
* 在应用的[入口脚本](structure-entry-scripts.md)里的 `Yii::$classMap` 数组中列出这些类, * 在应用的[入口脚本](structure-entry-scripts.md)里的 `Yii::$classMap` 数组中列出这些类,和他们各自对应的文件路径。
和他们各自对应的文件路径。举例来说, 举例来说,
```php ```php
Yii::$classMap['Class1'] = 'path/to/Class1.php'; Yii::$classMap['Class1'] = 'path/to/Class1.php';
Yii::$classMap['Class2'] = 'path/to/Class2.php'; Yii::$classMap['Class2'] = 'path/to/Class2.php';
@ -74,37 +75,22 @@ Yii::$classMap['Class2'] = 'path/to/Class2.php';
-------------------------------- --------------------------------
因为 Yii 提供了很多牛逼的功能,有时,你可能会想要使用它们中的一些功能用来支持开发或完善某些第三方的系统, 因为 Yii 提供了很多牛逼的功能,有时,你可能会想要使用它们中的一些功能用来支持开发或完善某些第三方的系统,
比如:WordPress,Joomla,或是用其他 PHP 框架开发的应用程序。举两个例子吧, 比如:WordPress,Joomla,或是用其他 PHP 框架开发的应用程序。
你可能会想念方便的 [[yii\helpers\ArrayHelper]] 类,或在第三方系统中使用 举两个例子吧,你可能会想念方便的 [[yii\helpers\ArrayHelper]] 类,或在第三方系统中使用
[Active Record](db-active-record.md) 活动记录功能。要实现这些目标, [Active Record](db-active-record.md) 活动记录功能。
你只需两个步骤:安装 Yii,启动 Yii。 要实现这些目标,你只需两个步骤:安装 Yii,启动 Yii。
若这个第三方系统支持 Composer 管理他的依赖文件, 若这个第三方系统支持 Composer 管理他的依赖文件,
你可以直接运行一下命令来安装 Yii: 你可以直接运行一下命令来安装 Yii:
composer global require "fxp/composer-asset-plugin:^1.3.1" ```bash
composer require yiisoft/yii2 composer require yiisoft/yii2
composer install
The first command installs the [composer asset plugin](https://github.com/francoispluchino/composer-asset-plugin/)
which allows managing bower and npm package dependencies through Composer. Even if you only want to use the database
layer or other non-asset related features of Yii, this is required to install the Yii composer package.
If you want to use the [Asset publishing feature of Yii](structure-assets.md) you should also add the following configuration
to the `extra` section in your `composer.json`:
```json
{
...
"extra": {
"asset-installer-paths": {
"npm-asset-library": "vendor/npm",
"bower-asset-library": "vendor/bower"
}
}
}
``` ```
In case you would like to use only the database abstraction layer or other non-asset related features of Yii,
you should require a special composer package that prevent Bower and NPM packages installation. See
[cebe/assetfree-yii2](https://github.com/cebe/assetfree-yii2) for details.
See also the general [section about installing Yii](start-installation.md#installing-via-composer) for more information See also the general [section about installing Yii](start-installation.md#installing-via-composer) for more information
on Composer and solution to possible issues popping up during the installation. on Composer and solution to possible issues popping up during the installation.
@ -125,9 +111,9 @@ new yii\web\Application($yiiConfig); // 千万别在这调用 run() 方法。(
因为,`run()` 方法的调用会接管 HTTP 请求的处理流程。 因为,`run()` 方法的调用会接管 HTTP 请求的处理流程。
(译注:换言之,这就不是第三方系统而是 Yii 系统了,URL 规则也会跟着换成 Yii 的规则了) (译注:换言之,这就不是第三方系统而是 Yii 系统了,URL 规则也会跟着换成 Yii 的规则了)
与 Yii 应用中一样,你可以依据运行该第三方系统的环境, 与 Yii 应用中一样,你可以依据运行该第三方系统的环境,针对性地配置 Yii 应用实例。
针对性地配置 Yii 应用实例。比如, 比如,为了使用[活动记录](db-active-record.md)功能
为了使用[活动记录](db-active-record.md)功能,你需要先用该第三方系统的 DB 连接信息,配置 Yii 的 `db` 应用组件。 你需要先用该第三方系统的 DB 连接信息,配置 Yii 的 `db` 应用组件。
现在,你就可以使用 Yii 提供的绝大多数功能了。 现在,你就可以使用 Yii 提供的绝大多数功能了。
比如,创建 AR 类,并用它们来操作数据库。 比如,创建 AR 类,并用它们来操作数据库。
@ -140,8 +126,8 @@ new yii\web\Application($yiiConfig); // 千万别在这调用 run() 方法。(
不必用 Yii 2 重写整个应用,你也可以通过增添对哪些 不必用 Yii 2 重写整个应用,你也可以通过增添对哪些
Yii 2 独占功能的支持来增强这个系统。下面我们就来详细描述一下具体的实现过程。 Yii 2 独占功能的支持来增强这个系统。下面我们就来详细描述一下具体的实现过程。
> 注意:Yii 2 需要 PHP 5.4+ 的版本。 > Note: Yii 2 需要 PHP 5.4+ 的版本。你需要确保你的服务器以及现有应用都
> 你需要确保你的服务器以及现有应用都可以支持 PHP 5.4。 > 可以支持 PHP 5.4。
首先,参考前文板块中给出的方法,在已有的应用中安装 Yii 2。 首先,参考前文板块中给出的方法,在已有的应用中安装 Yii 2。

Loading…
Cancel
Save