Browse Source

Merge pull request #16115 from yiichina/doc

zh-CN translation
tags/2.0.16
Alexander Makarov 7 years ago committed by GitHub
parent
commit
02276a6a2f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 30
      docs/guide-zh-CN/concept-aliases.md
  2. 15
      docs/guide-zh-CN/concept-components.md
  3. 20
      docs/guide-zh-CN/concept-configurations.md
  4. 104
      docs/guide-zh-CN/concept-di-container.md
  5. 118
      docs/guide-zh-CN/concept-events.md
  6. 17
      docs/guide-zh-CN/concept-properties.md
  7. 23
      docs/guide-zh-CN/concept-service-locator.md
  8. 414
      docs/guide-zh-CN/db-active-record.md
  9. 253
      docs/guide-zh-CN/db-dao.md
  10. 198
      docs/guide-zh-CN/helper-array.md
  11. 60
      docs/guide-zh-CN/helper-html.md
  12. 14
      docs/guide-zh-CN/helper-overview.md
  13. 26
      docs/guide-zh-CN/helper-url.md
  14. 12
      docs/guide-zh-CN/input-file-upload.md
  15. 147
      docs/guide-zh-CN/input-forms.md
  16. 1
      docs/guide-zh-CN/intro-yii.md
  17. 152
      docs/guide-zh-CN/output-formatting.md
  18. 587
      docs/guide-zh-CN/runtime-routing.md
  19. 201
      docs/guide-zh-CN/security-authorization.md
  20. 54
      docs/guide-zh-CN/security-cryptography.md
  21. 25
      docs/guide-zh-CN/security-overview.md
  22. 11
      docs/guide-zh-CN/start-looking-ahead.md
  23. 7
      docs/guide-zh-CN/start-prerequisites.md
  24. 49
      docs/guide-zh-CN/structure-assets.md
  25. 2
      docs/guide-zh-CN/structure-views.md
  26. 200
      docs/guide-zh-CN/tutorial-i18n.md
  27. 26
      docs/guide-zh-CN/tutorial-start-from-scratch.md
  28. 4
      docs/guide-zh-CN/tutorial-template-engines.md
  29. 21
      docs/guide-zh-CN/tutorial-yii-integration.md

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

