Browse Source

check line nums

tags/2.0.16
cuiliang 8 years ago
parent
commit
7af578a139
  1. 644
      docs/guide-zh-CN/db-dao.md
  2. 657
      docs/guide-zh-CN/db-migrations.md
  3. 70
      docs/guide-zh-CN/db-query-builder.md
  4. 20
      docs/guide-zh-CN/output-client-scripts.md
  5. 62
      docs/guide-zh-CN/output-data-providers.md
  6. 231
      docs/guide-zh-CN/output-data-widgets.md
  7. 319
      docs/guide-zh-CN/output-formatting.md
  8. 85
      docs/guide-zh-CN/output-pagination.md
  9. 115
      docs/guide-zh-CN/output-sorting.md
  10. 12
      docs/guide-zh-CN/output-theming.md
  11. 61
      docs/guide-zh-CN/rest-authentication.md
  12. 83
      docs/guide-zh-CN/rest-controllers.md
  13. 7
      docs/guide-zh-CN/rest-error-handling.md
  14. 43
      docs/guide-zh-CN/rest-quick-start.md
  15. 58
      docs/guide-zh-CN/rest-rate-limiting.md
  16. 96
      docs/guide-zh-CN/rest-resources.md
  17. 8
      docs/guide-zh-CN/rest-response-formatting.md
  18. 22
      docs/guide-zh-CN/rest-routing.md
  19. 20
      docs/guide-zh-CN/rest-versioning.md
  20. 42
      docs/guide-zh-CN/runtime-bootstrapping.md
  21. 55
      docs/guide-zh-CN/runtime-handling-errors.md
  22. 108
      docs/guide-zh-CN/runtime-logging.md
  23. 3
      docs/guide-zh-CN/runtime-overview.md
  24. 16
      docs/guide-zh-CN/runtime-requests.md
  25. 83
      docs/guide-zh-CN/runtime-responses.md
  26. 626
      docs/guide-zh-CN/runtime-routing.md
  27. 99
      docs/guide-zh-CN/runtime-sessions-cookies.md
  28. 6
      docs/guide-zh-CN/security-authorization.md
  29. 106
      docs/guide-zh-CN/security-best-practices.md
  30. 66
      docs/guide-zh-CN/security-cryptography.md
  31. 14
      docs/guide-zh-CN/security-overview.md
  32. 119
      docs/guide-zh-CN/security-passwords.md
  33. 125
      docs/guide-zh-CN/start-databases.md
  34. 112
      docs/guide-zh-CN/start-forms.md
  35. 53
      docs/guide-zh-CN/start-gii.md
  36. 89
      docs/guide-zh-CN/start-hello.md
  37. 174
      docs/guide-zh-CN/start-installation.md
  38. 29
      docs/guide-zh-CN/start-looking-ahead.md
  39. 51
      docs/guide-zh-CN/start-workflow.md
  40. 56
      docs/guide-zh-CN/structure-application-components.md
  41. 274
      docs/guide-zh-CN/structure-applications.md
  42. 358
      docs/guide-zh-CN/structure-assets.md
  43. 135
      docs/guide-zh-CN/structure-controllers.md
  44. 34
      docs/guide-zh-CN/structure-entry-scripts.md
  45. 338
      docs/guide-zh-CN/structure-extensions.md
  46. 84
      docs/guide-zh-CN/structure-filters.md
  47. 192
      docs/guide-zh-CN/structure-models.md
  48. 98
      docs/guide-zh-CN/structure-modules.md
  49. 22
      docs/guide-zh-CN/structure-overview.md
  50. 168
      docs/guide-zh-CN/structure-views.md
  51. 60
      docs/guide-zh-CN/structure-widgets.md
  52. 16
      docs/guide-zh-CN/test-environment-setup.md
  53. 12
      docs/guide-zh-CN/test-overview.md
  54. 113
      docs/guide-zh-CN/tutorial-console.md
  55. 349
      docs/guide-zh-CN/tutorial-core-validators.md
  56. 229
      docs/guide-zh-CN/tutorial-i18n.md
  57. 43
      docs/guide-zh-CN/tutorial-mailing.md
  58. 85
      docs/guide-zh-CN/tutorial-performance-tuning.md
  59. 7
      docs/guide-zh-CN/tutorial-shared-hosting.md
  60. 24
      docs/guide-zh-CN/tutorial-start-from-scratch.md
  61. 12
      docs/guide-zh-CN/tutorial-template-engines.md
  62. 117
      docs/guide-zh-CN/tutorial-yii-integration.md

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

@ -1,9 +1,16 @@
数据库访问 (DAO)
========
Yii 包含了一个建立在 PHP PDO 之上的数据访问层 (DAO). DAO为不同的数据库提供了一套统一的API. 其中```ActiveRecord``` 提供了数据库与模型(MVC 中的 M,Model) 的交互,```QueryBuilder``` 用于创建动态的查询语句. DAO提供了简单高效的SQL查询,可以用在与数据库交互的各个地方.
Yii 包含了一个建立在 PHP PDO 之上的数据访问层 (DAO)。DAO为不同的数据库提供了一套统一的API。
其中```ActiveRecord``` 提供了数据库与模型(MVC 中的 M,Model) 的交互,```QueryBuilder``` 用于创建动态的查询语句。
DAO提供了简单高效的SQL查询,可以用在与数据库交互的各个地方.
When using Yii DAO, you mainly need to deal with plain SQLs and PHP arrays. As a result, it is the most efficient
way to access databases. However, because SQL syntax may vary for different databases, using Yii DAO also means
you have to take extra effort to create a database-agnostic application.
Yii DAO supports the following databases out of box:
Yii 默认支持以下数据库 (DBMS):
- [MySQL](http://www.mysql.com/)
- [MariaDB](https://mariadb.com/)
- [SQLite](http://sqlite.org/)
@ -12,9 +19,22 @@ Yii 默认支持以下数据库 (DBMS):
- [Oracle](http://www.oracle.com/us/products/database/overview/index.html)
- [MSSQL](https://www.microsoft.com/en-us/sqlserver/default.aspx): 版本>=2005.
##配置
开始使用数据库首先需要配置数据库连接组件,通过添加 db 组件到应用配置实现("基础的" Web 应用是 config/web.php),DSN( Data Source Name )是数据源名称,用于指定数据库信息.如下所示:
## Creating DB Connections <span id="creating-db-connections"></span>
To access a database, you first need to connect to it by creating an instance of [[yii\db\Connection]]:
```php
$db = new yii\db\Connection([
'dsn' => 'mysql:host=localhost;dbname=example',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
]);
```
Because a DB connection often needs to be accessed in different places, a common practice is to configure it
in terms of an [application component](structure-application-components.md) like the following:
```php
return [
@ -23,16 +43,9 @@ return [
// ...
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=mydatabase', // MySQL, MariaDB
//'dsn' => 'sqlite:/path/to/database/file', // SQLite
//'dsn' => 'pgsql:host=localhost;port=5432;dbname=mydatabase', // PostgreSQL
//'dsn' => 'cubrid:dbname=demodb;host=localhost;port=33000', // CUBRID
//'dsn' => 'sqlsrv:Server=localhost;Database=mydatabase', // MS SQL Server, sqlsrv driver
//'dsn' => 'dblib:host=localhost;dbname=mydatabase', // MS SQL Server, dblib driver
//'dsn' => 'mssql:host=localhost;dbname=mydatabase', // MS SQL Server, mssql driver
//'dsn' => 'oci:dbname=//localhost:1521/mydatabase', // Oracle
'username' => 'root', //数据库用户名
'password' => '', //数据库密码
'dsn' => 'mysql:host=localhost;dbname=example',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
],
@ -40,21 +53,27 @@ return [
];
```
请参考PHP manual获取更多有关 DSN 格式信息。
配置连接组件后可以使用以下语法访问:
You can then access the DB connection via the expression `Yii::$app->db`.
<<<<<<< HEAD
```$connection = \Yii::$app->db;```
> Tip: You can configure multiple DB application components if your application needs to access multiple databases.
请参考```[[yii\db\Connection]]```获取可配置的属性列表。
=======
`$connection = \Yii::$app->db;`
When configuring a DB connection, you should always specify its Data Source Name (DSN) via the [[yii\db\Connection::dsn|dsn]]
property. The format of DSN varies for different databases. Please refer to the [PHP manual](http://www.php.net/manual/en/function.PDO-construct.php)
for more details. Below are some examples:
* MySQL, MariaDB: `mysql:host=localhost;dbname=mydatabase`
* SQLite: `sqlite:/path/to/database/file`
* PostgreSQL: `pgsql:host=localhost;port=5432;dbname=mydatabase`
* CUBRID: `cubrid:dbname=demodb;host=localhost;port=33000`
* MS SQL Server (via sqlsrv driver): `sqlsrv:Server=localhost;Database=mydatabase`
* MS SQL Server (via dblib driver): `dblib:host=localhost;dbname=mydatabase`
* MS SQL Server (via mssql driver): `mssql:host=localhost;dbname=mydatabase`
* Oracle: `oci:dbname=//localhost:1521/mydatabase`
请参考`[[yii\db\Connection]]`获取可配置的属性列表。
>>>>>>> yiichina/master
如果你想通过ODBC连接数据库,则需要配置[[yii\db\Connection::driverName]] 属性,例如:
Note that if you are connecting with a database via ODBC, you should configure the [[yii\db\Connection::driverName]]
property so that Yii can know the actual database type. For example,
```
```php
'db' => [
'class' => 'yii\db\Connection',
'driverName' => 'mysql',
@ -64,150 +83,202 @@ return [
],
```
注意:如果需要同时使用多个数据库可以定义多个连接组件:
Besides the [[yii\db\Connection::dsn|dsn]] property, you often need to configure [[yii\db\Connection::username|username]]
and [[yii\db\Connection::password|password]]. Please refer to [[yii\db\Connection]] for the full list of configurable properties.
> Info: When you create a DB connection instance, the actual connection to the database is not established until
you execute the first SQL or you call the [[yii\db\Connection::open()|open()]] method explicitly.
> Tip: Sometimes you may want to execute some queries right after the database connection is established to initialize
> some environment variables (e.g., to set the timezone or character set). You can do so by registering an event handler
> for the [[yii\db\Connection::EVENT_AFTER_OPEN|afterOpen]] event
> of the database connection. You may register the handler directly in the application configuration like so:
>
> ```php
> 'db' => [
> // ...
> 'on afterOpen' => function($event) {
> // $event->sender refers to the DB connection
> $event->sender->createCommand("SET time_zone = 'UTC'")->execute();
> }
> ],
> ```
## Executing SQL Queries <span id="executing-sql-queries"></span>
Once you have a database connection instance, you can execute a SQL query by taking the following steps:
1. Create a [[yii\db\Command]] with a plain SQL query;
2. Bind parameters (optional);
3. Call one of the SQL execution methods in [[yii\db\Command]].
The following example shows various ways of fetching data from a database:
```php
return [
// ...
'components' => [
// ...
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=mydatabase',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
'secondDb' => [
'class' => 'yii\db\Connection',
'dsn' => 'sqlite:/path/to/database/file',
],
],
// ...
];
```
在代码中通过以下方式使用:
// return a set of rows. each row is an associative array of column names and values.
// an empty array is returned if the query returned no results
$posts = Yii::$app->db->createCommand('SELECT * FROM post')
->queryAll();
```
$primaryConnection = \Yii::$app->db;
$secondaryConnection = \Yii::$app->secondDb;
```
// return a single row (the first row)
// false is returned if the query has no result
$post = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=1')
->queryOne();
如果不想定义数据库连接为全局[应用](structure-application-components.md)组件,可以在代码中直接初始化使用:
// return a single column (the first column)
// an empty array is returned if the query returned no results
$titles = Yii::$app->db->createCommand('SELECT title FROM post')
->queryColumn();
```
$connection = new \yii\db\Connection([
'dsn' => $dsn,
'username' => $username,
'password' => $password,
]);
$connection->open();
// return a scalar value
// false is returned if the query has no result
$count = Yii::$app->db->createCommand('SELECT COUNT(*) FROM post')
->queryScalar();
```
>小提示:如果在创建了连接后需要执行额外的 SQL 查询,可以添加以下代码到应用配置文件:
> Note: To preserve precision, the data fetched from databases are all represented as strings, even if the corresponding
database column types are numerical.
```
return [
// ...
'components' => [
// ...
'db' => [
'class' => 'yii\db\Connection',
// ...
'on afterOpen' => function($event) {
$event->sender->createCommand("SET time_zone = 'UTC'")->execute();
}
],
],
// ...
];
### Binding Parameters <span id="binding-parameters"></span>
When creating a DB command from a SQL with parameters, you should almost always use the approach of binding parameters
to prevent SQL injection attacks. For example,
```php
$post = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id AND status=:status')
->bindValue(':id', $_GET['id'])
->bindValue(':status', 1)
->queryOne();
```
##SQL 基础查询
In the SQL statement, you can embed one or multiple parameter placeholders (e.g. `:id` in the above example). A parameter
placeholder should be a string starting with a colon. You may then call one of the following parameter binding methods
to bind the parameter values:
一旦有了连接实例就可以通过[[yii\db\Command]]执行 SQL 查询。
* [[yii\db\Command::bindValue()|bindValue()]]: bind a single parameter value
* [[yii\db\Command::bindValues()|bindValues()]]: bind multiple parameter values in one call
* [[yii\db\Command::bindParam()|bindParam()]]: similar to [[yii\db\Command::bindValue()|bindValue()]] but also
support binding parameter references.
###SELECT 查询
查询返回多行:
The following example shows alternative ways of binding parameters:
```
$command = $connection->createCommand('SELECT * FROM post');
$posts = $command->queryAll();
```
返回单行:
<<<<<<< HEAD
=======
```php
$params = [':id' => $_GET['id'], ':status' => 1];
>>>>>>> yiichina/master
```
$command = $connection->createCommand('SELECT * FROM post WHERE id=1');
$post = $command->queryOne();
$post = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id AND status=:status')
->bindValues($params)
->queryOne();
$post = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id AND status=:status', $params)
->queryOne();
```
查询多行单值:
<<<<<<< HEAD
=======
Parameter binding is implemented via [prepared statements](http://php.net/manual/en/mysqli.quickstart.prepared-statements.php).
Besides preventing SQL injection attacks, it may also improve performance by preparing a SQL statement once and
executing it multiple times with different parameters. For example,
>>>>>>> yiichina/master
```
$command = $connection->createCommand('SELECT title FROM post');
$titles = $command->queryColumn();
```
查询标量值/计算值:
```php
$command = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id');
```
$command = $connection->createCommand('SELECT COUNT(*) FROM post');
$postCount = $command->queryScalar();
$post1 = $command->bindValue(':id', 1)->queryOne();
$post2 = $command->bindValue(':id', 2)->queryOne();
// ...
```
###UPDATE, INSERT, DELETE 更新、插入和删除等
Because [[yii\db\Command::bindParam()|bindParam()]] supports binding parameters by references, the above code
can also be written like the following:
```php
$command = Yii::$app->db->createCommand('SELECT * FROM post WHERE id=:id')
->bindParam(':id', $id);
如果执行 SQL 不返回任何数据可使用命令中的 execute 方法:
$id = 1;
$post1 = $command->queryOne();
$id = 2;
$post2 = $command->queryOne();
// ...
```
$command = $connection->createCommand('UPDATE post SET status=1 WHERE id=1');
$command->execute();
Notice that you bind the placeholder to the `$id` variable before the execution, and then change the value of that variable
before each subsequent execution (this is often done with loops). Executing queries in this manner can be vastly
more efficient than running a new query for every different parameter value.
### Executing Non-SELECT Queries <span id="non-select-queries"></span>
The `queryXyz()` methods introduced in the previous sections all deal with SELECT queries which fetch data from databases.
For queries that do not bring back data, you should call the [[yii\db\Command::execute()]] method instead. For example,
```php
Yii::$app->db->createCommand('UPDATE post SET status=1 WHERE id=1')
->execute();
```
你可以使用`insert`,`update`,`delete` 方法,这些方法会根据参数生成合适的SQL并执行.
The [[yii\db\Command::execute()]] method returns the number of rows affected by the SQL execution.
For INSERT, UPDATE and DELETE queries, instead of writing plain SQLs, you may call [[yii\db\Command::insert()|insert()]],
[[yii\db\Command::update()|update()]], [[yii\db\Command::delete()|delete()]], respectively, to build the corresponding
SQLs. These methods will properly quote table and column names and bind parameter values. For example,
```php
// INSERT
$connection->createCommand()->insert('user', [
// INSERT (table name, column values)
Yii::$app->db->createCommand()->insert('user', [
'name' => 'Sam',
'age' => 30,
])->execute();
// INSERT 一次插入多行
$connection->createCommand()->batchInsert('user', ['name', 'age'], [
// UPDATE (table name, column values, condition)
Yii::$app->db->createCommand()->update('user', ['status' => 1], 'age > 30')->execute();
// DELETE (table name, condition)
Yii::$app->db->createCommand()->delete('user', 'status = 0')->execute();
```
You may also call [[yii\db\Command::batchInsert()|batchInsert()]] to insert multiple rows in one shot, which is much
more efficient than inserting one row at a time:
```php
// table name, column names, column values
Yii::$app->db->createCommand()->batchInsert('user', ['name', 'age'], [
['Tom', 30],
['Jane', 20],
['Linda', 25],
])->execute();
```
// UPDATE
$connection->createCommand()->update('user', ['status' => 1], 'age > 30')->execute();
Note that the aforementioned methods only create the query and you always have to call [[yii\db\Command::execute()|execute()]]
to actually run them.
// DELETE
$connection->createCommand()->delete('user', 'status = 0')->execute();
```
###引用的表名和列名 <a name="quoting-table-and-column-names"></a>
## Quoting Table and Column Names <span id="quoting-table-and-column-names"></span>
大多数时间都使用以下语法来安全地引用表名和列名:
When writing database-agnostic code, properly quoting table and column names is often a headache because
different databases have different name quoting rules. To overcome this problem, you may use the following
quoting syntax introduced by Yii:
```php
$sql = "SELECT COUNT([[$column]]) FROM {{table}}";
$rowCount = $connection->createCommand($sql)->queryScalar();
```
以上代码`[[$column]]` 会转变为引用恰当的列名,而`{{table}}` 就转变为引用恰当的表名。
表名有个特殊的变量 {{%Y}} ,如果设置了表前缀使用该变体可以自动在表名前添加前缀:
* `[[column name]]`: enclose a column name to be quoted in double square brackets;
* `{{table name}}`: enclose a table name to be quoted in double curly brackets.
Yii DAO will automatically convert such constructs into the corresponding quoted column or table names using the
DBMS specific syntax.
For example,
```php
$sql = "SELECT COUNT([[$column]]) FROM {{%$table}}";
$rowCount = $connection->createCommand($sql)->queryScalar();
// executes this SQL for MySQL: SELECT COUNT(`id`) FROM `employee`
$count = Yii::$app->db->createCommand("SELECT COUNT([[id]]) FROM {{employee}}")
->queryScalar();
```
如果在配置文件如下设置了表前缀,以上代码将在 tbl_table 这个表查询结果:
### Using Table Prefix <span id="using-table-prefix"></span>
If most of your DB tables names share a common prefix, you may use the table prefix feature provided
by Yii DAO.
First, specify the table prefix via the [[yii\db\Connection::tablePrefix]] property in the application config:
```php
return [
@ -222,115 +293,164 @@ return [
];
```
手工引用表名和列名的另一个选择是使用[[yii\db\Connection::quoteTableName()]] 和 [[yii\db\Connection::quoteColumnName()]]:
Then in your code, whenever you need to refer to a table whose name contains such a prefix, use the syntax
`{{%table_name}}`. The percentage character will be automatically replaced with the table prefix that you have specified
when configuring the DB connection. For example,
```php
$column = $connection->quoteColumnName($column);
$table = $connection->quoteTableName($table);
$sql = "SELECT COUNT($column) FROM $table";
$rowCount = $connection->createCommand($sql)->queryScalar();
// executes this SQL for MySQL: SELECT COUNT(`id`) FROM `tbl_employee`
$count = Yii::$app->db->createCommand("SELECT COUNT([[id]]) FROM {{%employee}}")
->queryScalar();
```
###预处理语句
为安全传递查询参数可以使用预处理语句,首先应当使用`:placeholder`占位,再将变量绑定到对应占位符:
## Performing Transactions <span id="performing-transactions"></span>
```php
$command = $connection->createCommand('SELECT * FROM post WHERE id=:id');
$command->bindValue(':id', $_GET['id']);
$post = $command->query();
```
另一种用法是准备一次预处理语句而执行多次查询:
When running multiple related queries in a sequence, you may need to wrap them in a transaction to ensure the integrity
and consistency of your database. If any of the queries fails, the database will be rolled back to the state as if
none of these queries were executed.
The following code shows a typical way of using transactions:
```php
$command = $connection->createCommand('DELETE FROM post WHERE id=:id');
$command->bindParam(':id', $id);
$id = 1;
$command->execute();
$id = 2;
$command->execute();
Yii::$app->db->transaction(function($db) {
$db->createCommand($sql1)->execute();
$db->createCommand($sql2)->execute();
// ... executing other SQL statements ...
});
```
>提示,在执行前绑定变量,然后在每个执行中改变变量的值(一般用在循环中)比较高效.
##事务
当你需要顺序执行多个相关的的`query`时,你可以把他们封装到一个事务中去保护数据一致性.Yii提供了一个简单的接口来实现事务操作.
如下执行 SQL 事务查询语句:
The above code is equivalent to the following, which gives you more control about the error handling code:
```php
$transaction = $connection->beginTransaction();
$db = Yii::$app->db;
$transaction = $db->beginTransaction();
try {
$connection->createCommand($sql1)->execute();
$connection->createCommand($sql2)->execute();
// ... 执行其他 SQL 语句 ...
$db->createCommand($sql1)->execute();
$db->createCommand($sql2)->execute();
// ... executing other SQL statements ...
$transaction->commit();
} catch(Exception $e) {
} catch(\Exception $e) {
$transaction->rollBack();
throw $e;
}
```
我们通过[[yii\db\Connection::beginTransaction()|beginTransaction()]]开始一个事务,通过`try catch` 捕获异常.当执行成功,通过[[yii\db\Transaction::commit()|commit()]]提交事务并结束,当发生异常失败通过[[yii\db\Transaction::rollBack()|rollBack()]]进行事务回滚.
如需要也可以嵌套多个事务:
By calling the [[yii\db\Connection::beginTransaction()|beginTransaction()]] method, a new transaction is started.
The transaction is represented as a [[yii\db\Transaction]] object stored in the `$transaction` variable. Then,
the queries being executed are enclosed in a `try...catch...` block. If all queries are executed successfully,
the [[yii\db\Transaction::commit()|commit()]] method is called to commit the transaction. Otherwise, if an exception
will be triggered and caught, the [[yii\db\Transaction::rollBack()|rollBack()]] method is called to roll back
the changes made by the queries prior to that failed query in the transaction. `throw $e` will then re-throw the
exception as if we had not caught it, so the normal error handling process will take care of it.
### Specifying Isolation Levels <span id="specifying-isolation-levels"></span>
Yii also supports setting [isolation levels] for your transactions. By default, when starting a new transaction,
it will use the default isolation level set by your database system. You can override the default isolation level as follows,
```php
// 外部事务
$transaction1 = $connection->beginTransaction();
try {
$connection->createCommand($sql1)->execute();
$isolationLevel = \yii\db\Transaction::REPEATABLE_READ;
// 内部事务
$transaction2 = $connection->beginTransaction();
try {
$connection->createCommand($sql2)->execute();
$transaction2->commit();
} catch (Exception $e) {
$transaction2->rollBack();
}
Yii::$app->db->transaction(function ($db) {
....
}, $isolationLevel);
// or alternatively
$transaction1->commit();
} catch (Exception $e) {
$transaction1->rollBack();
}
$transaction = Yii::$app->db->beginTransaction($isolationLevel);
```
>注意你使用的数据库必须支持`Savepoints`才能正确地执行,以上代码在所有关系数据中都可以执行,但是只有支持`Savepoints`才能保证安全性。
Yii 也支持为事务设置隔离级别`isolation levels`,当执行事务时会使用数据库默认的隔离级别,你也可以为事物指定隔离级别.
Yii 提供了以下常量作为常用的隔离级别
Yii provides four constants for the most common isolation levels:
- [[\yii\db\Transaction::READ_UNCOMMITTED]] - the weakest level, Dirty reads, non-repeatable reads and phantoms may occur.
- [[\yii\db\Transaction::READ_COMMITTED]] - avoid dirty reads.
- [[\yii\db\Transaction::REPEATABLE_READ]] - avoid dirty reads and non-repeatable reads.
- [[\yii\db\Transaction::SERIALIZABLE]] - the strongest level, avoids all of the above named problems.
Besides using the above constants to specify isolation levels, you may also use strings with a valid syntax supported
by the DBMS that you are using. For example, in PostgreSQL, you may use `SERIALIZABLE READ ONLY DEFERRABLE`.
- [[\yii\db\Transaction::READ_UNCOMMITTED]] - 允许读取改变了的还未提交的数据,可能导致脏读、不可重复读和幻读
- [[\yii\db\Transaction::READ_COMMITTED]] - 允许并发事务提交之后读取,可以避免脏读,可能导致重复读和幻读。
- [[\yii\db\Transaction::REPEATABLE_READ]] - 对相同字段的多次读取结果一致,可导致幻读。
- [[\yii\db\Transaction::SERIALIZABLE]] - 完全服从ACID的原则,确保不发生脏读、不可重复读和幻读。
Note that some DBMS allow setting the isolation level only for the whole connection. Any subsequent transactions
will get the same isolation level even if you do not specify any. When using this feature
you may need to set the isolation level for all transactions explicitly to avoid conflicting settings.
At the time of this writing, only MSSQL and SQLite are affected by this limitation.
你可以使用以上常量或者使用一个string字符串命令,在对应数据库中执行该命令用以设置隔离级别,比如对于`postgres`有效的命令为`SERIALIZABLE READ ONLY DEFERRABLE`.
> Note: SQLite only supports two isolation levels, so you can only use `READ UNCOMMITTED` and `SERIALIZABLE`.
Usage of other levels will result in an exception being thrown.
> Note: 某些数据库只能针对连接来设置事务隔离级别,所以你必须要为连接明确制定隔离级别.目前受影响的数据库:`MSSQL SQLite`
> Note: PostgreSQL does not allow setting the isolation level before the transaction starts so you can not
specify the isolation level directly when starting the transaction.
You have to call [[yii\db\Transaction::setIsolationLevel()]] in this case after the transaction has started.
> Note: SQLite 只支持两种事务隔离级别,所以你只能设置`READ UNCOMMITTED` 和 `SERIALIZABLE`.使用其他隔离级别会抛出异常.
[isolation levels]: http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels
> Note: PostgreSQL 不允许在事务开始前设置隔离级别,所以你不能在事务开始时指定隔离级别.你可以在事务开始之后调用[[yii\db\Transaction::setIsolationLevel()]] 来设置.
关于隔离级别[isolation levels]: http://en.wikipedia.org/wiki/Isolation_%28database_systems%29#Isolation_levels
### Nesting Transactions <span id="nesting-transactions"></span>
##数据库复制和读写分离
If your DBMS supports Savepoint, you may nest multiple transactions like the following:
很多数据库支持数据库复制 [database replication](http://en.wikipedia.org/wiki/Replication_(computing)#Database_replication)来提高可用性和响应速度. 在数据库复制中,数据总是从*主服务器* 到 *从服务器*. 所有的插入和更新等写操作在主服务器执行,而读操作在从服务器执行.
```php
Yii::$app->db->transaction(function ($db) {
// outer transaction
$db->transaction(function ($db) {
// inner transaction
});
});
```
通过配置[[yii\db\Connection]]可以实现数据库复制和读写分离.
Or alternatively,
```php
$db = Yii::$app->db;
$outerTransaction = $db->beginTransaction();
try {
$db->createCommand($sql1)->execute();
$innerTransaction = $db->beginTransaction();
try {
$db->createCommand($sql2)->execute();
$innerTransaction->commit();
} catch (\Exception $e) {
$innerTransaction->rollBack();
throw $e;
}
$outerTransaction->commit();
} catch (\Exception $e) {
$outerTransaction->rollBack();
throw $e;
}
```
## Replication and Read-Write Splitting <span id="read-write-splitting"></span>
Many DBMS support [database replication](http://en.wikipedia.org/wiki/Replication_(computing)#Database_replication)
to get better database availability and faster server response time. With database replication, data are replicated
from the so-called *master servers* to *slave servers*. All writes and updates must take place on the master servers,
while reads may also take place on the slave servers.
To take advantage of database replication and achieve read-write splitting, you can configure a [[yii\db\Connection]]
component like the following:
```php
[
'class' => 'yii\db\Connection',
// 配置主服务器
// configuration for the master
'dsn' => 'dsn for master server',
'username' => 'master',
'password' => '',
// 配置从服务器
// common configuration for slaves
'slaveConfig' => [
'username' => 'slave',
'password' => '',
@ -340,7 +460,7 @@ Yii 提供了以下常量作为常用的隔离级别
],
],
// 配置从服务器组
// list of slave configurations
'slaves' => [
['dsn' => 'dsn for slave server 1'],
['dsn' => 'dsn for slave server 2'],
@ -349,31 +469,46 @@ Yii 提供了以下常量作为常用的隔离级别
],
]
```
以上的配置实现了一主多从的结构,从服务器用以执行读查询,主服务器执行写入查询,读写分离的功能由后台代码自动完成.调用者无须关心.例如:
The above configuration specifies a setup with a single master and multiple slaves. One of the slaves will
be connected and used to perform read queries, while the master will be used to perform write queries.
Such read-write splitting is accomplished automatically with this configuration. For example,
```php
// 使用以上配置创建数据库连接对象
$db = Yii::createObject($config);
// create a Connection instance using the above configuration
Yii::$app->db = Yii::createObject($config);
// 通过从服务器执行查询操作
$rows = $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
// query against one of the slaves
$rows = Yii::$app->db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
// 通过主服务器执行更新操作
$db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();
// query against the master
Yii::$app->db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();
```
> Note: 通过[[yii\db\Command::execute()]] 执行的查询被认为是写操作,所有使用[[yii\db\Command]]来执行的其他查询方法被认为是读操作.你可以通过`$db->slave`得到当前正在使用能够的从服务器.
`Connection`组件支持从服务器的负载均衡和故障转移,当第一次执行读查询时,会随即选择一个从服务器进行连接,如果连接失败则又选择另一个,如果所有从服务器都不可用,则会连接主服务器。你可以配置[[yii\db\Connection::serverStatusCache|server status cache]]来记住那些不能连接的从服务器,使Yii 在一段时间[[yii\db\Connection::serverRetryInterval]].内不会重复尝试连接那些根本不可用的从服务器.
> Info: Queries performed by calling [[yii\db\Command::execute()]] are considered as write queries, while
all other queries done through one of the "query" methods of [[yii\db\Command]] are read queries.
You can get the currently active slave connection via `Yii::$app->db->slave`.
The `Connection` component supports load balancing and failover between slaves.
When performing a read query for the first time, the `Connection` component will randomly pick a slave and
try connecting to it. If the slave is found "dead", it will try another one. If none of the slaves is available,
it will connect to the master. By configuring a [[yii\db\Connection::serverStatusCache|server status cache]],
a "dead" server can be remembered so that it will not be tried again during a
[[yii\db\Connection::serverRetryInterval|certain period of time]].
> Note: 在上述配置中,每个从服务器连接超时时间被指定为10s. 如果在10s内不能连接,则被认为该服务器已经挂掉.你也可以自定义超时参数.
> Info: In the above configuration, a connection timeout of 10 seconds is specified for every slave.
This means if a slave cannot be reached in 10 seconds, it is considered as "dead". You can adjust this parameter
based on your actual environment.
You can also configure multiple masters with multiple slaves. For example,
你也可以配置多主多从的结构,例如:
```php
[
'class' => 'yii\db\Connection',
// 配置主服务器
// common configuration for masters
'masterConfig' => [
'username' => 'master',
'password' => '',
@ -383,13 +518,13 @@ $db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();
],
],
// 配置主服务器组
// list of master configurations
'masters' => [
['dsn' => 'dsn for master server 1'],
['dsn' => 'dsn for master server 2'],
],
// 配置从服务器
// common configuration for slaves
'slaveConfig' => [
'username' => 'slave',
'password' => '',
@ -399,7 +534,7 @@ $db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();
],
],
// 配置从服务器组
// list of slave configurations
'slaves' => [
['dsn' => 'dsn for slave server 1'],
['dsn' => 'dsn for slave server 2'],
@ -408,18 +543,26 @@ $db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();
],
]
```
上述配置制定了2个主服务器和4个从服务器.`Connection`组件也支持主服务器的负载均衡和故障转移,与从服务器不同的是,如果所有主服务器都不可用,则会抛出异常.
> Note: 当你使用[[yii\db\Connection::masters|masters]]来配置一个或多个主服务器时,`Connection`中关于数据库连接的其他属性(例如:`dsn`, `username`, `password`)都会被忽略.
The above configuration specifies two masters and four slaves. The `Connection` component also supports
load balancing and failover between masters just as it does between slaves. A difference is that when none
of the masters are available an exception will be thrown.
> Note: When you use the [[yii\db\Connection::masters|masters]] property to configure one or multiple
masters, all other properties for specifying a database connection (e.g. `dsn`, `username`, `password`)
with the `Connection` object itself will be ignored.
事务默认使用主服务器的连接,并且在事务执行中的所有操作都会使用主服务器的连接,例如:
By default, transactions use the master connection. And within a transaction, all DB operations will use
the master connection. For example,
```php
// 在主服务器连接上开始事务
$db = Yii::$app->db;
// the transaction is started on the master connection
$transaction = $db->beginTransaction();
try {
// 所有的查询都在主服务器上执行
// both queries are performed against the master
$rows = $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
$db->createCommand("UPDATE user SET username='demo' WHERE id=1")->execute();
@ -430,56 +573,67 @@ try {
}
```
如果你想在从服务器上执行事务操作则必须要明确地指定,比如:
If you want to start a transaction with the slave connection, you should explicitly do so, like the following:
```php
$transaction = $db->slave->beginTransaction();
$transaction = Yii::$app->db->slave->beginTransaction();
```
有时你想强制使用主服务器来执行读查询,你可以调用`seMaster()`方法.
Sometimes, you may want to force using the master connection to perform a read query. This can be achieved
with the `useMaster()` method:
```php
$rows = $db->useMaster(function ($db) {
$rows = Yii::$app->db->useMaster(function ($db) {
return $db->createCommand('SELECT * FROM user LIMIT 10')->queryAll();
});
```
你也可以设置`$db->enableSlaves` 为`false`来使所有查询都在主服务器上执行.
##操作数据库模式
###获得模式信息
你可以通过 [[yii\db\Schema]]实例来获取Schema信息:
```php
$schema = $connection->getSchema();
```
该实例包括一系列方法来检索数据库多方面的信息:
You may also directly set `Yii::$app->db->enableSlaves` to be false to direct all queries to the master connection.
```php
$tables = $schema->getTableNames();
```
更多信息请参考[[yii\db\Schema]]
###修改模式
## Working with Database Schema <span id="database-schema"></span>
除了基础的 SQL 查询,[[yii\db\Command]]还包括一系列方法来修改数据库模式:
Yii DAO provides a whole set of methods to let you manipulate the database schema, such as creating new tables,
dropping a column from a table, etc. These methods are listed as follows:
- 创建/重命名/删除/清空表
- 增加/重命名/删除/修改字段
- 增加/删除主键
- 增加/删除外键
- 创建/删除索引
* [[yii\db\Command::createTable()|createTable()]]: creating a table
* [[yii\db\Command::renameTable()|renameTable()]]: renaming a table
* [[yii\db\Command::dropTable()|dropTable()]]: removing a table
* [[yii\db\Command::truncateTable()|truncateTable()]]: removing all rows in a table
* [[yii\db\Command::addColumn()|addColumn()]]: adding a column
* [[yii\db\Command::renameColumn()|renameColumn()]]: renaming a column
* [[yii\db\Command::dropColumn()|dropColumn()]]: removing a column
* [[yii\db\Command::alterColumn()|alterColumn()]]: altering a column
* [[yii\db\Command::addPrimaryKey()|addPrimaryKey()]]: adding a primary key
* [[yii\db\Command::dropPrimaryKey()|dropPrimaryKey()]]: removing a primary key
* [[yii\db\Command::addForeignKey()|addForeignKey()]]: adding a foreign key
* [[yii\db\Command::dropForeignKey()|dropForeignKey()]]: removing a foreign key
* [[yii\db\Command::createIndex()|createIndex()]]: creating an index
* [[yii\db\Command::dropIndex()|dropIndex()]]: removing an index
使用示例:
These methods can be used like the following:
```php
// 创建表
$connection->createCommand()->createTable('post', [
// CREATE TABLE
Yii::$app->db->createCommand()->createTable('post', [
'id' => 'pk',
'title' => 'string',
'text' => 'text',
]);
```
完整参考请查看[[yii\db\Command]].
The above array describes the name and types of the columns to be created. For the column types, Yii provides
a set of abstract data types, that allow you to define a database agnostic schema. These are converted to
DBMS specific type definitions dependent on the database, the table is created in.
Please refer to the API documentation of the [[yii\db\Command::createTable()|createTable()]]-method for more information.
Besides changing the database schema, you can also retrieve the definition information about a table through
the [[yii\db\Connection::getTableSchema()|getTableSchema()]] method of a DB connection. For example,
```php
$table = Yii::$app->db->getTableSchema('post');
```
The method returns a [[yii\db\TableSchema]] object which contains the information about the table's columns,
primary keys, foreign keys, etc. All these information are mainly utilized by [query builder](db-query-builder.md)
and [active record](db-active-record.md) to help you write database-agnostic code.

657
docs/guide-zh-CN/db-migrations.md

@ -1,9 +1,12 @@
数据库迁移
===========
在开发和维护一个数据库驱动的应用程序时,数据库的结构会随代码的改变而改变。例如,在开发应用程序的过程中,会增加一张新表且必须得加进来;
在开发和维护一个数据库驱动的应用程序时,
数据库的结构会随代码的改变而改变。
例如,在开发应用程序的过程中,会增加一张新表且必须得加进来;
在应用程序被部署到生产环境后,需要建立一个索引来提高查询的性能等等。
因为一个数据库结构发生改变的时候源代码也经常会需要做出改变,Yii 提供了一个 *数据库迁移* 功能,该功能可以记录数据库的变化,
因为一个数据库结构发生改变的时候源代码也经常会需要做出改变,
Yii 提供了一个 *数据库迁移* 功能,该功能可以记录数据库的变化,
以便使数据库和源代码一起受版本控制。
如下的步骤向我们展示了数据库迁移工具是如何为开发团队所使用的:
@ -11,7 +14,8 @@
1. Tim 创建了一个新的迁移对象(例如,创建一张新的表单,改变字段的定义等)。
2. Tim 将这个新的迁移对象提交到代码管理系统(例如,Git,Mercurial)。
3. Doug 从代码管理系统当中更新版本并获取到这个新的迁移对象。
4. Doug 把这个迁移对象提交到本地的开发数据库当中,这样一来,Doug 同步了 Tim 所做的修改。
4. Doug 把这个迁移对象提交到本地的开发数据库当中,
这样一来,Doug 同步了 Tim 所做的修改。
如下的步骤向我们展示了如何发布一个附带数据库迁移的新版本到生产环境当中:
@ -27,9 +31,12 @@ Yii 提供了一整套的迁移命令行工具,通过这些工具你可以:
* 重新提交迁移;
* 现实迁移历史和状态。
所有的这些工具都可以通过 `yii migrate` 命令来进行操作。 在这一章节,我们将详细的介绍如何使用这些工具来完成各种各样的任务。你也可以通过 `yii help migrate` 命令来获取每一种工具的具体使用方法。
所有的这些工具都可以通过 `yii migrate` 命令来进行操作。
在这一章节,我们将详细的介绍如何使用这些工具来完成各种各样的任务。
你也可以通过 `yii help migrate` 命令来获取每一种工具的具体使用方法。
> 注意:迁移不仅仅只作用于数据库表,它同样会调整现有的数据来适应新的表单、创建 RBAC 分层、又或者是清除缓存。
> 注意:迁移不仅仅只作用于数据库表,
它同样会调整现有的数据来适应新的表单、创建 RBAC 分层、又或者是清除缓存。
## 创建迁移 <span id="creating-migrations"></span>
@ -40,43 +47,63 @@ Yii 提供了一整套的迁移命令行工具,通过这些工具你可以:
yii migrate/create <name>
```
必填参数 `name` 的作用是对新的迁移做一个简要的描述。例如,如果这个迁移是用来创建一个叫做 *news* 的表单的,那么你可以使用 `create_news_table` 这个名称并运行如下命令:
必填参数 `name` 的作用是对新的迁移做一个简要的描述。
例如,如果这个迁移是用来创建一个叫做 *news* 的表单的,
那么你可以使用 `create_news_table` 这个名称并运行如下命令:
```
yii migrate/create create_news_table
```
> 注意:因为 `name` 参数会被用来生成迁移的类名的一部分,所以该参数应当只包含字母、数字和下划线。
> 注意:因为 `name` 参数会被用来生成迁移的类名的一部分,
所以该参数应当只包含字母、数字和下划线。
如上命令将会在 `@app/migrations` 目录下创建一个新的名为 `m150101_185401_create_news_table.php` 的 PHP 类文件。该文件包含如下的代码,它们用来声明一个迁移类 `m150101_185401_create_news_table`,并附有代码框架:
如上命令将会在 `@app/migrations` 目录下创建一个新的名为 `m150101_185401_create_news_table.php` 的 PHP 类文件。
该文件包含如下的代码,它们用来声明一个迁移类 `m150101_185401_create_news_table`
并附有代码框架:
```php
<?php
use yii\db\Schema;
use yii\db\Migration;
class m150101_185401_create_news_table extends Migration
{
public function up()
{
}
public function down()
{
echo "m101129_185401_create_news_table cannot be reverted.\n";
return false;
}
/*
// Use safeUp/safeDown to run migration code within a transaction
public function safeUp()
{
}
public function safeDown()
{
}
*/
}
```
每个数据库迁移都会被定义为一个继承自 [[yii\db\Migration]] 的 PHP 类。类的名称按照 `m<YYMMDD_HHMMSS>_<Name>` 的格式自动生成,其中
每个数据库迁移都会被定义为一个继承自 [[yii\db\Migration]] 的 PHP 类。
类的名称按照 `m<YYMMDD_HHMMSS>_<Name>` 的格式自动生成,其中
* `<YYMMDD_HHMMSS>` 指执行创建迁移命令的 UTC 时间。
* `<Name>` 和你执行命令时所带的 `name` 参数值相同。
在迁移类当中,你应当在 `up()` 方法中编写改变数据库结构的代码。你可能还需要在 `down()` 方法中编写代码来恢复由 `up()` 方法所做的改变。
当你通过 migration 升级数据库时, `up()` 方法将会被调用,反之, `down()` 将会被调用。如下代码展示了如何通过迁移类来创建一张 `news` 表:
在迁移类当中,你应当在 `up()` 方法中编写改变数据库结构的代码。
你可能还需要在 `down()` 方法中编写代码来恢复由 `up()` 方法所做的改变。
当你通过 migration 升级数据库时, `up()` 方法将会被调用,反之, `down()` 将会被调用。
如下代码展示了如何通过迁移类来创建一张 `news` 表:
```php
@ -102,27 +129,38 @@ class m150101_185401_create_news_table extends \yii\db\Migration
}
```
> 注意:并不是所有迁移都是可恢复的。例如,如果 `up()` 方法删除了表中的一行数据,这将无法通过 `down()` 方法来恢复这条数据。有时候,你也许只是懒得去执行 `down()` 方法了,因为它在恢复数据库迁移方面并不是那么的通用。在这种情况下,你应当在 `down()` 方法中返回 `false` 来表明这个 migration 是无法恢复的。
migration 的基类 [[yii\db\Migration]] 通过 [[yii\db\Migration::db|db]] 属性来连接了数据库。你可以通过 [配合数据库工作](db-dao.md#working-with-database-schema-) 章节中所描述的那些方法来操作数据库表。
> 注意:并不是所有迁移都是可恢复的。例如,如果 `up()` 方法删除了表中的一行数据,
这将无法通过 `down()` 方法来恢复这条数据。有时候,你也许只是懒得去执行 `down()` 方法了,
因为它在恢复数据库迁移方面并不是那么的通用。在这种情况下,
你应当在 `down()` 方法中返回 `false` 来表明这个 migration 是无法恢复的。
migration 的基类 [[yii\db\Migration]] 通过 [[yii\db\Migration::db|db]] 属性来连接了数据库。
你可以通过 [配合数据库工作](db-dao.md#working-with-database-schema-)
章节中所描述的那些方法来操作数据库表。
当你通过 migration 创建一张表或者字段的时候,你应该使用 *抽象类型* 而不是 *实体类型*,这样一来你的迁移对象就可以从特定的 DBMS 当中抽离出来。
[[yii\db\Schema]] 类定义了一整套可用的抽象类型常量。这些常量的格式为 `TYPE_<Name>`。例如,`TYPE_PK` 指代自增主键类型;`TYPE_STRING` 指代字符串类型。
当迁移对象被提交到某个特定的数据库的时候,这些抽象类型将会被转换成相对应的实体类型。以 MySQL 为例,`TYPE_PK` 将会变成 `int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY`, 而 `TYPE_STRING` 则变成 `varchar(255)`
当你通过 migration 创建一张表或者字段的时候,你应该使用 *抽象类型* 而不是 *实体类型*
这样一来你的迁移对象就可以从特定的 DBMS 当中抽离出来。
[[yii\db\Schema]] 类定义了一整套可用的抽象类型常量。这些常量的格式为 `TYPE_<Name>`
例如,`TYPE_PK` 指代自增主键类型;`TYPE_STRING` 指代字符串类型。
当迁移对象被提交到某个特定的数据库的时候,这些抽象类型将会被转换成相对应的实体类型。
以 MySQL 为例,`TYPE_PK` 将会变成 `int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY`
`TYPE_STRING` 则变成 `varchar(255)`
在使用抽象类型的时候,你可以添加额外的约束条件。在上面的例子当中, `NOT NULL` 被添加到 `Schema::TYPE_STRING` 当中来指定该字段不能为空。
在使用抽象类型的时候,你可以添加额外的约束条件。在上面的例子当中,
`NOT NULL` 被添加到 `Schema::TYPE_STRING` 当中来指定该字段不能为空。
> 提示:抽象类型和实体类型之间的映射关系是由每个具体的 `QueryBuilder` 类当中的 [[yii\db\QueryBuilder::$typeMap|$typeMap]] 属性所指定的。
> 提示:抽象类型和实体类型之间的映射关系是由每个具体的 `QueryBuilder`
类当中的 [[yii\db\QueryBuilder::$typeMap|$typeMap]] 属性所指定的。
从 2.0.5 的版本开始,schema 构造器提供了更加方便的方法来定义字段,因此上面的 migration 可以被改写成:
Since version 2.0.6, you can make use of the newly introduced schema builder which provides more convenient way of defining column schema.
So the migration above could be written like the following:
```php
<?php
use yii\db\Schema;
use yii\db\Migration;
class m150101_185401_create_news_table extends \yii\db\Migration
class m150101_185401_create_news_table extends Migration
{
public function up()
{
@ -137,16 +175,442 @@ class m150101_185401_create_news_table extends \yii\db\Migration
{
$this->dropTable('news');
}
}
```
A list of all available methods for defining the column types is available in the API documentation of [[yii\db\SchemaBuilderTrait]].
## Generating Migrations <span id="generating-migrations"></span>
Since version 2.0.7 migration console provides a convenient way to create migrations.
If the migration name is of a special form, for example `create_xxx` or `drop_xxx` then the generated migration
file will contain extra code, in this case for creating/dropping tables.
In the following all variants of this feature are described.
### Create Table
```php
yii migrate/create create_post
```
generates
```php
/**
* Handles the creation for table `post`.
*/
class m150811_220037_create_post extends Migration
{
/**
* @inheritdoc
*/
public function up()
{
$this->createTable('post', [
'id' => $this->primaryKey()
]);
}
/**
* @inheritdoc
*/
public function down()
{
$this->dropTable('post');
}
}
```
To create table fields right away, specify them via `--fields` option.
```php
yii migrate/create create_post --fields="title:string,body:text"
```
generates
```php
/**
* Handles the creation for table `post`.
*/
class m150811_220037_create_post extends Migration
{
/**
* @inheritdoc
*/
public function up()
{
$this->createTable('post', [
'id' => $this->primaryKey(),
'title' => $this->string(),
'body' => $this->text(),
]);
}
/**
* @inheritdoc
*/
public function down()
{
$this->dropTable('post');
}
}
```
You can specify more field parameters.
```php
yii migrate/create create_post --fields="title:string(12):notNull:unique,body:text"
```
generates
```php
/**
* Handles the creation for table `post`.
*/
class m150811_220037_create_post extends Migration
{
/**
* @inheritdoc
*/
public function up()
{
$this->createTable('post', [
'id' => $this->primaryKey(),
'title' => $this->string(12)->notNull()->unique(),
'body' => $this->text()
]);
}
/**
* @inheritdoc
*/
public function down()
{
$this->dropTable('post');
}
}
```
> Note: primary key is added automatically and is named `id` by default. If you want to use another name you may
> specify it explicitly like `--fields="name:primaryKey"`.
#### Foreign keys
Since 2.0.8 the generator supports foreign keys using the `foreignKey` keyword.
```php
yii migrate/create create_post --fields="author_id:integer:notNull:foreignKey(user),category_id:integer:defaultValue(1):foreignKey,title:string,body:text"
```
generates
```php
/**
* Handles the creation for table `post`.
* Has foreign keys to the tables:
*
* - `user`
* - `category`
*/
class m160328_040430_create_post extends Migration
{
/**
* @inheritdoc
*/
public function up()
{
$this->createTable('post', [
'id' => $this->primaryKey(),
'author_id' => $this->integer()->notNull(),
'category_id' => $this->integer()->defaultValue(1),
'title' => $this->string(),
'body' => $this->text(),
]);
// creates index for column `author_id`
$this->createIndex(
'idx-post-author_id',
'post',
'author_id'
);
// add foreign key for table `user`
$this->addForeignKey(
'fk-post-author_id',
'post',
'author_id',
'user',
'id',
'CASCADE'
);
// creates index for column `category_id`
$this->createIndex(
'idx-post-category_id',
'post',
'category_id'
);
// add foreign key for table `category`
$this->addForeignKey(
'fk-post-category_id',
'post',
'category_id',
'category',
'id',
'CASCADE'
);
}
/**
* @inheritdoc
*/
public function down()
{
// drops foreign key for table `user`
$this->dropForeignKey(
'fk-post-author_id',
'post'
);
// drops index for column `author_id`
$this->dropIndex(
'idx-post-author_id',
'post'
);
// drops foreign key for table `category`
$this->dropForeignKey(
'fk-post-category_id',
'post'
);
// drops index for column `category_id`
$this->dropIndex(
'idx-post-category_id',
'post'
);
$this->dropTable('post');
}
}
```
The position of the `foreignKey` keyword in the column description doesn't
change the generated code. That means:
- `author_id:integer:notNull:foreignKey(user)`
- `author_id:integer:foreignKey(user):notNull`
- `author_id:foreignKey(user):integer:notNull`
All generate the same code.
The `foreignKey` keyword can take a parameter between parenthesis which will be
the name of the related table for the generated foreign key. If no parameter
is passed then the table name will be deduced from the column name.
In the example above `author_id:integer:notNull:foreignKey(user)` will generate a
column named `author_id` with a foreign key to the `user` table while
`category_id:integer:defaultValue(1):foreignKey` will generate a column
`category_id` with a foreign key to the `category` table.
### Drop Table
```php
yii migrate/create drop_post --fields="title:string(12):notNull:unique,body:text"
```
generates
```php
class m150811_220037_drop_post extends Migration
{
public function up()
{
$this->dropTable('post');
}
public function down()
{
$this->createTable('post', [
'id' => $this->primaryKey(),
'title' => $this->string(12)->notNull()->unique(),
'body' => $this->text()
]);
}
}
```
### Add Column
If the migration name is of the form `add_xxx_to_yyy` then the file content would contain `addColumn` and `dropColumn`
statements necessary.
To add column:
```php
yii migrate/create add_position_to_post --fields="position:integer"
```
generates
```php
class m150811_220037_add_position_to_post extends Migration
{
public function up()
{
$this->addColumn('post', 'position', $this->integer());
}
public function down()
{
$this->dropColumn('post', 'position');
}
}
```
### Drop Column
If the migration name is of the form `drop_xxx_from_yyy` then the file content would contain `addColumn` and `dropColumn`
statements necessary.
```php
yii migrate/create drop_position_from_post --fields="position:integer"
```
generates
```php
class m150811_220037_drop_position_from_post extends Migration
{
public function up()
{
$this->dropColumn('post', 'position');
}
public function down()
{
$this->addColumn('post', 'position', $this->integer());
}
}
```
### Add Junction Table
If the migration name is in if the form of `create_junction_xxx_and_yyy` then code necessary to create junction table
will be generated.
```php
yii migrate/create create_junction_post_and_tag --fields="created_at:dateTime"
```
generates
```php
/**
* Handles the creation for table `post_tag`.
* Has foreign keys to the tables:
*
* - `post`
* - `tag`
*/
class m160328_041642_create_junction_post_and_tag extends Migration
{
/**
* @inheritdoc
*/
public function up()
{
$this->createTable('post_tag', [
'post_id' => $this->integer(),
'tag_id' => $this->integer(),
'created_at' => $this->dateTime(),
'PRIMARY KEY(post_id, tag_id)',
]);
// creates index for column `post_id`
$this->createIndex(
'idx-post_tag-post_id',
'post_tag',
'post_id'
);
// add foreign key for table `post`
$this->addForeignKey(
'fk-post_tag-post_id',
'post_tag',
'post_id',
'post',
'id',
'CASCADE'
);
// creates index for column `tag_id`
$this->createIndex(
'idx-post_tag-tag_id',
'post_tag',
'tag_id'
);
// add foreign key for table `tag`
$this->addForeignKey(
'fk-post_tag-tag_id',
'post_tag',
'tag_id',
'tag',
'id',
'CASCADE'
);
}
/**
* @inheritdoc
*/
public function down()
{
// drops foreign key for table `post`
$this->dropForeignKey(
'fk-post_tag-post_id',
'post_tag'
);
// drops index for column `post_id`
$this->dropIndex(
'idx-post_tag-post_id',
'post_tag'
);
// drops foreign key for table `tag`
$this->dropForeignKey(
'fk-post_tag-tag_id',
'post_tag'
);
// drops index for column `tag_id`
$this->dropIndex(
'idx-post_tag-tag_id',
'post_tag'
);
$this->dropTable('post_tag');
}
}
```
### 事务迁移 <span id="transactional-migrations"></span>
当需要实现复杂的数据库迁移的时候,确定每一个迁移的执行是否成功或失败就变得相当重要了,因为这将影响到数据库的完整性和一致性。为了达到这个目标,我们建议你把每个迁移里面的数据库操作都封装到一个 [transaction](db-dao.md#performing-transactions-) 里面。
当需要实现复杂的数据库迁移的时候,确定每一个迁移的执行是否成功或失败就变得相当重要了,
因为这将影响到数据库的完整性和一致性。为了达到这个目标,我们建议你把每个迁移里面的
数据库操作都封装到一个 [transaction](db-dao.md#performing-transactions-) 里面。
实现事务迁移的一个更为简便的方法是把迁移的代码都放到 `safeUp()``safeDown()` 方法里面。它们与 `up()``down()` 的不同点就在于它们是被隐式的封装到事务当中的。如此一来,只要这些方法里面的任何一个操作失败了,那么所有之前的操作都会被自动的回滚。
实现事务迁移的一个更为简便的方法是把迁移的代码都放到 `safeUp()``safeDown()` 方法里面。
它们与 `up()``down()` 的不同点就在于它们是被隐式的封装到事务当中的。
如此一来,只要这些方法里面的任何一个操作失败了,那么所有之前的操作都会被自动的回滚。
在如下的例子当中,除了创建 `news` 表以外,我们还插入了一行初始化数据到表里面。
@ -179,17 +643,25 @@ class m150101_185401_create_news_table extends Migration
}
```
需要注意的是,当你在 `safeUp()` 当中执行多个数据库操作的时候,你应该在 `safeDown()` 方法当中反转它们的执行顺序。在上面的例子当中,我们在 `safeUp()` 方法当中首先创建了一张表,然后插入了一条数据;而在 `safeDown()` 方法当中,我们首先删除那一行数据,然后才删除那张表。
需要注意的是,当你在 `safeUp()` 当中执行多个数据库操作的时候,你应该在 `safeDown()` 方法当中反转它们的执行顺序。
在上面的例子当中,我们在 `safeUp()` 方法当中首先创建了一张表,然后插入了一条数据;而在 `safeDown()` 方法当中,
我们首先删除那一行数据,然后才删除那张表。
> 注意:并不是所有的数据库都支持事务。有些数据库查询也是不能被放倒事务里面的。在 [implicit commit](http://dev.mysql.com/doc/refman/5.1/en/implicit-commit.html) 章节当中有相关的例子可以参考。如果遇到这种情况的话,那么你应该使用 `up()``down()` 方法进行替代。
> 注意:并不是所有的数据库都支持事务。有些数据库查询也是不能被放倒事务里面的。
在 [implicit commit](http://dev.mysql.com/doc/refman/5.1/en/implicit-commit.html) 章节当中有相关的例子可以参考。
如果遇到这种情况的话,那么你应该使用 `up()``down()` 方法进行替代。
### 访问数据库的方法 <span id="db-accessing-methods"></span>
迁移的基类 [[yii\db\Migration]] 提供了一整套访问和操作数据库的方法。你可能会发现这些方法的命名和 [[yii\db\Command]] 类提供的 [DAO 方法](db-dao.md) 很类似。
例如,[[yii\db\Migration::createTable()]] 方法可以创建一张新的表,这和 [[yii\db\Command::createTable()]] 的功能是一模一样的。
迁移的基类 [[yii\db\Migration]] 提供了一整套访问和操作数据库的方法。
你可能会发现这些方法的命名和 [[yii\db\Command]] 类提供的 [DAO 方法](db-dao.md) 很类似。
例如,[[yii\db\Migration::createTable()]] 方法可以创建一张新的表,
这和 [[yii\db\Command::createTable()]] 的功能是一模一样的。
使用 [[yii\db\Migration]] 所提供的方法的好处在于你不需要再显式的创建 [[yii\db\Command]] 实例,而且在执行每个方法的时候都会显示一些有用的信息来告诉我们数据库操作是不是都已经完成,还有它们完成这些操作花了多长时间等等。
使用 [[yii\db\Migration]] 所提供的方法的好处在于你不需要再显式的创建 [[yii\db\Command]] 实例,
而且在执行每个方法的时候都会显示一些有用的信息来告诉我们数据库操作是不是都已经完成,
还有它们完成这些操作花了多长时间等等。
如下是所有这些数据库访问方法的列表:
@ -212,8 +684,21 @@ class m150101_185401_create_news_table extends Migration
* [[yii\db\Migration::dropForeignKey()|dropForeignKey()]]: 删除一个外键
* [[yii\db\Migration::createIndex()|createIndex()]]: 创建一个索引
* [[yii\db\Migration::dropIndex()|dropIndex()]]: 删除一个索引
* [[yii\db\Migration::addCommentOnColumn()|addCommentOnColumn()]]: adding comment to column
* [[yii\db\Migration::dropCommentFromColumn()|dropCommentFromColumn()]]: dropping comment from column
* [[yii\db\Migration::addCommentOnTable()|addCommentOnTable()]]: adding comment to table
* [[yii\db\Migration::dropCommentFromTable()|dropCommentFromTable()]]: dropping comment from table
> 提示:[[yii\db\Migration]] 并没有提供数据库的查询方法。这是因为通常你是不需要去数据库把数据一行一行查出来再显示出来的。另外一个原因是你完全可以使用强大的 [Query Builder 查询构建器](db-query-builder.md) 来构建和查询。
> 提示:[[yii\db\Migration]] 并没有提供数据库的查询方法。
这是因为通常你是不需要去数据库把数据一行一行查出来再显示出来的。
另外一个原因是你完全可以使用强大的 [Query Builder 查询构建器](db-query-builder.md) 来构建和查询。
> Note: When manipulating data using a migration you may find that using your [Active Record](db-active-record.md) classes
> for this might be useful because some of the logic is already implemented there. Keep in mind however, that in contrast
> to code written in the migrations, who's nature is to stay constant forever, application logic is subject to change.
> So when using Active Record in migration code, changes to the logic in the Active Record layer may accidentally break
> existing migrations. For this reason migration code should be kept independent from other application logic such
> as Active Record classes.
## 提交迁移 <span id="applying-migrations"></span>
@ -224,20 +709,32 @@ class m150101_185401_create_news_table extends Migration
yii migrate
```
这条命令会列出迄今为止所有未提交的迁移。如果你确定你需要提交这些迁移,它将会按照类名当中的时间戳的顺序,一个接着一个的运行每个新的迁移类里面的 `up()` 或者是 `safeUp()` 方法。如果其中任意一个迁移提交失败了,那么这条命令将会退出并停止剩下的那些还未执行的迁移。
这条命令会列出迄今为止所有未提交的迁移。如果你确定你需要提交这些迁移,
它将会按照类名当中的时间戳的顺序,一个接着一个的运行每个新的迁移类里面的 `up()` 或者是 `safeUp()` 方法。
如果其中任意一个迁移提交失败了,
那么这条命令将会退出并停止剩下的那些还未执行的迁移。
> Tip: In case you don't have command line at your server you may try [web shell](https://github.com/samdark/yii2-webshell)
> extension.
对于每一个成功提交的迁移,这条命令都会在一个叫做 `migration` 的数据库表中插入一条包含应用程序成功提交迁移的记录,该记录将帮助迁移工具判断哪些迁移已经提交,
哪些还没有提交。
对于每一个成功提交的迁移,这条命令都会在一个叫做 `migration`
的数据库表中插入一条包含应用程序成功提交迁移的记录,
该记录将帮助迁移工具判断哪些迁移已经提交,哪些还没有提交。
> 提示:迁移工具将会自动在数据库当中创建 `migration` 表,该数据库是在该命令的 [[yii\console\controllers\MigrateController::db|db]] 选项当中指定的。默认情况下,是由 `db` [application component](structure-application-components.md) 指定的。
> 提示:迁移工具将会自动在数据库当中创建 `migration` 表,
该数据库是在该命令的 [[yii\console\controllers\MigrateController::db|db]] 选项当中指定的。
默认情况下,是由 `db` [application component](structure-application-components.md) 指定的。
有时,你可能只需要提交一个或者少数的几个迁移,你可以使用该命令指定需要执行的条数,而不是执行所有的可用迁移。例如,如下命令将会尝试提交前三个可用的迁移:
有时,你可能只需要提交一个或者少数的几个迁移,
你可以使用该命令指定需要执行的条数,而不是执行所有的可用迁移。
例如,如下命令将会尝试提交前三个可用的迁移:
```
yii migrate 3
```
你也可以指定一个特定的迁移,按照如下格式使用 `migrate/to` 命令来指定数据库应该提交哪一个迁移:
你也可以指定一个特定的迁移,按照如下格式使用 `migrate/to` 命令
来指定数据库应该提交哪一个迁移:
```
yii migrate/to 150101_185401 # using timestamp to specify the migration 使用时间戳来指定迁移
@ -246,7 +743,8 @@ yii migrate/to m150101_185401_create_news_table # using full name 使用全名
yii migrate/to 1392853618 # using UNIX timestamp 使用 UNIX 时间戳
```
如果在指定要提交的迁移前面还有未提交的迁移,那么在执行这个被指定的迁移之前,这些还未提交的迁移会先被提交。
如果在指定要提交的迁移前面还有未提交的迁移,那么在执行这个被指定的迁移之前,
这些还未提交的迁移会先被提交。
如果被指定提交的迁移在之前已经被提交过,那么在其之后的那些迁移将会被还原。
@ -260,12 +758,14 @@ yii migrate/down # revert the most recently applied migration 还原最近
yii migrate/down 3 # revert the most 3 recently applied migrations 还原最近三次提交的迁移
```
> 注意:并不是所有的迁移都能被还原。尝试还原这类迁移将可能导致报错甚至是终止所有的还原进程。
> 注意:并不是所有的迁移都能被还原。
尝试还原这类迁移将可能导致报错甚至是终止所有的还原进程。
## 重做迁移 <span id="redoing-migrations"></span>
重做迁移的意思是先还原指定的迁移,然后再次提交。如下所示:
重做迁移的意思是先还原指定的迁移,然后再次提交。
如下所示:
```
yii migrate/redo # redo the last applied migration 重做最近一次提交的迁移
@ -292,7 +792,10 @@ yii migrate/new all # 显示所有还未提交的迁移
## 修改迁移历史 <span id="modifying-migration-history"></span>
有时候你也许需要简单的标记一下你的数据库已经升级到一个特定的迁移,而不是实际提交或者是还原迁移。这个经常会发生在你手动的改变数据库的一个特定状态,而又不想相应的迁移被重复提交。那么你可以使用如下命令来达到目的:
有时候你也许需要简单的标记一下你的数据库已经升级到一个特定的迁移,
而不是实际提交或者是还原迁移。
这个经常会发生在你手动的改变数据库的一个特定状态,而又不想相应的迁移被重复提交。
那么你可以使用如下命令来达到目的:
```
yii migrate/mark 150101_185401 # 使用时间戳来指定迁移
@ -301,7 +804,8 @@ yii migrate/mark m150101_185401_create_news_table # 使用全名
yii migrate/mark 1392853618 # 使用 UNIX 时间戳
```
该命令将会添加或者删除 `migration` 表当中的某几行数据来表明数据库已经提交到了指定的某个迁移上。执行这条命令期间不会有任何的迁移会被提交或还原。
该命令将会添加或者删除 `migration` 表当中的某几行数据来表明数据库已经提交到了指定的某个迁移上。
执行这条命令期间不会有任何的迁移会被提交或还原。
## 自定义迁移 <span id="customizing-migrations"></span>
@ -313,19 +817,44 @@ yii migrate/mark 1392853618 # 使用 UNIX 时间戳
迁移命令附带了几个命令行选项,可以用来自定义它的行为:
* `interactive`: boolean (默认值为 true),指定是否以交互模式来运行迁移。当被设置为 true 时,在命令执行某些操作前,会提示用户。如果你希望在后台执行该命令,那么你应该把它设置成 false。
* `interactive`: boolean (默认值为 true),指定是否以交互模式来运行迁移。
当被设置为 true 时,在命令执行某些操作前,会提示用户。如果你希望在后台执行该命令,
那么你应该把它设置成 false。
* `migrationPath`: string (默认值为 `@app/migrations`),指定存放所有迁移类文件的目录。该选项可以是一个目录的路径,也可以是 [路径别名](concept-aliases.md)。需要注意的是指定的目录必选存在,否则将会触发一个错误。
* `migrationPath`: string (默认值为 `@app/migrations`),指定存放所有迁移类文件的目录。该选项可以是一个目录的路径,
也可以是 [路径别名](concept-aliases.md)。需要注意的是指定的目录必选存在,
否则将会触发一个错误。
* `migrationTable`: string (默认值为 `migration`),指定用于存储迁移历史信息的数据库表名称。如果这张表不存在,那么迁移命令将自动创建这张表。当然你也可以使用这样的字段结构: `version varchar(255) primary key, apply_time integer` 来手动创建这张表。
* `migrationTable`: string (默认值为 `migration`),指定用于存储迁移历史信息的数据库表名称。
如果这张表不存在,那么迁移命令将自动创建这张表。当然你也可以使用这样的字段结构:
`version varchar(255) primary key, apply_time integer` 来手动创建这张表。
* `db`: string (默认值为 `db`),指定数据库 [application component](structure-application-components.md) 的 ID。它指的是将会被该命令迁移的数据库。
* `db`: string (默认值为 `db`),指定数据库 [application component](structure-application-components.md) 的 ID。
它指的是将会被该命令迁移的数据库。
* `templateFile`: string (defaults to `@yii/views/migration.php`),指定生产迁移框架代码类文件的模版文件路径。该选项即可以使用文件路径来指定,也可以使用路径 [别名](concept-aliases.md) 来指定。该模版文件是一个可以使用预定义变量 `$className` 来获取迁移类名称的 PHP 脚本。
* `templateFile`: string (defaults to `@yii/views/migration.php`),
指定生产迁移框架代码类文件的模版文件路径。
该选项即可以使用文件路径来指定,也可以使用路径 [别名](concept-aliases.md) 来指定。
该模版文件是一个可以使用预定义变量 `$className` 来获取迁移类名称的 PHP 脚本。
* `generatorTemplateFiles`: array (defaults to `[
'create_table' => '@yii/views/createTableMigration.php',
'drop_table' => '@yii/views/dropTableMigration.php',
'add_column' => '@yii/views/addColumnMigration.php',
'drop_column' => '@yii/views/dropColumnMigration.php',
'create_junction' => '@yii/views/createJunctionMigration.php'
]`), specifies template files for generating migration code. See "[Generating Migrations](#generating-migrations)"
for more details.
* `fields`: array of column definition strings used for creating migration code. Defaults to `[]`. The format of each
definition is `COLUMN_NAME:COLUMN_TYPE:COLUMN_DECORATOR`. For example, `--fields=name:string(12):notNull` produces
a string column of size 12 which is not null.
如下例子向我们展示了如何使用这些选项:
例如,如果我们需要迁移一个 `forum` 模块,而该迁移文件放在该模块下的 `migrations` 目录当中,那么我们可以使用如下命令:
例如,如果我们需要迁移一个 `forum` 模块,
而该迁移文件放在该模块下的 `migrations` 目录当中,
那么我们可以使用如下命令:
```
# 在 forum 模块中以非交互模式进行迁移
@ -335,7 +864,8 @@ yii migrate --migrationPath=@app/modules/forum/migrations --interactive=0
### 全局配置命令 <span id="configuring-command-globally"></span>
在运行迁移命令的时候每次都要重复的输入一些同样的参数会很烦人,这时候,你可以选择在应用程序配置当中进行全局配置,一劳永逸:
在运行迁移命令的时候每次都要重复的输入一些同样的参数会很烦人,这时候,
你可以选择在应用程序配置当中进行全局配置,一劳永逸:
```php
return [
@ -348,12 +878,15 @@ return [
];
```
如上所示配置,在每次运行迁移命令的时候,`backend_migration` 表将会被用来记录迁移历史。你再也不需要通过 `migrationTable` 命令行参数来指定这张历史纪录表了。
如上所示配置,在每次运行迁移命令的时候,
`backend_migration` 表将会被用来记录迁移历史。
你再也不需要通过 `migrationTable` 命令行参数来指定这张历史纪录表了。
## 迁移多个数据库 <span id="migrating-multiple-databases"></span>
默认情况下,迁移将会提交到由 `db` [application component](structure-application-components.md) 所定义的同一个数据库当中。如果你需要提交到不同的数据库,你可以像下面那样指定 `db` 命令行选项,
默认情况下,迁移将会提交到由 `db` [application component](structure-application-components.md) 所定义的同一个数据库当中。
如果你需要提交到不同的数据库,你可以像下面那样指定 `db` 命令行选项,
```
yii migrate --db=db2
@ -361,11 +894,13 @@ yii migrate --db=db2
上面的命令将会把迁移提交到 `db2` 数据库当中。
偶尔有限时候你需要提交 *一些* 迁移到一个数据库,而另外一些则提交到另一个数据库。为了达到这个目的,你应该在实现一个迁移类的时候指定需要用到的数据库组件的 ID ,
偶尔有限时候你需要提交 *一些* 迁移到一个数据库,而另外一些则提交到另一个数据库。
为了达到这个目的,你应该在实现一个迁移类的时候指定需要用到的数据库组件的 ID ,
如下所示:
```php
use yii\db\Schema;
<?php
use yii\db\Migration;
class m150101_185401_create_news_table extends Migration
@ -378,13 +913,18 @@ class m150101_185401_create_news_table extends Migration
}
```
即使你使用 `db` 命令行选项指定了另外一个不同的数据库,上面的迁移还是会被提交到 `db2` 当中。需要注意的是这个时候迁移的历史信息依然会被记录到 `db` 命令行选项所指定的数据库当中。
即使你使用 `db` 命令行选项指定了另外一个不同的数据库,上面的迁移还是会被提交到 `db2` 当中。
需要注意的是这个时候迁移的历史信息依然会被记录到 `db` 命令行选项所指定的数据库当中。
如果有多个迁移都使用到了同一个数据库,那么建议你创建一个迁移的基类,里面包含上述的 `init()` 代码。然后每个迁移类都继承这个基类就可以了。
如果有多个迁移都使用到了同一个数据库,那么建议你创建一个迁移的基类,里面包含上述的 `init()` 代码。
然后每个迁移类都继承这个基类就可以了。
> 提示:除了在 [[yii\db\Migration::db|db]] 参数当中进行设置以外,你还可以通过在迁移类中创建新的数据库连接来操作不同的数据库。然后通过这些连接再使用 [DAO 方法](db-dao.md) 来操作不同的数据库。
> 提示:除了在 [[yii\db\Migration::db|db]] 参数当中进行设置以外,
你还可以通过在迁移类中创建新的数据库连接来操作不同的数据库。
然后通过这些连接再使用 [DAO 方法](db-dao.md) 来操作不同的数据库。
另外一个可以让你迁移多个数据库的策略是把迁移存放到不同的目录下,然后你可以通过如下命令分别对不同的数据库进行迁移:
另外一个可以让你迁移多个数据库的策略是把迁移存放到不同的目录下,
然后你可以通过如下命令分别对不同的数据库进行迁移:
```
yii migrate --migrationPath=@app/migrations/db1 --db=db1
@ -392,4 +932,5 @@ yii migrate --migrationPath=@app/migrations/db2 --db=db2
...
```
第一条命令将会把 `@app/migrations/db1` 目录下的迁移提交到 `db1` 数据库当中,第二条命令则会把 `@app/migrations/db2` 下的迁移提交到 `db2` 数据库当中,以此类推。
第一条命令将会把 `@app/migrations/db1` 目录下的迁移提交到 `db1` 数据库当中,
第二条命令则会把 `@app/migrations/db2` 下的迁移提交到 `db2` 数据库当中,以此类推。

70
docs/guide-zh-CN/db-query-builder.md

@ -89,6 +89,9 @@ $query->select(['user_id' => 'user.id', 'email']);
$query->select(["CONCAT(first_name, ' ', last_name) AS full_name", 'email']);
```
As with all places where raw SQL is involved, you may use the [DBMS agnostic quoting syntax](db-dao.md#quoting-table-and-column-names)
for table and column names when writing DB expressions in select.
从 2.0.1 的版本开始你就可以使用子查询了。在定义每一个子查询的时候,
你应该使用 [[yii\db\Query]] 对象。例如:
@ -163,13 +166,17 @@ $query->from(['u' => $subQuery]);
#### 字符串格式 <span id="string-format"></span>
在定义非常简单的查询条件的时候,字符串格式是最合适的。它看起来和原生 SQL 语句差不多。例如:
在定义非常简单的查询条件的时候,字符串格式是最合适的。
它看起来和原生 SQL 语句差不多。例如:
```php
$query->where('status=1');
// 或者使用参数绑定来绑定动态参数值
// or use parameter binding to bind dynamic parameter values
$query->where('status=:status', [':status' => $status]);
// raw SQL using MySQL YEAR() function on a date field
$query->where('YEAR(somedate) = 2015');
```
千万不要像如下的例子一样直接在条件语句当中嵌入变量,特别是当这些变量来源于终端用户输入的时候,
@ -188,6 +195,8 @@ $query->where('status=:status')
->addParams([':status' => $status]);
```
As with all places where raw SQL is involved, you may use the [DBMS agnostic quoting syntax](db-dao.md#quoting-table-and-column-names)
for table and column names when writing conditions in string format.
#### 哈希格式 <span id="hash-format"></span>
@ -215,6 +224,9 @@ $userQuery = (new Query())->select('id')->from('user');
$query->where(['id' => $userQuery]);
```
Using the Hash Format, Yii internally uses parameter binding so in contrast to the [string format](#string-format), here
you do not have to add parameters manually.
#### 操作符格式 <span id="operator-format"></span>
@ -224,8 +236,8 @@ $query->where(['id' => $userQuery]);
[操作符, 操作数1, 操作数2, ...]
```
其中每个操作数可以是字符串格式、哈希格式或者嵌套的操作符格式,而操作符可以是如下列表中的一个:
其中每个操作数可以是字符串格式、哈希格式或者嵌套的操作符格式,
而操作符可以是如下列表中的一个:
- `and`: 操作数会被 `AND` 关键字串联起来。例如,`['and', 'id=1', 'id=2']`
将会生成 `id=1 AND id=2`。如果操作数是一个数组,它也会按上述规则转换成
@ -239,8 +251,8 @@ $query->where(['id' => $userQuery]);
的取值范围。例如,`['between', 'id', 1, 10]` 将会生成
`id BETWEEN 1 AND 10`
- `not between`: 用法和 `BETWEEN` 操作符类似,这里就不再赘述。
- `not between`: similar to `between` except the `BETWEEN` is replaced with `NOT BETWEEN`
in the generated condition.
- `in`: 第一个操作数应为字段名称或者 DB 表达式。第二个操作符既可以是一个数组,
也可以是一个 `Query` 对象。它会转换成`IN` 条件语句。如果第二个操作数是一个
@ -253,7 +265,8 @@ $query->where(['id' => $userQuery]);
- `not in`: 用法和 `in` 操作符类似,这里就不再赘述。
- `like`: 第一个操作数应为一个字段名称或 DB 表达式,第二个操作数可以使字符串或数组,
- `like`: 第一个操作数应为一个字段名称或 DB 表达式,
第二个操作数可以使字符串或数组,
代表第一个操作数需要模糊查询的值。比如,`['like', 'name', 'tester']` 会生成
`name LIKE '%tester%'`。 如果范围值是一个数组,那么将会生成用 `AND` 串联起来的
多个 `like` 语句。例如,`['like', 'name', ['test', 'sample']]` 将会生成
@ -265,9 +278,8 @@ $query->where(['id' => $userQuery]);
当使用转义映射(又或者没有提供第三个操作数的时候),第二个操作数的值的前后
将会被加上百分号。
> 注意:当使用 PostgreSQL 的时候你还可以使用 [`ilike`](http://www.postgresql.org/docs/8.3/static/functions-matching.html#FUNCTIONS-LIKE),
> 该方法对大小写不敏感。
> 注意:当使用 PostgreSQL 的时候你还可以使用 [`ilike`](http://www.postgresql.org/docs/8.3/static/functions-matching.html#FUNCTIONS-LIKE),
> 该方法对大小写不敏感。
- `or like`: 用法和 `like` 操作符类似,区别在于当第二个操作数为数组时,
会使用 `OR` 来串联多个 `LIKE` 条件语句。
@ -286,6 +298,9 @@ $query->where(['id' => $userQuery]);
- `>`, `<=`, 或者其他包含两个操作数的合法 DB 操作符: 第一个操作数必须为字段的名称,
而第二个操作数则应为一个值。例如,`['>', 'age', 10]` 将会生成 `age>10`
Using the Operator Format, Yii internally uses parameter binding so in contrast to the [string format](#string-format), here
you do not have to add parameters manually.
#### 附加条件 <span id="appending-conditions"></span>
@ -336,6 +351,20 @@ $query->filterWhere([
你可以使用 [[yii\db\Query::andFilterWhere()|andFilterWhere()]] 和 [[yii\db\Query::orFilterWhere()|orFilterWhere()]] 方法
来追加额外的过滤条件。
Additionally, there is [[yii\db\Query::andFilterCompare()]] that can intelligently determine operator based on what's
in the value:
```php
$query->andFilterCompare('name', 'John Doe');
$query->andFilterCompare('rating', '>9');
$query->andFilterCompare('value', '<=100');
```
You can also specify operator explicitly:
```php
$query->andFilterCompare('name', 'Doe', 'like');
```
### [[yii\db\Query::orderBy()|orderBy()]] <span id="order-by"></span>
@ -448,8 +477,11 @@ $query->join('LEFT JOIN', 'post', 'post.user_id = user.id');
- `$type`: 连接类型,例如:`'INNER JOIN'`, `'LEFT JOIN'`
- `$table`: 将要连接的表名称。
- `$on`: 可选参数,连接条件,即 `ON` 子句。请查阅 [where()](#where)
获取更多有关于条件定义的细节。
- `$on`: optional, the join condition, i.e., the `ON` fragment. Please refer to [where()](#where) for details
about specifying a condition. Note, that the array syntax does **not** work for specifying a column based
condition, e.g. `['user.id' => 'comment.userId']` will result in a condition where the user id must be equal
to the string `'comment.userId'`. You should use the string syntax instead and specify the condition as
`'user.id = comment.userId'`.
- `$params`: 可选参数,与连接条件绑定的参数。
你可以分别调用如下的快捷方法来指定 `INNER JOIN`, `LEFT JOIN``RIGHT JOIN`
@ -602,13 +634,19 @@ $query = (new \yii\db\Query())
该匿名函数将带有一个包含了当前行的数据的 `$row` 参数,并且返回用作当前行索引的
标量值(译者注:就是简单的数值或者字符串,而不是其他复杂结构,例如数组)。
> Note: In contrast to query methods like [[yii\db\Query::groupBy()|groupBy()]] or [[yii\db\Query::orderBy()|orderBy()]]
> which are converted to SQL and are part of the query, this method works after the data has been fetched from the database.
> That means that only those column names can be used that have been part of SELECT in your query.
> Also if you selected a column with table prefix, e.g. `customer.id`, the result set will only contain `id` so you have to call
> `->indexBy('id')` without table prefix.
### 批处理查询 <span id="batch-query"></span>
当需要处理大数据的时候,像 [[yii\db\Query::all()]] 这样的方法就不太合适了,
因为它们会把所有数据都读取到内存上。为了保持较低的内存需求, Yii 提供了一个
所谓的批处理查询的支持。批处理查询会利用数据游标将数据以批为单位取出来。
所谓的批处理查询的支持。批处理查询会利用数据游标
将数据以批为单位取出来。
批处理查询的用法如下:
@ -638,7 +676,8 @@ foreach ($query->each() as $user) {
相对于 [[yii\db\Query::all()]] 方法,批处理查询每次只读取 100 行的数据到内存。
如果你在处理完这些数据后及时丢弃这些数据,那么批处理查询可以很好的帮助降低内存的占用率。
如果你通过 [[yii\db\Query::indexBy()]] 方法为查询结果指定了索引字段,那么批处理查询将仍然保持相对应的索引方案,例如,
如果你通过 [[yii\db\Query::indexBy()]] 方法为查询结果指定了索引字段,
那么批处理查询将仍然保持相对应的索引方案,例如,
```php
@ -653,4 +692,3 @@ foreach ($query->batch() as $users) {
foreach ($query->each() as $username => $user) {
}
```

20
docs/guide-zh-CN/output-client-scripts.md

@ -33,12 +33,12 @@ $this->registerJs("var options = ".json_encode($options).";", View::POS_END, 'my
$this->registerJsFile('http://example.com/js/main.js', ['depends' => [\yii\web\JqueryAsset::className()]]);
```
[[yii\web\View::registerJsFile()|registerJsFile()]] 中参数的使用与 [[yii\web\View::registerCssFile()|registerCssFile()]] 中的参数使用类似。
在上面的例子中,我们注册了 `main.js` 文件,并且依赖于 `JqueryAsset` 类。这意味着 `main.js` 文件将被添加在 `jquery.js` 的后面。
[[yii\web\View::registerJsFile()|registerJsFile()]] 中参数的使用与
[[yii\web\View::registerCssFile()|registerCssFile()]] 中的参数使用类似。
在上面的例子中,我们注册了 `main.js` 文件,并且依赖于 `JqueryAsset` 类。
这意味着 `main.js` 文件将被添加在 `jquery.js` 的后面。
如果没有这个依赖规范的话,`main.js`和 `jquery.js` 两者之间的顺序将不会被定义。
和 [[yii\web\View::registerCssFile()|registerCssFile()]] 一样,我们强烈建议您使用 [asset bundles](structure-assets.md) 来注册外部JS文件,而非使用
[[yii\web\View::registerJsFile()|registerJsFile()]] 来注册。
@ -85,12 +85,12 @@ $this->registerCssFile("http://example.com/css/themes/black-and-white.css", [
上面的代码将在页面的头部添加一个link引入CSS文件。
* 第一个参数指明被注册的CSS文件。
* 第二个参数指明 `<link>` 标签的HTML属性,选项 `depends` 是专门处理指明CSS文件依赖于哪个资源包。在这种情况下,依赖资源包就是
[[yii\bootstrap\BootstrapAsset|BootstrapAsset]]。这意味着CSS文件将被添加在 [[yii\bootstrap\BootstrapAsset|BootstrapAsset]] 之后。
* 最后一个参数指明一个ID来标识这个CSS文件。假如这个参数未传,CSS文件的URL将被作为ID来替代。
* 第二个参数指明 `<link>` 标签的HTML属性,选项 `depends` 是专门处理
指明CSS文件依赖于哪个资源包。在这种情况下,依赖资源包就是
[[yii\bootstrap\BootstrapAsset|BootstrapAsset]]。这意味着CSS文件将
被添加在 [[yii\bootstrap\BootstrapAsset|BootstrapAsset]] 之后。
* 最后一个参数指明一个ID来标识这个CSS文件。假如这个参数未传,
CSS文件的URL将被作为ID来替代。
我们强烈建议使用 [asset bundles](structure-assets.md) 来注册外部CSS文件,

62
docs/guide-zh-CN/output-data-providers.md

@ -6,8 +6,8 @@
因为分页和排序数据的任务是很常见的,所以Yii提供了一组封装好的*data provider*类。
数据提供者是一个实现了 [[yii\data\DataProviderInterface]] 接口的类。
它主要用于获取分页和数据排序。它经常用在 [data widgets](output-data-widgets.md) 小物件里,方便终端用户进行分页与数据排序。
它主要用于获取分页和数据排序。它经常用在 [data widgets](output-data-widgets.md)
小物件里,方便终端用户进行分页与数据排序。
下面的数据提供者类都包含在Yii的发布版本里面:
@ -36,11 +36,11 @@ $count = $provider->getCount();
$totalCount = $provider->getTotalCount();
```
你可以通过配置 [[yii\data\BaseDataProvider::pagination|pagination]] 和 [[yii\data\BaseDataProvider::sort|sort]]
的属性来设定数据提供者的分页和排序行为。属性分别对应于 [[yii\data\Pagination]] 和 [[yii\data\Sort]]。
你可以通过配置 [[yii\data\BaseDataProvider::pagination|pagination]] 和
[[yii\data\BaseDataProvider::sort|sort]]的属性来设定数据提供者的分页和排序行为。
属性分别对应于 [[yii\data\Pagination]] 和 [[yii\data\Sort]]。
你也可以对它们配置false来禁用分页和排序特性。
[Data widgets](output-data-widgets.md),诸如 [[yii\grid\GridView]],有一个属性名叫 `dataProvider` ,这个属性能够提供一个
数据提供者的示例并且可以显示所提供的数据,例如,
@ -50,8 +50,8 @@ echo yii\grid\GridView::widget([
]);
```
这些数据提供者的主要区别在于数据源的指定方式上。在下面的部分,我们将详细介绍这些数据提供者的使用方法。
这些数据提供者的主要区别在于数据源的指定方式上。在下面的部分,
我们将详细介绍这些数据提供者的使用方法。
## 活动数据提供者 <span id="active-data-provider"></span>
@ -91,9 +91,9 @@ use yii\db\Query;
$query = (new Query())->from('post')->where(['status' => 1]);
```
> 注意:假如查询已经指定了 `orderBy` 从句,则终端用户给定的新的排序说明(通过 `sort` 来配置的)将被添加到已经存在的从句中。
任何已经存在的 `limit``offset` 从句都将被终端用户所请求的分页(通过 `pagination` 所配置的)所重写。
> 注意:假如查询已经指定了 `orderBy` 从句,则终端用户给定的新的排序说明(通过 `sort` 来配置的)
将被添加到已经存在的从句中。任何已经存在的 `limit``offset` 从句都将被终端用户所请求的分页
(通过 `pagination` 所配置的)所重写。
默认情况下,[[yii\data\ActiveDataProvider]]使用 `db` 应用组件来作为数据库连接。你可以通过配置 [[yii\data\ActiveDataProvider::db]]
的属性来使用不同数据库连接。
@ -101,10 +101,10 @@ $query = (new Query())->from('post')->where(['status' => 1]);
## SQL数据提供者 <span id="sql-data-provider"></span>
[[yii\data\SqlDataProvider]] 应用的时候需要结合需要获取数据的SQL语句。基于 [[yii\data\SqlDataProvider::sort|sort]] 和
[[yii\data\SqlDataProvider::pagination|pagination]] 规格,数据提供者会根据所请求的数据页面(期望的顺序)来调整 `ORDER BY``LIMIT`
的SQL从句。
[[yii\data\SqlDataProvider]] 应用的时候需要结合需要获取数据的SQL语句。
基于 [[yii\data\SqlDataProvider::sort|sort]] 和
[[yii\data\SqlDataProvider::pagination|pagination]] 规格,
数据提供者会根据所请求的数据页面(期望的顺序)来调整 `ORDER BY``LIMIT` 的SQL从句。
为了使用 [[yii\data\SqlDataProvider]],你应该指定 [[yii\data\SqlDataProvider::sql|sql]] 属性以及
[[yii\data\SqlDataProvider::totalCount|totalCount]] 属性,例如,
@ -136,21 +136,21 @@ $provider = new SqlDataProvider([
$models = $provider->getModels();
```
> 说明:[[yii\data\SqlDataProvider::totalCount|totalCount]] 的属性只有你需要分页数据的时候才会用到。
这是因为通过 [[yii\data\SqlDataProvider::sql|sql]] 指定的SQL语句将被数据提供者所修改并且只返回当前页面数据。
数据提供者为了正确计算可用页面的数量仍旧需要知道数据项的总数。
> 说明:[[yii\data\SqlDataProvider::totalCount|totalCount]] 的属性只有你需要
分页数据的时候才会用到。这是因为通过 [[yii\data\SqlDataProvider::sql|sql]]
指定的SQL语句将被数据提供者所修改并且只返回当
前页面数据。数据提供者为了正确计算可用页面的数量仍旧需要知道数据项的总数。
## 数组数据提供者 <span id="array-data-provider"></span>
[[yii\data\ArrayDataProvider]] 非常适用于大的数组。数据提供者允许你返回一个经过一个或者多个字段排序的数组数据页面。
为了使用 [[yii\data\ArrayDataProvider]],你应该指定 [[yii\data\ArrayDataProvider::allModels|allModels]] 属性
作为一个大的数组。
这个大数组的元素既可以是一些关联数组(例如:[DAO](db-dao.md)查询出来的结果)也可以是一些对象(例如:[Active Record](db-active-record.md)实例)
[[yii\data\ArrayDataProvider]] 非常适用于大的数组。数据提供者允许你返回一个
经过一个或者多个字段排序的数组数据页面。为了使用 [[yii\data\ArrayDataProvider]],
你应该指定 [[yii\data\ArrayDataProvider::allModels|allModels]] 属性作为一个大的数组。
这个大数组的元素既可以是一些关联数组(例如:[DAO](db-dao.md)查询出来的结果)
也可以是一些对象(例如:[Active Record](db-active-record.md)实例)
例如,
```php
use yii\data\ArrayDataProvider;
@ -203,10 +203,10 @@ $ids = $provider->getKeys();
```
在上面的例子中,因为你提供给 [[yii\data\ActiveDataProvider]] 一个 [[yii\db\ActiveQuery]] 对象,
它是足够智能地返回一些主键值作为键。你也可以明确指出键值应该怎样被计算出来,计算的方式是通过使用一个字段名或者一个可调用的计算键值来配置。
它是足够智能地返回一些主键值作为键。你也可以明确指出键值应该怎样被计算出来,
计算的方式是通过使用一个字段名或者一个可调用的计算键值来配置。
例如,
```php
// 使用 "slug" 字段作为键值
$provider = new ActiveDataProvider([
@ -230,12 +230,12 @@ $provider = new ActiveDataProvider([
一个简单的方式是从 [[yii\data\BaseDataProvider]] 去扩展,这种方式允许你关注数据提供者的核心逻辑。
这时,你主要需要实现下面的一些方法:
- [[yii\data\BaseDataProvider::prepareModels()|prepareModels()]]:准备好在当前页面可用的数据模型,并且作为一个数组返回它们。
- [[yii\data\BaseDataProvider::prepareKeys()|prepareKeys()]]:接受一个当前可用的数据模型的数组,并且返回一些与它们相关联的键。
- [[yii\data\BaseDataProvider::prepareTotalCount()|prepareTotalCount]]: 在数据提供者中返回一个标识出数据模型总数的值。
- [[yii\data\BaseDataProvider::prepareModels()|prepareModels()]]:准备好在当前页面可用的数据模型,
并且作为一个数组返回它们。
- [[yii\data\BaseDataProvider::prepareKeys()|prepareKeys()]]:接受一个当前可用的数据模型的数组,
并且返回一些与它们相关联的键。
- [[yii\data\BaseDataProvider::prepareTotalCount()|prepareTotalCount]]: 在数据提供者中返回一个
标识出数据模型总数的值。
下面是一个数据提供者的例子,这个数据提供者可以高效地读取CSV数据:

231
docs/guide-zh-CN/output-data-widgets.md

@ -3,8 +3,8 @@
Yii提供了一套数据小部件 [widgets](structure-widgets.md) ,这些小部件可以用于显示数据。
[DetailView](#detail-view) 小部件能够用于显示一条记录数据,
[ListView](#list-view) 和 [GridView](#grid-view) 小部件能够用于显示一个拥有分页、排序和过滤功能的一个列表或者表格。
[ListView](#list-view) 和 [GridView](#grid-view) 小部件能够用于显示一个拥有分页、
排序和过滤功能的一个列表或者表格。
DetailView <a name="detail-view"></a>
@ -40,8 +40,8 @@ ListView <a name="list-view"></a>
[[yii\widgets\ListView|ListView]] 小部件用于显示数据提供者 [data provider](output-data-providers.md) 提供的数据。
每个数据模型用指定的视图文件 [[yii\widgets\ListView::$itemView|view file]] 来渲染。
因为它提供开箱即用式的(译者注:封装好的)分页、排序以及过滤这样一些特性,所以它可以很方便地为最终用户显示信息并同时创建数据管理界面。
因为它提供开箱即用式的(译者注:封装好的)分页、排序以及过滤这样一些特性,
所以它可以很方便地为最终用户显示信息并同时创建数据管理界面。
一个典型的用法如下例所示:
@ -82,8 +82,8 @@ use yii\helpers\HtmlPurifier;
- `$index`:整型,是由数据提供者返回的数组中以0起始的数据项的索引。
- `$widget`:类型是ListView,是小部件的实例。
假如你需要传递附加数据到每一个视图中,你可以像下面这样用 [[yii\widgets\ListView::$viewParams|$viewParams]] 属性传递键值对:
假如你需要传递附加数据到每一个视图中,你可以像下面这样用 [[yii\widgets\ListView::$viewParams|$viewParams]]
属性传递键值对:
```php
echo ListView::widget([
@ -104,11 +104,11 @@ GridView <a name="grid-view"></a>
--------
数据网格或者说 GridView 小部件是Yii中最强大的部件之一。如果你需要快速建立系统的管理后台,
GridView 非常有用。它从数据提供者 [data provider](output-data-providers.md) 中取得数据并使用 [[yii\grid\GridView::columns|columns]] 属性的一组列配置,在一个表格中渲染每一行数据。
表中的每一行代表一个数据项的数据,并且一列通常表示该项的属性(某些列可以对应于属性或静态文本的复杂表达式)。
GridView 非常有用。它从数据提供者 [data provider](output-data-providers.md) 中取得数据并使用
[[yii\grid\GridView::columns|columns]] 属性的一组列配置,在一个表格中渲染每一行数据。
表中的每一行代表一个数据项的数据,并且一列通常表示该项的属性
(某些列可以对应于属性或静态文本的复杂表达式)。
使用GridView的最少代码如下:
@ -158,8 +158,8 @@ echo GridView::widget([
]);
```
请注意,假如配置中没有指定 [[yii\grid\GridView::columns|columns]] 属性,那么Yii会试图显示数据提供者的模型中所有可能的列。
请注意,假如配置中没有指定 [[yii\grid\GridView::columns|columns]] 属性,
那么Yii会试图显示数据提供者的模型中所有可能的列。
### 列类
@ -223,10 +223,10 @@ echo GridView::widget([
]);
```
在上面的代码中,`text` 对应于 [[\yii\i18n\Formatter::asText()]]。列的值作为第一个参数传递。在第二列的定义中,`date` 对应于 [[\yii\i18n\Formatter::asDate()]]。
在上面的代码中,`text` 对应于 [[\yii\i18n\Formatter::asText()]]。列的值作为第一个参数传递。
在第二列的定义中,`date` 对应于 [[\yii\i18n\Formatter::asDate()]]。
同样地,列值也是通过第一个参数传递的,而 'php:Y-m-d' 用作第二个参数的值。
可用的格式化方法列表,请参照 [section about Data Formatting](output-formatting.md)。
数据列配置,还有一个”快捷格式化串”的方法,详情见API文档 [[yii\grid\GridView::columns|columns]]。
@ -265,13 +265,30 @@ echo GridView::widget([
}
```
在上面的代码中,`$url` 是列为按钮创建的URL,`$model`是当前要渲染的模型对象,并且 `$key` 是在数据提供者数组中模型的键。
在上面的代码中,`$url` 是列为按钮创建的URL,`$model`是当前要渲染的模型对象,
并且 `$key` 是在数据提供者数组中模型的键。
- [[yii\grid\ActionColumn::urlCreator|urlCreator]] 是使用指定的模型信息来创建一个按钮URL的回调函数。
该回调的原型和 [[yii\grid\ActionColumn::createUrl()]] 是一样的。
假如这个属性没有设置,按钮的URL将使用 [[yii\grid\ActionColumn::createUrl()]] 来创建。
该回调的原型和 [[yii\grid\ActionColumn::createUrl()]] 是一样的。
假如这个属性没有设置,按钮的URL将使用 [[yii\grid\ActionColumn::createUrl()]] 来创建。
- [[yii\grid\ActionColumn::visibleButtons|visibleButtons]] is an array of visibility conditions for each button.
The array keys are the button names (without curly brackets), and the values are the boolean true/false or the
anonymous function. When the button name is not specified in this array it will be shown by default.
The callbacks must use the following signature:
```php
function ($model, $key, $index) {
return $model->status === 'editable';
}
```
Or you can pass a boolean value:
```php
[
'update' => \Yii::$app->user->can('update')
]
```
#### 复选框列
@ -291,8 +308,8 @@ echo GridView::widget([
],
```
用户可点击复选框来选择网格中的一些行。被选择的行可通过调用下面的JavaScript代码来获得:
用户可点击复选框来选择网格中的一些行。被选择的行可通过调用下面的
JavaScript代码来获得:
```javascript
var keys = $('#grid').yiiGridView('getSelectedRows');
@ -322,11 +339,12 @@ echo GridView::widget([
### 数据过滤
为了过滤数据的 GridView 需要一个模型 [model](structure-models.md) 来 从过滤表单接收数据,以及调整数据提供者的查询对象,以满足搜索条件。
为了过滤数据的 GridView 需要一个模型 [model](structure-models.md) 来
从过滤表单接收数据,以及调整数据提供者的查询对象,以满足搜索条件。
使用活动记录 [active records](db-active-record.md) 时,通常的做法是
创建一个能够提供所需功能的搜索模型类(可以使用 [Gii](start-gii.md) 来生成)。
这个类为搜索定义了验证规则并且提供了一个将会返回数据提供者对象`search()` 方法。
这个类为搜索定义了验证规则并且提供了一个将会返回数据提供者对象
`search()` 方法。
为了给 `Post` 模型增加搜索能力,我们可以像下面的例子一样创建 `PostSearch` 模型:
@ -377,9 +395,11 @@ class PostSearch extends Post
return $dataProvider;
}
}
```
> Tip: See [Query Builder](db-query-builder.md) and especially [Filter Conditions](db-query-builder.md#filter-conditions)
> to learn how to build filtering query.
你可以在控制器中使用如下方法为网格视图获取数据提供者:
```php
@ -404,18 +424,95 @@ echo GridView::widget([
]);
```
### Separate filter form
### 处理关系型模型
Most of the time using GridView header filters is enough, but in case you need a separate filter form,
you can easily add it as well. You can create partial view `_search.php` with the following contents:
当我们在一个网格视图中显示活动数据的时候,你可能会遇到这种情况,就是显示关联表的列的值,例如:发帖者的名字,而不是显示他的 `id`
`Post` 模型有一个关联的属性名(译者注: `Post` 模型中用 `hasOne` 定义 `getAuthor()` 函数)
`author` 并且作者模型(译者注:本例的作者模型是 `users` )有一个属性叫 `name`,那么你可以通过在 [[yii\grid\GridView::$columns]]
中定义属性名为 `author.name` 来处理。这时的网格视图能显示作者名了,但是默认是不支持按作者名排序和过滤的。
你需要调整上个章节介绍的 `PostSearch` 模型,以添加此功能。
```php
<?php
use yii\helpers\Html;
use yii\widgets\ActiveForm;
/* @var $this yii\web\View */
/* @var $model app\models\PostSearch */
/* @var $form yii\widgets\ActiveForm */
?>
<div class="post-search">
<?php $form = ActiveForm::begin([
'action' => ['index'],
'method' => 'get',
]); ?>
<?= $form->field($model, 'title') ?>
为了使关联列能够排序,你需要连接关系表,以及添加排序规则到数据提供者的排序组件中:
<?= $form->field($model, 'creation_date') ?>
<div class="form-group">
<?= Html::submitButton('Search', ['class' => 'btn btn-primary']) ?>
<?= Html::submitButton('Reset', ['class' => 'btn btn-default']) ?>
</div>
<?php ActiveForm::end(); ?>
</div>
```
and include it in `index.php` view like so:
```php
<?= $this->render('_search', ['model' => $searchModel]) ?>
```
> Note: if you use Gii to generate CRUD code, the separate filter form (`_search.php`) is generated by default,
but is commented in `index.php` view. Uncomment it and it's ready to use!
Separate filter form is useful when you need to filter by fields, that are not displayed in GridView
or for special filtering conditions, like date range. For filtering by date range we can add non DB attributes
`createdFrom` and `createdTo` to the search model:
```php
class PostSearch extends Post
{
/**
* @var string
*/
public $createdFrom;
/**
* @var string
*/
public $createdTo;
}
```
Extend query conditions in the `search()` method like so:
```php
$query->andFilterWhere(['>=', 'creation_date', $this->createdFrom])
->andFilterWhere(['<=', 'creation_date', $this->createdTo]);
```
And add the representative fields to the filter form:
```php
<?= $form->field($model, 'creationFrom') ?>
<?= $form->field($model, 'creationTo') ?>
```
### 处理关系型模型
当我们在一个网格视图中显示活动数据的时候,你可能会遇到这种情况,就是显示关联表的列的值,
例如:发帖者的名字,而不是显示他的 `id`。当 `Post` 模型有一个关联的属性名(译者注: `Post` 模型中用 `hasOne` 定义 `getAuthor()` 函数)
`author` 并且作者模型(译者注:本例的作者模型是 `users` )有一个属性叫 `name`
那么你可以通过在 [[yii\grid\GridView::$columns]] 中定义属性名为 `author.name` 来处理。
这时的网格视图能显示作者名了,但是默认是不支持按作者名排序和过滤的。
你需要调整上个章节介绍的 `PostSearch` 模型,以添加此功能。
为了使关联列能够排序,你需要连接关系表,
以及添加排序规则到数据提供者的排序组件中:
```php
$query = Post::find();
@ -426,6 +523,7 @@ $dataProvider = new ActiveDataProvider([
// 连接与 `users` 表相关联的 `author`
// 并将 `users` 表的别名设为 `author`
$query->joinWith(['author' => function($query) { $query->from(['author' => 'users']); }]);
// since version 2.0.7, the above line can be simplified to $query->joinWith('author AS author');
// 使得关联字段可以排序
$dataProvider->sort->attributes['author.name'] = [
'asc' => ['author.name' => SORT_ASC],
@ -461,14 +559,15 @@ $query->andFilterWhere(['LIKE', 'author.name', $this->getAttribute('author.name'
> 信息:在上面的代码中,我们使用相同的字符串作为关联名称和表别名;
> 然而,当你的表别名和关联名称不相同的时候,你得注意在哪使用你的别名,在哪使用你的关联名称。
> 一个简单的规则是在每个构建数据库查询的地方使用别名,而在所有其他和定义相关的诸如:`attributes()` 和 `rules()` 等地方使用关联名称。
> 一个简单的规则是在每个构建数据库查询的地方使用别名,而在所有其他和定义相关的诸如:
>`attributes()` 和 `rules()` 等地方使用关联名称。
>
>例如,你使用 `au` 作为作者关系表的别名,那么联查语句就要写成像下面这样:
>
>
> 例如,你使用 `au` 作为作者关系表的别名,那么联查语句就要写成像下面这样:
>
> ```php
> $query->joinWith(['author' => function($query) { $query->from(['au' => 'users']); }]);
> ```
>$query->joinWith(['author' => function($query) { $query->from(['au' => 'users']); }]);
>```
>
> 当别名已经在关联函数中定义了时,也可以只调用 `$query->joinWith(['author']);`
>
> 在过滤条件中,别名必须使用,但属性名称保持不变:
@ -486,8 +585,8 @@ $query->andFilterWhere(['LIKE', 'author.name', $this->getAttribute('author.name'
> ];
> ```
>
> 同样,当指定使用 [[yii\data\Sort::defaultOrder|defaultOrder]] 来排序的时候,你需要使用关联名称替代别名:
>
> 同样,当指定使用 [[yii\data\Sort::defaultOrder|defaultOrder]] 来排序的时候,
>你需要使用关联名称替代别名:
>
> ```php
> $dataProvider->sort->defaultOrder = ['author.name' => SORT_ASC];
@ -568,12 +667,12 @@ class UserView extends ActiveRecord
### 单个页面多个网格视图部件
你可以在一个单独页面中使用多个网格视图,但是一些额外的配置是必须的,为的就是它们相互之间不干扰。
当使用多个网格视图实例的时候,你必须要为生成的排序和分页对象配置不同的参数名,以便于每个网格视图有它们各自独立的排序和分页。
你可以通过设置 [[yii\data\Sort::sortParam|sortParam]] 和 [[yii\data\Pagination::pageParam|pageParam]],对应于数据提供者的
[[yii\data\BaseDataProvider::$sort|sort]] 和 [[yii\data\BaseDataProvider::$pagination|pagination]] 实例。
当使用多个网格视图实例的时候,你必须要为生成的排序和分页对象配置不同的参数名,
以便于每个网格视图有它们各自独立的排序和分页。
你可以通过设置 [[yii\data\Sort::sortParam|sortParam]] 和
[[yii\data\Pagination::pageParam|pageParam]],对应于数据提供者的
[[yii\data\BaseDataProvider::$sort|sort]] 和
[[yii\data\BaseDataProvider::$pagination|pagination]] 实例。
假如我们想要同时显示 `Post``User` 模型,这两个模型已经在 `$userProvider``$postProvider` 这两个数据提供者中准备好,
具体做法如下:
@ -600,6 +699,44 @@ echo GridView::widget([
### Using GridView with Pjax
> 注意: 这部分正在开发中。
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 to update only the
[[yii\grid\GridView|GridView]] content when using filters.
```php
use yii\widgets\Pjax;
use yii\grid\GridView;
Pjax::begin([
// PJax options
]);
Gridview::widget([
// GridView options
]);
Pjax::end();
```
Pjax also works for the links inside the [[yii\widgets\Pjax|Pjax]] widget and
for the links specified by [[yii\widgets\Pjax::$linkSelector|Pjax::$linkSelector]].
But this might be a problem for the links of an [[yii\grid\ActionColumn|ActionColumn]].
To prevent this, add the HTML attribute `data-pjax="0"` to the links when you edit
the [[yii\grid\ActionColumn::$buttons|ActionColumn::$buttons]] property.
#### GridView/ListView with Pjax in Gii
Since 2.0.5, the CRUD generator of [Gii](start-gii.md) has an option called
`$enablePjax` that can be used via either web interface or command line.
```php
yii gii/crud --controllerClass="backend\\controllers\PostController" \
--modelClass="common\\models\\Post" \
--enablePjax=1
```
Which generates a [[yii\widgets\Pjax|Pjax]] widget wrapping the
[[yii\grid\GridView|GridView]] or [[yii\widgets\ListView|ListView]] widgets.
Further reading
---------------
待定
- [Rendering Data in Yii 2 with GridView and ListView](http://www.sitepoint.com/rendering-data-in-yii-2-with-gridview-and-listview/) by Arno Slatius.

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

@ -1,184 +1,229 @@
数据格式器
==============
Yii提供一个格式化类来格式化输出,以使输出数据对终端用户更友好易读,
[[yii\i18n\Formatter]] 是一个助手类,作为 [应用组件](structure-application-components.md) 使用,默认名为`formatter`。
它提供一些方法用来格式化数据,如日期/时间、数字或其他常用的本地化格式,
两种方式使用格式器:
1. 直接使用格式化方法(所有的格式器方法以 `as`做前缀):
```php
echo Yii::$app->formatter->asDate('2014-01-01', 'long'); // 输出: January 1, 2014
echo Yii::$app->formatter->asPercent(0.125, 2); // 输出: 12.50%
echo Yii::$app->formatter->asEmail('cebe@example.com'); // 输出: <a href="mailto:cebe@example.com">cebe@example.com</a>
echo Yii::$app->formatter->asBoolean(true); // 输出: Yes
// 也可处理null值的输出显示:
echo Yii::$app->formatter->asDate(null); // 输出: (Not set)
```
2. 使用 [[yii\i18n\Formatter::format()|format()]] 方法和格式化名,
该方法也被一些小部件如[[yii\grid\GridView]] 和 [[yii\widgets\DetailView]]使用,在小部件配置中可以指定列的数据格式。
```php
echo Yii::$app->formatter->format('2014-01-01', 'date'); // 输出: January 1, 2014
// 可使用数组来指定格式化方法的参数:
// `2` 是asPercent()方法的参数$decimals的值
echo Yii::$app->formatter->format(0.125, ['percent', 2]); // 输出: 12.50%
```
当[PHP intl extension](http://php.net/manual/en/book.intl.php)安装时,格式器的输出会本地化,
为此可配置格式器的 [[yii\i18n\Formatter::locale|locale]] 属性,如果没有配置,
应用配置 [[yii\base\Application::language|language]] 作为当前区域,更多详情参考 [国际化](tutorial-i18n.md)一节。
然后格式器根据当前区域为日期和数字选择正确的格式,包括月份和星期也会转换到当前语言,
日期格式也会被 [[yii\i18n\Formatter::timeZone|timeZone]] 参数影响,
该参数如果没有明确配置会使用应用的 [[yii\base\Application::timeZone|from the application]] 参数。
日期格式根据不同区域输出不同的结果,如下例所示:
For example the date format call will output different results for different locales:
To display data in a more readable format for users, you may format them using the `formatter` [application component](structure-application-components.md).
By default the formatter is implemented by [[yii\i18n\Formatter]] which provides a set of methods to format data as
date/time, numbers, currencies, and other commonly used formats. You can use the formatter like the following,
```php
Yii::$app->formatter->locale = 'en-US';
echo Yii::$app->formatter->asDate('2014-01-01'); // 输出: January 1, 2014
Yii::$app->formatter->locale = 'de-DE';
echo Yii::$app->formatter->asDate('2014-01-01'); // 输出: 1. Januar 2014
Yii::$app->formatter->locale = 'ru-RU';
echo Yii::$app->formatter->asDate('2014-01-01'); // 输出: 1 января 2014 г.
$formatter = \Yii::$app->formatter;
// output: January 1, 2014
echo $formatter->asDate('2014-01-01', 'long');
// output: 12.50%
echo $formatter->asPercent(0.125, 2);
// output: <a href="mailto:cebe@example.com">cebe@example.com</a>
echo $formatter->asEmail('cebe@example.com');
// output: Yes
echo $formatter->asBoolean(true);
// it also handles display of null values:
// output: (Not set)
echo $formatter->asDate(null);
```
> 注意不管[PHP intl extension](http://php.net/manual/en/book.intl.php)有没有安装,PHP编译的ICU库不同,格式化结果可能不同,
> 所以为确保不同环境下得到相同的输出,推荐在每个环境下安装PHP intl扩展以及相同的ICU库,
> 可参考: [为国际化设置PHP环境](tutorial-i18n.md#setup-environment).
As you can see, all these methods are named as `asXyz()`, where `Xyz` stands for a supported format. Alternatively,
you may format data using the generic method [[yii\i18n\Formatter::format()|format()]], which allows you to control
the desired format programmatically and is commonly used by widgets like [[yii\grid\GridView]] and [[yii\widgets\DetailView]].
For example,
```php
// output: January 1, 2014
echo Yii::$app->formatter->format('2014-01-01', 'date');
配置格式器 <span id="configuring-format"></span>
-------------------------
// you can also use an array to specify parameters for the format method:
// `2` is the value for the $decimals parameter of the asPercent()-method.
// output: 12.50%
echo Yii::$app->formatter->format(0.125, ['percent', 2]);
```
可配置[[yii\i18n\Formatter|formatter class]]的属性来调整格式器方法的默认格式,
可以在[应用主体配置](concept-configurations.md#application-configurations) 中配置 `formatter` 组件应用到整个项目,
配置样例如下所示,
更多关于可用属性的详情请参考 [[yii\i18n\Formatter|API documentation of the Formatter class]] 和接下来一小节。
> Note: The formatter component is designed to format values to be displayed for the end user. If you want
> to convert user input into machine readable format, or just format a date in a machine readable format,
> the formatter is not the right tool for that.
> To convert user input for date and number values you may use [[yii\validators\DateValidator]] and [[yii\validators\NumberValidator]]
> respectively. For simple conversion between machine readable date and time formats,
> the PHP [date()](http://php.net/manual/en/function.date.php)-function is enough.
## Configuring Formatter <span id="configuring-formatter"></span>
You may customize the formatting rules by configuring the `formatter` component in the [application configuration](concept-configurations.md#application-configurations).
For example,
```php
'components' => [
'formatter' => [
'dateFormat' => 'dd.MM.yyyy',
'decimalSeparator' => ',',
'thousandSeparator' => ' ',
'currencyCode' => 'EUR',
],
],
return [
'components' => [
'formatter' => [
'dateFormat' => 'dd.MM.yyyy',
'decimalSeparator' => ',',
'thousandSeparator' => ' ',
'currencyCode' => 'EUR',
],
],
];
```
格式化日期和时间 <span id="date-and-time"></span>
-------------------------------
Please refer to [[yii\i18n\Formatter]] for the properties that may be configured.
格式器类为格式化日期和时间提供了多个方法:
The formatter class provides different methods for formatting date and time values. These are:
- [[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 时间戳](http://en.wikipedia.org/wiki/Unix_time) 如 `1412609982`.
- [[yii\i18n\Formatter::asRelativeTime()|relativeTime]] - 值被格式化成和当前时间比较的时间间隔并用人们易读的格式,如`1 hour ago`.
## Formatting Date and Time Values <span id="date-and-time"></span>
可配置格式器的属性[[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]] 方法的日期和时间格式。
The formatter supports the following output formats that are related with date and time:
格式器默认会使用一个快捷格式,它根据当前启用的区域来解析,
这样日期和时间会格式化成用户国家和语言通用的格式,
有四种不同的快捷格式:
- [[yii\i18n\Formatter::asDate()|date]]: the value is formatted as a date, e.g. `January 01, 2014`.
- [[yii\i18n\Formatter::asTime()|time]]: the value is formatted as a time, e.g. `14:23`.
- [[yii\i18n\Formatter::asDatetime()|datetime]]: the value is formatted as date and time, e.g. `January 01, 2014 14:23`.
- [[yii\i18n\Formatter::asTimestamp()|timestamp]]: the value is formatted as a [unix timestamp](http://en.wikipedia.org/wiki/Unix_time), e.g. `1412609982`.
- [[yii\i18n\Formatter::asRelativeTime()|relativeTime]]: the value is formatted as the time interval between a date
and now in human readable form e.g. `1 hour ago`.
- [[yii\i18n\Formatter::asDuration()|duration]]: the value is formatted as a duration in human readable format. e.g. `1 day, 2 minutes`.
- `en_GB`区域的 `short` 会打印日期为 `06/10/2014`,时间为 `15:58`
- `medium` 会分别打印 `6 Oct 2014``15:58:42`,
- `long` 会分别打印 `6 October 2014``15:58:42 GMT`,
- `full` 会分别打印 `Monday, 6 October 2014``15:58:42 GMT`.
The default date and time formats used for the [[yii\i18n\Formatter::asDate()|date]], [[yii\i18n\Formatter::asTime()|time]],
and [[yii\i18n\Formatter::asDatetime()|datetime]] methods can be customized globally by configuring
[[yii\i18n\Formatter::dateFormat|dateFormat]], [[yii\i18n\Formatter::timeFormat|timeFormat]], and
[[yii\i18n\Formatter::datetimeFormat|datetimeFormat]].
另外你可使用[ICU 项目](http://site.icu-project.org/) 定义的语法来自定义格式,
ICU项目在该URL:<http://userguide.icu-project.org/formatparse/datetime>下的手册有介绍,
或者可使用PHP [date()](http://php.net/manual/de/function.date.php) 方法的语法字符串并加上前缀`php:`.
You can specify date and time formats using the [ICU syntax](http://userguide.icu-project.org/formatparse/datetime).
You can also use the [PHP date() syntax](http://php.net/manual/en/function.date.php) with a prefix `php:` to differentiate
it from ICU syntax. For example,
```php
// ICU 格式化
// ICU format
echo Yii::$app->formatter->asDate('now', 'yyyy-MM-dd'); // 2014-10-06
// PHP date()-格式化
// PHP date()-format
echo Yii::$app->formatter->asDate('now', 'php:Y-m-d'); // 2014-10-06
```
### 时区 <span id="time-zones"></span>
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`.
当格式化日期和时间时,Yii会将它们转换为对应的 [[yii\i18n\Formatter::timeZone|configured time zone]] 时区,
输入的值在没有指定时区时候会被当作UTC时间,因此,推荐存储所有的日期和时间为UTC而不是UNIX时间戳,UNIX通常也是UTC。
如果输入值所在的时区不同于UTC,时区应明确指定,如下所示:
Since version 2.0.7 it is also possible to format dates in different calendar systems.
Please refer to the API documentation of the formatters [[yii\i18n\Formatter::$calendar|$calendar]]-property on how to set a different calendar.
### Time Zones <span id="time-zones"></span>
When formatting date and time values, Yii will convert them to the target [[yii\i18n\Formatter::timeZone|time zone]].
The value being formatted is assumed to be in UTC, unless a time zone is explicitly given or you have configured
[[yii\i18n\Formatter::defaultTimeZone]].
In the following examples, we assume the target [[yii\i18n\Formatter::timeZone|time zone]] is set as `Europe/Berlin`.
```php
// 假定 Yii::$app->timeZone = 'Europe/Berlin';
// formatting a UNIX timestamp as a time
echo Yii::$app->formatter->asTime(1412599260); // 14:41:00
// formatting a datetime string (in UTC) as a time
echo Yii::$app->formatter->asTime('2014-10-06 12:41:00'); // 14:41:00
// formatting a datetime string (in CEST) as a time
echo Yii::$app->formatter->asTime('2014-10-06 14:41:00 CEST'); // 14:41:00
```
<<<<<<< .merge_file_a06508
> 注意:时区从属于全世界各国政府定的规则,可能会频繁的变更,因此你的系统的时区数据库可能不是最新的信息,
=======
> Note: 时区从属于全世界各国政府定的规则,可能会频繁的变更,因此你的系统的时区数据库可能不是最新的信息,
>>>>>>> .merge_file_a06028
> 可参考 [ICU manual](http://userguide.icu-project.org/datetime/timezone#TOC-Updating-the-Time-Zone-Data)
> 关于更新时区数据库的详情,
> 也可参考:[为国际化设置PHP环境](tutorial-i18n.md#setup-environment).
> Note: As time zones are subject to rules made by the governments around the world and may change frequently, it is
> likely that you do not have the latest information in the time zone database installed on your system.
> You may refer to the [ICU manual](http://userguide.icu-project.org/datetime/timezone#TOC-Updating-the-Time-Zone-Data)
> for details on updating the time zone database. Please also read
> [Setting up your PHP environment for internationalization](tutorial-i18n.md#setup-environment).
格式化数字 <span id="numbers"></span>
------------------
## Formatting Numbers <span id="numbers"></span>
格式器类提供如下方法格式化数值:
For formatting numeric values the formatter class provides the following methods:
The formatter supports the following output formats that are related with numbers:
- [[yii\i18n\Formatter::asInteger()|integer]] - 值被格式化成整型,如 `42`.
- [[yii\i18n\Formatter::asDecimal()|decimal]] - 值被格式化成十进制数字并带有小数位和千分位,如 `42.123`.
- [[yii\i18n\Formatter::asPercent()|percent]] - 值被格式化成百分率,如 `42%`.
- [[yii\i18n\Formatter::asScientific()|scientific]] - 值被格式化成科学计数型,如`4.2E4`.
- [[yii\i18n\Formatter::asCurrency()|currency]] - 值被格式化成货币格式,如 `£420.00`.
- [[yii\i18n\Formatter::asSize()|size]] - 字节值被格式化成易读的值,如 `410 kibibytes`.
- [[yii\i18n\Formatter::asInteger()|integer]]: the value is formatted as an integer e.g. `42`.
- [[yii\i18n\Formatter::asDecimal()|decimal]]: the value is formatted as a decimal number considering decimal and thousand
separators e.g. `2,542.123` or `2.542,123`.
- [[yii\i18n\Formatter::asPercent()|percent]]: the value is formatted as a percent number e.g. `42%`.
- [[yii\i18n\Formatter::asScientific()|scientific]]: the value is formatted as a number in scientific format e.g. `4.2E4`.
- [[yii\i18n\Formatter::asCurrency()|currency]]: the value is formatted as a currency value e.g. `£420.00`.
Note that for this function to work properly, the locale needs to include a country part e.g. `en_GB` or `en_US` because language only
would be ambiguous in this case.
- [[yii\i18n\Formatter::asSize()|size]]: the value that is a number of bytes is formatted as a human readable size e.g. `410 kibibytes`.
- [[yii\i18n\Formatter::asShortSize()|shortSize]]: is the short version of [[yii\i18n\Formatter::asSize()|size]], e.g. `410 KiB`.
可配置[[yii\i18n\Formatter::decimalSeparator|decimalSeparator]] 和 [[yii\i18n\Formatter::thousandSeparator|thousandSeparator]]
属性来调整数字格式化的格式,默认和当前区域相同。
The format for number formatting can be adjusted using the [[yii\i18n\Formatter::decimalSeparator|decimalSeparator]] and
[[yii\i18n\Formatter::thousandSeparator|thousandSeparator]], both of which take default values according to the
active [[yii\i18n\Formatter::locale|locale]].
更多高级配置, [[yii\i18n\Formatter::numberFormatterOptions]] 和 [[yii\i18n\Formatter::numberFormatterTextOptions]]
可用于配置内部使用 [Numberformatter class](http://php.net/manual/en/class.numberformatter.php)
为调整数字的小数部分的最大值和最小值,可配置如下属性:
For more advanced configuration, [[yii\i18n\Formatter::numberFormatterOptions]] and [[yii\i18n\Formatter::numberFormatterTextOptions]]
can be used to configure the [NumberFormatter class](http://php.net/manual/en/class.numberformatter.php) used internally
to implement the formatter. For example, to adjust the maximum and minimum value of fraction digits, you can configure
the [[yii\i18n\Formatter::numberFormatterOptions]] property like the following:
```php
[
'numberFormatterOptions' => [
NumberFormatter::MIN_FRACTION_DIGITS => 0,
NumberFormatter::MAX_FRACTION_DIGITS => 2,
]
```
其他格式器 <span id="other"></span>
----------------
除了日期、时间和数字格式化外,Yii提供其他用途提供一些实用的格式器:
Additional to date, time and number formatting, Yii provides a set of other useful formatters for different purposes:
- [[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]] - 值会格式化成图片标签;
- [[yii\i18n\Formatter::asUrl()|url]] - 值会格式化成超链接;
- [[yii\i18n\Formatter::asBoolean()|boolean]] - 值会格式化成布尔型值,默认情况下 `true` 对应 `Yes`,`false` 对应 `No`
可根据应用语言配置进行翻译,可以配置[[yii\i18n\Formatter::booleanFormat]]-属性来调整;
`null`-值 <span id="null-values"></span>
-------------
对于PHP的`null`值,格式器类会打印一个占位符而不是空字符串,空字符串默认会显示对应当前语言`(not set)`,
可配置[[yii\i18n\Formatter::nullDisplay|nullDisplay]]-属性配置一个自定义占位符,
如果对处理`null`值没有特殊要求,可设置[[yii\i18n\Formatter::nullDisplay|nullDisplay]] 为 `null`.
## Other Formats <span id="other"></span>
Besides date/time and number formats, Yii also supports other commonly used formats, including
- [[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 values are specially formatted. Instead of displaying an empty string, the formatter will convert it into a
preset string which defaults to `(not set)` translated into the current application language. You can configure the
[[yii\i18n\Formatter::nullDisplay|nullDisplay]] property to customize this string.
## Localizing Data Format <span id="localizing-data-format"></span>
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';
echo Yii::$app->formatter->asDate('2014-01-01'); // output: January 1, 2014
Yii::$app->formatter->locale = 'de-DE';
echo Yii::$app->formatter->asDate('2014-01-01'); // output: 1. Januar 2014
Yii::$app->formatter->locale = 'ru-RU';
echo Yii::$app->formatter->asDate('2014-01-01'); // output: 1 января 2014 г.
```
By default, the currently active [[yii\i18n\Formatter::locale|locale]] is determined by the value of
[[yii\base\Application::language]]. You may override it by setting the [[yii\i18n\Formatter::locale]] property explicitly.
> Note: The Yii formatter relies on the [PHP intl extension](http://php.net/manual/en/book.intl.php) to support
> localized data formatting. Because different versions of the ICU library compiled with PHP may cause different
> formatting results, it is recommended that you use the same ICU version for all your environments. For more details,
> please refer to [Setting up your PHP environment for internationalization](tutorial-i18n.md#setup-environment).
>
> If the intl extension is not installed, the data will not be localized.
>
> Note that for date values that are before year 1901 or after 2038, they will not be localized on 32-bit systems, even
> if the intl extension is installed. This is because in this case ICU is using 32-bit UNIX timestamps to date values.

85
docs/guide-zh-CN/output-pagination.md

@ -1,45 +1,72 @@
分页
==========
当一次要在一个页面上显示很多数据时,通过需要将其分为
几部分,每个部分都包含一些数据列表并且一次只显示一部分。这些部分在网页上被称为
分页。
当一次要在一个页面上显示很多数据时,通过需要将其分为几部分,每个部分都包含一些数据
列表并且一次只显示一部分。这些部分在网页上被称为 *分页*
如果你使用 [数据提供者](output-data-providers.md) 和 [数据小部件](output-data-widgets.md) 中之一,
分页已经自动为你整理。否则,你需要创建 [[\yii\data\Pagination]]
对象为其填充数据,例如 [[\yii\data\Pagination::$totalCount|总记录数]],
[[\yii\data\Pagination::$pageSize|每页数量]] 和 [[\yii\data\Pagination::$page|当前页码]],在
查询中使用它并且填充到 [[\yii\widgets\LinkPager|链接分页]]。
Yii uses a [[yii\data\Pagination]] object to represent the information about a pagination scheme. In particular,
* [[yii\data\Pagination::$totalCount|total count]] specifies the total number of data items. Note that this
is usually much more than the number of data items needed to display on a single page.
* [[yii\data\Pagination::$pageSize|page size]] specifies how many data items each page contains. The default
value is 20.
* [[yii\data\Pagination::$page|current page]] gives the current page number (zero-based). The default value
value is 0, meaning the first page.
首先在控制器的动作中,我们创建分页对象并且为其填充数据:
With a fully specified [[yii\data\Pagination]] object, you can retrieve and display data partially. For example,
if you are fetching data from a database, you can specify the `OFFSET` and `LIMIT` clause of the DB query with
the corresponding values provided by the pagination. Below is an example,
```php
function actionIndex()
{
$query = Article::find()->where(['status' => 1]);
$countQuery = clone $query;
$pages = new Pagination(['totalCount' => $countQuery->count()]);
$models = $query->offset($pages->offset)
->limit($pages->limit)
->all();
return $this->render('index', [
'models' => $models,
'pages' => $pages,
]);
}
use yii\data\Pagination;
// build a DB query to get all articles with status = 1
$query = Article::find()->where(['status' => 1]);
// get the total number of articles (but do not fetch the article data yet)
$count = $query->count();
// create a pagination object with the total count
$pagination = new Pagination(['totalCount' => $count]);
// limit the query using the pagination and retrieve the articles
$articles = $query->offset($pagination->offset)
->limit($pagination->limit)
->all();
```
其次在视图中我们输出的模板为当前页并通过分页对象链接到该页:
Which page of articles will be returned in the above example? It depends on whether a query parameter named `page`
is given. By default, the pagination will attempt to set the [[yii\data\Pagination::$page|current page]] to be
the value of the `page` parameter. If the parameter is not provided, then it will default to 0.
To facilitate building the UI element that supports pagination, Yii provides the [[yii\widgets\LinkPager]] widget
that displays a list of page buttons upon which users can click to indicate which page of data should be displayed.
The widget takes a pagination object so that it knows what is the current page and how many page buttons should
be displayed. For example,
```php
foreach ($models as $model) {
// 在这里显示 $model
}
use yii\widgets\LinkPager;
// 显示分页
echo LinkPager::widget([
'pagination' => $pages,
'pagination' => $pagination,
]);
```
If you want to build UI element manually, you may use [[yii\data\Pagination::createUrl()]] to create URLs that
would lead to different pages. The method requires a page parameter and will create a properly formatted URL
containing the page parameter. For example,
```php
// specifies the route that the URL to be created should use
// If you do not specify this, the currently requested route will be used
$pagination->route = 'article/index';
// displays: /index.php?r=article%2Findex&page=100
echo $pagination->createUrl(100);
// displays: /index.php?r=article%2Findex&page=101
echo $pagination->createUrl(101);
```
> Tip: You can customize the name of the `page` query parameter by configuring the
[[yii\data\Pagination::pageParam|pageParam]] property when creating the pagination object.

115
docs/guide-zh-CN/output-sorting.md

@ -1,56 +1,89 @@
排序
=======
有时显示数据会根据一个或多个属性进行排序。如果你正在使用
[数据提供者](output-data-providers.md) 和 [数据小部件](output-data-widgets.md) 中之一,排序
可以为你自动处理。否则,你应该创建一个 [[yii\data\Sort]] 实例,配置好后
将其应用到查询中。也可以传递给视图,可以在视图中通过某些属性创建链接来排序。
When displaying multiple rows of data, it is often needed that the data be sorted according to some columns
specified by end users. Yii uses a [[yii\data\Sort]] object to represent the information about a sorting schema.
In particular,
如下是一个典型的使用范例,
* [[yii\data\Sort::$attributes|attributes]] specifies the *attributes* by which the data can be sorted.
An attribute can be as simple as a [model attribute](structure-models.md#attributes). It can also be a composite
one by combining multiple model attributes or DB columns. More details will be given in the following.
* [[yii\data\Sort::$attributeOrders|attributeOrders]] gives the currently requested ordering directions for
each attribute.
* [[yii\data\Sort::$orders|orders]] gives the ordering directions in terms of the low-level columns.
To use [[yii\data\Sort]], first declare which attributes can be sorted. Then retrieve the currently requested
ordering information from [[yii\data\Sort::$attributeOrders|attributeOrders]] or [[yii\data\Sort::$orders|orders]]
and use them to customize the data query. For example,
```php
function actionIndex()
{
$sort = new Sort([
'attributes' => [
'age',
'name' => [
'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC],
'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC],
'default' => SORT_DESC,
'label' => 'Name',
],
use yii\data\Sort;
$sort = new Sort([
'attributes' => [
'age',
'name' => [
'asc' => ['first_name' => SORT_ASC, 'last_name' => SORT_ASC],
'desc' => ['first_name' => SORT_DESC, 'last_name' => SORT_DESC],
'default' => SORT_DESC,
'label' => 'Name',
],
]);
$models = Article::find()
->where(['status' => 1])
->orderBy($sort->orders)
->all();
return $this->render('index', [
'models' => $models,
'sort' => $sort,
]);
}
],
]);
$articles = Article::find()
->where(['status' => 1])
->orderBy($sort->orders)
->all();
```
在视图中:
In the above example, two attributes are declared for the [[yii\data\Sort|Sort]] object: `age` and `name`.
The `age` attribute is a *simple* attribute corresponding to the `age` attribute of the `Article` Active Record class.
It is equivalent to the following declaration:
```php
// 显示指向排序动作的链接
'age' => [
'asc' => ['age' => SORT_ASC],
'desc' => ['age' => SORT_DESC],
'default' => SORT_ASC,
'label' => Inflector::camel2words('age'),
]
```
The `name` attribute is a *composite* attribute defined by `first_name` and `last_name` of `Article`. It is declared
using the following array structure:
- The `asc` and `desc` elements specify how to sort by the attribute in ascending and descending directions, respectively.
Their values represent the actual columns and the directions by which the data should be sorted by. You can specify
one or multiple columns to indicate simple ordering or composite ordering.
- The `default` element specifies the direction by which the attribute should be sorted when initially requested.
It defaults to ascending order, meaning if it is not sorted before and you request to sort by this attribute,
the data will be sorted by this attribute in ascending order.
- The `label` element specifies what label should be used when calling [[yii\data\Sort::link()]] to create a sort link.
If not set, [[yii\helpers\Inflector::camel2words()]] will be called to generate a label from the attribute name.
Note that it will not be HTML-encoded.
> Info: You can directly feed the value of [[yii\data\Sort::$orders|orders]] to the database query to build
its `ORDER BY` clause. Do not use [[yii\data\Sort::$attributeOrders|attributeOrders]] because some of the
attributes may be composite and cannot be recognized by the database query.
You can call [[yii\data\Sort::link()]] to generate a hyperlink upon which end users can click to request sorting
the data by the specified attribute. You may also call [[yii\data\Sort::createUrl()]] to create a sortable URL.
For example,
```php
// specifies the route that the URL to be created should use
// If you do not specify this, the currently requested route will be used
$sort->route = 'article/index';
// display links leading to sort by name and age, respectively
echo $sort->link('name') . ' | ' . $sort->link('age');
foreach ($models as $model) {
// 在这里显示 $model
}
// displays: /index.php?r=article%2Findex&sort=age
echo $sort->createUrl('age');
```
以上,我们声明了支持了两个属性的排序:`name` 和 `age`
我们通过排序信息来查询以便于查询结果通过 Sort 对象
排序后更加准确有序。在视图中,我们通过相应的属性
展示了链接到页的两个超链接和数据排序。
[[yii\data\Sort|Sort]] 类将获得自动传递的请求参数
并相应地调整排序选项。
你可以通过配置 [[yii\data\Sort::$params|$params]] 属性来调整参数。
[[yii\data\Sort]] checks the `sort` query parameter to determine which attributes are being requested for sorting.
You may specify a default ordering via [[yii\data\Sort::defaultOrder]] when the query parameter is not present.
You may also customize the name of the query parameter by configuring the [[yii\data\Sort::sortParam|sortParam]] property.

12
docs/guide-zh-CN/output-theming.md

@ -10,12 +10,12 @@
- [[yii\base\Theme::basePath]]:指定包含主题资源(CSS, JS, images, 等等)的基准目录。
- [[yii\base\Theme::baseUrl]]:指定主题资源的基准URL。
- [[yii\base\Theme::pathMap]]:指定视图文件的替换规则。更多细节将在下面介绍。
例如,如果你在 `SiteController` 里面调用 `$this->render('about')`,那你将渲染视图文件 `@app/views/site/about.php`
然而,如果你在下面的应用配置中开启了主题功能,那么`@app/themes/basic/site/about.php` 文件将会被渲染。
- [[yii\base\Theme::pathMap]]:指定视图文件的替换规则。
更多细节将在下面介绍。
例如,如果你在 `SiteController` 里面调用 `$this->render('about')`,那你将渲染
视图文件 `@app/views/site/about.php` 。然而,如果你在下面的应用配置中开启了主
题功能,那么 `@app/themes/basic/site/about.php` 文件将会被渲染。
```php
return [
@ -34,7 +34,7 @@ return [
```
> 信息:主题支持路径别名。当我们在做视图替换的时候,
路径别名将被转换成实际的文件路径或者URL。
路径别名将被转换成实际的文件路径或者URL。
你可以通过 [[yii\base\View::theme]] 属性访问 [[yii\base\Theme]] 对象。例如,在一个视图文件里,你可以写下面的代码,
因为 `$this` 指向视图对象:

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

@ -1,19 +1,24 @@
认证
==============
和Web应用不同,RESTful APIs 通常是无状态的,也就意味着不应使用sessions 或 cookies,
和Web应用不同,RESTful APIs 通常是无状态的,
也就意味着不应使用sessions 或 cookies,
因此每个请求应附带某种授权凭证,因为用户授权状态可能没通过sessions 或 cookies维护,
常用的做法是每个请求都发送一个秘密的access token来认证用户,由于access token可以唯一识别和认证用户,
常用的做法是每个请求都发送一个秘密的access token来认证用户,
由于access token可以唯一识别和认证用户,
**API 请求应通过HTTPS来防止man-in-the-middle (MitM) 中间人攻击**.
下面有几种方式来发送access token:
* [HTTP 基本认证](http://en.wikipedia.org/wiki/Basic_access_authentication): access token
当作用户名发送,应用在access token可安全存在API使用端的场景,例如,API使用端是运行在一台服务器上的程序。
当作用户名发送,应用在access token可安全存在API使用端的场景,
例如,API使用端是运行在一台服务器上的程序。
* 请求参数: access token 当作API URL请求参数发送,例如
`https://example.com/users?access-token=xxxxxxxx`,由于大多数服务器都会保存请求参数到日志,
`https://example.com/users?access-token=xxxxxxxx`
由于大多数服务器都会保存请求参数到日志,
这种方式应主要用于`JSONP` 请求,因为它不能使用HTTP头来发送access token
* [OAuth 2](http://oauth.net/2/): 使用者从认证服务器上获取基于OAuth2协议的access token,然后通过
* [OAuth 2](http://oauth.net/2/): 使用者从认证服务器上获取基于
OAuth2协议的access token,然后通过
[HTTP Bearer Tokens](http://tools.ietf.org/html/rfc6750) 发送到API 服务器。
Yii 支持上述的认证方式,你也可很方便的创建新的认证方式。
@ -23,26 +28,25 @@ Yii 支持上述的认证方式,你也可很方便的创建新的认证方式
1. 配置`user` 应用组件:
- 设置 [[yii\web\User::enableSession|enableSession]] 属性为 `false`.
- 设置 [[yii\web\User::loginUrl|loginUrl]] 属性为`null` 显示一个HTTP 403 错误而不是跳转到登录界面.
2. 在你的REST 控制器类中配置`authenticator` 行为来指定使用哪种认证方式
2. 在你的REST 控制器类中配置`authenticator`
行为来指定使用哪种认证方式
3. 在你的[[yii\web\User::identityClass|user identity class]] 类中实现 [[yii\web\IdentityInterface::findIdentityByAccessToken()]] 方法.
步骤1不是必要的,但是推荐配置,因为RESTful APIs应为无状态的,当[[yii\web\User::enableSession|enableSession]]为false,
步骤1不是必要的,但是推荐配置,因为RESTful APIs应为无状态的,
当[[yii\web\User::enableSession|enableSession]]为false,
请求中的用户认证状态就不能通过session来保持,每个请求的认证通过步骤2和3来实现。
<<<<<<< .merge_file_a06500
> 提示: 如果你将RESTful APIs作为应用开发,可以设置应用配置中 `user` 组件的[[yii\web\User::enableSession|enableSession]],
=======
> Tip: 如果你将RESTful APIs作为应用开发,可以设置应用配置中 `user` 组件的[[yii\web\User::enableSession|enableSession]],
>>>>>>> .merge_file_a05220
如果将RESTful APIs作为模块开发,可以在模块的 `init()` 方法中增加如下代码,如下所示:
> 提示: 如果你将RESTful APIs作为应用开发,可以设置应用配置中
> `user` 组件的[[yii\web\User::enableSession|enableSession]],
> 如果将RESTful APIs作为模块开发,可以在模块的 `init()` 方法中增加如下代码,如下所示:
```php
public function init()
{
parent::init();
\Yii::$app->user->enableSession = false;
}
```
> ```php
> public function init()
> {
> parent::init();
> \Yii::$app->user->enableSession = false;
> }
> ```
例如,为使用HTTP Basic Auth,可配置`authenticator` 行为,如下所示:
@ -89,7 +93,6 @@ public function behaviors()
例如,一个简单的场景,当每个用户只有一个access token, 可存储access token 到user表的`access_token`列中,
方法可在`User`类中简单实现,如下所示:
```php
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
@ -103,22 +106,22 @@ class User extends ActiveRecord implements IdentityInterface
}
```
在上述认证启用后,对于每个API请求,请求控制器都会在它的`beforeAction()`步骤中对用户进行认证。
在上述认证启用后,对于每个API请求,请求控制器都会在它的`beforeAction()`
步骤中对用户进行认证。
如果认证成功,控制器再执行其他检查(如频率限制,操作权限),然后再执行操作,
授权用户信息可使用`Yii::$app->user->identity`获取.
如果认证失败,会发送一个HTTP状态码为401的响应,并带有其他相关信息头(如HTTP 基本认证会有`WWW-Authenticate` 头信息).
如果认证失败,会发送一个HTTP状态码为401的响应,并带有其他相关信息头
(如HTTP 基本认证会有`WWW-Authenticate` 头信息).
<<<<<<< .merge_file_a06500
## 授权 <a name="authorization"></a>
=======
## 授权 <span id="authorization"></span>
>>>>>>> .merge_file_a05220
在用户认证成功后,你可能想要检查他是否有权限执行对应的操作来获取资源,这个过程称为 *authorization*
在用户认证成功后,你可能想要检查他是否有权限执行对应的操作来获取资源,
这个过程称为 *authorization*
详情请参考 [Authorization section](security-authorization.md).
如果你的控制器从[[yii\rest\ActiveController]]类继承,可覆盖 [[yii\rest\Controller::checkAccess()|checkAccess()]] 方法
如果你的控制器从[[yii\rest\ActiveController]]类继承,
可覆盖 [[yii\rest\Controller::checkAccess()|checkAccess()]] 方法
来执行授权检查,该方法会被[[yii\rest\ActiveController]]内置的操作调用。

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

@ -1,14 +1,18 @@
控制器
===========
在创建资源类和指定资源格输出式化后,下一步就是创建控制器操作将资源通过RESTful APIs展现给终端用户。
在创建资源类和指定资源格输出式化后,下一步就是创建控制器操作将资源
通过RESTful APIs展现给终端用户。
Yii 提供两个控制器基类来简化创建RESTful 操作的工作:[[yii\rest\Controller]] 和 [[yii\rest\ActiveController]],
两个类的差别是后者提供一系列将资源处理成[Active Record](db-active-record.md)的操作。
因此如果使用[Active Record](db-active-record.md)内置的操作会比较方便,可考虑将控制器类
继承[[yii\rest\ActiveController]],它会让你用最少的代码完成强大的RESTful APIs.
Yii 提供两个控制器基类来简化创建RESTful 操作的工作:
[[yii\rest\Controller]] 和 [[yii\rest\ActiveController]],
两个类的差别是后者提供一系列将资源处理成[Active Record](db-active-record.md)
的操作。因此如果使用[Active Record](db-active-record.md)
内置的操作会比较方便,可考虑将控制器类继承[[yii\rest\ActiveController]],
它会让你用最少的代码完成强大的RESTful APIs.
[[yii\rest\Controller]] 和 [[yii\rest\ActiveController]] 提供以下功能,一些功能在后续章节详细描述:
[[yii\rest\Controller]] 和 [[yii\rest\ActiveController]] 提供以下功能,
一些功能在后续章节详细描述:
* HTTP 方法验证;
* [内容协商和数据格式化](rest-response-formatting.md);
@ -21,18 +25,17 @@ Yii 提供两个控制器基类来简化创建RESTful 操作的工作:[[yii\rest
* 对操作和资源进行用户认证.
<<<<<<< .merge_file_a00416
## 创建控制器类 <a name="creating-controller"></a>
=======
## 创建控制器类 <span id="creating-controller"></span>
>>>>>>> .merge_file_a02328
当创建一个新的控制器类,控制器类的命名最好使用资源名称的单数格式,例如,提供用户信息的控制器
当创建一个新的控制器类,控制器类的命名最好使用资源
名称的单数格式,例如,提供用户信息的控制器
可命名为`UserController`.
创建新的操作和Web应用中创建操作类似,唯一的差别是Web应用中调用`render()`方法渲染一个视图作为返回值,
对于RESTful操作直接返回数据,[[yii\rest\Controller::serializer|serializer]] 和
[[yii\web\Response|response object]] 会处理原始数据到请求格式的转换,例如
创建新的操作和Web应用中创建操作类似,唯一的差别是Web应用中
调用`render()`方法渲染一个视图作为返回值,对于RESTful操作
直接返回数据,[[yii\rest\Controller::serializer|serializer]] 和
[[yii\web\Response|response object]] 会处理原始数据到请求格式的转换,
例如
```php
public function actionView($id)
@ -42,24 +45,18 @@ public function actionView($id)
```
<<<<<<< .merge_file_a00416
## 过滤器 <a name="filters"></a>
=======
## 过滤器 <span id="filters"></span>
>>>>>>> .merge_file_a02328
[[yii\rest\Controller]]提供的大多数RESTful API功能通过[过滤器](structure-filters.md)实现.
特别是以下过滤器会按顺序执行:
* [[yii\filters\ContentNegotiator|contentNegotiator]]: 支持内容协商,在 [响应格式化](rest-response-formatting.md) 一节描述;
* [[yii\filters\VerbFilter|verbFilter]]: 支持HTTP 方法验证;
the [Authentication](rest-authentication.md) section;
<<<<<<< .merge_file_a00416
* [[yii\filters\AuthMethod|authenticator]]: 支持用户认证,在[认证](rest-authentication.md)一节描述;
=======
* [[yii\filters\auth\AuthMethod|authenticator]]: 支持用户认证,在[认证](rest-authentication.md)一节描述;
>>>>>>> .merge_file_a02328
* [[yii\filters\RateLimiter|rateLimiter]]: 支持频率限制,在[频率限制](rest-rate-limiting.md) 一节描述.
* [[yii\filters\ContentNegotiator|contentNegotiator]]: 支持内容协商,
在 [响应格式化](rest-response-formatting.md) 一节描述;
* [[yii\filters\VerbFilter|verbFilter]]: 支持HTTP 方法验证;the [Authentication](rest-authentication.md) section;
* [[yii\filters\auth\AuthMethod|authenticator]]: 支持用户认证,
在[认证](rest-authentication.md)一节描述;
* [[yii\filters\RateLimiter|rateLimiter]]: 支持频率限制,
在[频率限制](rest-rate-limiting.md) 一节描述.
这些过滤器都在[[yii\rest\Controller::behaviors()|behaviors()]]方法中声明,
可覆盖该方法来配置单独的过滤器,禁用某个或增加你自定义的过滤器。
@ -79,23 +76,14 @@ public function behaviors()
```
<<<<<<< .merge_file_a00416
## 继承 `ActiveController` <a name="extending-active-controller"></a>
如果你的控制器继承[[yii\rest\ActiveController]],应设置[[yii\rest\ActiveController::modelClass||modelClass]] 属性
为通过该控制器返回给用户的资源类名,该类必须继承[[yii\db\ActiveRecord]].
### 自定义操作 <a name="customizing-actions"></a>
=======
## 继承 `ActiveController` <span id="extending-active-controller"></span>
如果你的控制器继承[[yii\rest\ActiveController]],应设置[[yii\rest\ActiveController::modelClass|modelClass]] 属性
如果你的控制器继承[[yii\rest\ActiveController]],应设置
[[yii\rest\ActiveController::modelClass|modelClass]] 属性
为通过该控制器返回给用户的资源类名,该类必须继承[[yii\db\ActiveRecord]].
### 自定义操作 <span id="customizing-actions"></span>
>>>>>>> .merge_file_a02328
[[yii\rest\ActiveController]] 默认提供一下操作:
@ -132,24 +120,19 @@ public function prepareDataProvider()
请参考独立操作类的参考文档学习哪些配置项有用。
<<<<<<< .merge_file_a00416
### 执行访问检查 <a name="performing-access-check"></a>
=======
### 执行访问检查 <span id="performing-access-check"></span>
>>>>>>> .merge_file_a02328
通过RESTful APIs显示数据时,经常需要检查当前用户是否有权限访问和操作所请求的资源,
在[[yii\rest\ActiveController]]中,可覆盖[[yii\rest\ActiveController::checkAccess()|checkAccess()]]方法来完成权限检查。
在[[yii\rest\ActiveController]]中,可覆盖[[yii\rest\ActiveController::checkAccess()|checkAccess()]]
方法来完成权限检查。
```php
/**
* Checks the privilege of the current user. 检查当前用户的权限
* Checks the privilege of the current user.
*
* This method should be overridden to check whether the current user has the privilege
* to run the specified action against the specified data model.
* If the user does not have access, a [[ForbiddenHttpException]] should be thrown.
* 本方法应被覆盖来检查当前用户是否有权限执行指定的操作访问指定的数据模型
* 如果用户没有权限,应抛出一个[[ForbiddenHttpException]]异常
*
* @param string $action the ID of the action to be executed
* @param \yii\base\Model $model the model to be accessed. If null, it means no specific model is being accessed.
@ -158,16 +141,12 @@ public function prepareDataProvider()
*/
public function checkAccess($action, $model = null, $params = [])
{
// 检查用户能否访问 $action 和 $model
// 访问被拒绝应抛出ForbiddenHttpException
// check if the user can access $action and $model
// throw ForbiddenHttpException if access should be denied
}
```
`checkAccess()` 方法默认会被[[yii\rest\ActiveController]]默认操作所调用,如果创建新的操作并想执行权限检查,
应在新的操作中明确调用该方法。
<<<<<<< .merge_file_a00416
> 提示: 可使用[Role-Based Access Control (RBAC) 基于角色权限控制组件](security-authorization.md)实现`checkAccess()`。
=======
> Tip: 可使用[Role-Based Access Control (RBAC) 基于角色权限控制组件](security-authorization.md)实现`checkAccess()`。
>>>>>>> .merge_file_a02328

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

@ -1,7 +1,8 @@
错误处理
==============
处理一个 RESTful API 请求时, 如果有一个用户请求错误或服务器发生意外时, 你可以简单地抛出一个异常来通知用户出错了。
处理一个 RESTful API 请求时, 如果有一个用户请求错误或服务器发生意外时,
你可以简单地抛出一个异常来通知用户出错了。
如果你能找出错误的原因 (例如,所请求的资源不存在),你应该
考虑抛出一个适当的HTTP状态代码的异常 (例如, [[yii\web\NotFoundHttpException]]
意味着一个404 HTTP状态代码)。 Yii 将通过HTTP状态码和文本
@ -16,7 +17,6 @@ Transfer-Encoding: chunked
Content-Type: application/json; charset=UTF-8
{
"type": "yii\\web\\NotFoundHttpException",
"name": "Not Found Exception",
"message": "The requested resource was not found.",
"code": 0,
@ -41,8 +41,6 @@ Content-Type: application/json; charset=UTF-8
* `422`: 数据验证失败 (例如,响应一个 `POST` 请求)。 请检查响应体内详细的错误消息。
* `429`: 请求过多。 由于限速请求被拒绝。
* `500`: 内部服务器错误。 这可能是由于内部程序错误引起的。
<<<<<<< .merge_file_a05756
=======
## 自定义错误响应 <span id="customizing-error-response"></span>
@ -94,4 +92,3 @@ return [
`suppress_response_code` 作为 `GET` 参数传递时,上面的代码
将重新按照自己定义的格式响应(无论失败还是成功)。
>>>>>>> .merge_file_a06412

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

@ -37,7 +37,8 @@ class UserController extends ActiveController
}
```
控制器类扩展自 [[yii\rest\ActiveController]]。通过指定 [[yii\rest\ActiveController::modelClass|modelClass]]
控制器类扩展自 [[yii\rest\ActiveController]]。通过指定
[[yii\rest\ActiveController::modelClass|modelClass]]
作为 `app\models\User`, 控制器就能知道使用哪个模型去获取和处理数据。
@ -60,8 +61,6 @@ class UserController extends ActiveController
用户的数据就能通过美化的 URL 和有意义的 http 动词进行访问和操作。
<<<<<<< .merge_file_a05804
=======
## 启用 JSON 输入 <span id="enabling-json-input"></span>
为了使 API 接收 JSON 格式的输入数据,配置 `request` 应用程序组件的 [[yii\web\Request::$parsers|parsers]]
@ -79,7 +78,6 @@ class UserController extends ActiveController
`application/x-www-form-urlencoded``multipart/form-data` 输入格式。
>>>>>>> .merge_file_a05620
## 尝试 <span id="trying-it-out"></span>
随着以上所做的最小的努力,你已经完成了创建用于访问用户数据
@ -95,28 +93,16 @@ class UserController extends ActiveController
* `OPTIONS /users`: 显示关于末端 `/users` 支持的动词
* `OPTIONS /users/123`: 显示有关末端 `/users/123` 支持的动词
<<<<<<< .merge_file_a05804
> 补充:Yii 将在末端使用的控制器的名称自动变为复数。(译注:个人感觉这里应该变为注意)
你可以访问你的API用`curl`命令如下,
=======
> Info: Yii 将在末端使用的控制器的名称自动变为复数。(译注:个人感觉这里应该变为注意)
> 提示: Yii 将在末端使用的控制器的名称自动变为复数。(译注:个人感觉这里应该变为注意)
> 你可以用 [[yii\rest\UrlRule::$pluralize]]-属性来配置此项。
你可以访问你的API用 `curl` 命令如下,
>>>>>>> .merge_file_a05620
```
$ curl -i -H "Accept:application/json" "http://localhost/users"
HTTP/1.1 200 OK
<<<<<<< .merge_file_a05804
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
X-Powered-By: PHP/5.4.20
=======
...
>>>>>>> .merge_file_a05620
X-Pagination-Total-Count: 1000
X-Pagination-Page-Count: 50
X-Pagination-Current-Page: 1
@ -140,24 +126,14 @@ Content-Type: application/json; charset=UTF-8
]
```
<<<<<<< .merge_file_a05804
试着改变可接受的内容类型为`application/xml`,你会看到结果以 XML 格式返回:
=======
试着改变可接受的内容类型为`application/xml`,
你会看到结果以 XML 格式返回:
>>>>>>> .merge_file_a05620
```
$ curl -i -H "Accept:application/xml" "http://localhost/users"
HTTP/1.1 200 OK
<<<<<<< .merge_file_a05804
Date: Sun, 02 Mar 2014 05:31:43 GMT
Server: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y
X-Powered-By: PHP/5.4.20
=======
...
>>>>>>> .merge_file_a05620
X-Pagination-Total-Count: 1000
X-Pagination-Page-Count: 50
X-Pagination-Current-Page: 1
@ -182,9 +158,6 @@ Content-Type: application/xml
</response>
```
<<<<<<< .merge_file_a05804
> 技巧:你还可以通过 Web 浏览器中输入 URL `http://localhost/users` 来访问你的 API。
=======
以下命令将创建一个新的用户通过发送JSON格式的用户数据的 POST 请求:
```
@ -200,7 +173,6 @@ Content-Type: application/json; charset=UTF-8
```
> Tip: 你还可以通过 Web 浏览器中输入 URL `http://localhost/users` 来访问你的 API。
>>>>>>> .merge_file_a05620
尽管如此,你可能需要一些浏览器插件来发送特定的 headers 请求。
如你所见,在 headers 响应,有关于总数,页数的信息,等等。
@ -211,11 +183,7 @@ Content-Type: application/json; charset=UTF-8
例如:URL `http://localhost/users?fields=id,email` 将只返回 `id``email` 字段。
<<<<<<< .merge_file_a05804
> 补充:你可能已经注意到了 `http://localhost/users` 的结果包括一些敏感字段,
=======
> Info: 你可能已经注意到了 `http://localhost/users` 的结果包括一些敏感字段,
>>>>>>> .merge_file_a05620
> 例如 `password_hash`, `auth_key` 你肯定不希望这些出现在你的 API 结果中。
> 你应该在 [响应格式](rest-response-formatting.md) 部分中过滤掉这些字段。
@ -231,10 +199,5 @@ Content-Type: application/json; charset=UTF-8
你可以使用 [[yii\rest\UrlRule]] 简化路由到你的 API 末端。
<<<<<<< .merge_file_a05804
为了方便维护你的WEB前端和后端,建议你开发接口作为一个单独的应用程序,虽然这不是必须的。
=======
为了方便维护你的WEB前端和后端,建议你开发接口作为一个单独的应用程序,
虽然这不是必须的。
>>>>>>> .merge_file_a05620

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

@ -1,20 +1,13 @@
速率限制
=============
<<<<<<< .merge_file_a04232
为防止滥用,你应该考虑增加速率限制到您的API。
例如,您可以限制每个用户的API的使用是在10分钟内最多100次的API调用。
如果一个用户同一个时间段内太多的请求被接收, 将返回响应状态代码 429 (这意味着过多的请求)。
=======
为防止滥用,你应该考虑增加速率限制到您的 API。
例如,您可以限制每个用户的 API 的使用是在 10 分钟内最多 100 次的 API 调用。
如果一个用户在规定的时间内太多的请求被接收,将返回响应状态代码 429 (这意味着过多的请求)。
>>>>>>> .merge_file_a03968
要启用速率限制, [[yii\web\User::identityClass|user identity class]] 应该实现 [[yii\filters\RateLimitInterface]].
这个接口需要实现以下三个方法:
<<<<<<< .merge_file_a04232
* `getRateLimit()`: 返回允许的请求的最大数目及时间,例如,`[100, 600]` 表示在600秒内最多100次的API调用。
* `loadAllowance()`: 返回剩余的允许的请求和相应的UNIX时间戳数
当最后一次速率限制检查时。
@ -25,22 +18,33 @@
的这两列值的读和保存。为了提高性能,你也可以
考虑使用缓存或NoSQL存储这些信息。
一旦 identity 实现所需的接口, Yii 会自动使用 [[yii\filters\RateLimiter]]
为 [[yii\rest\Controller]] 配置一个行为过滤器来执行速率限制检查。 如果速度超出限制
该速率限制器将抛出一个 [[yii\web\TooManyRequestsHttpException]]。 你可以在你的 REST
控制器类里配置速率限制,
=======
* `getRateLimit()`: 返回允许的请求的最大数目及时间,例如,`[100, 600]` 表示在 600 秒内最多 100 次的 API 调用。
* `loadAllowance()`: 返回剩余的允许的请求和最后一次速率限制检查时相应的 UNIX 时间戳数。
* `saveAllowance()`: 保存剩余的允许请求数和当前的 UNIX 时间戳。
Implementation in the `User` model could look like the following:
你可以在 user 表中使用两列来记录容差和时间戳信息。
`loadAllowance()``saveAllowance()` 可以通过实现对符合当前身份验证的用户的这两列值的读和保存。为了提高性能,你也可以
考虑使用缓存或 NoSQL 存储这些信息。
```php
public function getRateLimit($request, $action)
{
return [$this->rateLimit, 1]; // $rateLimit requests per second
}
public function loadAllowance($request, $action)
{
return [$this->allowance, $this->allowance_updated_at];
}
public function saveAllowance($request, $action, $allowance, $timestamp)
{
$this->allowance = $allowance;
$this->allowance_updated_at = $timestamp;
$this->save();
}
```
一旦 identity 实现所需的接口, Yii 会自动使用 [[yii\filters\RateLimiter]]为 [[yii\rest\Controller]]
配置一个行为过滤器来执行速率限制检查。 如果速度超出限制该速率限制器将抛出一个 [[yii\web\TooManyRequestsHttpException]]。
你可以在你的 REST 控制器类里配置速率限制,
一旦 identity 实现所需的接口, Yii 会自动使用 [[yii\filters\RateLimiter]]
为 [[yii\rest\Controller]] 配置一个行为过滤器来执行速率限制检查。如果速度超出限制,该速率限制器将抛出一个 [[yii\web\TooManyRequestsHttpException]]。你可以参考以下代码在你的 REST 控制器类里配置速率限制:
>>>>>>> .merge_file_a03968
你可以在 user 表中使用两列来记录容差和时间戳信息。`loadAllowance()` 和 `saveAllowance()` 可以通过实现对符合当前身份
验证的用户的这两列值的读和保存。为了提高性能,你也可以考虑使用缓存或 NoSQL 存储这些信息。
```php
public function behaviors()
@ -51,20 +55,12 @@ public function behaviors()
}
```
<<<<<<< .merge_file_a04232
当速率限制被激活,默认情况下每个响应将包含以下HTTP头发送
目前的速率限制信息:
=======
当速率限制被激活,默认情况下每个响应将包含以下 HTTP 头发送目前的速率限制信息:
>>>>>>> .merge_file_a03968
当速率限制被激活,默认情况下每个响应将包含以下 HTTP
头发送目前的速率限制信息:
* `X-Rate-Limit-Limit`: 同一个时间段所允许的请求的最大数目;
* `X-Rate-Limit-Remaining`: 在当前时间段内剩余的请求的数量;
* `X-Rate-Limit-Reset`: 为了得到最大请求数所等待的秒数。
<<<<<<< .merge_file_a04232
你可以禁用这些头信息通过配置 [[yii\filters\RateLimiter::enableRateLimitHeaders]] 为false,
=======
你可以禁用这些头信息通过配置 [[yii\filters\RateLimiter::enableRateLimitHeaders]] 为 false,
>>>>>>> .merge_file_a03968
就像在上面的代码示例所示。

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

@ -4,32 +4,35 @@
RESTful 的 API 都是关于访问和操作 *资源*,可将资源看成MVC模式中的
[模型](structure-models.md)
在如何代表一个资源没有固定的限定,在Yii中通常使用 [[yii\base\Model]] 或它的子类(如 [[yii\db\ActiveRecord]])
在如何代表一个资源没有固定的限定,在Yii中通常使用 [[yii\base\Model]]
或它的子类(如 [[yii\db\ActiveRecord]])
代表资源,是为以下原因:
* [[yii\base\Model]] 实现了 [[yii\base\Arrayable]] 接口,它允许你通过RESTful API自定义你想要公开的资源数据。
* [[yii\base\Model]] 支持 [输入验证](input-validation.md), 在你的RESTful API需要支持数据输入时非常有用。
* [[yii\db\ActiveRecord]] 提供了强大的数据库访问和操作方面的支持,如资源数据需要存到数据库它提供了完美的支持。
* [[yii\base\Model]] 实现了 [[yii\base\Arrayable]] 接口,它允许你通过RESTful API
自定义你想要公开的资源数据。
* [[yii\base\Model]] 支持 [输入验证](input-validation.md), 在你的RESTful API
需要支持数据输入时非常有用。
* [[yii\db\ActiveRecord]] 提供了强大的数据库访问和操作方面的支持,
如资源数据需要存到数据库它提供了完美的支持。
本节主要描述资源类如何从 [[yii\base\Model]] (或它的子类) 继承并指定哪些数据可通过RESTful API返回,如果资源类没有
本节主要描述资源类如何从 [[yii\base\Model]] (或它的子类)
继承并指定哪些数据可通过RESTful API返回,如果资源类没有
继承 [[yii\base\Model]] 会将它所有的公开成员变量返回。
<<<<<<< .merge_file_a01056
## 字段 <a name="fields"></a>
=======
## 字段 <span id="fields"></span>
>>>>>>> .merge_file_a06160
当RESTful API响应中包含一个资源时,该资源需要序列化成一个字符串。
Yii将这个过程分成两步,首先,资源会被[[yii\rest\Serializer]]转换成数组,
然后,该数组会通过[[yii\web\ResponseFormatterInterface|response formatters]]根据请求格式(如JSON, XML)被序列化成字符串。
然后,该数组会通过[[yii\web\ResponseFormatterInterface|response formatters]]
根据请求格式(如JSON, XML)被序列化成字符串。
当开发一个资源类时应重点关注第一步。
通过覆盖 [[yii\base\Model::fields()|fields()]] 和/或 [[yii\base\Model::extraFields()|extraFields()]] 方法,
通过覆盖 [[yii\base\Model::fields()|fields()]] 和/或
[[yii\base\Model::extraFields()|extraFields()]] 方法,
可指定资源中称为 *字段* 的数据放入展现数组中,两个方法的差别为前者指定默认包含到展现数组的字段集合,
后者指定由于终端用户的请求包含 `expand` 参数哪些额外的字段应被包含到展现数组,例如,
后者指定由于终端用户的请求包含 `expand` 参数哪些额外的字段应被包含到展现数组,
例如,
```
// 返回fields()方法中申明的所有字段
@ -46,21 +49,20 @@ http://localhost/users?fields=id,email&expand=profile
```
<<<<<<< .merge_file_a01056
### 覆盖 `fields()` 方法 <a name="overriding-fields"></a>
=======
### 覆盖 `fields()` 方法 <span id="overriding-fields"></span>
>>>>>>> .merge_file_a06160
[[yii\base\Model::fields()]] 默认返回模型的所有属性作为字段,
[[yii\db\ActiveRecord::fields()]] 只返回和数据表关联的属性作为字段。
可覆盖 `fields()` 方法来增加、删除、重命名、重定义字段,`fields()` 的返回值应为数组,数组的键为字段名
数组的值为对应的字段定义,可为属性名或返回对应的字段值的匿名函数,特殊情况下,如果字段名和属性名相同,
可覆盖 `fields()` 方法来增加、删除、重命名、重定义字段,`fields()` 的返回值应为数组,
数组的键为字段名数组的值为对应的字段定义,
可为属性名或返回对应的字段值的匿名函数,
特殊情况下,如果字段名和属性名相同,
可省略数组的键,例如
```php
// 明确列出每个字段,适用于你希望数据表或模型属性修改时不导致你的字段修改(保持后端API兼容性)
// 明确列出每个字段,适用于你希望数据表或模型属性
//修改时不导致你的字段修改(保持后端API兼容性)
public function fields()
{
return [
@ -75,7 +77,8 @@ public function fields()
];
}
// 过滤掉一些字段,适用于你希望继承父类实现同时你想屏蔽掉一些敏感字段
// 过滤掉一些字段,适用于你希望继承父类
//实现同时你想屏蔽掉一些敏感字段
public function fields()
{
$fields = parent::fields();
@ -87,23 +90,19 @@ public function fields()
}
```
<<<<<<< .merge_file_a01056
> 警告: 模型的所有属性默认会被包含到API结果中,应检查数据确保没包含敏感数据,如果有敏感数据,
> 应覆盖`fields()`过滤掉,在上述例子中,我们选择过滤掉 `auth_key`, `password_hash``password_reset_token`.
### 覆盖 `extraFields()` 方法 <a name="overriding-extra-fields"></a>
=======
> Warning: 模型的所有属性默认会被包含到API结果中,应检查数据确保没包含敏感数据,如果有敏感数据,
> 应覆盖`fields()`过滤掉,在上述例子中,我们选择过滤掉 `auth_key`, `password_hash``password_reset_token`.
> 警告: 模型的所有属性默认会被包含到API结果中,
> 应检查数据确保没包含敏感数据,如果有敏感数据,
> 应覆盖`fields()`过滤掉,在上述例子中,我们选择过滤掉 `auth_key`,
> `password_hash``password_reset_token`.
### 覆盖 `extraFields()` 方法 <span id="overriding-extra-fields"></span>
>>>>>>> .merge_file_a06160
[[yii\base\Model::extraFields()]] 默认返回空值,[[yii\db\ActiveRecord::extraFields()]] 返回和数据表关联的属性。
[[yii\base\Model::extraFields()]] 默认返回空值,[[yii\db\ActiveRecord::extraFields()]]
返回和数据表关联的属性。
`extraFields()` 返回的数据格式和 `fields()` 相同,一般`extraFields()` 主要用于指定哪些值为对象的字段,
`extraFields()` 返回的数据格式和 `fields()` 相同,一般`extraFields()`
主要用于指定哪些值为对象的字段,
例如,给定以下字段申明
```php
@ -135,17 +134,16 @@ public function extraFields()
```
<<<<<<< .merge_file_a01056
## 链接 <a name="links"></a>
=======
## 链接 <span id="links"></span>
>>>>>>> .merge_file_a06160
[HATEOAS](http://en.wikipedia.org/wiki/HATEOAS), 是Hypermedia as the Engine of Application State的缩写,
提升RESTful API 应返回允许终端用户访问的资源操作的信息,HATEOAS 的目的是在API中返回包含相关链接信息的资源数据。
[HATEOAS](http://en.wikipedia.org/wiki/HATEOAS), 是
Hypermedia as the Engine of Application State的缩写,
提升RESTful API 应返回允许终端用户访问的资源操作的信息,
HATEOAS 的目的是在API中返回包含相关链接信息的资源数据。
资源类通过实现[[yii\web\Linkable]] 接口来支持HATEOAS,该接口包含方法 [[yii\web\Linkable::getLinks()|getLinks()]] 来返回
[[yii\web\Link|links]] 列表,典型情况下应返回包含代表本资源对象URL的 `self` 链接,例如
资源类通过实现[[yii\web\Linkable]] 接口来支持HATEOAS,
该接口包含方法 [[yii\web\Linkable::getLinks()|getLinks()]] 来返回
[[yii\web\Link|links]] 列表,典型情况下应返回包含代表本资源对象URL的 `self` 链接,例如,
```php
use yii\db\ActiveRecord;
@ -164,7 +162,8 @@ class User extends ActiveRecord implements Linkable
}
```
当响应中返回一个`User` 对象,它会包含一个 `_links` 单元表示和用户相关的链接,例如
当响应中返回一个`User` 对象,它会包含一个 `_links`
单元表示和用户相关的链接,例如
```
{
@ -180,16 +179,14 @@ class User extends ActiveRecord implements Linkable
```
<<<<<<< .merge_file_a01056
## 集合 <a name="collections"></a>
=======
## 集合 <span id="collections"></span>
>>>>>>> .merge_file_a06160
资源对象可以组成 *集合*,每个集合包含一组相同类型的资源对象。
资源对象可以组成 *集合*,每个集合包含一组相同
类型的资源对象。
集合可被展现成数组,更多情况下展现成 [data providers](output-data-providers.md).
因为data providers支持资源的排序和分页,这个特性在 RESTful API 返回集合时也用到,例如This is because data providers support sorting and pagination
因为data providers支持资源的排序和分页,这个特性在 RESTful API 返回集合时也用到,
例如This is because data providers support sorting and pagination
如下操作返回post资源的data provider:
```php
@ -210,7 +207,8 @@ class PostController extends Controller
}
```
当在RESTful API响应中发送data provider 时, [[yii\rest\Serializer]] 会取出资源的当前页并组装成资源对象数组,
当在RESTful API响应中发送data provider 时, [[yii\rest\Serializer]]
会取出资源的当前页并组装成资源对象数组,
[[yii\rest\Serializer]] 也通过如下HTTP头包含页码信息:
* `X-Pagination-Total-Count`: 资源所有数量;

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

@ -9,13 +9,9 @@
2. 资源对象转换为数组, 如在 [Resources](rest-resources.md) 部分中所描述的。
通过 [[yii\rest\Serializer]] 来完成。
3. 通过内容协商步骤将数组转换成字符串。
<<<<<<< .merge_file_a03016
[yii\web\ResponseFormatterInterface|response formatters]] 通过
[yii\web\Response::formatters|response]] 应用程序组件来注册完成。
=======
[[yii\web\ResponseFormatterInterface|response formatters]] 通过
[[yii\web\Response::formatters|response]] 应用程序组件来注册完成。
>>>>>>> .merge_file_a05144
[[yii\web\Response::formatters|response]]
[应用程序组件]((structure-application-components.md))来注册完成。
## 内容协商 <span id="content-negotiation"></span>

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

@ -70,9 +70,23 @@
'extraPatterns' => [
'GET search' => 'search',
],
]
```
您可能已经注意到控制器ID`user`以复数形式出现在`users`末端。
这是因为 [[yii\rest\UrlRule]] 能够为他们使用的末端全自动复数化控制器ID。
您可以通过设置 [[yii\rest\UrlRule::pluralize]] 为false 来禁用此行为,如果您想
使用一些特殊的名字您可以通过配置 [[yii\rest\UrlRule::controller]] 属性。
您可能已经注意到控制器ID`user`以复数形式出现在`users`末端。这是因为 [[yii\rest\UrlRule]]
能够为他们使用的末端全自动复数化控制器ID。您可以通过设置 [[yii\rest\UrlRule::pluralize]]
为false 来禁用此行为,如果您想使用一些特殊的名字您可以通过配置 [[yii\rest\UrlRule::controller]] 属性。
> Info: The pluralization of controller IDs is done by [[yii\helpers\Inflector::pluralize()]]. The method respects
special pluralization rules. For example, the word `box` will be pluralized as `boxes` instead of `boxs`.
In case when the automatic pluralization does not meet your requirement, you may also configure the
[[yii\rest\UrlRule::controller]] property to explicitly specify how to map a name used in endpoint URLs to
a controller ID. For example, the following code maps the name `u` to the controller ID `user`.
```php
[
'class' => 'yii\rest\UrlRule',
'controller' => ['u' => 'user'],
]
```

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

@ -1,14 +1,18 @@
版本
==========
你的API应该是版本化的。不像你完全控制在客户端和服务器端Web应用程序代码, 对于API,您通常没有对API的客户端代码的控制权。
因此,应该尽可能的保持向后兼容性(BC),如果一些不能向后兼容的变化必须引入
APIs,你应该增加版本号。你可以参考[Semantic Versioning](http://semver.org/)
有关设计的API的版本号的详细信息。
A good API is *versioned*: changes and new features are implemented in new versions of the API instead of continually altering just one version. Unlike Web applications, with which you have full control of both the client-side and server-side
code, APIs are meant to be used by clients beyond your control. For this reason, backward
compatibility (BC) of the APIs should be maintained whenever possible. If a change that may break BC is necessary, you should introduce it in new version of the API, and bump up the version number. Existing clients can continue to use the old, working version of the API; and new or upgraded clients can get the new functionality in the new API version.
关于如何实现API版本,一个常见的做法是在API的URL中嵌入版本号。
例如,`http://example.com/v1/users`代表`/users`版本1的API. 另一种API版本化的方法最近用的非常多的是把版本号放入HTTP请求头,通常是通过`Accept`头,
如下:
> Tip: Refer to [Semantic Versioning](http://semver.org/)
for more information on designing API version numbers.
关于如何实现API版本,一个常见的做法是在API的URL中嵌入版本号。例如,`http://example.com/v1/users`代表`/users`版本1的API.
另一种API版本化的方法最近用的非常多的是把版本号放入HTTP请求头,通常是通过`Accept`头,如下:
Another method of API versioning,
which has gained momentum recently, is to put the version number in the HTTP request headers. This is typically done through the `Accept` header:
```
// 通过参数
@ -49,6 +53,7 @@ api/
models/
User.php
Post.php
Module.php
v2/
controllers/
UserController.php
@ -56,6 +61,7 @@ api/
models/
User.php
Post.php
Module.php
```
你的应用程序配置应该这样:

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

@ -1,32 +1,46 @@
启动引导(Bootstrapping)
=============
启动引导是指:在应用开始解析并处理新接受请求之前,一个预先准备环境的过程。启动引导会在两个地方具体进行:[入口脚本(Entry Script)](structure-entry-scripts.md)
启动引导是指:在应用开始解析并处理新接受请求之前,一个预先准备环境的过程。
启动引导会在两个地方具体进行:[入口脚本(Entry Script)](structure-entry-scripts.md)
和 [应用主体(application)](structure-applications.md)。
在[入口脚本](structure-entry-scripts.md)里,需注册各个类库的类文件自动加载器(Class Autoloader,简称自动加载器)。这主要包括通过其 `autoload.php` 文件加载的
Composer 自动加载器,以及通过 `Yii` 类加载的 Yii 自动加载器。之后,入口脚本会加载应用的
[配置(configuration)](concept-configurations.md)
并创建一个 [应用主体](structure-applications.md) 的实例。
在[入口脚本](structure-entry-scripts.md)里,需注册各个类库的类文件自动加载器(Class Autoloader,简称自动加载器)。
这主要包括通过其 `autoload.php` 文件加载的Composer 自动加载器,以及通过 `Yii` 类加载的 Yii 自动加载器。之后,
入口脚本会加载应用的[配置(configuration)](concept-configurations.md)并创建一个
[应用主体](structure-applications.md) 的实例。
在应用主体的构造函数中,会执行以下引导工作:
1. 调用 [[yii\base\Application::preInit()|preInit()]](预初始化)方法,配置一些高优先级的应用属性,比如 [[yii\base\Application::basePath|basePath]] 属性。
1. 调用 [[yii\base\Application::preInit()|preInit()]](预初始化)方法,配置一些高优先级的应用属性,
比如 [[yii\base\Application::basePath|basePath]] 属性。
2. 注册[[yii\base\Application::errorHandler|错误处理器(ErrorHandler)]]。
3. 通过给定的应用配置初始化应用的各属性。
4. 通过调用 [[yii\base\Application::init()|init()]](初始化)方法,它会顺次调用
[[yii\base\Application::bootstrap()|bootstrap()]] 从而运行引导组件。
- 加载扩展清单文件(extension manifest file) `vendor/yiisoft/extensions.php`
- 创建并运行各个扩展声明的 [引导组件(bootstrap components)](structure-extensions.md#bootstrapping-classes)。
- 创建并运行各个 [应用组件](structure-application-components.md) 以及在应用的 [Bootstrap 属性](structure-applications.md#bootstrap)中声明的各个
- 创建并运行各个扩展声明的
[引导组件(bootstrap components)](structure-extensions.md#bootstrapping-classes)。
- 创建并运行各个 [应用组件](structure-application-components.md)
以及在应用的 [Bootstrap 属性](structure-applications.md#bootstrap)中声明的各个
[模块(modules)组件](structure-modules.md)(如果有)。
因为引导工作必须在处理**每一次**请求之前都进行一遍,因此让该过程尽可能轻量化就异常重要,请尽可能地优化这一步骤。
因为引导工作必须在处理**每一次**请求之前都进行一遍,
因此让该过程尽可能轻量化就异常重要,请尽可能地优化这一步骤。
请尽量不要注册太多引导组件。只有他需要在 HTTP 请求处理的全部生命周期中都作用时才需要使用它。举一个用到它的范例:一个模块需要注册额外的 URL 解析规则,就应该把它列在应用的
[bootstrap 属性](structure-applications.md#bootstrap)之中,这样该 URL 解析规则才能在解析请求之前生效。(译注:换言之,为了性能需要,除了 URL
解析等少量操作之外,绝大多数组件都应该按需加载,而不是都放在引导过程中。)
请尽量不要注册太多引导组件。只有他需要在 HTTP 请求处理的全部生命周期中都作用时才需要使用它。
举一个用到它的范例:一个模块需要注册额外的 URL 解析规则,就应该把它列在应用的
[bootstrap 属性](structure-applications.md#bootstrap)之中,
这样该 URL 解析规则才能在解析请求之前生效。
(译注:换言之,为了性能需要,除了 URL 解析等少量操作之外,绝大多数组件都应该按需加载,而不是都放在引导过程中。)
在生产环境中,可以开启字节码缓存,比如 APC,来进一步最小化加载和解析 PHP 文件所需的时间。
在生产环境中,可以开启字节码缓存,比如 APC,
来进一步最小化加载和解析 PHP 文件所需的时间。
一些大型应用都包含有非常复杂的应用[配置](concept-configurations.md),它们会被分割到许多更小的配置文件中。此时,可以考虑将整个配置数组缓存起来,并在入口脚本创建应用实例之前直接从缓存中加载。
[PHP OPcache]: http://php.net/manual/en/intro.opcache.php
[APC]: http://php.net/manual/en/book.apc.php
一些大型应用都包含有非常复杂的应用[配置](concept-configurations.md),
它们会被分割到许多更小的配置文件中。
此时,可以考虑将整个配置数组缓存起来,
并在入口脚本创建应用实例之前直接从缓存中加载。

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

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

108
docs/guide-zh-CN/runtime-logging.md

@ -1,10 +1,10 @@
日志
=======
Yii提供了一个强大的日志框架,这个框架具有高度的可定制性和可扩展性。使用这个框架,你可以轻松地记录各种类型的消息,过滤它们,
Yii提供了一个强大的日志框架,这个框架具有高度的可定制性和可扩展性。使用这个框架,
你可以轻松地记录各种类型的消息,过滤它们,
并且将它们收集到不同的目标,诸如文件,数据库,邮件。
使用Yii日志框架涉及下面的几个步骤:
* 在你代码里的各个地方记录 [log messages](#log-messages);
@ -32,36 +32,36 @@ Yii提供了一个强大的日志框架,这个框架具有高度的可定制
Yii::trace('start calculating average revenue');
```
> 信息:日志消息可以是字符串,也可以是复杂的数据,诸如数组或者对象。[log targets](#log-targets) 的义务是正确处理日志消息
默认情况下,假如一条日志消息不是一个字符串,它将被导出为一个字符串,通过调用 [[yii\helpers\VarDumper::export()]]。
> 注意:日志消息可以是字符串,也可以是复杂的数据,诸如数组或者对象。
[log targets](#log-targets) 的义务是正确处理日志消息。默认情况下,
假如一条日志消息不是一个字符串,它将被导出为一个字符串,通过调用 [[yii\helpers\VarDumper::export()]]。
为了更好地组织和过滤日志消息,我们建议您为每个日志消息指定一个适当的类别。
您可以为类别选择一个分层命名方案,这将使得 [log targets](#log-targets) 在基于它们的分类来过滤消息变得更加容易。
一个简单而高效的命名方案是使用PHP魔术常量 `__METHOD__` 作为分类名称。这种方式也在Yii框架的核心代码中得到应用,
为了更好地组织和过滤日志消息,我们建议您为每个日志消息指定一个适当的类别。您可以为类别选择一个分层命名方案,
这将使得 [log targets](#log-targets) 在基于它们的分类来过滤消息变得更加容易。
一个简单而高效的命名方案是使用PHP魔术常量 `__METHOD__` 作为分类名称。
这种方式也在Yii框架的核心代码中得到应用,
例如,
```php
Yii::trace('start calculating average revenue', __METHOD__);
```
`__METHOD__` 常量计算值作为该常量出现的地方的方法名(完全限定的类名前缀)。例如,假如上面那行代码在这个方法内被调用,则它将等于字符串
`__METHOD__` 常量计算值作为该常量出现的地方的方法名(完全限定的类名前缀)。
例如,假如上面那行代码在这个方法内被调用,则它将等于字符串
`'app\controllers\RevenueController::calculate'`
> 信息:上面所描述的日志方法实际上是 [[yii\log\Logger|logger object]] 对象(一个通过表达式 `Yii::getLogger()` 可访问的单例)
的方法 [[yii\log\Logger::log()|log()]] 的一个快捷方式。当足够的消息被记录或者当应用结束时,日志对象将会调用一个 [[yii\log\Dispatcher|message dispatcher]]
> 注意:上面所描述的日志方法实际上是 [[yii\log\Logger|logger object]] 对象(一个通过表达式 `Yii::getLogger()` 可访问的单例)
的方法 [[yii\log\Logger::log()|log()]] 的一个快捷方式。当足够的消息被记录或者当应用结束时,
日志对象将会调用一个 [[yii\log\Dispatcher|message dispatcher]]
调度对象将已经记录的日志消息发送到已注册的 [log targets](#log-targets) 目标中。
## 日志目标 <span id="log-targets"></span>
一个日志目标是一个 [[yii\log\Target]] 类或者它的子类的实例。它将通过他们的严重层级和类别来过滤日志消息,然后将它们导出到一些媒介中。
例如,一个 [[yii\log\DbTarget|database target]] 目标导出已经过滤的日志消息到一个数据的表里面,而一个 [[yii\log\EmailTarget|email target]]
目标将日志消息导出到指定的邮箱地址里。
一个日志目标是一个 [[yii\log\Target]] 类或者它的子类的实例。
它将通过他们的严重层级和类别来过滤日志消息,然后将它们导出到一些媒介中。
例如,一个 [[yii\log\DbTarget|database target]] 目标导出已经过滤的日志消息到一个数据的表里面,
而一个 [[yii\log\EmailTarget|email target]]目标将日志消息导出到指定的邮箱地址里。
在一个应用里,通过配置在应用配置里的 `log` [application component](structure-application-components.md) ,你可以注册多个日志目标。
就像下面这样:
@ -133,17 +133,17 @@ Yii配备了以下的内建日志目标。请参考关于这些类的API文档
[[yii\log\Target::categories|categories]] 属性是一个包含消息分类名称或者模式的数组。
一个目标将只处理那些在这个数组中能够找到对应的分类或者其中一个相匹配的模式的消息。
一个分类模式是一个以星号 `*` 结尾的分类名前缀。假如一个分类名与分类模式具有相同的前缀,那么该分类名将和分类模式相匹配。
例如,`yii\db\Command::execute` 和 `yii\db\Command::query` 都是作为分类名称运用在 [[yii\db\Command]] 类来记录日志消息的。
一个分类模式是一个以星号 `*` 结尾的分类名前缀。假如一个分类名与分类模式具有相同的前缀,
那么该分类名将和分类模式相匹配。例如,
`yii\db\Command::execute``yii\db\Command::query` 都是作为分类名称运用在 [[yii\db\Command]] 类来记录日志消息的。
它们都是匹配模式 `yii\db\*`
假如你没有指定 [[yii\log\Target::categories|categories]] 属性,这意味着目标将会处理 *任何* 分类的消息。
假如你没有指定 [[yii\log\Target::categories|categories]] 属性,
这意味着目标将会处理 *任何* 分类的消息。
除了通过 [[yii\log\Target::categories|categories]] 属性设置白名单分类,你也可以通过 [[yii\log\Target::except|except]]
属性来设置某些分类作为黑名单。假如一条消息的分类在这个属性中被发现或者是匹配其中一个,那么它将不会在目标中被处理。
属性来设置某些分类作为黑名单。假如一条消息的分类在这个属性中被发现或者是匹配其中一个,
那么它将不会在目标中被处理。
在下面的目标配置中指明了目标应该只处理错误和警告消息,当分类的名称匹配 `yii\db\*` 或者是 `yii\web\HttpException:*` 的时候,
但是除了 `yii\web\HttpException:404`
@ -162,17 +162,17 @@ Yii配备了以下的内建日志目标。请参考关于这些类的API文档
]
```
> 信息:当一个HTTP异常通过 [error handler](runtime-handling-errors.md) 被捕获的时候,一个错误消息将以 `yii\web\HttpException:ErrorCode`
> 注意:当一个HTTP异常通过 [error handler](runtime-handling-errors.md) 被捕获的时候,一个错误消息将以 `yii\web\HttpException:ErrorCode`
这样的格式的分类名被记录下来。例如,[[yii\web\NotFoundHttpException]] 将会引发一个分类是 `yii\web\HttpException:404`
错误消息。
### 消息格式化 <span id="message-formatting"></span>
日志目标以某种格式导出过滤过的日志消息。例如,假如你安装一个 [[yii\log\FileTarget]] 类的日志目标,
日志目标以某种格式导出过滤过的日志消息。例如,
假如你安装一个 [[yii\log\FileTarget]] 类的日志目标,
你应该能找出一个日志消息类似下面的 `runtime/log/app.log` 文件:
```
2014-10-04 18:10:15 [::1][][-][trace][yii\base\Module::getModule] Loading module: debug
```
@ -200,10 +200,10 @@ Timestamp [IP address][User ID][Session ID][Severity Level][Category] Message Te
除了消息前缀以外,日志目标也可以追加一些上下文信息到每组日志消息中。
默认情况下,这些全局的PHP变量的值被包含在:`$_GET`, `$_POST`, `$_FILES`, `$_COOKIE`,`$_SESSION` 和 `$_SERVER` 中。
你可以通过配置 [[yii\log\Target::logVars]] 属性适应这个行为,这个属性是你想要通过日志目标包含的全局变量名称。
你可以通过配置 [[yii\log\Target::logVars]] 属性适应这个行为,
这个属性是你想要通过日志目标包含的全局变量名称。
举个例子,下面的日志目标配置指明了只有 `$_SERVER` 变量的值将被追加到日志消息中。
```php
[
'class' => 'yii\log\FileTarget',
@ -211,11 +211,11 @@ Timestamp [IP address][User ID][Session ID][Severity Level][Category] Message Te
]
```
你可以将 `logVars` 配置成一个空数组来完全禁止上下文信息包含。或者假如你想要实现你自己提供上下文信息的方式,
你可以将 `logVars` 配置成一个空数组来完全禁止上下文信息包含。
或者假如你想要实现你自己提供上下文信息的方式,
你可以重写 [[yii\log\Target::getContextMessage()]] 方法。
### 消息跟踪级别 <span id="trace-level"></span>
在开发的时候,通常希望看到每个日志消息来自哪里。这个是能够被实现的,通过配置 `log` 组件的 [[yii\log\Dispatcher::traceLevel|traceLevel]] 属性,
@ -234,22 +234,22 @@ return [
```
上面的应用配置设置了 [[yii\log\Dispatcher::traceLevel|traceLevel]] 的层级,假如 `YII_DEBUG` 开启则是3,否则是0。
这意味着,假如 `YII_DEBUG` 开启,每个日志消息在日志消息被记录的时候,将被追加最多3个调用堆栈层级;假如 `YII_DEBUG` 关闭,
这意味着,假如 `YII_DEBUG` 开启,每个日志消息在日志消息被记录的时候,
将被追加最多3个调用堆栈层级;假如 `YII_DEBUG` 关闭,
那么将没有调用堆栈信息被包含。
> 信息:获得调用堆栈信息并不是不重要。因此,你应该只在开发或者调试一个应用的时候使用这个特性。
> 注意:获得调用堆栈信息并不是不重要。因此,
你应该只在开发或者调试一个应用的时候使用这个特性。
### 消息刷新和导出 <span id="flushing-exporting"></span>
如上所述,通过 [[yii\log\Logger|logger object]] 对象,日志消息被保存在一个数组里。为了这个数组的内存消耗,
当数组积累了一定数量的日志消息,日志对象每次都将刷新被记录的消息到 [log targets](#log-targets) 中。
如上所述,通过 [[yii\log\Logger|logger object]] 对象,日志消息被保存在一个数组里。
为了这个数组的内存消耗,当数组积累了一定数量的日志消息,
日志对象每次都将刷新被记录的消息到 [log targets](#log-targets) 中。
你可以通过配置 `log` 组件的 [[yii\log\Dispatcher::flushInterval|flushInterval]] 属性来自定义数量:
```php
return [
'bootstrap' => ['log'],
@ -262,7 +262,7 @@ return [
];
```
> 信息:当应用结束的时候,消息刷新也会发生,这样才能确保日志目标能够接收完整的日志消息。
> 注意:当应用结束的时候,消息刷新也会发生,这样才能确保日志目标能够接收完整的日志消息。
当 [[yii\log\Logger|logger object]] 对象刷新日志消息到 [log targets](#log-targets) 的时候,它们并
不能立即获取导出的消息。相反,消息导出仅仅在一个日志目标累积了一定数量的过滤消息的时候才会发生。你可以通过配置
@ -277,11 +277,11 @@ return [
```
因为刷新和导出层级的设置,默认情况下,当你调用 `Yii::trace()` 或者任何其他的记录方法,你将不能在日志目标中立即看到日志消息。
这对于一些长期运行的控制台应用来说可能是一个问题。为了让每个日志消息在日志目标中能够立即出现,你应该设置 [[yii\log\Dispatcher::flushInterval|flushInterval]]
这对于一些长期运行的控制台应用来说可能是一个问题。为了让每个日志消息在日志目标中能够立即出现,
你应该设置 [[yii\log\Dispatcher::flushInterval|flushInterval]]
和 [[yii\log\Target::exportInterval|exportInterval]] 都为1,
就像下面这样:
```php
return [
'bootstrap' => ['log'],
@ -311,8 +311,8 @@ return [
Yii::$app->log->targets['file']->enabled = false;
```
上面的代码要求您将目标命名为 `file`,像下面展示的那样,`targets` 数组中使用使用字符串键:
上面的代码要求您将目标命名为 `file`,像下面展示的那样,
`targets` 数组中使用使用字符串键:
```php
return [
@ -335,20 +335,20 @@ return [
### 创建新的目标 <span id="new-targets"></span>
创建一个新的日志目标类非常地简单。你主要需要实现 [[yii\log\Target::export()]] 方法来发送 [[yii\log\Target::messages]] 数组的
内容到一个指定的媒体中。你可以调用 [[yii\log\Target::formatMessage()]] 方法去格式化每个消息。更多细节,你可以参考任何一个包含在Yii
发布版中的日志目标类
创建一个新的日志目标类非常地简单。你主要需要实现 [[yii\log\Target::export()]]
方法来发送 [[yii\log\Target::messages]] 数组的
内容到一个指定的媒体中。你可以调用 [[yii\log\Target::formatMessage()]] 方法去格式化每个消息
更多细节,你可以参考任何一个包含在Yii发布版中的日志目标类。
## 性能分析 <span id="performance-profiling"></span>
性能分析是一个特殊的消息记录类型,它通常用在测量某段代码块的时间,并且找出性能瓶颈是什么。举个例子,[[yii\db\Command]] 类
性能分析是一个特殊的消息记录类型,它通常用在测量某段代码块的时间,
并且找出性能瓶颈是什么。举个例子,[[yii\db\Command]] 类
使用性能分析找出每个数据库查询的时间。
为了使用性能分析,首先确定需要进行分析的代码块。然后像下面这样围住每个代码块:
为了使用性能分析,首先确定需要进行分析的代码块。
然后像下面这样围住每个代码块:
```php
\Yii::beginProfile('myBenchmark');
@ -379,6 +379,6 @@ return [
假如你漏掉 `\Yii::endProfile('block1')` 或者切换了 `\Yii::endProfile('block1')``\Yii::endProfile('block2')`
顺序,那么性能分析将不会工作。
对于每个被分析的代码块,一个带有严重程度 `profile` 的日志消息被记录。你可以配置一个 [log target](#log-targets) 去收集这些
对于每个被分析的代码块,一个带有严重程度 `profile` 的日志消息被记录。
你可以配置一个 [log target](#log-targets) 去收集这些
消息,并且导出他们。[Yii debugger](tool-debugger.md) 有一个内建的性能分析面板能够展示分析结果。

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

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

16
docs/guide-zh-CN/runtime-requests.md

@ -38,10 +38,10 @@ $name = $request->post('name', '');
直接访问 `$_GET``$_POST`
这使你更容易编写测试用例,因为你可以伪造数据来创建一个模拟请求组件。
当实现 [RESTful APIs](rest-quick-start.md) 接口的时候,你经常需要获取通过PUT, PATCH或者其他的 [request methods](#request-methods)
当实现 [RESTful APIs](rest-quick-start.md) 接口的时候,你经常需要获取通过PUT,
PATCH或者其他的 [request methods](#request-methods)
请求方法提交上来的参数。你可以通过调用 [[yii\web\Request::getBodyParam()]] 方法来获取这些参数。例如,
```php
$request = Yii::$app->request;
@ -118,16 +118,16 @@ if ($headers->has('User-Agent')) { /* 这是一个 User-Agent 头 */ }
* [[yii\web\Request::acceptableLanguages|acceptableLanguages]]:返回用户可接受的语言。
返回的语言是按照他们的偏好层次来排序的。第一个参数代表最优先的语言。
假如你的应用支持多语言,并且你想在终端用户最喜欢的语言中显示页面,那么你可以使用语言协商方法 [[yii\web\Request::getPreferredLanguage()]]。
这个方法通过 [[yii\web\Request::acceptableLanguages|acceptableLanguages]] 在你的应用中所支持的语言列表里进行比较筛选,返回最适合的语言。
假如你的应用支持多语言,并且你想在终端用户最喜欢的语言中显示页面,
那么你可以使用语言协商方法 [[yii\web\Request::getPreferredLanguage()]]。
这个方法通过 [[yii\web\Request::acceptableLanguages|acceptableLanguages]]
在你的应用中所支持的语言列表里进行比较筛选,返回最适合的语言。
> 提示:你也可以使用 [[yii\filters\ContentNegotiator|ContentNegotiator]] 过滤器进行动态确定哪些内容类型和语言应该在响应中使用。
> 提示:你也可以使用 [[yii\filters\ContentNegotiator|ContentNegotiator]]
过滤器进行动态确定哪些内容类型和语言应该在响应中使用。
这个过滤器实现了上面介绍的内容协商的属性和方法。
## 客户端信息 <span id="client-information"></span>
你可以通过 [[yii\web\Request::userHost|userHost]] 和 [[yii\web\Request::userIP|userIP]] 分别获取host name和客户机的IP地址,

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

@ -2,13 +2,11 @@
=========
当应用完成处理一个[请求](runtime-requests.md)后, 会生成一个[[yii\web\Response|response]]响应对象并发送给终端用户
响应对象包含的信息有HTTP状态码,HTTP头和主体内容等, 网页应用开发的最终目的本质上就是根据不同的请求构建这些响应对象。
响应对象包含的信息有HTTP状态码,HTTP头和主体内容等,
网页应用开发的最终目的本质上就是根据不同的请求构建这些响应对象。
<<<<<<< HEAD
在大多是情况下主要处理继承自 [[yii\web\Response]] 的 `response` [应用组件](structure-application-components.md),
=======
在大多数情况下主要处理继承自 [[yii\web\Response]] 的 `response` [应用组件](structure-application-components.md),
>>>>>>> yiichina/master
在大多数情况下主要处理继承自 [[yii\web\Response]] 的
`response` [应用组件](structure-application-components.md),
尽管如此,Yii也允许你创建你自己的响应对象并发送给终端用户,这方面后续会阐述。
在本节,将会描述如何构建响应和发送给终端用户。
@ -25,7 +23,8 @@
Yii::$app->response->statusCode = 200;
```
尽管如此,大多数情况下不需要明确设置状态码,因为 [[yii\web\Response::statusCode]] 状态码默认为200,
尽管如此,大多数情况下不需要明确设置状态码,
因为 [[yii\web\Response::statusCode]] 状态码默认为200,
如果需要指定请求失败,可抛出对应的HTTP异常,如下所示:
```php
@ -33,7 +32,8 @@ throw new \yii\web\NotFoundHttpException;
```
当[错误处理器](runtime-handling-errors.md) 捕获到一个异常,会从异常中提取状态码并赋值到响应,
对于上述的 [[yii\web\NotFoundHttpException]] 对应HTTP 404状态码,以下为Yii预定义的HTTP异常:
对于上述的 [[yii\web\NotFoundHttpException]] 对应HTTP 404状态码,
以下为Yii预定义的HTTP异常:
* [[yii\web\BadRequestHttpException]]: status code 400.
* [[yii\web\ConflictHttpException]]: status code 409.
@ -47,7 +47,8 @@ throw new \yii\web\NotFoundHttpException;
* [[yii\web\UnauthorizedHttpException]]: status code 401.
* [[yii\web\UnsupportedMediaTypeHttpException]]: status code 415.
如果想抛出的异常不在如上列表中,可创建一个[[yii\web\HttpException]]异常,带上状态码抛出,如下:
如果想抛出的异常不在如上列表中,可创建一个[[yii\web\HttpException]]异常,
带上状态码抛出,如下:
```php
throw new \yii\web\HttpException(402);
@ -56,7 +57,8 @@ throw new \yii\web\HttpException(402);
## HTTP 头部 <span id="http-headers"></span>
可在 `response` 组件中操控[[yii\web\Response::headers|header collection]]来发送HTTP头部信息,例如:
可在 `response` 组件中操控[[yii\web\Response::headers|header collection]]来发送HTTP头部信息,
例如:
```php
$headers = Yii::$app->response->headers;
@ -71,14 +73,16 @@ $headers->set('Pragma', 'no-cache');
$values = $headers->remove('Pragma');
```
> Info: 头名称是大小写敏感的,在[[yii\web\Response::send()]]方法调用前新注册的头信息并不会发送给用户。
> Info: 头名称是大小写敏感的,在[[yii\web\Response::send()]]
方法调用前新注册的头信息并不会发送给用户。
## 响应主体 <span id="response-body"></span>
大多是响应应有一个主体存放你想要显示给终端用户的内容。
如果已有格式化好的主体字符串,可赋值到响应的[[yii\web\Response::content]]属性,例如:
如果已有格式化好的主体字符串,可赋值到响应的[[yii\web\Response::content]]属性,
例如:
```php
Yii::$app->response->content = 'hello world!';
@ -101,8 +105,10 @@ Yii支持以下可直接使用的格式,每个实现了[[yii\web\ResponseForma
* [[yii\web\Response::FORMAT_XML|XML]]: 通过 [[yii\web\XmlResponseFormatter]]来实现.
* [[yii\web\Response::FORMAT_JSON|JSON]]: 通过 [[yii\web\JsonResponseFormatter]]来实现.
* [[yii\web\Response::FORMAT_JSONP|JSONP]]: 通过 [[yii\web\JsonResponseFormatter]]来实现.
* [[yii\web\Response::FORMAT_RAW|RAW]]: use this format if you want to send the response directly without applying any formatting.
上述响应主体可明确地被设置,但是在大多数情况下是通过 [操作](structure-controllers.md) 方法的返回值隐式地设置,常用场景如下所示:
上述响应主体可明确地被设置,但是在大多数情况下是通过 [操作](structure-controllers.md) 方法的返回值隐式地设置,
常用场景如下所示:
```php
public function actionIndex()
@ -111,9 +117,11 @@ public function actionIndex()
}
```
上述的 `index` 操作返回 `index` 视图渲染结果,返回值会被 `response` 组件格式化后发送给终端用户。
上述的 `index` 操作返回 `index` 视图渲染结果,
返回值会被 `response` 组件格式化后发送给终端用户。
因为响应格式默认为[[yii\web\Response::FORMAT_HTML|HTML]], 只需要在操作方法中返回一个字符串,
因为响应格式默认为[[yii\web\Response::FORMAT_HTML|HTML]],
只需要在操作方法中返回一个字符串,
如果想使用其他响应格式,应在返回数据前先设置格式,例如:
```php
@ -127,7 +135,8 @@ public function actionInfo()
}
```
如上所述,触雷使用默认的 `response` 应用组件,也可创建自己的响应对象并发送给终端用户,可在操作方法中返回该响应对象,如下所示:
如上所述,触雷使用默认的 `response` 应用组件,也可创建自己的响应对象并发送给终端用户,
可在操作方法中返回该响应对象,如下所示:
```php
public function actionInfo()
@ -144,15 +153,18 @@ public function actionInfo()
```
> Note: 如果创建你自己的响应对象,将不能在应用配置中设置 `response` 组件,尽管如此,
可使用 [依赖注入](concept-di-container.md) 应用通用配置到你新的响应对象。
可使用 [依赖注入](concept-di-container.md)
应用通用配置到你新的响应对象。
## 浏览器跳转 <span id="browser-redirection"></span>
浏览器跳转依赖于发送一个`Location` HTTP 头,因为该功能通常被使用,Yii提供对它提供了特别的支持。
浏览器跳转依赖于发送一个`Location` HTTP 头,
因为该功能通常被使用,Yii提供对它提供了特别的支持。
可调用[[yii\web\Response::redirect()]] 方法将用户浏览器跳转到一个URL地址,该方法设置合适的
带指定URL的 `Location` 头并返回它自己为响应对象,在操作的方法中,可调用缩写版[[yii\web\Controller::redirect()]],例如:
带指定URL的 `Location` 头并返回它自己为响应对象,
在操作的方法中,可调用缩写版[[yii\web\Controller::redirect()]],例如:
```php
public function actionOld()
@ -161,7 +173,8 @@ public function actionOld()
}
```
在如上代码中,操作的方法返回`redirect()` 方法的结果,如前所述,操作的方法返回的响应对象会被当总响应发送给终端用户。
在如上代码中,操作的方法返回`redirect()` 方法的结果,如前所述,
操作的方法返回的响应对象会被当总响应发送给终端用户。
除了操作方法外,可直接调用[[yii\web\Response::redirect()]] 再调用
[[yii\web\Response::send()]] 方法来确保没有其他内容追加到响应中。
@ -171,26 +184,31 @@ public function actionOld()
```
> Info: [[yii\web\Response::redirect()]] 方法默认会设置响应状态码为302,该状态码会告诉浏览器请求的资源
*临时* 放在另一个URI地址上,可传递一个301状态码告知浏览器请求的资源已经 *永久* 重定向到新的URId地址。
*临时* 放在另一个URI地址上,
可传递一个301状态码告知浏览器请求的资源已经 *永久* 重定向到新的URId地址。
如果当前请求为AJAX 请求,发送一个 `Location` 头不会自动使浏览器跳转,为解决这个问题,
如果当前请求为AJAX 请求,
发送一个 `Location` 头不会自动使浏览器跳转,为解决这个问题,
[[yii\web\Response::redirect()]] 方法设置一个值为要跳转的URL的`X-Redirect` 头,
在客户端可编写JavaScript 代码读取该头部值然后让浏览器跳转对应的URL。
> Info: Yii 配备了一个`yii.js` JavaScript 文件提供常用JavaScript功能,包括基于`X-Redirect`头的浏览器跳转,
因此,如果你使用该JavaScript 文件(通过[[yii\web\YiiAsset]] 资源包注册),就不需要编写AJAX跳转的代码。
因此,如果你使用该JavaScript 文件(通过[[yii\web\YiiAsset]] 资源包注册),
就不需要编写AJAX跳转的代码。
## 发送文件 <span id="sending-files"></span>
和浏览器跳转类似,文件发送是另一个依赖指定HTTP头的功能,Yii提供方法集合来支持各种文件发送需求,它们对HTTP头都有内置的支持。
和浏览器跳转类似,文件发送是另一个依赖指定HTTP头的功能,
Yii提供方法集合来支持各种文件发送需求,它们对HTTP头都有内置的支持。
* [[yii\web\Response::sendFile()]]: 发送一个已存在的文件到客户端
* [[yii\web\Response::sendContentAsFile()]]: 发送一个文本字符串作为文件到客户端
* [[yii\web\Response::sendStreamAsFile()]]: 发送一个已存在的文件流作为文件到客户端
这些方法都将响应对象作为返回值,如果要发送的文件非常大,应考虑使用
[[yii\web\Response::sendStreamAsFile()]] 因为它更节约内存,以下示例显示在控制器操作中如何发送文件:
[[yii\web\Response::sendStreamAsFile()]] 因为它更节约内存,
以下示例显示在控制器操作中如何发送文件:
```php
public function actionDownload()
@ -199,14 +217,17 @@ public function actionDownload()
}
```
如果不是在操作方法中调用文件发送方法,在后面还应调用 [[yii\web\Response::send()]] 没有其他内容追加到响应中。
如果不是在操作方法中调用文件发送方法,
在后面还应调用 [[yii\web\Response::send()]] 没有其他内容追加到响应中。
```php
\Yii::$app->response->sendFile('path/to/file.txt')->send();
```
一些浏览器提供特殊的名为*X-Sendfile*的文件发送功能,原理为将请求跳转到服务器上的文件,
Web应用可在服务器发送文件前结束,为使用该功能,可调用[[yii\web\Response::xSendFile()]],
一些浏览器提供特殊的名为*X-Sendfile*的文件发送功能,
原理为将请求跳转到服务器上的文件,
Web应用可在服务器发送文件前结束,为使用该功能,
可调用[[yii\web\Response::xSendFile()]],
如下简要列出一些常用Web服务器如何启用`X-Sendfile` 功能:
- Apache: [X-Sendfile](http://tn123.org/mod_xsendfile)
@ -218,7 +239,8 @@ Web应用可在服务器发送文件前结束,为使用该功能,可调用[[
## 发送响应 <span id="sending-response"></span>
在[[yii\web\Response::send()]] 方法调用前响应中的内容不会发送给用户,该方法默认在[[yii\base\Application::run()]]
在[[yii\web\Response::send()]] 方法调用前响应中的内容不会发送给用户,
该方法默认在[[yii\base\Application::run()]]
结尾自动调用,尽管如此,可以明确调用该方法强制立即发送响应。
[[yii\web\Response::send()]] 方法使用以下步骤来发送响应:
@ -234,4 +256,5 @@ Web应用可在服务器发送文件前结束,为使用该功能,可调用[[
一旦[[yii\web\Response::send()]] 方法被执行后,其他地方调用该方法会被忽略,
这意味着一旦响应发出后,就不能再追加其他内容。
如你所见[[yii\web\Response::send()]] 触发了几个实用的事件,通过响应这些事件可调整或包装响应。
如你所见[[yii\web\Response::send()]] 触发了几个实用的事件,
通过响应这些事件可调整或包装响应。

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

@ -2,26 +2,100 @@
=======
当[入口脚本](structure-entry-scripts.md)在调用 [[yii\web\Application::run()|run()]]
方法时,它进行的第一个操作就是解析输入的请求,然后实例化对应的[控制器操作](structure-controllers.md)处理这个请求。该过程就被称为**引导路由(routing)**。(译注:中文里既是动词也是名词)
方法时,它进行的第一个操作就是解析输入的请求,然后实例化对应的[控制器操作](structure-controllers.md)处理这个请求。
该过程就被称为**引导路由(routing)**。(译注:中文里既是动词也是名词)
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.
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:
```php
use yii\helpers\Url;
// Url::to() calls UrlManager::createUrl() to create a 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.
```
/index.php?r=post%2Fview&id=100
/index.php/post/100
/posts/100
```
## URL Formats <span id="url-formats"></span>
## 解析路由 <span id="resolving-route"></span>
The [[yii\web\UrlManager|URL manager]] supports two URL formats: the default URL format and the pretty URL format.
路由引导的第一步,是把传入请求解析为一个路由。如我们在 [控制器(Controllers)](structure-controllers.md#routes)
章节中所描述的那样,路由是一个用于定位控制器操作的地址。这个过程通过 `request` 应用组件的 [[yii\web\Request::resolve()|resolve()]]
方法实现,该方法会调用 [URL 管理器](runtime-url-handling.md) 进行实质上的请求解析工作。
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.
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.
默认情况下,传入请求会包含一个名为 `r``GET` 参数,它的值即被视为路由。但是如果启用
[[yii\web\UrlManager::enablePrettyUrl|美化 URL 功能]],那么在确定请求的路由时,就会进行更多处理。具体的细节请参考
[URL 的解析与生成](runtime-url-handling.md) 章节。
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.
## Routing <span id="routing"></span>
Routing involves two steps. In the first step, the incoming request is parsed into a route and the associated
query parameters. In the second step, a [controller action](structure-controllers.md#actions) corresponding to the parsed route
is created to handle the request.
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.
假使某路由最终实在无法被确定,那么 `request` 组件会抛出 [[yii\web\NotFoundHttpException]] 异常(译注:大名鼎鼎的 404)。
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).
Among the above steps, if any error occurs, a [[yii\web\NotFoundHttpException]] will be thrown, indicating
the failure of the routing process.
### 缺省路由 <span id="default-route"></span>
如果传入请求并没有提供一个具体的路由,(一般这种情况多为于对首页的请求)此时就会启用由
[[yii\web\Application::defaultRoute]] 属性所指定的缺省路由。该属性的默认值为 `site/index`,它指向 `site` 控制器的 `index`
[[yii\web\Application::defaultRoute]] 属性所指定的缺省路由。
该属性的默认值为 `site/index`,它指向 `site` 控制器的 `index`
操作。你可以像这样在应用配置中调整该属性的值:
```php
@ -45,25 +119,529 @@ return [
];
```
`catchAll` 属性需要传入一个数组做参数,该数组的第一个元素为路由,剩下的元素会(以名值对的形式)指定绑定于该操作的各个参数。
With the above configuration, the `site/offline` action will be used to handle all incoming requests.
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).
> Info: Debug panel on development environment will not work when this property is enabled
## Creating 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,
```php
use yii\helpers\Url;
// creates a URL to a route: /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
echo Url::to(['post/view', 'id' => 100]);
// creates an anchored 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
echo Url::to(['post/index'], true);
// creates an absolute URL using the https scheme: 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.
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:
- 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.
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`,
```php
use yii\helpers\Url;
// currently requested route: /index.php?r=admin%2Fpost%2Findex
echo Url::to(['']);
// a relative route with action ID only: /index.php?r=admin%2Fpost%2Findex
echo Url::to(['index']);
// a relative route: /index.php?r=admin%2Fpost%2Findex
echo Url::to(['post/index']);
// an absolute route: /index.php?r=post%2Findex
echo Url::to(['/post/index']);
// /index.php?r=post%2Findex assume the alias "@posts" is defined as "/post/index"
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.
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,
```php
use yii\helpers\Url;
// currently requested URL: /index.php?r=admin%2Fpost%2Findex
echo Url::to();
// an aliased URL: http://example.com
Yii::setAlias('@example', 'http://example.com/');
echo Url::to('@example');
// an absolute 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,
```php
use yii\helpers\Url;
// home page 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
echo Url::base();
// the canonical URL of the currently requested URL
// see https://en.wikipedia.org/wiki/Canonical_link_element
echo Url::canonical();
// remember the currently requested URL and retrieve it back in later requests
Url::remember();
echo Url::previous();
```
## Using Pretty URLs <span id="using-pretty-urls"></span>
To use pretty URLs, configure the `urlManager` component in the application configuration like the following:
```php
[
'components' => [
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => false,
'rules' => [
// ...
],
],
],
]
```
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`.
```php
[
'posts' => 'post/index',
'post/<id:\d+>' => 'post/view',
]
```
> 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+)`.
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,
```php
[
// ...other url rules...
[
'pattern' => 'posts',
'route' => 'post/index',
'suffix' => '.json',
],
]
```
By default if you do not specify the `class` option for a rule configuration, it will take the default
class [[yii\web\UrlRule]].
当设置了 `catchAll` 属性时,它会替换掉所有从输入的请求中解析出来的路由。如果是上文的这种设置,用于处理所有传入请求的操作都会是相同的 `site/offline`
### 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.
> Note: You can only specify regular expressions for parameters. The rest part of a pattern is considered as plain text.
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:
```php
[
'posts/<year:\d{4}>/<category>' => 'post/index',
'posts' => 'post/index',
'post/<id:\d+>' => 'post/view',
]
```
When the rules are used to parse URLs:
- `/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.
And when the rules are used to create URLs:
- `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.
### Parameterizing Routes <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.
```php
[
'<controller:(post|comment)>/<id:\d+>/<action:(create|update|delete)>' => '<controller>/<action>',
'<controller:(post|comment)>/<id:\d+>' => '<controller>/view',
'<controller:(post|comment)>s' => '<controller>/index',
]
```
To parse a URL `/index.php/comment/100/create`, the first rule will apply, which sets the `controller` parameter to
be `comment` and `action` parameter to be `create`. The route `<controller>/<action>` is thus resolved as `comment/create`.
Similarly, to create a URL for the route `comment/index`, the third rule will apply, which creates a URL `/index.php/comments`.
> 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]].
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.
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',
'defaults' => ['page' => 1, 'tag' => ''],
],
]
```
The above rule can be used to parse or create any of the following URLs:
* `/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'`.
Without using optional parameters, you would have to create 4 rules to achieve the same result.
### Rules with Server Names <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`.
```php
[
'http://admin.example.com/login' => 'admin/user/login',
'http://www.example.com/login' => 'site/login',
]
```
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`.
```php
[
'http://<language:\w+>.example.com/posts' => 'post/index',
]
```
> Note: Rules with server names should NOT include the subfolder of the entry script in their patterns. For example, if the application is under `http://www.example.com/sandbox/blog`, 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 application code.
### URL Suffixes <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:
```php
[
'components' => [
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => true,
'suffix' => '.html',
'rules' => [
// ...
],
],
],
]
```
The above configuration will allow the [[yii\web\UrlManager|URL manager]] to recognize requested URLs and also create
URLs with `.html` as their suffix.
> Tip: You may set `/` as the URL suffix so that the URLs all end with a slash.
> 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).
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
[
'components' => [
'urlManager' => [
'enablePrettyUrl' => true,
'showScriptName' => false,
'enableStrictParsing' => true,
'suffix' => '.html',
'rules' => [
// ...
[
'pattern' => 'posts',
'route' => 'post/index',
'suffix' => '.json',
],
],
],
],
]
```
### HTTP Methods <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/create`, while a request for `GET post/100` will be parsed into `post/view`.
```php
[
'PUT,POST post/<id:\d+>' => 'post/create',
'DELETE post/<id:\d+>' => 'post/delete',
'post/<id:\d+>' => 'post/view',
]
```
> Note: If a URL rule contains HTTP method(s) in its pattern, the rule will only be used for parsing purpose.
It will be skipped when the [[yii\web\UrlManager|URL manager]] is called to create URLs.
> 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 about developing RESTful APIs.
### Customizing Rules <span id="customizing-rules"></span>
In the previous examples, URL rules are mainly declared in terms of pattern-route pairs. This is a commonly used
shortcut format. In certain scenarios, you may want to customize a URL rule by configuring its other properties, such
as [[yii\web\UrlRule::suffix]]. This can be done by using a full configuration array to specify a rule. The following
example is extracted from the [URL Suffixes](#url-suffixes) subsection,
```php
[
// ...other url rules...
[
'pattern' => 'posts',
'route' => 'post/index',
'suffix' => '.json',
],
]
```
> Info: By default if you do not specify the `class` option for a rule configuration, it will take the default
class [[yii\web\UrlRule]].
### Adding Rules Dynamically <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. 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:
```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.
### Creating Rule Classes <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.
We can create the following URL rule class to solve this problem.
```php
namespace app\components;
use yii\web\UrlRuleInterface;
use yii\base\Object;
class CarUrlRule extends Object implements UrlRuleInterface
{
public function createUrl($manager, $route, $params)
{
if ($route === 'car/index') {
if (isset($params['manufacturer'], $params['model'])) {
return $params['manufacturer'] . '/' . $params['model'];
} elseif (isset($params['manufacturer'])) {
return $params['manufacturer'];
}
}
return false; // this rule does not apply
}
public function parseRequest($manager, $request)
{
$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]
}
return false; // this rule does not apply
}
}
```
And use the new rule class in the [[yii\web\UrlManager::rules]] configuration:
```php
[
// ...other rules...
[
'class' => 'app\components\CarUrlRule',
// ...configure other properties...
],
]
```
## 创建操作 <span id="creating-action"></span>
一旦请求路由被确定了,紧接着的步骤就是创建一个“操作(action)”对象,用以响应该路由。
## Performance Consideration <span id="performance-consideration"></span>
路由可以用里面的斜杠分割成多个组成片段,举个栗子,`site/index` 可以分解为 `site``index`
两部分。每个片段都是指向某一模块(Module)、控制器(Controller)或操作(action)的 ID。
When developing a complex Web application, it is important to optimize URL rules so that it takes less time to parse
requests and create URLs.
从路由的首个片段开始,应用会经过以下流程依次创建模块(如果有),控制器,以及操作:
By using parameterized routes, you may reduce the number of URL rules, which can significantly improve performance.
1. 设置应用主体为当前模块。
2. 检查当前模块的 [[yii\base\Module::controllerMap|controller map(控制器映射表)]] 是否包含当前 ID。如果是,会根据该表中的配置创建一个控制器对象,然后跳到步骤五执行该路由的后续片段。
3. 检查该 ID 是否指向当前模块中 [[yii\base\Module::modules|modules]] 属性里的模块列表中的一个模块。如果是,会根据该模块表中的配置创建一个模块对象,然后会以新创建的模块为环境,跳回步骤二解析下一段路由。
4. 将该 ID 视为控制器 ID,并创建控制器对象。用下个步骤解析路由里剩下的片段。
5. 控制器会在他的 [[yii\base\Controller::actions()|action map(操作映射表)]]里搜索当前 ID。如果找得到,它会根据该映射表中的配置创建一个操作对象;反之,控制器则会尝试创建一个与该 ID
相对应,由某个 action 方法所定义的行内操作(inline action)。
When parsing or creating URLs, [[yii\web\UrlManager|URL manager]] examines URL rules in the order they are declared.
Therefore, you may consider adjusting the order of the URL rules so that more specific and/or more commonly used rules are placed before less used ones.
在上面的步骤里,如果有任何错误发生,都会抛出 [[yii\web\NotFoundHttpException]],指出路由引导的过程失败了。
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.

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

@ -9,7 +9,8 @@ Sessions 和 Cookies
## Sessions <span id="sessions"></span>
和 [请求](runtime-requests.md) 和 [响应](runtime-responses.md)类似,
默认可通过为[[yii\web\Session]] 实例的`session` [应用组件](structure-application-components.md) 来访问sessions。
默认可通过为[[yii\web\Session]] 实例的`session`
[应用组件](structure-application-components.md) 来访问sessions。
### 开启和关闭 Sessions <span id="opening-closing-sessions"></span>
@ -38,7 +39,6 @@ $session->destroy();
### 访问Session数据 <span id="access-session-data"></span>
To access the data stored in session, you can do the following:
可使用如下方式访问session中的数据:
```php
@ -69,14 +69,12 @@ foreach ($session as $name => $value) ...
foreach ($_SESSION as $name => $value) ...
```
<<<<<<< .merge_file_a02856
> 补充: 当使用`session`组件访问session数据时候,如果session没有开启会自动开启,
=======
> Info: 当使用`session`组件访问session数据时候,如果session没有开启会自动开启,
>>>>>>> .merge_file_a01508
> 注意: 当使用`session`组件访问session数据时候,
如果session没有开启会自动开启,
这和通过`$_SESSION`不同,`$_SESSION`要求先执行`session_start()`。
当session数据为数组时,`session`组件会限制你直接修改数据中的单元项,例如:
当session数据为数组时,`session`组件会限制你直接修改数据中的单元项,
例如:
```php
$session = Yii::$app->session;
@ -121,30 +119,31 @@ $session['captcha.number'] = 5;
$session['captcha.lifetime'] = 3600;
```
为更好的性能和可读性,推荐最后一种方案,也就是不用存储session变量为数组,
为更好的性能和可读性,推荐最后一种方案,
也就是不用存储session变量为数组,
而是将每个数组项变成有相同键前缀的session变量。
### 自定义Session存储 <span id="custom-session-storage"></span>
[[yii\web\Session]] 类默认存储session数据为文件到服务器上,Yii提供以下session类实现不同的session存储方式:
[[yii\web\Session]] 类默认存储session数据为文件到服务器上,
Yii提供以下session类实现不同的session存储方式:
* [[yii\web\DbSession]]: 存储session数据在数据表中
* [[yii\web\CacheSession]]: 存储session数据到缓存中,缓存和配置中的[缓存组件](caching-data.md#cache-components)相关
* [[yii\redis\Session]]: 存储session数据到以[redis](http://redis.io/) 作为存储媒介中
* [[yii\mongodb\Session]]: 存储session数据到[MongoDB](http://www.mongodb.org/).
所有这些session类支持相同的API方法集,因此,切换到不同的session存储介质不需要修改项目使用session的代码。
所有这些session类支持相同的API方法集,因此,
切换到不同的session存储介质不需要修改项目使用session的代码。
<<<<<<< .merge_file_a02856
> 注意: 如果通过`$_SESSION`访问使用自定义存储介质的session,需要确保session已经用[[yii\web\Session::open()]] 开启,
=======
> Note: 如果通过`$_SESSION`访问使用自定义存储介质的session,需要确保session已经用[[yii\web\Session::open()]] 开启,
>>>>>>> .merge_file_a01508
> 注意: 如果通过`$_SESSION`访问使用自定义存储介质的session,
需要确保session已经用[[yii\web\Session::open()]] 开启,
这是因为在该方法中注册自定义session存储处理器。
学习如何配置和使用这些组件类请参考它们的API文档,如下为一个示例
显示如何在应用配置中配置[[yii\web\DbSession]]将数据表作为session存储介质。
显示如何在应用配置中配置[[yii\web\DbSession]]
将数据表作为session存储介质。
```php
return [
@ -175,18 +174,17 @@ CREATE TABLE session
- PostgreSQL: BYTEA
- MSSQL: BLOB
<<<<<<< .merge_file_a02856
> 注意: 根据php.ini 设置的 `session.hash_function`,你需要调整`id`列的长度,
=======
> Note: 根据 php.ini 设置的 `session.hash_function`,你需要调整`id`列的长度,
>>>>>>> .merge_file_a01508
例如,如果 `session.hash_function=sha256` ,应使用长度为64而不是40的char类型。
例如,如果 `session.hash_function=sha256`
应使用长度为64而不是40的char类型。
### Flash 数据 <span id="flash-data"></span>
Flash数据是一种特别的session数据,它一旦在某个请求中设置后,只会在下次请求中有效,然后该数据就会自动被删除。
常用于实现只需显示给终端用户一次的信息,如用户提交一个表单后显示确认信息。
Flash数据是一种特别的session数据,它一旦在某个请求中设置后,
只会在下次请求中有效,然后该数据就会自动被删除。
常用于实现只需显示给终端用户一次的信息,
如用户提交一个表单后显示确认信息。
可通过`session`应用组件设置或访问`session`,例如:
@ -226,22 +224,31 @@ $session->addFlash('alerts', 'You are promoted.');
$alerts = $session->getFlash('alerts');
```
<<<<<<< .merge_file_a02856
> 注意: 不要在相同名称的flash数据中使用[[yii\web\Session::setFlash()]] 的同时也使用[[yii\web\Session::addFlash()]],
=======
> Note: 不要在相同名称的flash数据中使用[[yii\web\Session::setFlash()]] 的同时也使用[[yii\web\Session::addFlash()]],
>>>>>>> .merge_file_a01508
因为后一个防范会自动将flash信息转换为数组以使新的flash数据可追加进来,因此,
当你调用[[yii\web\Session::getFlash()]]时,会发现有时获取到一个数组,有时获取到一个字符串,
当你调用[[yii\web\Session::getFlash()]]时,
会发现有时获取到一个数组,有时获取到一个字符串,
取决于你调用这两个方法的顺序。
> Tip: For displaying Flash messages you can use [[yii\bootstrap\Alert|bootstrap Alert]] widget in the following way:
>
> ```php
> echo Alert::widget([
> 'options' => ['class' => 'alert-info'],
> 'body' => Yii::$app->session->getFlash('postDeleted'),
> ]);
> ```
## Cookies <span id="cookies"></span>
Yii使用 [[yii\web\Cookie]]对象来代表每个cookie,[[yii\web\Request]] 和 [[yii\web\Response]]
通过名为'cookies'的属性维护一个cookie集合,前者的cookie 集合代表请求提交的cookies,
通过名为'cookies'的属性维护一个cookie集合,
前者的cookie 集合代表请求提交的cookies,
后者的cookie集合表示发送给用户的cookies。
The part of the application dealing with request and response directly is controller. Therefore, cookies should be
read and sent in controller.
### 读取 Cookies <span id="reading-cookies"></span>
@ -272,7 +279,6 @@ if (isset($cookies['language'])) ...
### 发送 Cookies <span id="sending-cookies"></span>
You can send cookies to end users using the following code:
可使用如下代码发送cookie到终端用户:
```php
@ -296,34 +302,27 @@ unset($cookies['language']);
[[yii\web\Cookie::domain|domain]], [[yii\web\Cookie::expire|expire]]
可配置这些属性到cookie中并添加到响应的cookie集合中。
<<<<<<< .merge_file_a02856
> 注意: 为安全起见[[yii\web\Cookie::httpOnly]] 被设置为true,这可减少客户端脚本访问受保护cookie(如果浏览器支持)的风险,
=======
> Note: 为安全起见[[yii\web\Cookie::httpOnly]] 被设置为true,这可减少客户端脚本访问受保护cookie(如果浏览器支持)的风险,
>>>>>>> .merge_file_a01508
> 注意: 为安全起见[[yii\web\Cookie::httpOnly]] 被设置为true,
这可减少客户端脚本访问受保护cookie(如果浏览器支持)的风险,
更多详情可阅读 [httpOnly wiki article](https://www.owasp.org/index.php/HttpOnly) for more details.
### Cookie验证 <span id="cookie-validation"></span>
在上两节中,当通过`request` 和 `response` 组件读取和发送cookie时,你会喜欢扩展的cookie验证的保障安全功能,它能
使cookie不被客户端修改。该功能通过给每个cookie签发一个哈希字符串来告知服务端cookie是否在客户端被修改,
在上两节中,当通过`request` 和 `response` 组件读取和发送cookie时,
你会喜欢扩展的cookie验证的保障安全功能,它能
使cookie不被客户端修改。该功能通过给每个cookie签发一个
哈希字符串来告知服务端cookie是否在客户端被修改,
如果被修改,通过`request`组件的[[yii\web\Request::cookies|cookie collection]]cookie集合访问不到该cookie。
<<<<<<< .merge_file_a02856
> 注意: Cookie验证只保护cookie值被修改,如果一个cookie验证失败,仍然可以通过`$_COOKIE`来访问该cookie,
=======
> Note: Cookie验证只保护cookie值被修改,如果一个cookie验证失败,仍然可以通过`$_COOKIE`来访问该cookie,
>>>>>>> .merge_file_a01508
> 注意: Cookie验证只保护cookie值被修改,如果一个cookie验证失败,
仍然可以通过`$_COOKIE`来访问该cookie,
因为这是第三方库对未通过cookie验证自定义的操作方式。
Cookie验证默认启用,可以设置[[yii\web\Request::enableCookieValidation]]属性为false来禁用它,尽管如此,我们强烈建议启用它。
Cookie验证默认启用,可以设置[[yii\web\Request::enableCookieValidation]]属性为false来禁用它,
尽管如此,我们强烈建议启用它。
<<<<<<< .merge_file_a02856
> 注意: 直接通过`$_COOKIE` 和 `setcookie()` 读取和发送的Cookie不会被验证。
=======
> Note: 直接通过`$_COOKIE` 和 `setcookie()` 读取和发送的Cookie不会被验证。
>>>>>>> .merge_file_a01508
当使用cookie验证,必须指定[[yii\web\Request::cookieValidationKey]],它是用来生成s上述的哈希值,
可通过在应用配置中配置`request` 组件。
@ -338,9 +337,5 @@ return [
];
```
<<<<<<< .merge_file_a02856
> 补充: [[yii\web\Request::cookieValidationKey|cookieValidationKey]] 对你的应用安全很重要,
=======
> Info: [[yii\web\Request::cookieValidationKey|cookieValidationKey]] 对你的应用安全很重要,
>>>>>>> .merge_file_a01508
应只被你信任的人知晓,请不要将它放入版本控制中。

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

@ -227,6 +227,9 @@ return [
],
];
```
> 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`.
`DbManager` 使用4个数据库表存放它的数据:
@ -300,6 +303,9 @@ 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`.
在用 `yii rbac/init` 执行了这个命令后,我们将得到下图所示的层次结构:
![Simple RBAC hierarchy](images/rbac-hierarchy-1.png "简单的 RBAC 层次结构示意图")

106
docs/guide-zh-CN/security-best-practices.md

@ -14,7 +14,9 @@
### 过滤输入
过滤输入的意思是,用户输入不应该认为是安全的,你需要总是验证你获得的输入值是在允许范围内。比如,我们假设 sorting 只能指定为 `title``created_at``status` 三个值,然后,这个值是由用户输入提供的,那么,最好在我们接收参数的时候,检查一下这个值是否是指定的范围。
过滤输入的意思是,用户输入不应该认为是安全的,你需要总是验证你获得的输入值是在允许范围内。
比如,我们假设 sorting 只能指定为 `title``created_at``status` 三个值,然后,这个值是由用户输入提供的,
那么,最好在我们接收参数的时候,检查一下这个值是否是指定的范围。
对于基本的 PHP 而言,上述做法类似如下:
```php
@ -29,8 +31,10 @@ if (!in_array($sortBy, ['title', 'created_at', 'status'])) {
### 转义输出
转义输出的意思是,根据我们使用数据的上下文环境,数据需要被转义。比如:在 HTML 上下文,你需要转义 `<`,`>` 之类的特殊字符。在 JavaScript 或者 SQL 中,也有其他的特殊含义的字符串需要被转义。
由于手动的给所用的输出转义容易出错,Yii 提供了大量的工具来在不同的上下文执行转义。
转义输出的意思是,根据我们使用数据的上下文环境,数据需要被转义。比如:在 HTML 上下文,
你需要转义 `<`,`>` 之类的特殊字符。在 JavaScript 或者 SQL 中,也有其他的特殊含义的字符串需要被转义。
由于手动的给所用的输出转义容易出错,
Yii 提供了大量的工具来在不同的上下文执行转义。
避免 SQL 注入
-----------------------
@ -49,11 +53,14 @@ $sql = "SELECT * FROM user WHERE username = '$username'";
SELECT * FROM user WHERE username = ''; DROP TABLE user; --'
```
这是一个合法的查询语句,并将会执行以空的用户名搜索用户操作,然后,删除 `user` 表。这极有可能导致网站出差,数据丢失。(你是否进行了规律的数据备份?)
这是一个合法的查询语句,并将会执行以空的用户名搜索用户操作,然后,删除 `user` 表。
这极有可能导致网站出差,数据丢失。(你是否进行了规律的数据备份?)
在 Yii 中,大部分的数据查询是通过 [Active Record](db-active-record.md) 进行的,而其是完全使用 PDO 预处理语句执行 SQL 查询的。在预处理语句中,上述示例中,构造 SQL 查询的场景是不可能发生的。
在 Yii 中,大部分的数据查询是通过 [Active Record](db-active-record.md) 进行的,
而其是完全使用 PDO 预处理语句执行 SQL 查询的。在预处理语句中,上述示例中,构造 SQL 查询的场景是不可能发生的。
有时,你仍需要使用 [raw queries](db-dao.md) 或者 [query builder](db-query-builder.md)。在这种情况下,你应该使用安全的方式传递参数。如果数据是提供给表列的值,最好使用预处理语句:
有时,你仍需要使用 [raw queries](db-dao.md) 或者 [query builder](db-query-builder.md)。
在这种情况下,你应该使用安全的方式传递参数。如果数据是提供给表列的值,最好使用预处理语句:
```php
// query builder
@ -83,7 +90,8 @@ function actionList($orderBy = null)
}
```
如果上述方法不行,表名或者列名应该被转义。 Yii 针对这种转义提供了一个特殊的语法,这样可以在所有支持的数据库都使用一套方案。
如果上述方法不行,表名或者列名应该被转义。 Yii 针对这种转义提供了一个特殊的语法,
这样可以在所有支持的数据库都使用一套方案。
```php
$sql = "SELECT COUNT([[$column]]) FROM {{table}}";
@ -92,10 +100,15 @@ $rowCount = $connection->createCommand($sql)->queryScalar();
你可以在 [Quoting Table and Column Names](db-dao.md#quoting-table-and-column-names) 中获取更多的语法细节。
防止 XSS 攻击
------------
XSS 或者跨站脚本发生在输出 HTML 到浏览器时,输出内容没有正确的转义。例如,如果用户可以输入其名称,那么他输入 `<script>alert('Hello!');</script>` 而非其名字 `Alexander`,所有输出没有转义直接输出用户名的页面都会执行 JavaScript 代码 `alert('Hello!');`,这会导致浏览器页面上出现一个警告弹出框。就具体的站点而言,除了这种无意义的警告输出外,这样的脚本可以以你的名义发送一些消息到后台,甚至执行一些银行交易行为。
XSS 或者跨站脚本发生在输出 HTML 到浏览器时,输出内容没有正确的转义。
例如,如果用户可以输入其名称,那么他输入 `<script>alert('Hello!');</script>` 而非其名字 `Alexander`
所有输出没有转义直接输出用户名的页面都会执行 JavaScript 代码 `alert('Hello!');`
这会导致浏览器页面上出现一个警告弹出框。就具体的站点而言,除了这种无意义的警告输出外,
这样的脚本可以以你的名义发送一些消息到后台,甚至执行一些银行交易行为。
避免 XSS 攻击在 Yii 中非常简单,有如下两种一般情况:
@ -104,6 +117,7 @@ XSS 或者跨站脚本发生在输出 HTML 到浏览器时,输出内容没有
如果你需要的是纯文本,你可以如下简单的转义:
```php
<?= \yii\helpers\Html::encode($username) ?>
```
@ -119,9 +133,13 @@ XSS 或者跨站脚本发生在输出 HTML 到浏览器时,输出内容没有
防止 CSRF 攻击
-------------
CSRF 是跨站请求伪造的缩写。这个攻击思想源自许多应用程序假设来自用户的浏览器请求是由用户自己产生的,而事实并非如此。
CSRF 是跨站请求伪造的缩写。这个攻击思想源自许多应用程序假设来自用户的浏览器请求是由用户自己产生的,
而事实并非如此。
比如说:`an.example.com` 站点有一个 `/logout` URL,当以 GET 请求访问时,登出用户。如果它是由用户自己操作的,那么一切都没有问题。但是,有一天坏人在一个用户经常访问的论坛发了一个 `<img src="http://an.example.com/logout">` 内容的帖子。浏览器无法辨别请求一个图片还是一个页面,所以,当用户打开含有上述标签的页面时,他将会从 `an.example.com` 登出。
比如说:`an.example.com` 站点有一个 `/logout` URL,当以 GET 请求访问时,
登出用户。如果它是由用户自己操作的,那么一切都没有问题。但是,
有一天坏人在一个用户经常访问的论坛发了一个 `<img src="http://an.example.com/logout">` 内容的帖子。
浏览器无法辨别请求一个图片还是一个页面,所以,当用户打开含有上述标签的页面时,他将会从 `an.example.com` 登出。
上面就是最原始的思想。有人可能会说,登出用户也不是什么严重问题,然而,我们发送一些 POST 数据其实也不是很麻烦的事情。
@ -130,18 +148,76 @@ CSRF 是跨站请求伪造的缩写。这个攻击思想源自许多应用程序
1. 遵循 HTTP 准则,比如 GET 不应该改变应用的状态。
2. 保证 Yii CSRF 保护开启。
Sometimes you need to disable CSRF validation per controller and/or action. It could be achieved by setting its property:
```php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public $enableCsrfValidation = false;
public function actionIndex()
{
// CSRF validation will not be applied to this and other actions
}
}
```
To disable CSRF validation per custom actions you can do:
```php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public function beforeAction($action)
{
// ...set `$this->enableCsrfValidation` here based on some conditions...
// call parent method that will check CSRF if such property is true.
return parent::beforeAction($action);
}
}
```
防止文件暴露
----------------------
默认的服务器 webroot 目录指向包含有 `index.php``web` 目录。在共享托管环境下,这样是不可能的,这样导致了所有的代码,配置,日志都在webroot目录。
默认的服务器 webroot 目录指向包含有 `index.php``web` 目录。在共享托管环境下,这样是不可能的,
这样导致了所有的代码,配置,日志都在webroot目录。
如果是这样,别忘了拒绝除了 `web` 目录以外的目录的访问权限。如果没法这样做,考虑将你的应用程序托管在其他地方。
如果是这样,别忘了拒绝除了 `web` 目录以外的目录的访问权限。
如果没法这样做,考虑将你的应用程序托管在其他地方。
在生产环境关闭调试信息和工具
-------------------------------------------
在调试模式下, Yii 展示了大量的错误信息,这样是对开发有用的。同样,这些调试信息对于攻击者而言也是方便其用于破解数据结构,配置值,以及你的部分代码。永远不要在生产模式下将你的 `index.php` 中的 `YII_DEBUG` 设置为 `true`
在调试模式下, Yii 展示了大量的错误信息,这样是对开发有用的。
同样,这些调试信息对于攻击者而言也是方便其用于破解数据结构,配置值,以及你的部分代码。
永远不要在生产模式下将你的 `index.php` 中的 `YII_DEBUG` 设置为 `true`
你同样也不应该在生产模式下开启 Gii。它可以被用于获取数据结构信息,
代码,以及简单的用 Gii 生成的代码覆盖你的代码。
调试工具栏同样也应该避免在生产环境出现,除非非常有必要。它将会暴露所有的应用和配置的详情信息。
如果你确定需要,反复确认其访问权限限定在你自己的 IP。
Using secure connection over TLS
--------------------------------
Yii provides features that rely on cookies and/or PHP sessions. These can be vulnerable in case your connection is
compromised. The risk is reduced if the app uses secure connection via TLS.
你同样也不应该在生产模式下开启 Gii。它可以被用于获取数据结构信息,代码,以及简单的用 Gii 生成的代码覆盖你的代码。
Please refer to your webserver documentation for instructions on how to configure it. You may also check example configs
provided by H5BP project:
调试工具栏同样也应该避免在生产环境出现,除非非常有必要。它将会暴露所有的应用和配置的详情信息。如果你确定需要,反复确认其访问权限限定在你自己的 IP。
- [Nginx](https://github.com/h5bp/server-configs-nginx)
- [Apache](https://github.com/h5bp/server-configs-apache).
- [IIS](https://github.com/h5bp/server-configs-iis).
- [Lighttpd](https://github.com/h5bp/server-configs-lighttpd).

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

@ -0,0 +1,66 @@
Cryptography
============
In this section we'll review the following security aspects:
- Generating random data
- Encryption and Decryption
- Confirming Data Integrity
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:
```php
$key = Yii::$app->getSecurity()->generateRandomString();
```
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):
```php
// $data and $secretKey are obtained from the form
$encryptedData = Yii::$app->getSecurity()->encryptByPassword($data, $secretKey);
// store $encryptedData to database
```
Subsequently when user wants to read the data:
```php
// $secretKey is obtained from user input, $encryptedData is from the database
$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()]].
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.
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
$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
$data = Yii::$app->getSecurity()->validateData($data, $secretKey);
```

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

@ -0,0 +1,14 @@
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.
* [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)

119
docs/guide-zh-CN/security-passwords.md

@ -1,19 +1,18 @@
处理密码
========
> 注意:本节内容正在开发中。
大部分开发者知道密码不能以明文形式存储,但是许多开发者仍认为使用 `md5` 或者 `sha1` 来哈希化密码是安全的。
一度,使用上述的哈希算法是足够安全的,但是,
现代硬件的发展使得短时间内暴力破解上述算法生成的哈希串成为可能。
好的安全策略对任何应用的健康和成功极其重要。不幸的是,许多开发者在遇到安全问题时,因为认识不够或者实现起来比较麻烦,都不是很注意细节。为了让你的 Yii 应用程序尽可能的安全, Yii 囊括了一些卓越并简单易用的安全特性。
密码的哈希与验证
-------------------------------
大部分开发者知道密码不能以明文形式存储,但是许多开发者仍认为使用 `md5` 或者 `sha1` 来哈希化密码是安全的。一度,使用上述的哈希算法是足够安全的,但是,现代硬件的发展使得短时间内暴力破解上述算法生成的哈希串成为可能。
为了即使在最糟糕的情况下(你的应用程序被破解了)也能给用户密码提供增强的安全性,你需要使用一个能够对抗暴力破解攻击的哈希算法。目前最好的选择是 `bcrypt`。在 PHP 中,你可以通过 [crypt 函数](http://php.net/manual/en/function.crypt.php) 生成 `bcrypt` 哈希。Yii 提供了两个帮助函数以让使用 `crypt` 来进行安全的哈希密码生成和验证更加容易。
为了即使在最糟糕的情况下(你的应用程序被破解了)也能给用户密码提供增强的安全性,
你需要使用一个能够对抗暴力破解攻击的哈希算法。目前最好的选择是 `bcrypt`。在 PHP 中,
你可以通过 [crypt 函数](http://php.net/manual/en/function.crypt.php) 生成 `bcrypt` 哈希。
Yii 提供了两个帮助函数以让使用 `crypt` 来进行安全的哈希密码生成和验证更加容易。
当一个用户为第一次使用,提供了一个密码时(比如:注册时),密码就需要被哈希化。
```php
$hash = Yii::$app->getSecurity()->generatePasswordHash($password);
```
@ -22,6 +21,7 @@ $hash = Yii::$app->getSecurity()->generatePasswordHash($password);
当一个用户尝试登录时,表单提交的密码需要使用之前的存储的哈希串来验证:
```php
if (Yii::$app->getSecurity()->validatePassword($password, $hash)) {
// all good, logging user in
@ -29,104 +29,3 @@ if (Yii::$app->getSecurity()->validatePassword($password, $hash)) {
// wrong password
}
```
生成伪随机数
-----------
伪随机数据在许多场景下都非常有用。比如当通过邮件重置密码时,你需要生成一个令牌,将其保存到数据库中,并通过邮件发送到终端用户那里以让其证明其对某个账号的所有权。这个令牌的唯一性和难猜解性非常重要,否则,就存在攻击者猜解令牌,并重置用户的密码的可能性。
Yii security helper makes generating pseudorandom data simple:
Yii 安全助手使得生成伪随机数据非常简单:
```php
$key = Yii::$app->getSecurity()->generateRandomString();
```
注意,你需要安装有 `openssl` 扩展,以生成密码的安全随机数据。
加密与解密
-------------------------
Yii 提供了方便的帮助函数来让你用一个安全秘钥来加密解密数据。数据通过加密函数进行传输,这样只有拥有安全秘钥的人才能解密。比如,我们需要存储一些信息到我们的数据库中,但是,我们需要保证只有拥有安全秘钥的人才能看到它(即使应用的数据库泄露)
```php
// $data and $secretKey are obtained from the form
$encryptedData = Yii::$app->getSecurity()->encryptByPassword($data, $secretKey);
// store $encryptedData to database
```
随后,当用户需要读取数据时:
```php
// $secretKey is obtained from user input, $encryptedData is from the database
$data = Yii::$app->getSecurity()->decryptByPassword($encryptedData, $secretKey);
```
校验数据完整性
--------------------------------
有时,你需要验证你的数据没有第三方篡改或者使用某种方式破坏了。Yii 通过两个帮助函数,提供了一个简单的方式来进行数据的完整性校验。
首先,将由安全秘钥和数据生成的哈希串前缀到数据上。
```php
// $secretKey our application or user secret, $genuineData obtained from a reliable source
$data = Yii::$app->getSecurity()->hashData($genuineData, $secretKey);
```
验证数据完整性是否被破坏了。
```php
// $secretKey our application or user secret, $data obtained from an unreliable source
$data = Yii::$app->getSecurity()->validateData($data, $secretKey);
```
todo: XSS 防范, CSRF 防范, Cookie 保护相关的内容,参考 1.1 文档
你同样可以给控制器或者 action 设置它的 `enableCsrfValidation` 属性来单独禁用 CSRF 验证。
```php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public $enableCsrfValidation = false;
public function actionIndex()
{
// CSRF validation will not be applied to this and other actions
}
}
```
为了给某个定制的 action 关闭 CSRF 验证,你可以:
```php
namespace app\controllers;
use yii\web\Controller;
class SiteController extends Controller
{
public function beforeAction($action)
{
// ...set `$this->enableCsrfValidation` here based on some conditions...
// call parent method that will check CSRF if such property is true.
return parent::beforeAction($action);
}
}
```
安全 Cookie
----------------
- validation
- httpOnly is default
参考
--------
- [Views security](structure-views.md#security)

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

@ -1,7 +1,10 @@
使用数据库
======================
本章节将介绍如何如何创建一个从数据表 `country` 中读取国家数据并显示出来的页面。为了实现这个目标,你将会配置一个数据库连接,创建一个[活动记录](db-active-record.md)类,并且创建一个[操作](structure-controllers.md)及一个[视图](structure-views.md)。
本章节将介绍如何如何创建一个从数据表 `country` 中读取国家数据并显示出来的页面。
为了实现这个目标,你将会配置一个数据库连接,创建一个[活动记录](db-active-record.md)类,
并且创建一个[操作](structure-controllers.md)及一个[视图](structure-views.md)。
贯穿整个章节,你将会学到:
@ -10,13 +13,15 @@
* 使用活动记录从数据库中查询数据
* 以分页方式在视图中显示数据
请注意,为了掌握本章你应该具备最基本的数据库知识和使用经验。尤其是应该知道如何创建数据库,如何通过数据库终端执行 SQL 语句。
请注意,为了掌握本章你应该具备最基本的数据库知识和使用经验。
尤其是应该知道如何创建数据库,如何通过数据库终端执行 SQL 语句。
准备数据库 <span id="preparing-database"></span>
--------------------
首先创建一个名为 `yii2basic` 的数据库,应用将从这个数据库中读取数据。你可以创建 SQLite,MySQL,PostregSQL,MSSQL 或 Oracle 数据库,Yii 内置多种数据库支持。简单起见,后面的内容将以 MySQL 为例做演示。
首先创建一个名为 `yii2basic` 的数据库,应用将从这个数据库中读取数据。你可以创建 SQLite,MySQL,PostregSQL,MSSQL 或 Oracle 数据库,
Yii 内置多种数据库支持。简单起见,后面的内容将以 MySQL 为例做演示。
然后在数据库中创建一个名为 `country` 的表并插入简单的数据。可以执行下面的语句:
@ -27,7 +32,6 @@ CREATE TABLE `country` (
`population` INT(11) NOT NULL DEFAULT '0'
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
<<<<<<< .merge_file_a07132
INSERT INTO `country` VALUES ('AU','Australia',18886000);
INSERT INTO `country` VALUES ('BR','Brazil',170115000);
INSERT INTO `country` VALUES ('CA','Canada',1147000);
@ -38,18 +42,6 @@ INSERT INTO `country` VALUES ('GB','United Kingdom',59623400);
INSERT INTO `country` VALUES ('IN','India',1013662000);
INSERT INTO `country` VALUES ('RU','Russia',146934000);
INSERT INTO `country` VALUES ('US','United States',278357000);
=======
INSERT INTO `country` VALUES ('AU','Australia',24016400);
INSERT INTO `country` VALUES ('BR','Brazil',205722000);
INSERT INTO `country` VALUES ('CA','Canada',35985751);
INSERT INTO `country` VALUES ('CN','China',1375210000);
INSERT INTO `country` VALUES ('DE','Germany',81459000);
INSERT INTO `country` VALUES ('FR','France',64513242);
INSERT INTO `country` VALUES ('GB','United Kingdom',65097000);
INSERT INTO `country` VALUES ('IN','India',1285400000);
INSERT INTO `country` VALUES ('RU','Russia',146519759);
INSERT INTO `country` VALUES ('US','United States',322976000);
>>>>>>> .merge_file_a06196
```
此时便有了一个名为 `yii2basic` 的数据库,在这个数据库中有一个包含三个字段的数据表 `country`,表中有十行数据。
@ -57,9 +49,12 @@ INSERT INTO `country` VALUES ('US','United States',322976000);
配置数据库连接 <span id="configuring-db-connection"></span>
---------------------------
开始之前,请确保你已经安装了 PHP [PDO](http://www.php.net/manual/en/book.pdo.php) 扩展和你所使用的数据库的 PDO 驱动(例如 MySQL 的 `pdo_mysql`)。对于使用关系型数据库来讲,这是基本要求。
开始之前,请确保你已经安装了 PHP [PDO](http://www.php.net/manual/en/book.pdo.php)
扩展和你所使用的数据库的 PDO 驱动(例如 MySQL 的 `pdo_mysql`)。
对于使用关系型数据库来讲,这是基本要求。
驱动和扩展安装可用后,打开 `config/db.php` 修改里面的配置参数对应你的数据库配置。该文件默认包含这些内容:
驱动和扩展安装可用后,打开 `config/db.php` 修改里面的配置参数对应你的数据库配置。
该文件默认包含这些内容:
```php
<?php
@ -73,21 +68,28 @@ return [
];
```
`config/db/php` 是一个典型的基于文件的[配置](concept-configurations.md)工具。这个文件配置了数据库连接 [[yii\db\Connection]] 的创建和初始化参数,应用的 SQL 查询正是基于这个数据库。
`config/db/php` 是一个典型的基于文件的[配置](concept-configurations.md)工具。
这个文件配置了数据库连接 [[yii\db\Connection]] 的创建和初始化参数,
应用的 SQL 查询正是基于这个数据库。
上面配置的数据库连接可以在应用中通过 `Yii::$app->db` 表达式访问。
<<<<<<< .merge_file_a07132
> 补充:`config/db.php` 将被包含在应用配置文件 `config/web.php` 中,后者指定了整个[应用](structure-applications.md)如何初始化。请参考[配置](concept-configurations.md)章节了解更多信息。
=======
> Info: `config/db.php` 将被包含在应用配置文件 `config/web.php` 中,后者指定了整个[应用](structure-applications.md)如何初始化。请参考[配置](concept-configurations.md)章节了解更多信息。
>>>>>>> .merge_file_a06196
> 补充:`config/db.php` 将被包含在应用配置文件 `config/web.php` 中,
后者指定了整个[应用](structure-applications.md)如何初始化。
请参考[配置](concept-configurations.md)章节了解更多信息。
If you need to work with databases support for which isn't bundled with Yii, check the following extensions:
- [Informix](https://github.com/edgardmessias/yii2-informix)
- [IBM DB2](https://github.com/edgardmessias/yii2-ibm-db2)
- [Firebird](https://github.com/edgardmessias/yii2-firebird)
创建活动记录 <span id="creating-active-record"></span>
-------------------------
创建一个继承自[活动记录](db-active-record.md)类的类 `Country`,把它放在 `models/Country.php` 文件,去代表和读取 `country` 表的数据。
创建一个继承自[活动记录](db-active-record.md)类的类 `Country`
把它放在 `models/Country.php` 文件,去代表和读取 `country` 表的数据。
```php
<?php
@ -101,13 +103,11 @@ class Country extends ActiveRecord
}
```
这个 `Country` 类继承自 [[yii\db\ActiveRecord]]。你不用在里面写任何代码。只需要像现在这样,Yii 就能根据类名去猜测对应的数据表名。
这个 `Country` 类继承自 [[yii\db\ActiveRecord]]。你不用在里面写任何代码。
只需要像现在这样,Yii 就能根据类名去猜测对应的数据表名。
<<<<<<< .merge_file_a07132
> 补充:如果类名和数据表名不能直接对应,可以覆写 [[yii\db\ActiveRecord::tableName()|tableName()]] 方法去显式指定相关表名。
=======
> Info: 如果类名和数据表名不能直接对应,可以覆写 [[yii\db\ActiveRecord::tableName()|tableName()]] 方法去显式指定相关表名。
>>>>>>> .merge_file_a06196
> 注意:如果类名和数据表名不能直接对应,可以覆写 [[yii\db\ActiveRecord::tableName()|tableName()]]
方法去显式指定相关表名。
使用 `Country` 类可以很容易地操作 `country` 表数据,就像这段代码:
@ -128,17 +128,17 @@ $country->name = 'U.S.A.';
$country->save();
```
<<<<<<< .merge_file_a07132
> 补充:活动记录是面向对象、功能强大的访问和操作数据库数据的方式。你可以在[活动记录](db-active-record.md)章节了解更多信息。除此之外你还可以使用另一种更原生的被称做[数据访问对象](db-dao)的方法操作数据库数据。
=======
> Info: 活动记录是面向对象、功能强大的访问和操作数据库数据的方式。你可以在[活动记录](db-active-record.md)章节了解更多信息。除此之外你还可以使用另一种更原生的被称做[数据访问对象](db-dao)的方法操作数据库数据。
>>>>>>> .merge_file_a06196
> 补充:活动记录是面向对象、功能强大的访问和操作数据库数据的方式。你可以在[活动记录](db-active-record.md)章节了解更多信息。
除此之外你还可以使用另一种更原生的被称做[数据访问对象](db-dao)的方法操作数据库数据。
创建操作 <span id="creating-action"></span>
------------------
为了向最终用户显示国家数据,你需要创建一个操作。相比之前小节掌握的在 `site` 控制器中创建操作,在这里为所有和国家有关的数据新建一个控制器更加合理。新控制器名为 `CountryController`,并在其中创建一个 `index` 操作,如下:
为了向最终用户显示国家数据,你需要创建一个操作。
相比之前小节掌握的在 `site` 控制器中创建操作,
在这里为所有和国家有关的数据新建一个控制器更加合理。
新控制器名为 `CountryController`,并在其中创建一个 `index` 操作,如下:
```php
<?php
@ -175,18 +175,25 @@ class CountryController extends Controller
把上面的代码保存在 `controllers/CountryController.php` 文件中。
`index` 操作调用了活动记录 `Country::find()` 方法,去生成查询语句并从 `country` 表中取回所有数据。为了限定每个请求所返回的国家数量,查询在 [[yii\data\Pagination]] 对象的帮助下进行分页。 `Pagination` 对象的使命主要有两点:
`index` 操作调用了活动记录 `Country::find()` 方法,去生成查询语句并从 `country` 表中取回所有数据。
为了限定每个请求所返回的国家数量,查询在 [[yii\data\Pagination]] 对象的帮助下进行分页。
`Pagination` 对象的使命主要有两点:
* 为 SQL 查询语句设置 `offset``limit` 从句,确保每个请求只需返回一页数据(本例中每页是 5 行)。
* 在视图中显示一个由页码列表组成的分页器,这点将在后面的段落中解释。
* 为 SQL 查询语句设置 `offset``limit` 从句,
确保每个请求只需返回一页数据(本例中每页是 5 行)。
* 在视图中显示一个由页码列表组成的分页器,
这点将在后面的段落中解释。
在代码末尾,`index` 操作渲染一个名为 `index` 的视图,并传递国家数据和分页信息进去。
在代码末尾,`index` 操作渲染一个名为 `index` 的视图,
并传递国家数据和分页信息进去。
创建视图 <span id="creating-view"></span>
---------------
`views` 目录下先创建一个名为 `country` 的子目录。这个目录存储所有由 `country` 控制器渲染的视图。在 `views/country` 目录下创建一个名为 `index.php` 的视图文件,内容如下:
`views` 目录下先创建一个名为 `country` 的子目录。这个目录存储所有由 `country` 控制器渲染的视图。
`views/country` 目录下创建一个名为 `index.php` 的视图文件,
内容如下:
```php
<?php
@ -206,7 +213,10 @@ use yii\widgets\LinkPager;
<?= LinkPager::widget(['pagination' => $pagination]) ?>
```
这个视图包含两部分用以显示国家数据。第一部分遍历国家数据并以无序 HTML 列表渲染出来。第二部分使用 [[yii\widgets\LinkPager]] 去渲染从操作中传来的分页信息。小部件 `LinkPager` 显示一个分页按钮的列表。点击任何一个按钮都会跳转到对应的分页。
这个视图包含两部分用以显示国家数据。第一部分遍历国家数据并以无序 HTML 列表渲染出来。
第二部分使用 [[yii\widgets\LinkPager]] 去渲染从操作中传来的分页信息。
小部件 `LinkPager` 显示一个分页按钮的列表。
点击任何一个按钮都会跳转到对应的分页。
试运行 <span id="trying-it-out"></span>
@ -220,7 +230,9 @@ http://hostname/index.php?r=country/index
![国家列表](images/start-country-list.png)
首先你会看到显示着五个国家的列表页面。在国家下面,你还会看到一个包含四个按钮的分页器。如果你点击按钮 “2”,将会跳转到显示另外五个国家的页面,也就是第二页记录。如果观察仔细点你还会看到浏览器的 URL 变成了:
首先你会看到显示着五个国家的列表页面。在国家下面,
你还会看到一个包含四个按钮的分页器。如果你点击按钮 “2”,将会跳转到显示另外五个国家的页面,
也就是第二页记录。如果观察仔细点你还会看到浏览器的 URL 变成了:
```
http://hostname/index.php?r=country/index&page=2
@ -228,17 +240,24 @@ http://hostname/index.php?r=country/index&page=2
在这个场景里,[[yii\data\Pagination|Pagination]] 提供了为数据结果集分页的所有功能:
* 首先 [[yii\data\Pagination|Pagination]] 把 SELECT 的子查询 `LIMIT 5 OFFSET 0` 数据表示成第一页。因此开头的五条数据会被取出并显示。
* 然后小部件 [[yii\widgets\LinkPager|LinkPager]] 使用 [[yii\data\Pagination::createUrl()|Pagination::createUrl()]] 方法生成的 URL 去渲染翻页按钮。URL 中包含必要的参数 `page` 才能查询不同的页面编号。
* 如果你点击按钮 “2”,将会发起一个路由为 `country/index` 的新请求。[[yii\data\Pagination|Pagination]] 接收到 URL 中的 `page` 参数把当前的页码设为 2。新的数据库请求将会以 `LIMIT 5 OFFSET 5` 查询并显示。
* 首先 [[yii\data\Pagination|Pagination]] 把 SELECT 的子查询 `LIMIT 5 OFFSET 0` 数据表示成第一页。
因此开头的五条数据会被取出并显示。
* 然后小部件 [[yii\widgets\LinkPager|LinkPager]] 使用
[[yii\data\Pagination::createUrl()|Pagination::createUrl()]] 方法生成的 URL 去渲染翻页按钮。
URL 中包含必要的参数 `page` 才能查询不同的页面编号。
* 如果你点击按钮 “2”,将会发起一个路由为 `country/index` 的新请求。
[[yii\data\Pagination|Pagination]] 接收到 URL 中的 `page` 参数把当前的页码设为 2。
新的数据库请求将会以 `LIMIT 5 OFFSET 5`
查询并显示。
总结 <span id="summary"></span>
-------
本章节中你学到了如何使用数据库。你还学到了如何取出并使用 [[yii\data\Pagination]] 和 [[yii\widgets\LinkPager]] 显示数据。
本章节中你学到了如何使用数据库。你还学到了如何取出并使用
[[yii\data\Pagination]] 和 [[yii\widgets\LinkPager]] 显示数据。
<<<<<<< .merge_file_a07132
下一章中你会学到如何使用 Yii 中强大的代码生成器 [Gii](tool-gii.md),去帮助你实现一些常用的功能需求,例如增查改删(CRUD)数据表中的数据。事实上你之前所写的代码全部都可以由 Gii 自动生成。
=======
下一章中你会学到如何使用 Yii 中强大的代码生成器 [Gii](tool-gii.md),去帮助你实现一些常用的功能需求,例如增查改删(CRUD)数据表中的数据。事实上你之前所写的代码全部都可以由 Gii 自动生成。
>>>>>>> .merge_file_a06196
下一章中你会学到如何使用 Yii 中强大的代码生成器 [Gii](tool-gii.md),
去帮助你实现一些常用的功能需求,
例如增查改删(CRUD)数据表中的数据。
事实上你之前所写的代码全部都可以由 Gii 自动生成。

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

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

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

@ -1,7 +1,8 @@
使用 Gii 生成代码
========================
本章将介绍如何使用 [Gii](tool-gii.md) 去自动生成 Web 站点常用功能的代码。使用 Gii 生成代码非常简单,只要按照 Gii 页面上的介绍输入正确的信息即可。
本章将介绍如何使用 [Gii](tool-gii.md) 去自动生成 Web 站点常用功能的代码。使用 Gii 生成代码非常简单,
只要按照 Gii 页面上的介绍输入正确的信息即可。
贯穿本章节,你将会学到:
@ -14,20 +15,25 @@
开始 Gii <span id="starting-gii"></span>
------------
[Gii](tool-gii.md) 是 Yii 中的一个[模块](structure-modules.md)。可以通过配置应用的 [[yii\base\Application::modules|modules]] 属性开启它。通常来讲在 `config/web.php` 文件中会有以下配置代码:
[Gii](tool-gii.md) 是 Yii 中的一个[模块](structure-modules.md)。可以通过配置应用的 [[yii\base\Application::modules|modules]] 属性开启它。
通常来讲在 `config/web.php` 文件中会有以下配置代码:
```php
$config = [ ... ];
if (YII_ENV_DEV) {
$config['bootstrap'][] = 'gii';
$config['modules']['gii'] = 'yii\gii\Module';
$config['modules']['gii'] = [
'class' => 'yii\gii\Module',
];
}
```
这段配置表明,如果当前是[开发环境](concept-configurations.md#environment-constants),应用会包含 `gii` 模块,模块类是 [[yii\gii\Module]]。
这段配置表明,如果当前是[开发环境](concept-configurations.md#environment-constants),
应用会包含 `gii` 模块,模块类是 [[yii\gii\Module]]。
如果你检查应用的[入口脚本](structure-entry-scripts.md) `web/index.php`,将看到这行代码将 `YII_ENV_DEV` 设为 true:
如果你检查应用的[入口脚本](structure-entry-scripts.md) `web/index.php`
将看到这行代码将 `YII_ENV_DEV` 设为 true:
```php
defined('YII_ENV') or define('YII_ENV', 'dev');
@ -39,11 +45,8 @@ defined('YII_ENV') or define('YII_ENV', 'dev');
http://hostname/index.php?r=gii
```
<<<<<<< .merge_file_a06868
> 补充: 如果你通过本机以外的机器访问 Gii,请求会被出于安全原因拒绝。你可以配置 Gii 为其添加允许访问的 IP 地址:
=======
> Info: 如果你通过本机以外的机器访问 Gii,请求会被出于安全原因拒绝。你可以配置 Gii 为其添加允许访问的 IP 地址:
>>>>>>> .merge_file_a02624
> 补充: 如果你通过本机以外的机器访问 Gii,请求会被出于安全原因拒绝。
> 你可以配置 Gii 为其添加允许访问的 IP 地址:
>
```php
'gii' => [
@ -67,13 +70,16 @@ http://hostname/index.php?r=gii
然后点击 “Preview” 按钮。你会看到 `models/Country.php` 被列在将要生成的文件列表中。可以点击文件名预览内容。
如果你已经创建过同样的文件,使用 Gii 会覆写它,点击文件名旁边的 `diff` 能查看现有文件与将要生成的文件的内容区别。
如果你已经创建过同样的文件,
使用 Gii 会覆写它,
点击文件名旁边的 `diff` 能查看现有文件与将要生成的文件的内容区别。
![模型生成器预览](images/start-gii-model-preview.png)
想要覆写已存在文件,选中 “overwrite” 下的复选框然后点击 “Generator”。如果是新文件,只点击 “Generator” 就好。
接下来你会看到一个包含已生成文件的说明页面。如果生成过程中覆写过文件,还会有一条信息说明代码是重新生成覆盖的。
接下来你会看到一个包含已生成文件的说明页面。如果生成过程中覆写过文件,
还会有一条信息说明代码是重新生成覆盖的。
生成 CRUD 代码 <span id="generating-crud"></span>
@ -91,7 +97,8 @@ CRUD 代表增,查,改,删操作,这是绝大多数 Web 站点常用的
[[NEED THE IMAGE HERE / 等待官方补充图片]]
如果你之前创建过 `controllers/CountryController.php``views/country/index.php` 文件(在指南的使用数据库章节),选中 “overwrite” 下的复选框覆写它们(之前的文件没能全部支持 CRUD)。
如果你之前创建过 `controllers/CountryController.php``views/country/index.php` 文件(在指南的使用数据库章节),
选中 “overwrite” 下的复选框覆写它们(之前的文件没能全部支持 CRUD)。
试运行 <span id="trying-it-out"></span>
@ -103,28 +110,30 @@ CRUD 代表增,查,改,删操作,这是绝大多数 Web 站点常用的
http://hostname/index.php?r=country/index
```
可以看到一个栅格显示着从数据表中读取的国家数据。支持在列头对数据进行排序,输入筛选条件进行筛选。
可以看到一个栅格显示着从数据表中读取的国家数据。
支持在列头对数据进行排序,输入筛选条件进行筛选。
可以浏览详情,编辑,或删除栅格中的每个国家。还可以点击栅格上方的 “Create Country” 按钮通过表单创建新国家。
可以浏览详情,编辑,或删除栅格中的每个国家。
还可以点击栅格上方的 “Create Country” 按钮通过表单创建新国家。
![国家的数据栅格](images/start-gii-country-grid.png)
![编辑一个国家](images/start-gii-country-update.png)
下面列出由 Gii 生成的文件,以便你研习功能和实现,或修改它们。
下面列出由 Gii 生成的文件,以便你研习功能和实现,
或修改它们。
* 控制器:`controllers/CountryController.php`
* 模型:`models/Country.php` 和 `models/CountrySearch.php`
* 视图:`views/country/*.php`
<<<<<<< .merge_file_a06868
> 补充:Gii 被设计成高度可定制和可扩展的代码生成工具。使用它可以大幅提高应用开发速度。请参考 [Gii](tool-gii.md) 章节了解更多内容。
=======
> Info: Gii 被设计成高度可定制和可扩展的代码生成工具。使用它可以大幅提高应用开发速度。请参考 [Gii](tool-gii.md) 章节了解更多内容。
>>>>>>> .merge_file_a02624
> 注意:Gii 被设计成高度可定制和可扩展的代码生成工具。
使用它可以大幅提高应用开发速度。
请参考 [Gii](tool-gii.md) 章节了解更多内容。
总结 <span id="summary"></span>
-------
本章学习了如何使用 Gii 去生成为数据表中数据实现完整 CRUD 功能的代码。
本章学习了如何使用 Gii 去生成为数据表中
数据实现完整 CRUD 功能的代码。

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

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

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

@ -1,67 +1,63 @@
安装 Yii
==============
<<<<<<< .merge_file_a03504
<<<<<<< HEAD
你可以通过两种方式安装 Yii:使用 [Composer](http://getcomposer.org/) 或下载一个归档文件。推荐使用前者,这样只需执行一条简单的命令就可以安装新的[扩展](structure-extensions.md)或更新 Yii 了。
=======
你可以通过两种方式安装 Yii:使用 [Composer](https://getcomposer.org/) 或下载一个归档文件。推荐使用前者,这样只需执行一条简单的命令就可以安装新的[扩展](structure-extensions.md)或更新 Yii 了。
>>>>>>> yiichina/master
=======
你可以通过两种方式安装 Yii:使用 [Composer](https://getcomposer.org/) 或下载一个归档文件。推荐使用前者,这样只需执行一条简单的命令就可以安装新的[扩展](structure-extensions.md)或更新 Yii 了。
>>>>>>> .merge_file_a06364
你可以通过两种方式安装 Yii:使用 [Composer](http://getcomposer.org/) 或下载一个归档文件。
推荐使用前者,这样只需执行一条简单的命令就可以安装新的[扩展](structure-extensions.md)或更新 Yii 了。
> Note: 和 Yii 1 不同,以标准方式安装 Yii 2 时会同时下载并安装框架本身和一个应用程序的基本骨架。
Standard installations of Yii result in both the framework and a project template being downloaded and installed.
A project template is a working Yii project implementing some basic features, such as login, contact form, etc.
Its code is organized in a recommended way. Therefore, it can serve as a good starting point for your projects.
In this and the next few sections, we will describe how to install Yii with the so-called *Basic Project Template* and
how to implement new features on top of this template. Yii also provides another template called
the [Advanced Project Template](https://github.com/yiisoft/yii2-app-advanced/blob/master/docs/guide/README.md) which is better used in a team development environment
to develop applications with multiple tiers.
> Info: The Basic Project Template is suitable for developing 90 percent of Web applications. It differs
from the Advanced Project Template mainly in how their code is organized. If you are new to Yii, we strongly
recommend you stick to the Basic Project Template for its simplicity yet sufficient functionalities.
通过 Composer 安装 <span id="installing-via-composer"></span>
-----------------------
如果还没有安装 Composer,你可以按 [getcomposer.org](https://getcomposer.org/download/) 中的方法安装。在 Linux 和 Mac OS X 中可以运行如下命令:
如果还没有安装 Composer,你可以按 [getcomposer.org](https://getcomposer.org/download/) 中的方法安装。
在 Linux 和 Mac OS X 中可以运行如下命令:
<<<<<<< .merge_file_a03504
<<<<<<< HEAD
curl -s http://getcomposer.org/installer | php
=======
curl -sS https://getcomposer.org/installer | php
>>>>>>> yiichina/master
=======
curl -sS https://getcomposer.org/installer | php
>>>>>>> .merge_file_a06364
mv composer.phar /usr/local/bin/composer
```bash
curl -sS https://getcomposer.org/installer | php
mv composer.phar /usr/local/bin/composer
```
在 Windows 中,你需要下载并运行 [Composer-Setup.exe](https://getcomposer.org/Composer-Setup.exe)。
如果遇到任何问题或者想更深入地学习 Composer,请参考 [Composer 文档(英文)](https://getcomposer.org/doc/),[Composer 中文](https://github.com/5-say/composer-doc-cn)。
如果遇到任何问题或者想更深入地学习 Composer,
请参考 [Composer 文档(英文)](https://getcomposer.org/doc/),[Composer 中文](https://github.com/5-say/composer-doc-cn)。
如果你已经安装有 Composer 请确保使用的是最新版本,你可以用 `composer self-update` 命令更新 Composer 为最新版本。
如果你已经安装有 Composer 请确保使用的是最新版本,
你可以用 `composer self-update` 命令更新 Composer 为最新版本。
Composer 安装后,切换到一个可通过 Web 访问的目录,执行如下命令即可安装 Yii :
<<<<<<< .merge_file_a03504
<<<<<<< HEAD
composer global require "fxp/composer-asset-plugin:1.0.0"
=======
composer global require "fxp/composer-asset-plugin:~1.0.0"
>>>>>>> yiichina/master
=======
composer global require "fxp/composer-asset-plugin:~1.1.1"
>>>>>>> .merge_file_a06364
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
第一条命令安装 [Composer asset plugin](https://github.com/francoispluchino/composer-asset-plugin/),它是通过 Composer 管理 bower 和 npm 包所必须的,此命令全局生效,一劳永逸。
```bash
composer global require "fxp/composer-asset-plugin:~1.1.1"
composer create-project --prefer-dist yiisoft/yii2-app-basic basic
```
第一条命令安装 [Composer asset plugin](https://github.com/francoispluchino/composer-asset-plugin/),
它是通过 Composer 管理 bower 和 npm 包所必须的,此命令全局生效,一劳永逸。
第二条命令会将 Yii 安装在名为 `basic` 的目录中,你也可以随便选择其他名称。
> Note: 在安装过程中 Composer 可能会询问你 GitHub 账户的登录信息,因为可能在使用中超过了 GitHub API
(对匿名用户的)使用限制。因为 Composer 需要为所有扩展包从 GitHub
中获取大量信息,所以超限非常正常。(译注:也意味着作为程序猿没有 GitHub 账号,就真不能愉快地玩耍了)登陆 GitHub
之后可以得到更高的 API 限额,这样 Composer 才能正常运行。更多细节请参考 [Composer
文档](https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens)(该段 Composer
中文文档[期待您的参与](https://github.com/5-say/composer-doc-cn/blob/master/cn-introduction/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens))。
> Note: 在安装过程中 Composer 可能会询问你 GitHub 账户的登录信息,因为可能在使用中超过了 GitHub API (对匿名用户的)使用限制。因为 Composer 需要为所有扩展包从 GitHub
> 中获取大量信息,所以超限非常正常。(译注:也意味着作为程序猿没有 GitHub 账号,就真不能愉快地玩耍了)登陆 GitHub 之后可以得到更高的 API 限额,这样 Composer 才能正常运行。更多细节请参考 [Composer
> 文档](https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens)(该段 Composer中文文档[期待您的参与](https://github.com/5-say/composer-doc-cn/blob/master/cn-introduction/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens))。
> Tip: 如果你想安装 Yii 的最新开发版本,可以使用以下命令代替,它添加了一个 [stability 选项](https://getcomposer.org/doc/04-schema.md#minimum-stability)([中文版](https://github.com/5-say/composer-doc-cn/blob/master/cn-introduction/04-schema.md#minimum-stability)):
> Tip: 如果你想安装 Yii 的最新开发版本,可以使用以下命令代替,
> 它添加了一个 [stability 选项](https://getcomposer.org/doc/04-schema.md#minimum-stability)([中文版](https://github.com/5-say/composer-doc-cn/blob/master/cn-introduction/04-schema.md#minimum-stability)):
>
> composer create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic basic
> ```bash
> composer create-project --prefer-dist --stability=dev yiisoft/yii2-app-basic basic
> ```
>
> 注意,Yii 的开发版(dev 版)不应该用于生产环境中,它可能会破坏运行中的代码。
@ -73,7 +69,8 @@ Composer 安装后,切换到一个可通过 Web 访问的目录,执行如下
1. 从 [yiiframework.com](http://www.yiiframework.com/download/) 下载归档文件。
2. 将下载的文件解压缩到 Web 目录中。
3. 修改 `config/web.php` 文件,给 `cookieValidationKey` 配置项添加一个密钥(若你通过 Composer 安装,则此步骤会自动完成):
3. 修改 `config/web.php` 文件,给 `cookieValidationKey` 配置项
添加一个密钥(若你通过 Composer 安装,则此步骤会自动完成):
```php
// !!! 在下面插入一段密钥(若为空) - 以供 cookie validation 的需要
@ -84,28 +81,46 @@ Composer 安装后,切换到一个可通过 Web 访问的目录,执行如下
其他安装方式 <span id="other-installation-options"></span>
--------------------------
上文介绍了两种安装 Yii 的方法,安装的同时也会创建一个立即可用的 Web 应用程序。对于小的项目或用于学习上手,这都是一个不错的起点。
上文介绍了两种安装 Yii 的方法,
安装的同时也会创建一个立即可用的 Web 应用程序。
对于小的项目或用于学习上手,这都是一个不错的起点。
但是其他的安装方式也存在:
* 如果你只想安装核心框架,然后从零开始构建整个属于你自己的应用程序模版,可以参考[从头构建自定义模版](tutorial-start-from-scratch.md)一节的介绍。
* 如果你要开发一个更复杂的应用,可以更好地适用于团队开发环境的,可以考虑安装[高级应用模版](tutorial-advanced-app.md)。
* 如果你只想安装核心框架,然后从零开始构建整个属于你自己的应用程序模版,
可以参考[从头构建自定义模版](tutorial-start-from-scratch.md)一节的介绍。
* 如果你要开发一个更复杂的应用,可以更好地适用于团队开发环境的,
可以考虑安装[高级应用模版](tutorial-advanced-app.md)。
验证安装的结果 <span id="verifying-installation"></span>
--------------------------
After installation is done, either configure your web server (see next section) or use the
[built-in PHP web server](https://secure.php.net/manual/en/features.commandline.webserver.php) by running the following
console command while in the project `web` directory:
```bash
php yii serve
```
> Note: By default the HTTP-server will listen to port 8080. However if that port is already in use or you wish to
serve multiple applications this way, you might want to specify what port to use. Just add the --port argument:
```bash
php yii serve --port=8888
```
安装完成后,就可以使用浏览器通过如下 URL 访问刚安装完的 Yii 应用了:
```
http://localhost/basic/web/index.php
http://localhost:8080/
```
这个 URL 假设你将 Yii 安装到了一个位于 Web 文档根目录下的 `basic` 目录中,且该 Web 服务器正运行在你自己的电脑上(`localhost`)。你可能需要将其调整为适应自己的安装环境。
![Yii 安装成功](images/start-app-installed.png)
你应该可以在浏览器中看到如上所示的 “Congratulations!” 页面。如果没有,请通过以下任意一种方式,检查当前 PHP 环境是否满足 Yii 最基本需求:
你应该可以在浏览器中看到如上所示的 “Congratulations!” 页面。如果没有,
请通过以下任意一种方式,检查当前 PHP 环境是否满足 Yii 最基本需求:
* 通过浏览器访问 URL `http://localhost/basic/requirements.php`
* 执行如下命令:
@ -115,26 +130,42 @@ http://localhost/basic/web/index.php
php requirements.php
```
你需要配置好 PHP 安装环境,使其符合 Yii 的最小需求。主要是需要 PHP 5.4 以上版本。如果应用需要用到数据库,那还要安装 [PDO PHP 扩展](http://www.php.net/manual/zh/pdo.installation.php) 和相应的数据库驱动(例如访问 MySQL 数据库所需的 `pdo_mysql`)。
你需要配置好 PHP 安装环境,使其符合 Yii 的最小需求。主要是需要 PHP 5.4 以上版本。
如果应用需要用到数据库,那还要安装 [PDO PHP 扩展](http://www.php.net/manual/zh/pdo.installation.php)
和相应的数据库驱动(例如访问 MySQL 数据库所需的 `pdo_mysql`)。
配置 Web 服务器 <span id="configuring-web-servers"></span>
-----------------------
> Info: 如果你现在只是要试用 Yii 而不是将其部署到生产环境中,本小节可以跳过。
> Info: 如果你现在只是要试用 Yii 而不是将其部署到生产环境中,
本小节可以跳过。
通过上述方法安装的应用程序在 Windows,Max OS X,Linux 中的 [Apache HTTP 服务器](http://httpd.apache.org/)或 [Nginx HTTP 服务器](http://nginx.org/)且PHP版本为5.4或更高都可以直接运行。Yii 2.0 也兼容 Facebook 公司的 [HHVM](http://hhvm.com/),由于 HHVM 和标准 PHP 在边界案例上有些地方略有不同,在使用 HHVM 时需稍作处理。
通过上述方法安装的应用程序在 Windows,Max OS X,
Linux 中的 [Apache HTTP 服务器](http://httpd.apache.org/)
或 [Nginx HTTP 服务器](http://nginx.org/)且PHP版本为5.4或更高都可以直接运行。
Yii 2.0 也兼容 Facebook 公司的 [HHVM](http://hhvm.com/),
由于 HHVM 和标准 PHP 在边界案例上有些地方略有不同,在使用 HHVM 时需稍作处理。
在生产环境的服务器上,你可能会想配置服务器让应用程序可以通过 URL `http://www.example.com/index.php` 访问而不是 `http://www.example.com/basic/web/index.php`。这种配置需要将 Web 服务器的文档根目录指向 `basic/web` 目录。可能你还会想隐藏掉 URL 中的 `index.php`,具体细节在 [URL 解析和生成](runtime-url-handling.md)一章中有介绍,你将学到如何配置 Apache 或 Nginx 服务器实现这些目标。
在生产环境的服务器上,你可能会想配置服务器让应用程序可以通过
URL `http://www.example.com/index.php` 访问而不是 `http://www.example.com/basic/web/index.php`
这种配置需要将 Web 服务器的文档根目录指向 `basic/web` 目录。
可能你还会想隐藏掉 URL 中的 `index.php`,具体细节在 [URL 解析和生成](runtime-url-handling.md)一章中有介绍,
你将学到如何配置 Apache 或 Nginx 服务器实现这些目标。
> Info: 将 `basic/web` 设置为文档根目录,可以防止终端用户访问 `basic/web` 相邻目录中的私有应用代码和敏感数据文件。禁止对其他目录的访问是一个不错的安全改进。
> Info: 将 `basic/web` 设置为文档根目录,可以防止终端用户访问 `basic/web` 相邻目录中
的私有应用代码和敏感数据文件。
禁止对其他目录的访问是一个不错的安全改进。
> Info: 如果你的应用程序将来要运行在共享虚拟主机环境中,没有修改其 Web 服务器配置的权限,你依然可以通过调整应用的结构来提升安全性。详情请参考[共享主机环境](tutorial-shared-hosting.md) 一章。
> Info: 如果你的应用程序将来要运行在共享虚拟主机环境中,
没有修改其 Web 服务器配置的权限,你依然可以通过调整应用的结构来提升安全性。
详情请参考[共享主机环境](tutorial-shared-hosting.md) 一章。
### 推荐使用的 Apache 配置 <span id="recommended-apache-configuration"></span>
在 Apache 的 `httpd.conf` 文件或在一个虚拟主机配置文件中使用如下配置。注意,你应该将 `path/to/basic/web` 替换为实际的 `basic/web` 目录。
在 Apache 的 `httpd.conf` 文件或在一个虚拟主机配置文件中使用如下配置。
注意,你应该将 `path/to/basic/web` 替换为实际的 `basic/web` 目录。
```
# 设置文档根目录为 “basic/web”
@ -156,36 +187,39 @@ DocumentRoot "path/to/basic/web"
### 推荐使用的 Nginx 配置 <span id="recommended-nginx-configuration"></span>
为了使用 [Nginx](http://wiki.nginx.org/),你应该已经将 PHP 安装为 [FPM SAPI](http://php.net/install.fpm) 了。使用如下 Nginx 配置,将 `path/to/basic/web` 替换为实际的 `basic/web` 目录,`mysite.local` 替换为实际的主机名以提供服务。
为了使用 [Nginx](http://wiki.nginx.org/),你应该已经将 PHP 安装为 [FPM SAPI](http://php.net/install.fpm) 了。
使用如下 Nginx 配置,将 `path/to/basic/web` 替换为实际的 `basic/web` 目录,
`mysite.local` 替换为实际的主机名以提供服务。
```
```nginx
server {
charset utf-8;
client_max_body_size 128M;
listen 80; ## 监听 ipv4 上的 80 端口
#listen [::]:80 default_server ipv6only=on; ## 监听 ipv6 上的 80 端口
listen 80; ## listen for ipv4
#listen [::]:80 default_server ipv6only=on; ## listen for ipv6
server_name mysite.local;
root /path/to/basic/web;
index index.php;
access_log /path/to/basic/log/access.log main;
access_log /path/to/basic/log/access.log;
error_log /path/to/basic/log/error.log;
location / {
# 如果找不到真实存在的文件,把请求分发至 index.php
try_files $uri $uri/ /index.php?$args;
# Redirect everything that isn't a real file to index.php
try_files $uri $uri/ /index.php$is_args$args;
}
# 若取消下面这段的注释,可避免 Yii 接管不存在文件的处理过程(404)
# uncomment to avoid processing of calls to non-existing static files by Yii
#location ~ \.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {
# try_files $uri =404;
#}
#error_page 404 /404.html;
location ~ \.php$ {
include fastcgi.conf;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass 127.0.0.1:9000;
#fastcgi_pass unix:/var/run/php5-fpm.sock;
try_files $uri =404;
@ -197,6 +231,8 @@ server {
}
```
使用该配置时,你还应该在 `php.ini` 文件中设置 `cgi.fix_pathinfo=0` ,能避免掉很多不必要的 `stat()` 系统调用。
使用该配置时,你还应该在 `php.ini` 文件中设置 `cgi.fix_pathinfo=0`
能避免掉很多不必要的 `stat()` 系统调用。
还要注意当运行一个 HTTPS 服务器时,需要添加 `fastcgi_param HTTPS on;` 一行,这样 Yii 才能正确地判断连接是否安全。
还要注意当运行一个 HTTPS 服务器时,需要添加 `fastcgi_param HTTPS on;` 一行,
这样 Yii 才能正确地判断连接是否安全。

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

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

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

@ -1,13 +1,19 @@
运行应用
====================
安装 Yii 后,就有了一个可运行的 Yii 应用,根据配置的不同,可以通过 `http://hostname/basic/web/index.php``http://hostname/index.php` 访问。本章节将介绍应用的内建功能,如何组织代码,以及一般情况下应用如何处理请求。
安装 Yii 后,就有了一个可运行的 Yii 应用,
根据配置的不同,可以通过 `http://hostname/basic/web/index.php``http://hostname/index.php` 访问。
本章节将介绍应用的内建功能,如何组织代码,
以及一般情况下应用如何处理请求。
> 补充:为简单起见,在整个“入门”板块都假定你已经把
`basic/web` 设为 Web 服务器根目录并配置完毕,
你访问应用的地址会是 `http://lostname/index.php` 或类似的。
请按需调整 URL。
Note that unlike framework itself, after project template is installed it's all yours. You're free to add or delete
code and overall modify it as you need.
<<<<<<< .merge_file_a07004
> 补充:为简单起见,在整个“入门”板块都假定你已经把 `basic/web` 设为 Web 服务器根目录并配置完毕,你访问应用的地址会是 `http://lostname/index.php` 或类似的。请按需调整 URL。
=======
> Info: 为简单起见,在整个“入门”板块都假定你已经把 `basic/web` 设为 Web 服务器根目录并配置完毕,你访问应用的地址会是 `http://lostname/index.php` 或类似的。请按需调整 URL。
>>>>>>> .merge_file_a04932
功能 <span id="functionality"></span>
-------------
@ -17,11 +23,18 @@
* 主页,当你访问 `http://hostname/index.php` 时显示,
* “About” 页,
* “Contact” 页, 显示一个联系表单,允许终端用户通过 Email 联系你,
* “Login” 页, 显示一个登录表单,用来验证终端用户。试着用 “admin/admin” 登录,你可以看到当前是登录状态,已经可以“退出登录”了。
* “Login” 页, 显示一个登录表单,用来验证终端用户。试着用 “admin/admin” 登录,
你可以看到当前是登录状态,已经可以“退出登录”了。
这些页面使用同一个头部和尾部。
头部包含了一个可以在不同页面间切换的导航栏。
这些页面使用同一个头部和尾部。头部包含了一个可以在不同页面间切换的导航栏。
在浏览器底部可以看到一个工具栏。这是 Yii 提供的很有用的[调试工具](tool-debugger.md),
可以记录并显示大量的调试信息,例如日志信息,响应状态,数据库查询等等。
在浏览器底部可以看到一个工具栏。这是 Yii 提供的很有用的[调试工具](tool-debugger.md),可以记录并显示大量的调试信息,例如日志信息,响应状态,数据库查询等等。
Additionally to the web application, there is a console script called `yii`, which is located in the applications base directory.
This script can be used to run background and maintenance tasks for the application, which are described
in the [Console Application Section](tutorial-console.md).
应用结构 <span id="application-structure"></span>
@ -47,15 +60,23 @@ basic/ 应用根目录
yii Yii 控制台命令执行脚本
```
一般来说,应用中的文件可被分为两类:在 `basic/web` 下的和在其它目录下的。前者可以直接通过 HTTP 访问(例如浏览器),后者不能也不应该被直接访问。
一般来说,应用中的文件可被分为两类:在 `basic/web` 下的和在其它目录下的。
前者可以直接通过 HTTP 访问(例如浏览器),后者不能也不应该被直接访问。
Yii 实现了[模型-视图-控制器 (MVC)](http://wikipedia.org/wiki/Model-view-controller)设计模式,这点在上述目录结构中也得以体现。 `models` 目录包含了所有[模型类](structure-models.md),`views` 目录包含了所有[视图脚本](structure-views.md),`controllers` 目录包含了所有[控制器类](structure-controllers.md)。
Yii 实现了[模型-视图-控制器 (MVC)](http://wikipedia.org/wiki/Model-view-controller)设计模式,这点在上述目录结构中也得以体现。
`models` 目录包含了所有[模型类](structure-models.md),
`views` 目录包含了所有[视图脚本](structure-views.md),
`controllers` 目录包含了所有[控制器类](structure-controllers.md)。
以下图表展示了一个应用的静态结构:
![应用静态结构](images/application-structure.png)
每个应用都有一个入口脚本 `web/index.php`,这是整个应用中唯一可以访问的 PHP 脚本。入口脚本接受一个 Web 请求并创建[应用](structure-application.md)实例去处理它。 [应用](structure-applications.md)在它的[组建](concept-components.md)辅助下解析请求,并分派请求至 MVC 元素。[视图](structure-views.md)使用[小部件](structure-widgets.md)去创建复杂和动态的用户界面。
每个应用都有一个入口脚本 `web/index.php`
这是整个应用中唯一可以访问的 PHP 脚本。
入口脚本接受一个 Web 请求并创建[应用](structure-application.md)实例去处理它。
[应用](structure-applications.md)在它的[组建](concept-components.md)辅助下解析请求,
并分派请求至 MVC 元素。[视图](structure-views.md)使用[小部件](structure-widgets.md)去创建复杂和动态的用户界面。
请求生命周期 <span id="request-lifecycle"></span>
@ -66,8 +87,10 @@ Yii 实现了[模型-视图-控制器 (MVC)](http://wikipedia.org/wiki/Model-vie
![请求生命周期](images/request-lifecycle.png)
1. 用户向[入口脚本](structure-entry-scripts.md) `web/index.php` 发起请求。
2. 入口脚本加载应用[配置](concept-configurations.md)并创建一个[应用](structure-applications.md)实例去处理请求。
3. 应用通过[请求](runtime-request.md)组件解析请求的[路由](runtime-routing.md)。
2. 入口脚本加载应用[配置](concept-configurations.md)
并创建一个[应用](structure-applications.md)实例去处理请求。
3. 应用通过[请求](runtime-request.md)组件
解析请求的[路由](runtime-routing.md)。
4. 应用创建一个[控制器](structure-controllers.md)实例去处理请求。
5. 控制器创建一个[操作](structure-controllers.md)实例并针对操作执行过滤器。
6. 如果任何一个过滤器返回失败,则操作退出。

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

@ -1,10 +1,13 @@
应用组件
======================
应用主体是[服务定位器](concept-service-locator.md),它部署一组提供各种不同功能的 *应用组件* 来处理请求。
例如,`urlManager`组件负责处理网页请求路由到对应的控制器。`db`组件提供数据库相关服务等等。
应用主体是[服务定位器](concept-service-locator.md),
它部署一组提供各种不同功能的 *应用组件* 来处理请求。
例如,`urlManager`组件负责处理网页请求路由到对应的控制器。
`db`组件提供数据库相关服务等等。
在同一个应用中,每个应用组件都有一个独一无二的 ID 用来区分其他应用组件,你可以通过如下表达式访问应用组件。
在同一个应用中,每个应用组件都有一个独一无二的 ID 用来区分其他应用组件,
你可以通过如下表达式访问应用组件。
```php
\Yii::$app->componentID
@ -13,9 +16,11 @@
例如,可以使用 `\Yii::$app->db` 来获取到已注册到应用的 [[yii\db\Connection|DB connection]],
使用 `\Yii::$app->cache` 来获取到已注册到应用的 [[yii\caching\Cache|primary cache]]。
第一次使用以上表达式时候会创建应用组件实例,后续再访问会返回此实例,无需再次创建。
第一次使用以上表达式时候会创建应用组件实例,
后续再访问会返回此实例,无需再次创建。
应用组件可以是任意对象,可以在 [应用主体配置](structure-applications.md#application-configurations)配置 [[yii\base\Application::components]] 属性 .
应用组件可以是任意对象,可以在
[应用主体配置](structure-applications.md#application-configurations)配置 [[yii\base\Application::components]] 属性 .
例如:
```php
@ -40,17 +45,16 @@
]
```
<<<<<<< .merge_file_a05900
> 补充:请谨慎注册太多应用组件,应用组件就像全局变量,使用太多可能加大测试和维护的难度。
=======
> Info: 请谨慎注册太多应用组件,应用组件就像全局变量,使用太多可能加大测试和维护的难度。
>>>>>>> .merge_file_a06508
> 补充:请谨慎注册太多应用组件,
应用组件就像全局变量,
使用太多可能加大测试和维护的难度。
一般情况下可以在需要时再创建本地组件。
## 引导启动组件 <span id="bootstrapping-components"></span>
上面提到一个应用组件只会在第一次访问时实例化,如果处理请求过程没有访问的话就不实例化。
上面提到一个应用组件只会在第一次访问时实例化,
如果处理请求过程没有访问的话就不实例化。
有时你想在每个请求处理过程都实例化某个组件即便它不会被访问,
可以将该组件ID加入到应用主体的 [[yii\base\Application::bootstrap|bootstrap]] 属性中。
@ -79,27 +83,37 @@ Yii 定义了一组固定ID和默认配置的 *核心* 组件,例如 [[yii\web
通过这些组件,Yii应用主体能处理用户请求。
下面是预定义的核心应用组件列表,可以和普通应用组件一样配置和自定义它们。
当你配置一个核心组件,不指定它的类名的话就会使用Yii默认指定的类。
当你配置一个核心组件,
不指定它的类名的话就会使用Yii默认指定的类。
* [[yii\web\AssetManager|assetManager]]: 管理资源包和资源发布,详情请参考 [管理资源](output-assets.md) 一节。
* [[yii\web\AssetManager|assetManager]]: 管理资源包和资源发布,
详情请参考 [管理资源](output-assets.md) 一节。
* [[yii\db\Connection|db]]: 代表一个可以执行数据库操作的数据库连接,
注意配置该组件时必须指定组件类名和其他相关组件属性,如[[yii\db\Connection::dsn]]。
注意配置该组件时必须指定组件类名和其他相关组件属性,
如[[yii\db\Connection::dsn]]。
详情请参考 [数据访问对象](db-dao.md) 一节。
* [[yii\base\Application::errorHandler|errorHandler]]: 处理 PHP 错误和异常,
详情请参考 [错误处理](tutorial-handling-errors.md) 一节。
* [[yii\i18n\Formatter|formatter]]: 格式化输出显示给终端用户的数据,例如数字可能要带分隔符,
* [[yii\i18n\Formatter|formatter]]: 格式化输出显示给终端用户的数据,
例如数字可能要带分隔符,
日期使用长格式。详情请参考 [格式化输出数据](output-formatting.md) 一节。
* [[yii\i18n\I18N|i18n]]: 支持信息翻译和格式化。详情请参考 [国际化](tutorial-i18n.md) 一节。
* [[yii\log\Dispatcher|log]]: 管理日志对象。详情请参考 [日志](tutorial-logging.md) 一节。
* [[yii\swiftmailer\Mailer|mail]]: 支持生成邮件结构并发送,详情请参考 [邮件](tutorial-mailing.md) 一节。
* [[yii\i18n\I18N|i18n]]: 支持信息翻译和格式化。
详情请参考 [国际化](tutorial-i18n.md) 一节。
* [[yii\log\Dispatcher|log]]: 管理日志对象。
详情请参考 [日志](tutorial-logging.md) 一节。
* [[yii\swiftmailer\Mailer|mail]]: 支持生成邮件结构并发送,
详情请参考 [邮件](tutorial-mailing.md) 一节。
* [[yii\base\Application::response|response]]: 代表发送给用户的响应,
详情请参考 [响应](runtime-responses.md) 一节。
* [[yii\base\Application::request|request]]: 代表从终端用户处接收到的请求,
详情请参考 [请求](runtime-requests.md) 一节。
* [[yii\web\Session|session]]: 代表会话信息,仅在[[yii\web\Application|Web applications]] 网页应用中可用,
* [[yii\web\Session|session]]: 代表会话信息,
仅在[[yii\web\Application|Web applications]] 网页应用中可用,
详情请参考 [Sessions (会话) and Cookies](runtime-sessions-cookies.md) 一节。
* [[yii\web\UrlManager|urlManager]]: 支持URL地址解析和创建,
详情请参考 [URL 解析和生成](runtime-url-handling.md) 一节。
* [[yii\web\User|user]]: 代表认证登录用户信息,仅在[[yii\web\Application|Web applications]] 网页应用中可用,
* [[yii\web\User|user]]: 代表认证登录用户信息,
仅在[[yii\web\Application|Web applications]] 网页应用中可用,
详情请参考 [认证](security-authentication.md) 一节。
* [[yii\web\View|view]]: 支持渲染视图,详情请参考 [Views](structure-views.md) 一节。
* [[yii\web\View|view]]: 支持渲染视图,
详情请参考 [Views](structure-views.md) 一节。

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

@ -2,17 +2,21 @@
============
应用主体是管理 Yii 应用系统整体结构和生命周期的对象。
每个Yii应用系统只能包含一个应用主体,应用主体在 [入口脚本](structure-entry-scripts.md) 中创建并能通过表达式 `\Yii::$app` 全局范围内访问。
每个Yii应用系统只能包含一个应用主体,
应用主体在 [入口脚本](structure-entry-scripts.md) 中创建并能通过表达式 `\Yii::$app` 全局范围内访问。
> Info: 当我们说"一个应用",它可能是一个应用主体对象,也可能是一个应用系统,是根据上下文来决定[译:中文为避免歧义,Application翻译为应用主体]。
> Info: 当我们说"一个应用",它可能是一个应用主体对象,也可能是一个应用系统,
是根据上下文来决定[译:中文为避免歧义,Application翻译为应用主体]。
Yii有两种应用主体: [[yii\web\Application|网页应用主体]] and
[[yii\console\Application|控制台应用主体]], 如名称所示,前者主要处理网页请求,后者处理控制台请求。
[[yii\console\Application|控制台应用主体]],
如名称所示,前者主要处理网页请求,后者处理控制台请求。
## 应用主体配置 <span id="application-configurations"></span>
如下所示,当 [入口脚本](structure-entry-scripts.md) 创建了一个应用主体,它会加载一个 [配置](concept-configurations.md) 文件并传给应用主体。
如下所示,当 [入口脚本](structure-entry-scripts.md) 创建了一个应用主体,
它会加载一个 [配置](concept-configurations.md) 文件并传给应用主体。
```php
require(__DIR__ . '/../vendor/autoload.php');
@ -25,47 +29,60 @@ $config = require(__DIR__ . '/../config/web.php');
(new yii\web\Application($config))->run();
```
类似其他 [配置](concept-configurations.md) 文件, 应用主体配置文件标明如何设置应用对象初始属性。
由于应用主体配置比较复杂,一般保存在多个类似如上web.php的 [配置文件](concept-configurations.md#configuration-files) 当中。
类似其他 [配置](concept-configurations.md) 文件,
应用主体配置文件标明如何设置应用对象初始属性。
由于应用主体配置比较复杂,
一般保存在多个类似如上web.php的 [配置文件](concept-configurations.md#configuration-files) 当中。
## 应用主体属性 <span id="application-properties"></span>
应用主体配置文件中有许多重要的属性要配置,这些属性指定应用主体的运行环境。
比如,应用主体需要知道如何加载 [控制器](structure-controllers.md) ,临时文件保存到哪儿等等。
以下我们简述这些属性。
应用主体配置文件中有许多重要的属性要配置,
这些属性指定应用主体的运行环境。
比如,应用主体需要知道如何加载 [控制器](structure-controllers.md) ,
临时文件保存到哪儿等等。以下我们简述这些属性。
### 必要属性 <span id="required-properties"></span>
在一个应用中,至少要配置2个属性: [[yii\base\Application::id|id]] 和 [[yii\base\Application::basePath|basePath]]。
在一个应用中,至少要配置2个属性:
[[yii\base\Application::id|id]] 和 [[yii\base\Application::basePath|basePath]]。
#### [[yii\base\Application::id|id]] <span id="id"></span>
[[yii\base\Application::id|id]] 属性用来区分其他应用的唯一标识ID。主要给程序使用。
为了方便协作,最好使用数字作为应用主体ID,但不强制要求为数字。
[[yii\base\Application::id|id]] 属性用来区分其他应用的唯一标识ID。
主要给程序使用。为了方便协作,最好使用数字作为应用主体ID,
但不强制要求为数字。
#### [[yii\base\Application::basePath|basePath]] <span id="basePath"></span>
[[yii\base\Application::basePath|basePath]] 指定该应用的根目录。根目录包含应用系统所有受保护的源代码。
在根目录下可以看到对应MVC设计模式的`models`, `views`, `controllers`等子目录。
[[yii\base\Application::basePath|basePath]] 指定该应用的根目录。
根目录包含应用系统所有受保护的源代码。
在根目录下可以看到对应MVC设计模式的`models`,
`views`, `controllers`等子目录。
可以使用路径或 [路径别名](concept-aliases.md) 来在配置 [[yii\base\Application::basePath|basePath]] 属性。
两种格式所对应的目录都必须存在,否则系统会抛出一个异常。 系统会使用 `realpath()` 函数规范化配置的路径.
两种格式所对应的目录都必须存在,否则系统会抛出一个异常。
系统会使用 `realpath()` 函数规范化配置的路径.
[[yii\base\Application::basePath|basePath]] 属性经常用于派生一些其他重要路径(如runtime路径),因此,系统预定义 `@app` 代表这个路径。
[[yii\base\Application::basePath|basePath]] 属性经常用于派生一些其他重要路径(如runtime路径),
因此,系统预定义 `@app` 代表这个路径。
派生路径可以通过这个别名组成(如`@app/runtime`代表runtime的路径)。
### 重要属性 <span id="important-properties"></span>
本小节所描述的属性通常需要设置,因为不同的应用属性不同。
本小节所描述的属性通常需要设置,
因为不同的应用属性不同。
#### [[yii\base\Application::aliases|aliases]] <span id="aliases"></span>
该属性允许你用一个数组定义多个 [别名](concept-aliases.md)。数组的key为别名名称,值为对应的路径。例如:
该属性允许你用一个数组定义多个 [别名](concept-aliases.md)。
数组的key为别名名称,值为对应的路径。
例如:
```php
[
@ -76,13 +93,16 @@ $config = require(__DIR__ . '/../config/web.php');
]
```
使用这个属性来定义别名,代替 [[Yii::setAlias()]] 方法来设置。
使用这个属性来定义别名,
代替 [[Yii::setAlias()]] 方法来设置。
#### [[yii\base\Application::bootstrap|bootstrap]] <span id="bootstrap"></span>
这个属性很实用,它允许你用数组指定启动阶段[[yii\base\Application::bootstrap()|bootstrapping process]]需要运行的组件。
比如,如果你希望一个 [模块](structure-modules.md) 自定义 [URL 规则](runtime-url-handling.md),你可以将模块ID加入到bootstrap数组中。
这个属性很实用,它允许你用数组指定启动阶段
[[yii\base\Application::bootstrap()|bootstrapping process]]需要运行的组件。
比如,如果你希望一个 [模块](structure-modules.md) 自定义 [URL 规则](runtime-url-handling.md),
你可以将模块ID加入到bootstrap数组中。
属性中的每个组件需要指定以下一项:
@ -117,7 +137,10 @@ $config = require(__DIR__ . '/../config/web.php');
]
```
> Info: 如果模块ID和应用组件ID同名,优先使用应用组件ID,如果你想用模块ID,可以使用如下无名称函数返回模块ID。
> Info: 如果模块ID和应用组件ID同名,
> 优先使用应用组件ID,如果你想用模块ID,
> 可以使用如下无名称函数返回模块ID。
>
> ```php
[
function () {
@ -127,9 +150,12 @@ $config = require(__DIR__ . '/../config/web.php');
```
在启动阶段,每个组件都会实例化。如果组件类实现接口 [[yii\base\BootstrapInterface]],也会调用 [[yii\base\BootstrapInterface::bootstrap()|bootstrap()]] 方法。
在启动阶段,每个组件都会实例化。
如果组件类实现接口 [[yii\base\BootstrapInterface]],
也会调用 [[yii\base\BootstrapInterface::bootstrap()|bootstrap()]] 方法。
举一个实际的例子,[Basic Application Template](start-installation.md) 应用主体配置中,
举一个实际的例子,
[Basic Application Template](start-installation.md) 应用主体配置中,
开发环境下会在启动阶段运行 `debug``gii` 模块。
```php
@ -143,15 +169,18 @@ if (YII_ENV_DEV) {
}
```
> 注: 启动太多的组件会降低系统性能,因为每次请求都需要重新运行启动组件,因此谨慎配置启动组件。
> 注: 启动太多的组件会降低系统性能,
因为每次请求都需要重新运行启动组件,因此谨慎配置启动组件。
#### [[yii\web\Application::catchAll|catchAll]] <span id="catchAll"></span>
该属性仅 [[yii\web\Application|Web applications]] 网页应用支持。
它指定一个要处理所有用户请求的 [控制器方法](structure-controllers.md),通常在维护模式下使用,同一个方法处理所有用户请求。
它指定一个要处理所有用户请求的 [控制器方法](structure-controllers.md),
通常在维护模式下使用,同一个方法处理所有用户请求。
该配置为一个数组,第一项指定动作的路由,剩下的数组项(key-value 成对)指定传递给动作的参数,例如:
该配置为一个数组,第一项指定动作的路由,
剩下的数组项(key-value 成对)指定传递给动作的参数,例如:
```php
[
@ -163,10 +192,12 @@ if (YII_ENV_DEV) {
]
```
> Info: Debug panel on development environment will not work when this property is enabled
#### [[yii\base\Application::components|components]] <span id="components"></span>
这是最重要的属性,它允许你注册多个在其他地方使用的[应用组件](#structure-application-components.md). 例如
这是最重要的属性,它允许你注册多个在其他地方使用的[应用组件](#structure-application-components.md)。
例如
```php
[
@ -182,17 +213,21 @@ if (YII_ENV_DEV) {
]
```
每一个应用组件指定一个key-value对的数组,key代表组件ID,value代表组件类名或 [配置](concept-configurations.md)。
每一个应用组件指定一个key-value对的数组,key代表组件ID,
value代表组件类名或 [配置](concept-configurations.md)。
在应用中可以任意注册组件,并可以通过表达式 `\Yii::$app->ComponentID` 全局访问。
在应用中可以任意注册组件,
并可以通过表达式 `\Yii::$app->ComponentID` 全局访问。
详情请阅读 [应用组件](structure-application-components.md) 一节.
#### [[yii\base\Application::controllerMap|controllerMap]] <span id="controllerMap"></span>
该属性允许你指定一个控制器ID到任意控制器类。Yii遵循一个默认的 [规则](#controllerNamespace)指定控制器ID到任意控制器类(如`post`对应`app\controllers\PostController`)。
通过配置这个属性,可以打破这个默认规则,在下面的例子中,`account`对应到`app\controllers\UserController`,
该属性允许你指定一个控制器ID到任意控制器类。
Yii遵循一个默认的 [规则](#controllerNamespace)指定控制器ID到任意控制器类(如`post`对应`app\controllers\PostController`)。
通过配置这个属性,可以打破这个默认规则,在下面的例子中,
`account`对应到`app\controllers\UserController`,
`article` 对应到 `app\controllers\PostController`
```php
@ -209,31 +244,41 @@ if (YII_ENV_DEV) {
]
```
数组的键代表控制器ID,数组的值代表对应的类名。
数组的键代表控制器ID,
数组的值代表对应的类名。
#### [[yii\base\Application::controllerNamespace|controllerNamespace]] <span id="controllerNamespace"></span>
该属性指定控制器类默认的命名空间,默认为`app\controllers`。比如控制器ID为 `post` 默认对应 `PostController` (不带命名空间),
该属性指定控制器类默认的命名空间,默认为`app\controllers`。
比如控制器ID为 `post` 默认对应 `PostController` (不带命名空间),
类全名为 `app\controllers\PostController`
控制器类文件可能放在这个命名空间对应目录的子目录下,
例如,控制器ID `admin/post` 对应的控制器类全名为 `app\controllers\admin\PostController`
例如,控制器ID `admin/post` 对应的控制器类全名为
`app\controllers\admin\PostController`
控制器类全面能被 [自动加载](concept-autoloading.md),这点是非常重要的,控制器类的实际命名空间对应这个属性,
控制器类全面能被 [自动加载](concept-autoloading.md),这点是非常重要的,
控制器类的实际命名空间对应这个属性,
否则,访问时你会收到"Page Not Found"[译:页面找不到]。
如果你想打破上述的规则,可以配置 [controllerMap](#controllerMap) 属性。
如果你想打破上述的规则,
可以配置 [controllerMap](#controllerMap) 属性。
#### [[yii\base\Application::language|language]] <span id="language"></span>
该属性指定应用展示给终端用户的语言,默认为 `en` 标识英文。如果需要之前其他语言可以配置该属性。
该属性指定应用展示给终端用户的语言,
默认为 `en` 标识英文。
如果需要之前其他语言可以配置该属性。
该属性影响各种 [国际化](tutorial-i18n.md) ,包括信息翻译、日期格式、数字格式等。
例如 [[yii\jui\DatePicker]] 小部件会根据该属性展示对应语言的日历以及日期格式。
该属性影响各种 [国际化](tutorial-i18n.md) ,
包括信息翻译、日期格式、数字格式等。
例如 [[yii\jui\DatePicker]] 小部件会
根据该属性展示对应语言的日历以及日期格式。
推荐遵循 [IETF language tag](http://en.wikipedia.org/wiki/IETF_language_tag) 来设置语言,例如 `en` 代表英文, `en-US` 代表英文(美国).
推荐遵循 [IETF language tag](http://en.wikipedia.org/wiki/IETF_language_tag) 来设置语言,
例如 `en` 代表英文, `en-US` 代表英文(美国)。
该属性的更多信息可参考 [国际化](tutorial-i18n.md) 一节.
@ -242,7 +287,8 @@ if (YII_ENV_DEV) {
该属性指定应用所包含的 [模块](structure-modules.md)。
该属性使用数组包含多个模块类 [配置](concept-configurations.md),数组的键为模块ID,例:
该属性使用数组包含多个模块类 [配置](concept-configurations.md),
数组的键为模块ID,例:
```php
[
@ -264,7 +310,8 @@ if (YII_ENV_DEV) {
#### [[yii\base\Application::name|name]] <span id="name"></span>
该属性指定你可能想展示给终端用户的应用名称,不同于需要唯一性的 [[yii\base\Application::id|id]] 属性,
该属性指定你可能想展示给终端用户的应用名称,
不同于需要唯一性的 [[yii\base\Application::id|id]] 属性,
该属性可以不唯一,该属性用于显示应用的用途。
如果其他地方的代码没有用到,可以不配置该属性。
@ -272,7 +319,9 @@ if (YII_ENV_DEV) {
#### [[yii\base\Application::params|params]] <span id="params"></span>
该属性为一个数组,指定可以全局访问的参数,代替程序中硬编码的数字和字符,应用中的参数定义到一个单独的文件并随时可以访问是一个好习惯。
该属性为一个数组,指定可以全局访问的参数,
代替程序中硬编码的数字和字符,
应用中的参数定义到一个单独的文件并随时可以访问是一个好习惯。
例如用参数定义缩略图的长宽如下:
```php
@ -290,14 +339,17 @@ $size = \Yii::$app->params['thumbnail.size'];
$width = \Yii::$app->params['thumbnail.size'][0];
```
以后想修改缩略图长宽,只需要修改该参数而不需要相关的代码。
以后想修改缩略图长宽,
只需要修改该参数而不需要相关的代码。
#### [[yii\base\Application::sourceLanguage|sourceLanguage]] <span id="sourceLanguage"></span>
该属性指定应用代码的语言,默认为 `'en-US'` 标识英文(美国),如果应用不是英文请修改该属性。
该属性指定应用代码的语言,默认为 `'en-US'` 标识英文(美国),
如果应用不是英文请修改该属性。
和 [语言](#language) 属性类似,配置该属性需遵循 [IETF language tag](http://en.wikipedia.org/wiki/IETF_language_tag).
和 [语言](#language) 属性类似,
配置该属性需遵循 [IETF language tag](http://en.wikipedia.org/wiki/IETF_language_tag).
例如 `en` 代表英文, `en-US` 代表英文(美国)。
该属性的更多信息可参考 [国际化](tutorial-i18n.md) 一节.
@ -306,7 +358,8 @@ $width = \Yii::$app->params['thumbnail.size'][0];
#### [[yii\base\Application::timeZone|timeZone]] <span id="timeZone"></span>
该属性提供一种方式修改PHP运行环境中的默认时区,配置该属性本质上就是调用PHP函数
[date_default_timezone_set()](http://php.net/manual/en/function.date-default-timezone-set.php),例如:
[date_default_timezone_set()](http://php.net/manual/en/function.date-default-timezone-set.php),
例如:
```php
[
@ -317,25 +370,31 @@ $width = \Yii::$app->params['thumbnail.size'][0];
#### [[yii\base\Application::version|version]] <span id="version"></span>
该属性指定应用的版本,默认为`'1.0'`,其他代码不使用的话可以不配置。
该属性指定应用的版本,默认为`'1.0'`,
其他代码不使用的话可以不配置。
### 实用属性 <span id="useful-properties"></span>
本小节描述的属性不经常设置,通常使用系统默认值。如果你想改变默认值,可以配置这些属性。
本小节描述的属性不经常设置,通常使用系统默认值。
如果你想改变默认值,可以配置这些属性。
#### [[yii\base\Application::charset|charset]] <span id="charset"></span>
该属性指定应用使用的字符集,默认值为 `'UTF-8'`,绝大部分应用都在使用,除非已有的系统大量使用非unicode数据才需要更改该属性。
该属性指定应用使用的字符集,默认值为 `'UTF-8'`
绝大部分应用都在使用,除非已有的系统大量使用非unicode数据才需要更改该属性。
#### [[yii\base\Application::defaultRoute|defaultRoute]] <span id="defaultRoute"></span>
该属性指定未配置的请求的响应 [路由](runtime-routing.md) 规则,路由规则可能包含模块ID,控制器ID,动作ID。
例如`help`, `post/create`, `admin/post/create`,如果动作ID没有指定,会使用[[yii\base\Controller::defaultAction]]中指定的默认值。
该属性指定未配置的请求的响应 [路由](runtime-routing.md) 规则,
路由规则可能包含模块ID,控制器ID,动作ID。
例如`help`, `post/create`, `admin/post/create`,如果动作ID没有指定,
会使用[[yii\base\Controller::defaultAction]]中指定的默认值。
对于 [[yii\web\Application|Web applications]] 网页应用,默认值为 `'site'` 对应 `SiteController` 控制器,并使用默认的动作。
对于 [[yii\web\Application|Web applications]] 网页应用,
默认值为 `'site'` 对应 `SiteController` 控制器,并使用默认的动作。
因此你不带路由的访问应用,默认会显示 `app\controllers\SiteController::actionIndex()` 的结果。
对于 [[yii\console\Application|console applications]] 控制台应用,
@ -345,16 +404,9 @@ $width = \Yii::$app->params['thumbnail.size'][0];
#### [[yii\base\Application::extensions|extensions]] <span id="extensions"></span>
该属性用数组列表指定应用安装和使用的 [扩展](structure-extensions.md),默认使用`@vendor/yiisoft/extensions.php`文件返回的数组。
<<<<<<< .merge_file_a06168
<<<<<<< HEAD
该属性用数组列表指定应用安装和使用的 [扩展](structure-extensions.md),
默认使用`@vendor/yiisoft/extensions.php`文件返回的数组。
当你使用 [Composer](http://getcomposer.org) 安装扩展,`extensions.php` 会被自动生成和维护更新。
=======
当你使用 [Composer](https://getcomposer.org) 安装扩展,`extensions.php` 会被自动生成和维护更新。
>>>>>>> yiichina/master
=======
当你使用 [Composer](https://getcomposer.org) 安装扩展,`extensions.php` 会被自动生成和维护更新。
>>>>>>> .merge_file_a06960
所以大多数情况下,不需要配置该属性。
特殊情况下你想自己手动维护扩展,可以参照如下配置该属性:
@ -379,21 +431,25 @@ $width = \Yii::$app->params['thumbnail.size'][0];
```
如上所示,该属性包含一个扩展定义数组,每个扩展为一个包含 `name``version` 项的数组。
如果扩展要在 [引导启动](runtime-bootstrapping.md) 阶段运行,需要配置 `bootstrap`以及对应的引导启动类名或 [configuration](concept-configurations.md) 数组。
如果扩展要在 [引导启动](runtime-bootstrapping.md) 阶段运行,
需要配置 `bootstrap`以及对应的引导启动类名或 [configuration](concept-configurations.md) 数组。
扩展也可以定义 [别名](concept-aliases.md)
#### [[yii\base\Application::layout|layout]] <span id="layout"></span>
该属性指定渲染 [视图](structure-views.md) 默认使用的布局名字,默认值为 `'main'` 对应[布局路径](#layoutPath)下的 `main.php` 文件,
如果 [布局路径](#layoutPath) 和 [视图路径](#viewPath) 都是默认值,默认布局文件可以使用路径别名`@app/views/layouts/main.php`
该属性指定渲染 [视图](structure-views.md) 默认使用的布局名字,
默认值为 `'main'` 对应[布局路径](#layoutPath)下的 `main.php` 文件,
如果 [布局路径](#layoutPath) 和 [视图路径](#viewPath) 都是默认值,
默认布局文件可以使用路径别名`@app/views/layouts/main.php`
如果不想设置默认布局文件,可以设置该属性为 `false`,这种做法比较罕见。
#### [[yii\base\Application::layoutPath|layoutPath]] <span id="layoutPath"></span>
该属性指定查找布局文件的路径,默认值为 [视图路径](#viewPath) 下的 `layouts` 子目录。
该属性指定查找布局文件的路径,
默认值为 [视图路径](#viewPath) 下的 `layouts` 子目录。
如果 [视图路径](#viewPath) 使用默认值,默认的布局路径别名为`@app/views/layouts`。
该属性需要配置成一个目录或 路径 [别名](concept-aliases.md)。
@ -401,9 +457,11 @@ $width = \Yii::$app->params['thumbnail.size'][0];
#### [[yii\base\Application::runtimePath|runtimePath]] <span id="runtimePath"></span>
该属性指定临时文件如日志文件、缓存文件等保存路径,默认值为带别名的 `@app/runtime`
该属性指定临时文件如日志文件、缓存文件等保存路径,
默认值为带别名的 `@app/runtime`
可以配置该属性为一个目录或者路径 [别名](concept-aliases.md),注意应用运行时有对该路径的写入权限,
可以配置该属性为一个目录或者路径 [别名](concept-aliases.md),
注意应用运行时有对该路径的写入权限,
以及终端用户不能访问该路径因为临时文件可能包含一些敏感信息。
为了简化访问该路径,Yii预定义别名 `@runtime` 代表该路径。
@ -411,35 +469,32 @@ $width = \Yii::$app->params['thumbnail.size'][0];
#### [[yii\base\Application::viewPath|viewPath]] <span id="viewPath"></span>
该路径指定视图文件的根目录,默认值为带别名的 `@app/views`,可以配置它为一个目录或者路径 [别名](concept-aliases.md).
该路径指定视图文件的根目录,默认值为带别名的 `@app/views`
可以配置它为一个目录或者路径 [别名](concept-aliases.md).
#### [[yii\base\Application::vendorPath|vendorPath]] <span id="vendorPath"></span>
<<<<<<< .merge_file_a06168
<<<<<<< HEAD
该属性指定 [Composer](http://getcomposer.org) 管理的供应商路径,该路径包含应用使用的包括Yii框架在内的所有第三方库。
=======
该属性指定 [Composer](https://getcomposer.org) 管理的供应商路径,该路径包含应用使用的包括Yii框架在内的所有第三方库。
>>>>>>> yiichina/master
=======
该属性指定 [Composer](https://getcomposer.org) 管理的供应商路径,该路径包含应用使用的包括Yii框架在内的所有第三方库。
>>>>>>> .merge_file_a06960
该属性指定 [Composer](http://getcomposer.org) 管理的供应商路径,
该路径包含应用使用的包括 Yii 框架在内的所有第三方库。
默认值为带别名的 `@app/vendor`
可以配置它为一个目录或者路径 [别名](concept-aliases.md),当你修改时,务必修改对应的 Composer 配置。
可以配置它为一个目录或者路径 [别名](concept-aliases.md),当你修改时,
务必修改对应的 Composer 配置。
为了简化访问该路径,Yii预定义别名 `@vendor` 代表该路径。
#### [[yii\console\Application::enableCoreCommands|enableCoreCommands]] <span id="enableCoreCommands"></span>
该属性仅 [[yii\console\Application|console applications]] 控制台应用支持, 用来指定是否启用Yii中的核心命令,默认值为 `true`
该属性仅 [[yii\console\Application|console applications]] 控制台应用支持,
用来指定是否启用Yii中的核心命令,默认值为 `true`
## 应用事件 <span id="application-events"></span>
应用在处理请求过程中会触发事件,可以在配置文件配置事件处理代码,如下所示:
应用在处理请求过程中会触发事件,
可以在配置文件配置事件处理代码,如下所示:
```php
[
@ -449,9 +504,11 @@ $width = \Yii::$app->params['thumbnail.size'][0];
]
```
`on eventName` 语法的用法在 [Configurations](concept-configurations.md#configuration-format) 一节有详细描述.
`on eventName` 语法的用法在 [Configurations](concept-configurations.md#configuration-format)
一节有详细描述.
另外,在应用主体实例化后,你可以在[引导启动](runtime-bootstrapping.md) 阶段附加事件处理代码,例如:
另外,在应用主体实例化后,你可以在[引导启动](runtime-bootstrapping.md) 阶段附加事件处理代码,
例如:
```php
\Yii::$app->on(\yii\base\Application::EVENT_BEFORE_REQUEST, function ($event) {
@ -463,25 +520,31 @@ $width = \Yii::$app->params['thumbnail.size'][0];
该事件在应用处理请求*before*之前,实际的事件名为 `beforeRequest`
在事件触发前,应用主体已经实例化并配置好了,所以通过事件机制将你的代码嵌入到请求处理过程中非常不错。
在事件触发前,应用主体已经实例化并配置好了,
所以通过事件机制将你的代码嵌入到请求处理过程中非常不错。
例如在事件处理中根据某些参数动态设置[[yii\base\Application::language]]语言属性。
### [[yii\base\Application::EVENT_AFTER_REQUEST|EVENT_AFTER_REQUEST]] <span id="afterRequest"></span>
该事件在应用处理请求*after*之后但在返回响应*before*之前触发,实际的事件名为`afterRequest`。
该事件在应用处理请求*after*之后但在返回响应*before*之前触发,
实际的事件名为`afterRequest`。
该事件触发时,请求已经被处理完,可以做一些请求后处理或自定义响应。
该事件触发时,请求已经被处理完,
可以做一些请求后处理或自定义响应。
注意 [[yii\web\Response|response]] 组件在发送响应给终端用户时也会触发一些事件,这些事件都在本事件*after*之后触发。
注意 [[yii\web\Response|response]] 组件在发送响应给终端用户时也会触发一些事件,
这些事件都在本事件*after*之后触发。
### [[yii\base\Application::EVENT_BEFORE_ACTION|EVENT_BEFORE_ACTION]] <span id="beforeAction"></span>
该事件在每个 [控制器动作](structure-controllers.md) 运行*before*之前会被触发,实际的事件名为 `beforeAction`.
该事件在每个 [控制器动作](structure-controllers.md) 运行*before*之前会被触发,
实际的事件名为 `beforeAction`.
事件的参数为一个 [[yii\base\ActionEvent]] 实例,
事件处理中可以设置[[yii\base\ActionEvent::isValid]] 为 `false` 停止运行后续动作,例如:
事件处理中可以设置[[yii\base\ActionEvent::isValid]] 为 `false` 停止运行后续动作,
例如:
```php
[
@ -496,14 +559,17 @@ $width = \Yii::$app->params['thumbnail.size'][0];
注意 [模块](structure-modules.md) 和 [控制器](structure-controllers.md) 都会触发 `beforeAction` 事件。
应用主体对象首先触发该事件,然后模块触发(如果存在模块),最后控制器触发。
任何一个事件处理中设置 [[yii\base\ActionEvent::isValid]] 设置为 `false` 会停止触发后面的事件。
任何一个事件处理中设置 [[yii\base\ActionEvent::isValid]]
设置为 `false` 会停止触发后面的事件。
### [[yii\base\Application::EVENT_AFTER_ACTION|EVENT_AFTER_ACTION]] <span id="afterAction"></span>
该事件在每个 [控制器动作](structure-controllers.md) 运行*after*之后会被触发,实际的事件名为 `afterAction`.
该事件在每个 [控制器动作](structure-controllers.md) 运行*after*之后会被触发,
实际的事件名为 `afterAction`.
该事件的参数为 [[yii\base\ActionEvent]] 实例,通过[[yii\base\ActionEvent::result]]属性,
该事件的参数为 [[yii\base\ActionEvent]] 实例,
通过[[yii\base\ActionEvent::result]]属性,
事件处理可以访问和修改动作的结果。例如:
```php
@ -517,23 +583,31 @@ $width = \Yii::$app->params['thumbnail.size'][0];
]
```
注意 [模块](structure-modules.md) 和 [控制器](structure-controllers.md) 都会触发 `afterAction` 事件。
这些对象的触发顺序和 `beforeAction` 相反,也就是说,控制器最先触发,然后是模块(如果有模块),最后为应用主体。
注意 [模块](structure-modules.md) 和 [控制器](structure-controllers.md)
都会触发 `afterAction` 事件。
这些对象的触发顺序和 `beforeAction` 相反,也就是说,控制器最先触发,
然后是模块(如果有模块),最后为应用主体。
## 应用主体生命周期 <span id="application-lifecycle"></span>
当运行 [入口脚本](structure-entry-scripts.md) 处理请求时,应用主体会经历以下生命周期:
![Application Lifecycle](images/application-lifecycle.png)
当运行 [入口脚本](structure-entry-scripts.md) 处理请求时,
应用主体会经历以下生命周期:
1. 入口脚本加载应用主体配置数组。
2. 入口脚本创建一个应用主体实例:
* 调用 [[yii\base\Application::preInit()|preInit()]] 配置几个高级别应用主体属性,比如[[yii\base\Application::basePath|basePath]]。
* 调用 [[yii\base\Application::preInit()|preInit()]] 配置几个高级别应用主体属性,
比如[[yii\base\Application::basePath|basePath]]。
* 注册 [[yii\base\Application::errorHandler|error handler]] 错误处理方法.
* 配置应用主体属性.
* 调用 [[yii\base\Application::init()|init()]] 初始化,该函数会调用 [[yii\base\Application::bootstrap()|bootstrap()]] 运行引导启动组件.
* 调用 [[yii\base\Application::init()|init()]] 初始化,
该函数会调用 [[yii\base\Application::bootstrap()|bootstrap()]] 运行引导启动组件.
3. 入口脚本调用 [[yii\base\Application::run()]] 运行应用主体:
* 触发 [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_BEFORE_REQUEST]] 事件。
* 处理请求:解析请求 [路由](runtime-routing.md) 和相关参数;创建路由指定的模块、控制器和动作对应的类,并运行动作。
* 处理请求:解析请求 [路由](runtime-routing.md) 和相关参数;
创建路由指定的模块、控制器和动作对应的类,并运行动作。
* 触发 [[yii\base\Application::EVENT_AFTER_REQUEST|EVENT_AFTER_REQUEST]] 事件。
* 发送响应到终端用户.
4. 入口脚本接收应用主体传来的退出状态并完成请求的处理。

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

@ -4,21 +4,26 @@
Yii中的资源是和Web页面相关的文件,可为CSS文件,JavaScript文件,图片或视频等,
资源放在Web可访问的目录下,直接被Web服务器调用。
通过程序自动管理资源更好一点,例如,当你在页面中使用 [[yii\jui\DatePicker]] 小部件时,
通过程序自动管理资源更好一点,例如,
当你在页面中使用 [[yii\jui\DatePicker]] 小部件时,
它会自动包含需要的CSS和JavaScript文件,而不是要求你手工去找到这些文件并包含,
当你升级小部件时,它会自动使用新版本的资源文件,在本教程中,我们会详述Yii提供的强大的资源管理功能。
当你升级小部件时,它会自动使用新版本的资源文件,
在本教程中,我们会详述Yii提供的强大的资源管理功能。
## 资源包 <span id="asset-bundles"></span>
Yii在*资源包*中管理资源,资源包简单的说就是放在一个目录下的资源集合,
当在[视图](structure-views.md)中注册一个资源包,在渲染Web页面时会包含包中的CSS和JavaScript文件。
当在[视图](structure-views.md)中注册一个资源包,
在渲染Web页面时会包含包中的CSS和JavaScript文件。
## 定义资源包 <span id="defining-asset-bundles"></span>
资源包指定为继承[[yii\web\AssetBundle]]的PHP类,包名为可[自动加载](concept-autoloading.md)的PHP类名,
在资源包类中,要指定资源所在位置,包含哪些CSS和JavaScript文件以及和其他包的依赖关系。
资源包指定为继承[[yii\web\AssetBundle]]的PHP类,
包名为可[自动加载](concept-autoloading.md)的PHP类名,
在资源包类中,要指定资源所在位置,
包含哪些CSS和JavaScript文件以及和其他包的依赖关系。
如下代码定义[基础应用模板](start-installation.md)使用的主要资源包:
@ -61,67 +66,73 @@ class AppAsset extends AssetBundle
[路径别名](concept-aliases.md) 可在此处使用。
* [[yii\web\AssetBundle::baseUrl|baseUrl]]: 指定对应到[[yii\web\AssetBundle::basePath|basePath]]目录的URL,
和 [[yii\web\AssetBundle::basePath|basePath]] 类似,如果你指定 [[yii\web\AssetBundle::sourcePath|sourcePath]] 属性,
[资源管理器](#asset-manager) 会发布这些资源并覆盖该属性,[路径别名](concept-aliases.md) 可在此处使用。
* [[yii\web\AssetBundle::js|js]]: 一个包含该资源包JavaScript文件的数组,注意正斜杠"/"应作为目录分隔符,
[资源管理器](#asset-manager) 会发布这些资源并覆盖该属性,
[路径别名](concept-aliases.md) 可在此处使用。
* [[yii\web\AssetBundle::js|js]]: 一个包含该资源包JavaScript文件的数组,
注意正斜杠"/"应作为目录分隔符,
每个JavaScript文件可指定为以下两种格式之一:
- 相对路径表示为本地JavaScript文件 (如 `js/main.js`),文件实际的路径在该相对路径前加上
- 相对路径表示为本地JavaScript文件 (如 `js/main.js`),
文件实际的路径在该相对路径前加上
[[yii\web\AssetManager::basePath]],文件实际的URL在该路径前加上[[yii\web\AssetManager::baseUrl]]。
- 绝对URL地址表示为外部JavaScript文件,如
`http://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js`
`//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js`.
* [[yii\web\AssetBundle::css|css]]: 一个包含该资源包CSS文件的数组,该数组格式和 [[yii\web\AssetBundle::js|js]] 相同。
* [[yii\web\AssetBundle::depends|depends]]: 一个列出该资源包依赖的其他资源包(后两节有详细介绍)。
* [[yii\web\AssetBundle::css|css]]: 一个包含该资源包CSS文件的数组,
该数组格式和 [[yii\web\AssetBundle::js|js]] 相同。
* [[yii\web\AssetBundle::depends|depends]]: 一个列出该资源包
依赖的其他资源包(后两节有详细介绍)。
* [[yii\web\AssetBundle::jsOptions|jsOptions]]: 当调用[[yii\web\View::registerJsFile()]]注册该包 *每个* JavaScript文件时,
指定传递到该方法的选项。
* [[yii\web\AssetBundle::cssOptions|cssOptions]]: 当调用[[yii\web\View::registerCssFile()]]注册该包 *每个* css文件时,
指定传递到该方法的选项。
* [[yii\web\AssetBundle::publishOptions|publishOptions]]: 当调用[[yii\web\AssetManager::publish()]]发布该包资源文件到Web目录时
指定传递到该方法的选项,仅在指定了[[yii\web\AssetBundle::sourcePath|sourcePath]]属性时使用。
指定传递到该方法的选项,
仅在指定了[[yii\web\AssetBundle::sourcePath|sourcePath]]属性时使用。
### 资源位置 <span id="asset-locations"></span>
资源根据它们的位置可以分为:
* 源资源: 资源文件和PHP源代码放在一起,不能被Web直接访问,为了使用这些源资源,它们要拷贝到一个可Web访问的Web目录中
* 源资源: 资源文件和PHP源代码放在一起,不能被Web直接访问,
为了使用这些源资源,它们要拷贝到一个可Web访问的Web目录中
成为发布的资源,这个过程称为*发布资源*,随后会详细介绍。
* 发布资源: 资源文件放在可通过Web直接访问的Web目录中;
* 外部资源: 资源文件放在与你的Web应用不同的Web服务器上;
* 外部资源: 资源文件放在与你的Web应用不同的
Web服务器上;
当定义资源包类时候,如果你指定了[[yii\web\AssetBundle::sourcePath|sourcePath]] 属性,就表示任何使用相对路径的资源会被
当作源资源;如果没有指定该属性,就表示这些资源为发布资源(因此应指定[[yii\web\AssetBundle::basePath|basePath]] 和
当定义资源包类时候,如果你指定了[[yii\web\AssetBundle::sourcePath|sourcePath]] 属性,
就表示任何使用相对路径的资源会被当作源资源;如果没有指定该属性,
就表示这些资源为发布资源(因此应指定[[yii\web\AssetBundle::basePath|basePath]] 和
[[yii\web\AssetBundle::baseUrl|baseUrl]] 让Yii知道它们的位置)。
推荐将资源文件放到Web目录以避免不必要的发布资源过程,这就是之前的例子:指定
推荐将资源文件放到Web目录以避免不必要的发布资源过程,
这就是之前的例子:指定
[[yii\web\AssetBundle::basePath|basePath]] 而不是 [[yii\web\AssetBundle::sourcePath|sourcePath]].
对于 [扩展](structure-extensions.md)来说,由于它们的资源和源代码都在不能Web访问的目录下,
对于 [扩展](structure-extensions.md)来说,
由于它们的资源和源代码都在不能Web访问的目录下,
在定义资源包类时必须指定[[yii\web\AssetBundle::sourcePath|sourcePath]]属性。
> Note: [[yii\web\AssetBundle::sourcePath|source path]] 属性不要用`@webroot/assets`,该路径默认为
[[yii\web\AssetManager|asset manager]]资源管理器将源资源发布后存储资源的路径,该路径的所有内容会认为是临时文件,
[[yii\web\AssetManager|asset manager]]资源管理器将源资源发布后存储资源的路径,
该路径的所有内容会认为是临时文件,
可能会被删除。
### 资源依赖 <span id="asset-dependencies"></span>
当Web页面包含多个CSS或JavaScript文件时,它们有一定的先后顺序以避免属性覆盖,
当Web页面包含多个CSS或JavaScript文件时,
它们有一定的先后顺序以避免属性覆盖,
例如,Web页面在使用jQuery UI小部件前必须确保jQuery JavaScript文件已经被包含了,
我们称这种资源先后次序称为资源依赖。
资源依赖主要通过[[yii\web\AssetBundle::depends]] 属性来指定,
在`AppAsset` 示例中,资源包依赖其他两个资源包: [[yii\web\YiiAsset]] 和 [[yii\bootstrap\BootstrapAsset]]
在`AppAsset` 示例中,资源包依赖其他两个资源包:
[[yii\web\YiiAsset]] 和 [[yii\bootstrap\BootstrapAsset]]
也就是该资源包的CSS和JavaScript文件要在这两个依赖包的文件包含 *之后* 才包含。
<<<<<<< .merge_file_a00784
<<<<<<< HEAD
资源依赖关系是可传递,也就是人说A依赖B,B依赖C,那么A也依赖C。
=======
资源依赖关系是可传递,也就是说A依赖B,B依赖C,那么A也依赖C。
>>>>>>> yiichina/master
=======
资源依赖关系是可传递,也就是说A依赖B,B依赖C,那么A也依赖C。
>>>>>>> .merge_file_a03924
### 资源选项 <span id="asset-options"></span>
@ -131,7 +142,8 @@ class AppAsset extends AssetBundle
这些属性值会分别传递给 [[yii\web\View::registerCssFile()]] 和 [[yii\web\View::registerJsFile()]] 方法,
在[视图](structure-views.md) 调用这些方法包含CSS和JavaScript文件时。
> Note: 在资源包类中设置的选项会应用到该包中 *每个* CSS/JavaScript 文件,如果想对每个文件使用不同的选项,
> Note: 在资源包类中设置的选项会应用到该包中 *每个* CSS/JavaScript 文件,
如果想对每个文件使用不同的选项,
应创建不同的资源包并在每个包中使用一个选项集。
例如,只想IE9或更高的浏览器包含一个CSS文件,可以使用如下选项:
@ -154,30 +166,59 @@ public $cssOptions = ['condition' => 'lte IE9'];
public $cssOptions = ['noscript' => true];
```
为使JavaScript文件包含在页面head区域(JavaScript文件默认包含在body的结束处)使用以下选项:
为使JavaScript文件包含在页面head区域
(JavaScript文件默认包含在body的结束处)使用以下选项:
```php
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:
```php
<?php
namespace app\assets;
use yii\web\AssetBundle;
class FontAwesomeAsset extends AssetBundle
{
public $sourcePath = '@bower/font-awesome';
public $css = [
'css/font-awesome.min.css',
];
public $publishOptions = [
'only' => [
'fonts/',
'css/',
]
];
}
```
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.
### Bower 和 NPM 资源 <span id="bower-npm-assets"></span>
<<<<<<< HEAD
大多数 JavaScript/CSS 包通过[Bower](http://bower.io/) 和/或 [NPM](https://www.npmjs.org/)管理,
=======
大多数 JavaScript/CSS 包通过[Bower](http://bower.io/) 和(或) [NPM](https://www.npmjs.org/)管理,
>>>>>>> yiichina/master
如果你的应用或扩展使用这些包,推荐你遵循以下步骤来管理库中的资源:
如果你的应用或扩展使用这些包,
推荐你遵循以下步骤来管理库中的资源:
1. 修改应用或扩展的 `composer.json` 文件将包列入`require` 中,
应使用`bower-asset/PackageName` (Bower包) 或 `npm-asset/PackageName` (NPM包)来对应库。
应使用`bower-asset/PackageName` (Bower包)
`npm-asset/PackageName` (NPM包)来对应库。
2. 创建一个资源包类并将你的应用或扩展要使用的JavaScript/CSS 文件列入到类中,
应设置 [[yii\web\AssetBundle::sourcePath|sourcePath]] 属性为`@bower/PackageName` 或 `@npm/PackageName`
因为根据别名Composer会安装Bower或NPM包到对应的目录下。
> Note: 一些包会将它们分布式文件放到一个子目录中,对于这种情况,应指定子目录作为
[[yii\web\AssetBundle::sourcePath|sourcePath]]属性值,例如,[[yii\web\JqueryAsset]]使用 `@bower/jquery/dist` 而不是 `@bower/jquery`
[[yii\web\AssetBundle::sourcePath|sourcePath]]属性值,
例如,[[yii\web\JqueryAsset]]使用 `@bower/jquery/dist` 而不是 `@bower/jquery`
## 使用资源包 <span id="using-asset-bundles"></span>
@ -190,12 +231,18 @@ 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]].
如果在其他地方注册资源包,应提供视图对象,如在 [小部件](structure-widgets.md) 类中注册资源包,
可以通过 `$this->view` 获取视图对象。
当在视图中注册一个资源包时,在背后Yii会注册它所依赖的资源包,如果资源包是放在Web不可访问的目录下,会被发布到可访问的目录,
后续当视图渲染页面时,会生成这些注册包包含的CSS和JavaScript文件对应的`<link>` 和 `<script>` 标签,
这些标签的先后顺序取决于资源包的依赖关系以及在 [[yii\web\AssetBundle::css]]和[[yii\web\AssetBundle::js]] 的列出来的前后顺序。
当在视图中注册一个资源包时,在背后Yii会注册它所依赖的资源包,
如果资源包是放在Web不可访问的目录下,会被发布到可访问的目录,
后续当视图渲染页面时,
会生成这些注册包包含的CSS和JavaScript文件对应的`<link>` 和 `<script>` 标签,
这些标签的先后顺序取决于资源包的依赖关系以及在
[[yii\web\AssetBundle::css]]和[[yii\web\AssetBundle::js]] 的列出来的前后顺序。
### 自定义资源包 <span id="customizing-asset-bundles"></span>
@ -203,7 +250,8 @@ AppAsset::register($this); // $this 代表视图对象
Yii通过名为 `assetManager`的应用组件实现[[yii\web\AssetManager]] 来管理应用组件,
通过配置[[yii\web\AssetManager::bundles]] 属性,可以自定义资源包的行为,
例如,[[yii\web\JqueryAsset]] 资源包默认从jquery Bower包中使用`jquery.js` 文件,
为了提高可用性和性能,你可能需要从Google服务器上获取jquery文件,可以在应用配置中配置`assetManager`,如下所示:
为了提高可用性和性能,你可能需要从Google服务器上获取jquery文件,
可以在应用配置中配置`assetManager`,如下所示:
```php
return [
@ -223,10 +271,12 @@ return [
];
```
可通过类似[[yii\web\AssetManager::bundles]]配置多个资源包,数组的键应为资源包的类名(最开头不要反斜杠),
可通过类似[[yii\web\AssetManager::bundles]]配置多个资源包,
数组的键应为资源包的类名(最开头不要反斜杠),
数组的值为对应的[配置数组](concept-configurations.md).
> Tip: 可以根据条件判断使用哪个资源,如下示例为如何在开发环境用`jquery.js`,否则用`jquery.min.js`:
> Tip: 可以根据条件判断使用哪个资源,如下示例为如何在开发环境用`jquery.js`,
> 否则用`jquery.min.js`:
>
> ```php
> 'yii\web\JqueryAsset' => [
@ -236,12 +286,10 @@ return [
> ],
> ```
可以设置资源包的名称对应`false`来禁用想禁用的一个或多个资源包,当视图中注册一个禁用资源包,
<<<<<<< HEAD
视图不会包含任何该包的资源以及不会注册它所依赖的包,例如,为禁用[[yii\web\JqueryAsset]],可以使用如下配置:
=======
视图就不会包含任何该包的资源也不会注册它所依赖的包,例如,为禁用[[yii\web\JqueryAsset]],可以使用如下配置:
>>>>>>> yiichina/master
可以设置资源包的名称对应`false`来禁用想禁用的一个或多个资源包,
当视图中注册一个禁用资源包,
视图不会包含任何该包的资源以及不会注册它所依赖的包,
例如,为禁用[[yii\web\JqueryAsset]],可以使用如下配置:
```php
return [
@ -262,7 +310,8 @@ return [
### 资源部署 <span id="asset-mapping"></span>
有时你想"修复" 多个资源包中资源文件的错误/不兼容,例如包A使用1.11.1版本的`jquery.min.js`,
包B使用2.1.1版本的`jquery.js`,可自定义每个包来解决这个问题,更好的方式是使用*资源部署*特性来部署不正确的资源为想要的,
包B使用2.1.1版本的`jquery.js`,可自定义每个包来解决这个问题,
更好的方式是使用*资源部署*特性来部署不正确的资源为想要的,
为此,配置[[yii\web\AssetManager::assetMap]]属性,如下所示:
```php
@ -279,20 +328,25 @@ return [
```
[[yii\web\AssetManager::assetMap|assetMap]]的键为你想要修复的资源名,值为你想要使用的资源路径,
当视图注册资源包,在[[yii\web\AssetBundle::css|css]] 和 [[yii\web\AssetBundle::js|js]] 数组中每个相关资源文件会和该部署进行对比,
如果数组任何键对比为资源文件的最后文件名(如果有的话前缀为 [[yii\web\AssetBundle::sourcePath]]),对应的值为替换原来的资源。
当视图注册资源包,在[[yii\web\AssetBundle::css|css]] 和
[[yii\web\AssetBundle::js|js]] 数组中每个相关资源文件会和该部署进行对比,
如果数组任何键对比为资源文件的最后文件名
(如果有的话前缀为 [[yii\web\AssetBundle::sourcePath]]),对应的值为替换原来的资源。
例如,资源文件`my/path/to/jquery.js` 匹配键 `jquery.js`.
> Note: 只有相对相对路径指定的资源对应到资源部署,替换的资源路径可以为绝对路径,也可为和[[yii\web\AssetManager::basePath]]相关的路径。
> Note: 只有相对相对路径指定的资源对应到资源部署,替换的资源路径可以为绝对路径,
也可为和[[yii\web\AssetManager::basePath]]相关的路径。
### 资源发布 <span id="asset-publishing"></span>
如前所述,如果资源包放在Web不能访问的目录,当视图注册资源时资源会被拷贝到一个Web可访问的目录中,
如前所述,如果资源包放在Web不能访问的目录,
当视图注册资源时资源会被拷贝到一个Web可访问的目录中,
这个过程称为*资源发布*,[[yii\web\AssetManager|asset manager]]会自动处理该过程。
资源默认会发布到`@webroot/assets`目录,对应的URL为`@web/assets`,
可配置[[yii\web\AssetManager::basePath|basePath]] 和 [[yii\web\AssetManager::baseUrl|baseUrl]] 属性自定义发布位置。
可配置[[yii\web\AssetManager::basePath|basePath]] 和
[[yii\web\AssetManager::baseUrl|baseUrl]] 属性自定义发布位置。
除了拷贝文件方式发布资源,如果操作系统和Web服务器允许可以使用符号链接,该功能可以通过设置
[[yii\web\AssetManager::linkAssets|linkAssets]] 为 true 来启用。
@ -308,31 +362,56 @@ return [
];
```
使用以上配置,资源管理器会创建一个符号链接到要发布的资源包源路径,这比拷贝文件方式快并能确保发布的资源一直为最新的。
使用以上配置,
资源管理器会创建一个符号链接到要发布的资源包源路径,
这比拷贝文件方式快并能确保发布的资源一直为最新的。
### Cache Busting <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:
```php
return [
// ...
'components' => [
'assetManager' => [
'appendTimestamp' => true,
],
],
];
```
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.
## 常用资源包 <span id="common-asset-bundles"></span>
Yii框架定义许多资源包,如下资源包是最常用,可在你的应用或扩展代码中引用它们。
Yii框架定义许多资源包,如下资源包是最常用,
可在你的应用或扩展代码中引用它们。
- [[yii\web\YiiAsset]]: 主要包含`yii.js` 文件,该文件完成模块JavaScript代码组织功能,
也为 `data-method``data-confirm`属性提供特别支持和其他有用的功能。
- [[yii\web\JqueryAsset]]: 包含从jQuery bower 包的`jquery.js`文件。
- [[yii\bootstrap\BootstrapAsset]]: 包含从Twitter Bootstrap 框架的CSS文件。
- [[yii\bootstrap\BootstrapPluginAsset]]: 包含从Twitter Bootstrap 框架的JavaScript 文件来支持Bootstrap JavaScript插件。
- [[yii\bootstrap\BootstrapPluginAsset]]: 包含从Twitter Bootstrap 框架的JavaScript 文件
来支持Bootstrap JavaScript插件。
- [[yii\jui\JuiAsset]]: 包含从jQuery UI库的CSS 和 JavaScript 文件。
如果你的代码需要jQuery, jQuery UI 或 Bootstrap,应尽量使用这些预定义资源包而非自己创建,
如果这些包的默认配置不能满足你的需求,可以自定义配置,详情参考[自定义资源包](#customizing-asset-bundles)。
如果这些包的默认配置不能满足你的需求,可以自定义配置,
详情参考[自定义资源包](#customizing-asset-bundles)。
## 资源转换 <span id="asset-conversion"></span>
<<<<<<< HEAD
除了直接编写CSS 和/或 JavaScript代码,开发人员经常使用扩展语法来编写,再使用特殊的工具将它们转换成CSS/Javascript。
=======
除了直接编写CSS 和(或) JavaScript代码,开发人员经常使用扩展语法来编写,再使用特殊的工具将它们转换成CSS/Javascript。
>>>>>>> yiichina/master
例如,对于CSS代码可使用[LESS](http://lesscss.org/) 或 [SCSS](http://sass-lang.com/),
对于JavaScript 可使用 [TypeScript](http://www.typescriptlang.org/)。
@ -357,9 +436,12 @@ class AppAsset extends AssetBundle
```
当在视图中注册一个这样的资源包,[[yii\web\AssetManager|asset manager]]资源管理器会自动运行预处理工具将使用扩展语法
的资源转换成CSS/JavaScript,当视图最终渲染页面时,在页面中包含的是CSS/Javascipt文件,而不是原始的扩展语法代码文件。
的资源转换成CSS/JavaScript,当视图最终渲染页面时,
在页面中包含的是CSS/Javascipt文件,
而不是原始的扩展语法代码文件。
Yii使用文件扩展名来表示资源使用哪种扩展语法,默认可以识别如下语法和文件扩展名:
Yii使用文件扩展名来表示资源使用哪种扩展语法,
默认可以识别如下语法和文件扩展名:
- [LESS](http://lesscss.org/): `.less`
- [SCSS](http://sass-lang.com/): `.scss`
@ -367,9 +449,11 @@ Yii使用文件扩展名来表示资源使用哪种扩展语法,默认可以
- [CoffeeScript](http://coffeescript.org/): `.coffee`
- [TypeScript](http://www.typescriptlang.org/): `.ts`
Yii依靠安装的预处理工具来转换资源,例如,为使用[LESS](http://lesscss.org/),应安装`lessc` 预处理命令。
Yii依靠安装的预处理工具来转换资源,例如,
为使用[LESS](http://lesscss.org/),应安装`lessc` 预处理命令。
可配置[[yii\web\AssetManager::converter]]自定义预处理命令和支持的扩展语法,如下所示:
可配置[[yii\web\AssetManager::converter]]自定义预处理命令和支持的扩展语法,
如下所示:
```php
return [
@ -388,35 +472,40 @@ return [
```
如上所示,通过[[yii\web\AssetConverter::commands]] 属性指定支持的扩展语法,
数组的键为文件扩展名(前面不要.),数组的值为目标资源文件扩展名和执行资源转换的命令,
数组的键为文件扩展名(前面不要.),
数组的值为目标资源文件扩展名和执行资源转换的命令,
命令中的标记 `{from}` 和`{to}`会分别被源资源文件路径和目标资源文件路径替代。
> Info: 除了以上方式,也有其他的方式来处理扩展语法资源,例如,可使用编译工具如[grunt](http://gruntjs.com/)
来监控并自动转换扩展语法资源,此时,应使用资源包中编译后的CSS/Javascript文件而不是原始文件。
> Info: 除了以上方式,也有其他的方式来处理扩展语法资源,
例如,可使用编译工具如[grunt](http://gruntjs.com/)
来监控并自动转换扩展语法资源,此时,
应使用资源包中编译后的CSS/Javascript文件而不是原始文件。
## 合并和压缩资源 <span id="combining-compressing-assets"></span>
<<<<<<< HEAD
一个Web页面可以包含很多CSS 和/或 JavaScript 文件,为减少HTTP 请求和这些下载文件的大小,
=======
一个Web页面可以包含很多CSS 和(或) JavaScript 文件,为减少HTTP 请求和这些下载文件的大小,
>>>>>>> yiichina/master
通常的方式是在页面中合并并压缩多个CSS/JavaScript 文件为一个或很少的几个文件,并使用压缩后的文件而不是原始文件。
通常的方式是在页面中合并并压缩多个CSS/JavaScript 文件为一个或很少的几个文件,
并使用压缩后的文件而不是原始文件。
> Info: 合并和压缩资源通常在应用在产品上线模式,在开发模式下使用原始的CSS/JavaScript更方便调试。
> Info: 合并和压缩资源通常在应用在产品上线模式,
在开发模式下使用原始的CSS/JavaScript更方便调试。
接下来介绍一种合并和压缩资源文件而不需要修改已有代码的方式:
接下来介绍一种合并和压缩资源文件
而不需要修改已有代码的方式:
1. 找出应用中所有你想要合并和压缩的资源包,
2. 将这些包分成一个或几个组,注意每个包只能属于其中一个组,
3. 合并/压缩每个组里CSS文件到一个文件,同样方式处理JavaScript文件,
4. 为每个组定义新的资源包:
* 设置[[yii\web\AssetBundle::css|css]] 和 [[yii\web\AssetBundle::js|js]] 属性分别为压缩后的CSS和JavaScript文件;
* 自定义设置每个组内的资源包,设置资源包的[[yii\web\AssetBundle::css|css]] 和 [[yii\web\AssetBundle::js|js]] 属性为空,
* 设置[[yii\web\AssetBundle::css|css]] 和 [[yii\web\AssetBundle::js|js]]
属性分别为压缩后的CSS和JavaScript文件;
* 自定义设置每个组内的资源包,设置资源包的[[yii\web\AssetBundle::css|css]]
和 [[yii\web\AssetBundle::js|js]] 属性为空,
并设置它们的 [[yii\web\AssetBundle::depends|depends]] 属性为每个组新创建的资源包。
使用这种方式,当在视图中注册资源包时,会自动触发原始包所属的组资源包的注册,然后,页面就会包含以合并/压缩的资源文件,
使用这种方式,当在视图中注册资源包时,会自动触发原始包所属的组资源包的注册,
然后,页面就会包含以合并/压缩的资源文件,
而不是原始文件。
@ -426,20 +515,28 @@ return [
鉴定你的应用有两个页面X 和 Y,页面X使用资源包A,B和C,页面Y使用资源包B,C和D。
有两种方式划分这些资源包,一种使用一个组包含所有资源包,另一种是将(A,B,C)放在组X,(B,C,D)放在组Y,
哪种方式更好?第一种方式优点是两个页面使用相同的已合并CSS和JavaScript文件使HTTP缓存更高效,另一方面,由于单个组包含所有文件,
已合并的CSS和Javascipt文件会更大,因此会增加文件传输时间,在这个示例中,我们使用第一种方式,也就是用一个组包含所有包。
有两种方式划分这些资源包,一种使用一个组包含所有资源包,
另一种是将(A,B,C)放在组X,(B,C,D)放在组Y,
哪种方式更好?第一种方式优点是两个页面使用相同的已合并CSS和JavaScript文件使HTTP缓存更高效,
另一方面,由于单个组包含所有文件,
已合并的CSS和Javascipt文件会更大,因此会增加文件传输时间,在这个示例中,
我们使用第一种方式,也就是用一个组包含所有包。
> Info: 将资源包分组并不是无价值的,通常要求分析现实中不同页面各种资源的数据量,开始时为简便使用一个组。
> Info: 将资源包分组并不是无价值的,通常要求分析现实中不同页面各种资源的数据量,
开始时为简便使用一个组。
在所有包中使用工具(例如 [Closure Compiler](https://developers.google.com/closure/compiler/),
[YUI Compressor](https://github.com/yui/yuicompressor/)) 来合并和压缩CSS和JavaScript文件,
注意合并后的文件满足包间的先后依赖关系,例如,如果包A依赖B,B依赖C和D,那么资源文件列表以C和D开始,然后为B最后为A。
注意合并后的文件满足包间的先后依赖关系,
例如,如果包A依赖B,B依赖C和D,那么资源文件列表以C和D开始,
然后为B最后为A。
合并和压缩之后,会得到一个CSS文件和一个JavaScript文件,假定它们的名称为`all-xyz.css` 和 `all-xyz.js`
合并和压缩之后,会得到一个CSS文件和一个JavaScript文件,
假定它们的名称为`all-xyz.css` 和 `all-xyz.js`
`xyz` 为使文件名唯一以避免HTTP缓存问题的时间戳或哈希值。
现在到最后一步了,在应用配置中配置[[yii\web\AssetManager|asset manager]] 资源管理器如下所示:
现在到最后一步了,在应用配置中配置[[yii\web\AssetManager|asset manager]]
资源管理器如下所示:
```php
return [
@ -464,10 +561,14 @@ return [
```
如[自定义资源包](#customizing-asset-bundles) 小节中所述,如上配置改变每个包的默认行为,
特别是包A、B、C和D不再包含任何资源文件,都依赖包含合并后的`all-xyz.css` 和 `all-xyz.js`文件的包`all`,
因此,对于页面X会包含这两个合并后的文件而不是包A、B、C的原始文件,对于页面Y也是如此。
特别是包A、B、C和D不再包含任何资源文件,
都依赖包含合并后的`all-xyz.css` 和 `all-xyz.js`文件的包`all`,
因此,对于页面X会包含这两个合并后的文件而不是包A、B、C的原始文件,
对于页面Y也是如此。
最后有个方法更好地处理上述方式,除了直接修改应用配置文件,可将自定义包数组放到一个文件,在应用配置中根据条件包含该文件,例如:
最后有个方法更好地处理上述方式,除了直接修改应用配置文件,
可将自定义包数组放到一个文件,在应用配置中根据条件包含该文件,
例如:
```php
return [
@ -479,14 +580,16 @@ return [
];
```
如上所示,在产品上线模式下资源包数组存储在`assets-prod.php`文件中,不是产品上线模式存储在`assets-dev.php`文件中。
如上所示,在产品上线模式下资源包数组存储在`assets-prod.php`文件中,
不是产品上线模式存储在`assets-dev.php`文件中。
### 使用 `asset` 命令 <span id="using-asset-command"></span>
Yii提供一个名为`asset`控制台命令来使上述操作自动处理。
为使用该命令,应先创建一个配置文件设置哪些资源包要合并以及分组方式,可使用`asset/template` 子命令来生成一个模板,
为使用该命令,应先创建一个配置文件设置哪些资源包要合并以及分组方式,
可使用`asset/template` 子命令来生成一个模板,
然后修改模板成你想要的。
```
@ -528,11 +631,15 @@ return [
];
```
应修改该文件的`bundles`的选项指定哪些包你想要合并,在`targets`选项中应指定这些包如何分组,如前述的可以指定一个或多个组。
应修改该文件的`bundles`的选项指定哪些包你想要合并,
在`targets`选项中应指定这些包如何分组,
如前述的可以指定一个或多个组。
> Note: 由于在控制台应用别名 `@webroot` and `@web` 不可用,应在配置中明确指定它们。
> Note: 由于在控制台应用别名 `@webroot` and `@web` 不可用,
应在配置中明确指定它们。
JavaScript文件会被合并压缩后写入到`js/all-{hash}.js`文件,其中 {hash} 会被结果文件的哈希值替换。
JavaScript文件会被合并压缩后写入到`js/all-{hash}.js`文件,
其中 {hash} 会被结果文件的哈希值替换。
`jsCompressor``cssCompressor` 选项指定控制台命令或PHP回调函数来执行JavaScript和CSS合并和压缩,
Yii默认使用[Closure Compiler](https://developers.google.com/closure/compiler/)来合并JavaScript文件,
@ -540,13 +647,68 @@ Yii默认使用[Closure Compiler](https://developers.google.com/closure/compiler
你应手工安装这些工具或修改选项使用你喜欢的工具。
根据配置文件,可执行`asset` 命令来合并和压缩资源文件并生成一个新的资源包配置文件`assets-prod.php`:
根据配置文件,可执行`asset` 命令来合并和压缩资源文件
并生成一个新的资源包配置文件`assets-prod.php`:
```
yii asset assets.php config/assets-prod.php
```
生成的配置文件可以在应用配置中包含,如最后一小节所描述的。
生成的配置文件可以在应用配置中包含,
如最后一小节所描述的。
> Info: 使用`asset` 命令并不是唯一一种自动合并和压缩过程的方法,
可使用优秀的工具[grunt](http://gruntjs.com/)来完成这个过程。
### Grouping Asset Bundles <span id="grouping-asset-bundles"></span>
In the last subsection, we have explained how to combine all asset bundles into a single one in order to minimize
the HTTP requests for asset files referenced in an application. This is not always desirable in practice. For example,
imagine your application has a "front end" as well as a "back end", each of which uses a different set of JavaScript
and CSS files. In this case, combining all asset bundles from both ends into a single one does not make sense,
because the asset bundles for the "front end" are not used by the "back end" and it would be a waste of network
bandwidth to send the "back end" assets when a "front end" page is requested.
To solve the above problem, you can divide asset bundles into groups and combine asset bundles for each group.
The following configuration shows how you can group asset bundles:
```php
return [
...
// Specify output bundles with groups:
'targets' => [
'allShared' => [
'js' => 'js/all-shared-{hash}.js',
'css' => 'css/all-shared-{hash}.css',
'depends' => [
// Include all assets shared between 'backend' and 'frontend'
'yii\web\YiiAsset',
'app\assets\SharedAsset',
],
],
'allBackEnd' => [
'js' => 'js/all-{hash}.js',
'css' => 'css/all-{hash}.css',
'depends' => [
// Include only 'backend' assets:
'app\assets\AdminAsset'
],
],
'allFrontEnd' => [
'js' => 'js/all-{hash}.js',
'css' => 'css/all-{hash}.css',
'depends' => [], // Include all remaining assets
],
],
...
];
```
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: 使用`asset` 命令并不是唯一一种自动合并和压缩过程的方法,可使用优秀的工具[grunt](http://gruntjs.com/)来完成这个过程。
> 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.

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

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

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

@ -1,24 +1,22 @@
入口脚本
=============
入口脚本是应用启动流程中的第一环,一个应用(不管是网页应用还是控制台应用)只有一个入口脚本。终端用户的请求通过入口脚本实例化应用并将将请求转发到应用。
入口脚本是应用启动流程中的第一环,
一个应用(不管是网页应用还是控制台应用)只有一个入口脚本。
终端用户的请求通过入口脚本实例化应用并将将请求转发到应用。
Web 应用的入口脚本必须放在终端用户能够访问的目录下,通常命名为 `index.php`,也可以使用 Web 服务器能定位到的其他名称。
Web 应用的入口脚本必须放在终端用户能够访问的目录下,
通常命名为 `index.php`
也可以使用 Web 服务器能定位到的其他名称。
控制台应用的入口脚本一般在应用根目录下命名为 `yii`(后缀为.php),该文件需要有执行权限,这样用户就能通过命令 `./yii <route> [arguments] [options]` 来运行控制台应用。
控制台应用的入口脚本一般在应用根目录下命名为 `yii`(后缀为.php),
该文件需要有执行权限,
这样用户就能通过命令 `./yii <route> [arguments] [options]` 来运行控制台应用。
入口脚本主要完成以下工作:
* 定义全局常量;
<<<<<<< .merge_file_a05144
<<<<<<< HEAD
* 注册 [Composer 自动加载器](http://getcomposer.org/doc/01-basic-usage.md#autoloading);
=======
* 注册 [Composer 自动加载器](https://getcomposer.org/doc/01-basic-usage.md#autoloading);
>>>>>>> yiichina/master
=======
* 注册 [Composer 自动加载器](https://getcomposer.org/doc/01-basic-usage.md#autoloading);
>>>>>>> .merge_file_a03208
* 包含 [[Yii]] 类文件;
* 加载应用配置;
* 创建一个[应用](structure-applications.md)实例并配置;
@ -85,9 +83,14 @@ exit($exitCode);
入口脚本是定义全局常量的最好地方,Yii 支持以下三个常量:
* `YII_DEBUG`:标识应用是否运行在调试模式。当在调试模式下,应用会保留更多日志信息,如果抛出异常,会显示详细的错误调用堆栈。因此,调试模式主要适合在开发阶段使用,`YII_DEBUG` 默认值为 false。
* `YII_ENV`:标识应用运行的环境,详情请查阅[配置](concept-configurations.md#environment-constants)章节。`YII_ENV` 默认值为 `'prod'`,表示应用运行在线上产品环境。
* `YII_ENABLE_ERROR_HANDLER`:标识是否启用 Yii 提供的错误处理,默认为 true。
* `YII_DEBUG`:标识应用是否运行在调试模式。当在调试模式下,
应用会保留更多日志信息,如果抛出异常,会显示详细的错误调用堆栈。
因此,调试模式主要适合在开发阶段使用,`YII_DEBUG` 默认值为 false。
* `YII_ENV`:标识应用运行的环境,
详情请查阅[配置](concept-configurations.md#environment-constants)章节。
`YII_ENV` 默认值为 `'prod'`,表示应用运行在线上产品环境。
* `YII_ENABLE_ERROR_HANDLER`:标识是否启用 Yii 提供的错误处理,
默认为 true。
当定义一个常量时,通常使用类似如下代码来定义:
@ -105,4 +108,5 @@ if (!defined('YII_DEBUG')) {
显然第一段代码更加简洁易懂。
常量定义应该在入口脚本的开头,这样包含其他 PHP 文件时,常量就能生效。
常量定义应该在入口脚本的开头,这样包含其他 PHP 文件时,
常量就能生效。

338
docs/guide-zh-CN/structure-extensions.md

@ -1,38 +1,3 @@
<<<<<<< HEAD
Extensions
==========
Extensions are redistributable software packages specifically designed to be used in Yii applications and provide
ready-to-use features. For example, the [yiisoft/yii2-debug](tool-debugger.md) extension adds a handy debug toolbar
at the bottom of every page in your application to help you more easily grasp how the pages are generated. You can
use extensions to accelerate your development process. You can also package your code as extensions to share with
other people your great work.
> Info: We use the term "extension" to refer to Yii-specific software packages. For general purpose software packages
that can be used without Yii, we will refer to them using the term "package" or "library".
## Using Extensions <span id="using-extensions"></span>
To use an extension, you need to install it first. Most extensions are distributed as [Composer](https://getcomposer.org/)
packages which can be installed by taking the following two simple steps:
1. modify the `composer.json` file of your application and specify which extensions (Composer packages) you want to install.
2. run `composer install` to install the specified extensions.
Note that you may need to install [Composer](https://getcomposer.org/) if you do not have it.
By default, Composer installs packages registered on [Packagist](https://packagist.org/) - the biggest repository
for open source Composer packages. You can look for extensions on Packagist. You may also
[create your own repository](https://getcomposer.org/doc/05-repositories.md#repository) and configure Composer
to use it. This is useful if you are developing closed open extensions and want to share within your projects.
Extensions installed by Composer are stored in the `BasePath/vendor` directory, where `BasePath` refers to the
application's [base path](structure-applications.md#basePath). Because Composer is a dependency manager, when
it installs a package, it will also install all its dependent packages.
For example, to install the `yiisoft/yii2-imagine` extension, modify your `composer.json` like the following:
=======
扩展
==========
@ -66,7 +31,6 @@ For example, to install the `yiisoft/yii2-imagine` extension, modify your `compo
也将安装这个包所依赖的所有软件包。
例如想安装 `yiisoft/yii2-imagine` 扩展,可按如下示例修改你的 `composer.json` 文件:
>>>>>>> yiichina/master
```json
{
@ -80,17 +44,6 @@ For example, to install the `yiisoft/yii2-imagine` extension, modify your `compo
}
```
<<<<<<< HEAD
After the installation, you should see the directory `yiisoft/yii2-imagine` under `BasePath/vendor`. You should
also see another directory `imagine/imagine` which contains the installed dependent package.
> Info: The `yiisoft/yii2-imagine` is a core extension developed and maintained by the Yii developer team. All
core extensions are hosted on [Packagist](https://packagist.org/) and named like `yiisoft/yii2-xyz`, where `xyz`
varies for different extensions.
Now you can use the installed extensions like they are part of your application. The following example shows
how you can use the `yii\imagine\Image` class provided by the `yiisoft/yii2-imagine` extension:
=======
安装完成后,你应该能在 `BasePath/vendor` 目录下见到 `yiisoft/yii2-imagine` 目录。你也应该
见到另一个 `imagine/imagine` 目录,在其中安装了所依赖的包。
@ -100,40 +53,16 @@ how you can use the `yii\imagine\Image` class provided by the `yiisoft/yii2-imag
现在你可以使用安装好的扩展了,好比是应用的一部分。如下示例展示了如何使用 `yiisoft/yii2-imagine` 扩展
提供的 `yii\imagine\Image` 类:
>>>>>>> yiichina/master
```php
use Yii;
use yii\imagine\Image;
<<<<<<< HEAD
// generate a thumbnail image
=======
// 生成一个缩略图
>>>>>>> yiichina/master
Image::thumbnail('@webroot/img/test-image.jpg', 120, 120)
->save(Yii::getAlias('@runtime/thumb-test-image.jpg'), ['quality' => 50]);
```
<<<<<<< HEAD
> Info: Extension classes are autoloaded by the [Yii class autoloader](concept-autoloading.md).
### Installing Extensions Manually <span id="installing-extensions-manually"></span>
In some rare occasions, you may want to install some or all extensions manually, rather than relying on Composer.
To do so, you should
1. download the extension archive files and unpack them in the `vendor` directory.
2. install the class autoloaders provided by the extensions, if any.
3. download and install all dependent extensions as instructed.
If an extension does not have a class autoloader but follows the [PSR-4 standard](http://www.php-fig.org/psr/psr-4/),
you may use the class autoloader provided by Yii to autoload the extension classes. All you need to do is just to
declare a [root alias](concept-aliases.md#defining-aliases) for the extension root directory. For example,
assuming you have installed an extension in the directory `vendor/mycompany/myext`, and the extension classes
are under the `myext` namespace, then you can include the following code in your application configuration:
=======
> 信息: 扩展类由 [Yii class autoloader](concept-autoloading.md) 自动加载。
@ -151,7 +80,6 @@ are under the `myext` namespace, then you can include the following code in your
你需要做的仅仅是为扩展的根目录声明一个 [root alias](concept-aliases.md#defining-aliases)。
例如,假设在 `vendor/mycompany/myext` 目录中安装了一个扩展,并且扩展类的命名空间为 `myext`
那么你可以在应用配置文件中包含如下代码:
>>>>>>> yiichina/master
```php
[
@ -162,24 +90,6 @@ are under the `myext` namespace, then you can include the following code in your
```
<<<<<<< HEAD
## Creating Extensions <span id="creating-extensions"></span>
You may consider creating an extension when you feel the need to share with other people your great code.
An extension can contain any code you like, such as a helper class, a widget, a module, etc.
It is recommended that you create an extension in terms of a [Composer package](https://getcomposer.org/) so that
it can be more easily installed and used by other users, liked described in the last subsection.
Below are the basic steps you may follow to create an extension as a Composer package.
1. Create a project for your extension and host it on a VCS repository, such as [github.com](https://github.com).
The development and maintenance work about the extension should be done on this repository.
2. Under the root directory of the project, create a file named `composer.json` as required by Composer. Please
refer to the next subsection for more details.
3. Register your extension with a Composer repository, such as [Packagist](https://packagist.org/), so that
other users can find and install your extension using Composer.
=======
## 创建扩展 <span id="creating-extensions"></span>
在你需要将你的杰作分享给其他人的时候,你可能会考虑创建一个扩展。
@ -196,20 +106,13 @@ Below are the basic steps you may follow to create an extension as a Composer pa
详情请参考后面的章节。
3. 在一个 Composer 代码库中注册你的扩展,比如在 [Packagist](https://packagist.org/) 中,以便其他
用户能找到以及用 Composer 安装你的扩展。
>>>>>>> yiichina/master
### `composer.json` <span id="composer-json"></span>
<<<<<<< HEAD
Each Composer package must have a `composer.json` file in its root directory. The file contains the metadata about
the package. You may find complete specification about this file in the [Composer Manual](https://getcomposer.org/doc/01-basic-usage.md#composer-json-project-setup).
The following example shows the `composer.json` file for the `yiisoft/yii2-imagine` extension:
=======
每个 Composer 软件包在根目录都必须有一个 `composer.json` 文件。该文件包含软件包的元数据。
你可以在 [Composer手册](https://getcomposer.org/doc/01-basic-usage.md#composer-json-project-setup) 中找到完整关于该文件的规格。
以下例子展示了 `yiisoft/yii2-imagine` 扩展的 `composer.json` 文件。
>>>>>>> yiichina/master
```json
{
@ -252,41 +155,6 @@ The following example shows the `composer.json` file for the `yiisoft/yii2-imagi
```
<<<<<<< HEAD
#### Package Name <span id="package-name"></span>
Each Composer package should have a package name which uniquely identifies the package among all others.
The format of package names is `vendorName/projectName`. For example, in the package name `yiisoft/yii2-imagine`,
the vendor name and the project name are `yiisoft` and `yii2-imagine`, respectively.
Do NOT use `yiisoft` as vendor name as it is reserved for use by the Yii core code.
We recommend you prefix `yii2-` to the project name for packages representing Yii 2 extensions, for example,
`myname/yii2-mywidget`. This will allow users to more easily tell whether a package is a Yii 2 extension.
#### Package Type <span id="package-type"></span>
It is important that you specify the package type of your extension as `yii2-extension` so that the package can
be recognized as a Yii extension when being installed.
When a user runs `composer install` to install an extension, the file `vendor/yiisoft/extensions.php`
will be automatically updated to include the information about the new extension. From this file, Yii applications
can know which extensions are installed (the information can be accessed via [[yii\base\Application::extensions]].
#### Dependencies <span id="dependencies"></span>
Your extension depends on Yii (of course). So you should list it (`yiisoft/yii2`) in the `require` entry in `composer.json`.
If your extension also depends on other extensions or third-party libraries, you should list them as well.
Make sure you also list appropriate version constraints (e.g. `1.*`, `@stable`) for each dependent package. Use stable
dependencies when your extension is released in a stable version.
Most JavaScript/CSS packages are managed using [Bower](http://bower.io/) and/or [NPM](https://www.npmjs.org/),
instead of Composer. Yii uses the [Composer asset plugin](https://github.com/francoispluchino/composer-asset-plugin)
to enable managing these kinds of packages through Composer. If your extension depends on a Bower package, you can
simply list the dependency in `composer.json` like the following:
=======
#### 包名 <span id="package-name"></span>
每个 Composer 软件包都应当有一个唯一的包名以便能从其他的软件包中识别出来。
@ -320,7 +188,6 @@ simply list the dependency in `composer.json` like the following:
[Composer asset 插件](https://github.com/francoispluchino/composer-asset-plugin) 使之可以
通过 Composer 来管理这类包。如果你的扩展依赖 Bower 软件包,你可以如下例所示那样简单地
`composer.json` 文件的依赖中列出它。
>>>>>>> yiichina/master
```json
{
@ -331,21 +198,6 @@ simply list the dependency in `composer.json` like the following:
}
```
<<<<<<< HEAD
The above code states that the extension depends on the `jquery` Bower package. In general, you can use
`bower-asset/PackageName` to refer to a Bower package in `composer.json`, and use `npm-asset/PackageName`
to refer to a NPM package. When Composer installs a Bower or NPM package, by default the package content will be
installed under the `@vendor/bower/PackageName` and `@vendor/npm/Packages` directories, respectively.
These two directories can also be referred to using the shorter aliases `@bower/PackageName` and `@npm/PackageName`.
For more details about asset management, please refer to the [Assets](structure-assets.md#bower-npm-assets) section.
#### Class Autoloading <span id="class-autoloading"></span>
In order for your classes to be autoloaded by the Yii class autoloader or the Composer class autoloader,
you should specify the `autoload` entry in the `composer.json` file, like shown below:
=======
上述代码表明该扩展依赖于 `jquery` Bower 包。一般来说,你可以在 `composer.json`
中用 `bower-asset/PackageName` 指定 Bower 包,用 `npm-asset/PackageName` 指定 NPM 包。
当 Compower 安装 Bower 和 NPM 软件包时,包的内容默认会分别安装到 `@vendor/bower/PackageName`
@ -359,7 +211,6 @@ you should specify the `autoload` entry in the `composer.json` file, like shown
为使你的类能够被 Yii 的类自动加载器或者 Composer 的类自动加载器自动加载,你应当在
`composer.json` 中指定 `autoload` 条目,如下所示:
>>>>>>> yiichina/master
```json
{
@ -373,43 +224,6 @@ you should specify the `autoload` entry in the `composer.json` file, like shown
}
```
<<<<<<< HEAD
You may list one or multiple root namespaces and their corresponding file paths.
When the extension is installed in an application, Yii will create for each listed root namespace
an [alias](concept-aliases.md#extension-aliases) that refers to the directory corresponding to the namespace.
For example, the above `autoload` declaration will correspond to an alias named `@yii/imagine`.
### Recommended Practices <span id="recommended-practices"></span>
Because extensions are meant to be used by other people, you often need to take extra development effort. Below
we introduce some common and recommended practices in creating high quality extensions.
#### Namespaces <span id="namespaces"></span>
To avoid name collisions and make the classes in your extension autoloadable, you should use namespaces and
name the classes in your extension by following the [PSR-4 standard](http://www.php-fig.org/psr/psr-4/) or
[PSR-0 standard](http://www.php-fig.org/psr/psr-0/).
You class namespaces should start with `vendorName\extensionName`, where `extensionName` is similar to the project name
in the package name except that it should not contain the `yii2-` prefix. For example, for the `yiisoft/yii2-imagine`
extension, we use `yii\imagine` as the namespace its classes.
Do not use `yii`, `yii2` or `yiisoft` as vendor name. These names are reserved for use by the Yii core code.
#### Bootstrapping Classes <span id="bootstrapping-classes"></span>
Sometimes, you may want your extension to execute some code during the [bootstrapping process](runtime-bootstrapping.md)
stage of an application. For example, your extension may want to respond to the application's `beginRequest` event
to adjust some environment settings. While you can instruct users of the extension to explicitly attach your event
handler in the extension to the `beginRequest` event, a better way is to do this automatically.
To achieve this goal, you can create a so-called *bootstrapping class* by implementing [[yii\base\BootstrapInterface]].
For example,
=======
你可以列出一个或者多个根命名空间和它们的文件目录。
当扩展安装到应用中后,Yii 将为每个所列出根命名空间创建一个
@ -445,7 +259,6 @@ For example,
为实现该目标,你可以创建一个所谓 *bootstrapping class* (自举类)实现 [[yii\base\BootstrapInterface]] 接口。
例如,
>>>>>>> yiichina/master
```php
namespace myname\mywidget;
@ -464,11 +277,7 @@ class MyBootstrapClass implements BootstrapInterface
}
```
<<<<<<< HEAD
You then list this class in the `composer.json` file of your extension like follows,
=======
然后你将这个类在 `composer.json` 文件中列出来,如下所示,
>>>>>>> yiichina/master
```json
{
@ -480,152 +289,6 @@ You then list this class in the `composer.json` file of your extension like foll
}
```
<<<<<<< HEAD
When the extension is installed in an application, Yii will automatically instantiate the bootstrapping class
and call its [[yii\base\BootstrapInterface::bootstrap()|bootstrap()]] method during the bootstrapping process for
every request.
#### Working with Databases <span id="working-with-databases"></span>
Your extension may need to access databases. Do not assume that the applications that use your extension will always
use `Yii::$db` as the DB connection. Instead, you should declare a `db` property for the classes that require DB access.
The property will allow users of your extension to customize which DB connection they would like your extension to use.
As an example, you may refer to the [[yii\caching\DbCache]] class and see how it declares and uses the `db` property.
If your extension needs to create specific DB tables or make changes to DB schema, you should
- provide [migrations](db-migrations.md) to manipulate DB schema, rather than using plain SQL files;
- try to make the migrations applicable to different DBMS;
- avoid using [Active Record](db-active-record.md) in the migrations.
#### Using Assets <span id="using-assets"></span>
If your extension is a widget or a module, chances are that it may require some [assets](structure-assets.md) to work.
For example, a module may display some pages which contain images, JavaScript, and CSS. Because the files of an
extension are all under the same directory which is not Web accessible when installed in an application, you have
two choices to make the asset files directly accessible via Web:
- ask users of the extension to manually copy the asset files to a specific Web-accessible folder;
- declare an [asset bundle](structure-assets.md) and rely on the asset publishing mechanism to automatically
copy the files listed in the asset bundle to a Web-accessible folder.
We recommend you use the second approach so that your extension can be more easily used by other people.
Please refer to the [Assets](structure-assets.md) section for more details about how to work with assets in general.
#### Internationalization and Localization <span id="i18n-l10n"></span>
Your extension may be used by applications supporting different languages! Therefore, if your extension displays
content to end users, you should try to [internationalize and localize](tutorial-i18n.md) it. In particular,
- If the extension displays messages intended for end users, the messages should be wrapped into `Yii::t()`
so that they can be translated. Messages meant for developers (such as internal exception messages) do not need
to be translated.
- If the extension displays numbers, dates, etc., they should be formatted using [[yii\i18n\Formatter]] with
appropriate formatting rules.
For more details, please refer to the [Internationalization](tutorial-i18n.md) section.
#### Testing <span id="testing"></span>
You want your extension to run flawlessly without bringing problems to other people. To reach this goal, you should
test your extension before releasing it to public.
It is recommended that you create various test cases to cover your extension code rather than relying on manual tests.
Each time before you release a new version of your extension, you may simply run these test cases to make sure
everything is in good shape. Yii provides testing support, which can help you to more easily write unit tests,
acceptance tests and functionality tests. For more details, please refer to the [Testing](test-overview.md) section.
#### Versioning <span id="versioning"></span>
You should give each release of your extension a version number (e.g. `1.0.1`). We recommend you follow the
[semantic versioning](http://semver.org) practice when determining what version numbers should be used.
#### Releasing <span id="releasing"></span>
To let other people know your extension, you need to release it to public.
If it is the first time you release an extension, you should register it on a Composer repository, such as
[Packagist](https://packagist.org/). After that, all you need to do is simply creating a release tag (e.g. `v1.0.1`)
on the VCS repository of your extension and notify the Composer repository about the new release. People will
then be able to find the new release, and install or update the extension through the Composer repository.
In the releases of your extension, besides code files you should also consider including the following to
help other people learn about and use your extension:
* A readme file in the package root directory: it describes what your extension does and how to install and use it.
We recommend you write it in [Markdown](http://daringfireball.net/projects/markdown/) format and name the file
as `readme.md`.
* A changelog file in the package root directory: it lists what changes are made in each release. The file
may be written in Markdown format and named as `changelog.md`.
* An upgrade file in the package root directory: it gives the instructions on how to upgrade from older releases
of the extension. The file may be written in Markdown format and named as `upgrade.md`.
* Tutorials, demos, screenshots, etc.: these are needed if your extension provides many features that cannot be
fully covered in the readme file.
* API documentation: your code should be well documented to allow other people more easily read and understand it.
You may refer to the [Object class file](https://github.com/yiisoft/yii2/blob/master/framework/base/Object.php)
to learn how to document your code.
> Info: Your code comments can be written in Markdown format. The `yiisoft/yii2-apidoc` extension provides a tool
for you to generate pretty API documentation based on your code comments.
> Info: While not a requirement, we suggest your extension adhere to certain coding styles. You may refer to
the [core framework code style](https://github.com/yiisoft/yii2/wiki/Core-framework-code-style).
## Core Extensions <span id="core-extensions"></span>
Yii provides the following core extensions that are developed and maintained by the Yii developer team. They are all
registered on [Packagist](https://packagist.org/) and can be easily installed as described in the
[Using Extensions](#using-extensions) subsection.
- [yiisoft/yii2-apidoc](https://github.com/yiisoft/yii2-apidoc):
provides an extensible and high-performance API documentation generator. It is also used to generate the core
framework API documentation.
- [yiisoft/yii2-authclient](https://github.com/yiisoft/yii2-authclient):
provides a set of commonly used auth clients, such as Facebook OAuth2 client, GitHub OAuth2 client.
- [yiisoft/yii2-bootstrap](https://github.com/yiisoft/yii2-bootstrap):
provides a set of widgets that encapsulate the [Bootstrap](http://getbootstrap.com/) components and plugins.
- [yiisoft/yii2-codeception](https://github.com/yiisoft/yii2-codeception):
provides testing support based on [Codeception](http://codeception.com/).
- [yiisoft/yii2-debug](https://github.com/yiisoft/yii2-debug):
provides debugging support for Yii applications. When this extension is used, a debugger toolbar will appear
at the bottom of every page. The extension also provides a set of standalone pages to display more detailed
debug information.
- [yiisoft/yii2-elasticsearch](https://github.com/yiisoft/yii2-elasticsearch):
provides the support for using [Elasticsearch](http://www.elasticsearch.org/). It includes basic querying/search
support and also implements the [Active Record](db-active-record.md) pattern that allows you to store active records
in Elasticsearch.
- [yiisoft/yii2-faker](https://github.com/yiisoft/yii2-faker):
provides the support for using [Faker](https://github.com/fzaninotto/Faker) to generate fake data for you.
- [yiisoft/yii2-gii](https://github.com/yiisoft/yii2-gii):
provides a Web-based code generator that is highly extensible and can be used to quickly generate models,
forms, modules, CRUD, etc.
- [yiisoft/yii2-imagine](https://github.com/yiisoft/yii2-imagine):
provides commonly used image manipulation functions based on [Imagine](http://imagine.readthedocs.org/).
- [yiisoft/yii2-jui](https://github.com/yiisoft/yii2-jui):
provides a set of widgets that encapsulate the [JQuery UI](http://jqueryui.com/) interactions and widgets.
- [yiisoft/yii2-mongodb](https://github.com/yiisoft/yii2-mongodb):
provides the support for using [MongoDB](http://www.mongodb.org/). It includes features such as basic query,
Active Record, migrations, caching, code generation, etc.
- [yiisoft/yii2-redis](https://github.com/yiisoft/yii2-redis):
provides the support for using [redis](http://redis.io/). It includes features such as basic query,
Active Record, caching, etc.
- [yiisoft/yii2-smarty](https://github.com/yiisoft/yii2-smarty):
provides a template engine based on [Smarty](http://www.smarty.net/).
- [yiisoft/yii2-sphinx](https://github.com/yiisoft/yii2-sphinx):
provides the support for using [Sphinx](http://sphinxsearch.com). It includes features such as basic query,
Active Record, code generation, etc.
- [yiisoft/yii2-swiftmailer](https://github.com/yiisoft/yii2-swiftmailer):
provides email sending features based on [swiftmailer](http://swiftmailer.org/).
- [yiisoft/yii2-twig](https://github.com/yiisoft/yii2-twig):
provides a template engine based on [Twig](http://twig.sensiolabs.org/).
=======
当这个扩展安装到应用后,Yii 将在每一个请求的自举过程中
自动实例化自举类并调用其 [[yii\base\BootstrapInterface::bootstrap()|bootstrap()]]
方法。
@ -770,4 +433,3 @@ Yii 提供了下列核心扩展,由 Yii 开发团队开发和维护。这些
提供了基于 [swiftmailer](http://swiftmailer.org/) 的邮件发送功能。
- [yiisoft/yii2-twig](https://github.com/yiisoft/yii2-twig):
提供了一个基于 [Twig](http://twig.sensiolabs.org/) 的模板引擎。
>>>>>>> yiichina/master

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

@ -5,13 +5,15 @@
例如访问控制过滤器可在动作执行之前来控制特殊终端用户是否有权限执行动作,
内容压缩过滤器可在动作执行之后发给终端用户之前压缩响应内容。
过滤器可包含 预过滤(过滤逻辑在动作*之前*) 或 后过滤(过滤逻辑在动作*之后*),也可同时包含两者。
过滤器可包含 预过滤(过滤逻辑在动作*之前*) 或 后过滤(过滤逻辑在动作*之后*),
也可同时包含两者。
## 使用过滤器 <span id="using-filters"></span>
过滤器本质上是一类特殊的 [行为](concept-behaviors.md),所以使用过滤器和 [使用 行为](concept-behaviors.md#attaching-behaviors)一样。
可以在控制器类中覆盖它的 [[yii\base\Controller::behaviors()|behaviors()]] 方法来申明过滤器,如下所示:
可以在控制器类中覆盖它的 [[yii\base\Controller::behaviors()|behaviors()]] 方法来申明过滤器,
如下所示:
```php
public function behaviors()
@ -29,21 +31,20 @@ public function behaviors()
}
```
控制器类的过滤器默认应用到该类的 *所有* 动作,你可以配置[[yii\base\ActionFilter::only|only]]属性明确指定控制器应用到哪些动作。
在上述例子中,`HttpCache` 过滤器只应用到`index`和`view`动作。
控制器类的过滤器默认应用到该类的 *所有* 动作,
你可以配置[[yii\base\ActionFilter::only|only]]属性明确指定控制器应用到哪些动作。
在上述例子中,
`HttpCache` 过滤器只应用到`index`和`view`动作。
也可以配置[[yii\base\ActionFilter::except|except]]属性使一些动作不执行过滤器。
除了控制器外,可在 [模块](structure-modules.md)或[应用主体](structure-applications.md) 中申明过滤器。
申明之后,过滤器会应用到所属该模块或应用主体的 *所有* 控制器动作,
除非像上述一样配置过滤器的 [[yii\base\ActionFilter::only|only]] 和 [[yii\base\ActionFilter::except|except]] 属性。
除非像上述一样配置过滤器的 [[yii\base\ActionFilter::only|only]]
和 [[yii\base\ActionFilter::except|except]] 属性。
<<<<<<< .merge_file_a04372
> 补充: 在模块或应用主体中申明过滤器,在[[yii\base\ActionFilter::only|only]] 和 [[yii\base\ActionFilter::except|except]]
=======
> Info: 在模块或应用主体中申明过滤器,在[[yii\base\ActionFilter::only|only]] 和 [[yii\base\ActionFilter::except|except]]
>>>>>>> .merge_file_a06364
> 注意: 在模块或应用主体中申明过滤器,在[[yii\base\ActionFilter::only|only]] 和 [[yii\base\ActionFilter::except|except]]
属性中使用[路由](structure-controllers.md#routes) 代替动作ID,
因为在模块或应用主体中只用动作ID并不能唯一指定到具体动作。.
因为在模块或应用主体中只用动作ID并不能唯一指定到具体动作。
当一个动作有多个过滤器时,根据以下规则先后执行:
@ -51,7 +52,8 @@ public function behaviors()
- 按顺序执行应用主体中`behaviors()`列出的过滤器。
- 按顺序执行模块中`behaviors()`列出的过滤器。
- 按顺序执行控制器中`behaviors()`列出的过滤器。
- 如果任意过滤器终止动作执行,后面的过滤器(包括预过滤和后过滤)不再执行。
- 如果任意过滤器终止动作执行,
后面的过滤器(包括预过滤和后过滤)不再执行。
* 成功通过预过滤后执行动作。
* 后过滤
- 倒序执行控制器中`behaviors()`列出的过滤器。
@ -97,16 +99,20 @@ class ActionTimeFilter extends ActionFilter
## 核心过滤器 <span id="core-filters"></span>
Yii提供了一组常用过滤器,在`yii\filters`命名空间下,接下来我们简要介绍这些过滤器。
Yii提供了一组常用过滤器,在`yii\filters`命名空间下,
接下来我们简要介绍这些过滤器。
### [[yii\filters\AccessControl|AccessControl]] <span id="access-control"></span>
AccessControl提供基于[[yii\filters\AccessControl::rules|rules]]规则的访问控制。
特别是在动作执行之前,访问控制会检测所有规则并找到第一个符合上下文的变量(比如用户IP地址、登录状态等等)的规则,
来决定允许还是拒绝请求动作的执行,如果没有规则符合,访问就会被拒绝。
特别是在动作执行之前,
访问控制会检测所有规则并找到第一个符合上下文的变量(比如用户IP地址、登录状态等等)的规则,
来决定允许还是拒绝请求动作的执行,
如果没有规则符合,访问就会被拒绝。
如下示例表示表示允许已认证用户访问`create` 和 `update` 动作,拒绝其他用户访问这两个动作。
如下示例表示表示允许已认证用户访问`create` 和 `update` 动作,
拒绝其他用户访问这两个动作。
```php
use yii\filters\AccessControl;
@ -136,9 +142,11 @@ public function behaviors()
### 认证方法过滤器 <span id="auth-method-filters"></span>
认证方法过滤器通过[HTTP Basic Auth](http://en.wikipedia.org/wiki/Basic_access_authentication)或[OAuth 2](http://oauth.net/2/)
来认证一个用户,认证方法过滤器类在 `yii\filters\auth` 命名空间下。
来认证一个用户,
认证方法过滤器类在 `yii\filters\auth` 命名空间下。
如下示例表示可使用[[yii\filters\auth\HttpBasicAuth]]来认证一个用户,它使用基于HTTP基础认证方法的令牌。
如下示例表示可使用[[yii\filters\auth\HttpBasicAuth]]来认证一个用户,
它使用基于HTTP基础认证方法的令牌。
注意为了可运行,[[yii\web\User::identityClass|user identity class]] 类必须
实现 [[yii\web\IdentityInterface::findIdentityByAccessToken()|findIdentityByAccessToken()]]方法。
@ -155,7 +163,8 @@ public function behaviors()
}
```
认证方法过滤器通常在实现RESTful API中使用,更多关于访问控制的详情请参阅 RESTful [认证](rest-authentication.md) 一节。
认证方法过滤器通常在实现RESTful API中使用,
更多关于访问控制的详情请参阅 RESTful [认证](rest-authentication.md) 一节。
### [[yii\filters\ContentNegotiator|ContentNegotiator]] <span id="content-negotiator"></span>
@ -163,7 +172,8 @@ public function behaviors()
ContentNegotiator支持响应内容格式处理和语言处理。
通过检查 `GET` 参数和 `Accept` HTTP头部来决定响应内容格式和语言。
如下示例,配置ContentNegotiator支持JSON和XML响应格式和英语(美国)和德语。
如下示例,配置ContentNegotiator支持JSON和XML响应格式
和英语(美国)和德语。
```php
use yii\filters\ContentNegotiator;
@ -188,8 +198,10 @@ public function behaviors()
```
在[应用主体生命周期](structure-applications.md#application-lifecycle)过程中检测响应格式和语言简单很多,
因此ContentNegotiator设计可被[引导启动组件](structure-applications.md#bootstrap)调用的过滤器。
如下例所示可以将它配置在[应用主体配置](structure-applications.md#application-configurations)。
因此ContentNegotiator设计可被
[引导启动组件](structure-applications.md#bootstrap)调用的过滤器。
如下例所示可以将它配置在
[应用主体配置](structure-applications.md#application-configurations)。
```php
use yii\filters\ContentNegotiator;
@ -212,17 +224,15 @@ use yii\web\Response;
];
```
<<<<<<< .merge_file_a04372
> 补充: 如果请求中没有检测到内容格式和语言,使用[[formats]]和[[languages]]第一个配置项。
=======
> Info: 如果请求中没有检测到内容格式和语言,使用[[formats]]和[[languages]]第一个配置项。
>>>>>>> .merge_file_a06364
> 补充: 如果请求中没有检测到内容格式和语言,
使用[[formats]]和[[languages]]第一个配置项。
### [[yii\filters\HttpCache|HttpCache]] <span id="http-cache"></span>
HttpCache利用`Last-Modified` 和 `Etag` HTTP头实现客户端缓存。例如:
HttpCache利用`Last-Modified` 和 `Etag` HTTP头实现客户端缓存。
例如:
```php
use yii\filters\HttpCache;
@ -248,7 +258,8 @@ public function behaviors()
### [[yii\filters\PageCache|PageCache]] <span id="page-cache"></span>
PageCache实现服务器端整个页面的缓存。如下示例所示,PageCache应用在`index`动作,
缓存整个页面60秒或`post`表的记录数发生变化。它也会根据不同应用语言保存不同的页面版本。
缓存整个页面60秒或`post`表的记录数发生变化。
它也会根据不同应用语言保存不同的页面版本。
```php
use yii\filters\PageCache;
@ -279,12 +290,14 @@ public function behaviors()
### [[yii\filters\RateLimiter|RateLimiter]] <span id="rate-limiter"></span>
RateLimiter 根据 [漏桶算法](http://en.wikipedia.org/wiki/Leaky_bucket) 来实现速率限制。
主要用在实现RESTful APIs,更多关于该过滤器详情请参阅 [Rate Limiting](rest-rate-limiting.md) 一节。
主要用在实现RESTful APIs,
更多关于该过滤器详情请参阅 [Rate Limiting](rest-rate-limiting.md) 一节。
### [[yii\filters\VerbFilter|VerbFilter]] <span id="verb-filter"></span>
VerbFilter检查请求动作的HTTP请求方式是否允许执行,如果不允许,会抛出HTTP 405异常。
VerbFilter检查请求动作的HTTP请求方式是否允许执行,
如果不允许,会抛出HTTP 405异常。
如下示例,VerbFilter指定CRUD动作所允许的请求方式。
```php
@ -311,10 +324,12 @@ public function behaviors()
跨域资源共享 [CORS](https://developer.mozilla.org/fr/docs/HTTP/Access_control_CORS) 机制允许一个网页的许多资源(例如字体、JavaScript等)
这些资源可以通过其他域名访问获取。
特别是JavaScript's AJAX 调用可使用 XMLHttpRequest 机制,由于同源安全策略该跨域请求会被网页浏览器禁止.
特别是JavaScript's AJAX 调用可使用 XMLHttpRequest 机制,
由于同源安全策略该跨域请求会被网页浏览器禁止.
CORS定义浏览器和服务器交互时哪些跨域请求允许和禁止。
[[yii\filters\Cors|Cors filter]] 应在 授权 / 认证 过滤器之前定义,以保证CORS头部被发送。
[[yii\filters\Cors|Cors filter]] 应在 授权 / 认证 过滤器之前定义,
以保证CORS头部被发送。
```php
use yii\filters\Cors;
@ -358,7 +373,8 @@ public function behaviors()
}
```
可以覆盖默认参数为每个动作调整CORS 头部。例如,为`login`动作增加`Access-Control-Allow-Credentials`参数如下所示:
可以覆盖默认参数为每个动作调整CORS 头部。例如,
为`login`动作增加`Access-Control-Allow-Credentials`参数如下所示:
```php
use yii\filters\Cors;

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

@ -4,9 +4,11 @@
模型是 [MVC](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) 模式中的一部分,
是代表业务数据、规则和逻辑的对象。
可通过继承 [[yii\base\Model]] 或它的子类定义模型类,基类[[yii\base\Model]]支持许多实用的特性:
可通过继承 [[yii\base\Model]] 或它的子类定义模型类,
基类[[yii\base\Model]]支持许多实用的特性:
* [属性](#attributes): 代表可像普通类属性或数组一样被访问的业务数据;
* [属性](#attributes): 代表可像普通类属性或数组
一样被访问的业务数据;
* [属性标签](#attribute-labels): 指定属性显示出来的标签;
* [块赋值](#massive-assignment): 支持一步给许多属性赋值;
* [验证规则](#validation-rules): 确保输入数据符合所申明的验证规则;
@ -15,7 +17,8 @@
`Model` 类也是更多高级模型如[Active Record 活动记录](db-active-record.md)的基类,
更多关于这些高级模型的详情请参考相关手册。
> Info: 模型并不强制一定要继承[[yii\base\Model]],但是由于很多组件支持[[yii\base\Model]],最好使用它做为模型基类。
> Info: 模型并不强制一定要继承[[yii\base\Model]],但是由于很多组件支持[[yii\base\Model]],
最好使用它做为模型基类。
## 属性 <span id="attributes"></span>
@ -33,7 +36,8 @@ $model->name = 'example';
echo $model->name;
```
也可像访问数组单元项一样访问属性,这要感谢[[yii\base\Model]]支持 [ArrayAccess 数组访问](http://php.net/manual/en/class.arrayaccess.php)
也可像访问数组单元项一样访问属性,这要感谢 [[yii\base\Model]]
支持 [ArrayAccess 数组访问](http://php.net/manual/en/class.arrayaccess.php)
和 [ArrayIterator 数组迭代器](http://php.net/manual/en/class.arrayiterator.php):
```php
@ -71,15 +75,18 @@ class ContactForm extends Model
```
另一种方式是可覆盖 [[yii\base\Model::attributes()]] 来定义属性,该方法返回模型的属性名。
另一种方式是可覆盖 [[yii\base\Model::attributes()]] 来定义属性,
该方法返回模型的属性名。
例如 [[yii\db\ActiveRecord]] 返回对应数据表列名作为它的属性名,
注意可能需要覆盖魔术方法如`__get()`, `__set()`使属性像普通对象属性被访问。
注意可能需要覆盖魔术方法如`__get()`,
`__set()`使属性像普通对象属性被访问。
### 属性标签 <span id="attribute-labels"></span>
当属性显示或获取输入时,经常要显示属性相关标签,例如假定一个属性名为`firstName`,
在某些地方如表单输入或错误信息处,你可能想显示对终端用户来说更友好的 `First Name` 标签。
在某些地方如表单输入或错误信息处,
你可能想显示对终端用户来说更友好的 `First Name` 标签。
可以调用 [[yii\base\Model::getAttributeLabel()]] 获取属性的标签,例如:
@ -91,10 +98,12 @@ echo $model->getAttributeLabel('name');
```
默认情况下,属性标签通过[[yii\base\Model::generateAttributeLabel()]]方法自动从属性名生成.
它会自动将驼峰式大小写变量名转换为多个首字母大写的单词,例如 `username` 转换为 `Username`
它会自动将驼峰式大小写变量名转换为多个首字母大写的单词,
例如 `username` 转换为 `Username`
`firstName` 转换为 `First Name`
如果你不想用自动生成的标签,可以覆盖 [[yii\base\Model::attributeLabels()]] 方法明确指定属性标签,例如:
如果你不想用自动生成的标签,
可以覆盖 [[yii\base\Model::attributeLabels()]] 方法明确指定属性标签,例如:
```php
namespace app\models;
@ -138,24 +147,20 @@ public function attributeLabels()
甚至可以根据条件定义标签,例如通过使用模型的 [scenario场景](#scenarios),
可对相同的属性返回不同的标签。
<<<<<<< .merge_file_a04932
<<<<<<< HEAD
> 补充:属性标签是 [视图](structure-views.md)一部分,但是在模型中申明标签通常非常方便,并可行程非常简洁可重用代码。
=======
> 补充:属性标签是 [视图](structure-views.md)一部分,但是在模型中申明标签通常非常方便,并可形成非常简洁可重用代码。
>>>>>>> yiichina/master
=======
> Info: 属性标签是 [视图](structure-views.md)一部分,但是在模型中申明标签通常非常方便,并可行程非常简洁可重用代码。
>>>>>>> .merge_file_a03564
> 注意:属性标签是 [视图](structure-views.md)一部分,但是在模型中申明标签通常非常方便,
并可行程非常简洁可重用代码。
## 场景 <span id="scenarios"></span>
模型可能在多个 *场景* 下使用,例如 `User` 模块可能会在收集用户登录输入,也可能会在用户注册时使用。
在不同的场景下,模型可能会使用不同的业务规则和逻辑,例如 `email` 属性在注册时强制要求有,但在登陆时不需要。
模型可能在多个 *场景* 下使用,例如 `User` 模块可能会在收集用户登录输入,
也可能会在用户注册时使用。在不同的场景下,
模型可能会使用不同的业务规则和逻辑,
例如 `email` 属性在注册时强制要求有,但在登陆时不需要。
模型使用 [[yii\base\Model::scenario]] 属性保持使用场景的跟踪,
默认情况下,模型支持一个名为 `default` 的场景,如下展示两种设置场景的方法:
默认情况下,模型支持一个名为 `default` 的场景,
如下展示两种设置场景的方法:
```php
// 场景作为属性来设置
@ -167,7 +172,8 @@ $model = new User(['scenario' => 'login']);
```
默认情况下,模型支持的场景由模型中申明的 [验证规则](#validation-rules) 来决定,
但你可以通过覆盖[[yii\base\Model::scenarios()]]方法来自定义行为,如下所示:
但你可以通过覆盖[[yii\base\Model::scenarios()]]方法来自定义行为,
如下所示:
```php
namespace app\models;
@ -176,11 +182,14 @@ use yii\db\ActiveRecord;
class User extends ActiveRecord
{
const SCENARIO_LOGIN = 'login';
const SCENARIO_REGISTER = 'register';
public function scenarios()
{
return [
'login' => ['username', 'password'],
'register' => ['username', 'email', 'password'],
self::SCENARIO_LOGIN => ['username', 'password'],
self::SCENARIO_REGISTER => ['username', 'email', 'password'],
];
}
}
@ -195,7 +204,8 @@ class User extends ActiveRecord
除了 `username` and `password``email` 也被启用。
`scenarios()` 方法默认实现会返回所有[[yii\base\Model::rules()]]方法申明的验证规则中的场景,
当覆盖`scenarios()`时,如果你想在默认场景外使用新场景,可以编写类似如下代码:
当覆盖`scenarios()`时,如果你想在默认场景外使用新场景,
可以编写类似如下代码:
```php
namespace app\models;
@ -204,29 +214,36 @@ use yii\db\ActiveRecord;
class User extends ActiveRecord
{
const SCENARIO_LOGIN = 'login';
const SCENARIO_REGISTER = 'register';
public function scenarios()
{
$scenarios = parent::scenarios();
$scenarios['login'] = ['username', 'password'];
$scenarios['register'] = ['username', 'email', 'password'];
$scenarios[self::SCENARIO_LOGIN] = ['username', 'password'];
$scenarios[self::SCENARIO_REGISTER] = ['username', 'email', 'password'];
return $scenarios;
}
}
```
场景特性主要在[验证](#validation-rules) 和 [属性块赋值](#massive-assignment) 中使用。
你也可以用于其他目的,例如可基于不同的场景定义不同的 [属性标签](#attribute-labels)。
你也可以用于其他目的,
例如可基于不同的场景定义不同的 [属性标签](#attribute-labels)。
## 验证规则 <span id="validation-rules"></span>
当模型接收到终端用户输入的数据,数据应当满足某种规则(称为 *验证规则*, 也称为 *业务规则*)。
例如假定`ContactForm`模型,你可能想确保所有属性不为空且 `email` 属性包含一个有效的邮箱地址,
如果某个属性的值不满足对应的业务规则,相应的错误信息应显示,以帮助用户修正错误。
例如假定`ContactForm`模型,
你可能想确保所有属性不为空且 `email` 属性包含一个有效的邮箱地址,
如果某个属性的值不满足对应的业务规则,
相应的错误信息应显示,以帮助用户修正错误。
可调用 [[yii\base\Model::validate()]] 来验证接收到的数据,
该方法使用[[yii\base\Model::rules()]]申明的验证规则来验证每个相关属性,
如果没有找到错误,会返回 true,否则它会将错误保存在 [[yii\base\Model::errors]] 属性中并返回false,例如:
如果没有找到错误,会返回 true,
否则它会将错误保存在 [[yii\base\Model::errors]] 属性中并返回false,例如:
```php
$model = new \app\models\ContactForm;
@ -243,7 +260,8 @@ if ($model->validate()) {
```
通过覆盖 [[yii\base\Model::rules()]] 方法指定模型属性应该满足的规则来申明模型相关验证规则。
通过覆盖 [[yii\base\Model::rules()]] 方法指定
模型属性应该满足的规则来申明模型相关验证规则。
下述例子显示`ContactForm`模型申明的验证规则:
```php
@ -260,9 +278,11 @@ public function rules()
```
一条规则可用来验证一个或多个属性,一个属性可对应一条或多条规则。
更多关于如何申明验证规则的详情请参考 [验证输入](input-validation.md) 一节.
更多关于如何申明验证规则的详情请参考
[验证输入](input-validation.md) 一节。
有时你想一条规则只在某个 [场景](#scenarios) 下应用,为此你可以指定规则的 `on` 属性,如下所示:
有时你想一条规则只在某个 [场景](#scenarios) 下应用,
为此你可以指定规则的 `on` 属性,如下所示:
```php
public function rules()
@ -280,14 +300,16 @@ public function rules()
如果没有指定 `on` 属性,规则会在所有场景下应用, 在当前[[yii\base\Model::scenario|scenario]]
下应用的规则称之为 *active rule活动规则*
一个属性只会属于`scenarios()`中定义的活动属性且在`rules()`申明对应一条或多条活动规则的情况下被验证。
一个属性只会属于`scenarios()`中定义的活动属性且在`rules()`
申明对应一条或多条活动规则的情况下被验证。
## 块赋值 <span id="massive-assignment"></span>
块赋值只用一行代码将用户所有输入填充到一个模型,非常方便,
它直接将输入数据对应填充到 [[yii\base\Model::attributes]] 属性。
以下两段代码效果是相同的,都是将终端用户输入的表单数据赋值到 `ContactForm` 模型的属性,
以下两段代码效果是相同的,
都是将终端用户输入的表单数据赋值到 `ContactForm` 模型的属性,
明显地前一段块赋值的代码比后一段代码简洁且不易出错。
```php
@ -307,9 +329,11 @@ $model->body = isset($data['body']) ? $data['body'] : null;
### 安全属性 <span id="safe-attributes"></span>
块赋值只应用在模型当前[[yii\base\Model::scenario|scenario]]场景[[yii\base\Model::scenarios()]]方法
块赋值只应用在模型当前[[yii\base\Model::scenario|scenario]]
场景[[yii\base\Model::scenarios()]]方法
列出的称之为 *安全属性* 的属性上,例如,如果`User`模型申明以下场景,
当当前场景为`login`时候,只有`username` and `password` 可被块赋值,其他属性不会被赋值。
当当前场景为`login`时候,只有`username` and `password` 可被块赋值,
其他属性不会被赋值。
```php
public function scenarios()
@ -321,14 +345,17 @@ public function scenarios()
}
```
> Info: 块赋值只应用在安全属性上,因为你想控制哪些属性会被终端用户输入数据所修改,
> Info: 块赋值只应用在安全属性上,
因为你想控制哪些属性会被终端用户输入数据所修改,
例如,如果 `User` 模型有一个`permission`属性对应用户的权限,
你可能只想让这个属性在后台界面被管理员修改。
由于默认[[yii\base\Model::scenarios()]]的实现会返回[[yii\base\Model::rules()]]所有属性和数据,
由于默认[[yii\base\Model::scenarios()]]的实现
会返回[[yii\base\Model::rules()]]所有属性和数据,
如果不覆盖这个方法,表示所有只要出现在活动验证规则中的属性都是安全的。
为此,提供一个特别的别名为 `safe` 的验证器来申明哪些属性是安全的不需要被验证,
为此,提供一个特别的别名为 `safe` 的验证器来
申明哪些属性是安全的不需要被验证,
如下示例的规则申明 `title``description` 都为安全属性。
```php
@ -344,7 +371,8 @@ public function rules()
### 非安全属性 <span id="unsafe-attributes"></span>
如上所述,[[yii\base\Model::scenarios()]] 方法提供两个用处:定义哪些属性应被验证,定义哪些属性安全。
在某些情况下,你可能想验证一个属性但不想让他是安全的,可在`scenarios()`方法中属性名加一个惊叹号 `!`
在某些情况下,你可能想验证一个属性但不想让他是安全的,
可在`scenarios()`方法中属性名加一个惊叹号 `!`
例如像如下的`secret`属性。
```php
@ -356,59 +384,80 @@ public function scenarios()
}
```
当模型在 `login` 场景下,三个属性都会被验证,但只有 `username``password` 属性会被块赋值,
当模型在 `login` 场景下,三个属性都会被验证,
但只有 `username``password` 属性会被块赋值,
要对`secret`属性赋值,必须像如下例子明确对它赋值。
```php
$model->secret = $secret;
```
The same can be done in `rules()` method:
```php
public function rules()
{
return [
[['username', 'password', '!secret'], 'required', 'on' => 'login']
];
}
```
In this case attributes `username`, `password` and `secret` are required, but `secret` must be assigned explicitly.
## 数据导出 <span id="data-exporting"></span>
模型通常要导出成不同格式,例如,你可能想将模型的一个集合转成JSON或Excel格式,
导出过程可分解为两个步骤,第一步,模型转换成数组;第二步,数组转换成所需要的格式。
你只需要关注第一步,因为第二步可被通用的数据转换器如[[yii\web\JsonResponseFormatter]]来完成。
导出过程可分解为两个步骤,
第一步,模型转换成数组;第二步,数组转换成所需要的格式。
你只需要关注第一步,因为第二步可被通用的
数据转换器如[[yii\web\JsonResponseFormatter]]来完成。
将模型转换为数组最简单的方式是使用 [[yii\base\Model::attributes]] 属性,例如:
将模型转换为数组最简单的方式是使用 [[yii\base\Model::attributes]] 属性,
例如:
```php
$post = \app\models\Post::findOne(100);
$array = $post->attributes;
```
[[yii\base\Model::attributes]] 属性会返回 *所有* [[yii\base\Model::attributes()]] 申明的属性的值。
[[yii\base\Model::attributes]] 属性会返回 *所有*
[[yii\base\Model::attributes()]] 申明的属性的值。
更灵活和强大的将模型转换为数组的方式是使用 [[yii\base\Model::toArray()]] 方法,
它的行为默认和 [[yii\base\Model::attributes]] 相同,
但是它允许你选择哪些称之为*字段*的数据项放入到结果数组中并同时被格式化。
实际上,它是导出模型到 RESTful 网页服务开发的默认方法,详情请参阅[响应格式](rest-response-formatting.md).
实际上,它是导出模型到 RESTful 网页服务开发的默认方法,
详情请参阅[响应格式](rest-response-formatting.md).
### 字段 <span id="fields"></span>
字段是模型通过调用[[yii\base\Model::toArray()]]生成的数组的单元名。
字段是模型通过调用[[yii\base\Model::toArray()]]
生成的数组的单元名。
默认情况下,字段名对应属性名,但是你可以通过覆盖
[[yii\base\Model::fields()|fields()]] 和/或 [[yii\base\Model::extraFields()|extraFields()]] 方法来改变这种行为,
两个方法都返回一个字段定义列表,`fields()` 方法定义的字段是默认字段,表示`toArray()`方法默认会返回这些字段。
两个方法都返回一个字段定义列表,`fields()` 方法定义的字段是默认字段,
表示`toArray()`方法默认会返回这些字段。
`extraFields()`方法定义额外可用字段,通过`toArray()`方法指定`$expand`参数来返回这些额外可用字段。
例如如下代码会返回`fields()`方法定义的所有字段和`extraFields()`方法定义的`prettyName` and `fullAddress`字段。
例如如下代码会返回`fields()`方法定义的所有字段
和`extraFields()`方法定义的`prettyName` and `fullAddress`字段。
```php
$array = $model->toArray([], ['prettyName', 'fullAddress']);
```
可通过覆盖 `fields()` 来增加、删除、重命名和重定义字段,`fields()` 方法返回值应为数组,
可通过覆盖 `fields()` 来增加、删除、重命名和重定义字段,
`fields()` 方法返回值应为数组,
数组的键为字段名,数组的值为对应的可为属性名或匿名函数返回的字段定义对应的值。
<<<<<<< HEAD
特使情况下,如果字段名和属性定义名相同,可以省略数组键,例如:
=======
特殊情况下,如果字段名和属性定义名相同,可以省略数组键,例如:
>>>>>>> yiichina/master
特使情况下,如果字段名和属性定义名相同,可以省略数组键,
例如:
```php
// 明确列出每个字段,特别用于你想确保数据表或模型属性改变不会导致你的字段改变(保证后端的API兼容).
// 明确列出每个字段,特别用于你想确保数据表或模型
// 属性改变不会导致你的字段改变(保证后端的API兼容)。
public function fields()
{
return [
@ -425,7 +474,8 @@ public function fields()
];
}
// 过滤掉一些字段,特别用于你想继承父类实现并不想用一些敏感字段
// 过滤掉一些字段,特别用于你想
// 继承父类实现并不想用一些敏感字段
public function fields()
{
$fields = parent::fields();
@ -438,35 +488,43 @@ public function fields()
```
> Warning: 由于模型的所有属性会被包含在导出数组,最好检查数据确保没包含敏感数据,
> 如果有敏感数据,应覆盖 `fields()` 方法过滤掉,在上述列子中,我们选择过滤掉
> 如果有敏感数据,应覆盖 `fields()` 方法过滤掉,
> 在上述列子中,我们选择过滤掉
> `auth_key`, `password_hash` and `password_reset_token`
## 最佳实践 <span id="best-practices"></span>
模型是代表业务数据、规则和逻辑的中心地方,通常在很多地方重用,
在一个设计良好的应用中,模型通常比[控制器](structure-controllers.md)代码多。
在一个设计良好的应用中,
模型通常比[控制器](structure-controllers.md)代码多。
归纳起来,模型
* 可包含属性来展示业务数据;
* 可包含验证规则确保数据有效和完整;
* 可包含方法实现业务逻辑;
* 不应直接访问请求,session和其他环境数据,这些数据应该由[控制器](structure-controllers.md)传入到模型;
* 不应直接访问请求,session和其他环境数据,
这些数据应该由[控制器](structure-controllers.md)传入到模型;
* 应避免嵌入HTML或其他展示代码,这些代码最好在 [视图](structure-views.md)中处理;
* 单个模型中避免太多的 [场景](#scenarios).
在开发大型复杂系统时应经常考虑最后一条建议,
在这些系统中,模型会很大并在很多地方使用,因此会包含需要规则集和业务逻辑,
最后维护这些模型代码成为一个噩梦,因为一个简单修改会影响好多地方,
最后维护这些模型代码成为一个噩梦,
因为一个简单修改会影响好多地方,
为确保模型好维护,最好使用以下策略:
* 定义可被多个 [应用主体](structure-applications.md) 或 [模块](structure-modules.md) 共享的模型基类集合。
* 定义可被多个 [应用主体](structure-applications.md)
或 [模块](structure-modules.md) 共享的模型基类集合。
这些模型类应包含通用的最小规则集合和逻辑。
* 在每个使用模型的 [应用主体](structure-applications.md) 或 [模块](structure-modules.md)中,
通过继承对应的模型基类来定义具体的模型类,具体模型类包含应用主体或模块指定的规则和逻辑。
通过继承对应的模型基类来定义具体的模型类,
具体模型类包含应用主体或模块指定的规则和逻辑。
例如,在[高级应用模板](tutorial-advanced-app.md),你可以定义一个模型基类`common\models\Post`,
例如,在[高级应用模板](tutorial-advanced-app.md),
你可以定义一个模型基类`common\models\Post`,
然后在前台应用中,定义并使用一个继承`common\models\Post`的具体模型类`frontend\models\Post`,
在后台应用中可以类似地定义`backend\models\Post`。
通过这种策略,你清楚`frontend\models\Post`只对应前台应用,如果你修改它,就无需担忧修改会影响后台应用。
通过这种策略,你清楚`frontend\models\Post`只对应前台应用,
如果你修改它,就无需担忧修改会影响后台应用。

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

@ -29,8 +29,10 @@ forum/
### 模块类 <span id="module-classes"></span>
每个模块都有一个继承[[yii\base\Module]]的模块类,该类文件直接放在模块的[[yii\base\Module::basePath|base path]]目录下,
并且能被 [自动加载](concept-autoloading.md)。当一个模块被访问,和 [应用主体实例](structure-applications.md)
每个模块都有一个继承[[yii\base\Module]]的模块类,
该类文件直接放在模块的[[yii\base\Module::basePath|base path]]目录下,
并且能被 [自动加载](concept-autoloading.md)。
当一个模块被访问,和 [应用主体实例](structure-applications.md)
类似会创建该模块类唯一实例,模块实例用来帮模块内代码共享数据和组件。
以下示例一个模块类大致定义:
@ -62,7 +64,8 @@ public function init()
}
```
`config.php`配置文件可能包含以下内容,类似[应用主体配置](structure-applications.md#application-configurations).
`config.php`配置文件可能包含以下内容,
类似[应用主体配置](structure-applications.md#application-configurations).
```php
<?php
@ -80,8 +83,10 @@ return [
### 模块中的控制器 <span id="controllers-in-modules"></span>
创建模块的控制器时,惯例是将控制器类放在模块类命名空间的`controllers`子命名空间中,
也意味着要将控制器类文件放在模块[[yii\base\Module::basePath|base path]]目录中的`controllers`子目录中。
例如,上小节中要在`forum`模块中创建`post`控制器,应像如下申明控制器类:
也意味着要将控制器类文件放在模块
[[yii\base\Module::basePath|base path]]目录中的`controllers`子目录中。
例如,上小节中要在`forum`模块中创建`post`控制器,
应像如下申明控制器类:
```php
namespace app\modules\forum\controllers;
@ -104,17 +109,45 @@ class PostController extends Controller
视图应放在模块的[[yii\base\Module::basePath|base path]]对应目录下的 `views` 目录,
对于模块中控制器对应的视图文件应放在 `views/ControllerID` 目录下,
其中`ControllerID`对应 [控制器 ID](structure-controllers.md#routes). For example, if
例如,假定控制器类为`PostController`,目录对应模块[[yii\base\Module::basePath|base path]]目录下的 `views/post` 目录。
例如,假定控制器类为`PostController`,
目录对应模块[[yii\base\Module::basePath|base path]]目录下的 `views/post` 目录。
模块可指定 [布局](structure-views.md#layouts),它用在模块的控制器视图渲染。
布局文件默认放在 `views/layouts` 目录下,可配置[[yii\base\Module::layout]]属性指定布局名,
布局文件默认放在 `views/layouts` 目录下,
可配置[[yii\base\Module::layout]]属性指定布局名,
如果没有配置 `layout` 属性名,默认会使用应用的布局。
### Console commands in Modules <span id="console-commands-in-modules"></span>
Your module may also declare commands, that will be available through the [Console](tutorial-console.md) mode.
In order for the command line utility to see your commands, you will need to change the [[yii\base\Module::controllerNamespace]]
property, when Yii is executed in the console mode, and point it to your commands namespace.
One way to achieve that is to test the instance type of the Yii application in the module's `init` method:
```php
public function init()
{
parent::init();
if (Yii::$app instanceof \yii\console\Application) {
$this->controllerNamespace = 'app\modules\forum\commands';
}
}
```
Your commands will then be available from the command line using the following route:
```
yii <module_id>/<command>/<sub_command>
```
## 使用模块 <span id="using-modules"></span>
要在应用中使用模块,只需要将模块加入到应用主体配置的[[yii\base\Application::modules|modules]]属性的列表中,
如下代码的[应用主体配置](structure-applications.md#application-configurations) 使用 `forum` 模块:
如下代码的[应用主体配置](structure-applications.md#application-configurations)
使用 `forum` 模块:
```php
[
@ -127,16 +160,20 @@ class PostController extends Controller
]
```
[[yii\base\Application::modules|modules]] 属性使用模块配置数组,每个数组键为*模块 ID*,
它标识该应用中唯一的模块,数组的值为用来创建模块的 [配置](concept-configurations.md)。
[[yii\base\Application::modules|modules]] 属性使用模块配置数组,
每个数组键为*模块 ID*,它标识该应用中唯一的模块,
数组的值为用来创建模块的 [配置](concept-configurations.md)。
### 路由 <span id="routes"></span>
和访问应用的控制器类似,[路由](structure-controllers.md#routes) 也用在模块中控制器的寻址,
和访问应用的控制器类似,[路由](structure-controllers.md#routes)
也用在模块中控制器的寻址,
模块中控制器的路由必须以模块ID开始,接下来为控制器ID和操作ID。
例如,假定应用使用一个名为 `forum` 模块,路由`forum/post/index` 代表模块中 `post` 控制器的 `index` 操作,
如果路由只包含模块ID,默认为 `default` 的[[yii\base\Module::defaultRoute]] 属性来决定使用哪个控制器/操作,
例如,假定应用使用一个名为 `forum` 模块,
路由`forum/post/index` 代表模块中 `post` 控制器的 `index` 操作,
如果路由只包含模块ID,默认为 `default`
的[[yii\base\Module::defaultRoute]] 属性来决定使用哪个控制器/操作,
也就是说路由 `forum` 可能代表 `forum` 模块的 `default` 控制器。
@ -149,15 +186,15 @@ class PostController extends Controller
$module = MyModuleClass::getInstance();
```
其中 `MyModuleClass` 对应你想要的模块类,`getInstance()` 方法返回当前请求的模块类实例,
如果模块没有被请求,该方法会返回空,注意不需要手动创建一个模块类,因为手动创建的和Yii处理请求时自动创建的不同。
其中 `MyModuleClass` 对应你想要的模块类,
`getInstance()` 方法返回当前请求的模块类实例,
如果模块没有被请求,该方法会返回空,注意不需要手动创建一个模块类,
因为手动创建的和Yii处理请求时自动创建的不同。
<<<<<<< .merge_file_a05712
> 补充: 当开发模块时,你不能假定模块使用固定的ID,因为在应用或其他没模块中,模块可能会对应到任意的ID,
=======
> Info: 当开发模块时,你不能假定模块使用固定的ID,因为在应用或其他没模块中,模块可能会对应到任意的ID,
>>>>>>> .merge_file_a06564
为了获取模块ID,应使用上述代码获取模块实例,然后通过`$module->id`获取模块ID。
> 补充: 当开发模块时,你不能假定模块使用固定的ID,
因为在应用或其他没模块中,模块可能会对应到任意的ID,
为了获取模块ID,应使用上述代码获取模块实例,
然后通过`$module->id`获取模块ID。
也可以使用如下方式访问模块实例:
@ -169,7 +206,8 @@ $module = \Yii::$app->getModule('forum');
$module = \Yii::$app->controller->module;
```
第一种方式仅在你知道模块ID的情况下有效,第二种方式在你知道处理请求的控制器下使用。
第一种方式仅在你知道模块ID的情况下有效,
第二种方式在你知道处理请求的控制器下使用。
一旦获取到模块实例,可访问注册到模块的参数和组件,例如:
@ -200,7 +238,8 @@ $maxPostCount = $module->params['maxPostCount'];
## 模块嵌套 <span id="nested-modules"></span>
模块可无限级嵌套,也就是说,模块可以包含另一个包含模块的模块,我们称前者为*父模块*,后者为*子模块*,
模块可无限级嵌套,也就是说,模块可以包含另一个包含模块的模块,
我们称前者为*父模块*,后者为*子模块*,
子模块必须在父模块的[[yii\base\Module::modules|modules]]属性中申明,例如:
```php
@ -222,14 +261,21 @@ class Module extends \yii\base\Module
}
```
在嵌套模块中的控制器,它的路由应包含它所有祖先模块的ID,例如`forum/admin/dashboard/index` 代表
在嵌套模块中的控制器,它的路由应包含它所有祖先模块的ID,
例如`forum/admin/dashboard/index` 代表
在模块`forum`中子模块`admin`中`dashboard`控制器的`index`操作。
> Info: The [[yii\base\Module::getModule()|getModule()]] method only returns the child module directly belonging
to its parent. The [[yii\base\Application::loadedModules]] property keeps a list of loaded modules, including both
direct children and nested ones, indexed by their class names.
## 最佳实践 <span id="best-practices"></span>
模块在大型项目中常备使用,这些项目的特性可分组,每个组包含一些强相关的特性,
模块在大型项目中常备使用,这些项目的特性可分组,
每个组包含一些强相关的特性,
每个特性组可以做成一个模块由特定的开发人员和开发组来开发和维护。
在特性组上,使用模块也是重用代码的好方式,一些常用特性,如用户管理,评论管理,可以开发成模块,
在特性组上,使用模块也是重用代码的好方式,一些常用特性,
如用户管理,评论管理,可以开发成模块,
这样在相关项目中非常容易被重用。

22
docs/guide-zh-CN/structure-overview.md

@ -2,16 +2,24 @@
========
Yii 应用参照[模型-视图-控制器 (MVC)](http://wikipedia.org/wiki/Model-view-controller)
设计模式来组织。 [模型](structure-models.md)代表数据、业务逻辑和规则;[视图](structure-views.md)展示模型的输出;[控制器](structure-controllers.md)接受出入并将其转换为[模型](structure-models.md)和[视图](structure-views.md)命令。
设计模式来组织。 [模型](structure-models.md)代表数据、业务逻辑和规则;
[视图](structure-views.md)展示模型的输出;[控制器](structure-controllers.md)
接受出入并将其转换为[模型](structure-models.md)和[视图](structure-views.md)命令。
除了 MVC, Yii 应用还有以下部分:
* [入口脚本](structure-entry-scripts.md):终端用户能直接访问的 PHP 脚本,负责启动一个请求处理周期。
* [应用](structure-applications.md):能全局范围内访问的对象,管理协调组件来完成请求.
* [应用组件](structure-application-components.md):在应用中注册的对象,提供不同的功能来完成请求。
* [模块](structure-modules.md):包含完整 MVC 结构的独立包,一个应用可以由多个模块组建。
* [过滤器](structure-filters.md):控制器在处理请求之前或之后需要触发执行的代码。
* [小部件](structure-widgets.md):可嵌入到[视图](structure-views.md)中的对象,可包含控制器逻辑,可被不同视图重复调用。
* [入口脚本](structure-entry-scripts.md):终端用户能直接访问的 PHP 脚本,
负责启动一个请求处理周期。
* [应用](structure-applications.md):能全局范围内访问的对象,
管理协调组件来完成请求.
* [应用组件](structure-application-components.md):在应用中注册的对象,
提供不同的功能来完成请求。
* [模块](structure-modules.md):包含完整 MVC 结构的独立包,
一个应用可以由多个模块组建。
* [过滤器](structure-filters.md):控制器在处理请求之前或之后
需要触发执行的代码。
* [小部件](structure-widgets.md):可嵌入到[视图](structure-views.md)中的对象,
可包含控制器逻辑,可被不同视图重复调用。
下面的示意图展示了 Yii 应用的静态结构:

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

@ -2,15 +2,18 @@
=====
视图是 [MVC](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) 模式中的一部分。
它是展示数据到终端用户的代码,在网页应用中,根据*视图模板*来创建视图,视图模板为PHP脚本文件,
它是展示数据到终端用户的代码,在网页应用中,
根据*视图模板*来创建视图,视图模板为PHP脚本文件,
主要包含HTML代码和展示类PHP代码,通过[[yii\web\View|view]]应用组件来管理,
该组件主要提供通用方法帮助视图构造和渲染,简单起见,我们称视图模板或视图模板文件为视图。
该组件主要提供通用方法帮助视图构造和渲染,简单起见,
我们称视图模板或视图模板文件为视图。
## 创建视图 <span id="creating-views"></span>
如前所述,视图为包含HTML和PHP代码的PHP脚本,如下代码为一个登录表单的视图,
可看到PHP代码用来生成动态内容如页面标题和表单,HTML代码把它组织成一个漂亮的HTML页面。
可看到PHP代码用来生成动态内容如页面标题和表单,
HTML代码把它组织成一个漂亮的HTML页面。
```php
<?php
@ -34,24 +37,25 @@ $this->title = 'Login';
<?php ActiveForm::end(); ?>
```
在视图中,可访问 `$this` 指向 [[yii\web\View|view component]] 来管理和渲染这个视图文件。
在视图中,可访问 `$this` 指向 [[yii\web\View|view component]]
来管理和渲染这个视图文件。
除了 `$this`之外,上述示例中的视图有其他预定义变量如 `$model`
这些变量代表从[控制器](structure-controllers.md)或其他触发[视图渲染](#rendering-views)的对象 *传入* 到视图的数据。
这些变量代表从[控制器](structure-controllers.md)或
其他触发[视图渲染](#rendering-views)的对象 *传入* 到视图的数据。
<<<<<<< .merge_file_a05708
> 技巧: 将预定义变量列到视图文件头部注释处,这样可被IDE编辑器识别,也是生成视图文档的好方法。
=======
> Tip: 将预定义变量列到视图文件头部注释处,这样可被IDE编辑器识别,也是生成视图文档的好方法。
>>>>>>> .merge_file_a06984
> 技巧: 将预定义变量列到视图文件头部注释处,这样可被IDE编辑器识别,
也是生成视图文档的好方法。
### 安全 <span id="security"></span>
当创建生成HTML页面的视图时,在显示之前将用户输入数据进行转码和过滤非常重要,
当创建生成HTML页面的视图时,
在显示之前将用户输入数据进行转码和过滤非常重要,
否则,你的应用可能会被[跨站脚本](http://en.wikipedia.org/wiki/Cross-site_scripting) 攻击。
要显示纯文本,先调用 [[yii\helpers\Html::encode()]] 进行转码,例如如下代码将用户名在显示前先转码:
要显示纯文本,先调用 [[yii\helpers\Html::encode()]] 进行转码,
例如如下代码将用户名在显示前先转码:
```php
<?php
@ -63,7 +67,8 @@ use yii\helpers\Html;
</div>
```
要显示HTML内容,先调用 [[yii\helpers\HtmlPurifier]] 过滤内容,例如如下代码将提交内容在显示前先过滤:
要显示HTML内容,先调用 [[yii\helpers\HtmlPurifier]] 过滤内容,
例如如下代码将提交内容在显示前先过滤:
```php
<?php
@ -75,11 +80,7 @@ use yii\helpers\HtmlPurifier;
</div>
```
<<<<<<< .merge_file_a05708
> 技巧:HTMLPurifier在保证输出数据安全上做的不错,但性能不佳,如果你的应用需要高性能可考虑
=======
> Tip: HTMLPurifier在保证输出数据安全上做的不错,但性能不佳,如果你的应用需要高性能可考虑
>>>>>>> .merge_file_a06984
[缓存](caching-overview.md) 过滤后的结果。
@ -96,7 +97,8 @@ use yii\helpers\HtmlPurifier;
其中 `WidgetPath` 代表小部件类文件所在的目录;
* 对于其他对象渲染的视图文件,建议遵循和小部件相似的规则。
可覆盖控制器或小部件的 [[yii\base\ViewContextInterface::getViewPath()]] 方法来自定义视图文件默认目录。
可覆盖控制器或小部件的 [[yii\base\ViewContextInterface::getViewPath()]]
方法来自定义视图文件默认目录。
## 渲染视图 <span id="rendering-views"></span>
@ -123,7 +125,10 @@ methodName($view, $params = [])
* [[yii\base\Controller::renderPartial()|renderPartial()]]: 渲染一个 [视图名](#named-views) 并且不使用布局。
* [[yii\web\Controller::renderAjax()|renderAjax()]]: 渲染一个 [视图名](#named-views) 并且不使用布局,
并注入所有注册的JS/CSS脚本和文件,通常使用在响应AJAX网页请求的情况下。
* [[yii\base\Controller::renderFile()|renderFile()]]: 渲染一个视图文件目录或[别名](concept-aliases.md)下的视图文件。
* [[yii\base\Controller::renderFile()|renderFile()]]: 渲染一个视图文件目录或
[别名](concept-aliases.md)下的视图文件。
* [[yii\base\Controller::renderContent()|renderContent()]]: renders a static string by embedding it into
the currently applicable [layout](#layouts). This method is available since version 2.0.1.
例如:
@ -156,10 +161,10 @@ class PostController extends Controller
### 小部件中渲染 <span id="rendering-in-widgets"></span>
在 [小部件](structure-widgets.md) 中,可调用以下小部件方法来渲染视图:
Within [widgets](structure-widgets.md), you may call the following widget methods to render views.
* [[yii\base\Widget::render()|render()]]: 渲染一个 [视图名](#named-views).
* [[yii\base\Widget::renderFile()|renderFile()]]: 渲染一个视图文件目录或[别名](concept-aliases.md)下的视图文件。
* [[yii\base\Widget::renderFile()|renderFile()]]: 渲染一个视图文件目录或
[别名](concept-aliases.md)下的视图文件。
例如:
@ -191,7 +196,8 @@ class ListWidget extends Widget
* [[yii\base\View::render()|render()]]: 渲染一个 [视图名](#named-views).
* [[yii\web\View::renderAjax()|renderAjax()]]: 渲染一个 [视图名](#named-views)
并注入所有注册的JS/CSS脚本和文件,通常使用在响应AJAX网页请求的情况下。
* [[yii\base\View::renderFile()|renderFile()]]: 渲染一个视图文件目录或[别名](concept-aliases.md)下的视图文件。
* [[yii\base\View::renderFile()|renderFile()]]: 渲染一个视图文件目录或
[别名](concept-aliases.md)下的视图文件。
例如,视图中的如下代码会渲染该视图所在目录下的 `_overview.php` 视图文件,
记住视图中 `$this` 对应 [[yii\base\View|view]] 组件:
@ -225,14 +231,17 @@ echo \Yii::$app->view->renderFile('@app/views/site/license.php');
也就是说视图文件在 [[yii\base\Application::viewPath|application's view path]] 路径下找,
例如 `//site/about` 对应到 `@app/views/site/about.php`
* 视图名以单斜杠`/`开始,视图文件路径以当前使用[模块](structure-modules.md) 的[[yii\base\Module::viewPath|view path]]开始,
如果不存在模块,使用`@app/views/ViewName`开始,例如,如果当前模块为`user`, `/user/create` 对应成
`@app/modules/user/views/user/create.php`, 如果不在模块中,`/user/create`对应`@app/views/user/create.php`。
如果不存在模块,使用`@app/views/ViewName`开始,
例如,如果当前模块为`user`, `/user/create` 对应成
`@app/modules/user/views/user/create.php`,
如果不在模块中,`/user/create`对应`@app/views/user/create.php`。
* 如果 [[yii\base\View::context|context]] 渲染视图 并且上下文实现了 [[yii\base\ViewContextInterface]],
视图文件路径由上下文的 [[yii\base\ViewContextInterface::getViewPath()|view path]] 开始,
这种主要用在控制器和小部件中渲染视图,例如
如果上下文为控制器`SiteController`,`site/about` 对应到 `@app/views/site/about.php`
* 如果视图渲染另一个视图,包含另一个视图文件的目录以当前视图的文件路径开始,
例如被视图`@app/views/post/index.php` 渲染的 `item` 对应到 `@app/views/post/item`
例如被视图`@app/views/post/index.php`
渲染的 `item` 对应到 `@app/views/post/item`
根据以上规则,在控制器中 `app\controllers\PostController` 调用 `$this->render('view')`
实际上渲染 `@app/views/post/view.php` 视图文件,当在该视图文件中调用 `$this->render('_overview')`
@ -243,9 +252,11 @@ echo \Yii::$app->view->renderFile('@app/views/site/license.php');
在视图中有两种方式访问数据:推送和拉取。
推送方式是通过视图渲染方法的第二个参数传递数据,数据格式应为名称-值的数组,
推送方式是通过视图渲染方法的第二个参数传递数据,
数据格式应为名称-值的数组,
视图渲染时,调用PHP `extract()` 方法将该数组转换为视图可访问的变量。
例如,如下控制器的渲染视图代码推送2个变量到 `report` 视图:`$foo = 1` 和 `$bar = 2`
例如,如下控制器的渲染视图代码推送2个变量到
`report` 视图:`$foo = 1` 和 `$bar = 2`
```php
echo $this->render('report', [
@ -256,22 +267,25 @@ echo $this->render('report', [
拉取方式可让视图从[[yii\base\View|view component]]视图组件或其他对象中主动获得数据(如`Yii::$app`),
在视图中使用如下表达式`$this->context`可获取到控制器ID,
可让你在`report`视图中获取控制器的任意属性或方法,如以下代码获取控制器ID。
可让你在`report`视图中获取控制器的任意属性或方法,
如以下代码获取控制器ID。
```php
The controller ID is: <?= $this->context->id ?>
?>
```
推送方式让视图更少依赖上下文对象,是视图获取数据优先使用方式,
缺点是需要手动构建数组,有些繁琐,在不同地方渲染时容易出错。
缺点是需要手动构建数组,有些繁琐,
在不同地方渲染时容易出错。
### 视图间共享数据 <span id="sharing-data-among-views"></span>
[[yii\base\View|view component]]视图组件提供[[yii\base\View::params|params]]参数属性来让不同视图共享数据。
[[yii\base\View|view component]]视图组件提供[[yii\base\View::params|params]]参数
属性来让不同视图共享数据。
例如在`about`视图中,可使用如下代码指定当前breadcrumbs的当前部分。
例如在`about`视图中,可使用如下代码指定当前
breadcrumbs的当前部分。
```php
$this->params['breadcrumbs'][] = 'About Us';
@ -289,7 +303,8 @@ $this->params['breadcrumbs'][] = 'About Us';
## 布局 <span id="layouts"></span>
布局是一种特殊的视图,代表多个视图的公共部分,例如,大多数Web应用共享相同的页头和页尾,
布局是一种特殊的视图,代表多个视图的公共部分,
例如,大多数Web应用共享相同的页头和页尾,
在每个视图中重复相同的页头和页尾,更好的方式是将这些公共放到一个布局中,
渲染内容视图后在合适的地方嵌入到布局中。
@ -297,8 +312,10 @@ $this->params['breadcrumbs'][] = 'About Us';
### 创建布局 <span id="creating-layouts"></span>
由于布局也是视图,它可像普通视图一样创建,布局默认存储在`@app/views/layouts`路径下,
[模块](structure-modules.md)中使用的布局应存储在[[yii\base\Module::basePath|module directory]]模块目录
下的`views/layouts`路径下,可配置[[yii\base\Module::layoutPath]]来自定义应用或模块的布局默认路径。
[模块](structure-modules.md)中使用的布局应存储在
[[yii\base\Module::basePath|module directory]]模块目录
下的`views/layouts`路径下,可配置[[yii\base\Module::layoutPath]]
来自定义应用或模块的布局默认路径。
如下示例为一个布局大致内容,注意作为示例,简化了很多代码,
在实际中,你可能想添加更多内容,如头部标签,主菜单等。
@ -331,9 +348,11 @@ use yii\helpers\Html;
```
如上所示,布局生成每个页面通用的HTML标签,在`<body>`标签中,打印`$content`变量,
`$content`变量代表当[[yii\base\Controller::render()]]控制器渲染方法调用时传递到布局的内容视图渲染结果。
`$content`变量代表当[[yii\base\Controller::render()]]
控制器渲染方法调用时传递到布局的内容视图渲染结果。
大多数视图应调用上述代码中的如下方法,这些方法触发关于渲染过程的事件,
大多数视图应调用上述代码中的如下方法,
这些方法触发关于渲染过程的事件,
这样其他地方注册的脚本和标签会添加到这些方法调用的地方。
- [[yii\base\View::beginPage()|beginPage()]]: 该方法应在布局的开始处调用,
@ -341,7 +360,8 @@ use yii\helpers\Html;
- [[yii\base\View::endPage()|endPage()]]: 该方法应在布局的结尾处调用,
它触发表明页面结尾的 [[yii\base\View::EVENT_END_PAGE|EVENT_END_PAGE]] 时间。
- [[yii\web\View::head()|head()]]: 该方法应在HTML页面的`<head>`标签中调用,
它生成一个占位符,在页面渲染结束时会被注册的头部HTML代码(如,link标签, meta标签)替换。
它生成一个占位符,在页面渲染结束时会被注册的头部HTML代码
(如,link标签, meta标签)替换。
- [[yii\web\View::beginBody()|beginBody()]]: 该方法应在`<body>`标签的开始处调用,
它触发 [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]] 事件并生成一个占位符,
会被注册的HTML代码(如JavaScript)在页面主体开始处替换。
@ -352,22 +372,26 @@ use yii\helpers\Html;
### 布局中访问数据 <span id="accessing-data-in-layouts"></span>
在布局中可访问两个预定义变量:`$this` 和 `$content`,前者对应和普通视图类似的[[yii\base\View|view]] 视图组件
在布局中可访问两个预定义变量:`$this` 和 `$content`
前者对应和普通视图类似的[[yii\base\View|view]] 视图组件
后者包含调用[[yii\base\Controller::render()|render()]]方法渲染内容视图的结果。
如果想在布局中访问其他数据,必须使用[视图中访问数据](#accessing-data-in-views)一节介绍的拉取方式,
如果想从内容视图中传递数据到布局,可使用[视图间共享数据](#sharing-data-among-views)一节中的方法。
如果想从内容视图中传递数据到布局,
可使用[视图间共享数据](#sharing-data-among-views)一节中的方法。
### 使用布局 <span id="using-layouts"></span>
如[控制器中渲染](#rendering-in-controllers)一节描述,当控制器调用[[yii\base\Controller::render()|render()]]
方法渲染视图时,会同时使用布局到渲染结果中,默认会使用`@app/views/layouts/main.php`布局文件。
方法渲染视图时,会同时使用布局到渲染结果中,
默认会使用`@app/views/layouts/main.php`布局文件。
可配置[[yii\base\Application::layout]] 或 [[yii\base\Controller::layout]] 使用其他布局文件,
前者管理所有控制器的布局,后者覆盖前者来控制单个控制器布局。
例如,如下代码使 `post` 控制器渲染视图时使用 `@app/views/layouts/post.php` 作为布局文件,
假如 `layout` 属性没改变,控制器默认使用 `@app/views/layouts/main.php` 作为布局文件。
假如 `layout` 属性没改变,
控制器默认使用 `@app/views/layouts/main.php` 作为布局文件。
```php
namespace app\controllers;
@ -382,9 +406,11 @@ class PostController extends Controller
}
```
对于模块中的控制器,可配置模块的 [[yii\base\Module::layout|layout]] 属性指定布局文件应用到模块的所有控制器。
对于模块中的控制器,可配置模块的 [[yii\base\Module::layout|layout]]
属性指定布局文件应用到模块的所有控制器。
由于`layout` 可在不同层级(控制器、模块,应用)配置,在幕后Yii使用两步来决定控制器实际使用的布局。
由于`layout` 可在不同层级(控制器、模块,应用)配置,
在幕后Yii使用两步来决定控制器实际使用的布局。
第一步,它决定布局的值和上下文模块:
@ -395,16 +421,15 @@ class PostController extends Controller
并将它的[[yii\base\Module::layout|layout]] 的值作为布局的值,
如果都没有找到,表示不使用布局。
第二步,它决定第一步中布局的值和上下文模块对应到实际的布局文件,布局的值可为:
第二步,它决定第一步中布局的值和上下文模块对应到实际的布局文件,
布局的值可为:
- 路径别名 (如 `@app/views/layouts/main`).
<<<<<<< .merge_file_a05708
- 绝对路径 (如 `/main`): 布局的值以斜杠开始,在应用的[[yii\base\Application::layoutPath|layout path] 布局路径
=======
- 绝对路径 (如 `/main`): 布局的值以斜杠开始,在应用的[[yii\base\Application::layoutPath|layout path]] 布局路径
>>>>>>> .merge_file_a06984
中查找实际的布局文件,布局路径默认为 `@app/views/layouts`
- 相对路径 (如 `main`): 在上下文模块的[[yii\base\Module::layoutPath|layout path]]布局路径中查找实际的布局文件,
中查找实际的布局文件,
布局路径默认为 `@app/views/layouts`
- 相对路径 (如 `main`): 在上下文模块的[[yii\base\Module::layoutPath|layout path]]
布局路径中查找实际的布局文件,
布局路径默认为[[yii\base\Module::basePath|module directory]]模块目录下的`views/layouts` 目录。
- 布尔值 `false`: 不使用布局。
@ -439,7 +464,8 @@ class PostController extends Controller
例如,可在内容视图中定义数据块在布局中显示它。
调用 [[yii\base\View::beginBlock()|beginBlock()]] 和 [[yii\base\View::endBlock()|endBlock()]] 来定义数据块,
使用 `$view->blocks[$blockID]` 访问该数据块,其中 `$blockID` 为定义数据块时指定的唯一标识ID。
使用 `$view->blocks[$blockID]` 访问该数据块,
其中 `$blockID` 为定义数据块时指定的唯一标识ID。
如下实例显示如何在内容视图中使用数据块让布局使用。
@ -463,7 +489,8 @@ class PostController extends Controller
<?php $this->endBlock(); ?>
```
然后,在布局视图中,数据块可用的话会渲染数据块,如果数据未定义则显示一些默认内容。
然后,在布局视图中,数据块可用的话会渲染数据块,
如果数据未定义则显示一些默认内容。
```php
...
@ -494,9 +521,10 @@ class PostController extends Controller
## 使用视图组件 <span id="using-view-components"></span>
[[yii\base\View|View components]]视图组件提供许多视图相关特性,可创建[[yii\base\View]]或它的子类实例来获取视图组件,
大多数情况下主要使用 `view` 应用组件,可在[应用配置](structure-applications.md#application-configurations)中配置该组件,
如下所示:
[[yii\base\View|View components]]视图组件提供许多视图相关特性,
可创建[[yii\base\View]]或它的子类实例来获取视图组件,
大多数情况下主要使用 `view` 应用组件,
可在[应用配置](structure-applications.md#application-configurations)中配置该组件,如下所示:
```php
[
@ -545,9 +573,11 @@ $this->title = 'My page title';
### 注册Meta元标签 <span id="registering-meta-tags"></span>
Web页面通常需要生成各种元标签提供给不同的浏览器,如`<head>`中的页面标题,元标签通常在布局中生成。
Web页面通常需要生成各种元标签提供给不同的浏览器,如`<head>`中的页面标题,
元标签通常在布局中生成。
如果想在内容视图中生成元标签,可在内容视图中调用[[yii\web\View::registerMetaTag()]]方法,如下所示:
如果想在内容视图中生成元标签,可在内容视图中调用[[yii\web\View::registerMetaTag()]]方法,
如下所示:
```php
<?php
@ -555,14 +585,16 @@ $this->registerMetaTag(['name' => 'keywords', 'content' => 'yii, framework, php'
?>
```
以上代码会在视图组件中注册一个 "keywords" 元标签,在布局渲染后会渲染该注册的元标签,
以上代码会在视图组件中注册一个 "keywords" 元标签,
在布局渲染后会渲染该注册的元标签,
然后,如下HTML代码会插入到布局中调用[[yii\web\View::head()]]方法处:
```php
<meta name="keywords" content="yii, framework, php">
```
注意如果多次调用 [[yii\web\View::registerMetaTag()]] 方法,它会注册多个元标签,注册时不会检查是否重复。
注意如果多次调用 [[yii\web\View::registerMetaTag()]] 方法,
它会注册多个元标签,注册时不会检查是否重复。
为确保每种元标签只有一个,可在调用方法时指定键作为第二个参数,
例如,如下代码注册两次 "description" 元标签,但是只会渲染第二个。
@ -575,7 +607,8 @@ $this->registerMetaTag(['name' => 'description', 'content' => 'This website is a
### 注册链接标签 <span id="registering-link-tags"></span>
和 [Meta标签](#adding-meta-tags) 类似,链接标签有时很实用,如自定义网站图标,指定Rss订阅,或授权OpenID到其他服务器。
和 [Meta标签](#adding-meta-tags) 类似,链接标签有时很实用,
如自定义网站图标,指定Rss订阅,或授权OpenID到其他服务器。
可以和元标签相似的方式调用[[yii\web\View::registerLinkTag()]],例如,在内容视图中注册链接标签如下所示:
```php
@ -605,7 +638,8 @@ $this->registerLinkTag([
- [[yii\base\View::EVENT_BEFORE_RENDER|EVENT_BEFORE_RENDER]]: 在控制器渲染文件开始时触发,
该事件可设置 [[yii\base\ViewEvent::isValid]] 为 false 取消视图渲染。
- [[yii\base\View::EVENT_AFTER_RENDER|EVENT_AFTER_RENDER]]: 在布局中调用 [[yii\base\View::beginPage()]] 时触发,
该事件可获取[[yii\base\ViewEvent::output]]的渲染结果,可修改该属性来修改渲染结果。
该事件可获取[[yii\base\ViewEvent::output]]的渲染结果,
可修改该属性来修改渲染结果。
- [[yii\base\View::EVENT_BEGIN_PAGE|EVENT_BEGIN_PAGE]]: 在布局调用 [[yii\base\View::beginPage()]] 时触发;
- [[yii\base\View::EVENT_END_PAGE|EVENT_END_PAGE]]: 在布局调用 [[yii\base\View::endPage()]] 是触发;
- [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]]: 在布局调用 [[yii\web\View::beginBody()]] 时触发;
@ -622,7 +656,8 @@ $this->registerLinkTag([
## 渲染静态页面 <span id="rendering-static-pages"></span>
静态页面指的是大部分内容为静态的不需要控制器传递动态数据的Web页面。
静态页面指的是大部分内容为静态的
不需要控制器传递动态数据的Web页面。
可将HTML代码放置在视图中,在控制器中使用以下代码输出静态页面:
@ -677,9 +712,12 @@ http://localhost/index.php?r=site/page&view=about
如果需要请求数据,应由控制器推送到视图。
* 可读取模型属性,但不应修改它们。
为使模型更易于维护,避免创建太复杂或包含太多冗余代码的视图,可遵循以下方法达到这个目标:
为使模型更易于维护,避免创建太复杂或包含太多冗余代码的视图,
可遵循以下方法达到这个目标:
* 使用 [布局](#layouts) 来展示公共代码(如,页面头部、尾部);
* 将复杂的视图分成几个小视图,可使用上面描述的渲染方法将这些小视图渲染并组装成大视图;
* 将复杂的视图分成几个小视图,
可使用上面描述的渲染方法将这些小视图渲染并组装成大视图;
* 创建并使用 [小部件](structure-widgets.md) 作为视图的数据块;
* 创建并使用助手类在视图中转换和格式化数据。

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

@ -1,7 +1,8 @@
小部件
=======
小部件是在 [视图](structure-views.md) 中使用的可重用单元,使用面向对象方式创建复杂和可配置用户界面单元。
小部件是在 [视图](structure-views.md) 中使用的可重用单元,
使用面向对象方式创建复杂和可配置用户界面单元。
例如,日期选择器小部件可生成一个精致的允许用户选择日期的日期选择器,
你只需要在视图中插入如下代码:
@ -12,20 +13,18 @@ use yii\jui\DatePicker;
<?= DatePicker::widget(['name' => 'date']) ?>
```
<<<<<<< .merge_file_a04624
Yii提供许多优秀的小部件,比如[[yii\widgets\ActiveForm|active form]], [yii\widgets\Menu|menu]],
=======
Yii提供许多优秀的小部件,比如[[yii\widgets\ActiveForm|active form]], [[yii\widgets\Menu|menu]],
>>>>>>> .merge_file_a06288
[jQuery UI widgets](widget-jui.md), [Twitter Bootstrap widgets](widget-bootstrap.md)。
接下来介绍小部件的基本知识,如果你想了解某个小部件请参考对应的类API文档。
接下来介绍小部件的基本知识,
如果你想了解某个小部件请参考对应的类API文档。
## 使用小部件 <span id="using-widgets"></span>
小部件基本上在[views](structure-views.md)中使用,在视图中可调用 [[yii\base\Widget::widget()]] 方法使用小部件。
该方法使用 [配置](concept-configurations.md) 数组初始化小部件并返回小部件渲染后的结果。
例如如下代码插入一个日期选择器小部件,它配置为使用俄罗斯语,输入框内容为`$model`的`from_date`属性值。
例如如下代码插入一个日期选择器小部件,它配置为使用俄罗斯语,
输入框内容为`$model`的`from_date`属性值。
```php
<?php
@ -41,9 +40,11 @@ use yii\jui\DatePicker;
]) ?>
```
一些小部件可在[[yii\base\Widget::begin()]] 和 [[yii\base\Widget::end()]] 调用中使用数据内容。Some widgets can take a block of content which should be enclosed between the invocation of
一些小部件可在[[yii\base\Widget::begin()]] 和
[[yii\base\Widget::end()]] 调用中使用数据内容。
例如如下代码使用[[yii\widgets\ActiveForm]]小部件生成一个登录表单,
小部件会在`begin()` 和0 `end()`执行处分别生成`<form>`的开始标签和结束标签,中间的任何代码也会被渲染。
小部件会在`begin()` 和0 `end()`执行处分别生成`<form>`的开始标签和结束标签,
中间的任何代码也会被渲染。
```php
<?php
@ -68,8 +69,19 @@ use yii\helpers\Html;
调用 [[yii\base\Widget::begin()]] 方法返回一个可组建小部件内容的小部件实例。
### Configuring global defaults
Global defaults for a widget type could be configured via DI container:
```php
\Yii::$container->set('yii\widgets\LinkPager', ['maxButtonCount' => 5]);
```
See ["Practical Usage" section in Dependency Injection Container guide](concept-di-container.md#practical-usage) for
details.
## 创建小部件 <span id="creating-widgets"></span>
## Creating Widgets <span id="creating-widgets"></span>
继承 [[yii\base\Widget]] 类并覆盖 [[yii\base\Widget::init()]] 和/或
[[yii\base\Widget::run()]] 方法可创建小部件。通常`init()` 方法处理小部件属性,
@ -113,7 +125,8 @@ use app\components\HelloWidget;
<?= HelloWidget::widget(['message' => 'Good morning']) ?>
```
以下是另一种可在`begin()` 和 `end()`调用中使用的`HelloWidget`,HTML编码内容然后显示。
以下是另一种可在`begin()` 和 `end()`调用中使用的`HelloWidget`,
HTML编码内容然后显示。
```php
namespace app\components;
@ -137,13 +150,11 @@ class HelloWidget extends Widget
}
```
如上所示,PHP输出缓冲在`init()`启动,所有在`init()` 和 `run()`方法之间的输出内容都会被获取,并在`run()`处理和返回。
如上所示,PHP输出缓冲在`init()`启动,所有在`init()` 和 `run()`方法之间的输出内容都会被获取,
并在`run()`处理和返回。
<<<<<<< .merge_file_a04624
> 补充: 当你调用 [[yii\base\Widget::begin()]] 时会创建一个新的小部件实例并在构造结束时调用`init()`方法,
=======
> Info: 当你调用 [[yii\base\Widget::begin()]] 时会创建一个新的小部件实例并在构造结束时调用`init()`方法,
>>>>>>> .merge_file_a06288
> 注意: 当你调用 [[yii\base\Widget::begin()]] 时会创建一个
新的小部件实例并在构造结束时调用`init()`方法,
在`end()`时会调用`run()`方法并输出返回结果。
如下代码显示如何使用这种 `HelloWidget`:
@ -159,7 +170,8 @@ use app\components\HelloWidget;
<?php HelloWidget::end(); ?>
```
有时小部件需要渲染很多内容,一种更好的办法是将内容放入一个[视图](structure-views.md)文件,
有时小部件需要渲染很多内容,一种更好的办法
是将内容放入一个[视图](structure-views.md)文件,
然后调用[[yii\base\Widget::render()]]方法渲染该视图文件,例如:
```php
@ -170,7 +182,8 @@ public function run()
```
小部件的视图文件默认存储在`WidgetPath/views`目录,`WidgetPath`代表小部件类文件所在的目录。
假如上述示例小部件类文件在`@app/components`下,会渲染`@app/components/views/hello.php`视图文件。 You may override
假如上述示例小部件类文件在`@app/components`下,
会渲染`@app/components/views/hello.php`视图文件。 You may override
可以覆盖[[yii\base\Widget::getViewPath()]]方法自定义视图文件所在路径。
@ -178,11 +191,14 @@ public function run()
小部件是面向对象方式来重用视图代码。
创建小部件时仍需要遵循MVC模式,通常逻辑代码在小部件类,展示内容在[视图](structure-views.md)中。
创建小部件时仍需要遵循MVC模式,通常逻辑代码在小部件类,
展示内容在[视图](structure-views.md)中。
小部件设计时应是独立的,也就是说使用一个小部件时候,可以直接丢弃它而不需要额外的处理。
小部件设计时应是独立的,也就是说使用一个小部件时候,
可以直接丢弃它而不需要额外的处理。
但是当小部件需要外部资源如CSS, JavaScript, 图片等会比较棘手,
幸运的时候Yii提供 [资源包](structure-asset-bundles.md) 来解决这个问题。
当一个小部件只包含视图代码,它和[视图](structure-views.md)很相似,
实际上,在这种情况下,唯一的区别是小部件是可以重用类,视图只是应用中使用的普通PHP脚本。
实际上,在这种情况下,唯一的区别是小部件是可以重用类,
视图只是应用中使用的普通PHP脚本。

16
docs/guide-zh-CN/test-environment-setup.md

@ -17,12 +17,22 @@ Yii 为包括 [`yii2-basic`](https://github.com/yiisoft/yii2/tree/master/apps/ba
为了运行测试用例,你需要安装 [Codeception](https://github.com/Codeception/Codeception) 。
一个较好的安装方式是:
For the local installation use following commands:
```
composer global require "codeception/codeception=2.0.*"
composer global require "codeception/specify=*"
composer global require "codeception/verify=*"
```
For the global installation you will need to use `global` directive:
```
composer global require "codeception/codeception=2.1.*"
composer global require "codeception/specify=*"
composer global require "codeception/verify=*"
```
如果你从未通过 Composer 安装过全局的扩展包,运行 `composer global status` 。你的窗口应该输出类似如下:
```
@ -31,3 +41,9 @@ Changed current directory to <directory>
然后,将 `<directory>/vendor/bin` 增加到你的 `PATH` 环境变量中。现在,
我们可以在命令行中全局的使用 `codecept` 命令了。
> Note: global installation allows you use Codeception for all projects you are working on your development machine and
allows running `codecept` shell command globally without specifying path. However, such approach may be inappropriate,
for example, if 2 different projects require different versions of Codeception installed.
For the simplicity all shell commands related to the tests running around this guide are written assuming Codeception
has been installed globally.

12
docs/guide-zh-CN/test-overview.md

@ -14,10 +14,10 @@
带着测试进行开发
------------------
测试驱动开发(TDD)和行为驱动开发(BDD)在开始编写实际代码之前,首先通过描述一段
代码的行为或将其作为一组场景或测试的全部特征,然后创建符合这些测试预期验证的行为
实现。
测试驱动开发(TDD)和行为驱动开发(BDD)在开始编写实际代码之前,
首先通过描述一段代码的行为或将其作为一组场景或测试的全部特征,
然后创建符合这些测试预期验证
的行为实现。
开发一个功能的过程如下:
@ -30,8 +30,8 @@
走完上面的过程之后,为其他功能或者扩展重复上面测试过程。如果功能发生变化,测试也需
要跟着变化。
> **技巧**: 如果你觉得你做一些很小很简单的迭代是在浪费时间,请尝试覆盖更多的测试
场景,这样你就可以在执行测试之前做更多的尝试。如果你的调试过多,试着做相反的工作。
> 注意: 如果你觉得你做一些很小很简单的迭代是在浪费时间,请尝试覆盖更多的测试
> 场景,这样你就可以在执行测试之前做更多的尝试。如果你的调试过多,试着做相反的工作。
在做一些具体的实现之前创建测试的原因是,这允许我们后期专注于我们想要的实现,并且
可以花费更多的精力到实现细节。在涉及功能调整的时候,这会使得抽象更合理、测试维护

113
docs/guide-zh-CN/tutorial-console.md

@ -1,26 +1,33 @@
控制台命令
==========
除了用于构建 Web 应用程序的丰富功能,Yii 中也有一个拥有丰富功能的控制台,它们主要用于创建网站后台处理的任务。
除了用于构建 Web 应用程序的丰富功能,Yii 中也有一个拥有丰富功能的控制台,
它们主要用于创建网站后台处理的任务。
控制台应用程序的结构非常类似于 Yii 的一个 Web 应用程序。它由一个或多个 [[yii\console\Controller]] 类组成,它们在控制台环境下通常被称为“命令”。每个控制器还可以有一个或多个动作,就像 web 控制器。
控制台应用程序的结构非常类似于 Yii 的一个 Web 应用程序。
它由一个或多个 [[yii\console\Controller]] 类组成,它们在控制台环境下通常被称为“命令”。
每个控制器还可以有一个或多个动作,就像 web 控制器。
两个项目模板(基础模版和高级模版)都有自己的控制台应用程序。你可以通过运行 `yii` 脚本,在位于仓库的基本目录中运行它。
两个项目模板(基础模版和高级模版)都有自己的控制台应用程序。
你可以通过运行 `yii` 脚本,在位于仓库的基本目录中运行它。
当你不带任何参数来运行它时,会给你一些可用的命令列表:
![Running ./yii command for help output](images/tutorial-console-help.png)
正如你在截图中看到,Yii 中已经定义了一组默认情况下可用的命令:
- [[yii\console\controllers\AssetController|AssetController]] - 允许合并和压缩你的 JavaScript 和 CSS 文件。在 [资源 - 使用 asset 命令](structure-assets.md#using-the-asset-command) 一节可获取更多信息。
- [[yii\console\controllers\AssetController|AssetController]] - 允许合并和压缩你的 JavaScript 和 CSS 文件。
在 [资源 - 使用 asset 命令](structure-assets.md#using-the-asset-command) 一节可获取更多信息。
- [[yii\console\controllers\CacheController|CacheController]] - 清除应用程序缓存。
- [[yii\console\controllers\FixtureController|FixtureController]] - 管理用于单元测试 fixture 的加载和卸载。
这个命令的更多细节在 [Testing Section about Fixtures](test-fixtures.md#managing-fixtures).
- [[yii\console\controllers\HelpController|HelpController]] - 提供有关控制台命令的帮助信息,这是默认的命令并会打印上面截图所示的输出。
这个命令的更多细节在 [Testing Section about Fixtures](test-fixtures.md#managing-fixtures).
- [[yii\console\controllers\HelpController|HelpController]] - 提供有关控制台命令的帮助信息,
这是默认的命令并会打印上面截图所示的输出。
- [[yii\console\controllers\MessageController|MessageController]] - 从源文件提取翻译信息。
要了解更多关于这个命令的用法,请参阅 [I18N 章节](tutorial-i18n.md#message-command).
- [[yii\console\controllers\MigrateController|MigrateController]] - 管理应用程序数据库迁移。
在 [数据库迁移章节](db-migrations.md) 可获取更多信息。
- [[yii\console\controllers\ServeController|ServeController]] - Allows you run PHP built-in web server.
用法 <span id="usage"></span>
@ -32,23 +39,27 @@
yii <route> [--option1=value1 --option2=value2 ... argument1 argument2 ...]
```
以上,`<route>` 指的是控制器动作的路由。选项将填充类属性,参数是动作方法的参数。
以上,`<route>` 指的是控制器动作的路由。选项将填充类属性,
参数是动作方法的参数。
例如,将 [[yii\console\controllers\MigrateController::actionUp()|MigrateController::actionUp()]]
限制 5 个数据库迁移并将 [[yii\console\controllers\MigrateController::$migrationTable|MigrateController::$migrationTable]] 设置为 `migrations` 应该这样调用:
限制 5 个数据库迁移并将 [[yii\console\controllers\MigrateController::$migrationTable|MigrateController::$migrationTable]]
设置为 `migrations` 应该这样调用:
```
yii migrate/up 5 --migrationTable=migrations
```
> **注意**: 当在控制台使用 `*` 时, 不要忘记像 `"*"` 一样用引号来引起来,为了防止在 shell 中执行命令时被当成当前目录下的所有文件名。
> **注意**: 当在控制台使用 `*` 时, 不要忘记像 `"*"` 一样用引号来引起来,
> 为了防止在 shell 中执行命令时被当成当前目录下的所有文件名。
入口脚本 <span id="entry-script"></span>
----------------
控制台应用程序的入口脚本相当于用于 Web 应用程序的 `index.php` 入口文件。
控制台入口脚本通常被称为 `yii`,位于应用程序的根目录。它包含了类似下面的代码:
控制台入口脚本通常被称为 `yii`,位于应用程序的根目录。
它包含了类似下面的代码:
```php
#!/usr/bin/env php
@ -69,7 +80,8 @@ $exitCode = $application->run();
exit($exitCode);
```
该脚本将被创建为你应用程序中的一部分;你可以根据你的需求来修改它。如果你不需要记录错误信息或者希望提高整体性能,`YII_DEBUG` 常数应定义为 `false`
该脚本将被创建为你应用程序中的一部分;你可以根据你的需求来修改它。
如果你不需要记录错误信息或者希望提高整体性能,`YII_DEBUG` 常数应定义为 `false`
在基本的和高级的两个应用程序模板中,控制台应用程序的入口脚本在默认情况下会启用调试模式,以提供给开发者更好的环境。
@ -79,11 +91,15 @@ exit($exitCode);
在上面的代码中可以看到,控制台应用程序使用它自己的配置文件,名为 `console.php` 。在该文件里你可以给控制台配置各种
[应用组件](structure-application-components.md) 和属性。
如果你的 web 应用程序和控制台应用程序共享大量的配置参数和值,你可以考虑把这些值放在一个单独的文件中,该文件中包括( web 和控制台)应用程序配置。
如果你的 web 应用程序和控制台应用程序共享大量的配置参数和值,
你可以考虑把这些值放在一个单独的文件中,该文件中包括( web 和控制台)应用程序配置。
你可以在“高级”项目模板中看到一个例子。
> 提示:有时,你可能需要使用一个与在入口脚本中指定的应用程序配置不同的控制台命令。例如,你可能想使用 `yii migrate`
> 命令来升级你的测试数据库,它被配置在每个测试套件。要动态地更改配置,只需指定一个自定义应用程序的配置文件,通过 `appconfig`选项来执行命令:
> 提示:有时,你可能需要使用一个与在入口脚本中指定的应用程序配置不同的控制台命令。
> 例如,你可能想使用 `yii migrate`
> 命令来升级你的测试数据库,它被配置在每个测试套件。
> 要动态地更改配置,只需指定一个自定义应用程序的配置文件,
> 通过 `appconfig`选项来执行命令:
>
> ```
> yii <route> --appconfig=path/to/config.php ...
@ -98,24 +114,69 @@ exit($exitCode);
一个控制台命令继承自 [[yii\console\Controller]] 控制器类。
在控制器类中,定义一个或多个与控制器的子命令相对应的动作。在每一个动作中,编写你的代码实现特定的子命令的适当的任务。
当你运行一个命令时,你需要指定一个控制器的路由。例如,路由 `migrate/create` 调用子命令对应的[[yii\console\controllers\MigrateController::actionCreate()|MigrateController::actionCreate()]] 动作方法。
如果在执行过程中提供的路由不包含路由 ID ,将执行默认操作(如 web 控制器)。
当你运行一个命令时,你需要指定一个控制器的路由。
例如,路由 `migrate/create` 调用子命令对应的[[yii\console\controllers\MigrateController::actionCreate()|MigrateController::actionCreate()]] 动作方法。
如果在执行过程中提供的路由不包含路由 ID ,
将执行默认操作(如 web 控制器)。
### 选项
通过覆盖在 [[yii\console\Controller::options()]] 中的方法,你可以指定可用于控制台命令(controller/actionID)选项。这个方法应该返回控制器类的公共属性的列表。
通过覆盖在 [[yii\console\Controller::options()]] 中的方法,
你可以指定可用于控制台命令(controller/actionID)选项。这个方法应该返回控制器类的公共属性的列表。
当运行一个命令,你可以指定使用语法 `--OptionName=OptionValue` 选项的值。
这将分配 `OptionValue` 到控制器类的 `OptionName` 属性。
If the default value of an option is of an array type and you set this option while running the command,
the option value will be converted into an array by splitting the input string on any commas.
### Options Aliases
Since version 2.0.8 console command provides [[yii\console\Controller::optionAliases()]] method to add
aliases for options.
To define an alias, override [[yii\console\Controller::optionAliases()]] in your controller, for example:
```php
namespace app\commands;
use yii\console\Controller;
class HelloController extends Controller
{
public $message;
public function options()
{
return ['message'];
}
public function optionAliases()
{
return ['m' => 'message'];
}
public function actionIndex()
{
echo $message . "\n";
}
}
```
Now, you can use the following syntax to run the command:
```
./yii hello -m=hello
```
### 参数
除了选项,命令还可以接收参数。参数将传递给请求的子命令对应的操作方法。第一个参数对应第一个参数,第二个参数对应第二个参数,依次类推。
命令被调用时,如果没有足够的参数,如果有定义默认值的情况下,则相应的参数将采取默认声明的值;如果没有设置默认值,并且在运行时没有提供任何值,该命令将以一个错误退出。
除了选项,命令还可以接收参数。参数将传递给请求的子命令对应的操作方法。
第一个参数对应第一个参数,第二个参数对应第二个参数,依次类推。
命令被调用时,如果没有足够的参数,如果有定义默认值的情况下,则相应的参数将采取默认声明的值;
如果没有设置默认值,并且在运行时没有提供任何值,该命令将以一个错误退出。
你可以使用 `array` 类型提示来指示一个参数应该被视为一个数组。该数组通过拆分输入字符串的逗号来生成。
你可以使用 `array` 类型提示来指示一个参数应该被视为一个数组。
该数组通过拆分输入字符串的逗号来生成。
下面的示例演示如何声明参数:
@ -138,10 +199,13 @@ class ExampleController extends \yii\console\Controller
### 退出代码
使用退出代码是控制台应用程序开发的最佳做法。通常,执行成功的命令会返回 `0`。如果命令返回一个非零数字,会认为出现错误。
该返回的数字作为出错代码,用以了解错误的详细信息。例如 `1` 可能代表一个未知的错误,所有的代码都将保留在特定的情况下:输入错误,丢失的文件等等。
使用退出代码是控制台应用程序开发的最佳做法。通常,执行成功的命令会返回 `0`
如果命令返回一个非零数字,会认为出现错误。
该返回的数字作为出错代码,用以了解错误的详细信息。例如 `1` 可能代表一个未知的错误,
所有的代码都将保留在特定的情况下:输入错误,丢失的文件等等。
要让控制台命令返回一个退出代码,只需在控制器操作方法中返回一个整数:
要让控制台命令返回一个退出代码,
只需在控制器操作方法中返回一个整数:
```php
public function actionIndex()
@ -164,7 +228,8 @@ public function actionIndex()
### 格式和颜色
Yii 支持格式化输出,如果终端运行命令不支持的话则会自动退化为非格式化输出。
Yii 支持格式化输出,
如果终端运行命令不支持的话则会自动退化为非格式化输出。
要输出格式的字符串很简单。以下展示了如何输出一些加粗的文字:

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

@ -1,7 +1,9 @@
核心验证器(Core Validators)
===============
Yii 提供一系列常用的核心验证器,主要存在于 `yii\validators` 命名空间之下。为了避免使用冗长的类名,你可以直接用**昵称**来指定相应的核心验证器。比如你可以用 `required` 昵称代指 [[yii\validators\RequiredValidator]] 类:
Yii 提供一系列常用的核心验证器,主要存在于 `yii\validators` 命名空间之下。
为了避免使用冗长的类名,你可以直接用**昵称**来指定相应的核心验证器。
比如你可以用 `required` 昵称代指 [[yii\validators\RequiredValidator]] 类:
```php
public function rules()
@ -36,11 +38,7 @@ public function rules()
- `strict`:是否要求待测输入必须严格匹配 `trueValue``falseValue`。默认为 `false`
<<<<<<< .merge_file_a07020
> 注意:因为通过 HTML 表单传递的输入数据都是字符串类型,所以一般情况下你都需要保持
=======
> Note: 因为通过 HTML 表单传递的输入数据都是字符串类型,所以一般情况下你都需要保持
>>>>>>> .merge_file_a02836
[[yii\validators\BooleanValidator::strict|strict]] 属性为假。
@ -56,8 +54,10 @@ public function rules()
使用,以确保某一输入与 [[yii\captcha\Captcha|CAPTCHA]] 小部件所显示的验证代码(verification code)相同。
- `caseSensitive`:对验证代码的比对是否要求大小写敏感。默认为 false。
- `captchaAction`:指向用于渲染 CAPTCHA 图片的 [[yii\captcha\CaptchaAction|CAPTCHA action]] 的 [路由](structure-controllers.md#routes)。默认为 `'site/captcha'`
- `skipOnEmpty`:当输入为空时,是否跳过验证。默认为 false,也就是输入值为必需项。
- `captchaAction`:指向用于渲染 CAPTCHA 图片的 [[yii\captcha\CaptchaAction|CAPTCHA action]] 的 [路由](structure-controllers.md#routes)。
默认为 `'site/captcha'`
- `skipOnEmpty`:当输入为空时,是否跳过验证。
默认为 false,也就是输入值为必需项。
## [[yii\validators\CompareValidator|compare(比较)]] <span id="compare"></span>
@ -72,11 +72,17 @@ public function rules()
]
```
该验证器比较两个特定输入值之间的关系是否与 `operator` 属性所指定的相同。
- `compareAttribute`:用于与原特性相比较的特性名称。当该验证器被用于验证某目标特性时,该属性会默认为目标属性加后缀 `_repeat`。举例来说,若目标特性为 `password`,则该属性默认为 `password_repeat`
- `compareValue`:用于与输入值相比较的常量值。当该属性与 `compareAttribute` 属性同时被指定时,该属性优先被使用。
- `operator`:比较操作符。默认为 `==`,意味着检查输入值是否与 `compareAttribute``compareValue` 的值相等。该属性支持如下操作符:
该验证器比较两个特定输入值之间的关系是否与 `operator`
属性所指定的相同。
- `compareAttribute`:用于与原特性相比较的特性名称。
当该验证器被用于验证某目标特性时,
该属性会默认为目标属性加后缀 `_repeat`
举例来说,若目标特性为 `password`,则该属性默认为 `password_repeat`
- `compareValue`:用于与输入值相比较的常量值。当该属性与 `compareAttribute` 属性同时被指定时,
该属性优先被使用。
- `operator`:比较操作符。默认为 `==`,意味着检查输入值是否与 `compareAttribute``compareValue` 的值相等。
该属性支持如下操作符:
* `==`:检查两值是否相等。比对为非严格模式。
* `===`:检查两值是否全等。比对为严格模式。
* `!=`:检查两值是否不等。比对为非严格模式。
@ -95,12 +101,39 @@ public function rules()
]
```
该验证器检查输入值是否为适当格式的 date,time,或者 datetime。另外,它还可以帮你把输入值转换为一个 UNIX 时间戳并保存到 [[yii\validators\DateValidator::timestampAttribute|timestampAttribute]] 属性所指定的特性里。
该验证器检查输入值是否为适当格式的 date,time,或者 datetime。另外,
它还可以帮你把输入值转换为一个 UNIX 时间戳并保存到
[[yii\validators\DateValidator::timestampAttribute|timestampAttribute]] 属性所指定的特性里。
- `format`: the date/time format that the value being validated should be in.
This can be a date time pattern as described in the [ICU manual](http://userguide.icu-project.org/formatparse/datetime#TOC-Date-Time-Format-Syntax).
Alternatively this can be a string prefixed with `php:` representing a format that can be recognized by the PHP
`Datetime` class. Please refer to <http://php.net/manual/en/datetime.createfromformat.php> on supported formats.
If this is not set, it will take the value of `Yii::$app->formatter->dateFormat`.
See the [[yii\validators\DateValidator::$format|API documentation]] for more details.
- `timestampAttribute`: the name of the attribute to which this validator may assign the UNIX timestamp
converted from the input date/time. This can be the same attribute as the one being validated. If this is the case,
the original value will be overwritten with the timestamp value after validation.
See ["Handling date input with the DatePicker"](https://github.com/yiisoft/yii2-jui/blob/master/docs/guide/topics-date-picker.md) for a usage example.
Since version 2.0.4, a format and timezone can be specified for this attribute using
[[yii\validators\DateValidator::$timestampAttributeFormat|$timestampAttributeFormat]] and
[[yii\validators\DateValidator::$timestampAttributeTimeZone|$timestampAttributeTimeZone]].
- `format`:待测的 日期/时间 格式。请参考
[date_create_from_format() 相关的 PHP 手册](http://www.php.net/manual/zh/datetime.createfromformat.php)了解设定格式字符串的更多细节。默认值为 `'Y-m-d'`
- `timestampAttribute`:用于保存用输入时间/日期转换出来的 UNIX 时间戳的特性。
- Since version 2.0.4 it is also possible to specify a [[yii\validators\DateValidator::$min|minimum]] or
[[yii\validators\DateValidator::$max|maximum]] timestamp.
In case the input is optional you may also want to add a [default value filter](#default) in addition to the date validator
to ensure empty input is stored as `NULL`. Other wise you may end up with dates like `0000-00-00` in your database
or `1970-01-01` in the input field of a date picker.
```php
[
[['from_date', 'to_date'], 'default', 'value' => null],
[['from_date', 'to_date'], 'date'],
],
```
## [[yii\validators\DefaultValueValidator|default(默认值)]] <span id="default"></span>
@ -119,9 +152,11 @@ public function rules()
]
```
该验证器并不进行数据验证。而是,给为空的待测特性分配默认值。
该验证器并不进行数据验证。而是,
给为空的待测特性分配默认值。
- `value`:默认值,或一个返回默认值的 PHP Callable 对象(即回调函数)。它们会分配给检测为空的待测特性。PHP 回调方法的样式如下:
- `value`:默认值,或一个返回默认值的 PHP Callable 对象(即回调函数)。
它们会分配给检测为空的待测特性。PHP 回调方法的样式如下:
```php
function foo($model, $attribute) {
@ -130,11 +165,8 @@ function foo($model, $attribute) {
}
```
<<<<<<< .merge_file_a07020
> 补充:如何判断待测值是否为空,被写在另外一个话题的[处理空输入](input-validation.md#handling-empty-inputs)章节。
=======
> Info: 如何判断待测值是否为空,被写在另外一个话题的[处理空输入](input-validation.md#handling-empty-inputs)章节。
>>>>>>> .merge_file_a02836
> 补充:如何判断待测值是否为空,被写在另外一个话题的
[处理空输入](input-validation.md#handling-empty-inputs)章节。
## [[yii\validators\NumberValidator|double(双精度浮点型)]] <span id="double"></span>
@ -152,6 +184,30 @@ function foo($model, $attribute) {
- `min`:下限值(含界点)。若不设置,则验证器不检查下限。
## [[yii\validators\EachValidator|each]] <span id="each"></span>
> Info: This validator has been available since version 2.0.4.
```php
[
// checks if every category ID is an integer
['categoryIDs', 'each', 'rule' => ['integer']],
]
```
This validator only works with an array attribute. It validates if *every* element of the array can be successfully
validated by a specified validation rule. In the above example, the `categoryIDs` attribute must take an array value
and each array element will be validated by the `integer` validation rule.
- `rule`: an array specifying a validation rule. The first element in the array specifies the class name or
the alias of the validator. The rest of the name-value pairs in the array are used to configure the validator object.
- `allowMessageFromRule`: whether to use the error message returned by the embedded validation rule. Defaults to true.
If false, it will use `message` as the error message.
> Note: If the attribute value is not an array, it is considered validation fails and the `message` will be returned
as the error message.
## [[yii\validators\EmailValidator|email(电子邮件)]] <span id="email"></span>
```php
@ -164,8 +220,12 @@ function foo($model, $attribute) {
该验证器检查输入值是否为有效的邮箱地址。
- `allowName`:检查是否允许带名称的电子邮件地址 (e.g. `张三 <John.san@example.com>`)。 默认为 false。
- `checkDNS`:检查邮箱域名是否存在,且有没有对应的 A 或 MX 记录。不过要知道,有的时候该项检查可能会因为临时性 DNS 故障而失败,哪怕它其实是有效的。默认为 false。
- `enableIDN`:验证过程是否应该考虑 IDN(internationalized domain names,国际化域名,也称多语种域名,比如中文域名)。默认为 false。要注意但是为使用 IDN 验证功能,请先确保安装并开启 `intl` PHP 扩展,不然会导致抛出异常。
- `checkDNS`:检查邮箱域名是否存在,且有没有对应的 A 或 MX 记录。不过要知道,
有的时候该项检查可能会因为临时性 DNS 故障而失败,哪怕它其实是有效的。
默认为 false。
- `enableIDN`:验证过程是否应该考虑 IDN(internationalized domain names,国际化域名,
也称多语种域名,比如中文域名)。默认为 false。要注意但是为使用 IDN 验证功能,
请先确保安装并开启 `intl` PHP 扩展,不然会导致抛出异常。
## [[yii\validators\ExistValidator|exist(存在性)]] <span id="exist"></span>
@ -192,20 +252,28 @@ function foo($model, $attribute) {
]
```
该验证器检查输入值是否在某表字段中存在。它只对[活动记录](db-active-record.md)类型的模型类特性起作用,能支持对一个或多过字段的验证。
This validator checks if the input value can be found in a table column represented by
an [Active Record](db-active-record.md) attribute. You can use `targetAttribute` to specify the
[Active Record](db-active-record.md) attribute and `targetClass` the corresponding [Active Record](db-active-record.md)
class. If you do not specify them, they will take the values of the attribute and the model class being validated.
- `targetClass`:用于查找输入值的目标 [AR](db-active-record.md) 类。若不设置,则会使用正在进行验证的当前模型类。
- `targetAttribute`:用于检查输入值存在性的 `targetClass` 的模型特性。
- 若不设置,它会直接使用待测特性名(整个参数数组的首元素)。
- 除了指定为字符串以外,你也可以用数组的形式,同时指定多个用于验证的表字段,数组的键和值都是代表字段的特性名,值表示 `targetClass` 的待测数据源字段,而键表示当前模型的待测特性名。
- 若键和值相同,你可以只指定值。(如:`['a2']` 就代表 `['a2'=>'a2']`
- `filter`:用于检查输入值存在性必然会进行数据库查询,而该属性为用于进一步筛选该查询的过滤条件。可以为代表额外查询条件的字符串或数组(关于查询条件的格式,请参考 [[yii\db\Query::where()]]);或者样式为 `function ($query)` 的匿名函数,`$query` 参数为你希望在该函数内进行修改的 [[yii\db\Query|Query]] 对象。
- `allowArray`:是否允许输入值为数组。默认为 false。若该属性为 true 且输入值为数组,则数组的每个元素都必须在目标字段中存在。值得注意的是,若用吧 `targetAttribute` 设为多元素数组来验证被测值在多字段中的存在性时,该属性不能设置为 true。
You can use this validator to validate against a single column or multiple columns (i.e., the combination of
multiple attribute values should exist).
> 译注:[exist](#exist) 和 [unique](#unique) 验证器的机理和参数都相似,有点像一体两面的阴和阳。
- 他们的区别是 exist 要求 `targetAttribute` 键所代表的的属性在其值所代表字段中找得到;而 unique 正相反,要求键所代表的的属性不能在其值所代表字段中被找到。
- 从另一个角度来理解:他们都会在验证的过程中执行数据库查询,查询的条件即为where $v=$k (假设 `targetAttribute` 的其中一对键值对为 `$k => $v`)。unique 要求查询的结果数 `$count==0`,而 exist 则要求查询的结果数 `$count>0`
- 最后别忘了,unique 验证器不存在 `allowArray` 属性哦。
- `targetClass`:用于查找输入值的目标 [AR](db-active-record.md) 类。若不设置,
则会使用正在进行验证的当前模型类。
- `targetAttribute`:用于检查输入值存在性的 `targetClass` 的模型特性。
若不设置,它会直接使用待测特性名(整个参数数组的首元素)。
除了指定为字符串以外,你也可以用数组的形式,同时指定多个用于验证的表字段,数组的键和值都是代表字段的特性名,
值表示 `targetClass` 的待测数据源字段,而键表示当前模型的待测特性名。
若键和值相同,你可以只指定值。(如:`['a2']` 就代表 `['a2'=>'a2']`
- `filter`:用于检查输入值存在性必然会进行数据库查询,而该属性为用于进一步筛选该查询的过滤条件。
可以为代表额外查询条件的字符串或数组(关于查询条件的格式,请参考 [[yii\db\Query::where()]]);
或者样式为 `function ($query)` 的匿名函数,
`$query` 参数为你希望在该函数内进行修改的 [[yii\db\Query|Query]] 对象。
- `allowArray`:是否允许输入值为数组。默认为 false。若该属性为 true 且输入值为数组,则数组的每个元素都必须在目标字段中存在。
值得注意的是,若用吧 `targetAttribute` 设为多元素数组来验证被测值在多字段中的存在性时,
该属性不能设置为 true。
## [[yii\validators\FileValidator|file(文件)]] <span id="file"></span>
@ -220,16 +288,27 @@ function foo($model, $attribute) {
该验证器检查输入值是否为一个有效的上传文件。
- `extensions`:可接受上传的文件扩展名列表。它可以是数组,也可以是用空格或逗号分隔各个扩展名的字符串 (e.g. "gif, jpg")。
扩展名大小写不敏感。默认为 null,意味着所有扩展名都被接受。
- `mimeTypes`:可接受上传的 MIME 类型列表。它可以是数组,也可以是用空格或逗号分隔各个 MIME 的字符串 (e.g. "image/jpeg, image/png")。
Mime 类型名是大小写不敏感的。默认为 null,意味着所有 MIME 类型都被接受。
- `extensions`:可接受上传的文件扩展名列表。它可以是数组,
也可以是用空格或逗号分隔各个扩展名的字符串 (e.g. "gif, jpg")。
扩展名大小写不敏感。默认为 null,
意味着所有扩展名都被接受。
- `mimeTypes`:可接受上传的 MIME 类型列表。
它可以是数组,也可以是用空格或逗号分隔各个
MIME 的字符串 (e.g. "image/jpeg, image/png")。
Mime 类型名是大小写不敏感的。默认为 null,
意味着所有 MIME 类型都被接受。
For more details, please refer to [common media types](http://en.wikipedia.org/wiki/Internet_media_type#List_of_common_media_types).
- `minSize`:上传文件所需最少多少 Byte 的大小。默认为 null,代表没有下限。
- `maxSize`:上传文件所需最多多少 Byte 的大小。默认为 null,代表没有上限。
- `maxFiles`:给定特性最多能承载多少个文件。默认为 1,代表只允许单文件上传。若值大于一,那么输入值必须为包含最多 `maxFiles` 个上传文件元素的数组。
- `checkExtensionByMimeType`:是否通过文件的 MIME 类型来判断其文件扩展。若由 MIME 判定的文件扩展与给定文件的扩展不一样,则文件会被认为无效。默认为 true,代表执行上述检测。
- `maxFiles`:给定特性最多能承载多少个文件。
默认为 1,代表只允许单文件上传。
若值大于一,那么输入值必须为包含最多 `maxFiles` 个上传文件元素的数组。
- `checkExtensionByMimeType`:是否通过文件的 MIME 类型来判断其文件扩展。
若由 MIME 判定的文件扩展与给定文件的扩展不一样,则文件会被认为无效。
默认为 true,代表执行上述检测。
`FileValidator` 通常与 [[yii\web\UploadedFile]] 共同使用。请参考 [文件上传](input-file-upload.md)章节来了解有关文件上传与上传文件的检验的全部内容。
`FileValidator` 通常与 [[yii\web\UploadedFile]] 共同使用。
请参考 [文件上传](input-file-upload.md)章节来了解有关文件上传与上传文件的检验的全部内容。
## [[yii\validators\FilterValidator|filter(滤镜)]] <span id="filter"></span>
@ -247,16 +326,26 @@ function foo($model, $attribute) {
]
```
该验证器并不进行数据验证。而是,给输入值应用一个滤镜,并在检验过程之后把它赋值回特性变量。
该验证器并不进行数据验证。而是,给输入值应用一个滤镜,
并在检验过程之后把它赋值回特性变量。
- `filter`:用于定义滤镜的 PHP 回调函数。可以为全局函数名,匿名函数,或其他。该函数的样式必须是 `function ($value) { return $newValue; }`。该属性不能省略,必须设置。
- `skipOnArray`:是否在输入值为数组时跳过滤镜。默认为 false。请注意如果滤镜不能处理数组输入,你就应该把该属性设为 true。否则可能会导致 PHP Error 的发生。
- `filter`:用于定义滤镜的 PHP 回调函数。可以为全局函数名,匿名函数,或其他。
该函数的样式必须是 `function ($value) { return $newValue; }`。该属性不能省略,必须设置。
- `skipOnArray`:是否在输入值为数组时跳过滤镜。默认为 false。
请注意如果滤镜不能处理数组输入,你就应该把该属性设为 true。
否则可能会导致 PHP Error 的发生。
<<<<<<< .merge_file_a07020
> 技巧:如果你只是想要用 trim 处理下输入值,你可以直接用 [trim](#trim) 验证器的。
=======
> Tip: 如果你只是想要用 trim 处理下输入值,你可以直接用 [trim](#trim) 验证器的。
>>>>>>> .merge_file_a02836
> Tip: There are many PHP functions that have the signature expected for the `filter` callback.
> For example to apply type casting (using e.g. [intval](http://php.net/manual/en/function.intval.php),
> [boolval](http://php.net/manual/en/function.boolval.php), ...) to ensure a specific type for an attribute,
> you can simply specify the function names of the filter without the need to wrap them in a closure:
>
> ```php
> ['property', 'filter', 'filter' => 'boolval'],
> ['property', 'filter', 'filter' => 'intval'],
> ```
## [[yii\validators\ImageValidator|image(图片)]] <span id="image"></span>
@ -271,13 +360,88 @@ function foo($model, $attribute) {
]
```
该验证器检查输入值是否为代表有效的图片文件。它继承自 [file](#file) 验证器,并因此继承有其全部属性。除此之外,它还支持以下为图片检验而设的额外属性:
该验证器检查输入值是否为代表有效的图片文件。它继承自 [file](#file) 验证器,
并因此继承有其全部属性。除此之外,
它还支持以下为图片检验而设的额外属性:
- `minWidth`:图片的最小宽度。默认为 null,代表无下限。
- `maxWidth`:图片的最大宽度。默认为 null,代表无上限。
- `minHeight`:图片的最小高度。 默认为 null,代表无下限。
- `maxHeight`:图片的最大高度。默认为 null,代表无上限。
## [[yii\validators\IpValidator|ip]] <span id="ip"></span>
```php
[
// checks if "ip_address" is a valid IPv4 or IPv6 address
['ip_address', 'ip'],
// checks if "ip_address" is a valid IPv6 address or subnet,
// value will be expanded to full IPv6 notation.
['ip_address', 'ip', 'ipv4' => false, 'subnet' => null, 'expandIPv6' => true],
// checks if "ip_address" is a valid IPv4 or IPv6 address,
// allows negation character `!` at the beginning
['ip_address', 'ip', 'negation' => true],
]
```
The validator checks if the attribute value is a valid IPv4/IPv6 address or subnet.
It also may change attribute's value if normalization or IPv6 expansion is enabled.
The validator has such configuration options:
- `ipv4`: whether the validating value can be an IPv4 address. Defaults to true.
- `ipv6`: whether the validating value can be an IPv6 address. Defaults to true.
- `subnet`: whether the address can be an IP with CIDR subnet, like `192.168.10.0/24`
* `true` - the subnet is required, addresses without CIDR will be rejected
* `false` - the address can not have the CIDR
* `null` - the CIDR is optional
Defaults to false.
- `normalize`: whether to add the CIDR prefix with the smallest length (32 for IPv4 and 128 for IPv6) to an
address without it. Works only when `subnet` is not `false`. For example:
* `10.0.1.5` will normalized to `10.0.1.5/32`
* `2008:db0::1` will be normalized to `2008:db0::1/128`
Defaults to false.
- `negation`: whether the validation address can have a negation character `!` at the beginning. Defaults to false.
- `expandIPv6`: whether to expand an IPv6 address to the full notation format.
For example, `2008:db0::1` will be expanded to `2008:0db0:0000:0000:0000:0000:0000:0001`. Defaults to false.
- `ranges`: array of IPv4 or IPv6 ranges that are allowed or forbidden.
When the array is empty, or the option is not set, all the IP addresses are allowed.
Otherwise, the rules are checked sequentially until the first match is found.
IP address is forbidden, when it has not matched any of the rules.
For example:
```php
[
'client_ip', 'ip', 'ranges' => [
'192.168.10.128'
'!192.168.10.0/24',
'any' // allows any other IP addresses
]
]
```
In this example, access is allowed for all the IPv4 and IPv6 addresses excluding `192.168.10.0/24` subnet.
IPv4 address `192.168.10.128` is also allowed, because it is listed before the restriction.
- `networks`: array of network aliases, that can be used in `ranges`. Format of array:
* key - alias name
* value - array of strings. String can be a range, IP address or another alias. String can be
negated with `!` (independent of `negation` option).
The following aliases are defined by default:
* `*`: `any`
* `any`: `0.0.0.0/0, ::/0`
* `private`: `10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, fd00::/8`
* `multicast`: `224.0.0.0/4, ff00::/8`
* `linklocal`: `169.254.0.0/16, fe80::/10`
* `localhost`: `127.0.0.0/8', ::1`
* `documentation`: `192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24, 2001:db8::/32`
* `system`: `multicast, linklocal, localhost, documentation`
> Info: This validator has been available since version 2.0.7.
## [[yii\validators\RangeValidator|in(范围)]] <span id="in"></span>
@ -291,9 +455,12 @@ function foo($model, $attribute) {
该验证器检查输入值是否存在于给定列表的范围之中。
- `range`:用于检查输入值的给定值列表。
- `strict`:输入值与给定值直接的比较是否为严格模式(也就是类型与值都要相同,即全等)。默认为 false。
- `not`:是否对验证的结果取反。默认为 false。当该属性被设置为 true,验证器检查输入值是否**不在**给定列表内。
- `allowArray`:是否接受输入值为数组。当该值为 true 且输入值为数组时,数组内的每一个元素都必须在给定列表内存在,否则返回验证失败。
- `strict`:输入值与给定值直接的比较是否为严格模式(也就是类型与值都要相同,即全等)。
默认为 false。
- `not`:是否对验证的结果取反。默认为 false。当该属性被设置为 true,
验证器检查输入值是否**不在**给定列表内。
- `allowArray`:是否接受输入值为数组。当该值为 true 且输入值为数组时,
数组内的每一个元素都必须在给定列表内存在,否则返回验证失败。
## [[yii\validators\NumberValidator|integer(整数)]] <span id="integer"></span>
@ -322,8 +489,11 @@ function foo($model, $attribute) {
该验证器检查输入值是否匹配指定正则表达式。
- `pattern`:用于检测输入值的正则表达式。该属性是必须的,若不设置则会抛出异常。
- `not`:是否对验证的结果取反。默认为 false,代表输入值匹配正则表达式时验证成功。如果设为 true,则输入值不匹配正则时返回匹配成功。
- `pattern`:用于检测输入值的正则表达式。该属性是必须的,
若不设置则会抛出异常。
- `not`:是否对验证的结果取反。默认为 false,
代表输入值匹配正则表达式时验证成功。如果设为 true,
则输入值不匹配正则时返回匹配成功。
## [[yii\validators\NumberValidator|number(数字)]] <span id="number"></span>
@ -353,15 +523,14 @@ function foo($model, $attribute) {
该验证器检查输入值是否为空,还是已经提供了。
- `requiredValue`:所期望的输入值。若没设置,意味着输入不能为空。
- `strict`:检查输入值时是否检查类型。默认为 false。当没有设置 `requiredValue` 属性时,若该属性为 true,验证器会检查输入值是否严格为 null;若该属性设为 false,该验证器会用一个更加宽松的规则检验输入值是否为空。
当设置了 `requiredValue` 属性时,若该属性为 true,输入值与 `requiredValue` 的比对会同时检查数据类型。
- `strict`:检查输入值时是否检查类型。默认为 false。
当没有设置 `requiredValue` 属性时,若该属性为 true,
验证器会检查输入值是否严格为 null;若该属性设为 false,
该验证器会用一个更加宽松的规则检验输入值是否为空。
当设置了 `requiredValue` 属性时,若该属性为 true,输入值与 `requiredValue` 的比对会同时检查数据类型。
<<<<<<< .merge_file_a07020
> 补充:如何判断待测值是否为空,被写在另外一个话题的[处理空输入](input-validation.md#handling-empty-inputs)章节。
=======
> Info: 如何判断待测值是否为空,被写在另外一个话题的[处理空输入](input-validation.md#handling-empty-inputs)章节。
>>>>>>> .merge_file_a02836
> 注意:如何判断待测值是否为空,被写在另外一个话题的
[处理空输入](input-validation.md#handling-empty-inputs)章节。
## [[yii\validators\SafeValidator|safe(安全)]] <span id="safe"></span>
@ -373,7 +542,8 @@ function foo($model, $attribute) {
]
```
该验证器并不进行数据验证。而是把一个特性标记为[安全特性](structure-models.md#safe-attributes)。
该验证器并不进行数据验证。而是把一个特性标记为
[安全特性](structure-models.md#safe-attributes)。
## [[yii\validators\StringValidator|string(字符串)]] <span id="string"></span>
@ -387,14 +557,16 @@ function foo($model, $attribute) {
该验证器检查输入值是否为特定长度的字符串。并检查特性的值是否为某个特定长度。
- `length`:指定待测输入字符串的长度限制。该属性可以被指定为以下格式之一:
- `length`:指定待测输入字符串的长度限制。
该属性可以被指定为以下格式之一:
* 证书:the exact length that the string should be of;
* 单元素数组:代表输入字符串的最小长度 (e.g. `[8]`)。这会重写 `min` 属性。
* 包含两个元素的数组:代表输入字符串的最小和最大长度(e.g. `[8, 128]`)。
这会同时重写 `min``max` 属性。
- `min`:输入字符串的最小长度。若不设置,则代表不设下限。
- `max`:输入字符串的最大长度。若不设置,则代表不设上限。
- `encoding`:待测字符串的编码方式。若不设置,则使用应用自身的 [[yii\base\Application::charset|charset]] 属性值,该值默认为 `UTF-8`
- `encoding`:待测字符串的编码方式。若不设置,则使用应用自身的 [[yii\base\Application::charset|charset]] 属性值,
该值默认为 `UTF-8`
## [[yii\validators\FilterValidator|trim(译为修剪/裁边)]] <span id="trim"></span>
@ -406,7 +578,8 @@ function foo($model, $attribute) {
]
```
该验证器并不进行数据验证。而是,trim 掉输入值两侧的多余空格。注意若该输入值为数组,那它会忽略掉该验证器。
该验证器并不进行数据验证。而是,trim 掉输入值两侧的多余空格。
注意若该输入值为数组,那它会忽略掉该验证器。
## [[yii\validators\UniqueValidator|unique(唯一性)]] <span id="unique"></span>
@ -430,32 +603,40 @@ function foo($model, $attribute) {
]
```
该验证器检查输入值是否在某表字段中唯一。它只对[活动记录](db-active-record.md)类型的模型类特性起作用,能支持对一个或多过字段的验证。
该验证器检查输入值是否在某表字段中唯一。
它只对[活动记录](db-active-record.md)类型的模型类特性起作用,
能支持对一个或多过字段的验证。
- `targetClass`:用于查找输入值的目标 [AR](db-active-record.md) 类。若不设置,则会使用正在进行验证的当前模型类。
- `targetClass`:用于查找输入值的目标 [AR](db-active-record.md) 类。
若不设置,则会使用正在进行验证的当前模型类。
- `targetAttribute`:用于检查输入值唯一性的 `targetClass` 的模型特性。
- 若不设置,它会直接使用待测特性名(整个参数数组的首元素)。
- 除了指定为字符串以外,你也可以用数组的形式,同时指定多个用于验证的表字段,数组的键和值都是代表字段的特性名,值表示 `targetClass` 的待测数据源字段,而键表示当前模型的待测特性名。
- 若键和值相同,你可以只指定值。(如:`['a2']` 就代表 `['a2'=>'a2']`
- `filter`:用于检查输入值唯一性必然会进行数据库查询,而该属性为用于进一步筛选该查询的过滤条件。可以为代表额外查询条件的字符串或数组(关于查询条件的格式,请参考 [[yii\db\Query::where()]]);或者样式为 `function ($query)` 的匿名函数,`$query` 参数为你希望在该函数内进行修改的 [[yii\db\Query|Query]] 对象。
> 译注:[exist](#exist) 和 [unique](#unique) 验证器的机理和参数都相似,有点像一体两面的阴和阳。
- 他们的区别是 exist 要求 `targetAttribute` 键所代表的的属性在其值所代表字段中找得到;而 unique 正相反,要求键所代表的的属性不能在其值所代表字段中被找到。
- 从另一个角度来理解:他们都会在验证的过程中执行数据库查询,查询的条件即为where $v=$k (假设 `targetAttribute` 的其中一对键值对为 `$k => $v`)。unique 要求查询的结果数 `$count==0`,而 exist 则要求查询的结果数 `$count>0`
- 最后别忘了,unique 验证器不存在 `allowArray` 属性哦。
若不设置,它会直接使用待测特性名(整个参数数组的首元素)。
除了指定为字符串以外,你也可以用数组的形式,同时指定多个用于验证的表字段,数组的键和值都是代表字段的特性名,
值表示 `targetClass` 的待测数据源字段,而键表示当前模型的待测特性名。
若键和值相同,你可以只指定值。(如:`['a2']` 就代表 `['a2'=>'a2']`
- `filter`:用于检查输入值唯一性必然会进行数据库查询,
而该属性为用于进一步筛选该查询的过滤条件。可以为代表额外查询条件的字符串或数组
(关于查询条件的格式,请参考 [[yii\db\Query::where()]]);或者样式为 `function ($query)` 的匿名函数,
`$query` 参数为你希望在该函数内进行修改的 [[yii\db\Query|Query]] 对象。
## [[yii\validators\UrlValidator|url(网址)]] <span id="url"></span>
```php
[
// 检查 "website" 是否为有效的 URL。若没有 URI 方案,则给 "website" 特性加 "http://" 前缀
// 检查 "website" 是否为有效的 URL。若没有 URI 方案,
// 则给 "website" 特性加 "http://" 前缀
['website', 'url', 'defaultScheme' => 'http'],
]
```
该验证器检查输入值是否为有效 URL。
- `validSchemes`:用于指定那些 URI 方案会被视为有效的数组。默认为 `['http', 'https']`,代表 `http``https` URLs 会被认为有效。
- `defaultScheme`:若输入值没有对应的方案前缀,会使用的默认 URI 方案前缀。默认为 null,代表不修改输入值本身。
- `enableIDN`:验证过程是否应该考虑 IDN(internationalized domain names,国际化域名,也称多语种域名,比如中文域名)。默认为 false。要注意但是为使用 IDN 验证功能,请先确保安装并开启 `intl` PHP 扩展,不然会导致抛出异常。
- `validSchemes`:用于指定那些 URI 方案会被视为有效的数组。默认为 `['http', 'https']`
代表 `http``https` URLs 会被认为有效。
- `defaultScheme`:若输入值没有对应的方案前缀,会使用的默认 URI 方案前缀。
默认为 null,代表不修改输入值本身。
- `enableIDN`:验证过程是否应该考虑 IDN(internationalized domain names,国际化域名,也称多语种域名,比如中文域名)。
默认为 false。要注意但是为使用 IDN 验证功能,
请先确保安装并开启 `intl` PHP 扩展,不然会导致抛出异常。

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

@ -3,14 +3,17 @@
国际化(I18N)是指在设计软件时,使它可以无需做大的改变就能够适应不同的语言和地区的需要。对于 Web 应用程序,
这有着特别重要的意义,因为潜在的用户可能会在全球范围内。
Yii 提供的国际化功能支持全方位信息翻译,视图翻译,日期和数字格式化。
Yii 提供的国际化功能支持全方位信息翻译,
视图翻译,日期和数字格式化。
## 区域和语言 <span id="locale-language"></span>
区域设置是一组参数以定义用户希望能在他们的用户界面所看到用户的语言,国家和任何特殊的偏好。
它通常是由语言 ID 和区域 ID 组成。例如,ID “en-US” 代表英语和美国的语言环境。为了保持一致性,
在 Yii 应用程序中使用的所有区域 ID 应该规范化为 `ll-CC`,其中 `ll` 是根据两个或三个字母的小写字母语言代码
它通常是由语言 ID 和区域 ID 组成。
例如,ID “en-US” 代表英语和美国的语言环境。为了保持一致性,
在 Yii 应用程序中使用的所有区域 ID 应该规范化为 `ll-CC`
其中 `ll` 是根据两个或三个字母的小写字母语言代码
[ISO-639](http://www.loc.gov/standards/iso639-2/) 和 `CC` 是两个字母的国别代码
[ISO-3166](http://www.iso.org/iso/en/prods-services/iso3166ma/02iso-3166-code-lists/list-en1.html)。
有关区域设置的更多细节可以看
@ -19,7 +22,8 @@ Yii 提供的国际化功能支持全方位信息翻译,视图翻译,日期
在 Yii中,我们经常用 “language” 来代表一个区域。
一个 Yii 应用使用两种语言:[[yii\base\Application::$sourceLanguage|源语言]] 和
[[yii\base\Application::$language|目标语言]] 。前者指的是写在代码中的语言,后者是向最终用户显示内容的语言。
[[yii\base\Application::$language|目标语言]] 。
前者指的是写在代码中的语言,后者是向最终用户显示内容的语言。
而信息翻译服务主要是将文本消息从原语言翻译到目标语言。
可以用类似下面的应用程序配置来配置应用程序语言:
@ -37,10 +41,12 @@ return [
```
默认的 [[yii\base\Application::$sourceLanguage|源语言]] 值是 `en-US`,即美国英语。
建议你保留此默认值不变,因为通常让人将英语翻译成其它语言要比将其它语言翻译成其它语言容易得多。
建议你保留此默认值不变,
因为通常让人将英语翻译成其它语言要比将其它语言翻译成其它语言容易得多。
你经常需要根据不同的因素来动态地设置 [[yii\base\Application::$language|目标语言]] ,如最终用户的语言首选项。
要在应用程序配置中配置它,你可以使用下面的语句来更改目标语言:
你经常需要根据不同的因素来动态地设置 [[yii\base\Application::$language|目标语言]] ,
如最终用户的语言首选项。要在应用程序配置中配置它,
你可以使用下面的语句来更改目标语言:
```php
// 改变目标语言为中文
@ -51,7 +57,8 @@ return [
消息翻译服务用于将一条文本信息从一种语言(通常是 [[yii\base\Application::$sourceLanguage|源语言]] )
翻译成另一种语言(通常是 [[yii\base\Application::$language|目标语言]])。
它的翻译原理是通过在语言文件中查找要翻译的信息以及翻译的结果。如果要翻译的信息可以在语言文件中找到,会返回相应的翻译结果;
它的翻译原理是通过在语言文件中查找要翻译的信息以及翻译的结果。
如果要翻译的信息可以在语言文件中找到,会返回相应的翻译结果;
否则会返回原始未翻译的信息。
为了使用消息翻译服务,需要做如下工作:
@ -66,7 +73,8 @@ return [
echo \Yii::t('app', 'This is a string to translate!');
```
第一个参数指储存消息来源的类别名称,第二个参数指需要被翻译的消息。
第一个参数指储存消息来源的类别名称,
第二个参数指需要被翻译的消息。
这个 [[Yii::t()]] 方法会调用 `i18n` [应用组件](structure-application-components.md)
来实现翻译工作。这个组件可以在应用程序中按下面的代码来配置,
@ -91,13 +99,16 @@ echo \Yii::t('app', 'This is a string to translate!');
```
在上面的代码中,配置了由 [[yii\i18n\PhpMessageSource]] 所支持的消息来源。模式 `app*` 表示所有以 `app`
开头的消息类别名称都使用这个翻译的消息来源。该 [[yii\i18n\PhpMessageSource]] 类使用 PHP 文件来存储消息翻译。
每 PHP 文件对应单一类别的消息。默认情况下,文件名应该与类别名称相同。但是,你可以配置
开头的消息类别名称都使用这个翻译的消息来源。
该 [[yii\i18n\PhpMessageSource]] 类使用 PHP 文件来存储消息翻译。
每 PHP 文件对应单一类别的消息。默认情况下,
文件名应该与类别名称相同。但是,你可以配置
[[yii\i18n\PhpMessageSource::fileMap|fileMap]] 来映射一个类别到不同名称的 PHP 文件。在上面的例子中,
类别 `app/error` 被映射到PHP文件 `@app/messages/ru-RU/error.php`(假设 `ru-RU` 为目标语言)。如果没有此配置,
该类别将被映射到 `@app/messages/ru-RU/app/error.php`
除了在PHP文件中存储消息来源,也可以使用下面的消息来源在不同的存储来存储翻译的消息:
除了在PHP文件中存储消息来源,
也可以使用下面的消息来源在不同的存储来存储翻译的消息:
- [[yii\i18n\GettextMessageSource]] 使用 GNU Gettext 的 MO 或 PO 文件保存翻译的消息。
- [[yii\i18n\DbMessageSource]] 使用一个数据库表来存储翻译的消息。
@ -105,13 +116,16 @@ echo \Yii::t('app', 'This is a string to translate!');
## 消息格式化 <span id="message-formatting"></span>
在要翻译的消息里,你可以嵌入一些占位符,并让它们通过动态的参数值来代替。你甚至可以根据目标语言格式的参数值来使用特殊的占位符。
在要翻译的消息里,你可以嵌入一些占位符,并让它们通过动态的参数值来代替。
你甚至可以根据目标语言格式的参数值来使用特殊的占位符。
在本节中,我们将介绍如何用不同的方式来格式化消息。
### 消息参数 <span id="message-parameters"></span>
在待翻译的消息,可以嵌入一个或多个占位符,以便它们可以由给定的参数值取代。通过给不同的参数值,可以动态地改变翻译内容的消息。
在下面的例子中,占位符 `{username}``“Hello, {username}!”` 中将分别被 `'Alexander'`和`'Qiang'` 所替换。
在待翻译的消息,可以嵌入一个或多个占位符,以便它们可以由给定的参数值取代。
通过给不同的参数值,可以动态地改变翻译内容的消息。
在下面的例子中,
占位符 `{username}``“Hello, {username}!”` 中将分别被 `'Alexander'`和`'Qiang'` 所替换。
```php
$username = 'Alexander';
@ -127,15 +141,18 @@ echo \Yii::t('app', 'Hello, {username}!', [
]);
```
当翻译的消息包含占位符时,应该让占位符保留原样。这是因为调用 `Yii::t()` 时,占位符将被实际参数值代替。
当翻译的消息包含占位符时,应该让占位符保留原样。
这是因为调用 `Yii::t()` 时,占位符将被实际参数值代替。
你可以使用 *名称占位符* 或者 *位置占位符*,但不能两者都用在同一个消息里。
前面的例子说明了如何使用名称占位符。即每个占位符的格式为 `{参数名称}` ,你所提供的参数作为关联数组,
其中数组的键是参数名称(没有大括号),数组的值是对应的参数值。
其中数组的键是参数名称(没有大括号),
数组的值是对应的参数值。
位置占位符是使用基于零的整数序列,在调用 `Yii::t()` 时会参数值根据它们出现位置的顺序分别进行替换。
在下面的例子中,位置占位符 `{0}`,`{1}` 和 `{2}` 将分别被 `$price`,`$count` 和 `$subtotal` 所替换。
在下面的例子中,位置占位符 `{0}`,`{1}` 和 `{2}`
将分别被 `$price`,`$count` 和 `$subtotal` 所替换。
```php
$price = 100;
@ -144,12 +161,20 @@ $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);
```
> 提示:大多数情况下你应该使用名称占位符。
> 这是因为参数名称可以让翻译者更好的理解要被翻译的消息。
### 格式化参数 <span id="parameter-formatting"></span>
你可以在消息的占位符指定附加格式的规则,这样的参数值可在替换占位符之前格式化它们。在下面的例子中,
你可以在消息的占位符指定附加格式的规则,
这样的参数值可在替换占位符之前格式化它们。在下面的例子中,
价格参数值将视为一个数并格式化为货币值:
```php
@ -166,10 +191,14 @@ short form: {PlaceholderName, ParameterType}
full form: {PlaceholderName, ParameterType, ParameterStyle}
```
请参阅 [ICU 文档](http://icu-project.org/apiref/icu4c/classMessageFormat.html)
关于如何指定这样的占位符的说明。
> Note: If you need to use special characters such as `{`, `}`, `'`, `#`, wrap them in `'`:
>
```php
echo Yii::t('app', "Example of string with ''-escaped characters'': '{' '}' '{test}' {count,plural,other{''count'' value is # '#{}'}}", ['count' => 3]);
```
接下来我们会展示一些常用的使用方法。
请参阅 [ICU 文档](http://icu-project.org/apiref/icu4c/classMessageFormat.html)
关于如何指定这样的占位符的说明。接下来我们会展示一些常用的使用方法。
#### 数字 <span id="number"></span>
@ -195,8 +224,14 @@ $sum = 42;
echo \Yii::t('app', 'Balance: {0, number, ,000,000000}', $sum);
```
[格式化参考](http://icu-project.org/apiref/icu4c/classicu_1_1DecimalFormat.html)。
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.
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()]].
#### 日期 <span id="date"></span>
@ -253,6 +288,18 @@ 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 `%`.
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/).
#### 序数词 <span id="ordinal"></span>
参数值为一个数并被格式化为一个序数词。 例如,
@ -262,6 +309,17 @@ echo \Yii::t('app', '{n,number} is spelled as {n, spellout}', ['n' => 42]);
echo \Yii::t('app', 'You are the {n, ordinal} visitor here!', ['n' => 42]);
```
Ordinal supports more ways of formatting for languages such as Spanish:
```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 `%`.
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/).
#### 持续时间 <span id="duration"></span>
@ -272,10 +330,22 @@ echo \Yii::t('app', 'You are the {n, ordinal} visitor here!', ['n' => 42]);
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 `%`.
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/).
#### 复数 <span id="plural"></span>
不同的语言有不同的方式来表示复数。 Yii 提供一个便捷的途径,即使是非常复杂的规则也使翻译消息时不同的复数形式行之有效。
不同的语言有不同的方式来表示复数。 Yii 提供一个便捷的途径,
即使是非常复杂的规则也使翻译消息时不同的复数形式行之有效。
取之以直接处理词形变化规则,它是足以面对某些词形变化语言的翻译。 例如,
```php
@ -288,20 +358,61 @@ echo \Yii::t('app', 'There {n, plural, =0{are no cats} =1{is one cat} other{are
在上面的多个规则的参数中, `=0` 意味着 `n` 的值是 0 ,`=1` 意味着 `n` 的值是 1 , 而 `other` 则是对于其它值,
`#` 会被 `n` 中的值给替代。
复数形式可以是某些非常复杂的语言。下面以俄罗斯为例,`=1` 完全匹配 `n = 1`,而 `one` 匹配 `21``101`
复数形式可以是某些非常复杂的语言。下面以俄罗斯为例,`=1` 完全匹配 `n = 1`
`one` 匹配 `21``101`
```
Здесь {n, plural, =0{котов нет} =1{есть один кот} one{# кот} few{# кота} many{# котов} other{# кота}}!
```
注意,上述信息主要是作为一个翻译的信息,而不是一个原始消息,除非设置应用程序的
注意,上述信息主要是作为一个翻译的信息,
而不是一个原始消息,除非设置应用程序的
[[yii\base\Application::$sourceLanguage|源语言]] 为 `ru-RU`
如果没有找到一个翻译的原始消息,复数规则 [[yii\base\Application::$sourceLanguage|源语言]] 将被应用到原始消息。
> 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.
>
> 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.
There's an `offset` parameter for the cases when the string is like the following:
```php
$likeCount = 2;
echo Yii::t('app', 'You {likeCount,plural,
offset: 1
=0{did not like this}
=1{liked this}
one{and one other person liked this}
other{and # others liked this}
}', [
'likeCount' => $likeCount
]);
// You and one other person liked this
```
#### 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:
```php
$n = 3;
echo Yii::t('app', 'You are the {n,selectordinal,one{#st} two{#nd} few{#rd} other{#th}} visitor', ['n' => $n]);
// For English it outputs:
// You are the 3rd visitor
// Translation
'You are the {n,selectordinal,one{#st} two{#nd} few{#rd} other{#th}} visitor' => 'Вы {n,selectordinal,other{#-й}} посетитель',
要了解词形变化形式,你应该指定一个特定的语言,请参考
[rules reference at unicode.org](http://unicode.org/repos/cldr-tmp/trunk/diff/supplemental/language_plural_rules.html)。
// For Russian translation it outputs:
// Вы 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).
#### 选择 <span id="selection"></span>
@ -315,7 +426,8 @@ echo \Yii::t('app', '{name} is a {gender} and {gender, select, female{she} male{
]);
```
在上面的表达中, `female``male` 是可能的参数值,而 `other` 用于处理不与它们中任何一个相匹配的值。对于每一个可能的参数值,
在上面的表达中, `female``male` 是可能的参数值,
`other` 用于处理不与它们中任何一个相匹配的值。对于每一个可能的参数值,
应指定一个短语并把它放在在一对大括号中。
@ -345,7 +457,6 @@ echo Yii::t('not_specified_category', 'message from unspecified category');
该消息将来自 `@app/messages/<LanguageCode>/not_specified_category.php`
### 翻译模块消息
如果你想翻译一个模块的消息,并避免使用单一翻译文件的所有信息,你可以按照下面的方式来翻译:
@ -390,7 +501,8 @@ class Module extends \yii\base\Module
```
在上面的例子中,我们使用通配符匹配,然后过滤了所需的文件中的每个类别。取之使用 `fileMap` ,你可以简单地使用类映射的同名文件。
现在你可以直接使用 `Module::t('validation', 'your custom validation message')``Module::t('form', 'some form label')`
现在你可以直接使用 `Module::t('validation', 'your custom validation message')`
`Module::t('form', 'some form label')`
### 翻译小部件消息
@ -439,14 +551,16 @@ class Menu extends Widget
}
```
你可以简单地使用类映射的同名文件而不是使用 `fileMap` 。现在你直接可以使用 `Menu::t('messages', 'new messages {messages}', ['{messages}' => 10])`
你可以简单地使用类映射的同名文件而不是使用 `fileMap`
现在你直接可以使用 `Menu::t('messages', 'new messages {messages}', ['{messages}' => 10])`
> **提示**: 对于小部件也可以使用 i18n 视图,并一样以控制器的规则来应用它们。
### 翻译框架信息
Yii 自带了一些默认的信息验证错误和其他一些字符串的翻译。这些信息都是在 `yii` 类别中。有时候你想纠正应用程序的默认信息翻译。
Yii 自带了一些默认的信息验证错误和其他一些字符串的翻译。
这些信息都是在 `yii` 类别中。有时候你想纠正应用程序的默认信息翻译。
为了做到这一点,需配置 `i18n` [应用组件](structure-application-components.md) 如下:
```php
@ -466,7 +580,8 @@ Yii 自带了一些默认的信息验证错误和其他一些字符串的翻译
### 处理缺少的翻译
如果翻译的消息在消息源文件里找不到,Yii 将直接显示该消息内容。这样一来当你的原始消息是一个有效的冗长的文字时会很方便。
然而,有时它是不能实现我们的需求。你可能需要执行一些自定义处理的情况,这时请求的翻译可能在消息翻译源文件找不到。
然而,有时它是不能实现我们的需求。你可能需要执行一些自定义处理的情况,
这时请求的翻译可能在消息翻译源文件找不到。
这可通过使用 [[yii\i18n\MessageSource::EVENT_MISSING_TRANSLATION|missingTranslation]] - [[yii\i18n\MessageSource]] 的事件来完成。
例如,你可能想要将所有缺失的翻译做一个明显的标记,这样它们就可以很容易地在页面中找到。
@ -516,8 +631,7 @@ class TranslationEventHandler
### 使用 `message` 命令 <a name="message-command"></a>
翻译储存在 [[yii\i18n\PhpMessageSource|php 文件]],[[yii\i18n\GettextMessageSource|.po 文件] 或者 [[yii\i18n\DbMessageSource|数据库]]。
具体见类的附加选项。
翻译储存在 [[yii\i18n\PhpMessageSource|php 文件]],[[yii\i18n\GettextMessageSource|.po 文件] 或者 [[yii\i18n\DbMessageSource|数据库]]。具体见类的附加选项。
首先,你需要创建一个配置文件。确定应该保存在哪里,然后执行命令
@ -530,21 +644,36 @@ 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:
```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>
有时你可能想要翻译一个完整的视图文件,而不是翻译单条文本消息。为了达到这一目的,只需简单的翻译视图并在它子目录下保存一个名称一样的目标语言文件。
例如,如果你想要翻译的视图文件为 `views/site/index.php` 且目标语言是 `ru-RU`,你可以将视图翻译并保存为 `views/site/ru-RU/index.php`。现在
有时你可能想要翻译一个完整的视图文件,而不是翻译单条文本消息。为了达到这一目的,
只需简单的翻译视图并在它子目录下保存一个名称一样的目标语言文件。
例如,如果你想要翻译的视图文件为 `views/site/index.php` 且目标语言是 `ru-RU`
你可以将视图翻译并保存为 `views/site/ru-RU/index.php`。现在
每当你调用 [[yii\base\View::renderFile()]] 或任何其它方法 (如 [[yii\base\Controller::render()]]) 来渲染 `views/site/index.php` 视图,
它最终会使用所翻译的 `views/site/ru-RU/index.php`
@ -564,8 +693,11 @@ Yii 使用 [PHP intl 扩展](http://php.net/manual/en/book.intl.php) 来提供
`intl` 扩展没有安装时,两者会提供一个回调机制。然而,该回调机制只适用于目标语言是英语的情况下。
因此,当 I18N 对你来说必不可少时,强烈建议你安装 `intl`
[PHP intl 扩展](http://php.net/manual/en/book.intl.php) 是基于对于所有不同的语言环境提供格式化规则的 [ICU库](http://site.icu-project.org/)。
不同版本的 ICU 中可能会产生不同日期和数值格式的结果。为了确保你的网站在所有环境产生相同的结果,建议你安装与 `intl` 扩展相同的版本(和 ICU 同一版本)。
[PHP intl 扩展](http://php.net/manual/en/book.intl.php) 是基于对于所有不同的语言环境
提供格式化规则的 [ICU库](http://site.icu-project.org/)。
不同版本的 ICU 中可能会产生不同日期和数值格式的结果。
为了确保你的网站在所有环境产生相同的结果,
建议你安装与 `intl` 扩展相同的版本(和 ICU 同一版本)。
要找出所使用的 PHP 是哪个版本的 ICU ,你可以运行下面的脚本,它会给出你所使用的 PHP 和 ICU 的版本。
@ -573,12 +705,15 @@ Yii 使用 [PHP intl 扩展](http://php.net/manual/en/book.intl.php) 来提供
<?php
echo "PHP: " . PHP_VERSION . "\n";
echo "ICU: " . INTL_ICU_VERSION . "\n";
echo "ICU Data: " . INTL_ICU_DATA_VERSION . "\n";
```
此外,还建议你所使用的 ICU 版本应等于或大于 49 的版本。这确保了可以使用本文档描述的所有功能。例如,
低于 49 版本的 ICU 不支持使用 `#` 占位符来实现复数规则。请参阅 <http://site.icu-project.org/download> 获取可用 ICU 版本的完整列表。
低于 49 版本的 ICU 不支持使用 `#` 占位符来实现复数规则。
请参阅 <http://site.icu-project.org/download> 获取可用 ICU 版本的完整列表。
注意,版本编号在 4.8 之后发生了变化(如 ICU4.8,ICU49,50 ICU 等)。
另外,ICU 库中时区数据库的信息可能过时。要更新时区数据库时详情请参阅
[ICU 手册](http://userguide.icu-project.org/datetime/timezone#TOC-Updating-the-Time-Zone-Data) 。而对于 ICU 输出格式使用的时区数据库,
PHP 用的时区数据库可能跟它有关。你可以通过安装 [pecl package `timezonedb`](http://pecl.php.net/package/timezonedb) 的最新版本来更新它。
[ICU 手册](http://userguide.icu-project.org/datetime/timezone#TOC-Updating-the-Time-Zone-Data) 。
而对于 ICU 输出格式使用的时区数据库,PHP 用的时区数据库可能跟它有关。
你可以通过安装 [pecl package `timezonedb`](http://pecl.php.net/package/timezonedb) 的最新版本来更新它。

43
docs/guide-zh-CN/tutorial-mailing.md

@ -3,15 +3,19 @@
> 注意:本节正在开发中。
Yii 支持组成和发送电子邮件。然而,该框架提供的只有内容组成功能和基本接口。实际的邮件发送机制可以通过扩展提供,
因为不同的项目可能需要不同的实现方式,它通常取决于外部服务和库。
Yii 支持组成和发送电子邮件。然而,该框架提供的只有内容组成功能和基本接口。
实际的邮件发送机制可以通过扩展提供,
因为不同的项目可能需要不同的实现方式,
它通常取决于外部服务和库。
大多数情况下你可以使用 [yii2-swiftmailer](https://github.com/yiisoft/yii2-swiftmailer) 官方扩展。
配置
-------
邮件组件配置取决于你所使用的扩展。一般来说你的应用程序配置应如下:
邮件组件配置取决于你所使用的扩展。
一般来说你的应用程序配置应如下:
```php
return [
@ -56,7 +60,8 @@ $message->setTo(Yii::$app->params['adminEmail'])
->send();
```
> 注意:每个 “mailer” 的扩展也有两个主要类别:“Mailer” 和 “Message”。 “Mailer” 总是知道类名和具体的 “Message”。
> 注意:每个 “mailer” 的扩展也有两个主要类别:“Mailer”
和 “Message”。 “Mailer” 总是知道类名和具体的 “Message”。
不要试图直接实例 “Message” 对象 - 而是始终使用 `compose()` 方法。
你也可以一次发送几封邮件:
@ -77,7 +82,8 @@ Yii::$app->mailer->sendMultiple($messages);
撰写邮件内容
------------
Yii 允许通过特殊的视图文件来撰写实际的邮件内容。默认情况下,这些文件应该位于 “@app/mail” 路径。
Yii 允许通过特殊的视图文件来撰写实际的邮件内容。默认情况下,
这些文件应该位于 “@app/mail” 路径。
一个邮件视图内容的例子:
@ -123,10 +129,12 @@ Yii::$app->mailer->compose([
]);
```
如果指定视图名称为纯字符串,它的渲染结果将被用来作为 HTML Body,同时纯文本正文将被删除所有 HTML 实体。
如果指定视图名称为纯字符串,它的渲染结果将被用来作为 HTML Body,
同时纯文本正文将被删除所有 HTML 实体。
视图渲染结果可以被包裹进布局,可使用 [[yii\mail\BaseMailer::htmlLayout]] 和 [[yii\mail\BaseMailer::textLayout]] 来设置。
它的运行方式跟常规应用程序的布局是一样的。布局可用于设置邮件 CSS 样式或其他共享内容:
它的运行方式跟常规应用程序的布局是一样的。
布局可用于设置邮件 CSS 样式或其他共享内容:
```php
<?php
@ -178,7 +186,8 @@ $message->attachContent('Attachment content', ['fileName' => 'attach.txt', 'cont
嵌入图片
---------
你可以使用 `embed()` 方法将图片插入到邮件内容。此方法返回会图片 ID ,这将用在 "img" 标签中。
你可以使用 `embed()` 方法将图片插入到邮件内容。
此方法返回会图片 ID ,这将用在 "img" 标签中。
当通过视图文件来写信时,这种方法易于使用:
```php
@ -197,20 +206,26 @@ Yii::$app->mailer->compose('embed-email', ['imageFileName' => '/path/to/image.jp
测试和调试
-----------
开发人员常常要检查一下,有什么电子邮件是由应用程序发送的,他们的内容是什么等。这可通过 `yii\mail\BaseMailer::useFileTransport` 来检查。
如果开启这个选项,会把邮件信息保存在本地文件而不是发送它们。这些文件保存在 `yii\mail\BaseMailer::fileTransportPath` 中,默认在 '@runtime/mail' 。
开发人员常常要检查一下,有什么电子邮件是由应用程序发送的,他们的内容是什么等。
这可通过 `yii\mail\BaseMailer::useFileTransport` 来检查。
如果开启这个选项,会把邮件信息保存在本地文件而不是发送它们。
这些文件保存在 `yii\mail\BaseMailer::fileTransportPath` 中,默认在 '@runtime/mail' 。
> 提示: 你可以保存这些信息到本地文件或者把它们发送出去,但不能同时两者都做。
邮件信息文件可以在一个普通的文本编辑器中打开,这样你就可以浏览实际的邮件标题,内容等。这种机制可以用来调试应用程序或运行单元测试。
邮件信息文件可以在一个普通的文本编辑器中打开,这样你就可以浏览实际的邮件标题,内容等。
这种机制可以用来调试应用程序或运行单元测试。
> 提示: 该邮件信息文件是会被 `\yii\mail\MessageInterface::toString()` 转成字符串保存的,它依赖于实际在应用程序中使用的邮件扩展。
> 提示: 该邮件信息文件是会被 `\yii\mail\MessageInterface::toString()` 转成字符串保存的,
它依赖于实际在应用程序中使用的邮件扩展。
创建自己的邮件解决方案
------------------------
为了创建你自己的邮件解决方案,你需要创建两个类,一个用于 “Mailer”,另一个用于 “Message”。
你可以使用 `yii\mail\BaseMailer``yii\mail\BaseMessage` 作为基类。这些类已经实现了基本的逻辑,这在本指南中有介绍。
然而,它们的使用不是必须的,它实现了 `yii\mail\MailerInterface``yii\mail\MessageInterface` 接口。
你可以使用 `yii\mail\BaseMailer``yii\mail\BaseMessage` 作为基类。
这些类已经实现了基本的逻辑,这在本指南中有介绍。
然而,它们的使用不是必须的,
它实现了 `yii\mail\MailerInterface``yii\mail\MessageInterface` 接口。
然后,你需要实现所有 abstract 方法来构建解决方案。

85
docs/guide-zh-CN/tutorial-performance-tuning.md

@ -1,7 +1,8 @@
性能优化
========
有许多因素影响你的 Web 应用程序的性能。有些是环境,有些是你的代码,而其他一些与 Yii 本身有关。
有许多因素影响你的 Web 应用程序的性能。有些是环境,
有些是你的代码,而其他一些与 Yii 本身有关。
在本节中,我们将列举这些因素并解释如何通过调整这些因素来提高应用程序的性能。
@ -10,34 +11,43 @@
一个好的 PHP 环境是非常重要的。为了得到最大的性能,
- 使用最新稳定版本的 PHP 。 PHP 的主要版本可能带来显著的性能提升。
- 启用字节码缓存 [Opcache](http://php.net/opcache)(PHP 5.5或更高版本)或 [APC](http://ru2.php.net/apc)
- 启用字节码缓存 [Opcache](http://php.net/opcache)(PHP 5.5或更高版本)
或 [APC](http://ru2.php.net/apc)
(PHP 5.4或更早版本)。字节码缓存省去了每次解析和加载 PHP 脚本所带来的开销。
- [Tune `realpath()` cache](https://github.com/samdark/realpath_cache_tuner).
## 禁用调试模式 <span id="disable-debug"></span>
对于运行在生产环境中的应用程序,你应该禁用调试模式。 Yii 中使用名为 `YII_DEBUG` 的常量来定义调试模式是否应被激活。
对于运行在生产环境中的应用程序,你应该禁用调试模式。
Yii 中使用名为 `YII_DEBUG` 的常量来定义调试模式是否应被激活。
若启用了调试模式,Yii 将需要额外的时间来产生和记录调试信息。
你可以将下面的代码行放在 [入口脚本](structure-entry-scripts.md) 的开头来禁用调试模式:
你可以将下面的代码行放在 [入口脚本](structure-entry-scripts.md)
的开头来禁用调试模式:
```php
defined('YII_DEBUG') or define('YII_DEBUG', false);
```
> 提示: `YII_DEBUG` 的默认值是 false 。所以如果你确信你不在你应用程序代码中别的地方更改其默认值,
你可以简单地删除上述行来禁用调试模式。
你可以简单地删除上述行来禁用调试模式。
## 使用缓存技术 <span id="using-caching"></span>
你可以使用各种缓存技术来提高应用程序的性能。例如,如果你的应用程序允许用户以 Markdown 格式输入文字,
你可以考虑缓存解析后的 Markdown 内容,避免每个请求都重复解析相同的 Markdown 文本。
请参阅 [缓存](caching-overview.md) 一节,了解 Yii 提供的缓存支持。
请参阅 [缓存](caching-overview.md) 一节,
了解 Yii 提供的缓存支持。
## 开启 Schema 缓存 <span id="enable-schema-caching"></span>
Schema 缓存是一个特殊的缓存功能,每当你使用[活动记录](db-active-record.md)时应该要开启这个缓存功能。如你所知,
活动记录能智能检测数据库对象的集合(例如列名、列类型、约束)而不需要手动地描述它们。活动记录是通过执行额外的SQL查询来获得该信息。
Schema 缓存是一个特殊的缓存功能,
每当你使用[活动记录](db-active-record.md)时应该要开启这个缓存功能。如你所知,
活动记录能智能检测数据库对象的集合(例如列名、列类型、约束)而不需要手动地描述它们。
活动记录是通过执行额外的SQL查询来获得该信息。
通过启用 Schema 缓存,检索到的数据库对象的集合将被保存在缓存中并在将来的请求中重用。
要开启 Schema 缓存,需要配置一个 `cache` [应用组件](structure-application-components.md)来储存 Schema 信息,
@ -71,14 +81,21 @@ return [
## 合并和压缩资源文件 <span id="optimizing-assets"></span>
一个复杂的网页往往包括许多 CSS 和 JavaScript 资源文件。为减少 HTTP 请求的数量和这些资源总下载的大小,应考虑将它们合并成一个单一的文件并压缩。
这可大大提高页面加载时间,且减少了服务器负载。想了解更多细节,请参阅[前端资源](structure-assets.md)部分。
一个复杂的网页往往包括许多 CSS 和 JavaScript 资源文件。
为减少 HTTP 请求的数量和这些资源总下载的大小,应考虑将它们合并成一个单一的文件并压缩。
这可大大提高页面加载时间,且减少了服务器负载。
想了解更多细节,请参阅[前端资源](structure-assets.md)部分。
## 优化会话存储 <span id="optimizing-session"></span>
默认会话数据被存储在文件中。这是好的对处于发展项目或小型项目。但是,当涉及要处理大量并发请求时,最好使用其他的会话存储方式,比如数据库。
Yii 支持各种会话存储。你可以通过在[配置](concept-configurations.md)中配置 `session` 组件来使用这些存储,如下代码:
默认会话数据被存储在文件中。
这是好的对处于发展项目或小型项目。
但是,当涉及要处理大量并发请求时,
最好使用其他的会话存储方式,比如数据库。
Yii 支持各种会话存储。
你可以通过在[配置](concept-configurations.md)中配置 `session` 组件来使用这些存储,
如下代码:
```php
return [
@ -98,7 +115,8 @@ return [
];
```
以上配置是使用数据库来存储会话数据。默认情况下,它会使用 `db` 应用组件连接数据库并将会话数据存储在 `session` 表。
以上配置是使用数据库来存储会话数据。默认情况下,
它会使用 `db` 应用组件连接数据库并将会话数据存储在 `session` 表。
因此,你必须创建如下的 `session` 表,
```sql
@ -109,28 +127,38 @@ CREATE TABLE session (
)
```
你也可以通过使用缓存来存储会话数据 [[yii\web\CacheSession]] 。理论上讲,你可以使用只要支持[数据缓存](caching-data.md#supported-cache-storage)。
你也可以通过使用缓存来存储会话数据 [[yii\web\CacheSession]] 。
理论上讲,你可以使用只要支持[数据缓存](caching-data.md#supported-cache-storage)。
但是请注意,某些缓存的存储当达到存储限制会清除缓存数据。出于这个原因,你应主要在不存在存储限制时才使用这些缓存存储。
如果你的服务器支持 [Redis](http://redis.io/),强烈建议你通过使用 [[yii\redis\Session]] 来作为会话存储。
If you have [Redis](http://redis.io/) on your server, it is highly recommended you use it as session storage by using
[[yii\redis\Session]].
## 优化数据库 <span id="optimizing-databases"></span>
执行数据库查询并从数据库中取出数据往往是一个 Web 应用程序主要的性能瓶颈。
尽管使用[数据缓存](caching-data.md)技术可以缓解性能下降,但它并不完全解决这个问题。
当数据库包含大量的数据且缓存数据是无效的,获取最新的数据可能是最耗性能的假如在没有适当地设计数据库和查询条件。
当数据库包含大量的数据且缓存数据是无效的,
获取最新的数据可能是最耗性能的假如在没有适当地设计数据库和查询条件。
一般来说,提高数据库查询的性能是创建索引。例如,如果你需要找一个用户表的“用户名”,你应该为“用户名”创建一个索引。
一般来说,提高数据库查询的性能是创建索引。例如,如果你需要找一个用户表的“用户名”,
你应该为“用户名”创建一个索引。
注意,尽管索引可以使选择查询的速度快得多,但它会减慢插入、更新和删除的查询。
对于复杂的数据库查询,建议你创建数据库视图来保存查询分析和准备的时间。
最后,在“SELECT”中使用“LIMIT”查询。这可以避免从数据库中取出大量数据。
最后,在“SELECT”中使用“LIMIT”查询。
这可以避免从数据库中取出大量数据。
## 使用普通数组 <span id="using-arrays"></span>
尽管[活动记录](db-active-record.md)对象使用起来非常方便,但当你需要从数据库中检索大量数据时它的效率不如使用普通的数组。
在这种情况下,你可以考虑在使用活动记录查询数据时调用 `asArray()` ,使检索到的数据被表示为数组而不是笨重的活动记录对象。例如,
尽管[活动记录](db-active-record.md)对象使用起来非常方便,
但当你需要从数据库中检索大量数据时它的效率不如使用普通的数组。
在这种情况下,你可以考虑在使用活动记录查询数据时调用 `asArray()`
使检索到的数据被表示为数组而不是笨重的活动记录对象。例如,
```php
class PostController extends Controller
@ -152,7 +180,8 @@ class PostController extends Controller
## 优化 Composer 自动加载 <span id="optimizing-autoloader"></span>
因为 Composer 自动加载用于加载大多数第三方类文件,应考虑对其进行优化,通过执行以下命令:
因为 Composer 自动加载用于加载大多数第三方类文件,
应考虑对其进行优化,通过执行以下命令:
```
composer dumpautoload -o
@ -161,12 +190,15 @@ composer dumpautoload -o
## 处理离线数据 <span id="processing-data-offline"></span>
当一个请求涉及到一些资源密集操作,你应该想办法在无需用户等待他们完成脱机模式时来执行这些操作。
当一个请求涉及到一些资源密集操作,
你应该想办法在无需用户等待他们完成脱机模式时来执行这些操作。
有两种方法可以离线数据处理:推和拉。
在拉中,只要有请求涉及到一些复杂的操作,你创建一个任务,并将其保存在永久存储,例如数据库。然后,使用一个单独的进程(如 cron 作业)拉任务,并进行处理。
这种方法很容易实现,但它也有一些缺点。例如,该任务过程中需要定期地从任务存储拉。如果拉频率太低,这些任务可以延迟处理;
在拉中,只要有请求涉及到一些复杂的操作,你创建一个任务,并将其保存在永久存储,例如数据库。然后,
使用一个单独的进程(如 cron 作业)拉任务,并进行处理。
这种方法很容易实现,但它也有一些缺点。
例如,该任务过程中需要定期地从任务存储拉。如果拉频率太低,这些任务可以延迟处理;
但是如果频率过高,将引起的高开销。
在推中,你可以使用消息队列(如 RabbitMQ ,ActiveMQ , Amazon SQS 等)来管理任务。
@ -179,5 +211,10 @@ composer dumpautoload -o
以下分析工具可能是有用的:
- [Yii debug toolbar and debugger](https://github.com/yiisoft/yii2-debug/blob/master/docs/guide/README.md)
- [XDebug profiler](http://xdebug.org/docs/profiler)
- [Blackfire](https://blackfire.io/)
- [XHProf](http://www.php.net/manual/en/book.xhprof.php)
- [XDebug profiler](http://xdebug.org/docs/profiler)
## Prepare application for scaling
When nothing helps you may try making your application scalabe. A good introduction is provided in [Configuring a Yii2 Application for an Autoscaling Stack](https://github.com/samdark/yii2-cookbook/blob/master/book/scaling.md). For further reading you may refer to [Web apps performance and scaling](http://thehighload.com/).

7
docs/guide-zh-CN/tutorial-shared-hosting.md

@ -22,7 +22,6 @@ www
对于我们的基础项目模板而言,其 webroot 名为 `web` 。 在你上传你的应用程序到 web 服务器上去之前,将你的本地 webroot 重命名以匹配服务器。 即: 从 `web` 改为 `www`, `public_html` 或者其他你的托管环境的 webroot 名称。
### FTP 根目录可写
如果你有 FTP 根目录的写权限,即,有 `config`, `logs``www` 的根目录,那么,如本地根目录相同的结构上传 `assets`, `commands` 等目录。
@ -49,7 +48,8 @@ RewriteRule . index.php
### 检查环境要求
为了运行 Yii ,你的 web 服务器必须匹配它的环境要求。最低的要求必须是 PHP 5.4。为了检查环境配置,将 `requirements.php` 从你的根目录拷贝到 webroot 目录,并通过浏览器输入 URL `http://example.com/requirements.php` 运行它。最后,检查结束后别忘了删除这个文件哦!
为了运行 Yii ,你的 web 服务器必须匹配它的环境要求。最低的要求必须是 PHP 5.4。为了检查环境配置,将 `requirements.php` 从你的根目录拷贝到 webroot 目录,
并通过浏览器输入 URL `http://example.com/requirements.php` 运行它。最后,检查结束后别忘了删除这个文件哦!
部署一个高级应用程序模板
---------------------------------
@ -75,7 +75,8 @@ frontend
### 分离 Session 和 Cookie
通常情况下,backend 和 frontend 运行在不同的域下,当我们将其都移到同一个域时, frontend 和 backend 将会共享相同的 cookie,这样会造成冲突。为了修复这个问题,如下调整 backend 的应用程序配置文件 `backend/config/main.php`
通常情况下,backend 和 frontend 运行在不同的域下,当我们将其都移到同一个域时, frontend 和 backend 将会共享相同的 cookie,这样会造成冲突。为了修复这个问题,
如下调整 backend 的应用程序配置文件 `backend/config/main.php`
```php
'components' => [

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

@ -3,11 +3,15 @@
> 注:本章节正在开发中。
虽然 [basic](https://github.com/yiisoft/yii2-app-basic) 和 [advanced](https://github.com/yiisoft/yii2-app-advanced) 项目模板能够满足你的大部分需求,但是,你仍有可能需要创建你自己的项目模板来开始项目。
虽然 [basic](https://github.com/yiisoft/yii2-app-basic) 和 [advanced](https://github.com/yiisoft/yii2-app-advanced)
项目模板能够满足你的大部分需求,但是,
你仍有可能需要创建你自己的项目模板来开始项目。
Yii 的项目模板是一个包含 `composer.json` 文件的仓库,并被注册为一个 Composer package。任何一个仓库都可以被标识为一个 Composer package,只要让其可以通过 `create-project` Composer 命令安装。
Yii 的项目模板是一个包含 `composer.json` 文件的仓库,并被注册为一个 Composer package。任何一个仓库都可以被标识为一个 Composer package,
只要让其可以通过 `create-project` Composer 命令安装。
由于完全从新创建一个你自己的模板工作量有点大,最好的方式是以一个内建模板为基础。这里,我们使用基础应用模板。
由于完全从新创建一个你自己的模板工作量有点大,最好的方式是以一个内建模板为基础。
这里,我们使用基础应用模板。
克隆基础模板
----------------------------------------
@ -18,16 +22,17 @@ Yii 的项目模板是一个包含 `composer.json` 文件的仓库,并被注
git clone git@github.com:yiisoft/yii2-app-basic.git
```
等待仓库下载到你的电脑。因为为调整到你自己的模板所产生的修改不会被 push 回,你可以删除下载下来的 `.git` 目录及其内容。
等待仓库下载到你的电脑。因为为调整到你自己的模板所产生的修改不会被 push 回,
你可以删除下载下来的 `.git` 目录及其内容。
修改文件
------------
Next, you'll want to modify the `composer.json` to reflect your template. Change the `name`, `description`, `keywords`, `homepage`, `license`, and `support` values
to describe your new template. Also adjust the `require`, `require-dev`, `suggest`, and other options to match your template's requirements.
接下来,你需要修改 `composer.json` 以配置你自己的模板。修改 `name`, `description`, `keywords`, `homepage`, `license`, 和 `support` 的值来描述你自己的模板。同样,调整 `require`, `require-dev`, `suggest` 和其他的参数来匹配你模板的环境需求。
接下来,你需要修改 `composer.json` 以配置你自己的模板。修改 `name`, `description`, `keywords`, `homepage`, `license`, 和 `support` 的值来描述你自己的模板。
同样,调整 `require`, `require-dev`, `suggest` 和其他的参数来匹配你模板的环境需求。
> 注意:在 `composer.json` 文件中,使用 `extra` 下的 `writeable` 参数来指定使用模板创建的应用程序后需要设置文件权限的文件列表。
> 注意:在 `composer.json` 文件中,使用 `extra` 下的 `writeable` 参数来指定使用模板创建的应用程序后
> 需要设置文件权限的文件列表。
接下来,真正的修改你的应用程序默认的目录结构和内容。最后,更新 README 文件以符合你的模板。
@ -36,7 +41,8 @@ to describe your new template. Also adjust the `require`, `require-dev`, `sugges
模板调整好后,通过其创建一个 Git 仓库并提交你的代码。如果你希望将你的应用程序模板开源,[Github]() 将是最好的托管服务。如果你不喜欢其他的人来跟你一起协作,你可以使用任意的 Git 仓库服务。
接下来,你需要为 Composer 注册你的 package。对于公有的模板,你可以将 package 注册到 [Packagist](https://packagist.org/)。对于私有的模板,注册 package 将会麻烦一点。参考 [Composer documentation](https://getcomposer.org/doc/05-repositories.md#hosting-your-own) 获取更多的指示。
接下来,你需要为 Composer 注册你的 package。对于公有的模板,你可以将 package 注册到 [Packagist](https://packagist.org/)。对于私有的模板,
注册 package 将会麻烦一点。参考 [Composer documentation](https://getcomposer.org/doc/05-repositories.md#hosting-your-own) 获取更多的指示。
使用模板
------

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

@ -1,9 +1,11 @@
使用模板引擎
======================
默认情况下,Yii 使用 PHP 作为其默认的模板引擎语言,但是,你可以配置 Yii 以扩展的方式支持其他的渲染引擎,比如 [Twig](http://twig.sensiolabs.org/) 或 [Smarty](http://www.smarty.net/)等。
默认情况下,Yii 使用 PHP 作为其默认的模板引擎语言,但是,你可以配置 Yii 以扩展的方式支持其他的渲染引擎,
比如 [Twig](http://twig.sensiolabs.org/) 或 [Smarty](http://www.smarty.net/)等。
组件 `view` 就是用于渲染视图的。你可以重新配置这个组件的行为以增加一个自定义的模板引擎。
组件 `view` 就是用于渲染视图的。
你可以重新配置这个组件的行为以增加一个自定义的模板引擎。
```php
[
@ -32,16 +34,16 @@
]
```
在上述的代码中, Smarty 和 Twig 都被配置以让视图文件使用。但是,为了让扩展安装到项目中,你同样需要修改你的 `composer.json` 文件,如下:
在上述的代码中, Smarty 和 Twig 都被配置以让视图文件使用。但是,为了让扩展安装到项目中,
你同样需要修改你的 `composer.json` 文件,如下:
```
"yiisoft/yii2-smarty": "*",
"yiisoft/yii2-twig": "*",
```
上述代码需要增加到 `composer.json``require` 节中。在做了上述修改,并保存后,你可以运行 `composer update --prefer-dist` 命令来安装扩展。
对于特定模板引擎的使用详细,请参考其文档:
- [Twig guide](https://github.com/yiisoft/yii2-twig/tree/master/docs/guide)
- [Smarty guide](https://github.com/yiisoft/yii2-smarty/tree/master/docs/guide)
- [Smarty guide](https://github.com/yiisoft/yii2-smarty/tree/master/docs/guide)

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

@ -1,23 +1,27 @@
引入第三方代码
=============================
有时,你可能会需要在 Yii 应用中使用第三方的代码。又或者是你想要在第三方系统中把 Yii 作为类库引用。在下面这个板块中,我们向你展示如何实现这些目标。
有时,你可能会需要在 Yii 应用中使用第三方的代码。又或者是你想要在第三方系统中把 Yii 作为类库引用。在下面这个板块中,
我们向你展示如何实现这些目标。
## 在 Yii 中使用第三方类库 <span id="using-libs-in-yii"></span>
----------------------------------
要想在 Yii 应用中使用第三方类库,你主要需要确保这些库中的类文件都可以被正常导入或可以被自动加载。
要想在 Yii 应用中使用第三方类库,
你主要需要确保这些库中的类文件都可以被正常导入或可以被自动加载。
### 使用 Composer 包 <span id="using-composer-packages"></span>
目前很多第三方的类库都以 [Composer](https://getcomposer.org/) 包的形式发布。你只需要以下两个简单的步骤即可安装他们:
目前很多第三方的类库都以 [Composer](https://getcomposer.org/) 包的形式发布。
你只需要以下两个简单的步骤即可安装他们:
1. 修改你应用的 `composer.json` 文件,并注明需要安装哪些 Composer 包。
2. 运行 `php composer.phar install` 安装这些包。
这些Composer 包内的类库,可以通过 Composer 的自动加载器实现自动加载。不过请确保你应用的
[入口脚本](structure-entry-scripts.md)包含以下几行用于加载 Composer 自动加载器的代码:
这些Composer 包内的类库,可以通过 Composer 的自动加载器实现自动加载。
不过请确保你应用的[入口脚本](structure-entry-scripts.md)包含以下
几行用于加载 Composer 自动加载器的代码:
```php
// install Composer autoloader (安装 Composer 自动加载器)
@ -27,16 +31,21 @@ require(__DIR__ . '/../vendor/autoload.php');
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
```
### 使用下载的类库 <span id="using-downloaded-libs"></span>
若你的类库并未发布为一个 Composer 包,你可以参考以下安装说明来安装它。在大多数情况下,你需要预先下载一个发布文件,并把它解压缩到
若你的类库并未发布为一个 Composer 包,你可以参考以下安装说明来安装它。
在大多数情况下,你需要预先下载一个发布文件,并把它解压缩到
`BasePath/vendor` 目录,这里的 `BasePath` 代指你应用程序自身的 [base path(主目录)](structure-applications.md#basePath)。
若该类库包含他自己的类自动加载器,你可以把它安装到你应用的[入口脚本](structure-entry-scripts.md)里。我们推荐你把它的安装代码置于
`Yii.php` 的导入之前,这样 Yii 的官方自动加载器可以拥有更高的优先级。
若该类库包含他自己的类自动加载器,你可以把它安装到你应用的[入口脚本](structure-entry-scripts.md)里。
我们推荐你把它的安装代码置于`Yii.php` 的导入之前,
这样 Yii 的官方自动加载器可以拥有更高的优先级。
若一个类库并没有提供自动加载器,但是他的类库命名方式符合 [PSR-4](http://www.php-fig.org/psr/psr-4/) 标准,你可以使用 Yii 官方的自动加载器来自动加载这些类。你只需给他们的每个根命名空间声明一下[根路径别名](concept-aliases.md#defining-aliases)。比如,假设说你已经在目录 `vendor/foo/bar` 里安装了一个类库,且这些类库的根命名空间为 `xyz`。你可以把以下代码放入你的应用配置文件中:
若一个类库并没有提供自动加载器,但是他的类库命名方式符合 [PSR-4](http://www.php-fig.org/psr/psr-4/) 标准,
你可以使用 Yii 官方的自动加载器来自动加载这些类。
你只需给他们的每个根命名空间声明一下[根路径别名](concept-aliases.md#defining-aliases)。
比如,假设说你已经在目录 `vendor/foo/bar` 里安装了一个类库,且这些类库的根命名空间为 `xyz`
你可以把以下代码放入你的应用配置文件中:
```php
[
@ -46,15 +55,15 @@ require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
]
```
若以上情形都不符合,最可能是这些类库需要依赖于 PHP 的 include_path 配置,来正确定位并导入类文件。只需参考它的安装说明简单地配置一下 PHP 导入路径即可。
若以上情形都不符合,最可能是这些类库需要依赖于 PHP 的 include_path 配置,
来正确定位并导入类文件。只需参考它的安装说明简单地配置一下 PHP 导入路径即可。
最悲催的情形是,该类库需要显式导入每个类文件,你可以使用以下方法按需导入相关类文件:
最悲催的情形是,该类库需要显式导入每个类文件,
你可以使用以下方法按需导入相关类文件:
* 找出该库内包含哪些类。
* 在应用的[入口脚本](structure-entry-scripts.md)里的 `Yii::$classMap` 数组中列出这些类,和他们各自对应的文件路径。
举例来说,
* 在应用的[入口脚本](structure-entry-scripts.md)里的 `Yii::$classMap` 数组中列出这些类,
和他们各自对应的文件路径。举例来说,
```php
Yii::$classMap['Class1'] = 'path/to/Class1.php';
Yii::$classMap['Class2'] = 'path/to/Class2.php';
@ -62,18 +71,45 @@ Yii::$classMap['Class2'] = 'path/to/Class2.php';
## 在第三方系统内使用 Yii <span id="using-yii-in-others"></span>
--------------------------------
因为 Yii 提供了很多牛逼的功能,有时,你可能会想要使用它们中的一些功能用来支持开发或完善某些第三方的系统,比如:WordPress,Joomla,或是用其他 PHP 框架开发的应用程序。举两个例子吧,你可能会想念方便的 [[yii\helpers\ArrayHelper]] 类,或在第三方系统中使用
[Active Record](db-active-record.md) 活动记录功能。要实现这些目标,你只需两个步骤:安装 Yii,启动 Yii。
因为 Yii 提供了很多牛逼的功能,有时,你可能会想要使用它们中的一些功能用来支持开发或完善某些第三方的系统,
比如:WordPress,Joomla,或是用其他 PHP 框架开发的应用程序。举两个例子吧,
你可能会想念方便的 [[yii\helpers\ArrayHelper]] 类,或在第三方系统中使用
[Active Record](db-active-record.md) 活动记录功能。要实现这些目标,
你只需两个步骤:安装 Yii,启动 Yii。
若这个第三方系统支持 Composer 管理他的依赖文件,你可以直接运行一下命令来安装 Yii:
若这个第三方系统支持 Composer 管理他的依赖文件,
你可以直接运行一下命令来安装 Yii:
composer global require "fxp/composer-asset-plugin:~1.1.1"
composer require yiisoft/yii2
composer install
The first command installs the [composer asset plugin](https://github.com/francoispluchino/composer-asset-plugin/)
which allows managing bower and npm package dependencies through Composer. Even if you only want to use the database
layer or other non-asset related features of Yii, this is required to install the Yii composer package.
If you want to use the [Asset publishing feature of Yii](structure-assets.md) you should also add the following configuration
to the `extra` section in your `composer.json`:
```json
{
...
"extra": {
"asset-installer-paths": {
"npm-asset-library": "vendor/npm",
"bower-asset-library": "vendor/bower"
}
}
}
```
php composer.phar require yiisoft/yii2-framework:*
php composer.phar install
```
不然的话,你可以[下载](http://www.yiiframework.com/download/) Yii 的发布包,并把它解压到对应系统的 `BasePath/vendor` 目录内。
See also the general [section about installing Yii](start-installation.md#installing-via-composer) for more information
on Composer and solution to possible issues popping up during the installation.
不然的话,你可以[下载](http://www.yiiframework.com/download/) Yii 的发布包,
并把它解压到对应系统的 `BasePath/vendor` 目录内。
之后,你需要修改该第三方应用的入口脚本,在开头位置添加 Yii 的引入代码:
@ -84,23 +120,28 @@ $yiiConfig = require(__DIR__ . '/../config/yii/web.php');
new yii\web\Application($yiiConfig); // 千万别在这调用 run() 方法。(笑)
```
如你所见,这段代码与典型的 Yii 应用的[入口脚本](structure-entry-scripts.md)非常相似。唯一的不同之处在于在 Yii 应用创建成功之后,并不会紧接着调用 `run()` 方法。因为,`run()` 方法的调用会接管 HTTP 请求的处理流程。(译注:换言之,这就不是第三方系统而是 Yii 系统了,URL 规则也会跟着换成 Yii 的规则了)
如你所见,这段代码与典型的 Yii 应用的[入口脚本](structure-entry-scripts.md)非常相似。
唯一的不同之处在于在 Yii 应用创建成功之后,并不会紧接着调用 `run()` 方法。
因为,`run()` 方法的调用会接管 HTTP 请求的处理流程。
(译注:换言之,这就不是第三方系统而是 Yii 系统了,URL 规则也会跟着换成 Yii 的规则了)
与 Yii 应用中一样,你可以依据运行该第三方系统的环境,针对性地配置 Yii 应用实例。比如,为了使用[活动记录](db-active-record.md)功能,你需要先用该第三方系统的 DB 连接信息,配置 Yii 的 `db` 应用组件。
与 Yii 应用中一样,你可以依据运行该第三方系统的环境,
针对性地配置 Yii 应用实例。比如,
为了使用[活动记录](db-active-record.md)功能,你需要先用该第三方系统的 DB 连接信息,配置 Yii 的 `db` 应用组件。
现在,你就可以使用 Yii 提供的绝大多数功能了。比如,创建 AR 类,并用它们来操作数据库。
现在,你就可以使用 Yii 提供的绝大多数功能了。
比如,创建 AR 类,并用它们来操作数据库。
## 配合使用 Yii 2 和 Yii 1 <span id="using-both-yii2-yii1"></span>
----------------------
如果你之前使用 Yii 1,大概你也有正在运行的 Yii 1 应用吧。不必用 Yii 2 重写整个应用,你也可以通过增添对哪些
如果你之前使用 Yii 1,大概你也有正在运行的 Yii 1 应用吧。
不必用 Yii 2 重写整个应用,你也可以通过增添对哪些
Yii 2 独占功能的支持来增强这个系统。下面我们就来详细描述一下具体的实现过程。
<<<<<<< .merge_file_a06364
> 注意:Yii 2 需要 PHP 5.4+ 的版本。你需要确保你的服务器以及现有应用都可以支持 PHP 5.4。
=======
> Note: Yii 2 需要 PHP 5.4+ 的版本。你需要确保你的服务器以及现有应用都可以支持 PHP 5.4。
>>>>>>> .merge_file_a06880
> 注意:Yii 2 需要 PHP 5.4+ 的版本。
> 你需要确保你的服务器以及现有应用都可以支持 PHP 5.4。
首先,参考前文板块中给出的方法,在已有的应用中安装 Yii 2。
@ -119,7 +160,8 @@ $yii1Config = require(__DIR__ . '/../config/yii1/main.php');
Yii::createWebApplication($yii1Config)->run();
```
因为,Yii 1 和 Yii 2 都包含有 `Yii` 这个类,你应该创建一个定制版的 Yii 来把他们组合起来。上面的代码里包含了的这个定制版的 `Yii` 类,可以用以下代码创建出来:
因为,Yii 1 和 Yii 2 都包含有 `Yii` 这个类,你应该创建一个定制版的 Yii 来把他们组合起来。
上面的代码里包含了的这个定制版的 `Yii` 类,可以用以下代码创建出来:
```php
$yii2path = '/path/to/yii2';
@ -130,13 +172,14 @@ require($yii1path . '/YiiBase.php'); // Yii 1.x
class Yii extends \yii\BaseYii
{
// 复制粘贴 YiiBase (1.x) 文件中的代码于此
// copy-paste the code from YiiBase (1.x) here
}
Yii::$classMap = include($yii2path . '/classes.php');
// 通过 Yii 1 注册 Yii2 的类自动加载器
// register Yii 2 autoloader via Yii 1
Yii::registerAutoloader(['Yii', 'autoload']);
// create the dependency injection container
Yii::$container = new yii\di\Container;
```
大功告成!此时,你可以在你代码的任意位置,调用 `Yii::$app` 以访问 Yii 2 的应用实例,而用

Loading…
Cancel
Save