@ -1,12 +1,15 @@
别名(Aliases)
=======
=============
别名用来表示文件路径和 URL,这样就避免了在代码中硬编码一些绝对路径和 URL。
一个别名必须以 `@` 字符开头,以区别于传统的文件路径和 URL。
Yii 预定义了大量可用的别名。例如,别名 `@yii` 指的是 Yii 框架本身的安装目录,而 `@web` 表示的是当前运行应用的根 URL
没有前导 `@` 定义的别名将以 `@` 字符作为前缀
定义别名 <span id="defining-aliases"></span>
----------------
Yii 预定义了大量可用的别名。例如,别名 `@yii` 指的是 Yii 框架本身的安装目录,
`@web` 表示的是当前运行应用的根 URL。
定义别名(Defining Aliases) <span id="defining-aliases"></span>
-------------------------
你可以调用 [[Yii::setAlias()]] 来给文件路径或 URL 定义别名:
@ -16,6 +19,9 @@ Yii::setAlias('@foo', '/path/to/foo');
// URL 的别名
Yii::setAlias('@bar', 'http://www.example.com');
// 包含 \foo\Bar 类的具体文件的别名
Yii::setAlias('@foo/Bar.php', '/definitely/not/foo/Bar.php');
```
> Note: 别名所指向的文件路径或 URL 不一定是真实存在的文件或资源。
@ -47,8 +53,8 @@ return [
```
解析别名 <span id="resolving-aliases"></span>
-----------------
解析别名(Resolving Aliases) <span id="resolving-aliases"></span>
--------------------------
你可以调用 [[Yii::getAlias()]] 命令来解析根别名到对应的文件路径或 URL。
同样的页面也可以用于解析衍生别名。例如:
@ -79,8 +85,8 @@ echo Yii::getAlias('@foo/bar/file.php'); // 输出:/path2/bar/file.php
`@foo/bar` 未被定义为根别名,最后一行语句会显示为 `/path/to/foo/bar/file.php`
使用别名 <span id="using-aliases"></span>
-------------
使用别名(Using Aliases) <span id="using-aliases"></span>
----------------------
别名在 Yii 的很多地方都会被正确识别,
无需调用 [[Yii::getAlias()]] 来把它们转换为路径/URL。
@ -98,8 +104,8 @@ $cache = new FileCache([
请关注 API 文档了解特定属性或方法参数是否支持别名。
预定义的别名 <span id="predefined-aliases"></span>
------------------
预定义的别名(Predefined Aliases) <span id="predefined-aliases"></span>
------------------------------
Yii 预定义了一系列别名来简化常用路径和 URL 的使用:
@ -118,8 +124,8 @@ Yii 预定义了一系列别名来简化常用路径和 URL 的使用:
于应用的构造方法内定义的。
扩展的别名 <span id="extension-aliases"></span>
-----------------
扩展的别名(Extension Aliases) <span id="extension-aliases"></span>
----------------------------
每一个通过 Composer 安装的 [扩展](structure-extensions.md) 都自动添加了一个别名。
该别名会以该扩展在 `composer.json` 文件中所声明的根命名空间为名,

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

@ -1,5 +1,5 @@
组件(Component)
==========
==============
组件是 Yii 应用的主要基石。是 [[yii\base\Component]] 类或其子类的实例。
三个用以区分它和其它类的主要功能有:
@ -35,10 +35,10 @@ echo DatePicker::widget([
当继承 [[yii\base\Component]] 或 [[yii\base\Object]] 时,
推荐你使用如下的编码风格:
- 若你需要重写构造方法(Constructor),传入 `$config` 作为构造器方法**最后一个**参数,
- 若你需要重写构造方法(Constructor),传入 `$config` 作为构造器方法*最后一个*参数,
然后把它传递给父类的构造方法。
- 永远在你重写的构造方法**结尾处**调用一下父类的构造方法。
- 如果你重写了 [[yii\base\BaseObject::init()]] 方法,请确保你在 `init` 方法的**开头处**调用了父类的 `init` 方法。
- 永远在你重写的构造方法*结尾处*调用一下父类的构造方法。
- 如果你重写了 [[yii\base\BaseObject::init()]] 方法,请确保你在 `init` 方法的*开头处*调用了父类的 `init` 方法。
例子如下:
@ -56,7 +56,7 @@ class MyClass extends BaseObject
public function __construct($param1, $param2, $config = [])
{
// ... initialization before configuration is applied
// ... 在应用配置之前初始化
parent::__construct($config);
}
@ -65,7 +65,7 @@ class MyClass extends BaseObject
{
parent::init();
// ... initialization after configuration is applied
// ... 应用配置后进行初始化
}
}
```
@ -93,6 +93,5 @@ $component = \Yii::createObject([
3. 在 [[yii\base\BaseObject::init()|init()]] 方法内进行初始化后的收尾工作。你可以通过重写此方法,进行一些良品检验,属性的初始化之类的工作。
4. 对象方法调用。
前三步都是在对象的构造方法内发生的。这意味着一旦你获得了一个对象实例,
前三步都是在对象的构造方法内发生的。这意味着一旦你获得了一个对象实例(即一个对象)
那么它就已经初始化就绪可供使用。

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

@ -1,5 +1,5 @@
配置
=============
配置(Configurations)
====================
在 Yii 中,创建新对象和初始化已存在对象时广泛使用配置。
配置通常包含被创建对象的类名和一组将要赋值给对象
@ -35,7 +35,7 @@ Yii::configure($object, $config);
请注意,如果配置一个已存在的对象,那么配置数组中不应该包含指定类名的 `class` 元素。
## 配置的格式 <span id="configuration-format"></span>
## 配置的格式(Configuration Format) <span id="configuration-format"></span>
一个配置的格式可以描述为以下形式:
@ -78,14 +78,14 @@ Yii::configure($object, $config);
```
## 使用配置
## 使用配置(Using Configurations) <span id="using-configurations"></span>
Yii 中的配置可以用在很多场景。本章开头我们展示了如何使用 [[Yii::creatObject()]]
根据配置信息创建对象。本小节将介绍配置的两种
主要用法 —— 配置应用与配置小部件。
### 应用的配置 <span id="application-configurations"></span>
### 应用的配置(Application Configurations) <span id="application-configurations"></span>
[应用](structure-applications.md)的配置可能是最复杂的配置之一。
因为 [[yii\web\Application|application]] 类拥有很多可配置的属性和事件。
@ -158,7 +158,7 @@ $config = [
获取更多 `definitions``singletons` 配置项和实际使用的例子。
### 小部件的配置 <span id="widget-configurations"></span>
### 小部件的配置(Widget Configurations) <span id="widget-configurations"></span>
使用[小部件](structure-widgets.md)时,常常需要配置以便自定义其属性。
[[yii\base\Widget::widget()]] 和 [[yii\base\Widget::begin()]] 方法都可以用来创建小部件。
@ -183,10 +183,10 @@ echo Menu::widget([
请注意,代码中已经给出了类名 `yii\widgets\Menu`,配置数组**不应该**再包含 `class` 键。
## 配置文件 <span id="configuration-files"></span>
## 配置文件(Configuration Files) <span id="configuration-files"></span>
当配置的内容十分复杂,通用做法是将其存储在一或多个 PHP 文件中,
这些文件被称为**配置文件**。一个配置文件返回的是 PHP 数组。
这些文件被称为*配置文件*。一个配置文件返回的是 PHP 数组。
例如,像这样把应用配置信息存储在名为 `web.php` 的文件中:
```php
@ -236,7 +236,7 @@ $config = require 'path/to/web.php';
```
## 默认配置 <span id="default-configurations"></span>
## 默认配置(Default Configurations) <span id="default-configurations"></span>
[[Yii::createObject()]] 方法基于[依赖注入容器](concept-di-container.md)实现。
使用 [[Yii::creatObject()]] 创建对象时,可以附加一系列**默认配置**到指定类的任何实例。
@ -256,7 +256,7 @@ $config = require 'path/to/web.php';
都配置 `maxButtonCount` 的值。
## 环境常量 <span id="environment-constants"></span>
## 环境常量(Environment Constants) <span id="environment-constants"></span>
配置经常要随着应用运行的不同环境更改。例如在开发环境中,
你可能使用名为 `mydb_dev` 的数据库,

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

@ -1,13 +1,13 @@
依赖注入容器
==========
依赖注入容器(Dependency Injection Container)
===========================================
依赖注入(Dependency Injection,DI)容器就是一个对象,它知道怎样初始化并配置对象及其依赖的所有对象。
[Martin 的文章](http://martinfowler.com/articles/injection.html) 已经解释了 DI 容器为什么很有用。
这里我们主要讲解 Yii 提供的 DI 容器的使用方法。
依赖注入 <span id="dependency-injection"></span>
-------
依赖注入(Dependency Injection) <span id="dependency-injection"></span>
-----------------------------
Yii 通过 [[yii\di\Container]] 类提供 DI 容器特性。
它支持如下几种类型的依赖注入:
@ -18,7 +18,7 @@ Yii 通过 [[yii\di\Container]] 类提供 DI 容器特性。
* PHP 回调注入.
### 构造方法注入 <span id="constructor-injection"></span>
### 构造方法注入(Constructor Injection) <span id="constructor-injection"></span>
在参数类型提示的帮助下,DI 容器实现了构造方法注入。当容器被用于创建一个新对象时,
类型提示会告诉它要依赖什么类或接口。
@ -40,7 +40,7 @@ $foo = new Foo($bar);
```
### 方法注入 <span id="method-injection"></span>
### 方法注入(Method Injection) <span id="method-injection"></span>
通常,类的依赖关系传递给构造函数,并且在整个生命周期中都可以在类内部使用。
通过方法注入,可以提供仅由类的单个方法需要的依赖关系,
@ -70,7 +70,7 @@ $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 和属性注入(Setter and Property Injection) <span id="setter-and-property-injection"></span>
Setter 和属性注入是通过[配置](concept-configurations.md)提供支持的。
当注册一个依赖或创建一个新对象时,你可以提供一个配置,
@ -109,7 +109,7 @@ $container->get('Foo', [], [
否则,将在创建对象*后*应用该配置。
### PHP 回调注入 <span id="php-callable-injection"></span>
### PHP 回调注入(PHP Callable Injection) <span id="php-callable-injection"></span>
在这种情况下,容器将使用已注册的 PHP 回调来构建类的新实例。
每次调用 [[yii\di\Container::get()]] ,相应的回调将被调用。
@ -119,7 +119,7 @@ $container->get('Foo', [], [
```php
$container->set('Foo', function () {
$foo = new Foo(new Bar);
// ... other initializations ...
// ... 其他初始化 ...
return $foo;
});
@ -134,7 +134,7 @@ class FooBuilder
public static function build()
{
$foo = new Foo(new Bar);
// ... other initializations ...
// ... 其他初始化 ...
return $foo;
}
}
@ -147,8 +147,8 @@ $foo = $container->get('Foo');
这样做的话,想要配置 `Foo` 类的人不再需要知道它是如何构建的。
注册依赖关系 <span id="registering-dependencies"></span>
------------------------
注册依赖关系(Registering Dependencies) <span id="registering-dependencies"></span>
------------------------------------
可以用 [[yii\di\Container::set()]] 注册依赖关系。注册会用到一个依赖关系名称和一个依赖关系的定义。
依赖关系名称可以是一个类名,一个接口名或一个别名。
@ -216,8 +216,8 @@ $container->setSingleton('yii\db\Connection', [
```
解决依赖关系 <span id="resolving-dependencies"></span>
----------------------
解决依赖关系(Resolving Dependencies) <span id="resolving-dependencies"></span>
----------------------------------
注册依赖关系后,就可以使用 DI 容器创建新对象了。容器会自动解决依赖关系,
将依赖实例化并注入新创建的对象。依赖关系的解决是递归的,
@ -307,8 +307,8 @@ $lister = new UserLister($finder);
```
实践中的运用 <span id="practical-usage"></span>
---------------
实践中的运用(Practical Usage) <span id="practical-usage"></span>
---------------------------
当在应用程序的[入口脚本](structure-entry-scripts.md)中引入 `Yii.php` 文件时,
Yii 就创建了一个 DI 容器。这个 DI 容器可以通过 [[Yii::$container]] 访问。
@ -372,16 +372,16 @@ class HotelController extends Controller
现在如果你再次访问这个控制器,一个 `app\components\BookingService`
的实例就会被创建并被作为第三个参数注入到控制器的构造器中。
高级实用性 <span id="advanced-practical-usage"></span>
---------
高级实用性(Advanced Practical Usage) <span id="advanced-practical-usage"></span>
------------------------------------
比如说我们在 API 应用方面工作:
- `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:
- `app\components\Request` 类继承了 `yii\web\Request` 并提供了额外的功能
- `app\components\Response` 类继承了 `yii\web\Response` 并且在创建时应该将 `format`
属性设置为 `json`
- `app\storage\FileStorage` `app\storage\DocumentsReader`
用于处理位于某些文件存储中的文档的某些逻辑:
```php
class FileStorage
@ -399,18 +399,18 @@ class HotelController extends Controller
}
```
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.
可以一次配置多个定义,将配置数组传递给
[[yii\di\Container::setDefinitions()|setDefinitions()]] 或 [[yii\di\Container::setSingletons()|setSingletons()]] 方法。
遍历配置数组,将分别为每个对象分别调用 [[yii\di\Container::set()|set()]]
或 [[yii\di\Container::setSingleton()|setSingleton()]] 方法。
配置数组格式为:
- `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`.
- `key`:类名称,接口名称或别名。 该 key 将作为第一个参数
`$class` 传递给 [[yii\di\Container::set()|set()]] 方法。
- `value`:与 `$class` 关联的定义。`$definition` 参数的值可能在 [[yii\di\Container::set()|set()]]
文档中描述。`$definition` 将作为第二个参数传递给 [[set()]]
方法。
例如,让我们配置我们的容器以遵循上述要求:
@ -428,32 +428,32 @@ $container->setDefinitions([
]);
$reader = $container->get('app\storage\DocumentsReader);
// Will create DocumentReader object with its dependencies as described in the config
// 将按照配置中的描述创建 DocumentReader 对象及其依赖关系
```
> 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.
> Tip: 自 2.0.11 版以后,可以使用应用程序配置以声明式风格配置容器。
查看[配置](concept-configurations.md)指南文章的
[应用程序配置](concept-configurations.md#application-configurations)小节。
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.
一切正常,但如果我们需要创建 `Document Writer` 类,
我们将复制粘贴创建 `FileStorage` 对象的行,这显然不是最聪明的方式。
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:
如 [解决依赖关系](#resolving-dependencies) 子节中所述,[[yii\di\Container::set()|set()]]
和 [[yii\di\Container::setSingleton()|setSingleton()]] 可以选择将依赖项的构造函数参数作为第三个参数。
要设置构造函数参数,可以使用以下配置数组格式:
- `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`.
- `key`:类名称,接口名称或别名。该 key 将作为第一个参数
`$class` 传递给 [[yii\di\Container::set()|set()]] 方法。
- `value`:两个元素的数组。第一个元素将传递给 [[yii\di\Container::set()|set()]] 方法
作为第二个参数 `$definition`,第二个元素为 `$params`
让我们来修改我们的例子:
```php
$container->setDefinitions([
'tempFileStorage' => [ // we've created an alias for convenience
'tempFileStorage' => [ // 我们为了方便创建了一个别名
['class' => 'app\storage\FileStorage'],
['/var/tempfiles'] // could be extracted from some config files
       ['/var/tempfiles'] // 可以从一些配置文件中获取
],
'app\storage\DocumentsReader' => [
['class' => 'app\storage\DocumentsReader'],
@ -466,7 +466,7 @@ $container->setDefinitions([
]);
$reader = $container->get('app\storage\DocumentsReader);
// Will behave exactly the same as in the previous example.
// 将与前面示例中的行为完全相同。
```
你可能会注意到 `Instance::of('tempFileStorage')` 符号。这意味着,[[yii\di\Container|Container]]
@ -507,8 +507,8 @@ $container->setDefinitions([
$reader = $container->get('app\storage\DocumentsReader');
```
什么时候注册依赖关系 <span id="when-to-register-dependencies"></span>
-----------------------------
什么时候注册依赖关系(When to Register Dependencies) <span id="when-to-register-dependencies"></span>
------------------------------------------------
由于依赖关系在创建新对象时需要解决,因此它们的注册应该尽早完成。
如下是推荐的实践:
@ -520,8 +520,8 @@ $reader = $container->get('app\storage\DocumentsReader');
你可以将依赖关系注册到扩展的引导类中。
总结 <span id="summary"></span>
-------
总结(Summary) <span id="summary"></span>
-------------
依赖注入和[服务定位器](concept-service-locator.md)都是流行的设计模式,
它们使你可以用充分解耦且更利于测试的风格构建软件。

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

@ -1,5 +1,5 @@
事件
======
事件(Events)
============
事件可以将自定义代码“注入”到现有代码中的特定执行点。
附加自定义代码到某个事件,当这个事件被触发时,这些代码就会自动执行。
@ -10,8 +10,8 @@ Yii 引入了名为 [[yii\base\Component]] 的基类以支持事件。
如果一个类需要触发事件就应该继承 [[yii\base\Component]] 或其子类。
事件处理器 <span id="event-handlers"></span>
--------------
事件处理器(Event Handlers) <span id="event-handlers"></span>
-------------------------
事件处理器是一个[PHP 回调函数](http://www.php.net/manual/en/language.types.callable.php),
当它所附加到的事件被触发时它就会执行。可以使用以下回调函数之一:
@ -36,8 +36,8 @@ function ($event) {
- [[yii\base\Event::data|custom data]]:附加事件处理器时传入的数据,默认为空,后文详述
附加事件处理器
----------------
附加事件处理器(Attaching Event Handlers) <span id="attaching-event-handlers"></span>
--------------------------------------
调用 [[yii\base\Component::on()]] 方法来附加处理器到事件上。如:
@ -76,8 +76,8 @@ function function_name($event) {
}
```
事件处理器顺序
-----------------
事件处理器顺序(Event Handler Order)
---------------------------------
可以附加一个或多个处理器到一个事件。当事件被触发,已附加的处理器将按附加次序依次调用。
如果某个处理器需要停止其后的处理器调用,可以设置 `$event` 参数的 [[yii\base\Event::handled]] 属性为真,
@ -99,10 +99,10 @@ $foo->on(Foo::EVENT_HELLO, function ($event) {
}, $data, false);
```
触发事件 <span id="triggering-events"></span>
----------
触发事件(Triggering Events) <span id="triggering-events"></span>
--------------------------
事件通过调用 [[yii\base\Component::trigger()]] 方法触发,此方法须传递**事件名**,
事件通过调用 [[yii\base\Component::trigger()]] 方法触发,此方法须传递*事件名*,
还可以传递一个事件对象,用来传递参数到事件处理器。如:
```php
@ -164,8 +164,8 @@ class Mailer extends Component
它将调用所有附加到命名事件(trigger 方法第一个参数)的事件处理器。
移除事件处理器
---------------
移除事件处理器(Detaching Event Handlers) <span id="detaching-event-handlers"></span>
--------------------------------------
从事件移除处理器,调用 [[yii\base\Component::off()]] 方法。如:
@ -194,13 +194,13 @@ $foo->off(Foo::EVENT_HELLO);
```
类级别的事件处理器
-------------------
类级别的事件处理器(Class-Level Event Handlers) <span id="class-level-event-handlers"></span>
-------------------------------------------
以上部分,我们叙述了在**实例级别**如何附加处理器到事件。
有时想要一个类的所有实例而不是一个指定的实例都响应一个被触发的事件,
以上部分,我们叙述了在*实例级别*如何附加处理器到事件。
有时想要一个类的*所有*实例而不是一个指定的实例都响应一个被触发的事件,
并不是一个个附加事件处理器到每个实例,
而是通过调用静态方法 [[yii\base\Event::on()]] 在**类级别**附加处理器。
而是通过调用静态方法 [[yii\base\Event::on()]] 在*类级别*附加处理器。
例如,[活动记录](db-active-record.md)对象要在每次往数据库新增一条新记录时触发一个
[[yii\db\BaseActiveRecord::EVENT_AFTER_INSERT|EVENT_AFTER_INSERT]] 事件。
@ -222,7 +222,7 @@ Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function
当对象触发事件时,它首先调用实例级别的处理器,然后才会调用类级别处理器。
可调用静态方法[[yii\base\Event::trigger()]]来触发一个**类级别**事件。
可调用静态方法[[yii\base\Event::trigger()]]来触发一个*类级别*事件。
类级别事件不与特定对象相关联。因此,它只会引起类级别事件处理器的调用。
如:
@ -252,8 +252,8 @@ Event::off(Foo::className(), Foo::EVENT_HELLO);
```
使用接口事件 <span id="interface-level-event-handlers"></span>
-------------
使用接口事件(Events using interfaces) <span id="interface-level-event-handlers"></span>
-----------------------------------
有更多的抽象方式来处理事件。你可以为特殊的事件创建一个独立的接口,
然后在你需要的类中实现它。
@ -328,10 +328,10 @@ Event::off('app\interfaces\DanceEventInterface', DanceEventInterface::EVENT_DANC
```
全局事件
-------------
全局事件(Global Events) <span id="global-events"></span>
----------------------
所谓**全局事件**实际上是一个基于以上叙述的事件机制的戏法。它需要一个全局可访问的单例,
所谓*全局事件*实际上是一个基于以上叙述的事件机制的戏法。它需要一个全局可访问的单例,
如[应用](structure-applications.md)实例。
事件触发者不调用其自身的 `trigger()` 方法,而是调用单例的 `trigger()` 方法来触发全局事件。
@ -356,3 +356,73 @@ Yii::$app->trigger('bar', new Event(['sender' => new Foo]));
然而,因为全局事件的命名空间由各方共享,应合理命名全局事件,
如引入一些命名空间(例:"frontend.mail.sent", "backend.mail.sent")。
通配符事件(Wildcard Events) <span id="wildcard-events"></span>
--------------------------
自 2.0.14 以来,您可以为多个匹配通配符模式的事件设置事件处理程序。
例如:
```php
use Yii;
$foo = new Foo();
$foo->on('foo.event.*', function ($event) {
   // 触发任何事件,该名称以 'foo.event.' 开头
   Yii::debug('trigger event: ' . $event->name);
});
```
通配符模式也可以用于类级别的事件。 例如:
```php
use yii\base\Event;
use Yii;
Event::on('app\models\*', 'before*', function ($event) {
   // 触发命名空间 'app\models' 中的任何类的任何事件,名称以 'before' 开头。
   Yii::debug('trigger event: ' . $event->name . ' for class: ' . get_class($event->sender));
});
```
这允许您使用以下代码通过单个处理程序捕获所有应用程序事件:
```php
use yii\base\Event;
use Yii;
Event::on('*', '*', function ($event) {
   // 触发任何类的任何事件
   Yii::debug('trigger event: ' . $event->name);
});
```
> Note: 事件处理程序设置的使用通配符可能会降低应用程序的性能。
如果可能,最好避免。
为了移除由通配符模式指定的事件处理程序,您应该在
[[yii\base\Component::off()]] 或 [[yii\base\Event::off()]] 调用中重复相同的模式。
请记住,在移除事件处理程序期间传递通配符将移除为此通配符指定的处理程序,
而为常规事件名称附加的处理程序将保留,即使它们与模式匹配。 例如:
```php
use Yii;
$foo = new Foo();
// 附加常规处理
$foo->on('event.hello', function ($event) {
echo 'direct-handler'
});
// 附加通配符处理程序
$foo->on('*', function ($event) {
echo 'wildcard-handler'
});
// 仅移除通配符处理程序!
$foo->off('*');
$foo->trigger('event.hello'); // 输出:'direct-handler'
```

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

@ -1,7 +1,7 @@
属性(Property
==========
属性(Properties
================
在 PHP 中,类的成员变量也被称为**属性(properties)**。它们是类定义的一部分,
在 PHP 中,类的成员变量也被称为*属性*。它们是类定义的一部分,
用来表现一个实例的状态(也就是区分类的不同实例)。
在具体实践中,常常会想用一个稍微特殊些的方法实现属性的读写。
例如,如果有需求每次都要对 `label` 属性执行 trim 操作,
@ -17,7 +17,7 @@ $object->label = trim($label);
这种实践显然需要尽可能避免。
为解决该问题,Yii 引入了一个名为 [[yii\base\Object]] 的基类,
它支持基于类内的 **getter****setter**(读取器和设定器)方法来定义属性。
它支持基于类内的 *getter**setter*(读取器和设定器)方法来定义属性。
如果某类需要支持这个特性,只需要继承 [[yii\base\Object]] 或其子类即可。
> Info: 几乎每个 Yii 框架的核心类都继承自 [[yii\base\Object]] 或其子类。
@ -63,20 +63,20 @@ $label = $object->label;
$object->label = 'abc';
```
只定义了 getter 没有 setter 的属性是**只读属性**。
只定义了 getter 没有 setter 的属性是*只读属性*。
尝试赋值给这样的属性将导致 [[yii\base\InvalidCallException|InvalidCallException]] (无效调用)异常。
类似的,只有 setter 方法而没有 getter 方法定义的属性是**只写属性**,
类似的,只有 setter 方法而没有 getter 方法定义的属性是*只写属性*,
尝试读取这种属性也会触发异常。使用只写属性的情况几乎没有。
通过 getter 和 setter 定义的属性也有一些特殊规则和限制:
* 这类属性的名字是**不区分大小写**的。如,`$object->label` 和 `$object->Label` 是同一个属性。
* 这类属性的名字是*不区分大小写*的。如,`$object->label` 和 `$object->Label` 是同一个属性。
因为 PHP 方法名是不区分大小写的。
* 如果此类属性名和类成员变量相同,以后者为准。例如,
假设以上 `Foo` 类有个 `label` 成员变量,然后给 `$object->label = 'abc'` 赋值,
将赋给成员变量而不是 setter `setLabel()` 方法。
* 这类属性不支持可见性(访问限制)。定义属性的 getter 和 setter 方法是 public、protected 还是 private 对属性的可见性没有任何影响。
* 这类属性的 getter 和 setter 方法只能定义为**非静态**的,若定义为静态方法(static)则不会以相同方式处理。
* 这类属性的 getter 和 setter 方法只能定义为*非静态*的,若定义为静态方法(static)则不会以相同方式处理。
* 对不确定有无魔术方法(getter 或 setter)的属性正常调用 `property_exists()` 将不会生效。你应该分别调用 [[yii\base\BaseObject::canGetProperty()|canGetProperty()]]
或 [[yii\base\BaseObject::canSetProperty()|canSetProperty()]] 。  
@ -84,4 +84,3 @@ $object->label = 'abc';
现在我们只需在 setter `setLabel()` 方法内调用一次。
如果 label 首字母变成大写的新要求来了,我们只需要修改`setLabel()` 方法,
而无须接触任何其它代码。

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

@ -1,5 +1,5 @@
服务定位器
===============
服务定位器(Service Locator)
==========================
服务定位器是一个了解如何提供各种应用所需的服务(或组件)的对象。在服务定位器中,
每个组件都只有一个单独的实例,并通过ID 唯一地标识。
@ -7,8 +7,8 @@
在 Yii 中,服务定位器是 [[yii\di\ServiceLocator]] 或其子类的一个实例。
最常用的服务定位器是**application(应用)**对象,可以通过 `\Yii::$app` 访问。
它所提供的服务被称为**application components(应用组件)**,
最常用的服务定位器是*application(应用)*对象,可以通过 `\Yii::$app` 访问。
它所提供的服务被称为*application components(应用组件)*,
比如:`request`、`response`、`urlManager` 组件。可以通过服务定位器所提供的功能,
非常容易地配置这些组件,或甚至是用你自己的实现替换掉他们。
@ -119,14 +119,13 @@ return [
当您使用如上所示的静态方法来表示构建复杂逻辑的第三方对象时,
您的组件用户只需要调用静态方法来配置组件。
## Tree traversal <span id="tree-traversal"></span>
## 遍历树(Tree traversal <span id="tree-traversal"></span>
Modules allow arbitrary nesting; a Yii application is essentially a tree of modules.
Since each of these modules is a service locator it makes sense for children to have access to their parent.
This allows modules to use `$this->get('db')` instead of referencing the root service locator `Yii::$app->get('db')`.
Added benefit is the option for a developer to override configuration in a module.
模块允许任意嵌套; Yii 应用程序本质上是一个模块树。
由于这些模块中的每一个都是服务定位器,所以子模块有权限访问其父模块。
这允许模块使用 `$this->get('db')` 而不是引用根服务定位器 `Yii::$app->get('db')`
增加的好处是开发人员可以覆盖模块中的配置。
Any request for a service to be retrieved from a module will be passed on to its parent in case the module is not able to satisfy it.
Note that configuration from components in a module is never merged with configuration from a component in a parent module. The Service Locator pattern allows us to define named services but one cannot assume servicees with the same name use the same configuration parameters.
如果模块无法满足要求,则从模块中检索服务的请求将被传递给它的父模块。
请注意,模块中组件的配置决不会与来自父模块中组件的配置合并。Service Locator 模式允许我们定义命名服务,但不能假定具有相同名称的服务使用相同的配置参数。

414
docs/guide-zh-CN/db-active-record.md

@ -1,14 +1,14 @@
活动记录
=============
活动记录(Active Record)
======================
[Active Record](http://zh.wikipedia.org/wiki/Active_Record) (活动记录,以下简称 AR)提供了一个面向对象的接口,
用以访问和操作数据库中的数据。一个 AR 类关联一张数据表,
每个 AR 对象对应表中的一行,对象的属性(即 AR 的特性Attribute)映射到数据行的对应列。
即一条活动记录(AR 对象)对应数据表的一行,AR 对象的属性则映射该行的相应列。
您可以直接以面向对象的方式来操纵数据表中的数据,
[Active Record](http://zh.wikipedia.org/wiki/Active_Record) 提供了一个面向对象的接口,
用以访问和操作数据库中的数据。Active Record 类与数据库表关联,
Active Record 实例对应于该表的一行,
Active Record 实例的*属性*表示该行中特定列的值。
您可以访问 Active Record 属性并调用 Active Record 方法来访问和操作存储在数据库表中的数据,
而不用编写原始 SQL 语句。
例如,假定 `Customer` AR 类关联着 `customer` 表,
例如,假定 `Customer` Active Record 类关联着 `customer` 表,
且该类的 `name` 属性代表 `customer` 表的 `name` 列。
你可以写以下代码来哉 `customer` 表里插入一行新的记录:
@ -27,45 +27,45 @@ $db->createCommand('INSERT INTO `customer` (`name`) VALUES (:name)', [
])->execute();
```
下面是所有目前被 Yii 的 AR 功能所支持的数据库列表
Yii 为以下关系数据库提供 Active Record 支持
* MySQL 4.1 及以上: 通过 [[yii\db\ActiveRecord]] 支持
* MySQL 4.1 及以上通过 [[yii\db\ActiveRecord]] 支持
* PostgreSQL 7.3 及以上:通过 [[yii\db\ActiveRecord]] 支持
* SQLite 2 and 3: 通过 [[yii\db\ActiveRecord]] 支持
* SQLite 2 and 3通过 [[yii\db\ActiveRecord]] 支持
* Microsoft SQL Server 2008 及以上:通过 [[yii\db\ActiveRecord]] 支持
* Oracle: 通过 [[yii\db\ActiveRecord]] 支持
* Oracle通过 [[yii\db\ActiveRecord]] 支持
* CUBRID 9.3 及以上:通过 [[yii\db\ActiveRecord]] 支持 (提示, 由于 CUBRID PDO 扩展的 [bug](http://jira.cubrid.org/browse/APIS-658),
给变量加引用将不起作用,所以你得使用 CUBRID 9.3 客户端及服务端。
* Sphinx: 通过 [[yii\sphinx\ActiveRecord]] 支持, 依赖 `yii2-sphinx` 扩展
* ElasticSearch: 通过 [[yii\elasticsearch\ActiveRecord]] 支持, 依赖 `yii2-elasticsearch` 扩展
* Sphinx通过 [[yii\sphinx\ActiveRecord]] 支持, 依赖 `yii2-sphinx` 扩展
* ElasticSearch通过 [[yii\elasticsearch\ActiveRecord]] 支持, 依赖 `yii2-elasticsearch` 扩展
此外,Yii 的 AR 功能还支持以下 NoSQL 数据库:
此外,Yii 的 Active Record 功能还支持以下 NoSQL 数据库:
* Redis 2.6.12 及以上: 通过 [[yii\redis\ActiveRecord]] 支持, 依赖 `yii2-redis` 扩展
* MongoDB 1.3.0 及以上: 通过 [[yii\mongodb\ActiveRecord]] 支持, 依赖 `yii2-mongodb` 扩展
在本教程中,我们会主要描述对关系型数据库的 AR 用法。
然而,绝大多数的内容在 NoSQL 的 AR 里同样适用。
在本教程中,我们会主要描述对关系型数据库的 Active Record 用法。
然而,绝大多数的内容在 NoSQL 的 Active Record 里同样适用。
## 声明 AR 类 <span id="declaring-ar-classes"></span>
## 声明 Active Record(Declaring Active Record Classes) <span id="declaring-ar-classes"></span>
要想声明一个 AR 类,你需要定义几个类 继承 [[yii\db\ActiveRecord]].
要想声明一个 Active Record 类,你需要声明该类继承 [[yii\db\ActiveRecord]]。
### 设置表的名称
### 设置表的名称(Setting a table name)
默认的,每个 AR 类关联各自的数据库表。
默认的,每个 Active Record 类关联各自的数据库表。
经过 [[yii\helpers\Inflector::camel2id()]] 处理,[[yii\db\ActiveRecord::tableName()|tableName()]] 方法默认返回的表名称是通过类名转换来得。
如果这个默认名称不正确,你得重写这个方法。
此外,[[yii\db\Connection::$tablePrefix|tablePrefix]] 表前缀也会起作用。例如,如果
[[yii\db\Connection::$tablePrefix|tablePrefix]] 表前缀是 `tbl_`, `Customer` 的类名将转换成 `tbl_customer` 表名, `OrderItem` 转换成 `tbl_order_item`.
[[yii\db\Connection::$tablePrefix|tablePrefix]] 表前缀是 `tbl_`,`Customer` 的类名将转换成 `tbl_customer` 表名,`OrderItem` 转换成 `tbl_order_item`
如果你定义的表名是 `{{%TableName}}`, 百分比字符 `%` 会被替换成表前缀。
例如, `{{%post}}` 会变成 `{{tbl_post}}`。表名两边的括号会被 [SQL 查询引用](db-dao.md#quoting-table-and-column-names) 处理。
下面的例子中,我们给 `customer` 数据库表定义叫 `Customer` 的 AR 类。
下面的例子中,我们给 `customer` 数据库表定义叫 `Customer` 的 Active Record 类。
```php
namespace app\models;
@ -78,7 +78,7 @@ class Customer extends ActiveRecord
const STATUS_ACTIVE = 1;
/**
* @return string AR 类关联的数据库表名称
* @return string Active Record 类关联的数据库表名称
*/
public static function tableName()
{
@ -87,17 +87,17 @@ class Customer extends ActiveRecord
}
```
### 将 AR 称为模型吧
AR 实例称为 [模型](structure-models.md)。因此, 我们通常将 AR 类
### 将 Active Record 称为模型(Active records are called "models")
Active Record 实例称为[模型](structure-models.md)。因此, 我们通常将 Active Record
放在 `app\models` 命名空间下(或者其他保存模型的命名空间)。
因为 AR [[yii\db\ActiveRecord]] 继承了模型 [[yii\base\Model]], 它就拥有所有 [模型](structure-models.md) 特性,
比如说属性(attributes),验规则(rules),数据序列化,等等。
因为 [[yii\db\ActiveRecord]] 继承了模型 [[yii\base\Model]], 它就拥有所有[模型](structure-models.md)特性,
比如说属性(attributes),验规则(rules),数据序列化(data serialization),等等。
## 建立数据库连接 <span id="db-connection"></span>
## 建立数据库连接(Connecting to Databases) <span id="db-connection"></span>
活动记录 AR 默认使用 `db` [组件](structure-application-components.md)
活动记录 Active Record 默认使用 `db` [组件](structure-application-components.md)
作为连接器 [[yii\db\Connection|DB connection]] 访问和操作数据库数据。
基于[数据库访问](db-dao.md)中的解释,你可以在系统配置中
这样配置 `db` 组件。
@ -132,20 +132,20 @@ class Customer extends ActiveRecord
```
## 查询数据 <span id="querying-data"></span>
## 查询数据(Querying Data) <span id="querying-data"></span>
定义 AR 类后,你可以从相应的数据库表中查询数据。
定义 Active Record 类后,你可以从相应的数据库表中查询数据。
查询过程大致如下三个步骤:
1. 通过 [[yii\db\ActiveRecord::find()]] 方法创建一个新的查询生成器对象;
2. 使用[查询生成器的构建方法](db-query-builder.md#building-queries)来构建你的查询;
3. 调用 [查询生成器的查询方法](db-query-builder.md#query-methods) 来取出数据到 AR 实例中。
3. 调用[查询生成器的查询方法](db-query-builder.md#query-methods)来取出数据到 Active Record 实例中。
你瞅瞅, 是不是跟 [查询生成器](db-query-builder.md) 的步骤差不多。
正如你看到的,是不是跟[查询生成器](db-query-builder.md)的步骤差不多。
唯一有区别的地方在于你用 [[yii\db\ActiveRecord::find()]] 去获得一个新的查询生成器对象,这个对象是 [[yii\db\ActiveQuery]],
而不是使用 `new` 操作符创建一个查询生成器对象。
下面是一些栗子,介绍如何使用 AR 查询数据:
下面是一些例子,介绍如何使用 Active Query 查询数据:
```php
// 返回 ID 为 123 的客户:
@ -177,14 +177,14 @@ $customers = Customer::find()
上述代码中,`$customer` 是个 `Customer` 对象,而 `$customers` 是个以 `Customer` 对象为元素的数组。
它们两都是以 `customer` 表中取回的数据结果集填充的。
> Tip: 由于 [[yii\db\ActiveQuery]] 继承 [[yii\db\Query]],你可以使用 [查询生成器](db-query-builder.md) 章节里所描述的所有查询方法。
> Tip: 由于 [[yii\db\ActiveQuery]] 继承 [[yii\db\Query]],
你可以使用 [Query Builder](db-query-builder.md) 章节里所描述的*所有*查询方法。
根据主键获取数据行是比较常见的操作,所以 Yii
提供了两个快捷方法:
- [[yii\db\ActiveRecord::findOne()]]: 返回一个 AR 实例,填充于查询结果的第一行数据。
- [[yii\db\ActiveRecord::findAll()]]:返回一个 AR 实例的数据,填充于查询结果的全部数据。
- [[yii\db\ActiveRecord::findOne()]]:返回一个 Active Record 实例,填充于查询结果的第一行数据。
- [[yii\db\ActiveRecord::findAll()]]:返回一个 Active Record 实例的数据,填充于查询结果的全部数据。
这两个方法的传参格式如下:
@ -219,11 +219,30 @@ $customers = Customer::findAll([
]);
```
> 注:如果你需要将用户输入传递给这些方法,请确保输入值是标量或者是
> 数组条件,确保数组结构不能被外部所改变:
>
> ```php
> // yii\web\Controller 确保了 $id 是标量
> public function actionView($id)
> {
> $model = Post::findOne($id);
> // ...
> }
>
> // 明确了指定要搜索的列,在此处传递标量或数组将始终只是查找出单个记录而已
> $model = Post::findOne(['id' => Yii::$app->request->get('id')]);
>
> // 不要使用下面的代码!可以注入一个数组条件来匹配任意列的值!
> $model = Post::findOne(Yii::$app->request->get('id'));
> ```
> Tip: [[yii\db\ActiveRecord::findOne()]] 和 [[yii\db\ActiveQuery::one()]] 都不会添加 `LIMIT 1`
生成的 SQL 语句中。如果你的查询会返回很多行的数据,
你明确的应该加上 `limit(1)` 来提高性能,比如 `Customer::find()->limit(1)->one()`
除了使用查询生成器的方法之外,你还可以书写原生的 SQL 语句来查询数据,并填充结果集到 AR 对象中。
除了使用查询生成器的方法之外,你还可以书写原生的 SQL 语句来查询数据,并填充结果集到 Active Record 对象中。
通过使用 [[yii\db\ActiveRecord::findBySql()]] 方法:
```php
@ -236,11 +255,11 @@ $customers = Customer::findBySql($sql, [':status' => Customer::STATUS_INACTIVE])
多余的查询方法都会被忽略。
## 访问数据 <span id="accessing-data"></span>
## 访问数据(Accessing Data) <span id="accessing-data"></span>
如上所述,从数据库返回的数据被填充到 AR 实例中,
查询结果的每一行对应于单个 AR 实例。
您可以通过 AR 实例的属性来访问列值,例如,
如上所述,从数据库返回的数据被填充到 Active Record 实例中,
查询结果的每一行对应于单个 Active Record 实例。
您可以通过 Active Record 实例的属性来访问列值,例如,
```php
// "id" 和 "email" 是 "customer" 表中的列名
@ -249,23 +268,23 @@ $id = $customer->id;
$email = $customer->email;
```
> Tip: AR 的属性以区分大小写的方式为相关联的表列命名的。
Yii 会自动为关联表的每一列定义 AR 中的一个属性。
> Tip: Active Record 的属性以区分大小写的方式为相关联的表列命名的。
Yii 会自动为关联表的每一列定义 Active Record 中的一个属性。
您不应该重新声明任何属性。
由于 AR 的属性以表的列名命名,可能你会发现你正在编写像这样的 PHP 代码 :
由于 Active Record 的属性以表的列名命名,可能你会发现你正在编写像这样的 PHP 代码
`$ customer-> first_name`,如果你的表的列名是使用下划线分隔的,那么属性名中的单词
以这种方式命名。 如果您担心代码风格一致性的问题,那么你应当重命名相应的表列名
(例如使用骆驼拼写法)。
### 数据转换 <span id="data-transformation"></span>
### 数据转换(Data Transformation) <span id="data-transformation"></span>
常常遇到,要输入或显示的数据是一种格式,而要将其存储在数据库中是另一种格式。
例如,在数据库中,您将客户的生日存储为 UNIX 时间戳(虽然这不是一个很好的设计),
而在大多数情况下,你想以字符串 `'YYYY/MM/DD'` 的格式处理生日数据。
为了实现这一目标,您可以在 `Customer` 中定义 *数据转换* 方法
定义 AR 类如下:
定义 Active Record 类如下:
```php
class Customer extends ActiveRecord
@ -292,9 +311,9 @@ class Customer extends ActiveRecord
> 这将更易用,更强大。
### 以数组形式获取数据 <span id="data-in-arrays"></span>
### 以数组形式获取数据(Retrieving Data in Arrays) <span id="data-in-arrays"></span>
通过 AR 对象获取数据十分方便灵活,与此同时,当你需要返回大量的数据的时候,
通过 Active Record 对象获取数据十分方便灵活,与此同时,当你需要返回大量的数据的时候,
这样的做法并不令人满意,因为这将导致大量内存占用。在这种情况下,您可以
在查询方法前调用 [[yii\db\ActiveQuery::asArray()|asArray()]] 方法,来获取 PHP 数组形式的结果:
@ -307,16 +326,16 @@ $customers = Customer::find()
```
> Tip: 虽然这种方法可以节省内存并提高性能,但它更靠近较低的 DB 抽象层
你将失去大部分的 AR 提供的功能。 一个非常重要的区别在于列值的数据类型。
当您在 AR 实例中返回数据时,列值将根据实际列类型,自动类型转换;
你将失去大部分的 Active Record 提供的功能。 一个非常重要的区别在于列值的数据类型。
当您在 Active Record 实例中返回数据时,列值将根据实际列类型,自动类型转换;
然而,当您以数组返回数据时,列值将为
字符串(因为它们是没有处理过的 PDO 的结果),不管它们的实际列是什么类型。
### 批量获取数据 <span id="data-in-batches"></span>
### 批量获取数据(Retrieving Data in Batches) <span id="data-in-batches"></span>
在 [查询生成器](db-query-builder.md) 中,我们已经解释说可以使用 *批处理查询* 来最小化你的内存使用,
每当从数据库查询大量数据。你可以在 AR 中使用同样的技巧。例如,
每当从数据库查询大量数据。你可以在 Active Record 中使用同样的技巧。例如,
```php
// 每次获取 10 条客户数据
@ -336,15 +355,15 @@ foreach (Customer::find()->with('orders')->each() as $customer) {
```
## 保存数据 <span id="inserting-updating-data"></span>
## 保存数据(Saving Data) <span id="inserting-updating-data"></span>
使用 AR (活动记录),您可以通过以下步骤轻松地将数据保存到数据库:
使用 Active Record,您可以通过以下步骤轻松地将数据保存到数据库:
1. 准备一个 AR 实例
2. 将新值赋给 AR 的属性
1. 准备一个 Active Record 实例
2. 将新值赋给 Active Record 的属性
3. 调用 [[yii\db\ActiveRecord::save()]] 保存数据到数据库中。
举个栗子,
例如,
```php
// 插入新记录
@ -359,12 +378,12 @@ $customer->email = 'james@newexample.com';
$customer->save();
```
[[yii\db\ActiveRecord::save()|save()]] 方法可能插入或者更新表的记录,这取决于 AR 实例的状态。
[[yii\db\ActiveRecord::save()|save()]] 方法可能插入或者更新表的记录,这取决于 Active Record 实例的状态。
如果实例通过 `new` 操作符实例化,调用 [[yii\db\ActiveRecord::save()|save()]] 方法将插入新记录;
如果实例是一个查询方法的结果,调用 [[yii\db\ActiveRecord::save()|save()]] 方法
将更新这个实例对应的表记录行。
你可以通过检查 AR 实例的 [[yii\db\ActiveRecord::isNewRecord|isNewRecord]] 属性值来区分这两个状态。
你可以通过检查 Active Record 实例的 [[yii\db\ActiveRecord::isNewRecord|isNewRecord]] 属性值来区分这两个状态。
此属性也被使用在 [[yii\db\ActiveRecord::save()|save()]] 方法内部,
代码如下:
@ -383,7 +402,7 @@ public function save($runValidation = true, $attributeNames = null)
方法来插入或更新一条记录。
### 数据验证 <span id="data-validation"></span>
### 数据验证(Data Validation) <span id="data-validation"></span>
因为 [[yii\db\ActiveRecord]] 继承于 [[yii\base\Model]],它共享相同的 [输入验证](input-validation.md) 功能。
你可以通过重写 [[yii\db\ActiveRecord::rules()|rules()]] 方法声明验证规则并执行,
@ -397,10 +416,10 @@ public function save($runValidation = true, $attributeNames = null)
你可以调用 `save(false)` 来跳过验证过程。
### 块赋值 <span id="massive-assignment"></span>
### 块赋值(Massive Assignment) <span id="massive-assignment"></span>
和普通的 [models](structure-models.md) 一样,你亦可以享受 AR 实例的 [块赋值](structure-models.md#massive-assignment) 特性。
使用此功能,您可以在单个 PHP 语句中,给 AR 实例的多个属性批量赋值,
和普通的 [models](structure-models.md) 一样,你亦可以享受 Active Record 实例的 [块赋值](structure-models.md#massive-assignment) 特性。
使用此功能,您可以在单个 PHP 语句中,给 Active Record 实例的多个属性批量赋值,
如下所示。 记住,只有 [安全属性](structure-models.md#safe-attributes) 才可以批量赋值。
```php
@ -416,7 +435,7 @@ $customer->save();
```
### 更新计数 <span id="updating-counters"></span>
### 更新计数(Updating Counters) <span id="updating-counters"></span>
在数据库表中增加或减少一个字段的值是个常见的任务。我们将这些列称为“计数列”。
您可以使用 [[yii\db\ActiveRecord::updateCounters()|updateCounters()]] 更新一个或多个计数列。
@ -429,24 +448,24 @@ $post = Post::findOne(100);
$post->updateCounters(['view_count' => 1]);
```
> 注:如果你使用 [[yii\db\ActiveRecord::save()]] 更新一个计数列,你最终将得到错误的结果,
> Note: 如果你使用 [[yii\db\ActiveRecord::save()]] 更新一个计数列,你最终将得到错误的结果,
因为可能发生这种情况,多个请求间并发读写同一个计数列。
### 脏属性 <span id="dirty-attributes"></span>
### 脏属性(Dirty Attributes) <span id="dirty-attributes"></span>
当您调用 [[yii\db\ActiveRecord::save()|save()]] 保存 AR 实例时,只有 *脏属性*
当您调用 [[yii\db\ActiveRecord::save()|save()]] 保存 Active Record 实例时,只有 *脏属性*
被保存。如果一个属性的值已被修改,则会被认为是 *脏*,因为它是从 DB 加载出来的或者
刚刚保存到 DB 。请注意,无论如何 AR 都会执行数据验证
刚刚保存到 DB 。请注意,无论如何 Active Record 都会执行数据验证
不管有没有脏属性。
AR 自动维护脏属性列表。 它保存所有属性的旧值,
Active Record 自动维护脏属性列表。 它保存所有属性的旧值,
并其与最新的属性值进行比较,就是酱紫个道理。你可以调用 [[yii\db\ActiveRecord::getDirtyAttributes()]]
获取当前的脏属性。你也可以调用 [[yii\db\ActiveRecord::getDirtyAttributes()]]
将属性显式标记为脏。
如果你有需要获取属性原先的值,你可以调用
[[yii\db\ActiveRecord::getOldAttributes()|getOldAttributes()]] 或者 [[yii\db\ActiveRecord::getOldAttribute()|getOldAttribute()]].
[[yii\db\ActiveRecord::getOldAttributes()|getOldAttributes()]] 或者 [[yii\db\ActiveRecord::getOldAttribute()|getOldAttribute()]]
> 注:属性新旧值的比较是用 `===` 操作符,所以一样的值但类型不同,
> 依然被认为是脏的。当模型从 HTML 表单接收用户输入时,通常会出现这种情况,
@ -456,12 +475,12 @@ AR 自动维护脏属性列表。 它保存所有属性的旧值,
> [intval()](http://php.net/manual/en/function.intval.php), [floatval()](http://php.net/manual/en/function.floatval.php),
> [boolval](http://php.net/manual/en/function.boolval.php),等等
### 默认属性值 <span id="default-attribute-values"></span>
### 默认属性值(Default Attribute Values) <span id="default-attribute-values"></span>
某些表列可能在数据库中定义了默认值。有时,你可能想预先填充
具有这些默认值的 AR 实例的 Web 表单。 为了避免再次写入相同的默认值,
具有这些默认值的 Active Record 实例的 Web 表单。 为了避免再次写入相同的默认值,
您可以调用 [[yii\db\ActiveRecord::loadDefaultValues()|loadDefaultValues()]] 来填充 DB 定义的默认值
进入相应的 AR 属性:
进入相应的 Active Record 属性:
```php
$customer = new Customer();
@ -470,11 +489,11 @@ $customer->loadDefaultValues();
```
### 属性类型转换 <span id="attributes-typecasting"></span>
### 属性类型转换(Attributes Typecasting) <span id="attributes-typecasting"></span>
在查询结果填充 [[yii\db\ActiveRecord]] 活动记录时,将自动对其属性值执行类型转换,基于
在查询结果填充 [[yii\db\ActiveRecord]] 时,将自动对其属性值执行类型转换,基于
[数据库表模式](db-dao.md#database-schema) 中的信息。 这允许从数据表中获取数据,
声明为整型的,使用 PHP 整型填充 AR 实例,布尔值(boolean)的也用布尔值填充 AR 实例,等等。
声明为整型的,使用 PHP 整型填充 ActiveRecord 实例,布尔值(boolean)的也用布尔值填充,等等。
但是,类型转换机制有几个限制:
* 浮点值不被转换,并且将被表示为字符串,否则它们可能会使精度降低。
@ -491,10 +510,36 @@ $customer->loadDefaultValues();
> Tip: 你可以使用 [[yii\behaviors\AttributeTypecastBehavior]] 来简化属性的类型转换
在 ActiveRecord 验证或者保存过程中。
从2.0.14开始,Yii ActiveRecord 支持了更多的复杂数据类型,例如 JSON 或多维数组。
#### MySQL 和 PostgreSQL 中的 JSON(JSON in MySQL and PostgreSQL)
数据填充后,基于 JSON 标准解码规则,
来自 JSON 列的值将自动解码。
### Updating Multiple Rows <span id="updating-multiple-rows"></span>
另一方面,为了将属性值保存到 JSON 列中,ActiveRecord 会自动创建一个 [[yii\db\JsonExpression|JsonExpression]] 对象,
这对象将在 [QueryBuilder](db-query-builder.md) 层被编码成 JSON 字符串。
上述方法都可以用于单个 AR 实例,以插入或更新单条
#### PostgreSQL 中的数组(Arrays in PostgreSQL)
数据填充后,来自 Array 列的值将自动从 PgSQL 的编码值解码为 一个 [[yii\db\ArrayExpression|ArrayExpression]]
对象。它继承于 PHP 的 `ArrayAccess` 接口,所以你可以把它当作一个数组用,或者调用 `->getValue()` 来获取数组本身。
另一方面,为了将属性值保存到数组列,ActiveRecord 会自动创建一个 [[yii\db\ArrayExpression|ArrayExpression]] 对象,
这对象将在 [QueryBuilder](db-query-builder.md) 中被编码成数组的 PgSQL 字符串表达式。
你还可以这样使用 JSON 列的条件:
```php
$query->andWhere(['=', 'json', new ArrayExpression(['foo' => 'bar'])
```
要详细了解表达式构建系统,可以访问 [Query Builder – 增加自定义条件和语句](db-query-builder.md#adding-custom-conditions-and-expressions)
文章。
### 更新多个数据行(Updating Multiple Rows) <span id="updating-multiple-rows"></span>
上述方法都可以用于单个 Active Record 实例,以插入或更新单条
表数据行。 要同时更新多个数据行,你应该调用 [[yii\db\ActiveRecord::updateAll()|updateAll()]]
这是一个静态方法。
@ -512,9 +557,9 @@ Customer::updateAllCounters(['age' => 1]);
```
## 删除数据 <span id="deleting-data"></span>
## 删除数据(Deleting Data) <span id="deleting-data"></span>
要删除单行数据,首先获取与该行对应的 AR 实例,然后调用
要删除单行数据,首先获取与该行对应的 Active Record 实例,然后调用
[[yii\db\ActiveRecord::delete()]] 方法。
```php
@ -528,43 +573,43 @@ $customer->delete();
Customer::deleteAll(['status' => Customer::STATUS_INACTIVE]);
```
> Tip: 不要随意使用 [[yii\db\ActiveRecord::deleteAll()|deleteAll()]] 它真的会
清空你表里的数据,因为你指不定啥时候犯二
> Tip: 调用 [[yii\db\ActiveRecord::deleteAll()|deleteAll()]] 时要非常小心,因为如果在指定条件时出错,
它可能会完全擦除表中的所有数据
## AR 的生命周期 <span id="ar-life-cycles"></span>
## Active Record 的生命周期(Active Record Life Cycles) <span id="ar-life-cycles"></span>
当你实现各种功能的时候,会发现了解 AR 的生命周期很重要。
当你实现各种功能的时候,会发现了解 Active Record 的生命周期很重要。
在每个生命周期中,一系列的方法将被调用执行,您可以重写这些方法
以定制你要的生命周期。您还可以响应触发某些 AR 事件
以便在生命周期中注入您的自定义代码。这些事件在开发 AR 的 [行为](concept-behaviors.md)时特别有用,
通过行为可以定制 AR 生命周期的 。
以定制你要的生命周期。您还可以响应触发某些 Active Record 事件
以便在生命周期中注入您的自定义代码。这些事件在开发 Active Record 的 [行为](concept-behaviors.md)时特别有用,
通过行为可以定制 Active Record 生命周期的 。
下面,我们将总结各种 AR 的生命周期,以及生命周期中
下面,我们将总结各种 Active Record 的生命周期,以及生命周期中
所涉及的各种方法、事件。
### 实例化生命周期 <span id="new-instance-life-cycle"></span>
### 实例化生命周期(New Instance Life Cycle) <span id="new-instance-life-cycle"></span>
当通过 `new` 操作符新建一个 AR 实例时,会发生以下生命周期:
当通过 `new` 操作符新建一个 Active Record 实例时,会发生以下生命周期:
1. 类的构造函数调用.
2. [[yii\db\ActiveRecord::init()|init()]]:触发 [[yii\db\ActiveRecord::EVENT_INIT|EVENT_INIT]] 事件。
### 查询数据生命周期 <span id="querying-data-life-cycle"></span>
### 查询数据生命周期(Querying Data Life Cycle) <span id="querying-data-life-cycle"></span>
当通过 [查询方法](#querying-data) 查询数据时,每个新填充出来的 AR 实例
当通过 [查询方法](#querying-data) 查询数据时,每个新填充出来的 Active Record 实例
将发生下面的生命周期:
1. 类的构造函数调用.
1. 类的构造函数调用
2. [[yii\db\ActiveRecord::init()|init()]]:触发 [[yii\db\ActiveRecord::EVENT_INIT|EVENT_INIT]] 事件。
3. [[yii\db\ActiveRecord::afterFind()|afterFind()]]:触发 [[yii\db\ActiveRecord::EVENT_AFTER_FIND|EVENT_AFTER_FIND]] 事件。
### 保存数据生命周期 <span id="saving-data-life-cycle"></span>
### 保存数据生命周期(Saving Data Life Cycle) <span id="saving-data-life-cycle"></span>
当通过 [[yii\db\ActiveRecord::save()|save()]] 插入或更新 AR 实例时
当通过 [[yii\db\ActiveRecord::save()|save()]] 插入或更新 Active Record 实例时
会发生以下生命周期:
1. [[yii\db\ActiveRecord::beforeValidate()|beforeValidate()]]:触发
@ -583,9 +628,9 @@ Customer::deleteAll(['status' => Customer::STATUS_INACTIVE]);
或者 [[yii\db\ActiveRecord::EVENT_AFTER_UPDATE|EVENT_AFTER_UPDATE]] 事件。
### 删除数据生命周期 <span id="deleting-data-life-cycle"></span>
### 删除数据生命周期(Deleting Data Life Cycle) <span id="deleting-data-life-cycle"></span>
当通过 [[yii\db\ActiveRecord::delete()|delete()]] 删除 AR 实例时,
当通过 [[yii\db\ActiveRecord::delete()|delete()]] 删除 Active Record 实例时,
会发生以下生命周期:
1. [[yii\db\ActiveRecord::beforeDelete()|beforeDelete()]]:触发
@ -597,24 +642,24 @@ Customer::deleteAll(['status' => Customer::STATUS_INACTIVE]);
> Tip: 调用以下方法则不会启动上述的任何生命周期,
> 因为这些方法直接操作数据库,而不是基于 AR 模型:
> 因为这些方法直接操作数据库,而不是基于 Active Record 模型:
>
> - [[yii\db\ActiveRecord::updateAll()]]
> - [[yii\db\ActiveRecord::deleteAll()]]
> - [[yii\db\ActiveRecord::updateCounters()]]
> - [[yii\db\ActiveRecord::updateAllCounters()]]
### 刷新数据生命周期 <span id="refreshing-data-life-cycle"></span>
### 刷新数据生命周期(Refreshing Data Life Cycle) <span id="refreshing-data-life-cycle"></span>
当通过 [[yii\db\ActiveRecord::refresh()|refresh()]] 刷新 AR 实例时,
当通过 [[yii\db\ActiveRecord::refresh()|refresh()]] 刷新 Active Record 实例时,
如刷新成功方法返回 `true`,那么 [[yii\db\ActiveRecord::EVENT_AFTER_REFRESH|EVENT_AFTER_REFRESH]] 事件将被触发。
## 事务操作 <span id="transactional-operations"></span>
## 事务操作(Working with Transactions) <span id="transactional-operations"></span>
AR 活动记录有两种方式来使用 [事务](db-dao.md#performing-transactions)。
Active Record 有两种方式来使用[事务](db-dao.md#performing-transactions)。
第一种方法是在事务块中显式地包含 AR 的各个方法调用,如下所示,
第一种方法是在事务块中显式地包含 Active Record 的各个方法调用,如下所示,
```php
$customer = Customer::findOne(123);
@ -678,7 +723,7 @@ class Customer extends ActiveRecord
这个事务方法的原理是:相应的事务在调用 [[yii\db\ActiveRecord::beforeSave()|beforeSave()]] 方法时开启,
在调用 [[yii\db\ActiveRecord::afterSave()|afterSave()]] 方法时被提交。
## 乐观锁 <span id="optimistic-locks"></span>
## 乐观锁(Optimistic Locks) <span id="optimistic-locks"></span>
乐观锁是一种防止此冲突的方法:一行数据
同时被多个用户更新。例如,同一时间内,用户 A 和用户 B 都在编辑
@ -694,15 +739,15 @@ class Customer extends ActiveRecord
使用乐观锁的步骤,
1. 在与 AR 类相关联的 DB 表中创建一个列,以存储每行的版本号。
1. 在与 Active Record 类相关联的 DB 表中创建一个列,以存储每行的版本号。
这个列应当是长整型(在 MySQL 中是 `BIGINT DEFAULT 0`)。
2. 重写 [[yii\db\ActiveRecord::optimisticLock()]] 方法返回这个列的命名。
3. 在用于用户填写的 Web 表单中,添加一个隐藏字段(hidden field)来存储正在更新的行的当前版本号。
(AR 类中)版本号这个属性你要自行写进 rules() 方法并自己验证一下。
4. 在使用 AR 更新数据的控制器动作中,要捕获(try/catch) [[yii\db\StaleObjectException]] 异常。
(Active Record 类中)版本号这个属性你要自行写进 rules() 方法并自己验证一下。
4. 在使用 Active Record 更新数据的控制器动作中,要捕获(try/catch) [[yii\db\StaleObjectException]] 异常。
实现一些业务逻辑来解决冲突(例如合并更改,提示陈旧的数据等等)。
举个栗子,假定版本列被命名为 `version`。您可以使用下面的代码来实现乐观锁。
 
例如,假定版本列被命名为 `version`。您可以使用下面的代码来实现乐观锁。
```php
@ -737,18 +782,18 @@ public function actionUpdate($id)
```
## 使用关联数据 <span id="relational-data"></span>
## 使用关联数据(Working with Relational Data) <span id="relational-data"></span>
除了处理单个数据库表之外,AR 还可以将相关数据集中进来,
除了处理单个数据库表之外,Active Record 还可以将相关数据集中进来,
使其可以通过原始数据轻松访问。 例如,客户数据与订单数据相关
因为一个客户可能已经存放了一个或多个订单。这种关系通过适当的声明,
你可以使用 `$customer->orders` 表达式访问客户的订单信息
这表达式将返回包含 `Order` AR 实例的客户订单信息的数组。
这表达式将返回包含 `Order` Active Record 实例的客户订单信息的数组。
### 声明关联关系 <span id="declaring-relations"></span>
### 声明关联关系(Declaring Relations) <span id="declaring-relations"></span>
你必须先在 AR 类中定义关联关系,才能使用 AR 的关联数据。
你必须先在 Active Record 类中定义关联关系,才能使用 Active Record 的关联数据。
简单地为每个需要定义关联关系声明一个 *关联方法* 即可,如下所示,
```php
@ -784,12 +829,12 @@ class Order extends ActiveRecord
- 关联的对应关系:通过调用 [[yii\db\ActiveRecord::hasMany()|hasMany()]]
或者 [[yii\db\ActiveRecord::hasOne()|hasOne()]] 指定。在上面的例子中,您可以很容易看出这样的关联声明:
一个客户可以有很多订单,而每个订单只有一个客户。
- 相关联 AR 类名:用来指定为 [[yii\db\ActiveRecord::hasMany()|hasMany()]] 或者
- 相关联 Active Record 类名:用来指定为 [[yii\db\ActiveRecord::hasMany()|hasMany()]] 或者
[[yii\db\ActiveRecord::hasOne()|hasOne()]] 方法的第一个参数。
推荐的做法是调用 `Xyz::className()` 来获取类名称的字符串,以便您
可以使用 IDE 的自动补全,以及让编译阶段的错误检测生效。
- 两组数据的关联列:用以指定两组数据相关的列(hasOne()/hasMany() 的第二个参数)。
数组的值填的是主数据的列(当前要声明关联的 AR 类为主数据),
数组的值填的是主数据的列(当前要声明关联的 Active Record 类为主数据),
而数组的键要填的是相关数据的列。
一个简单的口诀,先附表的主键,后主表的主键。
@ -797,7 +842,7 @@ class Order extends ActiveRecord
(译者注:hasMany() 的第二个参数,这个数组键值顺序不要弄反了)
### 访问关联数据 <span id="accessing-relational-data"></span>
### 访问关联数据(Accessing Relational Data) <span id="accessing-relational-data"></span>
定义了关联关系后,你就可以通过关联名访问相应的关联数据了。就像
访问一个由关联方法定义的对象一样,具体概念请查看 [属性](concept-properties.md)。
@ -816,9 +861,9 @@ $orders = $customer->orders;
[属性](concept-properties.md) 那样访问 `xyz`。注意这个命名是区分大小写的。
如果使用 [[yii\db\ActiveRecord::hasMany()|hasMany()]] 声明关联关系,则访问此关联属性
将返回相关的 AR 实例的数组;
将返回相关的 Active Record 实例的数组;
如果使用 [[yii\db\ActiveRecord::hasOne()|hasOne()]] 声明关联关系,访问此关联属性
将返回相关的 AR 实例,如果没有找到相关数据的话,则返回 `null`
将返回相关的 Active Record 实例,如果没有找到相关数据的话,则返回 `null`
当你第一次访问关联属性时,将执行 SQL 语句获取数据,如
上面的例子所示。如果再次访问相同的属性,将返回先前的结果,而不会重新执行
@ -828,7 +873,7 @@ SQL 语句。要强制重新执行 SQL 语句,你应该先 unset 这个关联
> Tip: 虽然这个概念跟 这个 [属性](concept-properties.md) 特性很像,
> 但是还是有一个很重要的区别。普通对象属性的属性值与其定义的 getter 方法的类型是相同的。
> 而关联方法返回的是一个 [[yii\db\ActiveQuery]] 活动查询生成器的实例。只有当访问关联属性的的时候,
> 才会返回 [[yii\db\ActiveRecord]] AR 实例,或者 AR 实例组成的数组。
> 才会返回 [[yii\db\ActiveRecord]] Active Record 实例,或者 Active Record 实例组成的数组。
>
> ```php
> $customer->orders; // 获得 `Order` 对象的数组
@ -838,7 +883,7 @@ SQL 语句。要强制重新执行 SQL 语句,你应该先 unset 这个关联
> 这对于创建自定义查询很有用,下一节将对此进行描述。
### 动态关联查询 <span id="dynamic-relational-query"></span>
### 动态关联查询(Dynamic Relational Query) <span id="dynamic-relational-query"></span>
由于关联方法返回 [[yii\db\ActiveQuery]] 的实例,因此你可以在执行 DB 查询之前,
使用查询构建方法进一步构建此查询。例如,
@ -882,7 +927,7 @@ $orders = $customer->bigOrders;
```
### 中间关联表 <span id="junction-table"></span>
### 中间关联表(Relations via a Junction Table) <span id="junction-table"></span>
在数据库建模中,当两个关联表之间的对应关系是多对多时,
通常会引入一个[连接表](https://en.wikipedia.org/wiki/Junction_table)。例如,`order` 表
@ -936,10 +981,45 @@ $items = $order->items;
```
### 延迟加载和即时加载(又称惰性加载与贪婪加载) <span id="lazy-eager-loading"></span>
### 通过多个表来连接关联声明(Chaining relation definitions via multiple tables) <span id="multi-table-relations"></span>
通过使用 [[yii\db\ActiveQuery::via()|via()]] 方法,它还可以通过多个表来定义关联声明。
再考虑考虑上面的例子,我们有 `Customer`, `Order`, 和 `Item` 类。
我们可以添加一个关联关系到 `Customer` 类,这个关联可以列出了 `Customer`(客户) 的订单下放置的所有 `Item`(商品),
这个关联命名为 `getPurchasedItems()`,关联声明如下代码示例所示:
```php
class Customer extends ActiveRecord
{
// ...
public function getPurchasedItems()
{
// 客户的商品,将 Item 中的 'id' 列与 OrderItem 中的 'item_id' 相匹配
return $this->hasMany(Item::className(), ['id' => 'item_id'])
->via('orderItems');
}
public function getOrderItems()
{
// 客户订单中的商品,将 `Order` 的 'id' 列和 OrderItem 的 'order_id' 列相匹配
return $this->hasMany(OrderItem::className(), ['order_id' => 'id'])
->via('orders');
}
public function getOrders()
{
// 见上述列子
return $this->hasMany(Order::className(), ['customer_id' => 'id']);
}
}
```
### 延迟加载和即时加载(Lazy Loading and Eager Loading) <span id="lazy-eager-loading"></span>
在 [访问关联数据](#accessing-relational-data) 中,我们解释说可以像问正常的对象属性那样
访问 AR 实例的关联属性。SQL 语句仅在
访问 Active Record 实例的关联属性。SQL 语句仅在
你第一次访问关联属性时执行。我们称这种关联数据访问方法为 *延迟加载*
例如,
@ -954,7 +1034,7 @@ $orders = $customer->orders;
$orders2 = $customer->orders;
```
延迟加载使用非常方便。但是,当你需要访问相同的具有多个 AR 实例的关联属性时,
延迟加载使用非常方便。但是,当你需要访问相同的具有多个 Active Record 实例的关联属性时,
可能会遇到性能问题。请思考一下以下代码示例。
有多少 SQL 语句会被执行?
@ -988,11 +1068,11 @@ foreach ($customers as $customer) {
}
```
通过调用 [[yii\db\ActiveQuery::with()]] 方法,你使 AR 在一条 SQL 语句里就返回了这 100 位客户的订单。
通过调用 [[yii\db\ActiveQuery::with()]] 方法,你使 Active Record 在一条 SQL 语句里就返回了这 100 位客户的订单。
结果就是,你把要执行的 SQL 语句从 101 减少到 2 条!
你可以即时加载一个或多个关联。 你甚至可以即时加载 *嵌套关联* 。嵌套关联是一种
在相关的 AR 类中声明的关联。例如,`Customer` 通过 `orders` 关联属性 与 `Order` 相关联,
在相关的 Active Record 类中声明的关联。例如,`Customer` 通过 `orders` 关联属性 与 `Order` 相关联,
`Order``Item` 通过 `items` 关联属性相关联。 当查询 `Customer` 时,您可以即时加载
通过嵌套关联符 `orders.items` 关联的 `items`
@ -1009,10 +1089,10 @@ $orders= $customers[0]->orders;
// 没有任何的 SQL 执行
$country = $customers[0]->country;
// eager loading "orders" and the nested relation "orders.items"
// 即时加载“订单”和嵌套关系“orders.items”
$customers = Customer::find()->with('orders.items')->all();
// access the items of the first order of the first customer
// no SQL executed
// 访问第一个客户的第一个订单中的商品
// 没有 SQL 查询执行
$items = $customers[0]->orders[0]->items;
```
@ -1056,7 +1136,7 @@ $customers = Customer::find()->with([
> ```
### 关联关系的 JOIN 查询 <span id="joining-with-relations"></span>
### 关联关系的 JOIN 查询(Joining with Relations) <span id="joining-with-relations"></span>
> Tip: 这小节的内容仅仅适用于关系数据库,
比如 MySQL,PostgreSQL 等等。
@ -1099,7 +1179,9 @@ $customers = Customer::find()
如果你想要的连接类型是 `INNER JOIN`,你可以直接用 [[yii\db\ActiveQuery::innerJoinWith()|innerJoinWith()]] 方法代替。
调用 [[yii\db\ActiveQuery::joinWith()|joinWith()]] 方法会默认 [即时加载](#lazy-eager-loading) 相应的关联数据。
如果你不需要那些关联数据,你可以指定它的第二个参数 $eagerLoading` 为 `false`
如果你不需要那些关联数据,你可以指定它的第二个参数 `$eagerLoading``false`
> Note: 即使在启用即时加载的情况下使用 [[yii\db\ActiveQuery::joinWith()|joinWith()]] 或 [[yii\db\ActiveQuery::innerJoinWith()|innerJoinWith()]],相应的关联数据也**不会**从这个 `JOIN` 查询的结果中填充。 因此,每个连接关系还有一个额外的查询,正如[即时加载](#lazy-eager-loading)部分所述。
和 [[yii\db\ActiveQuery::with()|with()]] 一样,你可以 join 多个关联表;你可以动态的自定义
你的关联查询;你可以使用嵌套关联进行 join。你也可以将 [[yii\db\ActiveQuery::with()|with()]]
@ -1130,14 +1212,14 @@ $customers = Customer::find()->joinWith([
```
以上查询取出 *所有* 客户,并为每个客户取回所有活跃订单。
港真,这与我们之前的例子不同,后者仅取出至少有一个活跃订单的客户。
请注意,这与我们之前的例子不同,后者仅取出至少有一个活跃订单的客户。
> Tip: 当通过 [[yii\db\ActiveQuery::onCondition()|onCondition()]] 修改 [[yii\db\ActiveQuery]] 时,
如果查询涉及到 JOIN 查询,那么条件将被放在 `ON` 部分。如果查询不涉及
JOIN ,条件将自动附加到查询的 `WHERE` 部分。
因此,它可以只包含 包含了关联表的列 的条件。(译者注:意思是 onCondition() 中可以只写关联表的列,主表的列写不写都行)
#### Relation table aliases <span id="relation-table-aliases"></span>
#### 关联表别名(Relation table aliases <span id="relation-table-aliases"></span>
如前所述,当在查询中使用 JOIN 时,我们需要消除列名的歧义。因此通常为一张表定义
一个别名。可以通过以下列方式自定义关联查询来设置关联查询的别名:
@ -1169,9 +1251,9 @@ $query->joinWith(['orders o' => function($q) {
->where('o.amount > 100');
```
### 反向关联 <span id="inverse-relations"></span>
### 反向关联(Inverse Relations) <span id="inverse-relations"></span>
两个 AR 类之间的关联声明往往像 *倒数* 那样。例如,`Customer` 是
两个 Active Record 类之间的关联声明往往是相互关联的。例如,`Customer` 是
通过 `orders` 关联到 `Order` ,而`Order` 通过 `customer` 又关联回到了 `Customer`
```php
@ -1192,7 +1274,7 @@ class Order extends ActiveRecord
}
```
现在开一下脑洞
现在考虑下面的一段代码
```php
// SELECT * FROM `customer` WHERE `id` = 123
@ -1242,15 +1324,15 @@ $customer2 = $order->customer;
echo $customer2 === $customer ? 'same' : 'not the same';
```
> Tip: 反向关联不能用在有 [连接表](#junction-table) 关联声明中。
> Note: 反向关联不能用在有 [连接表](#junction-table) 关联声明中。
也就是说,如果一个关联关系通过 [[yii\db\ActiveQuery::via()|via()]] 或 [[yii\db\ActiveQuery::viaTable()|viaTable()]] 声明,
你就不能再调用 [[yii\db\ActiveQuery::inverseOf()|inverseOf()]] 了。
## 保存关联数据 <span id="saving-relations"></span>
## 保存关联数据(Saving Relations) <span id="saving-relations"></span>
在使用关联数据时,您经常需要建立不同数据之间的关联或销毁
现有关联。这需要为定义的关联的列设置正确的值。通过使用 AR 活动记录
现有关联。这需要为定义的关联的列设置正确的值。通过使用 Active Record
你就可以编写如下代码:
```php
@ -1264,7 +1346,7 @@ $order->customer_id = $customer->id;
$order->save();
```
AR 提供了 [[yii\db\ActiveRecord::link()|link()]] 方法,可以更好地完成此任务:
Active Record 提供了 [[yii\db\ActiveRecord::link()|link()]] 方法,可以更好地完成此任务:
```php
$customer = Customer::findOne(123);
@ -1276,15 +1358,15 @@ $order->link('customer', $customer);
```
[[yii\db\ActiveRecord::link()|link()]] 方法需要指定关联名
和要建立关联的目标 AR 实例。该方法将修改属性的值
以连接两个 AR 实例,并将其保存到数据库。在上面的例子中,它将设置 `Order` 实例的 `customer_id` 属性
和要建立关联的目标 Active Record 实例。该方法将修改属性的值
以连接两个 Active Record 实例,并将其保存到数据库。在上面的例子中,它将设置 `Order` 实例的 `customer_id` 属性
`Customer` 实例的 `id` 属性的值,然后保存
到数据库。
> Tip: 你不能 link() 两个新的 AR 实例。(译者注:其中的一个必须是数据库中查询出来的)
> Note: 你不能关联两个新的 Active Record 实例。
当一个关联关系通过 [连接表](#junction-table) 定义时,此 [[yii\db\ActiveRecord::link()|link()]] 方法更能体现在党的领导下的中国特色社会主义的优越性
例如,你可以使用以下代码 link() `Order` 实例
使用 [[yii\db\ActiveRecord::link()|link()]] 的好处在通过 [junction table](#junction-table) 定义关系时更加明显
例如,你可以使用以下代码关联 `Order` 实例
`Item` 实例:
```php
@ -1293,12 +1375,12 @@ $order->link('items', $item);
上述代码会自动在 `order_item` 关联表中插入一行,以关联 order 和 item 这两个数据记录。
> Tip: [[yii\db\ActiveRecord::link()|link()]] 方法在保存相应的 AR 实例时,
> Info: [[yii\db\ActiveRecord::link()|link()]] 方法在保存相应的 Active Record 实例时,
将不会执行任何数据验证。在调用此方法之前,
您应当验证所有的输入数据。
[[yii\db\ActiveRecord::link()|link()]] 方法的反向操作是 [[yii\db\ActiveRecord::unlink()|unlink()]] 方法,
这将可以断掉两个 AR 实例间的已经存在了的关联关系。例如,
这将可以断掉两个 Active Record 实例间的已经存在了的关联关系。例如,
```php
$customer = Customer::find()->with('orders')->where(['id' => 123])->one();
@ -1314,9 +1396,9 @@ $customer->unlink('orders', $customer->orders[0]);
连接表中的外键或相应的行被删除。
## 跨数据库关联 <span id="cross-database-relations"></span>
## 跨数据库关联(Cross-Database Relations) <span id="cross-database-relations"></span>
AR 活动记录允许您在不同数据库驱动的 AR 类之间声明关联关系。
Active Record 允许您在不同数据库驱动的 Active Record 类之间声明关联关系。
这些数据库可以是不同的类型(例如 MySQL 和 PostgreSQL ,或是 MS SQL 和 MongoDB),它们也可以运行在
不同的服务器上。你可以使用相同的语法来执行关联查询。例如,
@ -1356,13 +1438,13 @@ $customers = Customer::find()->with('comments')->all();
本节中描述的大多数关联查询功能,你都可以抄一抄。
> Tip: [[yii\db\ActiveQuery::joinWith()|joinWith()]] 这个功能限制于某些数据库是否支持跨数据库 JOIN 查询。
因此,你再上述的代码里就不能用此方法了,因为 MongoDB 不知道 JOIN 查询。
> Note: [[yii\db\ActiveQuery::joinWith()|joinWith()]] 这个功能限制于某些数据库是否支持跨数据库 JOIN 查询。
 因此,你再上述的代码里就不能用此方法了,因为 MongoDB 不支持 JOIN 查询。
## 自定义查询类 <span id="customizing-query-classes"></span>
## 自定义查询类(Customizing Query Classes) <span id="customizing-query-classes"></span>
默认情况下,[[yii\db\ActiveQuery]] 支持所有 AR 查询。要在 AR 类中使用自定义的查询类,
默认情况下,[[yii\db\ActiveQuery]] 支持所有 Active Record 查询。要在 Active Record 类中使用自定义的查询类,
您应该重写 [[yii\db\ActiveRecord::find()]] 方法并返回一个你自定义查询类的实例。
例如,
@ -1410,7 +1492,7 @@ class CommentQuery extends ActiveQuery
}
```
> Tip: 作为 [[yii\db\ActiveQuery::onCondition()|onCondition()]] 方法的替代方案,你应当
> Note: 作为 [[yii\db\ActiveQuery::onCondition()|onCondition()]] 方法的替代方案,你应当
调用 [[yii\db\ActiveQuery::andOnCondition()|andOnCondition()]] 或 [[yii\db\ActiveQuery::orOnCondition()|orOnCondition()]] 方法来附加新增的条件,不然在一个新定义的查询方法,已存在的条件可能会被覆盖。
然后你就可以先下面这样构建你的查询了:
@ -1421,7 +1503,7 @@ $inactiveComments = Comment::find()->active(false)->all();
```
> Tip: 在大型项目中,建议您使用自定义查询类来容纳大多数与查询相关的代码,
以使 AR 类保持简洁。
以使 Active Record 类保持简洁。
您还可以在 `Comment` 关联关系的定义中或在执行关联查询时,使用刚刚新建查询构建方法:
@ -1456,12 +1538,12 @@ $customers = Customer::find()->joinWith([
你依然可以使用自定义查询类、查询方法来达到一样的效果。
## 选择额外的字段
## 选择额外的字段(Selecting extra fields)
当 AR 实例从查询结果中填充时,从数据结果集中,
当 Active Record 实例从查询结果中填充时,从数据结果集中,
其属性的值将被相应的列填充。
你可以从查询中获取其他列或值,并将其存储在 AR 活动记录中。
你可以从查询中获取其他列或值,并将其存储在 Active Record 活动记录中。
例如,假设我们有一个名为 `room` 的表,其中包含有关酒店可用房间的信息。
每个房间使用字段 `length`,`width`,`height` 存储有关其空间大小的信息。
想象一下,我们需要检索出所有可用房间的列表,并按照体积大小倒序排列。
@ -1570,8 +1652,8 @@ class Room extends \yii\db\ActiveRecord
}
```
当 select 查询不提供 volume 体积时,这模型将能够自动计算体积的值出来
当访问模型的属性的时候。
当 select 查询不提供 volume 体积时,这模型将能够自动计算体积的值出来
当访问模型的属性的时候。
当定义关联关系的时候,你也可以计算聚合字段:
@ -1608,7 +1690,7 @@ class Customer extends \yii\db\ActiveRecord
```
使用此代码,如果 'select' 语句中存在 'ordersCount' - 它会从查询结果集获取数据填充 `Customer::ordersCount` 属性,
否则它会在被访问的时候,使用 `Customer::orders` 关联按需计算。
否则它会在被访问的时候,使用 `Customer::orders` 关联按需计算。
这种方法也适用于创建一些关联数据的快捷访问方式,特别是对于聚合。
例如:

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

@ -1,5 +1,5 @@
数据库访问 (DAO)
========
数据库访问对象(Database Access Objects)
=====================================
Yii 包含了一个建立在 PHP PDO 之上的数据访问层 (DAO)。DAO为不同的数据库提供了一套统一的API。
其中 `ActiveRecord` 提供了数据库与模型(MVC 中的 M,Model) 的交互,`QueryBuilder` 用于创建动态的查询语句。
@ -23,10 +23,9 @@ Yii DAO 支持下列现成的数据库:
[instruction provided by community](https://github.com/yiisoft/yii2/issues/10975#issuecomment-248479268)
to compile it or use [PDO emulation layer](https://github.com/taq/pdooci).
## 创建数据库连接 <span id="creating-db-connections"></span>
## 创建数据库连接(Creating DB Connections) <span id="creating-db-connections"></span>
想要访问数据库,
你首先需要通过创建一个 [[yii\db\Connection]] 实例来与之建立连接。
想要访问数据库,你首先需要通过创建一个 [[yii\db\Connection]] 实例来与之建立连接。
```php
$db = new yii\db\Connection([
@ -38,8 +37,7 @@ $db = new yii\db\Connection([
```
因为数据库连接经常需要在多个地方使用到,
一个常见的做法是以[应用组件](structure-application-components.md)的方式来配置它,
如下:
一个常见的做法是以[应用组件](structure-application-components.md)的方式来配置它,如下:
```php
return [
@ -64,8 +62,7 @@ return [
配置数据库连接时, 你应该总是通过 [[yii\db\Connection::dsn|dsn]] 属性来指明它的数据源名称 (DSN) 。
不同的数据库有着不同的 DSN 格式。
请参考 [PHP manual](http://www.php.net/manual/en/function.PDO-construct.php) 来获得更多细节。
下面是一些例子:
请参考 [PHP manual](http://www.php.net/manual/en/function.PDO-construct.php) 来获得更多细节。下面是一些例子:
* MySQL, MariaDB: `mysql:host=localhost;dbname=mydatabase`
* SQLite: `sqlite:/path/to/database/file`
@ -76,10 +73,8 @@ return [
* MS SQL Server (via mssql driver): `mssql:host=localhost;dbname=mydatabase`
* Oracle: `oci:dbname=//localhost:1521/mydatabase`
请注意,如果你是通过 ODBC 来连接数据库,
你应该配置 [[yii\db\Connection::driverName]] 属性,
以便 Yii 能够知道实际的数据库种类。
例如:
请注意,如果你是通过 ODBC 来连接数据库,你应该配置 [[yii\db\Connection::driverName]] 属性,
以便 Yii 能够知道实际的数据库种类。例如:
```php
'db' => [
@ -92,15 +87,14 @@ return [
```
除了 [[yii\db\Connection::dsn|dsn]] 属性,
你常常需要配置 [[yii\db\Connection::username|username]] 和 [[yii\db\Connection::password|password]]。
请参考 [[yii\db\Connection]] 来获取完整的可配置属性列表。
你常常需要配置 [[yii\db\Connection::username|username]] 和 [[yii\db\Connection::password|password]]。请参考 [[yii\db\Connection]] 来获取完整的可配置属性列表。
> Info: 当你实例化一个 DB Connection 时,
直到你第一次执行 SQL 或者你明确地调用 [[yii\db\Connection::open()|open()]] 方法时,
> Info: 当你实例化一个 DB Connection 时,直到你第一次执行 SQL 或者你明确地调用 [[yii\db\Connection::open()|open()]] 方法时,
才建立起实际的数据库连接。
> Tip: 有时你可能想要在建立起数据库连接时立即执行一些语句来初始化一些环境变量 (比如设置时区或者字符集),
> 你可以通过为数据库连接的 [[yii\db\Connection::EVENT_AFTER_OPEN|afterOpen]] 事件注册一个事件处理器来达到目的。
> 你可以通过为数据库连接的 [[yii\db\Connection::EVENT_AFTER_OPEN|afterOpen]]
> 事件注册一个事件处理器来达到目的。
> 你可以像这样直接在应用配置中注册处理器:
>
> ```php
@ -114,13 +108,12 @@ return [
> ```
## 执行 SQL 查询 <span id="executing-sql-queries"></span>
## 执行 SQL 查询(Executing SQL Queries) <span id="executing-sql-queries"></span>
一旦你拥有了 DB Connection 实例,
你可以按照下列步骤来执行 SQL 查询:
一旦你拥有了 DB Connection 实例,你可以按照下列步骤来执行 SQL 查询:
1. 使用纯SQL查询来创建出 [[yii\db\Command]];
2. 绑定参数 (可选的);
1. 使用纯SQL查询来创建出 [[yii\db\Command]]
2. 绑定参数 (可选的)
3. 调用 [[yii\db\Command]] 里 SQL 执行方法中的一个。
下列例子展示了几种不同的从数据库取得数据的方法:
@ -147,12 +140,11 @@ $count = Yii::$app->db->createCommand('SELECT COUNT(*) FROM post')
->queryScalar();
```
> Note: 为了保持精度,
> 即使对应的数据库列类型为数值型,
> Note: 为了保持精度,即使对应的数据库列类型为数值型,
> 所有从数据库取得的数据都被表现为字符串。
### 绑定参数 <span id="binding-parameters"></span>
### 绑定参数(Binding Parameters) <span id="binding-parameters"></span>
当使用带参数的 SQL 来创建数据库命令时,
你几乎总是应该使用绑定参数的方法来防止 SQL 注入攻击,例如:
@ -164,14 +156,14 @@ $post = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id AND status
->queryOne();
```
在 SQL 语句中,
你可以嵌入一个或多个参数占位符(例如,上述例子中的 `:id` )。
在 SQL 语句中,你可以嵌入一个或多个参数占位符(例如,上述例子中的 `:id` )。
一个参数占位符应该是以冒号开头的字符串。
之后你可以调用下面绑定参数的方法来绑定参数值:
* [[yii\db\Command::bindValue()|bindValue()]]:绑定一个参数值
* [[yii\db\Command::bindValues()|bindValues()]]:在一次调用中绑定多个参数值
* [[yii\db\Command::bindParam()|bindParam()]]:与 [[yii\db\Command::bindValue()|bindValue()]] 相似,但是也支持绑定参数引用。
* [[yii\db\Command::bindParam()|bindParam()]]:与 [[yii\db\Command::bindValue()|bindValue()]]
相似,但是也支持绑定参数引用。
下面的例子展示了几个可供选择的绑定参数的方法:
@ -187,11 +179,8 @@ $post = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id AND status
```
绑定参数是通过 [预处理语句](http://php.net/manual/en/mysqli.quickstart.prepared-statements.php) 实现的。
除了防止 SQL 注入攻击,
它也可以通过一次预处理 SQL 语句,
使用不同参数多次执行,
来提升性能。
例如:
除了防止 SQL 注入攻击,它也可以通过一次预处理 SQL 语句,
使用不同参数多次执行,来提升性能。例如:
```php
$command = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id');
@ -220,13 +209,16 @@ $post2 = $command->queryOne();
然后在之后的每次执行前改变变量的值(这通常是用循环来完成的)。
以这种方式执行查询比为每个不同的参数值执行一次新的查询要高效得多得多。
> Info: 参数绑定仅用于需要将值插入到包含普通SQL的字符串中的地方。
> 在 [Query Builder](db-query-builder.md) 和 [Active Record](db-active-record.md)
> 等更高抽象层的许多地方,您经常会指定一组将被转换为 SQL 的值。
> 在这些地方,参数绑定是由 Yii 内部完成的,因此不需要手动指定参数。
### 执行非查询语句 <span id="non-select-queries"></span>
上面部分中介绍的 `queryXyz()` 方法都处理的是从数据库返回数据的查询语句。
对于那些不取回数据的语句,
你应该调用的是 [[yii\db\Command::execute()]] 方法。
例如,
### 执行非查询语句(Executing Non-SELECT Queries) <span id="non-select-queries"></span>
上面部分中介绍的 `queryXyz()` 方法都处理的是从数据库返回数据的查询语句。对于那些不取回数据的语句,
你应该调用的是 [[yii\db\Command::execute()]] 方法。例如,
```php
Yii::$app->db->createCommand('UPDATE post SET status=1 WHERE id=1')
@ -235,14 +227,9 @@ Yii::$app->db->createCommand('UPDATE post SET status=1 WHERE id=1')
[[yii\db\Command::execute()]] 方法返回执行 SQL 所影响到的行数。
对于 INSERT, UPDATE 和 DELETE 语句,
不再需要写纯SQL语句了,
你可以直接调用 [[yii\db\Command::insert()|insert()]]、
[[yii\db\Command::update()|update()]]、
[[yii\db\Command::delete()|delete()]],
来构建相应的 SQL 语句。
这些方法将正确地引用表和列名称以及绑定参数值。
例如,
对于 INSERT, UPDATE 和 DELETE 语句,不再需要写纯SQL语句了,
你可以直接调用 [[yii\db\Command::insert()|insert()]]、[[yii\db\Command::update()|update()]]、[[yii\db\Command::delete()|delete()]],
来构建相应的 SQL 语句。这些方法将正确地引用表和列名称以及绑定参数值。例如,
```php
// INSERT (table name, column values)
@ -270,23 +257,36 @@ Yii::$app->db->createCommand()->batchInsert('user', ['name', 'age'], [
])->execute();
```
另一个有用的方法是 [[yii\db\Command::upsert()|upsert()]]。Upsert 是一种原子操作,如果它们不存在(匹配唯一约束),则将行插入到数据库表中,
或者在它们执行时更新它们:
```php
Yii::$app->db->createCommand()->upsert('pages', [
'name' => 'Front page',
'url' => 'http://example.com/', // url is unique
'visits' => 0,
], [
'visits' => new \yii\db\Expression('visits + 1'),
], $params)->execute();
```
上面的代码将插入一个新的页面记录或自动增加访问计数器。
请注意,上述的方法只是构建出语句,
你总是需要调用 [[yii\db\Command::execute()|execute()]] 来真正地执行它们。
## 引用表和列名称 <span id="quoting-table-and-column-names"></span>
## 引用表和列名称(Quoting Table and Column Names) <span id="quoting-table-and-column-names"></span>
当写与数据库无关的代码时,
正确地引用表和列名称总是一件头疼的事,
因为不同的数据库有不同的名称引用规则,
为了克服这个问题,
当写与数据库无关的代码时,正确地引用表和列名称总是一件头疼的事,
因为不同的数据库有不同的名称引用规则,为了克服这个问题,
你可以使用下面由 Yii 提出的引用语法。
* `[[column name]]`: 使用两对方括号来将列名括起来;
* `{{table name}}`: 使用两对大括号来将表名括起来。
Yii DAO 将自动地根据数据库的具体语法来将这些结构转化为对应的被引用的列或者表名称。
Yii DAO 将自动地根据数据库的具体语法来将这些结构转化为对应的
被引用的列或者表名称。
例如,
```php
@ -296,7 +296,7 @@ $count = Yii::$app->db->createCommand("SELECT COUNT([[id]]) FROM {{employee}}")
```
### 使用表前缀 <span id="using-table-prefix"></span>
### 使用表前缀(Using Table Prefix) <span id="using-table-prefix"></span>
如果你的数据库表名大多都拥有一个共同的前缀,
你可以使用 Yii DAO 所提供的表前缀功能。
@ -316,10 +316,8 @@ return [
];
```
接着在你的代码中,
当你需要涉及到一张表名中包含该前缀的表时,
应使用语法 `{{%table_name}}`
百分号将被自动地替换为你在配置 DB 组件时指定的表前缀。
接着在你的代码中,当你需要涉及到一张表名中包含该前缀的表时,
应使用语法 `{{%table_name}}`。百分号将被自动地替换为你在配置 DB 组件时指定的表前缀。
例如,
```php
@ -328,14 +326,10 @@ $count = Yii::$app->db->createCommand("SELECT COUNT([[id]]) FROM {{%employee}}")
->queryScalar();
```
### 预处理语句
为安全传递查询参数可以使用预处理语句,首先应当使用 `:placeholder` 占位,再将变量绑定到对应占位符:
## 执行事务(Performing Transactions) <span id="performing-transactions"></span>
## 执行事务 <span id="performing-transactions"></span>
当顺序地执行多个相关的语句时,
你或许需要将它们包在一个事务中来保证数据库的完整性和一致性。
当顺序地执行多个相关的语句时, 你或许需要将它们包在一个事务中来保证数据库的完整性和一致性。
如果这些语句中的任何一个失败了,
数据库将回滚到这些语句执行前的状态。
@ -349,24 +343,22 @@ Yii::$app->db->transaction(function($db) {
});
```
上述代码等价于下面的代码,
但是下面的代码给予了你对于错误处理代码的更多掌控:
上述代码等价于下面的代码,但是下面的代码给予了你对于错误处理代码的更多掌控:
```php
$db = Yii::$app->db;
$transaction = $db->beginTransaction();
try {
$db->createCommand($sql1)->execute();
$db->createCommand($sql2)->execute();
// ... executing other SQL statements ...
$transaction->commit();
} catch(\Exception $e) {
$transaction->rollBack();
throw $e;
} catch(\Throwable $e) {
$transaction->rollBack();
throw $e;
}
```
@ -384,13 +376,10 @@ try {
就好像我们没有捕获它一样,
因此正常的错误处理程序将处理它。
### 指定隔离级别 <span id="specifying-isolation-levels"></span>
### 指定隔离级别(Specifying Isolation Levels) <span id="specifying-isolation-levels"></span>
Yii 也支持为你的事务设置[隔离级别]。
默认情况下,
当我们开启一个新事务,
它将使用你的数据库所设定的隔离级别。
你也可以向下面这样重载默认的隔离级别,
Yii 也支持为你的事务设置[隔离级别]。默认情况下,当我们开启一个新事务,
它将使用你的数据库所设定的隔离级别。你也可以向下面这样重载默认的隔离级别,
```php
$isolationLevel = \yii\db\Transaction::REPEATABLE_READ;
@ -411,38 +400,28 @@ Yii 为四个最常用的隔离级别提供了常量:
- [[\yii\db\Transaction::REPEATABLE_READ]] - 避免了脏读和不可重复读。
- [[\yii\db\Transaction::SERIALIZABLE]] - 最强的隔离级别, 避免了上述所有的问题。
> 注意: 你使用的数据库必须支持 `Savepoints` 才能正确地执行,以上代码在所有关系数据中都可以执行,但是只有支持 `Savepoints` 才能保证安全性。
Yii 也支持为事务设置隔离级别 `isolation levels`,当执行事务时会使用数据库默认的隔离级别,你也可以为事务指定隔离级别.
Yii 提供了以下常量作为常用的隔离级别
除了使用上述的常量来指定隔离级别,
你还可以使用你的数据库所支持的具有有效语法的字符串。
比如,在 PostgreSQL 中,
你可以使用 `SERIALIZABLE READ ONLY DEFERRABLE`
除了使用上述的常量来指定隔离级别,你还可以使用你的数据库所支持的具有有效语法的字符串。
比如,在 PostgreSQL 中,你可以使用 `SERIALIZABLE READ ONLY DEFERRABLE`
请注意,一些数据库只允许为整个连接设置隔离级别,
即使你之后什么也没指定,
后来的事务都将获得与之前相同的隔离级别。
即使你之后什么也没指定,后来的事务都将获得与之前相同的隔离级别。
使用此功能时,你需要为所有的事务明确地设置隔离级别来避免冲突的设置。
在本文写作之时,
只有 MSSQL 和 SQLite 受这些限制的影响。
在本文写作之时,只有 MSSQL 和 SQLite 受这些限制的影响。
> Note: SQLite 只支持两种隔离级别,
所以你只能使用 `READ UNCOMMITTED``SERIALIZABLE`
> Note: SQLite 只支持两种隔离级别,所以你只能使用 `READ UNCOMMITTED``SERIALIZABLE`
使用其他级别将导致异常的抛出。
> Note: PostgreSQL 不支持在事务开启前设定隔离级别,
因此,你不能在开启事务时直接指定隔离级别。
你必须在事务开始后再调用 [[yii\db\Transaction::setIsolationLevel()]]。
[隔离级别]: http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels
### 嵌套事务 <span id="nesting-transactions"></span>
如果你的数据库支持保存点,
你可以像下面这样嵌套多个事务:
### 嵌套事务(Nesting Transactions) <span id="nesting-transactions"></span>
如果你的数据库支持保存点,你可以像下面这样嵌套多个事务:
```php
Yii::$app->db->transaction(function ($db) {
// outer transaction
@ -468,26 +447,31 @@ try {
} catch (\Exception $e) {
$innerTransaction->rollBack();
throw $e;
} catch (\Throwable $e) {
$innerTransaction->rollBack();
throw $e;
}
$outerTransaction->commit();
} catch (\Exception $e) {
$outerTransaction->rollBack();
throw $e;
} catch (\Throwable $e) {
$outerTransaction->rollBack();
throw $e;
}
```
## 复制和读写分离 <span id="read-write-splitting"></span>
## 复制和读写分离(Replication and Read-Write Splitting) <span id="read-write-splitting"></span>
许多数据库支持[数据库复制](http://en.wikipedia.org/wiki/Replication_(computing)#Database_replication)来获得更好的数据库可用性,
以及更快的服务器响应时间。
通过数据库复制功能,
数据从所谓的主服务器被复制到从服务器。
所有的写和更新必须发生在主服务器上,
以及更快的服务器响应时间。通过数据库复制功能,
数据从所谓的主服务器被复制到从服务器。所有的写和更新必须发生在主服务器上,
而读可以发生在从服务器上。
为了利用数据库复制并且完成读写分离,你可以按照下面的方法来配置 [[yii\db\Connection]] 组件:
为了利用数据库复制并且完成读写分离,
你可以按照下面的方法来配置 [[yii\db\Connection]] 组件:
```php
[
@ -519,10 +503,8 @@ try {
```
上述的配置指定了一主多从的设置。
这些从库其中之一将被建立起连接并执行读操作,
而主库将被用来执行写操作。
这样的读写分离将通过上述配置自动地完成。
比如,
这些从库其中之一将被建立起连接并执行读操作,而主库将被用来执行写操作。
这样的读写分离将通过上述配置自动地完成。比如,
```php
// 使用上述配置来创建一个 Connection 实例
@ -540,24 +522,20 @@ Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->exec
你可以通过 `Yii::$app->db->slave` 来获取当前有效的从库连接。
`Connection` 组件支持从库间的负载均衡和失效备援,
当第一次执行读操作时,
`Connection` 组件将随机地挑选出一个从库并尝试与之建立连接,
如果这个从库被发现为”挂掉的“,
将尝试连接另一个从库。
如果没有一个从库是连接得上的,
那么将试着连接到主库上。
当第一次执行读操作时,`Connection` 组件将随机地挑选出一个从库并尝试与之建立连接,
如果这个从库被发现为”挂掉的“,将尝试连接另一个从库。
如果没有一个从库是连接得上的,那么将试着连接到主库上。
通过配置 [[yii\db\Connection::serverStatusCache|server status cache]],
一个“挂掉的”服务器将会被记住,
因此,在一个 yii\db\Connection::serverRetryInterval 内将不再试着连接该服务器。
一个“挂掉的”服务器将会被记住,因此,在一个 yii\db\Connection::serverRetryInterval 内将不再试着连接该服务器。
> Info: 在上面的配置中,
每个从库都共同地指定了 10 秒的连接超时时间,
这意味着,如果一个从库在 10 秒内不能被连接上,
它将被视为“挂掉的”。
每个从库都共同地指定了 10 秒的连接超时时间,这意味着,如果一个从库在 10 秒内不能被连接上,它将被视为“挂掉的”。
你可以根据你的实际环境来调整该参数。
你也可以配置多主多从。例如,
```php
[
'class' => 'yii\db\Connection',
@ -599,19 +577,16 @@ Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->exec
```
上述配置指定了两个主库和两个从库。
`Connection` 组件在主库之间,
也支持如从库间般的负载均衡和失效备援。
唯一的差别是,
如果没有主库可用,将抛出一个异常。
`Connection` 组件在主库之间,也支持如从库间般的负载均衡和失效备援。
唯一的差别是,如果没有主库可用,将抛出一个异常。
> Note: 当你使用 [[yii\db\Connection::masters|masters]] 属性来配置一个或多个主库时,
所有其他指定数据库连接的属性 (例如 `dsn`, `username`, `password`) 与 `Connection` 对象本身将被忽略。
所有其他指定数据库连接的属性 (例如 `dsn`, `username`, `password`)
`Connection` 对象本身将被忽略。
默认情况下,
事务使用主库连接,
一个事务内,
所有的数据库操作都将使用主库连接,
例如,
默认情况下,事务使用主库连接,
一个事务内,所有的数据库操作都将使用主库连接,例如,
```php
$db = Yii::$app->db;
@ -627,6 +602,9 @@ try {
} catch(\Exception $e) {
$transaction->rollBack();
throw $e;
} catch(\Throwable $e) {
$transaction->rollBack();
throw $e;
}
```
@ -635,6 +613,7 @@ try {
```php
$transaction = Yii::$app->db->slave->beginTransaction();
```
有时,你或许想要强制使用主库来执行读查询。
这可以通过 `useMaster()` 方法来完成:
@ -642,11 +621,12 @@ $transaction = Yii::$app->db->slave->beginTransaction();
$rows = Yii::$app->db->useMaster(function ($db) {
return $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
});
你也可以明确地将 `Yii::$app->db->enableSlaves` 设置为 false 来将所有的读操作指向主库连接。
```
你也可以明确地将 `Yii::$app->db->enableSlaves` 设置为 false 来将所有的读操作指向主库连接。
## 操纵数据库模式 <span id="database-schema"></span>
## 操纵数据库模式(Working with Database Schema) <span id="database-schema"></span>
Yii DAO 提供了一套完整的方法来让你操纵数据库模式,
如创建表、从表中删除一列,等等。这些方法罗列如下:
@ -677,21 +657,13 @@ Yii::$app->db->createCommand()->createTable('post', [
]);
```
更多信息请参考[[yii\db\Schema]]
### 修改模式
上面的数组描述要创建的列的名称和类型。
对于列的类型,
Yii 提供了一套抽象数据类型来允许你定义出数据库无关的模式。
这些将根据表所在数据库的种类,
被转换为特定的类型定义。
对于列的类型, Yii 提供了一套抽象数据类型来允许你定义出数据库无关的模式。
这些将根据表所在数据库的种类,被转换为特定的类型定义。
请参考 [[yii\db\Command::createTable()|createTable()]]-method 的 API 文档来获取更多信息。
除了改变数据库模式,
你也可以通过 DB Connection 的 [[yii\db\Connection::getTableSchema()|getTableSchema()]] 方法来检索某张表的定义信息。
例如,
你也可以通过 DB Connection 的 [[yii\db\Connection::getTableSchema()|getTableSchema()]] 方法来检索某张表的定义信息。例如,
```php
$table = Yii::$app->db->getTableSchema('post');
@ -700,4 +672,3 @@ $table = Yii::$app->db->getTableSchema('post');
该方法返回一个 [[yii\db\TableSchema]] 对象,
它包含了表中的列、主键、外键,等等的信息。
所有的这些信息主要被 [query builder](db-query-builder.md) 和 [active record](db-active-record.md) 所使用,来帮助你写出数据库无关的代码。

198
docs/guide-zh-CN/helper-array.md

@ -1,11 +1,11 @@
数组助手类
===========
数组助手类(ArrayHelper)
======================
除了[PHP中丰富的数组函数集](http://php.net/manual/zh/book.array.php),
Yii 数组助手类提供了额外的静态方法,让你更高效地处理数组。
## 获取值 <span id="getting-values"></span>
## 获取值(Getting Values) <span id="getting-values"></span>
用原生PHP从一个对象、数组、或者包含这两者的一个复杂数据结构中获取数据是非常繁琐的。
你首先得使用 `isset` 检查 key 是否存在, 然后如果存在你就获取它,如果不存在,
@ -53,18 +53,69 @@ $fullName = ArrayHelper::getValue($user, function ($user, $defaultValue) {
$username = ArrayHelper::getValue($comment, 'user.username', 'Unknown');
```
对于取到值后想要立即从数组中删除的情况,你可以使用 `remove` 方法:
## 设定值(Setting values) <span id="setting-values"></span>
```php
$array = [
'key' => [
'in' => ['k' => 'value']
]
];
ArrayHelper::setValue($array, 'key.in', ['arr' => 'val']);
// 在 `$array` 中写入值的路径可以被指定为一个数组
ArrayHelper::setValue($array, ['key', 'in'], ['arr' => 'val']);
```
结果,`$array['key']['in']` 的初始值将被新值覆盖
```php
[
'key' => [
'in' => ['arr' => 'val']
]
]
```
如果路径包含一个不存在的键,它将被创建
```php
// 如果 `$array['key']['in']['arr0']` 不为空,则该值将被添加到数组中
ArrayHelper::setValue($array, 'key.in.arr0.arr1', 'val');
// 如果你想完全覆盖值 `$array['key']['in']['arr0']`
ArrayHelper::setValue($array, 'key.in.arr0', ['arr1' => 'val']);
```
结果将是
```php
[
'key' => [
'in' => [
'k' => 'value',
'arr0' => ['arr1' => 'val']
]
]
]
```
## 从数组中获取值(Take a value from an array) <span id="removing-values"></span>
如果你想获得一个值,然后立即从数组中删除它,你可以使用 `remove` 方法:
```php
$array = ['type' => 'A', 'options' => [1, 2]];
$type = ArrayHelper::remove($array, 'type');
```
执行了上述代码之后, `$array` 将包含 `['options' => [1, 2]]` 并且 `$type` 将会是 `A`
注意和 `getValue` 方法不同的是,`remove` 方法只支持简单键名。
执行代码后,`$array` 将包含 `['options' => [1, 2]]` `$type` 将包含 `A`
请注意,与 `getValue` 方法不同,`remove` 仅支持简单的键名称。
## 检查键名的存在<span id="checking-existence-of-keys"></span>
## 检查键名的存在(Checking Existence of Keys) <span id="checking-existence-of-keys"></span>
`ArrayHelper::keyExists` 工作原理和[array_key_exists](http://php.net/manual/en/function.array-key-exists.php)差不多,除了
它还可支持大小写不敏感的键名比较,比如:
@ -83,7 +134,7 @@ if (!ArrayHelper::keyExists('username', $data1, false) || !ArrayHelper::keyExist
}
```
## 检索列 <span id="retrieving-columns"></span>
## 检索列(Retrieving Columns) <span id="retrieving-columns"></span>
通常你要从多行数据或者多个对象构成的数组中获取某列的值,一个普通的例子是获取id值列表。
@ -107,20 +158,20 @@ $result = ArrayHelper::getColumn($array, function ($element) {
```
## 重建数组索引 <span id="reindexing-arrays"></span>
## 重建数组索引(Re-indexing Arrays) <span id="reindexing-arrays"></span>
按一个指定的键名重新索引一个数组,可以用 `index` 方法。输入的数组应该是多维数组或者是一个对象数组。
键名(译者注:第二个参数)可以是子数组的键名、对象的属性名,
也可以是一个返回给定元素数组键值的匿名函数。
The `$groups` attribute is an array of keys, that will be used to group the input array into one or more sub-arrays
based on keys specified.
`$groups` 属性是一个键数组,
它将根据指定的键将输入数组分组为一个或多个子数组。
If the `$key` attribute or its value for the particular element is null and `$groups` is not defined, the array
element will be discarded. Otherwise, if `$groups` is specified, array element will be added to the result array
without any key.
如果 `$key` 属性或其特定元素的值为 null,并且未定义 `$groups`
则数组元素将被丢弃。否则,如果指定了 `$groups`
则数组元素将被添加到没有任何键的结果数组中。
For example:
例如:
```php
$array = [
@ -131,17 +182,17 @@ $array = [
$result = ArrayHelper::index($array, 'id');
```
The result will be an associative array, where the key is the value of `id` attribute
结果将是一个关联数组,其中键是 `id` 属性的值
```php
[
'123' => ['id' => '123', 'data' => 'abc', 'device' => 'laptop'],
'345' => ['id' => '345', 'data' => 'hgi', 'device' => 'smartphone']
// The second element of an original array is overwritten by the last element because of the same id
// 原始数组的第二个元素由于相同的 ID 而被最后一个元素覆盖
]
```
Anonymous function, passed as a `$key`, gives the same result.
匿名函数作为 `$key` 传递,给出了相同的结果。
```php
$result = ArrayHelper::index($array, function ($element) {
@ -149,13 +200,13 @@ $result = ArrayHelper::index($array, function ($element) {
});
```
Passing `id` as a third argument will group `$array` by `id`:
传递 `id` 作为第三个参数将 `id` 分配给 `$ array`
```php
$result = ArrayHelper::index($array, null, 'id');
```
The result will be a multidimensional array grouped by `id` on the first level and not indexed on the second level:
结果将是一个多维数组,它由第一级的 `id` 分组,并且不在第二级索引:
```php
[
@ -169,7 +220,7 @@ The result will be a multidimensional array grouped by `id` on the first level a
]
```
An anonymous function can be used in the grouping array as well:
匿名函数也可用于分组数组中:
```php
$result = ArrayHelper::index($array, 'data', [function ($element) {
@ -177,8 +228,8 @@ $result = ArrayHelper::index($array, 'data', [function ($element) {
}, 'device']);
```
The result will be a multidimensional array grouped by `id` on the first level, by `device` on the second level and
indexed by `data` on the third level:
结果将是一个多维数组,由第一级的 `id` 分组,第二级的 `device` 和第三级的
`data` 索引:
```php
[
@ -198,10 +249,10 @@ indexed by `data` on the third level:
]
```
## 建立哈希表 <span id="building-maps"></span>
## 建立哈希表(Building Maps) <span id="building-maps"></span>
为了从一个多维数组或者一个对象数组中建立一个映射表(键值对),你可以使用
`map`方法.`$from` 和 `$to` 参数分别指定了欲构建的映射表的键名和属性名。
为了从一个多维数组或者一个对象数组中建立一个映射表(键值对),你可以使用
`map` 方法。`$from` 和 `$to` 参数分别指定了欲构建的映射表的键名和属性名。
根据需要,你可以按照一个分组字段 `$group` 将映射表进行分组,例如,
```php
@ -233,7 +284,7 @@ $result = ArrayHelper::map($array, 'id', 'name', 'class');
```
## 多维排序 <span id="multidimensional-sorting"></span>
## 多维排序(Multidimensional Sorting) <span id="multidimensional-sorting"></span>
`multisort` 方法可用来对嵌套数组或者对象数组进行排序,可按一到多个键名排序,比如,
@ -273,7 +324,7 @@ ArrayHelper::multisort($data, function($item) {
[sort()](http://php.net/manual/zh/function.sort.php) 函数时传递的值一样。
## 检测数组类型 <span id="detecting-array-types"></span>
## 检测数组类型(Detecting Array Types) <span id="detecting-array-types"></span>
想知道一个数组是索引数组还是联合数组很方便,这有个例子:
@ -288,7 +339,7 @@ echo ArrayHelper::isAssociative($associative);
```
## HTML 编码和解码值 <span id="html-encoding-values"></span>
## HTML 编码和解码值(HTML Encoding and Decoding Values) <span id="html-encoding-values"></span>
为了将字符串数组中的特殊字符做 HTML 编解码,你可以使用下列方法:
@ -301,30 +352,77 @@ $decoded = ArrayHelper::htmlDecode($data);
编码将默认使用应用程序的字符集,你可以通过第三个参数指定该字符集。
## 合并数组 <span id="merging-arrays"></span>
## 合并数组(Merging Arrays) <span id="merging-arrays"></span>
您可以使用 [[yii\helpers\ArrayHelper::merge()|ArrayHelper::merge()]] 将两个或多个数组合并成一个递归的数组。
如果每个数组都有一个具有相同字符串键值的元素,则后者将覆盖前者
(不同于 [array_merge_recursive()](http://php.net/manual/en/function.array-merge-recursive.php))。
如果两个数组都有一个数组类型的元素并且具有相同的键,则将执行递归合并。
对于整数键的元素,来自后一个数组的元素将被附加到前一个数组。
您可以使用 [[yii\helpers\UnsetArrayValue]] 对象来取消前一个数组的值或
[[yii\helpers\ReplaceArrayValue]] 以强制替换先前的值而不是递归合并。
例如:
```php
/**
* 将两个或者多个数组递归式的合并为一个数组。
* 如果每个数组有一个元素的键名相同,
* 那么后面元素的将覆盖前面的元素(不同于 array_merge_recursive)。
* 如果两个数组都有相同键名的数组元素(译者注:嵌套数组)
* 则将引发递归合并。
* 对数值型键名的元素,后面数组中的这些元素会被追加到前面数组中。
* @param array $a 被合并的数组
* @param array $b 合并的数组,你可以在第三、第四个
* 参数中指定另外的合并数组,等等
* @return 合并的结果数组 (原始数组不会被改变)
*/
public static function merge($a, $b)
$array1 = [
'name' => 'Yii',
'version' => '1.1',
'ids' => [
1,
],
'validDomains' => [
'example.com',
'www.example.com',
],
'emails' => [
'admin' => 'admin@example.com',
'dev' => 'dev@example.com',
],
];
$array2 = [
'version' => '2.0',
'ids' => [
2,
],
'validDomains' => new \yii\helpers\ReplaceArrayValue([
'yiiframework.com',
'www.yiiframework.com',
]),
'emails' => [
'dev' => new \yii\helpers\UnsetArrayValue(),
],
];
$result = ArrayHelper::merge($array1, $array2);
```
结果将是:
```php
[
'name' => 'Yii',
'version' => '2.0',
'ids' => [
1,
2,
],
'validDomains' => [
'yiiframework.com',
'www.yiiframework.com',
],
'emails' => [
'admin' => 'admin@example.com',
],
]
```
## 对象转换为数组 <span id="converting-objects-to-arrays"></span>
## 对象转换为数组(Converting Objects to Arrays) <span id="converting-objects-to-arrays"></span>
你经常要将一个对象或者对象的数组转换成一个数组,常见的情形是,为了通过 REST API 提供数据数组(或其他使用方式),
将AR模型(活动记录模型)转换成数组。如下代码可完成这个工作:
AR 模型(活动记录模型)转换成数组。如下代码可完成这个工作:
```php
$posts = Post::find()->limit(10)->all();
@ -366,13 +464,13 @@ $data = ArrayHelper::toArray($posts, [
也可以在一个特定的类中实现 [[yii\base\Arrayable|Arrayable]] 接口,
从而为其对象提供默认的转换成数组的方法。
## Testing against Arrays <span id="testing-arrays"></span>
## 测试阵列(Testing against Arrays <span id="testing-arrays"></span>
Often you need to check if an element is in an array or a set of elements is a subset of another.
While PHP offers `in_array()`, this does not support subsets or `\Traversable` objects.
通常你需要检查一个元素是否在数组中,或者一组元素是另一个元素的子集。
虽然PHP提供 `in_array()`,这不支持子集或 `\Traversable` 对象。
To aid these kinds of tests, [[yii\base\ArrayHelper]] provides [[yii\base\ArrayHelper::isIn()|isIn()]]
and [[yii\base\ArrayHelper::isSubset()|isSubset()]] with the same signature as [[in_array()]].
为了支持这些测试,[[yii\base\ArrayHelper]] 提供了 [[yii\base\ArrayHelper::isIn()|isIn()]]
和 [[yii\base\ArrayHelper::isSubset()|isSubset()]] 与 [[in_array()]] 签名相同。
```php
// true

60
docs/guide-zh-CN/helper-html.md

@ -1,5 +1,5 @@
Html 帮助类
===========
Html 帮助类(Html helper)
=======================
任何一个 web 应用程序会生成很多 HTMl 超文本标记。如果超文本标记是静态的,
那么[将 PHP 和 HTML 混合在一个文件里](http://php.net/manual/en/language.basic-syntax.phpmode.php)
@ -10,13 +10,13 @@ Yii 通过 HTML 帮助类来提供生成超文本标记的方法。这个帮助
没有必要把所有的超文本标记都用 HTML 辅助类来生成。
## 基础 <span id="basics"></span>
## 基础(Basics) <span id="basics"></span>
由于通过字符串连接来生成动态的 HTML 会很容易变得凌乱,
Yii 提供了一系列的静态方法来操作标签配置并基于这些配置来创建对应的标签。
### 生成标签 <span id="generating-tags"></span>
### 生成标签(Generating Tags) <span id="generating-tags"></span>
生成一个标签的代码类似如下:
@ -56,7 +56,7 @@ Yii 提供了一系列的静态方法来操作标签配置并基于这些配置
生成 `params='{"id":1,"name":"yii"}'`
### 生成 CSS 类和样式 <span id="forming-css"></span>
### 生成 CSS 类和样式(Forming CSS Classes and Styles) <span id="forming-css"></span>
当开始构造一个 HTML 标签的属性时,我们经常需要对默认的属性进行修改。
为了添加或者删除 CSS 类,你可以使用如下代码:
@ -84,7 +84,7 @@ echo Html::tag('div', 'Save', $options);
// renders '<div class="btn btn-default">Save</div>'
```
While adding or removing classes you may use the array format as well:
在添加或删除类时,您也可以使用数组格式:
```php
$options = ['class' => 'btn'];
@ -97,7 +97,7 @@ echo Html::tag('div', 'Save', $options);
// renders '<div class="btn btn-success btn-lg">Save</div>'
```
`Html::addCssClass()` prevents duplicating classes, so you don't need to worry that the same class may appear twice:
`Html::addCssClass()` 防止重复类,所以你不必担心同一个类可能会出现两次:
```php
$options = ['class' => 'btn btn-default'];
@ -108,8 +108,8 @@ echo Html::tag('div', 'Save', $options);
// renders '<div class="btn btn-default">Save</div>'
```
If the CSS class option is specified via the array format, you may use a named key to mark the logical purpose of the class.
In this case, a class with the same key in the array format will be ignored in `Html::addCssClass()`:
如果通过数组格式指定 CSS 类选项,则可以使用命名键来标记该类的逻辑用途。
在这种情况下,在 `Html::addCssClass()` 类中会忽略数组格式中具有相同键:
```php
$options = [
@ -119,13 +119,13 @@ $options = [
]
];
Html::addCssClass($options, ['theme' => 'btn-success']); // 'theme' key is already taken
Html::addCssClass($options, ['theme' => 'btn-success']); // 'theme' 键已被使用
echo Html::tag('div', 'Save', $options);
// renders '<div class="btn btn-default">Save</div>'
```
CSS styles can be setup in similar way using `style` attribute:
可以使用 `style` 属性以类似的方式设置 CSS 样式:
```php
$options = ['style' => ['width' => '100px', 'height' => '100px']];
@ -144,7 +144,7 @@ Html::removeCssStyle($options, ['width', 'height']);
如果只想移除一个属性,你可以直接传递一个字符串。
### 标签内容的转码和解码 <span id="encoding-and-decoding-content"></span>
### 标签内容的转码和解码(Encoding and Decoding Content) <span id="encoding-and-decoding-content"></span>
为了让内容能够正确安全的显示,一些 HTML 特殊字符应该被转码。在 PHP 中,
这个操作由 [htmlspecialchars](http://www.php.net/manual/en/function.htmlspecialchars.php) 和
@ -161,7 +161,7 @@ $decodedUserName = Html::decode($userName);
```
## 表单 <span id="forms"></span>
## 表单(Forms) <span id="forms"></span>
处理表单标签是大量的重复性劳动并且易错。因此,
Yii 也提供了一系列的方法来辅助处理表单标签。
@ -169,7 +169,7 @@ Yii 也提供了一系列的方法来辅助处理表单标签。
> Note: 考虑在处理 models 以及需要验证的情形下,使用 [[yii\widgets\ActiveForm|ActiveForm]] 组件。
### 创建表单 <span id="creating-forms"></span>
### 创建表单(Creating Forms) <span id="creating-forms"></span>
表单可以用类似如下代码,使用 [[yii\helpers\Html::beginForm()|beginForm()]] 方法开启:
@ -189,7 +189,7 @@ Yii 也提供了一系列的方法来辅助处理表单标签。
```
### 按钮 <span id="buttons"></span>
### 按钮(Buttons) <span id="buttons"></span>
你可以用如下代码生成按钮:
@ -203,7 +203,7 @@ Yii 也提供了一系列的方法来辅助处理表单标签。
那么请自行用 [[yii\helpers\Html::encode()|Html::encode()]] 方法进行转码。
### 输入栏 <span id="input-fields"></span>
### 输入栏(Input Fields) <span id="input-fields"></span>
input 相关的方法有两组:以 `active` 开头的被称为 active inputs,
另一组则不以其开头。active inputs 依据指定的模型和属性获取数据,
@ -250,8 +250,7 @@ Dropdown list 和 list box 将会如下渲染:
<?= Html::activeListBox($users, 'id', ArrayHelper::map($userModels, 'id', 'name')) ?>
```
第一个参数是 input 的名称,第二个是当前选中的值,第三个则是一个下标为列表值,
值为列表标签的名值对数组。
第一个参数是 input 的名称,第二个是当前选中的值,第三个则是一个下标为列表值,值为列表标签的名值对数组。
如果你需要使用多项选择, checkbox list 应该能够符合你的需求:
@ -268,10 +267,9 @@ Dropdown list 和 list box 将会如下渲染:
```
### Labels 和 Errors <span id="labels-and-errors"></span>
### Labels 和 Errors(Labels and Errors) <span id="labels-and-errors"></span>
如同 inputs 一样,Yii 也提供了两个方法用于生成表单 label 。
带 ative 方法用于从 model 中取数据,另外一个则是直接接收数据。
如同 inputs 一样,Yii 也提供了两个方法用于生成表单 label。带 ative 方法用于从 model 中取数据,另外一个则是直接接收数据。
```php
<?= Html::label('User name', 'username', ['class' => 'label username']) ?>
@ -291,7 +289,7 @@ Dropdown list 和 list box 将会如下渲染:
```
### Input 的名和值 <span id="input-names-and-values"></span>
### Input 的名和值(Input Names and Values) <span id="input-names-and-values"></span>
Yii 提供了方法用于从 model 中获取 input 的名称,ids,值。这些主要用于内部调用,
但是有时候你也需要使用它们:
@ -310,9 +308,7 @@ echo Html::getAttributeValue($post, 'title');
echo Html::getAttributeValue($post, '[0]authors[0]');
```
在上面的例子中,第一个参数为模型,而第二个参数是属性表达式。
在最简单的表单中,这个属性表达式就是属性名称,但是在一些多行输入的时候,
它也可以是属性名以数组下标前缀或者后缀(也可能是同时)。
在上面的例子中,第一个参数为模型,而第二个参数是属性表达式。在最简单的表单中,这个属性表达式就是属性名称,但是在一些多行输入的时候,它也可以是属性名以数组下标前缀或者后缀(也可能是同时)。
- `[0]content` 代表多行输入时第一个 model 的 content 属性的数据值。
- `dates[0]` 代表 dates 属性的第一个数组元素。
@ -326,7 +322,7 @@ echo Html::getAttributeName('dates[0]');
```
## 样式表和脚本 <span id="styles-and-scripts"></span>
## 样式表和脚本(Styles and Scripts) <span id="styles-and-scripts"></span>
Yii 提供两个方法用于生成包含内联样式和脚本代码的标签。
@ -374,7 +370,7 @@ generates
`cssFile` 一样,你可以指定 `condtion` 配置项。
## 超链接 <span id="hyperlinks"></span>
## 超链接(Hyperlinks) <span id="hyperlinks"></span>
有一个方法可以用于便捷的生成超链接:
@ -384,7 +380,8 @@ generates
第一个参数是超链接的标题。它不会被转码,所以如果是用户输入数据,
你需要使用 `Html::encode()` 方法进行转码。第二个参数是 `<a` 标签的 `href` 属性的值。
关于该参数能够接受的更详细的数据值,请参阅 [Url::to()](helper-url.md)。第三个参数是标签的属性数组。
关于该参数能够接受的更详细的数据值,请参阅 [Url::to()](helper-url.md)。
第三个参数是标签的属性数组。
在需要的时候,你可以用如下代码生成 `mailto` 链接:
@ -393,7 +390,7 @@ generates
```
## 图片 <span id="images"></span>
## 图片(Images) <span id="images"></span>
为了生成图片标签,你可以如下做:
@ -405,11 +402,10 @@ generates
<img src="http://example.com/images/logo.png" alt="My logo" />
```
除了 [aliases](concept-aliases.md) 之外,第一个参数可以接受 路由,查询,URLs。
同 [Url::to()](helper-url.md) 一样。
除了 [aliases](concept-aliases.md) 之外,第一个参数可以接受 路由,查询,URLs。同 [Url::to()](helper-url.md) 一样。
## 列表 <span id="lists"></span>
## 列表(Lists) <span id="lists"></span>
无序列表可以如下生成:

14
docs/guide-zh-CN/helper-overview.md

@ -1,5 +1,5 @@
助手类
=======
助手类(Helpers)
==============
> Note: 这部分正在开发中。
@ -20,8 +20,8 @@ echo Html::encode('Test > test');
当使用助手类时,应该仅使用具体的类版本而不使用基类。
核心助手类
-------------------
核心助手类(Core Helper Classes)
-----------------------------
Yii 发布版中提供以下核心助手类:
@ -30,7 +30,7 @@ Yii 发布版中提供以下核心助手类:
- FileHelper
- [Html](helper-html.md)
- HtmlPurifier
- Image
- Imagine(由 yii2-imagine 扩展提供)
- Inflector
- Json
- Markdown
@ -40,8 +40,8 @@ Yii 发布版中提供以下核心助手类:
- VarDumper
自定义助手类 <span id="customizing-helper-classes"></span>
--------------------------
自定义助手类(Customizing Helper Classes) <span id="customizing-helper-classes"></span>
--------------------------------------
如果想要自定义一个核心助手类 (例如 [[yii\helpers\ArrayHelper]]),你应该创建一个新的类继承
helpers对应的基类 (例如 [[yii\helpers\BaseArrayHelper]]) 并同样的命

26
docs/guide-zh-CN/helper-url.md

@ -1,10 +1,10 @@
Url 助类
==========
Url 助(Url Helper)
=====================
Url 帮助类提供一系列的静态方法来帮助管理 URL。
## 获得通用 URL <span id="getting-common-urls"></span>
## 获得通用 URL(Getting Common URLs) <span id="getting-common-urls"></span>
有两种获取通用 URLS 的方法 :当前请求的 home URL 和 base URL 。
为了获取 home URL ,使用如下代码:
@ -29,7 +29,7 @@ $httpsAbsoluteBaseUrl = Url::base('https');
这个方法的调用方式和 `Url::home()` 的完全一样。
## 创建 URLs <span id="creating-urls"></span>
## 创建 URLs(Creating URLs) <span id="creating-urls"></span>
为了创建一个给定路由的 URL 地址,请使用 `Url::toRoute()`方法。 这个方法使用 [[\yii\web\UrlManager]]
来创建一个 URL :
@ -75,7 +75,7 @@ echo Url::toRoute('site/index');
// /index.php?r=site/index&src=ref1#name
echo Url::toRoute(['site/index', 'src' => 'ref1', '#' => 'name']);
// /index.php?r=post/edit&id=100 assume the alias "@postEdit" is defined as "post/edit"
// /index.php?r=post/edit&id=100     假设别名 "@postEdit" 被定义为 "post/edit"
echo Url::toRoute(['@postEdit', 'id' => 100]);
// http://www.example.com/index.php?r=site/index
@ -111,10 +111,10 @@ echo Url::to(['site/index']);
// /index.php?r=site/index&src=ref1#name
echo Url::to(['site/index', 'src' => 'ref1', '#' => 'name']);
// /index.php?r=post/edit&id=100 assume the alias "@postEdit" is defined as "post/edit"
// /index.php?r=post/edit&id=100     假设别名 "@postEdit" 被定义为 "post/edit"
echo Url::to(['@postEdit', 'id' => 100]);
// the currently requested URL
// 当前请求的 URL
echo Url::to();
// /images/logo.gif
@ -135,7 +135,7 @@ echo Url::to('@web/images/logo.gif', 'https');
例如:
```php
// assume $_GET = ['id' => 123, 'src' => 'google'], current route is "post/view"
// 假设 $_GET = ['id' => 123, 'src' => 'google'],当前路由为 "post/view"
// /index.php?r=post/view&id=123&src=google
echo Url::current();
@ -147,19 +147,19 @@ echo Url::current(['id' => 100]);
```
## 记住 URLs <span id="remember-urls"></span>
## 记住 URLs(Remember URLs) <span id="remember-urls"></span>
有时,你需要记住一个 URL 并在后续的请求处理中使用它。
你可以用以下方式达到这个目的:
```php
// Remember current URL
// 记住当前 URL
Url::remember();
// Remember URL specified. See Url::to() for argument format.
// 记住指定的 URL。参数格式请参阅 Url::to()。
Url::remember(['product/view', 'id' => 42]);
// Remember URL specified with a name given
// 记住用给定名称指定的 URL
Url::remember(['product/view', 'id' => 42], 'product');
```
@ -170,7 +170,7 @@ $url = Url::previous();
$productUrl = Url::previous('product');
```
## 检查相对 URLs <span id="checking-relative-urls"></span>
## 检查相对 URLs(Checking Relative URLs) <span id="checking-relative-urls"></span>
你可以用如下代码检测一个 URL 是否是相对的(比如,包含主机信息部分)。

12
docs/guide-zh-CN/input-file-upload.md

@ -77,8 +77,8 @@ use yii\widgets\ActiveForm;
需要注意的是要记得在表单选项里加入 `enctype` 属性以确保文件能被正常上传。
`fileInput()` 方法会渲染一个 `<input type="file">` 标签,让用户可以选择一个文件上传。
> Tip: since version 2.0.8, [[yii\web\widgets\ActiveField::fileInput|fileInput]] adds `enctype` option to the form
automatically when file input field is used.
> Tip: 自2.0.8版本开始,当使用文件输入字段时,[[yii\web\widgets\ActiveField::fileInput|fileInput]]
会自动向表单添加 `enctype` 选项。
## 视图和模型的连接 <span id="wiring-up"></span>
@ -121,10 +121,10 @@ class SiteController extends Controller
将前面所述的代码做一些调整,也可以一次性上传多个文件。
首先你得调整模型类,在 `file` 验证规则里增加一个 `maxFiles` 选项,用以限制一次上传文件的最大数量。
`upload()`方法也得修改,以便一个一个地保存上传的文件。Setting `maxFiles` to `0` means there is no limit on the number of files
that can be uploaded simultaneously. The maximum number of files allowed to be uploaded simultaneously is also limited
with PHP directive [`max_file_uploads`](http://php.net/manual/en/ini.core.php#ini.max-file-uploads),
which defaults to 20. The `upload()` method should also be updated to save the uploaded files one by one.
`upload()`方法也得修改,以便一个一个地保存上传的文件。`maxFiles` 设置为 `0` 意味着可以同时上传的文件数量没有限制。
允许同时上传的文件的最大数量也受到 PHP 指令
[`max_file_uploads`](http://php.net/manual/en/ini.core.php#ini.max-file-uploads)的限制,
默认为20。还应该更新 `upload()` 方法以逐个保存上传的文件。
```php
namespace app\models;

147
docs/guide-zh-CN/input-forms.md

@ -1,25 +1,20 @@
创建表单
========
在 Yii 中使用表单的主要方式是通过 [[yii\widgets\ActiveForm]]。如果是基于
模型的表单应首选这种方式。此外,在 [[yii\helpers\Html]]中也有一些实用的
方法用于添加按钮和帮助文本。
在客户端上显示的表单,大多数情况下有一个相应的[模型](structure-models.md),用来验证其输入的服务器数据
(可在 [输入验证](input-validation.md) 一节获取关于验证的细节)。
当创建基于模型的表单时,第一步是定义模型本身。该模式可以是一个基于[活动记录](db-active-record.md)的类,
表示数据库中的数据,也可以是一个基于通用模型的类(继承自 [[yii\base\Model]] ),
来获取任意的输入数据,如登录表单。在下面的例子中,我们展示了一个用来做
登录表单的通用模型:
=======
基于活动记录(ActiveRecord)的表单:ActiveForm
基于活动记录(ActiveRecord)的表单:ActiveForm
-----------------------
在yii中使用表单的主要方式是通过[[yii\widgets\ActiveForm]]。当某个表单是基于一个模型时,应该首选这种方式。此外,在[[yii\helpers\Html]]中有很多实用的方法为表单添加按钮和帮助文档。
在yii中使用表单的主要方式是通过 [[yii\widgets\ActiveForm]]。
当某个表单是基于一个模型时,应该首选这种方式。
此外,在 [[yii\helpers\Html]] 中有很多实用的方法为表单添加按钮和帮助文档。
在客户端显示的表单,大多数情况下都有一个相应的[模型](structure-models.md),用来在服务器上验证其输入的数据(可在[输入验证](input-validation.md)一节获取关于验证的细节)。当创建一个基于模型的表单时,第一步是定义模型本身。该模型可以是一个基于[活动记录](db-active-record.md)的类,表示数据库中的数据,也可以是一个基于通用模型的类(继承自[[yii\base\Model]]),来获取任意的输入数据,如登录表单。
在客户端显示的表单,大多数情况下都有一个相应的[模型](structure-models.md),
用来在服务器上验证其输入的数据(可在[输入验证](input-validation.md)一节获取关于验证的细节)。
当创建一个基于模型的表单时,第一步是定义模型本身。该模型可以是一个基于[活动记录](db-active-record.md)的类,
表示数据库中的数据,也可以是一个基于通用模型的类(继承自[[yii\base\Model]]),
来获取任意的输入数据,如登录表单。
> Tip: 如果一个表单的输入域与数据库的字段不匹配,或者它存在只适用于它的特殊的格式或者方法,则最好为它创建一个单独的继承自[[yii\base\Model]]的模型。
> Tip: 如果一个表单的输入域与数据库的字段不匹配,或者它存在只适用于它的特殊的格式或者方法,
> 则最好为它创建一个单独的继承自 [[yii\base\Model]] 的模型。
在接下来的例子中,我们展示了通用模型如何用于登录表单:
@ -63,6 +58,7 @@ $form = ActiveForm::begin([
<?php ActiveForm::end() ?>
```
### 用 `begin()` `end()` 包裹 <span id="wrapping-with-begin-and-end"></span>
在上面的代码中,[[yii\widgets\ActiveForm::begin()|ActiveForm::begin()]] 不仅创建了一个表单实例,同时也标志着表单的开始。
放在 [[yii\widgets\ActiveForm::begin()|ActiveForm::begin()]] 与 [[yii\widgets\ActiveForm::end()|ActiveForm::end()]]
之间的所有内容都被包裹在 HTML 的 `<form>` 标签中。
@ -70,6 +66,7 @@ $form = ActiveForm::begin([
一个额外的 CSS 类和 ID 会在 `<form>` 标签中使用。要查看所有可用的选项,
请参阅 API 文档的 [[yii\widgets\ActiveForm]]。
### ActiveField <span id="activefield"></span>
为了在表单中创建表单元素与元素的标签,以及任何适用的 JavaScript 验证,[[yii\widgets\ActiveForm::field()|ActiveForm::field()]]
方法在调用时,会返回一个 [[yii\widgets\ActiveField]] 的实例。
直接输出该方法时,结果是一个普通的(文本)输入。要自定义输出,可以附加上 [[yii\widgets\ActiveField|ActiveField]]
@ -89,9 +86,9 @@ input 输入框的 name 属性会自动地根据 [[yii\base\Model::formName()|fo
例如,对于在上面的例子中 `username` 输入字段的 name 属性将是 `LoginForm[username]`
这种命名规则使所有属性的数组的登录表单在服务器端的 `$_POST['LoginForm']` 数组中是可用的。
> Tip: If you have only one model in a form and want to simplify the input names you may skip the array part by
> overriding the [[yii\base\Model::formName()|formName()]] method of the model to return an empty string.
> This can be useful for filter models used in the [GridView](output-data-widgets.md#grid-view) to create nicer URLs.
> Tip: 如果在表单中只有一个模型并且想要简化输入名称,则可以通过覆盖模型的
> [[yii\base\Model::formName()|formName()]] 方法来返回一个空字符串。
> 这对于 [GridView](output-data-widgets.md#grid-view) 中使用的过滤器模型来创建更好的URL很有用。
指定模型的属性可以以更复杂的方式来完成。例如,当上传时,多个文件
或选择多个项目的属性,可能需要一个数组值,你可以通过附加 `[]`
@ -133,41 +130,92 @@ echo $form->field($model, 'items[]')->checkboxList(['a' => 'Item A', 'b' => 'Ite
创建下拉列表 <span id="creating-activeform-dropdownlist"></span>
------------
可以使用 ActiveForm 的 [dropDownList()](http://www.yiiframework.com/doc-2.0/yii-widgets-activefield.html#dropDownList()-detail)
方法来创建一个下拉列表:
有三种类型的列表:
* 下拉列表
* 单选列表
* 复选框列表
要创建一个列表,你必须准备这些项目。可以手动完成:
```php
use app\models\ProductCategory;
$items = [
1 => 'item 1',
2 => 'item 2'
]
```
/* @var $this yii\web\View */
或从 DB 中检索:
```php
$items = Category::find()
->select(['label'])
->indexBy('id')
->column();
```
这些 `$items` 必须由不同的列表小部件处理。
表单域(和当前活动项目)的值将由
`$model` 属性的当前值自动设置。
#### 创建一个下拉列表 <span id="creating-activeform-dropdownlist"></span>
我们可以使用 ActiveField [[\yii\widgets\ActiveField::dropDownList()]] 方法创建一个下拉列表:
```php
/* @var $form yii\widgets\ActiveForm */
/* @var $model app\models\Product */
echo $form->field($model, 'product_category')->dropdownList(
ProductCategory::find()->select(['category_name', 'id'])->indexBy('id')->column(),
echo $form->field($model, 'category')->dropdownList([
1 => 'item 1',
2 => 'item 2'
],
['prompt'=>'Select Category']
);
```
模型字段的值将被自动预先选定。
#### 创建一个单选列表 <span id="creating-activeform-radioList"></span>
我们可以使用 ActiveField [[\yii\widgets\ActiveField::radioList()]] 方法创建一个单选列表:
```php
/* @var $form yii\widgets\ActiveForm */
echo $form->field($model, 'category')->radioList([
1 => 'radio 1',
2 => 'radio 2'
]);
```
#### 创建一个复选框列表 <span id="creating-activeform-checkboxList"></span>
我们可以使用 ActiveField [[\yii\widgets\ActiveField::checkboxList()]] 方法创建一个复选框列表:
```php
/* @var $form yii\widgets\ActiveForm */
echo $form->field($model, 'category')->checkboxList([
1 => 'checkbox 1',
2 => 'checkbox 2'
]);
```
Working with Pjax <span id="working-with-pjax"></span>
与 Pjax 一起工作 <span id="working-with-pjax"></span>
-----------------------
The [[yii\widgets\Pjax|Pjax]] widget allows you to update a certain section of a
page instead of reloading the entire page. You can use it to update only the form
and replace its contents after the submission.
[[yii\widgets\Pjax|Pjax]] 小部件允许您更新某个部分
而不是重新加载整个页面。
您可以使用它来仅更新表单并在提交后更换其内容。
You can configure [[yii\widgets\Pjax::$formSelector|$formSelector]] to specify
which form submission may trigger pjax. If not set, all forms with `data-pjax`
attribute within the enclosed content of Pjax will trigger pjax requests.
你可以配置 [[yii\widgets\Pjax::$formSelector|$formSelector]]
来指定表单提交可能会触发 pjax。如果没有设置,所有封装 Pjax 内容的 `data-pjax`
属性的表单都会触发 pjax 请求。
```php
use yii\widgets\Pjax;
use yii\widgets\ActiveForm;
Pjax::begin([
// Pjax options
   // Pjax 配置项
]);
$form = ActiveForm::begin([
'options' => ['data' => ['pjax' => true]],
@ -179,28 +227,27 @@ Pjax::begin([
ActiveForm::end();
Pjax::end();
```
> Tip: Be careful with the links inside the [[yii\widgets\Pjax|Pjax]] widget since
> the response will also be rendered inside the widget. To prevent this, use the
> `data-pjax="0"` HTML attribute.
> Tip: 请小心处理 [[yii\widgets\Pjax|Pjax]] 小部件中的链接,
> 因为响应也将在小部件内呈现。为了防止这种情况,
> 使用 `data-pjax="0"` HTML 属性。
#### Values in Submit Buttons and File Upload
#### 提交按钮和文件上传中的值
There are known issues using `jQuery.serializeArray()` when dealing with
[[https://github.com/jquery/jquery/issues/2321|files]] and
[[https://github.com/jquery/jquery/issues/2321|submit button values]] which
won't be solved and are instead deprecated in favor of the `FormData` class
introduced in HTML5.
在处理 [[https://github.com/jquery/jquery/issues/2321|files]] 和
[[https://github.com/jquery/jquery/issues/2321|submit button values]]
时使用 `jQuery.serializeArray()`
有已知的问题,这将不会被解决,而是被弃用,
以支持 HTML5 中引入的 FormData 类。
That means the only official support for files and submit button values with
ajax or using the [[yii\widgets\Pjax|Pjax]] widget depends on the
[[https://developer.mozilla.org/en-US/docs/Web/API/FormData#Browser_compatibility|browser support]]
for the `FormData` class.
这意味着对 ajax 或使用 [[yii\widgets\Pjax|Pjax]]
小部件的文件和提交按钮值的唯一官方支持取决于
`FormData` 类的
[[https://developer.mozilla.org/en-US/docs/Web/API/FormData#Browser_compatibility|浏览器支持]]。
延伸阅读 <span id="further-reading"></span>
---------------
下一节 [输入验证](input-validation.md) 处理提交的表单数据的服务器端验证,
以及 ajax- 和客户端验证。
下一节 [输入验证](input-validation.md) 处理提交的表单数据的服务器端验证,以及 ajax 和客户端验证。
要学会有关表格的更复杂的用法,你可以查看以下几节:

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

@ -37,7 +37,6 @@ Yii 开发者团队始终对 Web 开发趋势和其他框架及项目中的最
那些有意义的最佳实践及特性会被不定期的整合进核心框架中,
并提供简单优雅的接口。
[about_yii]: http://www.yiiframework.com/about/
Yii 版本
------------

152
docs/guide-zh-CN/output-formatting.md

@ -1,5 +1,5 @@
数据格式器
==============
数据格式器(Data Formatting)
==========================
你可以使用 `formatter` [application component](structure-application-components.md) 来格式化数据。
默认 `fomatter` 由 [[yii\i18n\Formatter]] 来实现,这个组件提供了一系列关于日期/时间,数字,货币等的格式化方法。
@ -41,13 +41,16 @@ echo Yii::$app->formatter->format(0.125, ['percent', 2]);
```
> Note: `formatter` 组件用来格式化最终展示给用户的数据。
> 如果你想要将用户的输入进行格式化或者只是将一些别的日期数据进行格式化(这里的格式化说的是机器可读的格式化),不要使用这个组件,
> 如果你想要将用户的输入进行格式化或者只是将一些别的日期数据进行格式化(这里的格式化说的是机器可读的格式化),
> 不要使用这个组件,
> 而应该使用 [[yii\validators\DateValidator]] 和 [[yii\validators\NumberValidator]] 进行用户输入格式化
> 关于日期格式化,戳这里 [date()](http://php.net/manual/en/function.date.php)
> 对于机器可读的日期和时间格式之间的简单转换,
> PHP 方法 [date()](http://php.net/manual/en/function.date.php) 就足够了。
## 配置 Formatter <span id="configuring-formatter"></span>
## 配置 Formatter(Configuring Formatter) <span id="configuring-formatter"></span>
可以对 `formatter` 组件在 [application configuration](concept-configurations.md#application-configurations) 中进行配置
可以对 `formatter` 组件在 [application configuration](concept-configurations.md#application-configurations) 中进行配置。
例如,
```php
return [
@ -65,21 +68,26 @@ return [
可以参考 [[yii\i18n\Formatter]] 的配置
## 格式化时间/日期数据 <span id="date-and-time"></span>
## 格式化时间/日期数据(Formatting Date and Time Values) <span id="date-and-time"></span>
默认支持一下几种格式化格式
- [[yii\i18n\Formatter::asDate()|date]]: 这个变量将被格式化为日期 `January 01, 2014`.
- [[yii\i18n\Formatter::asTime()|time]]: 这个变量将被格式化为时间 `14:23`.
- [[yii\i18n\Formatter::asDatetime()|datetime]]: 这个变量将被格式化为日期+时间 `January 01, 2014 14:23`.
- [[yii\i18n\Formatter::asTimestamp()|timestamp]]: 这个变量将被格式化为 UNIX 时间戳 [unix timestamp](http://en.wikipedia.org/wiki/Unix_time), 例如 `1412609982`.
- [[yii\i18n\Formatter::asRelativeTime()|relativeTime]]: 这个变量将被格式化为人类可读的当前相对时间 `1 hour ago`.
- [[yii\i18n\Formatter::asDuration()|duration]]: 这个变量将被格式化为人类可读的时长 `1 day, 2 minutes`.
- [[yii\i18n\Formatter::asDate()|date]]:这个变量将被格式化为日期 `January 01, 2014`
- [[yii\i18n\Formatter::asTime()|time]]:这个变量将被格式化为时间 `14:23`
- [[yii\i18n\Formatter::asDatetime()|datetime]]:这个变量将被格式化为日期+时间 `January 01, 2014 14:23`
- [[yii\i18n\Formatter::asTimestamp()|timestamp]]:这个变量将被格式化为 UNIX 时间戳 [unix timestamp](http://en.wikipedia.org/wiki/Unix_time),例如 `1412609982`
- [[yii\i18n\Formatter::asRelativeTime()|relativeTime]]:这个变量将被格式化为人类可读的
当前相对时间 `1 hour ago`
- [[yii\i18n\Formatter::asDuration()|duration]]:这个变量将被格式化为人类可读的时长 `1 day, 2 minutes`
时间/日期数据默认使用 [[yii\i18n\Formatter::asDate()|date]], [[yii\i18n\Formatter::asTime()|time]], [[yii\i18n\Formatter::asDatetime()|datetime]] 方法进行格式化,
你可以对他们进行一些自己的配置,只需在配置文件里配置 [[yii\i18n\Formatter::dateFormat|dateFormat]], [[yii\i18n\Formatter::timeFormat|timeFormat]], 和 [[yii\i18n\Formatter::datetimeFormat|datetimeFormat]] 即可。
时间/日期数据默认使用 [[yii\i18n\Formatter::asDate()|date]], [[yii\i18n\Formatter::asTime()|time]],
[[yii\i18n\Formatter::asDatetime()|datetime]] 方法进行格式化,
你可以对他们进行一些自己的配置,只需在配置文件里配置 [[yii\i18n\Formatter::dateFormat|dateFormat]],
[[yii\i18n\Formatter::timeFormat|timeFormat]], 和 [[yii\i18n\Formatter::datetimeFormat|datetimeFormat]] 即可。
同时,你还可以配置它使用 [ICU syntax](http://userguide.icu-project.org/formatparse/datetime),同时你也可以配置它使用 [PHP date() 语法](http://php.net/manual/en/function.date.php),只需要加上 `php:` 前缀即可。
同时,你还可以配置它使用 [ICU syntax](http://userguide.icu-project.org/formatparse/datetime),
同时你也可以配置它使用 [PHP date() 语法](http://php.net/manual/en/function.date.php),只需要加上 `php:` 前缀即可。
例如,
```php
// ICU format
@ -89,22 +97,39 @@ echo Yii::$app->formatter->asDate('now', 'yyyy-MM-dd'); // 2014-10-06
echo Yii::$app->formatter->asDate('now', 'php:Y-m-d'); // 2014-10-06
```
不同的国家和地区使用不同的时间格式。 你可以使用短语 (例如 `long`, `short`) 来代替.
`formatter` 组件会根据当前的 [[yii\i18n\Formatter::locale|locale]] 将你的短语转换成合适的格式化输出。
目前支持以下短语 (例子当前的 [[yii\i18n\Formatter::locale|locale]] 为 `en_GB`):
> Info: Some letters of the PHP format syntax are not supported by ICU and thus the PHP intl extension and can not be used
> in Yii formatter. Most of these (`w`, `t`, `L`, `B`, `u`, `I`, `Z`) are not really useful for formatting dates but rather
> used when doing date math. `S` and `U` however may be useful. Their behavior can be achived by doing the following:
>
> - for `S`, which is the English ordinal suffix for the day of the month (e.g. st, nd, rd or th.), the following replacement can be used:
>
> ```php
> $f = Yii::$app->formatter;
> $d = $f->asOrdinal($f->asDate('2017-05-15', 'php:j'));
> echo "On the $d day of the month."; // prints "On the 15th day of the month."
> ```
>
> - for `U`, the Unix Epoch, you can use the [[yii\i18n\Formatter::asTimestamp()|timestamp]] format.
When working with applications that need to support multiple languages, you often need to specify different date
and time formats for different locales. To simplify this task, you may use format shortcuts (e.g. `long`, `short`), instead.
The formatter will turn a format shortcut into an appropriate format according to the currently active [[yii\i18n\Formatter::locale|locale]].
The following format shortcuts are supported (the examples assume `en_GB` is the active locale):
- `short`: will output `06/10/2014` for date and `15:58` for time;
- `medium`: will output `6 Oct 2014` and `15:58:42`;
- `long`: will output `6 October 2014` and `15:58:42 GMT`;
- `full`: will output `Monday, 6 October 2014` and `15:58:42 GMT`.
版本 2.0.7 起,支持格式化日期为不同的系统时钟,具体请查看文档 [[yii\i18n\Formatter::$calendar|$calendar]]-property
版本 2.0.7 起,支持格式化日期为不同的系统时钟,
Please refer to the API documentation of the formatters [[yii\i18n\Formatter::$calendar|$calendar]]-property on how to set a different calendar.
### 时区 <span id="time-zones"></span>
### 时区(Time Zones) <span id="time-zones"></span>
格式化时间/日期数据时,你会将他们转换成 [[yii\i18n\Formatter::timeZone|time zone]]
这个时候,默认的时区为 UTC,除非你另外指定 [[yii\i18n\Formatter::defaultTimeZone]]。
这个时候,默认的时区为 UTC,除非你另外指定
[[yii\i18n\Formatter::defaultTimeZone]]。
下面使用 `Europe/Berlin` 作为默认 [[yii\i18n\Formatter::timeZone|time zone]]
@ -119,31 +144,39 @@ echo Yii::$app->formatter->asTime('2014-10-06 12:41:00'); // 14:41:00
echo Yii::$app->formatter->asTime('2014-10-06 14:41:00 CEST'); // 14:41:00
```
> 不同的政府和地区政策决定不同的时区, 你在你的时区数据库中可能拿不到最新的数据。
If the [[yii\i18n\Formatter::timeZone|time zone]] is not set explicitly on the formatter component, the
[[yii\base\Application::timeZone|time zone configured in the application]] is used, which is the same time zone
as set in the PHP configuration.
> 不同的政府和地区政策决定不同的时区,
> 你在你的时区数据库中可能拿不到最新的数据。
> 这时你可以戳 [ICU manual](http://userguide.icu-project.org/datetime/timezone#TOC-Updating-the-Time-Zone-Data) 来查看如何更新时区。
> 同时,这篇也可以作为参考 [Setting up your PHP environment for internationalization](tutorial-i18n.md#setup-environment)
> 同时,这篇也可以作为参考 [Setting up your PHP environment for internationalization](tutorial-i18n.md#setup-environment)
## 格式化数字 <span id="numbers"></span>
## 格式化数字(Formatting Numbers) <span id="numbers"></span>
`formatter` 支持如下的方法
- [[yii\i18n\Formatter::asInteger()|integer]]: 这个变量将被格式化为整形 e.g. `42`.
- [[yii\i18n\Formatter::asDecimal()|decimal]]: 这个变量将被格式化为带着逗号的指定精度的浮点型 e.g. `2,542.123` or `2.542,123`.
- [[yii\i18n\Formatter::asDecimal()|decimal]]: 这个变量将被格式化为带着逗号的指定精度的浮点型,
 例如:`2,542.123` 或 `2.542,123`
- [[yii\i18n\Formatter::asPercent()|percent]]: 这个变量将被格式化为百分比 e.g. `42%`.
- [[yii\i18n\Formatter::asScientific()|scientific]]: 这个变量将被格式化为科学计数法 e.g. `4.2E4`.
- [[yii\i18n\Formatter::asCurrency()|currency]]: 这个变量将被格式化为货币 `£420.00`.
- [[yii\i18n\Formatter::asCurrency()|currency]]: 这个变量将被格式化为货币,
 例如:`£420.00`。
使用这个方法前请确认是否已经正确配置 [[yii\i18n\Formatter::locale|locale]]
- [[yii\i18n\Formatter::asSize()|size]]: 这个变量将被格式化为人类可读的字节数 e.g. `410 kibibytes`.
- [[yii\i18n\Formatter::asShortSize()|shortSize]]: 这个变量将被格式化为人类可读的字节数(缩写) [[yii\i18n\Formatter::asSize()|size]], e.g. `410 KiB`.
- [[yii\i18n\Formatter::asShortSize()|shortSize]]: 这个变量将被格式化为人类可读的字节数(缩写) [[yii\i18n\Formatter::asSize()|size]],例如:`410 KiB`。
你可以使用 [[yii\i18n\Formatter::decimalSeparator|decimalSeparator]] 和 [[yii\i18n\Formatter::thousandSeparator|thousandSeparator]] 来进行调整。
你可以使用 [[yii\i18n\Formatter::decimalSeparator|decimalSeparator]] 和
[[yii\i18n\Formatter::thousandSeparator|thousandSeparator]] 来进行调整。
他们都会根据当前的 [[yii\i18n\Formatter::locale|locale]] 来进行格式化.
如果你想要进行更高级的配置, 可以使用 [[yii\i18n\Formatter::numberFormatterOptions]] 和 [[yii\i18n\Formatter::numberFormatterTextOptions]],[NumberFormatter class](http://php.net/manual/en/class.numberformatter.php) 来进行格式化。
举个例子,为了调整小数部分的最大值和最小值,你可以配置 [[yii\i18n\Formatter::numberFormatterOptions]] 如下:
如果你想要进行更高级的配置, 可以使用 [[yii\i18n\Formatter::numberFormatterOptions]] 和
[[yii\i18n\Formatter::numberFormatterTextOptions]],
[NumberFormatter class](http://php.net/manual/en/class.numberformatter.php) 来进行格式化。
例如,为了调整小数部分的最大值和最小值,你可以配置 [[yii\i18n\Formatter::numberFormatterOptions]] 如下:
```php
'numberFormatterOptions' => [
@ -153,31 +186,40 @@ echo Yii::$app->formatter->asTime('2014-10-06 14:41:00 CEST'); // 14:41:00
```
## 其他的格式化 <span id="other"></span>
## 其他的格式化(Other Formats) <span id="other"></span>
除了时间/日期和数字的格式化,Yii 还支持如下的常用格式化
- [[yii\i18n\Formatter::asRaw()|raw]]: 除了 `null` 会被 [[nullDisplay]] 格式化外,原样输出。
- [[yii\i18n\Formatter::asText()|text]]: 编码为 HTML 格式。同时这也是 [GridView DataColumn](output-data-widgets.md#data-column) 默认使用的方法。
- [[yii\i18n\Formatter::asNtext()|ntext]]: 编码为 HTML 格式,换行也将被转换。
- [[yii\i18n\Formatter::asParagraphs()|paragraphs]]: 编码为 HTML 格式,以 `<p>` 标签包裹。
- [[yii\i18n\Formatter::asHtml()|html]]: 这个数值将会被 [[HtmlPurifier]] 来进行过滤来防御 XSS 攻击,你可以添加一些配置例如 `['html', ['Attr.AllowedFrameTargets' => ['_blank']]]`
- [[yii\i18n\Formatter::asEmail()|email]]: 这个数值将被转换为 `mailto` 链接。
- [[yii\i18n\Formatter::asImage()|image]]: 转换为图片标签(`img`)。
- [[yii\i18n\Formatter::asUrl()|url]]: 转换为超链接。
- [[yii\i18n\Formatter::asBoolean()|boolean]]: `true` => `Yes`, `false` => `No`,可以进行另外的配置: [[yii\i18n\Formatter::booleanFormat]] 。
## 空值 <span id="null-values"></span>
- [[yii\i18n\Formatter::asRaw()|raw]]: the value is outputted as is, this is a pseudo-formatter that has no effect except that
`null` values will be formatted using [[nullDisplay]].
- [[yii\i18n\Formatter::asText()|text]]: the value is HTML-encoded.
This is the default format used by the [GridView DataColumn](output-data-widgets.md#data-column).
- [[yii\i18n\Formatter::asNtext()|ntext]]: the value is formatted as an HTML-encoded plain text with newlines converted
into line breaks.
- [[yii\i18n\Formatter::asParagraphs()|paragraphs]]: the value is formatted as HTML-encoded text paragraphs wrapped
into `<p>` tags.
- [[yii\i18n\Formatter::asHtml()|html]]: the value is purified using [[HtmlPurifier]] to avoid XSS attacks. You can
pass additional options such as `['html', ['Attr.AllowedFrameTargets' => ['_blank']]]`.
- [[yii\i18n\Formatter::asEmail()|email]]: the value is formatted as a `mailto`-link.
- [[yii\i18n\Formatter::asImage()|image]]: the value is formatted as an image tag.
- [[yii\i18n\Formatter::asUrl()|url]]: the value is formatted as a hyperlink.
- [[yii\i18n\Formatter::asBoolean()|boolean]]: the value is formatted as a boolean. By default `true` is rendered
as `Yes` and `false` as `No`, translated to the current application language. You can adjust this by configuring
the [[yii\i18n\Formatter::booleanFormat]] property.
## 空值(Null Values) <span id="null-values"></span>
空值(`null`)会被特殊格式化. `fommater` 默认会将空值格式化为 `(not set)` 对应的当前的语言.
你可以配置 [[yii\i18n\Formatter::nullDisplay|nullDisplay]] 属性来进行个性化.
你可以配置 [[yii\i18n\Formatter::nullDisplay|nullDisplay]]
属性来进行个性化。
## 本地日期格式化 <span id="localizing-data-format"></span>
## 本地日期格式化(Localizing Data Format) <span id="localizing-data-format"></span>
`formatter` 会使用当前的 [[yii\i18n\Formatter::locale|locale]] 来决定格式化的内容。
对于同样的日期,不同的时区配置会有不同的输出:
As aforementioned, the formatter may use the currently active [[yii\i18n\Formatter::locale|locale]] to determine how
to format a value that is suitable in the target country/region. For example, the same date value may be formatted
differently for different locales:
```php
Yii::$app->formatter->locale = 'en-US';
@ -193,10 +235,12 @@ echo Yii::$app->formatter->asDate('2014-01-01'); // output: 1 января 2014
默认配置下,当前 [[yii\i18n\Formatter::locale|locale]] 决定于 [[yii\base\Application::language]].
你可以覆盖 [[yii\i18n\Formatter::locale]] 属性来满足不同的需要。
> Note: Yii formatter 依赖 [PHP intl extension](http://php.net/manual/en/book.intl.php) 来进行本地数据格式化
> 因为不同的 ICU 库可能会导致不同的输出,所以请在你的所有机器上保持 ICU 库的一致性.
> 请戳 [Setting up your PHP environment for internationalization](tutorial-i18n.md#setup-environment).
> Note: Yii formatter 依赖 [PHP intl extension](http://php.net/manual/en/book.intl.php)
> 来进行本地数据格式化
> 因为不同的 ICU 库可能会导致不同的输出,所以请在你的所有机器上保持 ICU 库的一致性.。
> 请参阅 [Setting up your PHP environment for internationalization](tutorial-i18n.md#setup-environment)。
>
> 如果 `intl` 扩展没有被安装,数据格式化不会考虑本地化.
>
> 在 32 位系统中,1901 年前或者 2038 年后的日期数据将不会被本地化,因为 ICU 使用的是 32 位的 UNIX 时间戳。
> 在 32 位系统中,1901 年前或者 2038 年后的日期数据将不会被本地化,
> 因为 ICU 使用的是 32 位的 UNIX 时间戳。

587
docs/guide-zh-CN/runtime-routing.md

@ -2,32 +2,32 @@
=======
当[入口脚本](structure-entry-scripts.md)在调用 [[yii\web\Application::run()|run()]]
方法时,它进行的第一个操作就是解析输入的请求,然后实例化对应的[控制器操作](structure-controllers.md)处理这个请求。
该过程就被称为**引导路由(routing)**。
方法时,它进行的第一个操作就是解析输入的请求,然后实例化对应的[控制器动作](structure-controllers.md)处理这个请求。
该过程就被称为*引导路由(routing)*。
路由相反的操作会将给定的路由和参数生成一个可访问的URL地址,
这个操作叫做*创建URL*。
创建出来的URL被请求的时候,路由处理器可以解析成原始的路由信息和参数。
The reverse process of routing is called *URL creation*, which creates a URL from a given route
and the associated query parameters. When the created URL is later requested, the routing process can resolve it
back into the original route and query parameters.
The central piece responsible for routing and URL creation is the [[yii\web\UrlManager|URL manager]],
which is registered as the `urlManager` [application component](structure-application-components.md). The [[yii\web\UrlManager|URL manager]]
provides the [[yii\web\UrlManager::parseRequest()|parseRequest()]] method to parse an incoming request into
a route and the associated query parameters and the [[yii\web\UrlManager::createUrl()|createUrl()]] method to
create a URL from a given route and its associated query parameters.
负责路由解析和创建URL的组件是 [[yii\web\UrlManager|URL管理器]],
URL管理器在[程序组件](structure-application-components.md)中被注册成 `urlManager`
[[yii\web\UrlManager|URL管理器]] 提供方法 [[yii\web\UrlManager::parseRequest()|parseRequest()]] 来
解析请求的URL并返回路由信息和参数,
方法 [[yii\web\UrlManager::createUrl()|createUrl()]] 用来根据提供的路由和参数创建一个可访问的URL。
By configuring the `urlManager` component in the application configuration, you can let your application
recognize arbitrary URL formats without modifying your existing application code. For example, you can
use the following code to create a URL for the `post/view` action:
在程序配置中配置 `urlManager` 组件,可以让你的应用不改变现有代码的情况下
识别任意的URL格式。
例如使用下面的代码创建一个到 `post/view` 控制器的 URL:
```php
use yii\helpers\Url;
// Url::to() calls UrlManager::createUrl() to create a URL
// Url::to() 将调用 UrlManager::createUrl() 来创建URL
$url = Url::to(['post/view', 'id' => 100]);
```
Depending on the `urlManager` configuration, the created URL may look like one of the following (or other format).
And if the created URL is requested later, it will still be parsed back into the original route and query parameter value.
根据 `urlManager` 中的配置,创建出来的URL可能看起来像是以下的一种格式(或者其它的格式)。
如果此URL被访问,将被解析成原来的路由和参数。
```
/index.php?r=post%2Fview&id=100
@ -38,62 +38,62 @@ And if the created URL is requested later, it will still be parsed back into the
## URL 格式化 <span id="url-formats"></span>
The [[yii\web\UrlManager|URL manager]] supports two URL formats:
[[yii\web\UrlManager|URL管理器]]提供两种URL格式:
- the default URL format;
- the pretty URL format.
- 默认URL格式;
- 美化URL格式。
The default URL format uses a query parameter named `r` to represent the route and normal query parameters
to represent the query parameters associated with the route. For example, the URL `/index.php?r=post/view&id=100` represents
the route `post/view` and the `id` query parameter 100. The default URL format does not require any configuration of
the [[yii\web\UrlManager|URL manager]] and works in any Web server setup.
默认URL格式试用一个参数`r`表示路由,
并且试用一般的参数格式表示请求参数。例如,`/index.php?r=post/view&id=100`表示路由为`post/view`,参数`id`为100。
默认URL格式不需要为[[yii\web\UrlManager|URL管理器]]做任何配置,
并且在任何Web服务器都可以正常试用。
The pretty URL format uses the extra path following the entry script name to represent the route and the associated
query parameters. For example, the extra path in the URL `/index.php/post/100` is `/post/100` which may represent
the route `post/view` and the `id` query parameter 100 with a proper [[yii\web\UrlManager::rules|URL rule]]. To use
the pretty URL format, you will need to design a set of [[yii\web\UrlManager::rules|URL rules]] according to the actual
requirement about how the URLs should look like.
美化URL格式在脚本名称后面使用更多的路径信息表示路由和参数信息。
例如,用适当的[[yii\web\UrlManager::rules|URL规则]],`/index.php/post/100`中附加的路径信息`/post/100`表示
路由为`post/view`,参数`id`为100。
要试用美化的URL格式,你需要根据实际的需求
设计一组[[yii\web\UrlManager::rules|URL规则]]来规定URL的样式。
You may switch between the two URL formats by toggling the [[yii\web\UrlManager::enablePrettyUrl|enablePrettyUrl]]
property of the [[yii\web\UrlManager|URL manager]] without changing any other application code.
你可以仅设置[[yii\web\UrlManager|URL管理器]]中的[[yii\web\UrlManager::enablePrettyUrl|开启美化URL]]来切换两种URL格式,
而不必改动任何程序代码。
## 路由 <span id="routing"></span>
Routing involves two steps:
路由处理包含两个步骤:
- the incoming request is parsed into a route and the associated query parameters;
- a [controller action](structure-controllers.md#actions) corresponding to the parsed route
is created to handle the request.
- 请求被解析成一个路由和关联的参数;
- 路由相关的一个[控制器动作](structure-controllers.md#actions)被创建出来处理这个请求。
When using the default URL format, parsing a request into a route is as simple as getting the value of a `GET`
query parameter named `r`.
When using the pretty URL format, the [[yii\web\UrlManager|URL manager]] will examine the registered
[[yii\web\UrlManager::rules|URL rules]] to find matching one that can resolve the request into a route.
If such a rule cannot be found, a [[yii\web\NotFoundHttpException]] exception will be thrown.
如果使用默认URL格式,解析请求到路由只是简单的从`GET`请求中得到命名为`r`的参数。
Once the request is parsed into a route, it is time to create the controller action identified by the route.
The route is broken down into multiple parts by the slashes in it. For example, `site/index` will be
broken into `site` and `index`. Each part is an ID which may refer to a module, a controller or an action.
Starting from the first part in the route, the application takes the following steps to create modules (if any),
controller and action:
1. Set the application as the current module.
2. Check if the [[yii\base\Module::controllerMap|controller map]] of the current module contains the current ID.
If so, a controller object will be created according to the controller configuration found in the map,
and Step 5 will be taken to handle the rest part of the route.
3. Check if the ID refers to a module listed in the [[yii\base\Module::modules|modules]] property of
the current module. If so, a module is created according to the configuration found in the module list,
and Step 2 will be taken to handle the next part of the route under the context of the newly created module.
4. Treat the ID as a [controller ID](structure-controllers.md#controller-ids) and create a controller object. Do the next step with the rest part of
the route.
5. The controller looks for the current ID in its [[yii\base\Controller::actions()|action map]]. If found,
it creates an action according to the configuration found in the map. Otherwise, the controller will
attempt to create an inline action which is defined by an action method corresponding to the current [action ID](structure-controllers.md#action-ids).
当试用美化URL格式时,[[yii\web\UrlManager|URL管理器]]将检查注册的[[yii\web\UrlManager::rules|URL规则]],
找到一条可以匹配的将请求转到路由的规则。
如果找不到任何匹配的规则,系统将抛出[[yii\web\NotFoundHttpException]]异常。
Among the above steps, if any error occurs, a [[yii\web\NotFoundHttpException]] will be thrown, indicating
the failure of the routing process.
一旦请求解析成路由,系统将马上根据路由信息创建一个控制器动作。
路由信息根据`/`分解成多个部分。例如,`site/index`将被分解成`site`和`index`两部分。
每个部分都可能被认为是一个模块、控制器或动作的ID。
从路由的第一个部分开始,系统将执行以下步骤创建所需模块(如果有模块的话)、控制器和动作:
1. 设置应用系统作为当前的模块。
2. 检查当前模块中的[[yii\base\Module::controllerMap|控制器映射]]是否存在当前ID。
如果存在,根据控制器映射中的定义创建一个控制器实例,
跳到步骤5处理路由剩下的部分。
3. 检查ID是否为当前模块下[[yii\base\Module::modules|modules]]定义的子模块
如果是,创建对应子模块,
跳到步骤2使用刚创建的子模块处理路由下一部分。
4. 将ID作为一个[控制器ID](structure-controllers.md#controller-ids)并创建一个控制器实例,
并用来处理路由剩下的部分。
5. 控制器在自己的[[yii\base\Controller::actions()|动作映射]]中查找当前ID。
如果找到,根据映射中的定义创建一个动作。
如果没找到,控制器将尝试根据[动作ID](structure-controllers.md#action-ids)定义的动作方法创建一个行内动作。
在上面的步骤中,如果出现任何错误,系统将抛出一个[[yii\web\NotFoundHttpException]]异常,
表示路由处理程序出现的错误信息。
### 缺省路由 <span id="default-route"></span>
@ -110,17 +110,17 @@ return [
];
```
Similar to the default route of the application, there is also a default route for modules, so for example if there
is a `user` module and the request is parsed into the route `user` the module's [[yii\base\Module::defaultRoute|defaultRoute]]
is used to determine the controller. By default the controller name is `default`. If no action is specified in [[yii\base\Module::defaultRoute|defaultRoute]],
the [[yii\base\Controller::defaultAction|defaultAction]] property of the controller is used to determine the action.
In this example, the full route would be `user/default/index`.
和应用系统中的缺省路由类似,模块中也存在一个缺省路由,所以如果
有一个`user`模块,当请求到`user`模块时,模块的[[yii\base\Module::defaultRoute|缺省路由]]
被用来决定缺省的控制器。默认的缺省控制器名称是`default`。如果在[[yii\base\Module::defaultRoute|缺省路由]]中没有指定任何动作,
[[yii\base\Controller::defaultAction|缺省动作]]将被用来决定缺省的动作。
在这个例子中,完整的路由应该是`user/default/index`。
### `catchAll` 路由(全拦截路由) <span id="catchall-route"></span>
有时候,你会想要将你的 Web
应用临时调整到维护模式,所有的请求下都会显示相同的信息页。当然,要实现这一点有很多种方法。这里面最简单快捷的方法就是在应用配置中设置
有时候,你会想要将你的 Web应用临时调整到维护模式,所有的请求下都会显示相同的信息页。
当然,要实现这一点有很多种方法。这里面最简单快捷的方法就是在应用配置中设置
[[yii\web\Application::catchAll]] 属性:
```php
@ -130,123 +130,123 @@ return [
];
```
With the above configuration, the `site/offline` action will be used to handle all incoming requests.
根据上面的配置,`site/offline`控制器将被用来处理所有的请求。
The `catchAll` property should take an array whose first element specifies a route, and
the rest of the elements (name-value pairs) specify the parameters to be [bound to the action](structure-controllers.md#action-parameters).
`catchAll`属性应该配置成一个数组,第一个元素为路由,
剩下的元素为键值对格式的[动作的参数](structure-controllers.md#action-parameters)。
> Info: The [debug toolbar](https://github.com/yiisoft/yii2-debug/blob/master/docs/guide/README.md) in development environment
> will not work when this property is enabled.
> Info: 如果此属性被设置,开发环境中的[调试工具条](https://github.com/yiisoft/yii2-debug/blob/master/docs/guide/README.md)
> 将被停用。
## 创建 URLs <span id="creating-urls"></span>
Yii provides a helper method [[yii\helpers\Url::to()]] to create various kinds of URLs from given routes and
their associated query parameters. For example,
Yii提供了一个助手方法[[yii\helpers\Url::to()]],用来根据提供的路由和参数创建各种各样的URL。
例如:
```php
use yii\helpers\Url;
// creates a URL to a route: /index.php?r=post%2Findex
// 创建一个普通的路由URL:/index.php?r=post%2Findex
echo Url::to(['post/index']);
// creates a URL to a route with parameters: /index.php?r=post%2Fview&id=100
// 创建一个带路由参数的URL:/index.php?r=post%2Fview&id=100
echo Url::to(['post/view', 'id' => 100]);
// creates an anchored URL: /index.php?r=post%2Fview&id=100#content
// 创建一个带锚定的URL:/index.php?r=post%2Fview&id=100#content
echo Url::to(['post/view', 'id' => 100, '#' => 'content']);
// creates an absolute URL: http://www.example.com/index.php?r=post%2Findex
// 创建一个绝对路径URL:http://www.example.com/index.php?r=post%2Findex
echo Url::to(['post/index'], true);
// creates an absolute URL using the https scheme: https://www.example.com/index.php?r=post%2Findex
// 创建一个带https协议的绝对路径URL:https://www.example.com/index.php?r=post%2Findex
echo Url::to(['post/index'], 'https');
```
Note that in the above example, we assume the default URL format is being used. If the pretty URL format is enabled,
the created URLs will be different, according to the [[yii\web\UrlManager::rules|URL rules]] in use.
注意上面的例子中,我们假定使用默认的URL格式。如果启用美化的URL格式,
创建出来的URL根据使用的[[yii\web\UrlManager::rules|URL规则]]可能有所不同。
方法[[yii\helpers\Url::to()]]传入的路由是上下文相关的。
根据以下规则确认传入的路由是一个*相对的*路由还是*绝对的*路由:
The route passed to the [[yii\helpers\Url::to()]] method is context sensitive. It can be either a *relative* route
or an *absolute* route which will be normalized according to the following rules:
- 如果路由是一个空字符串,则使用当前请求的[[yii\web\Controller::route|路由]];
- 如果路由中不存在`/`,则被认为是一个当前控制器下的动作ID,
且路由被附加到当前控制器的[[\yii\web\Controller::uniqueId|唯一ID]]后面;
- 如果路由不以`/`开头,被认为是当前模块下的路由,
路由将被附加到当前模块的[[\yii\base\Module::uniqueId|唯一ID]]后面。
- If the route is an empty string, the currently requested [[yii\web\Controller::route|route]] will be used;
- If the route contains no slashes at all, it is considered to be an action ID of the current controller
and will be prepended with the [[\yii\web\Controller::uniqueId|uniqueId]] value of the current controller;
- If the route has no leading slash, it is considered to be a route relative to the current module and
will be prepended with the [[\yii\base\Module::uniqueId|uniqueId]] value of the current module.
从版本 2.0.2 开始,你可以使用根据[别名](concept-aliases.md)中定义的别名路由。如果是这种情况,
别名将首先被转化为实际的路由,然后根据上面的规则转化成一个绝对路由。
Starting from version 2.0.2, you may specify a route in terms of an [alias](concept-aliases.md). If this is the case,
the alias will first be converted into the actual route which will then be turned into an absolute route according
to the above rules.
For example, assume the current module is `admin` and the current controller is `post`,
例如,假设当前的模块为`admin`,当前控制器为`post`,
```php
use yii\helpers\Url;
// currently requested route: /index.php?r=admin%2Fpost%2Findex
// 当前请求路由:/index.php?r=admin%2Fpost%2Findex
echo Url::to(['']);
// a relative route with action ID only: /index.php?r=admin%2Fpost%2Findex
// 只有动作ID的相对路由:/index.php?r=admin%2Fpost%2Findex
echo Url::to(['index']);
// a relative route: /index.php?r=admin%2Fpost%2Findex
// 相对路由:/index.php?r=admin%2Fpost%2Findex
echo Url::to(['post/index']);
// an absolute route: /index.php?r=post%2Findex
// 绝对路由:/index.php?r=post%2Findex
echo Url::to(['/post/index']);
// /index.php?r=post%2Findex assume the alias "@posts" is defined as "/post/index"
// 假设有一个"/post/index"的别名"@posts":/index.php?r=post%2Findex
echo Url::to(['@posts']);
```
The [[yii\helpers\Url::to()]] method is implemented by calling the [[yii\web\UrlManager::createUrl()|createUrl()]]
and [[yii\web\UrlManager::createAbsoluteUrl()|createAbsoluteUrl()]] methods of the [[yii\web\UrlManager|URL manager]].
In the next few subsections, we will explain how to configure the [[yii\web\UrlManager|URL manager]] to customize
the format of the created URLs.
方法 [[yii\helpers\Url::to()]] 实际上调用了 [[yii\web\UrlManager|URL管理器]] 中的 [[yii\web\UrlManager::createUrl()|createUrl()]] 方法
和 [[yii\web\UrlManager::createAbsoluteUrl()|createAbsoluteUrl()]] 方法。
下面的介绍中,我们将介绍如何配置 [[yii\web\UrlManager|URL管理器]] 来创建自定义的 URL 格式。
The [[yii\helpers\Url::to()]] method also supports creating URLs that are NOT related with particular routes.
Instead of passing an array as its first parameter, you should pass a string in this case. For example,
方法 [[yii\helpers\Url::to()]] 同时支持创建和任何路由不相关的 URL。
这种情况下,第一个参数不再传入一个数组,而是传入一个字符串。例如:
```php
use yii\helpers\Url;
// currently requested URL: /index.php?r=admin%2Fpost%2Findex
// 当前请求URL:/index.php?r=admin%2Fpost%2Findex
echo Url::to();
// an aliased URL: http://example.com
// 设定了别名的URL:http://example.com
Yii::setAlias('@example', 'http://example.com/');
echo Url::to('@example');
// an absolute URL: http://example.com/images/logo.gif
// 绝对URL:http://example.com/images/logo.gif
echo Url::to('/images/logo.gif', true);
```
Besides the `to()` method, the [[yii\helpers\Url]] helper class also provides several other convenient URL creation
methods. For example,
除了 `to()` 方法,[[yii\helpers\Url]] 助手类同时提供了多个其它创建 URL 的方法。
例如:
```php
use yii\helpers\Url;
// home page URL: /index.php?r=site%2Findex
// 主页URL:/index.php?r=site%2Findex
echo Url::home();
// the base URL, useful if the application is deployed in a sub-folder of the Web root
// 根URL,如果程序部署到一个Web目录下的子目录时非常有用
echo Url::base();
// the canonical URL of the currently requested URL
// see https://en.wikipedia.org/wiki/Canonical_link_element
// 当前请求的权威规范URL
// 参考 https://en.wikipedia.org/wiki/Canonical_link_element
echo Url::canonical();
// remember the currently requested URL and retrieve it back in later requests
// 记住当前请求的URL并在以后获取
Url::remember();
echo Url::previous();
```
## Using Pretty URLs <span id="using-pretty-urls"></span>
## 使用美化的 URL <span id="using-pretty-urls"></span>
To use pretty URLs, configure the `urlManager` component in the application configuration like the following:
要使用美化的URL,像下面这样在应用配置中配置`urlManager`组件:
```php
[
@ -263,47 +263,47 @@ To use pretty URLs, configure the `urlManager` component in the application conf
]
```
The [[yii\web\UrlManager::enablePrettyUrl|enablePrettyUrl]] property is mandatory as it toggles the pretty URL format.
The rest of the properties are optional. However, their configuration shown above is most commonly used.
* [[yii\web\UrlManager::showScriptName|showScriptName]]: this property determines whether the entry script
should be included in the created URLs. For example, instead of creating a URL `/index.php/post/100`,
by setting this property to be false, a URL `/post/100` will be generated.
* [[yii\web\UrlManager::enableStrictParsing|enableStrictParsing]]: this property determines whether to enable
strict request parsing. If strict parsing is enabled, the incoming requested URL must match at least one of
the [[yii\web\UrlManager::rules|rules]] in order to be treated as a valid request, or a [[yii\web\NotFoundHttpException]]
will be thrown. If strict parsing is disabled, when none of the [[yii\web\UrlManager::rules|rules]] matches
the requested URL, the path info part of the URL will be treated as the requested route.
* [[yii\web\UrlManager::rules|rules]]: this property contains a list of rules specifying how to parse and create
URLs. It is the main property that you should work with in order to create URLs whose format satisfies your
particular application requirement.
> Note: In order to hide the entry script name in the created URLs, besides setting
[[yii\web\UrlManager::showScriptName|showScriptName]] to be false, you may also need to configure your Web server
so that it can correctly identify which PHP script should be executed when a requested URL does not explicitly
specify one. If you are using Apache Web server, you may refer to the recommended configuration as described in the
[Installation](start-installation.md#recommended-apache-configuration) section.
### URL Rules <span id="url-rules"></span>
A URL rule is an instance of [[yii\web\UrlRule]] or its child class. Each URL rule consists of a pattern used
for matching the path info part of URLs, a route, and a few query parameters. A URL rule can be used to parse a request
if its pattern matches the requested URL. A URL rule can be used to create a URL if its route and query parameter
names match those that are given.
When the pretty URL format is enabled, the [[yii\web\UrlManager|URL manager]] uses the URL rules declared in its
[[yii\web\UrlManager::rules|rules]] property to parse incoming requests and create URLs. In particular,
to parse an incoming request, the [[yii\web\UrlManager|URL manager]] examines the rules in the order they are
declared and looks for the *first* rule that matches the requested URL. The matching rule is then used to
parse the URL into a route and its associated parameters. Similarly, to create a URL, the [[yii\web\UrlManager|URL manager]]
looks for the first rule that matches the given route and parameters and uses that to create a URL.
You can configure [[yii\web\UrlManager::rules]] as an array with keys being the patterns and values the corresponding
routes. Each pattern-route pair constructs a URL rule. For example, the following [[yii\web\UrlManager::rules|rules]]
configuration declares two URL rules. The first rule matches a URL `posts` and maps it into the route `post/index`.
The second rule matches a URL matching the regular expression `post/(\d+)` and maps it into the route `post/view` and
a parameter named `id`.
[[yii\web\UrlManager::enablePrettyUrl|开启美化URL]] 属性被用来切换是否启用美化URL格式。
虽然除了[[yii\web\UrlManager::enablePrettyUrl|开启美化URL]] 属性以外其它属性都是可选的,但是上面的配置是最常用到的。
* [[yii\web\UrlManager::showScriptName|是否显示脚本名称]]:
此属性决定创建的URL中是否包含入口脚本名称。
例如,默认的 `/index.php/post/100`,开启此属性后将创建成 `/post/100`
* [[yii\web\UrlManager::enableStrictParsing|是否开启严格解析]]:此属性决定是否开启严格的请求解析。
如果设置为启用,请求的URL必须至少匹配 [[yii\web\UrlManager::rules|规则]] 中设定的一条规则作为正确请求,
否则系统将抛出 [[yii\web\NotFoundHttpException]] 异常。
如果严格解析被关闭,当 [[yii\web\UrlManager::rules|规则]] 中没有任何一条匹配时,
请求URL中的路径信息将被作为请求路由使用。
* [[yii\web\UrlManager::rules|规则]]:此属性包含一个规则列表,用来规定如何解析和创建URL。
这是一个主要属性,你应该根据特定的应用环境配置此属性用来生成特定格式的URL。
> Note: 如果你想在URL中隐藏入口脚本名称,除了要设置 [[yii\web\UrlManager::showScriptName|showScriptName]] 为 false,
同时应该配置 Web 服务,处理当请求 URL 没有特殊指定入口脚本时确定要执行哪个PHP文件,
如果你试用 Apache Web server,你可以参考[安装](start-installation.md#recommended-apache-configuration)中推荐的配置。
### URL规则 <span id="url-rules"></span>
一个URL规则是类 [[yii\web\UrlRule]] 或子类的一个实例。每个URL规则包含一个匹配URL中的路径、路由和少量参数的规则。
如果请求地址匹配一个URL规则,则此规则可以用来解析此请求。
如果生成URL时路由和参数符合一个URL规则,则此规则可以用来生成此URL。
如果开启了美化URL格式,[[yii\web\UrlManager|URL管理器]]使用定义的[[yii\web\UrlManager::rules|规则]]解析请求和创建URL。
尤其注意,[[yii\web\UrlManager|URL管理器]]按照规则中定义的顺序依次检测请求地址,
当找到*第一条*匹配的规则时停止。
匹配到的规则将被用来解析请求URL到指定的路由和参数。
同样的,创建URL的时候,[[yii\web\UrlManager|URL管理器]] 查找
第一条匹配的的规则并用来生成URL。
你可以配置 [[yii\web\UrlManager::rules]] 为一个数组,键为匹配规则,值为路由。
每条键值对为一条URL规则。例如,下面的 [[yii\web\UrlManager::rules|规则]]
配置了两条URL规则。第一条规则匹配URL `posts` 映射到路由 `post/index`
第二条规则匹配符合正则表达式 `post/(\d+)` 的URL并映射到路由 `post/view`,同时包含
一个参数 `id`
```php
[
@ -312,17 +312,17 @@ a parameter named `id`.
]
```
> Info: The pattern in a rule is used to match the path info part of a URL. For example, the path info of
`/index.php/post/100?source=ad` is `post/100` (the leading and ending slashes are ignored) which matches
the pattern `post/(\d+)`.
> Info: 规则中的匹配模式用来匹配URL中的路径信息。例如,
`/index.php/post/100?source=ad`中的路径信息为 `post/100`(开始和结尾处的 `/` 将被忽略)和模式 `post/(\d+)` 匹配。
Besides declaring URL rules as pattern-route pairs, you may also declare them as configuration arrays. Each configuration
array is used to configure a single URL rule object. This is often needed when you want to configure other
properties of a URL rule. For example,
除了定义 URL 规则外,你还可以将规则定义为配置数组。
每个配置数组用来配置一个单独的 URL 规则对象。如果你需要配置 URL 规则的其它参数时可以这样用。
例如:
```php
[
// ...other url rules...
// ...其它 URL 规则...
[
'pattern' => 'posts',
@ -332,25 +332,25 @@ properties of a URL rule. For example,
]
```
By default if you do not specify the `class` option for a rule configuration, it will take the default
class [[yii\web\UrlRule]].
如果你在URL规则中不配置 `class` 选项,默认将使用类 [[yii\web\UrlRule]]。
### Named Parameters <span id="named-parameters"></span>
A URL rule can be associated with a few named query parameters which are specified in the pattern in the format
of `<ParamName:RegExp>`, where `ParamName` specifies the parameter name and `RegExp` is an optional regular
expression used to match parameter values. If `RegExp` is not specified, it means the parameter value should be
a string without any slash.
### 命名参数 <span id="named-parameters"></span>
> Note: You can only specify regular expressions for parameters. The rest part of a pattern is considered as plain text.
一条URL规则可以对匹配模式中的参数设置格式为 `<ParamName:RegExp>` 的命名,
其中 `ParamName` 指定参数的名称,`RegExp` 是可选的用来匹配参数值得正则表达式。
如果没有设置 `RegExp`,表示参数值为不包含 `/` 的字符串。
When a rule is used to parse a URL, it will fill the associated parameters with values matching the corresponding
parts of the URL, and these parameters will be made available in `$_GET` later by the `request` application component.
When the rule is used to create a URL, it will take the values of the provided parameters and insert them at the
places where the parameters are declared.
Let's use some examples to illustrate how named parameters work. Assume we have declared the following three URL rules:
> Note: 你可以仅针对参数设置正则表达式,其余部分设置普通文本。
当一条规则用来匹配URL时,符合匹配规则的相关的参数值被填充到规则中,
并且这些参数可以在 `request` 组件中使用 `$_GET` 获取到。
当规则用来创建 URL 时,
提供的参数值将被插入到规则定义的指定位置。
让我们使用一些例子来说明命名参数是如何工作的。假设我们定义了以下三条 URL 规则:
```php
[
@ -360,33 +360,33 @@ Let's use some examples to illustrate how named parameters work. Assume we have
]
```
When the rules are used to parse URLs:
当规则用来解析 URL 时:
- `/index.php/posts` is parsed into the route `post/index` using the second rule;
- `/index.php/posts/2014/php` is parsed into the route `post/index`, the `year` parameter whose value is 2014
and the `category` parameter whose value is `php` using the first rule;
- `/index.php/post/100` is parsed into the route `post/view` and the `id` parameter whose value is 100 using
the third rule;
- `/index.php/posts/php` will cause a [[yii\web\NotFoundHttpException]] when [[yii\web\UrlManager::enableStrictParsing]]
is `true`, because it matches none of the patterns. If [[yii\web\UrlManager::enableStrictParsing]] is `false` (the
default value), the path info part `posts/php` will be returned as the route.
- 根据第二条规则,`/index.php/posts` 被解析成路由 `post/index`
- 根据第一条规则,`/index.php/posts/2014/php` 被解析成路由 `post/index`
参数 `year` 的值是 2014,参数 `category` 的值是 `php`
- 根据第三条规则,`/index.php/post/100` 被解析成路由 `post/view`
参数 `id` 的值是 100;
- 当[[yii\web\UrlManager::enableStrictParsing]] 设置为 `true` 时,`/index.php/posts/php` 将导致一个[[yii\web\NotFoundHttpException]] 异常,
因为无法匹配任何规则。如果 [[yii\web\UrlManager::enableStrictParsing]] 设为 `false`(默认值),
路径部分 `posts/php` 将被作为路由。
And when the rules are used to create URLs:
当规则用来生成 URL 时:
- `Url::to(['post/index'])` creates `/index.php/posts` using the second rule;
- `Url::to(['post/index', 'year' => 2014, 'category' => 'php'])` creates `/index.php/posts/2014/php` using the first rule;
- `Url::to(['post/view', 'id' => 100])` creates `/index.php/post/100` using the third rule;
- `Url::to(['post/view', 'id' => 100, 'source' => 'ad'])` creates `/index.php/post/100?source=ad` using the third rule.
Because the `source` parameter is not specified in the rule, it is appended as a query parameter in the created URL.
- `Url::to(['post/index', 'category' => 'php'])` creates `/index.php/post/index?category=php` using none of the rules.
Note that since none of the rules applies, the URL is created by simply appending the route as the path info
and all parameters as the query string part.
- 根据第二条规则 `Url::to(['post/index'])` 生成 `/index.php/posts`
- 根据第一条规则 `Url::to(['post/index', 'year' => 2014, 'category' => 'php'])` 生成 `/index.php/posts/2014/php`
- 根据第三条规则 `Url::to(['post/view', 'id' => 100])` 生成 `/index.php/post/100`
- 根据第三条规则 `Url::to(['post/view', 'id' => 100, 'source' => 'ad'])` 生成 `/index.php/post/100?source=ad`
因为参数 `source` 在规则中没有指定,将被作为普通请求参数附加到生成的 URL 后面。
- `Url::to(['post/index', 'category' => 'php'])` 生成 `/index.php/post/index?category=php`
注意因为没有任何规则适用,将把路由信息当做路径信息来生成URL,
并且所有参数作为请求查询参数附加到 URL 后面。
### Parameterizing Routes <span id="parameterizing-routes"></span>
### 参数化路由 <span id="parameterizing-routes"></span>
You can embed parameter names in the route of a URL rule. This allows a URL rule to be used for matching multiple
routes. For example, the following rules embed `controller` and `action` parameters in the routes.
你可以在 URL 规则中嵌入参数名称,这样可以允许一个 URL 规则用来匹配多个路由。
例如,下面的规则在路由中嵌入了 `controller``action` 两个参数。
```php
'rules' => [
@ -397,27 +397,27 @@ routes. For example, the following rules embed `controller` and `action` paramet
]
```
To parse a URL `/index.php/comment/100/update`, the second rule will apply, which sets the `controller` parameter to
be `comment` and `action` parameter to be `update`. The route `<controller>/<action>` is thus resolved as `comment/update`.
解析 URL `/index.php/comment/100/update` 时,第二条规则适用,设置参数 `controller``comment`
设置参数 `action``update`。自然的,路由 `<controller>/<action>` 变成了 `comment/update`
同样的,根据路由 `comment/index` 创建 URL 时,最后一条规则适用,将生成 URL `/index.php/comments`
Similarly, to create a URL for the route `comment/index`, the last rule will apply, which creates a URL `/index.php/comments`.
> Info: 使用参数化的路由,可以显著的减少 URL 规则的数量,
可以显著提高[[yii\web\UrlManager|URL管理器]]的效率。
> Info: By parameterizing routes, it is possible to greatly reduce the number of URL rules, which can significantly
improve the performance of [[yii\web\UrlManager|URL manager]].
### 默认参数值 <span id="default-parameter-values"></span>
### Default Parameter Values <span id="default-parameter-values"></span>
默认的,所有规则中定义的参数都是必须的。如果一个请求 URL 不存在其中一个参数,
或者创建URL时没有指定其中一个参数,则无法应用此规则。
如果需要设置某些参数为可选的,必须设置规则的[[yii\web\UrlRule::defaults|默认值]]属性。
此属性中列出的参数将变成可选的且在没有指定时会使用此处设置的默认值。
By default, all parameters declared in a rule are required. If a requested URL does not contain a particular parameter,
or if a URL is being created without a particular parameter, the rule will not apply. To make some of the parameters
optional, you can configure the [[yii\web\UrlRule::defaults|defaults]] property of a rule. Parameters listed in this
property are optional and will take the specified values when they are not provided.
下面设置的规则中,参数 `page``tag` 都是可选的,当没有指定时将分别使用值 1 和空字符串。
In the following rule declaration, the `page` and `tag` parameters are both optional and will take the value of 1 and
empty string, respectively, when they are not provided.
```php
[
// ...other rules...
// ...其它规则...
[
'pattern' => 'posts/<page:\d+>/<tag>',
'route' => 'post/index',
@ -426,24 +426,27 @@ empty string, respectively, when they are not provided.
]
```
The above rule can be used to parse or create any of the following URLs:
上面的规则可以用来解析或创建下面的 URL:
* `/index.php/posts`: `page` is 1, `tag` is ''.
* `/index.php/posts/2`: `page` is 2, `tag` is ''.
* `/index.php/posts/2/news`: `page` is 2, `tag` is `'news'`.
* `/index.php/posts/news`: `page` is 1, `tag` is `'news'`.
* `/index.php/posts`:`page` 为 1,`tag` 为 ''。
* `/index.php/posts/2`:`page` 为 2,`tag` 为 ''。
* `/index.php/posts/2/news`:`page` 为 2,`tag`为 `'news'`
* `/index.php/posts/news`:`page` 为 1,`tag` 为 `'news'`
如果不使用可选参数,你必须创建 4 条规则才可以实现相同的效果。
> Note: 如果 [[yii\web\UrlRule::$pattern|pattern]] 中只存在可选参数和 `/`,只有所有参数被忽略时第一个参数才被忽略。
Without using optional parameters, you would have to create 4 rules to achieve the same result.
> Note: If [[yii\web\UrlRule::$pattern|pattern]] contains only optional parameters and slashes, first parameter could be omitted
only if all other parameters are omitted.
### Rules with Server Names <span id="rules-with-server-names"></span>
### 带服务名称的规则 <span id="rules-with-server-names"></span>
It is possible to include Web server names in the patterns of URL rules. This is mainly useful when your application
should behave differently for different Web server names. For example, the following rules will parse the URL
`http://admin.example.com/login` into the route `admin/user/login` and `http://www.example.com/login` into `site/login`.
可以在URL规则中设置Web服务的名称,如果你需要使你的应用程序在不同的Web服务名称下表现不同的话。
例如,下面的规则将URL`http://admin.example.com/login`解析成路由`admin/user/login`,
URL`http://www.example.com/login`解析成路由`site/login`。
```php
[
@ -452,8 +455,8 @@ should behave differently for different Web server names. For example, the follo
]
```
You can also embed parameters in the server names to extract dynamic information from them. For example, the following rule
will parse the URL `http://en.example.com/posts` into the route `post/index` and the parameter `language=en`.
你还可以在服务名称中嵌入参数用来动态的提取服务名称。例如,下面的规则
将URL`http://en.example.com/posts`解析成路由`post/index`且参数`language=en`。
```php
[
@ -461,20 +464,20 @@ will parse the URL `http://en.example.com/posts` into the route `post/index` and
]
```
Since version 2.0.11, you may also use protocol relative patterns that work for both, `http` and `https`.
The syntax is the same as above but skipping the `http:` part, e.g.: `'//www.example.com/login' => 'site/login'`.
从版本 2.0.11 开始,你还可以使用不带协议类型的模式来同时匹配 `http``https`
规则语法和上面相比只是忽略掉 `http:` 部分,例如:`'//www.example.com/login' => 'site/login'`。
> Note: Rules with server names should **not** include the subfolder of the entry script in their patterns. For example, if the applications entry script is at `http://www.example.com/sandbox/blog/index.php`, then you should use the pattern
`http://www.example.com/posts` instead of `http://www.example.com/sandbox/blog/posts`. This will allow your application
to be deployed under any directory without the need to change your url rules. Yii will automatically detect the base url of the application.
> Note: 带服务名称的规则**不应该**包含任何子目录。例如,如果程序入口脚本在 `http://www.example.com/sandbox/blog/index.php`
应该使用 `http://www.example.com/posts` 代替 `http://www.example.com/sandbox/blog/posts`
这样才可以将你的应用部署到任何目录而不需要更改 URL 规则。Yii 将会自动的检测应用程序所在的根目录。
### URL Suffixes <span id="url-suffixes"></span>
### URL 后缀 <span id="url-suffixes"></span>
You may want to add suffixes to the URLs for various purposes. For example, you may add `.html` to the URLs so that they
look like URLs for static HTML pages; you may also add `.json` to the URLs to indicate the expected content type
of the response. You can achieve this goal by configuring the [[yii\web\UrlManager::suffix]] property like
the following in the application configuration:
你可能因为各种目的需要在 URL 后面添加后缀。例如,你可以在URL后面添加 `.html` 让其看起来像是一个 HTML 页面;
也可以添加 `.json` 用来表明需要的返回值内容类型。
可以参考下面的系统配置,
通过设置 [[yii\web\UrlManager::suffix]] 属性来达到此目的:
```php
[
@ -492,18 +495,18 @@ the following in the application configuration:
]
```
The above configuration will allow the [[yii\web\UrlManager|URL manager]] to recognize requested URLs and also create
URLs with `.html` as their suffix.
上面的配置允许[[yii\web\UrlManager|URL管理器]]识别或生成带 `.html` 后缀的 URL。
> Tip: You may set `/` as the URL suffix so that the URLs all end with a slash.
> Tip: 你可以设置URL后缀为 `/` 让所有的 URL 以斜线结束。
> Note: When you configure a URL suffix, if a requested URL does not have the suffix, it will be considered as
an unrecognized URL. This is a recommended practice for SEO (search engine optimization).
> Note: 当你配置 URL 后缀时,如果请求的 URL 没有此后缀,系统将认为此 URL 无法识别。
这是 SEO(搜索引擎优化)的最佳实践。
有时你可能需要在不同的URL使用不同的后缀。可以通过在不同的URL规则下不同的设置[[yii\web\UrlRule::suffix|后缀]]属性。
URL规则中此属性将覆盖在[[yii\web\UrlManager|URL管理器]]中设置的值。
例如,下面的配置中全局使用 `.html` 后缀,但是定义了一个自定义的使用 `.json` 为后缀的规则。
Sometimes you may want to use different suffixes for different URLs. This can be achieved by configuring the
[[yii\web\UrlRule::suffix|suffix]] property of individual URL rules. When a URL rule has this property set, it will
override the suffix setting at the [[yii\web\UrlManager|URL manager]] level. For example, the following configuration
contains a customized URL rule which uses `.json` as its suffix instead of the global one `.html`.
```php
[
@ -525,13 +528,13 @@ contains a customized URL rule which uses `.json` as its suffix instead of the g
]
```
### HTTP Methods <span id="http-methods"></span>
### HTTP 方法 <span id="http-methods"></span>
When implementing RESTful APIs, it is commonly needed that the same URL be parsed into different routes according to
the HTTP methods being used. This can be easily achieved by prefixing the supported HTTP methods to the patterns of
the rules. If a rule supports multiple HTTP methods, separate the method names with commas. For example, the following
rules have the same pattern `post/<id:\d+>` with different HTTP method support. A request for `PUT post/100` will
be parsed into `post/update`, while a request for `GET post/100` will be parsed into `post/view`.
当使用 RESTful 接口时,经常需要根据 HTTP 请求方法将同样的URL解析到不同的路由。
可以容易的通过将支持的 HTTP 方法设置为 URL 规则的前缀来实现这个目的。
如果一个规则需要支持多种 HTTP 方法,可以将方法名称用逗号隔开。
例如,下面的规则有相同的模式 `post/<id:\d+>` 但是支持不同的 HTTP 方法。
一个 `PUT post/100` 请求将被解析到 `post/update`,`GET post/100` 请求将被解析到 `post/view`
```php
'rules' => [
@ -541,43 +544,43 @@ be parsed into `post/update`, while a request for `GET post/100` will be parsed
]
```
> Note: If a URL rule contains HTTP method(s) in its pattern, the rule will only be used for parsing purpose unless `GET` is among the specified verbs.
It will be skipped when the [[yii\web\UrlManager|URL manager]] is called to create URLs.
> Note: 如果一个 URL 规则包含 HTTP 方法,这个规则将只能用来解析请求,除非 `GET` 请求明确被指定在 HTTP 方法中,
否则创建 URL 时此规则将被[[yii\web\UrlManager|URL管理器]]忽略。
> Tip: To simplify the routing of RESTful APIs, Yii provides a special URL rule class [[yii\rest\UrlRule]]
which is very efficient and supports some fancy features such as automatic pluralization of controller IDs.
For more details, please refer to the [Routing](rest-routing.md) section in the RESTful APIs chapter.
> Tip: 为了简化 RESTful 接口的路由定义,Yii 提供了一个特殊的URL规则类 [[yii\rest\UrlRule]]
支持高效的且支持一些设想中的功能,像自动多元化控制器 ID。
更多信息,请参考 RESTful 接口说明中的[路由](rest-routing.md)章节。
### Adding Rules Dynamically <span id="adding-rules"></span>
### 动态添加规则 <span id="adding-rules"></span>
URL rules can be dynamically added to the [[yii\web\UrlManager|URL manager]]. This is often needed by redistributable
[modules](structure-modules.md) which want to manage their own URL rules. In order for the dynamically added rules
to take effect during the routing process, you should add them during the [bootstrapping](runtime-bootstrapping.md)
stage of the application. For modules, this means they should implement [[yii\base\BootstrapInterface]] and add the rules in the
[[yii\base\BootstrapInterface::bootstrap()|bootstrap()]] method like the following:
URL规则可以动态添加到[[yii\web\UrlManager|URL管理器]]。如果[模块](structure-modules.md)需要管理自己的URL规则时很有必要。
如果需要使路由处理过程中动态添加的规则可用,
你应该在应用程序[启动引导](runtime-bootstrapping.md)时添加。
对模块来说,需要实现 [[yii\base\BootstrapInterface]] 接口的 [[yii\base\BootstrapInterface::bootstrap()|bootstrap()]] 方法,
类似下面这样动态添加规则:
```php
public function bootstrap($app)
{
$app->getUrlManager()->addRules([
// rule declarations here
// 规则在这里定义
], false);
}
```
Note that you should also list these modules in [[yii\web\Application::bootstrap]] so that they can participate the
[bootstrapping](runtime-bootstrapping.md) process.
注意你需要同时在 [[yii\web\Application::bootstrap]] 中指定这些模块,这样模块才可以参与到
[启动引导](runtime-bootstrapping.md)过程中。
### Creating Rule Classes <span id="creating-rules"></span>
### 创建规则类 <span id="creating-rules"></span>
Despite the fact that the default [[yii\web\UrlRule]] class is flexible enough for the majority of projects, there
are situations when you have to create your own rule classes. For example, in a car dealer Web site, you may want
to support the URL format like `/Manufacturer/Model`, where both `Manufacturer` and `Model` must match some data
stored in a database table. The default rule class will not work here because it relies on statically declared patterns.
尽管默认的 [[yii\web\UrlRule]] 类已经足够灵活可以处理大部分项目了,
有时还是会需要创建一个自定义的规则类。例如,在一个汽车经销网站,你可能会需要使用
这样的URL格式 `/Manufacturer/Model`,`Manufacturer` 和 `Model` 必须同时匹配保存在数据库中的一些数据。
默认的规则类只能使用静态定义而无法适应此种情况。
We can create the following URL rule class to solve this problem.
我们可以创建一个自定义的 URL 规则类来解决这个问题。
```php
<?php
@ -605,41 +608,41 @@ class CarUrlRule extends BaseObject implements UrlRuleInterface
{
$pathInfo = $request->getPathInfo();
if (preg_match('%^(\w+)(/(\w+))?$%', $pathInfo, $matches)) {
// check $matches[1] and $matches[3] to see
// if they match a manufacturer and a model in the database.
// If so, set $params['manufacturer'] and/or $params['model']
// and return ['car/index', $params]
// 检查 $matches[1] 和 $matches[3]
// 确认是否匹配到一个数据库中保存的厂家和型号。
// 如果匹配,设置参数 $params['manufacturer'] 和 / 或 $params['model']
// 返回 ['car/index', $params]
}
return false; // this rule does not apply
return false; // 本规则不会起作用
}
}
```
And use the new rule class in the [[yii\web\UrlManager::rules]] configuration:
在 [[yii\web\UrlManager::rules]] 配置中设置新定义的规则类:
```php
'rules' => [
// ...other rules...
// ...其它规则...
[
'class' => 'app\components\CarUrlRule',
// ...configure other properties...
// ...配置其它参数...
],
]
```
## URL normalization <span id="url-normalization"></span>
## URL规范化 <span id="url-normalization"></span>
从 2.0.10 版开始[[yii\web\UrlManager|Url管理器]]可以配置用[[yii\web\UrlNormalizer|URL规范器]]来处理
相同URL的不同格式,例如是否带结束斜线。因为技术上来说 `http://example.com/path`
`http://example.com/path/` 是完全不同的 URL,两个地址返回相同的内容会导致SEO排名降低。
默认情况下 URL 规范器会合并连续的斜线,根据配置决定是否添加或删除结尾斜线,
并且会使用[永久重定向](https://en.wikipedia.org/wiki/HTTP_301)将地址重新跳转到规范化后的URL。
URL规范器可以针对URL管理器全局配置,也可以针对规则单独配置 - 默认每个规则都使用URL管理器中的规范器。
你可以针对特定的URL规则设置 [[yii\web\UrlRule::$normalizer|UrlRule::$normalizer]] 为 `false` 来关闭规范化。
Since version 2.0.10 [[yii\web\UrlManager|UrlManager]] can be configured to use [[yii\web\UrlNormalizer|UrlNormalizer]] for dealing
with variations of the same URL, for example with and without a trailing slash. Because technically `http://example.com/path`
and `http://example.com/path/` are different URLs, serving the same content for both of them can degrade SEO ranking.
By default normalizer collapses consecutive slashes, adds or removes trailing slashes depending on whether the
suffix has a trailing slash or not, and redirects to the normalized version of the URL using [permanent redirection](https://en.wikipedia.org/wiki/HTTP_301).
The normalizer can be configured globally for the URL manager or individually for each rule - by default each rule will use the normalizer
from URL manager. You can set [[yii\web\UrlRule::$normalizer|UrlRule::$normalizer]] to `false` to disable normalization
for particular URL rule.
The following shows an example configuration for the [[yii\web\UrlNormalizer|UrlNormalizer]]:
下面的例子显示了一个[[yii\web\UrlNormalizer|URL规范器]]的配置:
```php
'urlManager' => [
@ -649,22 +652,22 @@ The following shows an example configuration for the [[yii\web\UrlNormalizer|Url
'suffix' => '.html',
'normalizer' => [
'class' => 'yii\web\UrlNormalizer',
// use temporary redirection instead of permanent for debugging
// 调试时使用临时跳转代替永久跳转
'action' => UrlNormalizer::ACTION_REDIRECT_TEMPORARY,
],
'rules' => [
// ...other rules...
// ...其它规则...
[
'pattern' => 'posts',
'route' => 'post/index',
'suffix' => '/',
'normalizer' => false, // disable normalizer for this rule
'normalizer' => false, // 针对此规则关闭规范器
],
[
'pattern' => 'tags',
'route' => 'tag/index',
'normalizer' => [
// do not collapse consecutive slashes for this rule
// 针对此规则不合并连续的斜线
'collapseSlashes' => false,
],
],
@ -672,8 +675,8 @@ The following shows an example configuration for the [[yii\web\UrlNormalizer|Url
]
```
> Note: by default [[yii\web\UrlManager::$normalizer|UrlManager::$normalizer]] is disabled. You need to explicitly
configure it in order to enable URL normalization.
> Note: 默认 [[yii\web\UrlManager::$normalizer|UrlManager::$normalizer]] 规范器是关闭的。你需要明确配置其开启
来启用 URL 规范化。
@ -687,7 +690,7 @@ The following shows an example configuration for the [[yii\web\UrlNormalizer|Url
当解析或创建URL时,[[yii\web\UrlManager|URL manager]] 按照它们声明的顺序检查 URL 规则。
因此,您可以考虑调整 URL 规则的顺序,以便在较少使用的规则之前放置更具体和/或更常用的规则。
If some URL rules share the same prefix in their patterns or routes, you may consider using [[yii\web\GroupUrlRule]]
so that they can be more efficiently examined by [[yii\web\UrlManager|URL manager]] as a group. This is often the case
when your application is composed by modules, each having its own set of URL rules with module ID as their common prefixes.
如果多个 URL 规则使用相同的前缀,你可以考虑使用 [[yii\web\GroupUrlRule]],
这样作为一个组合,[[yii\web\UrlManager|URL管理器]]会更高效。
特别是当应用程序由模块组合而成时,每个模块都有各自的 URL 规则且都有各自的模块 ID 作为前缀。

201
docs/guide-zh-CN/security-authorization.md

@ -100,6 +100,9 @@ ACF 自顶向下逐一检查存取规则,直到找到一个与当前
使用其他角色名时,将触发调用 [[yii\web\User::can()]],这时要求 RBAC 的支持 (在下一节中阐述)。
如果该选项为空或者不使用该选项,意味着该规则适用于所有角色。
* [[yii\filters\AccessRule::roleParams|roleParams]]:指定将传递给 [[yii\web\User::can()]] 的参数。
请参阅下面描述RBAC规则的部分,了解如何使用它。 如果此选项为空或未设置,则不传递任何参数。
* [[yii\filters\AccessRule::ips|ips]]:指定该规则用于匹配哪些 [[yii\web\Request::userIP|客户端IP地址]] 。
IP 地址可在其末尾包含通配符 `*` 以匹配一批前缀相同的IP地址。
例如,`192.168.*` 匹配所有 `192.168.` 段的IP地址。
@ -222,14 +225,16 @@ return [
'components' => [
'authManager' => [
'class' => 'yii\rbac\DbManager',
// uncomment if you want to cache RBAC items hierarchy
// 'cache' => 'cache',
],
// ...
],
];
```
> Note: If you are using yii2-basic-app template, there is a `config/console.php` configuration file where the
`authManager` needs to be declared additionally to `config/web.php`.
> In case of yii2-advanced-app the `authManager` should be declared only once in `common/config/main.php`.
> Note: 如果您使用的是 yii2-basic-app 模板,则有一个 `config/console.php` 配置文件,其中
 `authManager` 需要另外声明在 `config/web.php`
> 在 yii2-advanced-app 的情况下,`authManager` 只能在 `common/config/main.php` 中声明一次。
`DbManager` 使用4个数据库表存放它的数据:
@ -242,6 +247,9 @@ return [
`yii migrate --migrationPath=@yii/rbac/migrations`
阅读 [Separated Migrations](db-migrations.md#separated-migrations)
部分中有关处理来自不同名称空间的迁移的更多信息。
现在可以通过 `\Yii::$app->authManager` 访问 `authManager`
@ -255,10 +263,83 @@ return [
- 将规则与角色和权限作关联;
- 指派角色给用户。
根据授权的弹性需求,上述任务可用不同的方法完成。
根据授权灵活性要求,上述任务可以通过不同的方式完成。
如果您的权限层次结构仅由开发人员更改,则可以使用迁移或控制台命令。
Migration pro 是可以与其他迁移一起执行的。
控制台命令 pro 是您可以很好地了解代码中的层次结构,
而不是分散在多个迁移中。
无论哪种方式,最终都会得到以下 RBAC 层次结构:
![Simple RBAC hierarchy](images/rbac-hierarchy-1.png "简单的 RBAC 层次结构示意图")
如果您需要动态形成权限层次结构,则需要 UI 或控制台命令。 用于构建层次结构的
API 本身不会有所不同。
#### 使用迁移(Using migrations)
您可以使用 [migrations](db-migrations.md)
通过 `authManager` 提供的 API 初始化和修改层次结构。
使用 `./yii migrate/create init_rbac` 创建新迁移,然后实现创建层次结构:
```php
<?php
use yii\db\Migration;
class m170124_084304_init_rbac extends Migration
{
public function up()
{
$auth = Yii::$app->authManager;
// 添加 "createPost" 权限
$createPost = $auth->createPermission('createPost');
$createPost->description = 'Create a post';
$auth->add($createPost);
// 添加 "updatePost" 权限
$updatePost = $auth->createPermission('updatePost');
$updatePost->description = 'Update post';
$auth->add($updatePost);
// 添加 "author" 角色并赋予 "createPost" 权限
$author = $auth->createRole('author');
$auth->add($author);
$auth->addChild($author, $createPost);
// 添加 "admin" 角色并赋予 "updatePost"
// 和 "author" 权限
$admin = $auth->createRole('admin');
$auth->add($admin);
$auth->addChild($admin, $updatePost);
$auth->addChild($admin, $author);
// 为用户指派角色。其中 1 和 2 是由 IdentityInterface::getId() 返回的id
// 通常在你的 User 模型中实现这个函数。
$auth->assign($author, 2);
$auth->assign($admin, 1);
}
public function down()
{
$auth = Yii::$app->authManager;
$auth->removeAll();
}
}
```
> 如果您不想硬编码哪些用户具有某些角色,请不要在迁移中使用 `->assign()` 调用。
相反,请创建UI或控制台命令来管理分配。
如果你的权限层次结构不会发生改变,而且你的用户数是恒定的,你可以通过 `authManager`
提供的 API 创建一个 [控制台命令](tutorial-console.md#create-command) 一次性初始化授权数据:
迁移可以通过 `yii migrate` 使用。
### 使用控制台命令(Using console command)
如果您的权限层次根本没有改变,并且您拥有固定数量的用户,
则可以创建一个[控制台命令](tutorial-console.md#create-command),它将通过
`authManager` 提供的 API 初始化授权数据一次:
```php
<?php
@ -272,6 +353,7 @@ class RbacController extends Controller
public function actionInit()
{
$auth = Yii::$app->authManager;
$auth->removeAll();
// 添加 "createPost" 权限
$createPost = $auth->createPermission('createPost');
@ -295,7 +377,7 @@ class RbacController extends Controller
$auth->addChild($admin, $updatePost);
$auth->addChild($admin, $author);
// 为用户指派角色。其中 1 和 2 是由 IdentityInterface::getId() 返回的id (译者注:user表的id)
// 为用户指派角色。其中 1 和 2 是由 IdentityInterface::getId() 返回的id
// 通常在你的 User 模型中实现这个函数。
$auth->assign($author, 2);
$auth->assign($admin, 1);
@ -303,18 +385,25 @@ class RbacController extends Controller
}
```
> Note: If you are using advanced template, you need to put your `RbacController` inside `console/controllers` directory
and change namespace to `console/controllers`.
> Note: 如果您使用高级模板,则需要将 `RbacController` 放在 `console/controllers` 目录中,
并将命名空间更改为 `console/controllers`
在用 `yii rbac/init` 执行了这个命令后,我们将得到下图所示的层次结构
上面的命令可以通过以下方式从控制台执行
![Simple RBAC hierarchy](images/rbac-hierarchy-1.png "简单的 RBAC 层次结构示意图")
```
yii rbac/init
```
> 如果您不想硬编码用户具有某些角色,请不要将 `->assign()` 调用放入命令中。
相反,请创建UI或控制台命令来管理分配。
## 为用户分配角色(Assigning roles to users)
作者可创建新贴,管理员可编辑帖子以及所有作者可做的事情。
作者可以创建帖子,管理员可以更新帖子并可以做一切作者都能做的
如果你的应用允许用户注册,你需要在注册时给新用户指派一次角色。例如,
在高级项目模板中,要让所有注册用户成为作者,你需要如下例所示修改
`frontend\models\SignupForm::signup()` 方法:
如果您的应用程序允许用户注册,则需要为这些新用户分配一次角色。
例如,为了让所有注册用户成为高级项目模板中的作者,您需要修改 `frontend\models\SignupForm::signup()`
如下所示
```php
public function signup()
@ -327,8 +416,8 @@ public function signup()
$user->generateAuthKey();
$user->save(false);
// 要添加以下三行代码
$auth = Yii::$app->authManager;
// 增加了以下三行
$auth = \Yii::$app->authManager;
$authorRole = $auth->getRole('author');
$auth->assign($authorRole, $user->getId());
@ -339,8 +428,8 @@ public function signup()
}
```
对于有动态更改授权数据的复杂存取控制需求的,你可能需要使用 `authManager`
提供的 API 的开发用户界面(例如:管理面板)。
对于需要动态更新授权数据的复杂访问控制的应用程序,可能需要使用
`authManager` 提供的 API 来开发特殊的用户界面(即管理面板)。
### 使用规则 (Rules) <span id="using-rules"></span>
@ -353,6 +442,7 @@ public function signup()
namespace app\rbac;
use yii\rbac\Rule;
use app\models\Post;
/**
* 检查 authorID 是否和通过参数传进来的 user 参数相符
@ -439,6 +529,79 @@ if (\Yii::$app->user->can('updatePost', ['post' => $post])) {
![Access check](images/rbac-access-check-3.png "Access check")
在您的控制器内部有几种实现授权的方式。
如果您希望细化权限来分开添加和删除的访问权限,那么您需要检查每个操作的访问权限。
您可以在每个操作方法中使用上述条件,或使用 [[yii\filters\AccessControl]]:
```php
public function behaviors()
{
return [
'access' => [
'class' => AccessControl::className(),
'rules' => [
[
'allow' => true,
'actions' => ['index'],
'roles' => ['managePost'],
],
[
'allow' => true,
'actions' => ['view'],
'roles' => ['viewPost'],
],
[
'allow' => true,
'actions' => ['create'],
'roles' => ['createPost'],
],
[
'allow' => true,
'actions' => ['update'],
'roles' => ['updatePost'],
],
[
'allow' => true,
'actions' => ['delete'],
'roles' => ['deletePost'],
],
],
],
];
}
```
如果所有的CRUD操作都是一起管理的,那么使用 `managePost` 这样的单一权限并且在
[[yii\web\Controller::beforeAction()]] 中检查它是个好主意。
在上面的例子中,没有参数与指定的访问动作的角色一起传递,但是在
`updatePost` 权限的情况下,我们需要传递 `post` 参数才能正常工作。
您可以通过在访问规则中指定 [[yii\filters\AccessRule::roleParams|roleParams]] 将参数传递给
[[yii\web\User::can()]]:
```php
[
'allow' => true,
'actions' => ['update'],
'roles' => ['updatePost'],
'roleParams' => function() {
return ['post' => Post::findOne(['id' => Yii::$app->request->get('id')])];
},
],
```
在上面的例子中,[[yii\filters\AccessRule::roleParams|roleParams]] 是一个 Closure,
将在检查访问规则时进行评估,因此模型只会在需要时加载。
如果创建角色参数是一个简单的操作,那么您可以指定一个数组,如下所示:
```php
[
'allow' => true,
'actions' => ['update'],
'roles' => ['updatePost'],
'roleParams' => ['postId' => Yii::$app->request->get('id')];
],
```
### 使用默认角色 <span id="using-default-roles"></span>

54
docs/guide-zh-CN/security-cryptography.md

@ -1,66 +1,66 @@
Cryptography
============
加密(Cryptography
==================
In this section we'll review the following security aspects:
在本节中,我们将回顾以下安全问题:
- Generating random data
- Encryption and Decryption
- Confirming Data Integrity
- 生成随机数据
- 加密和解密
- 确认数据完整性
Generating Pseudorandom Data
生成伪随机数据(Generating Pseudorandom Data
----------------------------
Pseudorandom data is useful in many situations. For example when resetting a password via email you need to generate a
token, save it to the database, and send it via email to end user which in turn will allow them to prove ownership of
that account. It is very important that this token be unique and hard to guess, else there is a possibility that attacker
can predict the token's value and reset the user's password.
伪随机数据在很多情况下都很有用。 例如,当通过电子邮件重置密码时,
您需要生成一个令牌,将其保存到数据库中,并通过电子邮件发送给最终用户,
这反过来又会允许他们证明该帐户的所有权。
这个令牌是独一无二且难以猜测的,否则攻击者可能会预测令牌的值并重置用户的密码。
Yii security helper makes generating pseudorandom data simple:
Yii 安全助手类简单生成伪随机数据:
```php
$key = Yii::$app->getSecurity()->generateRandomString();
```
Encryption and Decryption
加密和解密(Encryption and Decryption
-------------------------
Yii provides convenient helper functions that allow you to encrypt/decrypt data using a secret key. The data is passed through the encryption function so that only the person which has the secret key will be able to decrypt it.
For example, we need to store some information in our database but we need to make sure only the user who has the secret key can view it (even if the application database is compromised):
Yii 提供了便利的帮助功能,使您可以使用密钥 加密/解密 数据。 数据通过加密功能传递,以便只有拥有密钥的人才能解密。
例如,我们需要在数据库中存储一些信息,但我们需要确保只有拥有密钥的用户才能查看它(即使应用程序数据库已被泄露):
```php
// $data and $secretKey are obtained from the form
// $data 和 $secretKey 从表单中获得
$encryptedData = Yii::$app->getSecurity()->encryptByPassword($data, $secretKey);
// store $encryptedData to database
// 将 $encryptedData 存储到数据库
```
Subsequently when user wants to read the data:
随后当用户想要读取数据时:
```php
// $secretKey is obtained from user input, $encryptedData is from the database
// $secretKey 从用户输入获得,$encryptedData 来自数据库
$data = Yii::$app->getSecurity()->decryptByPassword($encryptedData, $secretKey);
```
It's also possible to use key instead of password via [[\yii\base\Security::encryptByKey()]] and
[[\yii\base\Security::decryptByKey()]].
也可以通过 [[\yii\base\Security::encryptByKey()]] 和
[[\yii\base\Security::decryptByKey()]] 使用密钥而不是密码。
Confirming Data Integrity
确认数据完整性(Confirming Data Integrity
-------------------------
There are situations in which you need to verify that your data hasn't been tampered with by a third party or even corrupted in some way. Yii provides an easy way to confirm data integrity in the form of two helper functions.
在某些情况下,您需要验证您的数据未被第三方篡改甚至以某种方式损坏。 Yii 提供了一种简单的方法用两个帮助功能的类确认数据完整性的。
Prefix the data with a hash generated from the secret key and data
用密钥和数据生成的哈希前缀数据
```php
// $secretKey our application or user secret, $genuineData obtained from a reliable source
// $secretKey 是我们的应用程序或用户密钥,$genuineData 是从可靠来源获得的
$data = Yii::$app->getSecurity()->hashData($genuineData, $secretKey);
```
Checks if the data integrity has been compromised
检查数据完整性是否受到损害
```php
// $secretKey our application or user secret, $data obtained from an unreliable source
// $secretKey 我们的应用程序或用户密钥,$data 从不可靠的来源获得
$data = Yii::$app->getSecurity()->validateData($data, $secretKey);
```

25
docs/guide-zh-CN/security-overview.md

@ -1,14 +1,15 @@
Security
========
安全(Security
==============
Good security is vital to the health and success of any application. Unfortunately, many developers cut corners when it
comes to security, either due to a lack of understanding or because implementation is too much of a hurdle. To make your
Yii powered application as secure as possible, Yii has included several excellent and easy to use security features.
良好的安全性对于任何应用的健康和成功都至关重要。
不幸的是,许多开发人员在安全方面偷工减料,要么是由于缺乏理解,要么是由于实现过于困难。
为了尽可能保证您的 Yii 应用程序的安全,Yii 包含了一些优秀且易于使用的安全功能。
* [Authentication](security-authentication.md)
* [Authorization](security-authorization.md)
* [Working with Passwords](security-passwords.md)
* [Cryptography](security-cryptography.md)
* [Views security](structure-views.md#security)
* [Auth Clients](https://github.com/yiisoft/yii2-authclient/blob/master/docs/guide/README.md)
* [Best Practices](security-best-practices.md)
* [认证](security-authentication.md)
* [授权](security-authorization.md)
* [使用密码](security-passwords.md)
* [加密](security-cryptography.md)
* [视图安全](structure-views.md#security)
* [身份验证客户端](https://github.com/yiisoft/yii2-authclient/blob/master/docs/guide/README.md)
* [最佳实践](security-best-practices.md)
* [受信任的代理和头文件](runtime-requests.md#trusted-proxies)

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

@ -1,5 +1,5 @@
更上一层楼
=============
更上一层楼(Looking Ahead)
========================
通篇阅读完整个“入门”部分,你就完成了一个完整 Yii 应用的创建。在此过程中你学到了如何实现一些常用功能,
例如通过 HTML 表单从用户那获取数据,从数据库中获取数据并以分页形式显示。
@ -22,14 +22,15 @@
但它们往往覆盖了更广泛的话题,并常常提供解决方案,
所以它们也很有用。
- 书籍
* [扩展](http://www.yiiframework.com/extensions/):Yii 拥有数以千计用户提供的扩展,这些扩展能非常方便的插入到应用中,
* [扩展](http://www.yiiframework.com/extensions/)Yii 拥有数以千计用户提供的扩展,这些扩展能非常方便的插入到应用中,
使你的应用开发过程更加方便快捷。
* 社区
- 官方论坛:<http://www.yiiframework.com/forum/>
- IRC 聊天室:Freenode 网络上的 #yii 频道 (<irc://irc.freenode.net/yii>)
- Gitter chat: <https://gitter.im/yiisoft/yii2>
- Slack chanel:<https://yii.slack.com>
- Gitter chat:<https://gitter.im/yiisoft/yii2>
- GitHub:<https://github.com/yiisoft/yii2>
- Facebook:<https://www.facebook.com/groups/yiitalk/>
- Twitter:<https://twitter.com/yiiframework>
- LinkedIn:<https://www.linkedin.com/groups/yii-framework-1483367>
- Stackoverflow: <http://stackoverflow.com/questions/tagged/yii2>
- Stackoverflow<http://stackoverflow.com/questions/tagged/yii2>

7
docs/guide-zh-CN/start-prerequisites.md

@ -1,12 +1,13 @@
# 你需要了解什么
# 你需要了解什么(What do you need to know)
Yii 的学习曲线并不像其他 PHP 框架那样陡峭,但仍然需要一些基础知识。
## PHP
Yii 是一个 PHP 框架,因此请确保您 [阅读并理解语言参考](http://php.net/manual/zh/langref.php)。
用 Yii 进行开发时,您将以面向对象的方式编写代码,因此请确保您熟悉[类与对象](https://secure.php.net/manual/en/language.oop5.basic.php)以及[命名空间](https://secure.php.net/manual/en/language.namespaces.php)。
## 面向对象编程
## 面向对象编程(Object oriented programming)
对面向对象编程的基本理解是必需的。如果您不熟悉它,请选中其中一个
可用的教程,如 [tuts+](https://code.tutsplus.com/tutorials/object-oriented-php-for-beginners--net-12762)。
@ -14,7 +15,7 @@ Yii 是一个 PHP 框架,因此请确保您 [阅读并理解语言参考](http
请注意,您的应用程序越复杂,您需要学习的更高级的 OOP 概念才能成功
掌握这种复杂度。
## 命令行和 Composer
## 命令行和 Composer(Command line and composer)
Yii 广泛使用了标准的 PHP 包管理器 [Composer](https://getcomposer.org/),因此请确保您阅读
并理解其指南。如果您不熟悉命令行,现在该开始尝试了。

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

@ -173,10 +173,10 @@ public $cssOptions = ['noscript' => true];
public $jsOptions = ['position' => \yii\web\View::POS_HEAD];
```
By default, when an asset bundle is being published, all contents in the directory specified by [[yii\web\AssetBundle::sourcePath]]
will be published. You can customize this behavior by configuring the [[yii\web\AssetBundle::publishOptions|publishOptions]]
property. For example, to publish only one or a few subdirectories of [[yii\web\AssetBundle::sourcePath]],
you can do the following in the asset bundle class:
默认情况下,当发布资源包时,所有在 [[yii\web\AssetBundle::sourcePath]] 目录里的内容都会发布。
你可以通过配置 [[yii\web\AssetBundle::publishOptions|publishOptions]] 属性来自定义这种行为。
比如,为了只发布[[yii\web\AssetBundle::sourcePath]]其中的某些内容或子目录里的内容,
可以在资源类中试试下面的做法:
```php
<?php
@ -199,8 +199,8 @@ class FontAwesomeAsset extends AssetBundle
}
```
The above example defines an asset bundle for the ["fontawesome" package](http://fontawesome.io/). By specifying
the `only` publishing option, only the `fonts` and `css` subdirectories will be published.
上述的代码为 ["fontawesome" package](http://fontawesome.io/) 定义了资源包。
通过配置发布选项的 only 下标,只有 `fonts``css` 子目录会发布。
### Bower 和 NPM 资源 <span id="bower-npm-assets"></span>
@ -231,8 +231,7 @@ use app\assets\AppAsset;
AppAsset::register($this); // $this 代表视图对象
```
> Info: The [[yii\web\AssetBundle::register()]] method returns an asset bundle object containing the information
about the published assets, such as [[yii\web\AssetBundle::basePath|basePath]] or [[yii\web\AssetBundle::baseUrl|baseUrl]].
> Info: [[yii\web\AssetBundle::register()]] 方法返回资源包对象,该对象包含了发布资源的信息比如 [[yii\web\AssetBundle::basePath|basePath]] 或 [[yii\web\AssetBundle::baseUrl|baseUrl]]。
如果在其他地方注册资源包,应提供视图对象,如在 [小部件](structure-widgets.md) 类中注册资源包,
可以通过 `$this->view` 获取视图对象。
@ -367,12 +366,12 @@ return [
这比拷贝文件方式快并能确保发布的资源一直为最新的。
### Cache Busting <span id="cache-busting"></span>
### 打破缓存 <span id="cache-busting"></span>
For Web application running in production mode, it is a common practice to enable HTTP caching for assets and other
static resources. A drawback of this practice is that whenever you modify an asset and deploy it to production, a user
client may still use the old version due to the HTTP caching. To overcome this drawback, you may use the cache busting
feature, which was introduced in version 2.0.3, by configuring [[yii\web\AssetManager]] like the following:
对于运行在生产模式的 Web 应用来说,通常的做法是为资源包和其他静态资源开启 http 缓存。
但这种做法有个不好的地方就是,当你更新某个资源并部署到生产环境时,
用户的客户端可能由于 http 缓存而仍然使用旧版本的资源。
为了克服该不足,你可以试试打破缓存特性,它由2.0.3版本引入,只需如下配置 [[yii\web\AssetManager]] 即可:
```php
return [
@ -385,10 +384,10 @@ return [
];
```
By doing so, the URL of every published asset will be appended with its last modification timestamp. For example,
the URL to `yii.js` may look like `/assets/5515a87c/yii.js?v=1423448645"`, where the parameter `v` represents the
last modification timestamp of the `yii.js` file. Now if you modify an asset, its URL will be changed, too, which causes
the client to fetch the latest version of the asset.
通过上述配置后,每个发布资源的 url 都会添加一个最后更新时间戳信息。
比如,`yii.js` 的 url 可能是 `/assets/5515a87c/yii.js?v=1423448645"`这样的,
这里的参数 v 表示 `yii.js` 文件的最后更新时间戳。
现在一旦你更新了某个资源,它的 URL 也会改变进而强制客户端获取该资源的最新版本。
## 常用资源包 <span id="common-asset-bundles"></span>
@ -678,7 +677,7 @@ return [
'js' => 'js/all-shared-{hash}.js',
'css' => 'css/all-shared-{hash}.css',
'depends' => [
// Include all assets shared between 'backend' and 'frontend'
// 包含由'backend' 和 'frontend' 共享的资源包
'yii\web\YiiAsset',
'app\assets\SharedAsset',
],
@ -687,14 +686,14 @@ return [
'js' => 'js/all-{hash}.js',
'css' => 'css/all-{hash}.css',
'depends' => [
// Include only 'backend' assets:
// 只包含 'backend' 资源:
'app\assets\AdminAsset'
],
],
'allFrontEnd' => [
'js' => 'js/all-{hash}.js',
'css' => 'css/all-{hash}.css',
'depends' => [], // Include all remaining assets
'depends' => [], // 包含所有的剩余资源
],
],
...
@ -702,10 +701,8 @@ return [
```
如上所示,资源包分成了三个组:`allShared`,`allBackEnd` 和 `allFrontEnd`
它们每个都依赖各自的资源包集合。 比如, `allBackEnd` 依赖 `app\assets\AdminAsset`
当对该配置运行 `asset` 命令时,将会根据各自依赖合并资源包。
As you can see, the asset bundles are divided into three groups: `allShared`, `allBackEnd` and `allFrontEnd`.
They each depends on an appropriate set of asset bundles. For example, `allBackEnd` depends on `app\assets\AdminAsset`.
When running `asset` command with this configuration, it will combine asset bundles according to the above specification.
> Info: You may leave the `depends` configuration empty for one of the target bundle. By doing so, that particular
asset bundle will depend on all of the remaining asset bundles that other target bundles do not depend on.
> Info: 你也可以把某个分组的 `depends` 配置留空。 这样做得话,
这个分组将会依赖剩余的资源包,剩余资源包是指不被其他分组依赖的那些资源包。

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

@ -80,7 +80,7 @@ use yii\helpers\HtmlPurifier;
</div>
```
> 技巧:HTMLPurifier在保证输出数据安全上做的不错,但性能不佳,如果你的应用需要高性能可考虑
> Tip: HTMLPurifier在保证输出数据安全上做的不错,但性能不佳,如果你的应用需要高性能可考虑
[缓存](caching-overview.md) 过滤后的结果。

200
docs/guide-zh-CN/tutorial-i18n.md

@ -1,5 +1,5 @@
国际化
=======
国际化(Internationalization)
===========================
国际化(I18N)是指在设计软件时,使它可以无需做大的改变就能够适应不同的语言和地区的需要。对于 Web 应用程序,
这有着特别重要的意义,因为潜在的用户可能会在全球范围内。
@ -7,11 +7,16 @@ Yii 提供的国际化功能支持全方位信息翻译,
视图翻译,日期和数字格式化。
## 区域和语言 <span id="locale-language"></span>
## 区域和语言(Locale and Language) <span id="locale-language"></span>
区域设置是一组参数以定义用户希望能在他们的用户界面所看到用户的语言,国家和任何特殊的偏好。
### 区域(Locale)
区域设置是一组参数以定义用户希望能在他们的用户界面所看到用户的语言,
国家和任何特殊的偏好。
它通常是由语言 ID 和区域 ID 组成。
例如,ID “en-US” 代表英语和美国的语言环境。为了保持一致性,
在 Yii 应用程序中使用的所有区域 ID 应该规范化为 `ll-CC`
其中 `ll` 是根据两个或三个字母的小写字母语言代码
[ISO-639](http://www.loc.gov/standards/iso639-2/) 和 `CC` 是两个字母的国别代码
@ -19,13 +24,17 @@ Yii 提供的国际化功能支持全方位信息翻译,
有关区域设置的更多细节可以看
[ICU 项目文档](http://userguide.icu-project.org/locale#TOC-The-Locale-Concept)。
### 语言(Language)
在 Yii中,我们经常用 “language” 来代表一个区域。
一个 Yii 应用使用两种语言:[[yii\base\Application::$sourceLanguage|源语言]] 和
[[yii\base\Application::$language|目标语言]] 。
前者指的是写在代码中的语言,后者是向最终用户显示内容的语言。
而信息翻译服务主要是将文本消息从原语言翻译到目标语言。
Yii 应用程序使用两种语言:
* [[yii\base\Application::$sourceLanguage|源语言]]:前者指的是写在代码中的语言,后者是向最终用户显示内容的语言。
* [[yii\base\Application::$language|目标语言]]:而信息翻译服务主要是将文本消息从原语言翻译到目标语言。
所谓的消息翻译服务主要将文本消息从源语言转换为目标语言。
### 配置(Configuration)
可以用类似下面的应用程序配置来配置应用程序语言:
```php
@ -53,20 +62,27 @@ return [
\Yii::$app->language = 'zh-CN';
```
## 消息翻译 <span id="message-translation"></span>
> Tip: 如果您的源语言在代码的不同部分中有所不同,那么您可以覆盖不同消息源的源语言,
> 这将在下一节中介绍。
## 消息翻译(Message Translation) <span id="message-translation"></span>
### 从源语言到目标语言(From source language to target language)
消息翻译服务用于将一条文本信息从一种语言(通常是 [[yii\base\Application::$sourceLanguage|源语言]] )
翻译成另一种语言(通常是 [[yii\base\Application::$language|目标语言]])。
它的翻译原理是通过在语言文件中查找要翻译的信息以及翻译的结果。
如果要翻译的信息可以在语言文件中找到,会返回相应的翻译结果;
它的翻译原理是通过在语言文件中查找要翻译的信息以及翻译的结果。如果要翻译的信息可以在语言文件中找到,会返回相应的翻译结果;
否则会返回原始未翻译的信息。
### 如何实现(How to implement)
为了使用消息翻译服务,需要做如下工作:
* 调用 [[Yii::t()]] 方法且在其中包含每一条要翻译的消息;
* 配置一个或多个消息来源,能在其中找得到要翻译的消息和翻译结果;
* 让译者翻译信息并将它们存储在消息来源。
1. 调用 [[Yii::t()]] 方法且在其中包含每一条要翻译的消息;
2. 配置一个或多个消息来源,能在其中找得到要翻译的消息和翻译结果;
3. 让译者翻译信息并将它们存储在消息来源。
#### 1. 包裹一条消息(Wrap a text message)
这个 [[Yii::t()]] 方法的用法如下,
```php
@ -76,6 +92,7 @@ echo \Yii::t('app', 'This is a string to translate!');
第一个参数指储存消息来源的类别名称,
第二个参数指需要被翻译的消息。
#### 2. 配置一个或多个消息源(Configure one or multiple message sources)
这个 [[Yii::t()]] 方法会调用 `i18n` [应用组件](structure-application-components.md)
来实现翻译工作。这个组件可以在应用程序中按下面的代码来配置,
@ -98,15 +115,47 @@ echo \Yii::t('app', 'This is a string to translate!');
],
```
在上面的代码中,正在配置 [[yii\i18n\PhpMessageSource]] 支持的消息源。
##### 带 `*` 符号的类别通配符(Category wildcards with `*` symbol)
在上面的代码中,配置了由 [[yii\i18n\PhpMessageSource]] 所支持的消息来源。模式 `app*` 表示所有以 `app`
开头的消息类别名称都使用这个翻译的消息来源。
该 [[yii\i18n\PhpMessageSource]] 类使用 PHP 文件来存储消息翻译。
每 PHP 文件对应单一类别的消息。默认情况下,
文件名应该与类别名称相同。但是,你可以配置
[[yii\i18n\PhpMessageSource::fileMap|fileMap]] 来映射一个类别到不同名称的 PHP 文件。在上面的例子中,
类别 `app/error` 被映射到PHP文件 `@app/messages/ru-RU/error.php`(假设 `ru-RU` 为目标语言)。如果没有此配置,
#### 3. 让译员翻译消息并将它们存储在消息源中(Let the translators translate messages and store them in the message source(s))
[[yii\i18n\PhpMessageSource]] 类使用PHP文件和一个简单的 PHP 数组来存储消息转换。
这些文件包含 `源语言` 中的消息到 `目标语言` 中的翻译的映射。
> Info: 您可以使用 [`message` 命令](#message-command) 自动生成这些 PHP 文件,
> 这将在本章后面介绍。
每个PHP文件对应于单个类别的消息。 默认情况下,文件名应与类别名称相同。
`app/messages/nl-NL/main.php` 的例子:
```php
<?php
/**
* Translation map for nl-NL
*/
return [
'welcome' => 'welkom'
];
```
##### 文件映射(File mapping)
[[yii\i18n\PhpMessageSource::fileMap|fileMap]] 来映射一个类别到不同名称的 PHP 文件。
在上面的例子中,类别 `app/error` 被映射到PHP文件 `@app/messages/ru-RU/error.php`(假设 `ru-RU` 为目标语言)。
如果没有此配置,
该类别将被映射到 `@app/messages/ru-RU/app/error.php`
##### 其他存储类型(Other storage types)
除了在PHP文件中存储消息来源,
也可以使用下面的消息来源在不同的存储来存储翻译的消息:
@ -114,13 +163,13 @@ echo \Yii::t('app', 'This is a string to translate!');
- [[yii\i18n\DbMessageSource]] 使用一个数据库表来存储翻译的消息。
## 消息格式化 <span id="message-formatting"></span>
## 消息格式化(Message Formatting) <span id="message-formatting"></span>
在要翻译的消息里,你可以嵌入一些占位符,并让它们通过动态的参数值来代替。
你甚至可以根据目标语言格式的参数值来使用特殊的占位符。
在本节中,我们将介绍如何用不同的方式来格式化消息。
### 消息参数 <span id="message-parameters"></span>
### 消息参数(Message Parameters) <span id="message-parameters"></span>
在待翻译的消息,可以嵌入一个或多个占位符,以便它们可以由给定的参数值取代。
通过给不同的参数值,可以动态地改变翻译内容的消息。
@ -161,7 +210,7 @@ $subtotal = 200;
echo \Yii::t('app', 'Price: {0}, Count: {1}, Subtotal: {2}', $price, $count, $subtotal);
```
In case of a single positional parameter its value could be specified without wrapping it into array:
在单个位置参数的情况下,它的值可以被指定而不包含在数组中:
```php
echo \Yii::t('app', 'Price: {0}', $price);
@ -191,7 +240,7 @@ short form: {PlaceholderName, ParameterType}
full form: {PlaceholderName, ParameterType, ParameterStyle}
```
> Note: If you need to use special characters such as `{`, `}`, `'`, `#`, wrap them in `'`:
> Note: 如果您需要使用特殊字符(如 `{`,`}`,`'`,`#`,请使用 `'`
>
```php
echo Yii::t('app', "Example of string with ''-escaped characters'': '{' '}' '{test}' {count,plural,other{''count'' value is # '#{}'}}", ['count' => 3]);
@ -201,7 +250,7 @@ echo Yii::t('app', "Example of string with ''-escaped characters'': '{' '}' '{te
关于如何指定这样的占位符的说明。接下来我们会展示一些常用的使用方法。
#### 数字 <span id="number"></span>
#### 数字(Number) <span id="number"></span>
参数值应该被格式化为一个数。例如,
@ -224,16 +273,16 @@ $sum = 42;
echo \Yii::t('app', 'Balance: {0, number, ,000,000000}', $sum);
```
Characters used in the custom format could be found in
[ICU API reference](http://icu-project.org/apiref/icu4c/classicu_1_1DecimalFormat.html) under "Special Pattern Characters"
section.
自定义格式中使用的字符可以在“特殊模式字符”一节的
[ICU API 参考](http://icu-project.org/apiref/icu4c/classicu_1_1DecimalFormat.html)
中找到。
The value is always formatted according to the locale you are translating to i.e. you cannot change decimal or thousands
separators, currency symbol etc. without changing translation locale. If you need to customize these you can
use [[yii\i18n\Formatter::asDecimal()]] and [[yii\i18n\Formatter::asCurrency()]].
该值始终根据您翻译的区域设置进行格式设置,即无需更改翻译区域设置即可更改小数或千位分隔符,货币符号等。
如果你需要定制这些,你可以使用
[[yii\i18n\Formatter::asDecimal()]] 和 [[yii\i18n\Formatter::asCurrency()]]。
#### 日期 <span id="date"></span>
#### 日期(Date) <span id="date"></span>
该参数值应该被格式化为一个日期。 例如,
@ -256,7 +305,7 @@ echo \Yii::t('app', 'Today is {0, date, yyyy-MM-dd}', time());
[格式化参考](http://icu-project.org/apiref/icu4c/classicu_1_1SimpleDateFormat.html#details)。
#### 时间 <span id="time"></span>
#### 时间(Time) <span id="time"></span>
参数值应该被格式化为一个时间。 例如,
@ -279,7 +328,7 @@ echo \Yii::t('app', 'It is {0, date, HH:mm}', time());
[格式化参考](http://icu-project.org/apiref/icu4c/classicu_1_1SimpleDateFormat.html#details)。
#### 拼写 <span id="spellout"></span>
#### 拼写(Spellout) <span id="spellout"></span>
参数值为一个数并被格式化为它的字母拼写形式。 例如,
@ -288,19 +337,19 @@ echo \Yii::t('app', 'It is {0, date, HH:mm}', time());
echo \Yii::t('app', '{n,number} is spelled as {n, spellout}', ['n' => 42]);
```
By default the number is spelled out as cardinal. It could be changed:
默认情况下,该数字拼写为基数。 它可以改变:
```php
// may produce "I am forty-seventh agent"
echo \Yii::t('app', 'I am {n,spellout,%spellout-ordinal} agent', ['n' => 47]);
```
Note that there should be no space after `spellout,` and before `%`.
请注意,在 `spellout,` 之后和 `%` 之前不应该有空格。
To get a list of options available for locale you're using check
"Numbering schemas, Spellout" at [http://intl.rmcreative.ru/](http://intl.rmcreative.ru/).
要获取可用于您正在使用的语言环境的选项列表,请查看
[http://intl.rmcreative.ru/](http://intl.rmcreative.ru/) 上的“编号模式,拼写”。
#### 序数词 <span id="ordinal"></span>
#### 序数词(Ordinal) <span id="ordinal"></span>
参数值为一个数并被格式化为一个序数词。 例如,
@ -309,19 +358,19 @@ To get a list of options available for locale you're using check
echo \Yii::t('app', 'You are the {n, ordinal} visitor here!', ['n' => 42]);
```
Ordinal supports more ways of formatting for languages such as Spanish:
Ordinal 支持更多格式化西班牙语等语言的方式:
```php
// may produce 471ª
echo \Yii::t('app', '{n,ordinal,%digits-ordinal-feminine}', ['n' => 471]);
```
Note that there should be no space after `ordinal,` and before `%`.
请注意,在 `ordinal,` 之后和 `%` 之前不应该有空格。
To get a list of options available for locale you're using check
"Numbering schemas, Ordinal" at [http://intl.rmcreative.ru/](http://intl.rmcreative.ru/).
要获取可用于您正在使用的语言环境的选项列表,请查看
[http://intl.rmcreative.ru/](http://intl.rmcreative.ru/) 上的“编号模式,序号”。
#### 持续时间 <span id="duration"></span>
#### 持续时间(Duration) <span id="duration"></span>
参数值为秒数并被格式化为持续的时间段。 例如,
@ -330,19 +379,19 @@ To get a list of options available for locale you're using check
echo \Yii::t('app', 'You are here for {n, duration} already!', ['n' => 47]);
```
Duration supports more ways of formatting:
持续时间支持更多格式化方法:
```php
// may produce 130:53:47
echo \Yii::t('app', '{n,duration,%in-numerals}', ['n' => 471227]);
```
Note that there should be no space after `duration,` and before `%`.
请注意,在 `duration,` 之后和 `%` 之前不应该有空格。
To get a list of options available for locale you're using check
"Numbering schemas, Duration" at [http://intl.rmcreative.ru/](http://intl.rmcreative.ru/).
要获取您正在使用的区域设置的可用选项列表,请查看
[http://intl.rmcreative.ru/](http://intl.rmcreative.ru/) 上的“编号模式,持续时间”。
#### 复数 <span id="plural"></span>
#### 复数(Plural) <span id="plural"></span>
不同的语言有不同的方式来表示复数。 Yii 提供一个便捷的途径,
即使是非常复杂的规则也使翻译消息时不同的复数形式行之有效。
@ -369,13 +418,13 @@ echo \Yii::t('app', 'There {n, plural, =0{are no cats} =1{is one cat} other{are
而不是一个原始消息,除非设置应用程序的
[[yii\base\Application::$sourceLanguage|源语言]] 为 `ru-RU`
> Note: The above example Russian message is mainly used as a translated message, not an original message, unless you set
> the [[yii\base\Application::$sourceLanguage|source language]] of your application as `ru-RU` and translating from Russian.
> Note: 除非您将应用程序的 [[yii\base\Application::$sourceLanguage|源语言]]
> 设置为“RU-RU”,并且从以下语言转换而来,上面的示例俄语消息主要用作翻译的消息,而不是原始消息俄语。
>
> When a translation is not found for an original message specified in `Yii::t()` call, the plural rules for the
> [[yii\base\Application::$sourceLanguage|source language]] will be applied to the original message.
> 当在 `Yii::t()` 调用中指定的原始消息未找到翻译时,
> [[yii\base\Application::$sourceLanguage|源语言]] 复数规则将应用于原始消息。
There's an `offset` parameter for the cases when the string is like the following:
对于字符串如下所示的情况,有一个 `offset` 参数:
```php
$likeCount = 2;
@ -392,10 +441,10 @@ echo Yii::t('app', 'You {likeCount,plural,
// You and one other person liked this
```
#### Ordinal selection <span id="ordinal-selection">
#### 序数选择(Ordinal selection <span id="ordinal-selection">
The parameter type of `selectordinal` is meant to choose a string based on language rules for ordinals for the
locale you are translating to:
`selectordinal` 的参数类型旨在为您所翻译的语言环境选择一个基于语序规则的字符串:
一个基于语序规则的字符串:
```php
$n = 3;
@ -410,11 +459,11 @@ echo Yii::t('app', 'You are the {n,selectordinal,one{#st} two{#nd} few{#rd} othe
// Вы 3-й посетитель
```
The format is very close to what's used for plurals. To learn which arguments you should specify for a particular locale,
please refer to "Plural Rules, Ordinal" at [http://intl.rmcreative.ru/](http://intl.rmcreative.ru/).
Alternatively you can refer to [rules reference at unicode.org](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html).
格式与复数使用的格式非常接近。 要了解您应为特定语言环境指定哪些参数,请参阅
[http://intl.rmcreative.ru/](http://intl.rmcreative.ru/) 上的“复数规则,序数”。
或者,您可以参考 [unicode.org上的规则参考](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)
#### 选择 <span id="selection"></span>
#### 选择(Selection) <span id="selection"></span>
可以使用 `select` 参数类型来选择基于参数值的短语。例如,
@ -431,9 +480,10 @@ echo \Yii::t('app', '{name} is a {gender} and {gender, select, female{she} male{
应指定一个短语并把它放在在一对大括号中。
### 指定默认翻译
### 指定默认翻译(Specifying default message source) <span id="default-message-source"></span>
你可以指定使用默认的翻译,该翻译将作为一个类别,用于不匹配任何其他翻译的后备。这种翻译应标有 `*`
你可以指定使用默认的翻译,该翻译将作为一个类别,用于不匹配任何其他翻译的后备。
这种翻译应标有 `*`
为了做到这一点以下内容需要添加到应用程序的配置:
```php
@ -457,7 +507,7 @@ echo Yii::t('not_specified_category', 'message from unspecified category');
该消息将来自 `@app/messages/<LanguageCode>/not_specified_category.php`
### 翻译模块消息
### 翻译模块消息(Translating module messages) <span id="module-translation"></span>
如果你想翻译一个模块的消息,并避免使用单一翻译文件的所有信息,你可以按照下面的方式来翻译:
@ -504,7 +554,7 @@ class Module extends \yii\base\Module
现在你可以直接使用 `Module::t('validation', 'your custom validation message')`
`Module::t('form', 'some form label')`
### 翻译小部件消息
### 翻译小部件消息(Translating widgets messages) <span id="widget-translation"></span>
上述模块的翻译规则也同样适用于小部件的翻译规则,例如:
@ -557,7 +607,7 @@ class Menu extends Widget
> Tip: 对于小部件也可以使用 i18n 视图,并一样以控制器的规则来应用它们。
### 翻译框架信息
### 翻译框架信息(Translating framework messages) <span id="framework-translation"></span>
Yii 自带了一些默认的信息验证错误和其他一些字符串的翻译。
这些信息都是在 `yii` 类别中。有时候你想纠正应用程序的默认信息翻译。
@ -577,7 +627,7 @@ Yii 自带了一些默认的信息验证错误和其他一些字符串的翻译
现在可以把你修改过的翻译放在 `@app/messages/<language>/yii.php`
### 处理缺少的翻译
### 处理缺少的翻译(Handling missing translations) <span id="missing-translations"></span>
如果翻译的消息在消息源文件里找不到,Yii 将直接显示该消息内容。这样一来当你的原始消息是一个有效的冗长的文字时会很方便。
然而,有时它是不能实现我们的需求。你可能需要执行一些自定义处理的情况,
@ -629,7 +679,7 @@ class TranslationEventHandler
> 你应该给它们每一个消息源指定相应的事件处理程序。
### 使用 `message` 命令 <a name="message-command"></a>
### 使用 `message` 命令(Using the `message` command) <a name="message-command"></a>
翻译储存在 [[yii\i18n\PhpMessageSource|php 文件]],[[yii\i18n\GettextMessageSource|.po 文件] 或者 [[yii\i18n\DbMessageSource|数据库]]。具体见类的附加选项。
@ -644,31 +694,31 @@ class TranslationEventHandler
* `languages`: 代表你的应用程序应该被翻译成什么语言的一个数组;
* `messagePath`: 存储消息文件的路径,这应与配置中 `i18n``basePath` 参数一致。
You may also use './yii message/config' command to dynamically generate configuration file with specified options via cli.
For example, you can set `languages` and `messagePath` parameters like the following:
您也可以使用 './yii message/config' 命令通过 cli 动态生成带有指定选项的配置文件。
例如,你可以像下面这样设置 `languages` `messagePath` 参数:
```bash
./yii message/config --languages=de,ja --messagePath=messages path/to/config.php
```
To get list of available options execute next command:
要获取可用选项列表,请执行下一个命令:
```bash
./yii help message/config
```
Once you're done with the configuration file you can finally extract your messages with the command:
一旦你完成了配置文件,你最终可以用命令提取你的消息:
```bash
./yii message path/to/config.php
```
Also, you may use options to dynamically change parameters for extraction.
另外,您可以使用选项来动态更改提取参数。
然后你会发现你的文件(如果你已经选择基于文件的翻译)在 `messagePath` 目录。
## 视图的翻译 <span id="view-translation"></span>
## 视图的翻译(View Translation) <span id="view-translation"></span>
有时你可能想要翻译一个完整的视图文件,而不是翻译单条文本消息。为了达到这一目的,
只需简单的翻译视图并在它子目录下保存一个名称一样的目标语言文件。
@ -681,12 +731,12 @@ Also, you may use options to dynamically change parameters for extraction.
在翻译视图的存在下,将呈现原始视图。
## 格式化日期和数字值 <span id="date-number"></span>
## 格式化日期和数字值(Formatting Date and Number Values) <span id="date-number"></span>
在 [格式化输出数据](output-formatting.md) 一节可获取详细信息。
## 设置 PHP 环境 <span id="setup-environment"></span>
## 设置 PHP 环境(Setting Up PHP Environment) <span id="setup-environment"></span>
Yii 使用 [PHP intl 扩展](http://php.net/manual/en/book.intl.php) 来提供大多数 I18N 的功能,
如日期和数字格式的 [[yii\i18n\Formatter]] 类和消息格式的 [[yii\i18n\MessageFormatter]] 类。

26
docs/guide-zh-CN/tutorial-start-from-scratch.md

@ -1,5 +1,5 @@
创建你自己的应用程序结构
=======================================
=======================
> 注:本章节正在开发中。
@ -14,7 +14,7 @@ Yii 的项目模板是一个包含 `composer.json` 文件的仓库,并被注
这里,我们使用基础应用模板。
克隆基础模板
----------------------------------------
------------
第一步是从 Git 仓库克隆 Yii 的基础模板:
@ -26,30 +26,34 @@ git clone git@github.com:yiisoft/yii2-app-basic.git
你可以删除下载下来的 `.git` 目录及其内容。
修改文件
------------
--------
接下来,你需要修改 `composer.json` 以配置你自己的模板。修改 `name`, `description`, `keywords`, `homepage`, `license`, 和 `support` 的值来描述你自己的模板。
同样,调整 `require`, `require-dev`, `suggest` 和其他的参数来匹配你模板的环境需求。
同样,调整 `require`, `require-dev`, `suggest`
和其他的参数来匹配你模板的环境需求。
> Note: 在 `composer.json` 文件中,使用 `extra` 下的 `writeable` 参数来指定使用模板创建的应用程序后
> 需要设置文件权限的文件列表。
接下来,真正的修改你的应用程序默认的目录结构和内容。最后,更新 README 文件以符合你的模板。
接下来,真正的修改你的应用程序默认的目录结构和内容。
最后,更新 README 文件以符合你的模板。
发布一个 Package
--------------
发布一个 Package(Make a Package)
--------------------------------
模板调整好后,通过其创建一个 Git 仓库并提交你的代码。如果你希望将你的应用程序模板开源,[Github]() 将是最好的托管服务。如果你不喜欢其他的人来跟你一起协作,你可以使用任意的 Git 仓库服务。
模板调整好后,通过其创建一个 Git 仓库并提交你的代码。
如果你希望将你的应用程序模板开源,[Github](http://github.com) 将是最好的托管服务。
如果你不喜欢其他的人来跟你一起协作,你可以使用任意的 Git 仓库服务。
接下来,你需要为 Composer 注册你的 package。对于公有的模板,你可以将 package 注册到 [Packagist](https://packagist.org/)。对于私有的模板,
注册 package 将会麻烦一点。参考 [Composer documentation](https://getcomposer.org/doc/05-repositories.md#hosting-your-own) 获取更多的指示。
注册 package 将会麻烦一点。
参考 [Composer documentation](https://getcomposer.org/doc/05-repositories.md#hosting-your-own) 获取更多的指示。
使用模板
------
-------
以上就是为了创建一个新的 Yii 项目模板你需要做的事情。现在,你可以使用你自己的模板创建项目了:
```
composer global require "fxp/composer-asset-plugin:~1.0.0"
composer create-project --prefer-dist --stability=dev mysoft/yii2-app-coolone new-project
```

4
docs/guide-zh-CN/tutorial-template-engines.md

@ -1,5 +1,5 @@
使用模板引擎
======================
使用模板引擎(Using template engines)
====================================
默认情况下,Yii 使用 PHP 作为其默认的模板引擎语言,但是,你可以配置 Yii 以扩展的方式支持其他的渲染引擎,
比如 [Twig](http://twig.sensiolabs.org/) 或 [Smarty](http://www.smarty.net/)等。

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

@ -1,17 +1,17 @@
引入第三方代码
=============================
引入第三方代码(Working with Third-Party Code)
=============================================
有时,你可能会需要在 Yii 应用中使用第三方的代码。又或者是你想要在第三方系统中把 Yii 作为类库引用。
在下面这个板块中,我们向你展示如何实现这些目标。
## 在 Yii 中使用第三方类库 <span id="using-libs-in-yii"></span>
----------------------------------
## 在 Yii 中使用第三方类库(Using Third-Party Libraries in Yii) <span id="using-libs-in-yii"></span>
--------------------------------------------------------------
要想在 Yii 应用中使用第三方类库,
你主要需要确保这些库中的类文件都可以被正常导入或可以被自动加载。
### 使用 Composer 包 <span id="using-composer-packages"></span>
### 使用 Composer 包(Using Composer Packages) <span id="using-composer-packages"></span>
目前很多第三方的类库都以 [Composer](https://getcomposer.org/) 包的形式发布。
你只需要以下两个简单的步骤即可安装他们:
@ -31,7 +31,7 @@ require __DIR__ . '/../vendor/autoload.php';
require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php';
```
### 使用下载的类库 <span id="using-downloaded-libs"></span>
### 使用下载的类库(Using Downloaded Libraries) <span id="using-downloaded-libs"></span>
若你的类库并未发布为一个 Composer 包,你可以参考以下安装说明来安装它。
在大多数情况下,你需要预先下载一个发布文件,并把它解压缩到`BasePath/vendor` 目录,
@ -64,15 +64,14 @@ require __DIR__ . '/../vendor/yiisoft/yii2/Yii.php';
* 找出该库内包含哪些类。
* 在应用的[入口脚本](structure-entry-scripts.md)里的 `Yii::$classMap` 数组中列出这些类,和他们各自对应的文件路径。
举例来说,
```php
Yii::$classMap['Class1'] = 'path/to/Class1.php';
Yii::$classMap['Class2'] = 'path/to/Class2.php';
```
## 在第三方系统内使用 Yii <span id="using-yii-in-others"></span>
--------------------------------
## 在第三方系统内使用 Yii(Using Yii in Third-Party Systems) <span id="using-yii-in-others"></span>
-----------------------------------------------------------
因为 Yii 提供了很多牛逼的功能,有时,你可能会想要使用它们中的一些功能用来支持开发或完善某些第三方的系统,
比如:WordPress,Joomla,或是用其他 PHP 框架开发的应用程序。
@ -119,8 +118,8 @@ new yii\web\Application($yiiConfig); // 千万别在这调用 run() 方法。(
比如,创建 AR 类,并用它们来操作数据库。
## 配合使用 Yii 2 和 Yii 1 <span id="using-both-yii2-yii1"></span>
----------------------
## 配合使用 Yii 2 和 Yii 1(Using Yii 2 with Yii 1) <span id="using-both-yii2-yii1"></span>
--------------------------------------------------
如果你之前使用 Yii 1,大概你也有正在运行的 Yii 1 应用吧。
不必用 Yii 2 重写整个应用,你也可以通过增添对哪些

Loading…
Cancel
Save