Aleksandr
10 years ago
52 changed files with 2952 additions and 242 deletions
@ -0,0 +1,101 @@ |
|||||||
|
应用组件 |
||||||
|
====================== |
||||||
|
|
||||||
|
应用主体是[服务定位器](concept-service-locator.md),它部署一组提供各种不同功能的 *应用组件* 来处理请求。 |
||||||
|
例如,`urlManager`组件负责处理网页请求路由到对应的控制器。`db`组件提供数据库相关服务等等。 |
||||||
|
|
||||||
|
在同一个应用中,每个应用组件都有一个独一无二的 ID 用来区分其他应用组件,你可以通过如下表达式访问应用组件。 |
||||||
|
|
||||||
|
```php |
||||||
|
\Yii::$app->componentID |
||||||
|
``` |
||||||
|
|
||||||
|
例如,可以使用 `\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]] 属性 . |
||||||
|
例如: |
||||||
|
|
||||||
|
```php |
||||||
|
[ |
||||||
|
'components' => [ |
||||||
|
// 使用类名注册 "cache" 组件 |
||||||
|
'cache' => 'yii\caching\ApcCache', |
||||||
|
|
||||||
|
// 使用配置数组注册 "db" 组件 |
||||||
|
'db' => [ |
||||||
|
'class' => 'yii\db\Connection', |
||||||
|
'dsn' => 'mysql:host=localhost;dbname=demo', |
||||||
|
'username' => 'root', |
||||||
|
'password' => '', |
||||||
|
], |
||||||
|
|
||||||
|
// 使用函数注册"search" 组件 |
||||||
|
'search' => function () { |
||||||
|
return new app\components\SolrService; |
||||||
|
}, |
||||||
|
], |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
> 补充:请谨慎注册太多应用组件,应用组件就像全局变量,使用太多可能加大测试和维护的难度。 |
||||||
|
一般情况下可以在需要时再创建本地组件。 |
||||||
|
|
||||||
|
|
||||||
|
## 引导启动组件 <a name="bootstrapping-components"></a> |
||||||
|
|
||||||
|
上面提到一个应用组件只会在第一次访问时实例化,如果处理请求过程没有访问的话就不实例化。 |
||||||
|
有时你想在每个请求处理过程都实例化某个组件即便它不会被访问, |
||||||
|
可以将该组件ID加入到应用主体的 [[yii\base\Application::bootstrap|bootstrap]] 属性中。 |
||||||
|
|
||||||
|
例如, 如下的应用主体配置保证了 `log` 组件一直被加载。 |
||||||
|
|
||||||
|
```php |
||||||
|
[ |
||||||
|
'bootstrap' => [ |
||||||
|
// 将 log 组件 ID 加入引导让它始终载入 |
||||||
|
'log', |
||||||
|
], |
||||||
|
'components' => [ |
||||||
|
'log' => [ |
||||||
|
// "log" 组件的配置 |
||||||
|
], |
||||||
|
], |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
## 核心应用组件 <a name="core-application-components"></a> |
||||||
|
|
||||||
|
Yii 定义了一组固定ID和默认配置的 *核心* 组件,例如 [[yii\web\Application::request|request]] 组件 |
||||||
|
用来收集用户请求并解析 [路由](runtime-routing.md); |
||||||
|
[[yii\base\Application::db|db]] 代表一个可以执行数据库操作的数据库连接。 |
||||||
|
通过这些组件,Yii应用主体能处理用户请求。 |
||||||
|
|
||||||
|
下面是预定义的核心应用组件列表,可以和普通应用组件一样配置和自定义它们。 |
||||||
|
当你配置一个核心组件,不指定它的类名的话就会使用Yii默认指定的类。 |
||||||
|
|
||||||
|
* [[yii\web\AssetManager|assetManager]]: 管理资源包和资源发布,详情请参考 [管理资源](output-assets.md) 一节。 |
||||||
|
* [[yii\db\Connection|db]]: 代表一个可以执行数据库操作的数据库连接, |
||||||
|
注意配置该组件时必须指定组件类名和其他相关组件属性,如[[yii\db\Connection::dsn]]。 |
||||||
|
详情请参考 [数据访问对象](db-dao.md) 一节。 |
||||||
|
* [[yii\base\Application::errorHandler|errorHandler]]: 处理 PHP 错误和异常, |
||||||
|
详情请参考 [错误处理](tutorial-handling-errors.md) 一节。 |
||||||
|
* [[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\base\Application::response|response]]: 代表发送给用户的响应, |
||||||
|
详情请参考 [响应](runtime-responses.md) 一节。 |
||||||
|
* [[yii\base\Application::request|request]]: 代表从终端用户处接收到的请求, |
||||||
|
详情请参考 [请求](runtime-requests.md) 一节。 |
||||||
|
* [[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]] 网页应用中可用, |
||||||
|
详情请参考 [认证](security-authentication.md) 一节。 |
||||||
|
* [[yii\web\View|view]]: 支持渲染视图,详情请参考 [Views](structure-views.md) 一节。 |
@ -0,0 +1,524 @@ |
|||||||
|
应用主体 |
||||||
|
============ |
||||||
|
|
||||||
|
应用主体是管理 Yii 应用系统整体结构和生命周期的对象。 |
||||||
|
每个Yii应用系统只能包含一个应用主体,应用主体在 [入口脚本](structure-entry-scripts.md) 中创建并能通过表达式 `\Yii::$app` 全局范围内访问。 |
||||||
|
|
||||||
|
> 补充: 当我们说"一个应用",它可能是一个应用主体对象,也可能是一个应用系统,是根据上下文来决定[译:中文为避免歧义,Application翻译为应用主体]。 |
||||||
|
|
||||||
|
Yii有两种应用主体: [[yii\web\Application|网页应用主体]] and |
||||||
|
[[yii\console\Application|控制台应用主体]], 如名称所示,前者主要处理网页请求,后者处理控制台请求。 |
||||||
|
|
||||||
|
|
||||||
|
## 应用主体配置 <a name="application-configurations"></a> |
||||||
|
|
||||||
|
如下所示,当 [入口脚本](structure-entry-scripts.md) 创建了一个应用主体,它会加载一个 [配置](concept-configurations.md) 文件并传给应用主体。 |
||||||
|
|
||||||
|
```php |
||||||
|
require(__DIR__ . '/../vendor/autoload.php'); |
||||||
|
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php'); |
||||||
|
|
||||||
|
// 加载应用主体配置 |
||||||
|
$config = require(__DIR__ . '/../config/web.php'); |
||||||
|
|
||||||
|
// 实例化应用主体、配置应用主体 |
||||||
|
(new yii\web\Application($config))->run(); |
||||||
|
``` |
||||||
|
|
||||||
|
类似其他 [配置](concept-configurations.md) 文件, 应用主体配置文件标明如何设置应用对象初始属性。 |
||||||
|
由于应用主体配置比较复杂,一般保存在多个类似如上web.php的 [配置文件](concept-configurations.md#configuration-files) 当中。 |
||||||
|
|
||||||
|
## 应用主体属性 <a name="application-properties"></a> |
||||||
|
|
||||||
|
应用主体配置文件中有许多重要的属性要配置,这些属性指定应用主体的运行环境。 |
||||||
|
比如,应用主体需要知道如何加载 [控制器](structure-controllers.md) ,临时文件保存到哪儿等等。 |
||||||
|
以下我们简述这些属性。 |
||||||
|
|
||||||
|
### 必要属性 <a name="required-properties"></a> |
||||||
|
|
||||||
|
在一个应用中,至少要配置2个属性: [[yii\base\Application::id|id]] 和 [[yii\base\Application::basePath|basePath]]。 |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::id|id]] <a name="id"></a> |
||||||
|
|
||||||
|
[[yii\base\Application::id|id]] 属性用来区分其他应用的唯一标识ID。主要给程序使用。 |
||||||
|
为了方便协作,最好使用数字作为应用主体ID,但不强制要求为数字。 |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::basePath|basePath]] <a name="basePath"></a> |
||||||
|
|
||||||
|
|
||||||
|
[[yii\base\Application::basePath|basePath]] 指定该应用的根目录。根目录包含应用系统所有受保护的源代码。 |
||||||
|
在根目录下可以看到对应MVC设计模式的`models`, `views`, `controllers`等子目录。 |
||||||
|
|
||||||
|
可以使用路径或 [路径别名](concept-aliases.md) 来在配置 [[yii\base\Application::basePath|basePath]] 属性。 |
||||||
|
两种格式所对应的目录都必须存在,否则系统会抛出一个异常。 系统会使用 `realpath()` 函数规范化配置的路径. |
||||||
|
|
||||||
|
[[yii\base\Application::basePath|basePath]] 属性经常用于派生一些其他重要路径(如runtime路径),因此,系统预定义 `@app` 代表这个路径。 |
||||||
|
派生路径可以通过这个别名组成(如`@app/runtime`代表runtime的路径)。 |
||||||
|
|
||||||
|
|
||||||
|
### 重要属性 <a name="important-properties"></a> |
||||||
|
|
||||||
|
本小节所描述的属性通常需要设置,因为不用的应用属性不同。 |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::aliases|aliases]] <a name="aliases"></a> |
||||||
|
|
||||||
|
该属性允许你用一个数组定义多个 [别名](concept-aliases.md)。数组的key为别名名称,值为对应的路径。例如: |
||||||
|
|
||||||
|
```php |
||||||
|
[ |
||||||
|
'aliases' => [ |
||||||
|
'@name1' => 'path/to/path1', |
||||||
|
'@name2' => 'path/to/path2', |
||||||
|
], |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
使用这个属性来定义别名,代替 [[Yii::setAlias()]] 方法来设置。 |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::bootstrap|bootstrap]] <a name="bootstrap"></a> |
||||||
|
|
||||||
|
这个属性很实用,它允许你用数组指定启动阶段[[yii\base\Application::bootstrap()|bootstrapping process]]需要运行的组件。 |
||||||
|
比如,如果你希望一个 [模块](structure-modules.md) 自定义 [URL 规则](runtime-url-handling.md),你可以将模块ID加入到bootstrap数组中。 |
||||||
|
|
||||||
|
属性中的每个组件需要指定以下一项: |
||||||
|
|
||||||
|
- 应用 [组件](#components) ID. |
||||||
|
- [模块](#modules) ID. |
||||||
|
- 类名. |
||||||
|
- 配置数组. |
||||||
|
- 创建并返回一个组件的无名称函数. |
||||||
|
|
||||||
|
例如: |
||||||
|
|
||||||
|
```php |
||||||
|
[ |
||||||
|
'bootstrap' => [ |
||||||
|
// 应用组件ID或模块ID |
||||||
|
'demo', |
||||||
|
|
||||||
|
// 类名 |
||||||
|
'app\components\Profiler', |
||||||
|
|
||||||
|
// 配置数组 |
||||||
|
[ |
||||||
|
'class' => 'app\components\Profiler', |
||||||
|
'level' => 3, |
||||||
|
], |
||||||
|
|
||||||
|
// 无名称函数 |
||||||
|
function () { |
||||||
|
return new app\components\Profiler(); |
||||||
|
} |
||||||
|
], |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
> 补充: 如果模块ID和应用组件ID同名,优先使用应用组件ID,如果你想用模块ID,可以使用如下无名称函数返回模块ID。 |
||||||
|
>```php |
||||||
|
[ |
||||||
|
function () { |
||||||
|
return Yii::$app->getModule('user'); |
||||||
|
}, |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
在启动阶段,每个组件都会实例化。如果组件类实现接口 [[yii\base\BootstrapInterface]],也会调用 [[yii\base\BootstrapInterface::bootstrap()|bootstrap()]] 方法。 |
||||||
|
|
||||||
|
举一个实际的例子,[Basic Application Template](start-installation.md) 应用主体配置中, |
||||||
|
开发环境下会在启动阶段运行 `debug` 和 `gii` 模块。 |
||||||
|
|
||||||
|
```php |
||||||
|
if (YII_ENV_DEV) { |
||||||
|
// configuration adjustments for 'dev' environment |
||||||
|
$config['bootstrap'][] = 'debug'; |
||||||
|
$config['modules']['debug'] = 'yii\debug\Module'; |
||||||
|
|
||||||
|
$config['bootstrap'][] = 'gii'; |
||||||
|
$config['modules']['gii'] = 'yii\gii\Module'; |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
> 注: 启动太多的组件会降低系统性能,因为每次请求都需要重新运行启动组件,因此谨慎配置启动组件。 |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\web\Application::catchAll|catchAll]] <a name="catchAll"></a> |
||||||
|
|
||||||
|
该属性仅 [[yii\web\Application|Web applications]] 网页应用支持。 |
||||||
|
它指定一个要处理所有用户请求的 [控制器方法](structure-controllers.md),通常在维护模式下使用,同一个方法处理所有用户请求。 |
||||||
|
|
||||||
|
该配置为一个数组,第一项指定动作的路由,剩下的数组项(key-value 成对)指定传递给动作的参数,例如: |
||||||
|
|
||||||
|
```php |
||||||
|
[ |
||||||
|
'catchAll' => [ |
||||||
|
'offline/notice', |
||||||
|
'param1' => 'value1', |
||||||
|
'param2' => 'value2', |
||||||
|
], |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::components|components]] <a name="components"></a> |
||||||
|
|
||||||
|
这是最重要的属性,它允许你注册多个在其他地方使用的[应用组件](#structure-application-components.md). 例如 |
||||||
|
|
||||||
|
```php |
||||||
|
[ |
||||||
|
'components' => [ |
||||||
|
'cache' => [ |
||||||
|
'class' => 'yii\caching\FileCache', |
||||||
|
], |
||||||
|
'user' => [ |
||||||
|
'identityClass' => 'app\models\User', |
||||||
|
'enableAutoLogin' => true, |
||||||
|
], |
||||||
|
], |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
每一个应用组件指定一个key-value对的数组,key代表组件ID,value代表组件类名或 [配置](concept-configurations.md)。 |
||||||
|
|
||||||
|
在应用中可以任意注册组件,并可以通过表达式 `\Yii::$app->ComponentID` 全局访问。 |
||||||
|
|
||||||
|
详情请阅读 [应用组件](structure-application-components.md) 一节. |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::controllerMap|controllerMap]] <a name="controllerMap"></a> |
||||||
|
|
||||||
|
该属性允许你指定一个控制器ID到任意控制器类。Yii遵循一个默认的 [规则](#controllerNamespace)指定控制器ID到任意控制器类(如`post`对应`app\controllers\PostController`)。 |
||||||
|
通过配置这个属性,可以打破这个默认规则,在下面的例子中,`account`对应到`app\controllers\UserController`, |
||||||
|
`article` 对应到 `app\controllers\PostController`。 |
||||||
|
|
||||||
|
```php |
||||||
|
[ |
||||||
|
'controllerMap' => [ |
||||||
|
[ |
||||||
|
'account' => 'app\controllers\UserController', |
||||||
|
'article' => [ |
||||||
|
'class' => 'app\controllers\PostController', |
||||||
|
'enableCsrfValidation' => false, |
||||||
|
], |
||||||
|
], |
||||||
|
], |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
数组的键代表控制器ID,数组的值代表对应的类名。 |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::controllerNamespace|controllerNamespace]] <a name="controllerNamespace"></a> |
||||||
|
|
||||||
|
该属性指定控制器类默认的命名空间,默认为`app\controllers`。比如控制器ID为 `post` 默认对应 `PostController` (不带命名空间), |
||||||
|
类全名为 `app\controllers\PostController`。 |
||||||
|
|
||||||
|
控制器类文件可能放在这个命名空间对应目录的子目录下, |
||||||
|
例如,控制器ID `admin/post` 对应的控制器类全名为 `app\controllers\admin\PostController`。 |
||||||
|
|
||||||
|
控制器类全面能被 [自动加载](concept-autoloading.md),这点是非常重要的,控制器类的实际命名空间对应这个属性, |
||||||
|
否则,访问时你会收到"Page Not Found"[译:页面找不到]。 |
||||||
|
|
||||||
|
如果你想打破上述的规则,可以配置 [controllerMap](#controllerMap) 属性。 |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::language|language]] <a name="language"></a> |
||||||
|
|
||||||
|
该属性指定应用展示给终端用户的语言,默认为 `en` 标识英文。如果需要之前其他语言可以配置该属性。 |
||||||
|
|
||||||
|
该属性影响各种 [国际化](tutorial-i18n.md) ,包括信息翻译、日期格式、数字格式等。 |
||||||
|
例如 [[yii\jui\DatePicker]] 小部件会根据该属性展示对应语言的日历以及日期格式。 |
||||||
|
|
||||||
|
推荐遵循 [IETF language tag](http://en.wikipedia.org/wiki/IETF_language_tag) 来设置语言,例如 `en` 代表英文, `en-US` 代表英文(美国). |
||||||
|
|
||||||
|
该属性的更多信息可参考 [国际化](tutorial-i18n.md) 一节. |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::modules|modules]] <a name="modules"></a> |
||||||
|
|
||||||
|
该属性指定应用所包含的 [模块](structure-modules.md)。 |
||||||
|
|
||||||
|
该属性使用数组包含多个模块类 [配置](concept-configurations.md),数组的键为模块ID,例: |
||||||
|
|
||||||
|
```php |
||||||
|
[ |
||||||
|
'modules' => [ |
||||||
|
// "booking" 模块以及对应的类 |
||||||
|
'booking' => 'app\modules\booking\BookingModule', |
||||||
|
|
||||||
|
// "comment" 模块以及对应的配置数组 |
||||||
|
'comment' => [ |
||||||
|
'class' => 'app\modules\comment\CommentModule', |
||||||
|
'db' => 'db', |
||||||
|
], |
||||||
|
], |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
更多详情请参考 [模块](structure-modules.md) 一节。 |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::name|name]] <a name="name"></a> |
||||||
|
|
||||||
|
该属性指定你可能想展示给终端用户的应用名称,不同于需要唯一性的 [[yii\base\Application::id|id]] 属性, |
||||||
|
该属性可以不唯一,该属性用于显示应用的用途。 |
||||||
|
|
||||||
|
如果其他地方的代码没有用到,可以不配置该属性。 |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::params|params]] <a name="params"></a> |
||||||
|
|
||||||
|
该属性为一个数组,指定可以全局访问的参数,代替程序中硬编码的数字和字符,应用中的参数定义到一个单独的文件并随时可以访问是一个好习惯。 |
||||||
|
例如用参数定义缩略图的长宽如下: |
||||||
|
|
||||||
|
```php |
||||||
|
[ |
||||||
|
'params' => [ |
||||||
|
'thumbnail.size' => [128, 128], |
||||||
|
], |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
然后简单的使用如下代码即可获取到你需要的长宽参数: |
||||||
|
|
||||||
|
```php |
||||||
|
$size = \Yii::$app->params['thumbnail.size']; |
||||||
|
$width = \Yii::$app->params['thumbnail.size'][0]; |
||||||
|
``` |
||||||
|
|
||||||
|
以后想修改缩略图长宽,只需要修改该参数而不需要相关的代码。 |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::sourceLanguage|sourceLanguage]] <a name="sourceLanguage"></a> |
||||||
|
|
||||||
|
该属性指定应用代码的语言,默认为 `'en-US'` 标识英文(美国),如果应用不是英文请修改该属性。 |
||||||
|
|
||||||
|
和 [语言](#language) 属性类似,配置该属性需遵循 [IETF language tag](http://en.wikipedia.org/wiki/IETF_language_tag). |
||||||
|
例如 `en` 代表英文, `en-US` 代表英文(美国)。 |
||||||
|
|
||||||
|
该属性的更多信息可参考 [国际化](tutorial-i18n.md) 一节. |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::timeZone|timeZone]] <a name="timeZone"></a> |
||||||
|
|
||||||
|
该属性提供一种方式修改PHP运行环境中的默认时区,配置该属性本质上就是调用PHP函数 |
||||||
|
[date_default_timezone_set()](http://php.net/manual/en/function.date-default-timezone-set.php),例如: |
||||||
|
|
||||||
|
```php |
||||||
|
[ |
||||||
|
'timeZone' => 'America/Los_Angeles', |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::version|version]] <a name="version"></a> |
||||||
|
|
||||||
|
该属性指定应用的版本,默认为`'1.0'`,其他代码不使用的话可以不配置。 |
||||||
|
|
||||||
|
|
||||||
|
### 实用属性 <a name="useful-properties"></a> |
||||||
|
|
||||||
|
本小节描述的属性不经常设置,通常使用系统默认值。如果你想改变默认值,可以配置这些属性。 |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::charset|charset]] <a name="charset"></a> |
||||||
|
|
||||||
|
该属性指定应用使用的字符集,默认值为 `'UTF-8'`,绝大部分应用都在使用,除非已有的系统大量使用非unicode数据才需要更改该属性。 |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::defaultRoute|defaultRoute]] <a name="defaultRoute"></a> |
||||||
|
|
||||||
|
该属性指定未配置的请求的响应 [路由](runtime-routing.md) 规则,路由规则可能包含模块ID,控制器ID,动作ID。 |
||||||
|
例如`help`, `post/create`, `admin/post/create`,如果动作ID没有指定,会使用[[yii\base\Controller::defaultAction]]中指定的默认值。 |
||||||
|
|
||||||
|
对于 [[yii\web\Application|Web applications]] 网页应用,默认值为 `'site'` 对应 `SiteController` 控制器,并使用默认的动作。 |
||||||
|
因此你不带路由的访问应用,默认会显示 `app\controllers\SiteController::actionIndex()` 的结果。 |
||||||
|
|
||||||
|
对于 [[yii\console\Application|console applications]] 控制台应用, |
||||||
|
默认值为 `'help'` 对应 [[yii\console\controllers\HelpController::actionIndex()]]。 |
||||||
|
因此,如果执行的命令不带参数,默认会显示帮助信息。 |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::extensions|extensions]] <a name="extensions"></a> |
||||||
|
|
||||||
|
该属性用数组列表指定应用安装和使用的 [扩展](structure-extensions.md),默认使用`@vendor/yiisoft/extensions.php`文件返回的数组。 |
||||||
|
当你使用 [Composer](http://getcomposer.org) 安装扩展,`extensions.php` 会被自动生成和维护更新。 |
||||||
|
所以大多数情况下,不需要配置该属性。 |
||||||
|
|
||||||
|
特殊情况下你想自己手动维护扩展,可以参照如下配置该属性: |
||||||
|
|
||||||
|
```php |
||||||
|
[ |
||||||
|
'extensions' => [ |
||||||
|
[ |
||||||
|
'name' => 'extension name', |
||||||
|
'version' => 'version number', |
||||||
|
'bootstrap' => 'BootstrapClassName', // 可选配,可为配置数组 |
||||||
|
'alias' => [ // 可选配 |
||||||
|
'@alias1' => 'to/path1', |
||||||
|
'@alias2' => 'to/path2', |
||||||
|
], |
||||||
|
], |
||||||
|
|
||||||
|
// ... 更多像上面的扩展 ... |
||||||
|
|
||||||
|
], |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
如上所示,该属性包含一个扩展定义数组,每个扩展为一个包含 `name` 和 `version` 项的数组。 |
||||||
|
如果扩展要在 [引导启动](runtime-bootstrapping.md) 阶段运行,需要配置 `bootstrap`以及对应的引导启动类名或 [configuration](concept-configurations.md) 数组。 |
||||||
|
扩展也可以定义 [别名](concept-aliases.md) |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::layout|layout]] <a name="layout"></a> |
||||||
|
|
||||||
|
该属性指定渲染 [视图](structure-views.md) 默认使用的布局名字,默认值为 `'main'` 对应[布局路径](#layoutPath)下的 `main.php` 文件, |
||||||
|
如果 [布局路径](#layoutPath) 和 [视图路径](#viewPath) 都是默认值,默认布局文件可以使用路径别名`@app/views/layouts/main.php` |
||||||
|
|
||||||
|
如果不想设置默认布局文件,可以设置该属性为 `false`,这种做法比较罕见。 |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::layoutPath|layoutPath]] <a name="layoutPath"></a> |
||||||
|
|
||||||
|
该属性指定查找布局文件的路径,默认值为 [视图路径](#viewPath) 下的 `layouts` 子目录。 |
||||||
|
如果 [视图路径](#viewPath) 使用默认值,默认的布局路径别名为`@app/views/layouts`。 |
||||||
|
|
||||||
|
该属性需要配置成一个目录或 路径 [别名](concept-aliases.md)。 |
||||||
|
You may configure it as a directory or a path [alias](concept-aliases.md). |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::runtimePath|runtimePath]] <a name="runtimePath"></a> |
||||||
|
|
||||||
|
该属性指定临时文件如日志文件、缓存文件等保存路径,默认值为带别名的 `@app/runtime`。 |
||||||
|
|
||||||
|
可以配置该属性为一个目录或者路径 [别名](concept-aliases.md),注意应用运行时有对该路径的写入权限, |
||||||
|
以及终端用户不能访问改路径因为临时文件可能包含一些敏感信息。 |
||||||
|
|
||||||
|
为了简化访问该路径,Yii预定义别名 `@runtime` 代表该路径。 |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::viewPath|viewPath]] <a name="viewPath"></a> |
||||||
|
|
||||||
|
该路径指定视图文件的根目录,默认值为带别名的 `@app/views`,可以配置它为一个目录或者路径 [别名](concept-aliases.md). |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\base\Application::vendorPath|vendorPath]] <a name="vendorPath"></a> |
||||||
|
|
||||||
|
该属性指定 [Composer](http://getcomposer.org) 管理的供应商路径,该路径包含应用使用的包括Yii框架在内的所有第三方库。 |
||||||
|
默认值为带别名的 `@app/vendor` 。 |
||||||
|
|
||||||
|
可以配置它为一个目录或者路径 [别名](concept-aliases.md),当你修改时,务必修改对应的 Composer 配置。 |
||||||
|
|
||||||
|
为了简化访问该路径,Yii预定义别名 `@vendor` 代表该路径。 |
||||||
|
|
||||||
|
|
||||||
|
#### [[yii\console\Application::enableCoreCommands|enableCoreCommands]] <a name="enableCoreCommands"></a> |
||||||
|
|
||||||
|
该属性仅 [[yii\console\Application|console applications]] 控制台应用支持, 用来指定是否启用Yii中的核心命令,默认值为 `true`。 |
||||||
|
|
||||||
|
|
||||||
|
## 应用事件 <a name="application-events"></a> |
||||||
|
|
||||||
|
应用在处理请求过程中会触发事件,可以在配置文件配置事件处理代码,如下所示: |
||||||
|
|
||||||
|
```php |
||||||
|
[ |
||||||
|
'on beforeRequest' => function ($event) { |
||||||
|
// ... |
||||||
|
}, |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
`on eventName` 语法的用法在 [Configurations](concept-configurations.md#configuration-format) 一节有详细描述. |
||||||
|
|
||||||
|
另外,在应用主体实例化后,你可以在[引导启动](runtime-bootstrapping.md) 阶段附加事件处理代码,例如: |
||||||
|
|
||||||
|
```php |
||||||
|
\Yii::$app->on(\yii\base\Application::EVENT_BEFORE_REQUEST, function ($event) { |
||||||
|
// ... |
||||||
|
}); |
||||||
|
``` |
||||||
|
|
||||||
|
### [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_BEFORE_REQUEST]] <a name="beforeRequest"></a> |
||||||
|
|
||||||
|
该事件在应用处理请求*before*之前,实际的事件名为 `beforeRequest`。 |
||||||
|
|
||||||
|
在事件触发前,应用主体已经实例化并配置好了,所以通过事件机制将你的代码嵌入到请求处理过程中非常不错。 |
||||||
|
例如在事件处理中根据某些参数动态设置[[yii\base\Application::language]]语言属性。 |
||||||
|
|
||||||
|
|
||||||
|
### [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_AFTER_REQUEST]] <a name="afterRequest"></a> |
||||||
|
|
||||||
|
该事件在应用处理请求*after*之后但在返回响应*before*之前触发,实际的事件名为`afterRequest`。 |
||||||
|
|
||||||
|
该事件触发时,请求已经被处理完,可以做一些请求后处理或自定义响应。 |
||||||
|
|
||||||
|
注意 [[yii\web\Response|response]] 组件在发送响应给终端用户时也会触发一些事件,这些事件都在本事件*after*之后触发。 |
||||||
|
|
||||||
|
|
||||||
|
### [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_BEFORE_ACTION]] <a name="beforeAction"></a> |
||||||
|
|
||||||
|
该事件在每个 [控制器动作](structure-controllers.md) 运行*before*之前会被触发,实际的事件名为 `beforeAction`. |
||||||
|
|
||||||
|
事件的参数为一个 [[yii\base\ActionEvent]] 实例, |
||||||
|
事件处理中可以设置[[yii\base\ActionEvent::isValid]] 为 `false` 停止运行后续动作,例如: |
||||||
|
|
||||||
|
```php |
||||||
|
[ |
||||||
|
'on beforeAction' => function ($event) { |
||||||
|
if (some condition) { |
||||||
|
$event->isValid = false; |
||||||
|
} else { |
||||||
|
} |
||||||
|
}, |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
注意 [模块](structure-modules.md) 和 [控制器](structure-controllers.md) 都会触发 `beforeAction` 事件。 |
||||||
|
应用主体对象首先触发该事件,然后模块触发(如果存在模块),最后控制器触发。 |
||||||
|
任何一个事件处理中设置 [[yii\base\ActionEvent::isValid]] 设置为 `false` 会停止触发后面的事件。 |
||||||
|
|
||||||
|
|
||||||
|
### [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_AFTER_ACTION]] <a name="afterAction"></a> |
||||||
|
|
||||||
|
该事件在每个 [控制器动作](structure-controllers.md) 运行*after*之后会被触发,实际的事件名为 `afterAction`. |
||||||
|
|
||||||
|
该事件的参数为 [[yii\base\ActionEvent]] 实例,通过[[yii\base\ActionEvent::result]]属性, |
||||||
|
事件处理可以访问和修改动作的结果。例如: |
||||||
|
|
||||||
|
```php |
||||||
|
[ |
||||||
|
'on afterAction' => function ($event) { |
||||||
|
if (some condition) { |
||||||
|
// 修改 $event->result |
||||||
|
} else { |
||||||
|
} |
||||||
|
}, |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
注意 [模块](structure-modules.md) 和 [控制器](structure-controllers.md) 都会触发 `afterAction` 事件。 |
||||||
|
这些对象的触发顺序和 `beforeAction` 相反,也就是说,控制器最先触发,然后是模块(如果有模块),最后为应用主体。 |
||||||
|
|
||||||
|
|
||||||
|
## 应用主体生命周期 <a name="application-lifecycle"></a> |
||||||
|
|
||||||
|
当运行 [入口脚本](structure-entry-scripts.md) 处理请求时,应用主体会经历以下生命周期: |
||||||
|
|
||||||
|
1. 入口脚本加载应用主体配置数组。 |
||||||
|
2. 入口脚本创建一个应用主体实例: |
||||||
|
* 调用 [[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()]] 运行引导启动组件. |
||||||
|
3. 入口脚本调用 [[yii\base\Application::run()]] 运行应用主体: |
||||||
|
* 触发 [[yii\base\Application::EVENT_BEFORE_REQUEST|EVENT_BEFORE_REQUEST]] 事件。 |
||||||
|
* 处理请求:解析请求 [路由](runtime-routing.md) 和相关参数;创建路由指定的模块、控制器和动作对应的类,并运行动作。 |
||||||
|
* 触发 [[yii\base\Application::EVENT_AFTER_REQUEST|EVENT_AFTER_REQUEST]] 事件。 |
||||||
|
* 发送响应到终端用户. |
||||||
|
4. 入口脚本接收应用主体传来的退出状态并完成请求的处理。 |
@ -0,0 +1,449 @@ |
|||||||
|
Controllers |
||||||
|
=========== |
||||||
|
|
||||||
|
Controllers are part of the [MVC](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) architecture. |
||||||
|
They are objects of classes extending from [[yii\base\Controller]] and are responsible for processing requests and |
||||||
|
generating responses. In particular, after taking over the control from [applications](structure-applications.md), |
||||||
|
controllers will analyze incoming request data, pass them to [models](structure-models.md), inject model results |
||||||
|
into [views](structure-views.md), and finally generate outgoing responses. |
||||||
|
|
||||||
|
|
||||||
|
## Actions <a name="actions"></a> |
||||||
|
|
||||||
|
Controllers are composed by *actions* which are the most basic units that end users can address and request for |
||||||
|
execution. A controller can have one or multiple actions. |
||||||
|
|
||||||
|
The following example shows a `post` controller with two actions: `view` and `create`: |
||||||
|
|
||||||
|
```php |
||||||
|
namespace app\controllers; |
||||||
|
|
||||||
|
use Yii; |
||||||
|
use app\models\Post; |
||||||
|
use yii\web\Controller; |
||||||
|
use yii\web\NotFoundHttpException; |
||||||
|
|
||||||
|
class PostController extends Controller |
||||||
|
{ |
||||||
|
public function actionView($id) |
||||||
|
{ |
||||||
|
$model = Post::findOne($id); |
||||||
|
if ($model === null) { |
||||||
|
throw new NotFoundHttpException; |
||||||
|
} |
||||||
|
|
||||||
|
return $this->render('view', [ |
||||||
|
'model' => $model, |
||||||
|
]); |
||||||
|
} |
||||||
|
|
||||||
|
public function actionCreate() |
||||||
|
{ |
||||||
|
$model = new Post; |
||||||
|
|
||||||
|
if ($model->load(Yii::$app->request->post()) && $model->save()) { |
||||||
|
return $this->redirect(['view', 'id' => $model->id]); |
||||||
|
} else { |
||||||
|
return $this->render('create', [ |
||||||
|
'model' => $model, |
||||||
|
]); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
In the `view` action (defined by the `actionView()` method), the code first loads the [model](structure-models.md) |
||||||
|
according to the requested model ID; If the model is loaded successfully, it will display it using |
||||||
|
a [view](structure-views.md) named `view`. Otherwise, it will throw an exception. |
||||||
|
|
||||||
|
In the `create` action (defined by the `actionCreate()` method), the code is similar. It first tries to populate |
||||||
|
the [model](structure-models.md) using the request data and save the model. If both succeed it will redirect |
||||||
|
the browser to the `view` action with the ID of the newly created model. Otherwise it will display |
||||||
|
the `create` view through which users can provide the needed input. |
||||||
|
|
||||||
|
|
||||||
|
## Routes <a name="routes"></a> |
||||||
|
|
||||||
|
End users address actions through the so-called *routes*. A route is a string that consists of the following parts: |
||||||
|
|
||||||
|
* a module ID: this exists only if the controller belongs to a non-application [module](structure-modules.md); |
||||||
|
* a controller ID: a string that uniquely identifies the controller among all controllers within the same application |
||||||
|
(or the same module if the controller belongs to a module); |
||||||
|
* an action ID: a string that uniquely identifies the action among all actions within the same controller. |
||||||
|
|
||||||
|
Routes take the following format: |
||||||
|
|
||||||
|
``` |
||||||
|
ControllerID/ActionID |
||||||
|
``` |
||||||
|
|
||||||
|
or the following format if the controller belongs to a module: |
||||||
|
|
||||||
|
```php |
||||||
|
ModuleID/ControllerID/ActionID |
||||||
|
``` |
||||||
|
|
||||||
|
So if a user requests with the URL `http://hostname/index.php?r=site/index`, the `index` action in the `site` controller |
||||||
|
will be executed. For more details how routes are resolved into actions, please refer to |
||||||
|
the [Routing](runtime-routing.md) section. |
||||||
|
|
||||||
|
|
||||||
|
## Creating Controllers <a name="creating-controllers"></a> |
||||||
|
|
||||||
|
In [[yii\web\Application|Web applications]], controllers should extend from [[yii\web\Controller]] or its |
||||||
|
child classes. Similarly in [[yii\console\Application|console applications]], controllers should extend from |
||||||
|
[[yii\console\Controller]] or its child classes. The following code defines a `site` controller: |
||||||
|
|
||||||
|
```php |
||||||
|
namespace app\controllers; |
||||||
|
|
||||||
|
use yii\web\Controller; |
||||||
|
|
||||||
|
class SiteController extends Controller |
||||||
|
{ |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
### Controller IDs <a name="controller-ids"></a> |
||||||
|
|
||||||
|
Usually, a controller is designed to handle the requests regarding a particular type of resource. |
||||||
|
For this reason, controller IDs are often nouns referring to the types of the resources that they are handling. |
||||||
|
For example, you may use `article` as the ID of a controller that handles article data. |
||||||
|
|
||||||
|
By default, controller IDs should contain these characters only: English letters in lower case, digits, |
||||||
|
underscores, dashes and forward slashes. For example, `article` and `post-comment` are both valid controller IDs, |
||||||
|
while `article?`, `PostComment`, `admin\post` are not. |
||||||
|
|
||||||
|
A controller ID may also contain a subdirectory prefix. For example, `admin/article` stands for an `article` controller |
||||||
|
in the `admin` subdirectory under the [[yii\base\Application::controllerNamespace|controller namespace]]. |
||||||
|
Valid characters for subdirectory prefixes include: English letters in lower and upper cases, digits, underscores and |
||||||
|
forward slashes, where forward slashes are used as separators for multi-level subdirectories (e.g. `panels/admin`). |
||||||
|
|
||||||
|
|
||||||
|
### Controller Class Naming <a name="controller-class-naming"></a> |
||||||
|
|
||||||
|
Controller class names can be derived from controller IDs according to the following rules: |
||||||
|
|
||||||
|
* Turn the first letter in each word separated by dashes into upper case. Note that if the controller ID |
||||||
|
contains slashes, this rule only applies to the part after the last slash in the ID. |
||||||
|
* Remove dashes and replace any forward slashes with backward slashes. |
||||||
|
* Append the suffix `Controller`. |
||||||
|
* And prepend the [[yii\base\Application::controllerNamespace|controller namespace]]. |
||||||
|
|
||||||
|
The followings are some examples, assuming the [[yii\base\Application::controllerNamespace|controller namespace]] |
||||||
|
takes the default value `app\controllers`: |
||||||
|
|
||||||
|
* `article` derives `app\controllers\ArticleController`; |
||||||
|
* `post-comment` derives `app\controllers\PostCommentController`; |
||||||
|
* `admin/post-comment` derives `app\controllers\admin\PostCommentController`; |
||||||
|
* `adminPanels/post-comment` derives `app\controllers\adminPanels\PostCommentController`. |
||||||
|
|
||||||
|
Controller classes must be [autoloadable](concept-autoloading.md). For this reason, in the above examples, |
||||||
|
the `article` controller class should be saved in the file whose [alias](concept-aliases.md) |
||||||
|
is `@app/controllers/ArticleController.php`; while the `admin/post2-comment` controller should be |
||||||
|
in `@app/controllers/admin/Post2CommentController.php`. |
||||||
|
|
||||||
|
> Info: The last example `admin/post2-comment` shows how you can put a controller under a sub-directory |
||||||
|
of the [[yii\base\Application::controllerNamespace|controller namespace]]. This is useful when you want |
||||||
|
to organize your controllers into several categories and you do not want to use [modules](structure-modules.md). |
||||||
|
|
||||||
|
|
||||||
|
### Controller Map <a name="controller-map"></a> |
||||||
|
|
||||||
|
You can configure [[yii\base\Application::controllerMap|controller map]] to overcome the constraints |
||||||
|
of the controller IDs and class names described above. This is mainly useful when you are using some |
||||||
|
third-party controllers which you do not control over their class names. |
||||||
|
|
||||||
|
You may configure [[yii\base\Application::controllerMap|controller map]] in the |
||||||
|
[application configuration](structure-applications.md#application-configurations) like the following: |
||||||
|
|
||||||
|
```php |
||||||
|
[ |
||||||
|
'controllerMap' => [ |
||||||
|
// declares "account" controller using a class name |
||||||
|
'account' => 'app\controllers\UserController', |
||||||
|
|
||||||
|
// declares "article" controller using a configuration array |
||||||
|
'article' => [ |
||||||
|
'class' => 'app\controllers\PostController', |
||||||
|
'enableCsrfValidation' => false, |
||||||
|
], |
||||||
|
], |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
### Default Controller <a name="default-controller"></a> |
||||||
|
|
||||||
|
Each application has a default controller specified via the [[yii\base\Application::defaultRoute]] property. |
||||||
|
When a request does not specify a [route](#ids-routes), the route specified by this property will be used. |
||||||
|
For [[yii\web\Application|Web applications]], its value is `'site'`, while for [[yii\console\Application|console applications]], |
||||||
|
it is `help`. Therefore, if a URL is `http://hostname/index.php`, it means the `site` controller will handle the request. |
||||||
|
|
||||||
|
You may change the default controller with the following [application configuration](structure-applications.md#application-configurations): |
||||||
|
|
||||||
|
```php |
||||||
|
[ |
||||||
|
'defaultRoute' => 'main', |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
## Creating Actions <a name="creating-actions"></a> |
||||||
|
|
||||||
|
Creating actions can be as simple as defining the so-called *action methods* in a controller class. An action method is |
||||||
|
a *public* method whose name starts with the word `action`. The return value of an action method represents |
||||||
|
the response data to be sent to end users. The following code defines two actions `index` and `hello-world`: |
||||||
|
|
||||||
|
```php |
||||||
|
namespace app\controllers; |
||||||
|
|
||||||
|
use yii\web\Controller; |
||||||
|
|
||||||
|
class SiteController extends Controller |
||||||
|
{ |
||||||
|
public function actionIndex() |
||||||
|
{ |
||||||
|
return $this->render('index'); |
||||||
|
} |
||||||
|
|
||||||
|
public function actionHelloWorld() |
||||||
|
{ |
||||||
|
return 'Hello World'; |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
### Action IDs <a name="action-ids"></a> |
||||||
|
|
||||||
|
An action is often designed to perform a particular manipulation about a resource. For this reason, |
||||||
|
action IDs are usually verbs, such as `view`, `update`, etc. |
||||||
|
|
||||||
|
By default, action IDs should contain these characters only: English letters in lower case, digits, |
||||||
|
underscores and dashes. The dashes in an actionID are used to separate words. For example, |
||||||
|
`view`, `update2`, `comment-post` are all valid action IDs, while `view?`, `Update` are not. |
||||||
|
|
||||||
|
You can create actions in two ways: inline actions and standalone actions. An inline action is |
||||||
|
defined as a method in the controller class, while a standalone action is a class extending |
||||||
|
[[yii\base\Action]] or its child class. Inline actions take less effort to create and are often preferred |
||||||
|
if you have no intention to reuse these actions. Standalone actions, on the other hand, are mainly |
||||||
|
created to be used in different controllers or be redistributed as [extensions](structure-extensions.md). |
||||||
|
|
||||||
|
|
||||||
|
### Inline Actions <a name="inline-actions"></a> |
||||||
|
|
||||||
|
Inline actions refer to the actions that are defined in terms of action methods as we just described. |
||||||
|
|
||||||
|
The names of the action methods are derived from action IDs according to the following criteria: |
||||||
|
|
||||||
|
* Turn the first letter in each word of the action ID into upper case; |
||||||
|
* Remove dashes; |
||||||
|
* Prepend the prefix `action`. |
||||||
|
|
||||||
|
For example, `index` becomes `actionIndex`, and `hello-world` becomes `actionHelloWorld`. |
||||||
|
|
||||||
|
> Note: The names of the action methods are *case-sensitive*. If you have a method named `ActionIndex`, |
||||||
|
it will not be considered as an action method, and as a result, the request for the `index` action |
||||||
|
will result in an exception. Also note that action methods must be public. A private or protected |
||||||
|
method does NOT define an inline action. |
||||||
|
|
||||||
|
|
||||||
|
Inline actions are the most commonly defined actions because they take little effort to create. However, |
||||||
|
if you plan to reuse the same action in different places, or if you want to redistribute an action, |
||||||
|
you should consider defining it as a *standalone action*. |
||||||
|
|
||||||
|
|
||||||
|
### Standalone Actions <a name="standalone-actions"></a> |
||||||
|
|
||||||
|
Standalone actions are defined in terms of action classes extending [[yii\base\Action]] or its child classes. |
||||||
|
For example, in the Yii releases, there are [[yii\web\ViewAction]] and [[yii\web\ErrorAction]], both of which |
||||||
|
are standalone actions. |
||||||
|
|
||||||
|
To use a standalone action, you should declare it in the *action map* by overriding the |
||||||
|
[[yii\base\Controller::actions()]] method in your controller classes like the following: |
||||||
|
|
||||||
|
```php |
||||||
|
public function actions() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
// declares "error" action using a class name |
||||||
|
'error' => 'yii\web\ErrorAction', |
||||||
|
|
||||||
|
// declares "view" action using a configuration array |
||||||
|
'view' => [ |
||||||
|
'class' => 'yii\web\ViewAction', |
||||||
|
'viewPrefix' => '', |
||||||
|
], |
||||||
|
]; |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
As you can see, the `actions()` method should return an array whose keys are action IDs and values the corresponding |
||||||
|
action class names or [configurations](concept-configurations.md). Unlike inline actions, action IDs for standalone |
||||||
|
actions can contain arbitrary characters, as long as they are declared in the `actions()` method. |
||||||
|
|
||||||
|
|
||||||
|
To create a standalone action class, you should extend [[yii\base\Action]] or its child class, and implement |
||||||
|
a public method named `run()`. The role of the `run()` method is similar to that of an action method. For example, |
||||||
|
|
||||||
|
```php |
||||||
|
<?php |
||||||
|
namespace app\components; |
||||||
|
|
||||||
|
use yii\base\Action; |
||||||
|
|
||||||
|
class HelloWorldAction extends Action |
||||||
|
{ |
||||||
|
public function run() |
||||||
|
{ |
||||||
|
return "Hello World"; |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
### Action Results <a name="action-results"></a> |
||||||
|
|
||||||
|
The return value of an action method or the `run()` method of a standalone action is significant. It stands |
||||||
|
for the result of the corresponding action. |
||||||
|
|
||||||
|
The return value can be a [response](runtime-responses.md) object which will be sent to as the response |
||||||
|
to end users. |
||||||
|
|
||||||
|
* For [[yii\web\Application|Web applications]], the return value can also be some arbitrary data which will |
||||||
|
be assigned to [[yii\web\Response::data]] and be further converted into a string representing the response body. |
||||||
|
* For [[yii\console\Application|console applications]], the return value can also be an integer representing |
||||||
|
the [[yii\console\Response::exitStatus|exit status]] of the command execution. |
||||||
|
|
||||||
|
In the examples shown above, the action results are all strings which will be treated as the response body |
||||||
|
to be sent to end users. The following example shows how an action can redirect the user browser to a new URL |
||||||
|
by returning a response object (because the [[yii\web\Controller::redirect()|redirect()]] method returns |
||||||
|
a response object): |
||||||
|
|
||||||
|
```php |
||||||
|
public function actionForward() |
||||||
|
{ |
||||||
|
// redirect the user browser to http://example.com |
||||||
|
return $this->redirect('http://example.com'); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
### Action Parameters <a name="action-parameters"></a> |
||||||
|
|
||||||
|
The action methods for inline actions and the `run()` methods for standalone actions can take parameters, |
||||||
|
called *action parameters*. Their values are obtained from requests. For [[yii\web\Application|Web applications]], |
||||||
|
the value of each action parameter is retrieved from `$_GET` using the parameter name as the key; |
||||||
|
for [[yii\console\Application|console applications]], they correspond to the command line arguments. |
||||||
|
|
||||||
|
In the following example, the `view` action (an inline action) has declared two parameters: `$id` and `$version`. |
||||||
|
|
||||||
|
```php |
||||||
|
namespace app\controllers; |
||||||
|
|
||||||
|
use yii\web\Controller; |
||||||
|
|
||||||
|
class PostController extends Controller |
||||||
|
{ |
||||||
|
public function actionView($id, $version = null) |
||||||
|
{ |
||||||
|
// ... |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
The action parameters will be populated as follows for different requests: |
||||||
|
|
||||||
|
* `http://hostname/index.php?r=post/view&id=123`: the `$id` parameter will be filled with the value |
||||||
|
`'123'`, while `$version` is still null because there is no `version` query parameter. |
||||||
|
* `http://hostname/index.php?r=post/view&id=123&version=2`: the `$id` and `$version` parameters will |
||||||
|
be filled with `'123'` and `'2'`, respectively. |
||||||
|
* `http://hostname/index.php?r=post/view`: a [[yii\web\BadRequestHttpException]] exception will be thrown |
||||||
|
because the required `$id` parameter is not provided in the request. |
||||||
|
* `http://hostname/index.php?r=post/view&id[]=123`: a [[yii\web\BadRequestHttpException]] exception will be thrown |
||||||
|
because `$id` parameter is receiving an unexpected array value `['123']`. |
||||||
|
|
||||||
|
If you want an action parameter to accept array values, you should type-hint it with `array`, like the following: |
||||||
|
|
||||||
|
```php |
||||||
|
public function actionView(array $id, $version = null) |
||||||
|
{ |
||||||
|
// ... |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
Now if the request is `http://hostname/index.php?r=post/view&id[]=123`, the `$id` parameter will take the value |
||||||
|
of `['123']`. If the request is `http://hostname/index.php?r=post/view&id=123`, the `$id` parameter will still |
||||||
|
receive the same array value because the scalar value `'123'` will be automatically turned into an array. |
||||||
|
|
||||||
|
The above examples mainly show how action parameters work for Web applications. For console applications, |
||||||
|
please refer to the [Console Commands](tutorial-console.md) section for more details. |
||||||
|
|
||||||
|
|
||||||
|
### Default Action <a name="default-action"></a> |
||||||
|
|
||||||
|
Each controller has a default action specified via the [[yii\base\Controller::defaultAction]] property. |
||||||
|
When a [route](#ids-routes) contains the controller ID only, it implies that the default action of |
||||||
|
the specified controller is requested. |
||||||
|
|
||||||
|
By default, the default action is set as `index`. If you want to change the default value, simply override |
||||||
|
this property in the controller class, like the following: |
||||||
|
|
||||||
|
```php |
||||||
|
namespace app\controllers; |
||||||
|
|
||||||
|
use yii\web\Controller; |
||||||
|
|
||||||
|
class SiteController extends Controller |
||||||
|
{ |
||||||
|
public $defaultAction = 'home'; |
||||||
|
|
||||||
|
public function actionHome() |
||||||
|
{ |
||||||
|
return $this->render('home'); |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
## Controller Lifecycle <a name="controller-lifecycle"></a> |
||||||
|
|
||||||
|
When processing a request, an [application](structure-applications.md) will create a controller |
||||||
|
based on the requested [route](#routes). The controller will then undergo the following lifecycle |
||||||
|
to fulfill the request: |
||||||
|
|
||||||
|
1. The [[yii\base\Controller::init()]] method is called after the controller is created and configured. |
||||||
|
2. The controller creates an action object based on the requested action ID: |
||||||
|
* If the action ID is not specified, the [[yii\base\Controller::defaultAction|default action ID]] will be used. |
||||||
|
* If the action ID is found in the [[yii\base\Controller::actions()|action map]], a standalone action |
||||||
|
will be created; |
||||||
|
* If the action ID is found to match an action method, an inline action will be created; |
||||||
|
* Otherwise an [[yii\base\InvalidRouteException]] exception will be thrown. |
||||||
|
3. The controller sequentially calls the `beforeAction()` method of the application, the module (if the controller |
||||||
|
belongs to a module) and the controller. |
||||||
|
* If one of the calls returns false, the rest of the uncalled `beforeAction()` will be skipped and the |
||||||
|
action execution will be cancelled. |
||||||
|
* By default, each `beforeAction()` method call will trigger a `beforeAction` event to which you can attach a handler. |
||||||
|
4. The controller runs the action: |
||||||
|
* The action parameters will be analyzed and populated from the request data; |
||||||
|
5. The controller sequentially calls the `afterAction()` method of the controller, the module (if the controller |
||||||
|
belongs to a module) and the application. |
||||||
|
* By default, each `afterAction()` method call will trigger an `afterAction` event to which you can attach a handler. |
||||||
|
6. The application will take the action result and assign it to the [response](runtime-responses.md). |
||||||
|
|
||||||
|
|
||||||
|
## Best Practices <a name="best-practices"></a> |
||||||
|
|
||||||
|
In a well-designed application, controllers are often very thin with each action containing only a few lines of code. |
||||||
|
If your controller is rather complicated, it usually indicates that you should refactor it and move some code |
||||||
|
to other classes. |
||||||
|
|
||||||
|
In summary, controllers |
||||||
|
|
||||||
|
* may access the [request](runtime-requests.md) data; |
||||||
|
* may call methods of [models](structure-models.md) and other service components with request data; |
||||||
|
* may use [views](structure-views.md) to compose responses; |
||||||
|
* should NOT process the request data - this should be done in [models](structure-models.md); |
||||||
|
* should avoid embedding HTML or other presentational code - this is better done in [views](structure-views.md). |
@ -0,0 +1,104 @@ |
|||||||
|
入口脚本 |
||||||
|
============= |
||||||
|
|
||||||
|
入口脚本是应用启动流程中的第一环,一个应用(不管是网页应用还是控制台应用)只有一个入口脚本。终端用户的请求通过入口脚本实例化应用并将将请求转发到应用。 |
||||||
|
|
||||||
|
Web 应用的入口脚本必须放在终端用户能够访问的目录下,通常命名为 `index.php`,也可以使用 Web 服务器能定位到的其他名称。 |
||||||
|
|
||||||
|
控制台应用的入口脚本一般在应用根目录下命名为 `yii`(后缀为.php),该文件需要有执行权限,这样用户就能通过命令 `./yii <route> [arguments] [options]` 来运行控制台应用。 |
||||||
|
|
||||||
|
入口脚本主要完成以下工作: |
||||||
|
|
||||||
|
* 定义全局常量; |
||||||
|
* 注册 [Composer 自动加载器](http://getcomposer.org/doc/01-basic-usage.md#autoloading); |
||||||
|
* 包含 [[Yii]] 类文件; |
||||||
|
* 加载应用配置; |
||||||
|
* 创建一个[应用](structure-applications.md)实例并配置; |
||||||
|
* 调用 [[yii\base\Application::run()]] 来处理请求。 |
||||||
|
|
||||||
|
|
||||||
|
## Web 应用 <a name="web-applications"></a> |
||||||
|
|
||||||
|
以下是[基础应用模版](start-installation.md)入口脚本的代码: |
||||||
|
|
||||||
|
```php |
||||||
|
<?php |
||||||
|
|
||||||
|
defined('YII_DEBUG') or define('YII_DEBUG', true); |
||||||
|
defined('YII_ENV') or define('YII_ENV', 'dev'); |
||||||
|
|
||||||
|
// 注册 Composer 自动加载器 |
||||||
|
require(__DIR__ . '/../vendor/autoload.php'); |
||||||
|
|
||||||
|
// 包含 Yii 类文件 |
||||||
|
require(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php'); |
||||||
|
|
||||||
|
// 加载应用配置 |
||||||
|
$config = require(__DIR__ . '/../config/web.php'); |
||||||
|
|
||||||
|
// 创建、配置、运行一个应用 |
||||||
|
(new yii\web\Application($config))->run(); |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
## 控制台应用 <a name="console-applications"></a> |
||||||
|
|
||||||
|
以下是一个控制台应用的入口脚本: |
||||||
|
|
||||||
|
```php |
||||||
|
#!/usr/bin/env php |
||||||
|
<?php |
||||||
|
/** |
||||||
|
* Yii console bootstrap file. |
||||||
|
* |
||||||
|
* @link http://www.yiiframework.com/ |
||||||
|
* @copyright Copyright (c) 2008 Yii Software LLC |
||||||
|
* @license http://www.yiiframework.com/license/ |
||||||
|
*/ |
||||||
|
|
||||||
|
defined('YII_DEBUG') or define('YII_DEBUG', true); |
||||||
|
|
||||||
|
// fcgi 默认没有定义 STDIN 和 STDOUT |
||||||
|
defined('STDIN') or define('STDIN', fopen('php://stdin', 'r')); |
||||||
|
defined('STDOUT') or define('STDOUT', fopen('php://stdout', 'w')); |
||||||
|
|
||||||
|
// 注册 Composer 自动加载器 |
||||||
|
require(__DIR__ . '/vendor/autoload.php'); |
||||||
|
|
||||||
|
// 包含 Yii 类文件 |
||||||
|
require(__DIR__ . '/vendor/yiisoft/yii2/Yii.php'); |
||||||
|
|
||||||
|
// 加载应用配置 |
||||||
|
$config = require(__DIR__ . '/config/console.php'); |
||||||
|
|
||||||
|
$application = new yii\console\Application($config); |
||||||
|
$exitCode = $application->run(); |
||||||
|
exit($exitCode); |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
## 定义常量 <a name="defining-constants"></a> |
||||||
|
|
||||||
|
入口脚本是定义全局常量的最好地方,Yii 支持以下三个常量: |
||||||
|
|
||||||
|
* `YII_DEBUG`:标识应用是否运行在调试模式。当在调试模式下,应用会保留更多日志信息,如果抛出异常,会显示详细的错误调用堆栈。因此,调试模式主要适合在开发阶段使用,`YII_DEBUG` 默认值为 false。 |
||||||
|
* `YII_ENV`:标识应用运行的环境,详情请查阅[配置](concept-configurations.md#environment-constants)章节。`YII_ENV` 默认值为 `'prod'`,表示应用运行在线上产品环境。 |
||||||
|
* `YII_ENABLE_ERROR_HANDLER`:标识是否启用 Yii 提供的错误处理,默认为 true。 |
||||||
|
|
||||||
|
当定义一个常量时,通常使用类似如下代码来定义: |
||||||
|
|
||||||
|
```php |
||||||
|
defined('YII_DEBUG') or define('YII_DEBUG', true); |
||||||
|
``` |
||||||
|
|
||||||
|
上面的代码等同于: |
||||||
|
|
||||||
|
```php |
||||||
|
if (!defined('YII_DEBUG')) { |
||||||
|
define('YII_DEBUG', true); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
显然第一段代码更加简洁易懂。 |
||||||
|
|
||||||
|
常量定义应该在入口脚本的开头,这样包含其他 PHP 文件时,常量就能生效。 |
@ -0,0 +1,511 @@ |
|||||||
|
Models |
||||||
|
====== |
||||||
|
|
||||||
|
Models are part of the [MVC](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) architecture. |
||||||
|
They are objects representing business data, rules and logic. |
||||||
|
|
||||||
|
You can create model classes by extending [[yii\base\Model]] or its child classes. The base class |
||||||
|
[[yii\base\Model]] supports many useful features: |
||||||
|
|
||||||
|
* [Attributes](#attributes): represent the business data and can be accessed like normal object properties |
||||||
|
or array elements; |
||||||
|
* [Attribute labels](#attribute-labels): specify the display labels for attributes; |
||||||
|
* [Massive assignment](#massive-assignment): supports populating multiple attributes in a single step; |
||||||
|
* [Validation rules](#validation-rules): ensures input data based on the declared validation rules; |
||||||
|
* [Data Exporting](#data-exporting): allows model data to be exported in terms of arrays with customizable formats. |
||||||
|
|
||||||
|
The `Model` class is also the base class for more advanced models, such as [Active Record](db-active-record.md). |
||||||
|
Please refer to the relevant documentation for more details about these advanced models. |
||||||
|
|
||||||
|
> Info: You are not required to base your model classes on [[yii\base\Model]]. However, because there are many Yii |
||||||
|
components built to support [[yii\base\Model]], it is usually the preferable base class for a model. |
||||||
|
|
||||||
|
|
||||||
|
## Attributes <a name="attributes"></a> |
||||||
|
|
||||||
|
Models represent business data in terms of *attributes*. Each attribute is like a publicly accessible property |
||||||
|
of a model. The method [[yii\base\Model::attributes()]] specifies what attributes a model class has. |
||||||
|
|
||||||
|
You can access an attribute like accessing a normal object property: |
||||||
|
|
||||||
|
```php |
||||||
|
$model = new \app\models\ContactForm; |
||||||
|
|
||||||
|
// "name" is an attribute of ContactForm |
||||||
|
$model->name = 'example'; |
||||||
|
echo $model->name; |
||||||
|
``` |
||||||
|
|
||||||
|
You can also access attributes like accessing array elements, thanks to the support for |
||||||
|
[ArrayAccess](http://php.net/manual/en/class.arrayaccess.php) and [ArrayIterator](http://php.net/manual/en/class.arrayiterator.php) |
||||||
|
by [[yii\base\Model]]: |
||||||
|
|
||||||
|
```php |
||||||
|
$model = new \app\models\ContactForm; |
||||||
|
|
||||||
|
// accessing attributes like array elements |
||||||
|
$model['name'] = 'example'; |
||||||
|
echo $model['name']; |
||||||
|
|
||||||
|
// iterate attributes |
||||||
|
foreach ($model as $name => $value) { |
||||||
|
echo "$name: $value\n"; |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
### Defining Attributes <a name="defining-attributes"></a> |
||||||
|
|
||||||
|
By default, if your model class extends directly from [[yii\base\Model]], all its *non-static public* member |
||||||
|
variables are attributes. For example, the `ContactForm` model class below has four attributes: `name`, `email`, |
||||||
|
`subject` and `body`. The `ContactForm` model is used to represent the input data received from an HTML form. |
||||||
|
|
||||||
|
```php |
||||||
|
namespace app\models; |
||||||
|
|
||||||
|
use yii\base\Model; |
||||||
|
|
||||||
|
class ContactForm extends Model |
||||||
|
{ |
||||||
|
public $name; |
||||||
|
public $email; |
||||||
|
public $subject; |
||||||
|
public $body; |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
You may override [[yii\base\Model::attributes()]] to define attributes in a different way. The method should |
||||||
|
return the names of the attributes in a model. For example, [[yii\db\ActiveRecord]] does so by returning |
||||||
|
the column names of the associated database table as its attribute names. Note that you may also need to |
||||||
|
override the magic methods such as `__get()`, `__set()` so that the attributes can be accessed like |
||||||
|
normal object properties. |
||||||
|
|
||||||
|
|
||||||
|
### Attribute Labels <a name="attribute-labels"></a> |
||||||
|
|
||||||
|
When displaying values or getting input for attributes, you often need to display some labels associated |
||||||
|
with attributes. For example, given an attribute named `firstName`, you may want to display a label `First Name` |
||||||
|
which is more user-friendly when displayed to end users in places such as form inputs and error messages. |
||||||
|
|
||||||
|
You can get the label of an attribute by calling [[yii\base\Model::getAttributeLabel()]]. For example, |
||||||
|
|
||||||
|
```php |
||||||
|
$model = new \app\models\ContactForm; |
||||||
|
|
||||||
|
// displays "Name" |
||||||
|
echo $model->getAttributeLabel('name'); |
||||||
|
``` |
||||||
|
|
||||||
|
By default, attribute labels are automatically generated from attribute names. The generation is done by |
||||||
|
the method [[yii\base\Model::generateAttributeLabel()]]. It will turn camel-case variable names into |
||||||
|
multiple words with the first letter in each word in upper case. For example, `username` becomes `Username`, |
||||||
|
and `firstName` becomes `First Name`. |
||||||
|
|
||||||
|
If you do not want to use automatically generated labels, you may override [[yii\base\Model::attributeLabels()]] |
||||||
|
to explicitly declare attribute labels. For example, |
||||||
|
|
||||||
|
```php |
||||||
|
namespace app\models; |
||||||
|
|
||||||
|
use yii\base\Model; |
||||||
|
|
||||||
|
class ContactForm extends Model |
||||||
|
{ |
||||||
|
public $name; |
||||||
|
public $email; |
||||||
|
public $subject; |
||||||
|
public $body; |
||||||
|
|
||||||
|
public function attributeLabels() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'name' => 'Your name', |
||||||
|
'email' => 'Your email address', |
||||||
|
'subject' => 'Subject', |
||||||
|
'body' => 'Content', |
||||||
|
]; |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
For applications supporting multiple languages, you may want to translate attribute labels. This can be done |
||||||
|
in the [[yii\base\Model::attributeLabels()|attributeLabels()]] method as well, like the following: |
||||||
|
|
||||||
|
```php |
||||||
|
public function attributeLabels() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'name' => \Yii::t('app', 'Your name'), |
||||||
|
'email' => \Yii::t('app', 'Your email address'), |
||||||
|
'subject' => \Yii::t('app', 'Subject'), |
||||||
|
'body' => \Yii::t('app', 'Content'), |
||||||
|
]; |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
You may even conditionally define attribute labels. For example, based on the [scenario](#scenarios) the model |
||||||
|
is being used in, you may return different labels for the same attribute. |
||||||
|
|
||||||
|
> Info: Strictly speaking, attribute labels are part of [views](structure-views.md). But declaring labels |
||||||
|
in models is often very convenient and can result in very clean and reusable code. |
||||||
|
|
||||||
|
|
||||||
|
## Scenarios <a name="scenarios"></a> |
||||||
|
|
||||||
|
A model may be used in different *scenarios*. For example, a `User` model may be used to collect user login inputs, |
||||||
|
but it may also be used for the user registration purpose. In different scenarios, a model may use different |
||||||
|
business rules and logic. For example, the `email` attribute may be required during user registration, |
||||||
|
but not so during user login. |
||||||
|
|
||||||
|
A model uses the [[yii\base\Model::scenario]] property to keep track of the scenario it is being used in. |
||||||
|
By default, a model supports only a single scenario named `default`. The following code shows two ways of |
||||||
|
setting the scenario of a model: |
||||||
|
|
||||||
|
```php |
||||||
|
// scenario is set as a property |
||||||
|
$model = new User; |
||||||
|
$model->scenario = 'login'; |
||||||
|
|
||||||
|
// scenario is set through configuration |
||||||
|
$model = new User(['scenario' => 'login']); |
||||||
|
``` |
||||||
|
|
||||||
|
By default, the scenarios supported by a model are determined by the [validation rules](#validation-rules) declared |
||||||
|
in the model. However, you can customize this behavior by overriding the [[yii\base\Model::scenarios()]] method, |
||||||
|
like the following: |
||||||
|
|
||||||
|
```php |
||||||
|
namespace app\models; |
||||||
|
|
||||||
|
use yii\db\ActiveRecord; |
||||||
|
|
||||||
|
class User extends ActiveRecord |
||||||
|
{ |
||||||
|
public function scenarios() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'login' => ['username', 'password'], |
||||||
|
'register' => ['username', 'email', 'password'], |
||||||
|
]; |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
> Info: In the above and following examples, the model classes are extending from [[yii\db\ActiveRecord]] |
||||||
|
because the usage of multiple scenarios usually happens to [Active Record](db-active-record.md) classes. |
||||||
|
|
||||||
|
The `scenarios()` method returns an array whose keys are the scenario names and values the corresponding |
||||||
|
*active attributes*. An active attribute can be [massively assigned](#massive-assignment) and is subject |
||||||
|
to [validation](#validation-rules). In the above example, the `username` and `password` attributes are active |
||||||
|
in the `login` scenario; while in the `register` scenario, `email` is also active besides `username` and `password`. |
||||||
|
|
||||||
|
The default implementation of `scenarios()` will return all scenarios found in the validation rule declaration |
||||||
|
method [[yii\base\Model::rules()]]. When overriding `scenarios()`, if you want to introduce new scenarios |
||||||
|
in addition to the default ones, you may write code like the following: |
||||||
|
|
||||||
|
```php |
||||||
|
namespace app\models; |
||||||
|
|
||||||
|
use yii\db\ActiveRecord; |
||||||
|
|
||||||
|
class User extends ActiveRecord |
||||||
|
{ |
||||||
|
public function scenarios() |
||||||
|
{ |
||||||
|
$scenarios = parent::scenarios(); |
||||||
|
$scenarios['login'] = ['username', 'password']; |
||||||
|
$scenarios['register'] = ['username', 'email', 'password']; |
||||||
|
return $scenarios; |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
The scenario feature is primarily used by [validation](#validation-rules) and [massive attribute assignment](#massive-assignment). |
||||||
|
You can, however, use it for other purposes. For example, you may declare [attribute labels](#attribute-labels) |
||||||
|
differently based on the current scenario. |
||||||
|
|
||||||
|
|
||||||
|
## Validation Rules <a name="validation-rules"></a> |
||||||
|
|
||||||
|
When the data for a model is received from end users, it should be validated to make sure it satisfies |
||||||
|
certain rules (called *validation rules*, also known as *business rules*). For example, given a `ContactForm` model, |
||||||
|
you may want to make sure all attributes are not empty and the `email` attribute contains a valid email address. |
||||||
|
If the values for some attributes do not satisfy the corresponding business rules, appropriate error messages |
||||||
|
should be displayed to help the user to fix the errors. |
||||||
|
|
||||||
|
You may call [[yii\base\Model::validate()]] to validate the received data. The method will use |
||||||
|
the validation rules declared in [[yii\base\Model::rules()]] to validate every relevant attribute. If no error |
||||||
|
is found, it will return true. Otherwise, it will keep the errors in the [[yii\base\Model::errors]] property |
||||||
|
and return false. For example, |
||||||
|
|
||||||
|
```php |
||||||
|
$model = new \app\models\ContactForm; |
||||||
|
|
||||||
|
// populate model attributes with user inputs |
||||||
|
$model->attributes = \Yii::$app->request->post('ContactForm'); |
||||||
|
|
||||||
|
if ($model->validate()) { |
||||||
|
// all inputs are valid |
||||||
|
} else { |
||||||
|
// validation failed: $errors is an array containing error messages |
||||||
|
$errors = $model->errors; |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
To declare validation rules associated with a model, override the [[yii\base\Model::rules()]] method by returning |
||||||
|
the rules that the model attributes should satisfy. The following example shows the validation rules declared |
||||||
|
for the `ContactForm` model: |
||||||
|
|
||||||
|
```php |
||||||
|
public function rules() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
// the name, email, subject and body attributes are required |
||||||
|
[['name', 'email', 'subject', 'body'], 'required'], |
||||||
|
|
||||||
|
// the email attribute should be a valid email address |
||||||
|
['email', 'email'], |
||||||
|
]; |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
A rule can be used to validate one or multiple attributes, and an attribute may be validated by one or multiple rules. |
||||||
|
Please refer to the [Validating Input](input-validation.md) section for more details on how to declare |
||||||
|
validation rules. |
||||||
|
|
||||||
|
Sometimes, you may want a rule to be applied only in certain [scenarios](#scenarios). To do so, you can |
||||||
|
specify the `on` property of a rule, like the following: |
||||||
|
|
||||||
|
```php |
||||||
|
public function rules() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
// username, email and password are all required in "register" scenario |
||||||
|
[['username', 'email', 'password'], 'required', 'on' => 'register'], |
||||||
|
|
||||||
|
// username and password are required in "login" scenario |
||||||
|
[['username', 'password'], 'required', 'on' => 'login'], |
||||||
|
]; |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
If you do not specify the `on` property, the rule would be applied in all scenarios. A rule is called |
||||||
|
an *active rule* if it can be applied in the current [[yii\base\Model::scenario|scenario]]. |
||||||
|
|
||||||
|
An attribute will be validated if and only if it is an active attribute declared in `scenarios()` and |
||||||
|
is associated with one or multiple active rules declared in `rules()`. |
||||||
|
|
||||||
|
|
||||||
|
## Massive Assignment <a name="massive-assignment"></a> |
||||||
|
|
||||||
|
Massive assignment is a convenient way of populating a model with user inputs using a single line of code. |
||||||
|
It populates the attributes of a model by assigning the input data directly to the [[yii\base\Model::$attributes]] |
||||||
|
property. The following two pieces of code are equivalent, both trying to assign the form data submitted by end users |
||||||
|
to the attributes of the `ContactForm` model. Clearly, the former, which uses massive assignment, is much cleaner |
||||||
|
and less error prone than the latter: |
||||||
|
|
||||||
|
```php |
||||||
|
$model = new \app\models\ContactForm; |
||||||
|
$model->attributes = \Yii::$app->request->post('ContactForm'); |
||||||
|
``` |
||||||
|
|
||||||
|
```php |
||||||
|
$model = new \app\models\ContactForm; |
||||||
|
$data = \Yii::$app->request->post('ContactForm', []); |
||||||
|
$model->name = isset($data['name']) ? $data['name'] : null; |
||||||
|
$model->email = isset($data['email']) ? $data['email'] : null; |
||||||
|
$model->subject = isset($data['subject']) ? $data['subject'] : null; |
||||||
|
$model->body = isset($data['body']) ? $data['body'] : null; |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
### Safe Attributes <a name="safe-attributes"></a> |
||||||
|
|
||||||
|
Massive assignment only applies to the so-called *safe attributes* which are the attributes listed in |
||||||
|
[[yii\base\Model::scenarios()]] for the current [[yii\base\Model::scenario|scenario]] of a model. |
||||||
|
For example, if the `User` model has the following scenario declaration, then when the current scenario |
||||||
|
is `login`, only the `username` and `password` can be massively assigned. Any other attributes will |
||||||
|
be kept untouched. |
||||||
|
|
||||||
|
```php |
||||||
|
public function scenarios() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'login' => ['username', 'password'], |
||||||
|
'register' => ['username', 'email', 'password'], |
||||||
|
]; |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
> Info: The reason that massive assignment only applies to safe attributes is because you want to |
||||||
|
control which attributes can be modified by end user data. For example, if the `User` model |
||||||
|
has a `permission` attribute which determines the permission assigned to the user, you would |
||||||
|
like this attribute to be modifiable by administrators through a backend interface only. |
||||||
|
|
||||||
|
Because the default implementation of [[yii\base\Model::scenarios()]] will return all scenarios and attributes |
||||||
|
found in [[yii\base\Model::rules()]], if you do not override this method, it means an attribute is safe as long |
||||||
|
as it appears in one of the active validation rules. |
||||||
|
|
||||||
|
For this reason, a special validator aliased `safe` is provided so that you can declare an attribute |
||||||
|
to be safe without actually validating it. For example, the following rules declare that both `title` |
||||||
|
and `description` are safe attributes. |
||||||
|
|
||||||
|
```php |
||||||
|
public function rules() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
[['title', 'description'], 'safe'], |
||||||
|
]; |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
### Unsafe Attributes <a name="unsafe-attributes"></a> |
||||||
|
|
||||||
|
As described above, the [[yii\base\Model::scenarios()]] method serves for two purposes: determining which attributes |
||||||
|
should be validated, and determining which attributes are safe. In some rare cases, you may want to validate |
||||||
|
an attribute but do not want to mark it safe. You can do so by prefixing an exclamation mark `!` to the attribute |
||||||
|
name when declaring it in `scenarios()`, like the `secret` attribute in the following: |
||||||
|
|
||||||
|
```php |
||||||
|
public function scenarios() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'login' => ['username', 'password', '!secret'], |
||||||
|
]; |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
When the model is in the `login` scenario, all three attributes will be validated. However, only the `username` |
||||||
|
and `password` attributes can be massively assigned. To assign an input value to the `secret` attribute, you |
||||||
|
have to do it explicitly as follows, |
||||||
|
|
||||||
|
```php |
||||||
|
$model->secret = $secret; |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
## Data Exporting <a name="data-exporting"></a> |
||||||
|
|
||||||
|
Models often need to be exported in different formats. For example, you may want to convert a collection of |
||||||
|
models into JSON or Excel format. The exporting process can be broken down into two independent steps. |
||||||
|
In the first step, models are converted into arrays; in the second step, the arrays are converted into |
||||||
|
target formats. You may just focus on the first step, because the second step can be achieved by generic |
||||||
|
data formatters, such as [[yii\web\JsonResponseFormatter]]. |
||||||
|
|
||||||
|
The simplest way of converting a model into an array is to use the [[yii\base\Model::$attributes]] property. |
||||||
|
For example, |
||||||
|
|
||||||
|
```php |
||||||
|
$post = \app\models\Post::findOne(100); |
||||||
|
$array = $post->attributes; |
||||||
|
``` |
||||||
|
|
||||||
|
By default, the [[yii\base\Model::$attributes]] property will return the values of *all* attributes |
||||||
|
declared in [[yii\base\Model::attributes()]]. |
||||||
|
|
||||||
|
A more flexible and powerful way of converting a model into an array is to use the [[yii\base\Model::toArray()]] |
||||||
|
method. Its default behavior is the same as that of [[yii\base\Model::$attributes]]. However, it allows you |
||||||
|
to choose which data items, called *fields*, to be put in the resulting array and how they should be formatted. |
||||||
|
In fact, it is the default way of exporting models in RESTful Web service development, as described in |
||||||
|
the [Response Formatting](rest-response-formatting.md). |
||||||
|
|
||||||
|
|
||||||
|
### Fields <a name="fields"></a> |
||||||
|
|
||||||
|
A field is simply a named element in the array that is obtained by calling the [[yii\base\Model::toArray()]] method |
||||||
|
of a model. |
||||||
|
|
||||||
|
By default, field names are equivalent to attribute names. However, you can change this behavior by overriding |
||||||
|
the [[yii\base\Model::fields()|fields()]] and/or [[yii\base\Model::extraFields()|extraFields()]] methods. Both methods |
||||||
|
should return a list of field definitions. The fields defined by `fields()` are default fields, meaning that |
||||||
|
`toArray()` will return these fields by default. The `extraFields()` method defines additionally available fields |
||||||
|
which can also be returned by `toArray()` as long as you specify them via the `$expand` parameter. For example, |
||||||
|
the following code will return all fields defined in `fields()` and the `prettyName` and `fullAddress` fields |
||||||
|
if they are defined in `extraFields()`. |
||||||
|
|
||||||
|
```php |
||||||
|
$array = $model->toArray([], ['prettyName', 'fullAddress']); |
||||||
|
``` |
||||||
|
|
||||||
|
You can override `fields()` to add, remove, rename or redefine fields. The return value of `fields()` |
||||||
|
should be an array. The array keys are the field names, and the array values are the corresponding |
||||||
|
field definitions which can be either property/attribute names or anonymous functions returning the |
||||||
|
corresponding field values. In the special case when a field name is the same as its defining attribute |
||||||
|
name, you can omit the array key. For example, |
||||||
|
|
||||||
|
```php |
||||||
|
// explicitly list every field, best used when you want to make sure the changes |
||||||
|
// in your DB table or model attributes do not cause your field changes (to keep API backward compatibility). |
||||||
|
public function fields() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
// field name is the same as the attribute name |
||||||
|
'id', |
||||||
|
|
||||||
|
// field name is "email", the corresponding attribute name is "email_address" |
||||||
|
'email' => 'email_address', |
||||||
|
|
||||||
|
// field name is "name", its value is defined by a PHP callback |
||||||
|
'name' => function () { |
||||||
|
return $this->first_name . ' ' . $this->last_name; |
||||||
|
}, |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
// filter out some fields, best used when you want to inherit the parent implementation |
||||||
|
// and blacklist some sensitive fields. |
||||||
|
public function fields() |
||||||
|
{ |
||||||
|
$fields = parent::fields(); |
||||||
|
|
||||||
|
// remove fields that contain sensitive information |
||||||
|
unset($fields['auth_key'], $fields['password_hash'], $fields['password_reset_token']); |
||||||
|
|
||||||
|
return $fields; |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
> Warning: Because by default all attributes of a model will be included in the exported array, you should |
||||||
|
> examine your data to make sure they do not contain sensitive information. If there is such information, |
||||||
|
> you should override `fields()` to filter them out. In the above example, we choose |
||||||
|
> to filter out `auth_key`, `password_hash` and `password_reset_token`. |
||||||
|
|
||||||
|
|
||||||
|
## Best Practices <a name="best-practices"></a> |
||||||
|
|
||||||
|
Models are the central places to represent business data, rules and logic. They often need to be reused |
||||||
|
in different places. In a well-designed application, models are usually much fatter than |
||||||
|
[controllers](structure-controllers.md). |
||||||
|
|
||||||
|
In summary, models |
||||||
|
|
||||||
|
* may contain attributes to represent business data; |
||||||
|
* may contain validation rules to ensure the data validity and integrity; |
||||||
|
* may contain methods implementing business logic; |
||||||
|
* should NOT directly access request, session, or any other environmental data. These data should be injected |
||||||
|
by [controllers](structure-controllers.md) into models; |
||||||
|
* should avoid embedding HTML or other presentational code - this is better done in [views](structure-views.md); |
||||||
|
* avoid having too many [scenarios](#scenarios) in a single model. |
||||||
|
|
||||||
|
You may usually consider the last recommendation above when you are developing large complex systems. |
||||||
|
In these systems, models could be very fat because they are used in many places and may thus contain many sets |
||||||
|
of rules and business logic. This often ends up in a nightmare in maintaining the model code |
||||||
|
because a single touch of the code could affect several different places. To make the mode code more maintainable, |
||||||
|
you may take the following strategy: |
||||||
|
|
||||||
|
* Define a set of base model classes that are shared by different [applications](structure-applications.md) or |
||||||
|
[modules](structure-modules.md). These model classes should contain minimal sets of rules and logic that |
||||||
|
are common among all their usages. |
||||||
|
* In each [application](structure-applications.md) or [module](structure-modules.md) that uses a model, |
||||||
|
define a concrete model class by extending from the corresponding base model class. The concrete model classes |
||||||
|
should contain rules and logic that are specific for that application or module. |
||||||
|
|
||||||
|
For example, in the [Advanced Application Template](tutorial-advanced-app.md), you may define a base model |
||||||
|
class `common\models\Post`. Then for the front end application, you define and use a concrete model class |
||||||
|
`frontend\models\Post` which extends from `common\models\Post`. And similarly for the back end application, |
||||||
|
you define `backend\models\Post`. With this strategy, you will be sure that the code in `frontend\models\Post` |
||||||
|
is only specific to the front end application, and if you make any change to it, you do not need to worry if |
||||||
|
the change may break the back end application. |
@ -0,0 +1,18 @@ |
|||||||
|
总览 |
||||||
|
======== |
||||||
|
|
||||||
|
Yii 应用参照[模型-视图-控制器 (MVC)](http://wikipedia.org/wiki/Model-view-controller) |
||||||
|
设计模式来组织。 [模型](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)中的对象,可包含控制器逻辑,可被不同视图重复调用。 |
||||||
|
|
||||||
|
下面的示意图展示了 Yii 应用的静态结构: |
||||||
|
|
||||||
|
![Yii应用静态结构](images/application-structure.png) |
@ -0,0 +1,722 @@ |
|||||||
|
Views |
||||||
|
===== |
||||||
|
|
||||||
|
Views are part of the [MVC](http://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) architecture. |
||||||
|
They are code responsible for presenting data to end users. In a Web application, views are usually created |
||||||
|
in terms of *view templates* which are PHP script files containing mainly HTML code and presentational PHP code. |
||||||
|
They are managed by the [[yii\web\View|view]] application component which provides commonly used methods |
||||||
|
to facilitate view composition and rendering. For simplicity, we often call view templates or view template files |
||||||
|
as views. |
||||||
|
|
||||||
|
|
||||||
|
## Creating Views <a name="creating-views"></a> |
||||||
|
|
||||||
|
As aforementioned, a view is simply a PHP script mixed with HTML and PHP code. The following is the view |
||||||
|
that presents a login form. As you can see, PHP code is used to generate the dynamic content, such as the |
||||||
|
page title and the form, while HTML code organizes them into a presentable HTML page. |
||||||
|
|
||||||
|
```php |
||||||
|
<?php |
||||||
|
use yii\helpers\Html; |
||||||
|
use yii\widgets\ActiveForm; |
||||||
|
|
||||||
|
/* @var $this yii\web\View */ |
||||||
|
/* @var $form yii\widgets\ActiveForm */ |
||||||
|
/* @var $model app\models\LoginForm */ |
||||||
|
|
||||||
|
$this->title = 'Login'; |
||||||
|
?> |
||||||
|
<h1><?= Html::encode($this->title) ?></h1> |
||||||
|
|
||||||
|
<p>Please fill out the following fields to login:</p> |
||||||
|
|
||||||
|
<?php $form = ActiveForm::begin(); ?> |
||||||
|
<?= $form->field($model, 'username') ?> |
||||||
|
<?= $form->field($model, 'password')->passwordInput() ?> |
||||||
|
<?= Html::submitButton('Login') ?> |
||||||
|
<?php ActiveForm::end(); ?> |
||||||
|
``` |
||||||
|
|
||||||
|
Within a view, you can access `$this` which refers to the [[yii\web\View|view component]] managing |
||||||
|
and rendering this view template. |
||||||
|
|
||||||
|
Besides `$this`, there may be other predefined variables in a view, such as `$model` in the above |
||||||
|
example. These variables represent the data that are *pushed* into the view by [controllers](structure-controllers.md) |
||||||
|
or other objects whose trigger the [view rendering](#rendering-views). |
||||||
|
|
||||||
|
> Tip: The predefined variables are listed in a comment block at beginning of a view so that they can |
||||||
|
be recognized by IDEs. It is also a good way of documenting your views. |
||||||
|
|
||||||
|
|
||||||
|
### Security <a name="security"></a> |
||||||
|
|
||||||
|
When creating views that generate HTML pages, it is important that you encode and/or filter the data coming |
||||||
|
from end users before presenting them. Otherwise, your application may be subject to |
||||||
|
[cross-site scripting](http://en.wikipedia.org/wiki/Cross-site_scripting) attacks. |
||||||
|
|
||||||
|
To display a plain text, encode it first by calling [[yii\helpers\Html::encode()]]. For example, the following code |
||||||
|
encodes the user name before displaying it: |
||||||
|
|
||||||
|
```php |
||||||
|
<?php |
||||||
|
use yii\helpers\Html; |
||||||
|
?> |
||||||
|
|
||||||
|
<div class="username"> |
||||||
|
<?= Html::encode($user->name) ?> |
||||||
|
</div> |
||||||
|
``` |
||||||
|
|
||||||
|
To display HTML content, use [[yii\helpers\HtmlPurifier]] to filter the content first. For example, the following |
||||||
|
code filters the post content before displaying it: |
||||||
|
|
||||||
|
```php |
||||||
|
<?php |
||||||
|
use yii\helpers\HtmlPurifier; |
||||||
|
?> |
||||||
|
|
||||||
|
<div class="post"> |
||||||
|
<?= HtmlPurifier::process($post->text) ?> |
||||||
|
</div> |
||||||
|
``` |
||||||
|
|
||||||
|
> Tip: While HTMLPurifier does excellent job in making output safe, it is not fast. You should consider |
||||||
|
[caching](caching-overview.md) the filtering result if your application requires high performance. |
||||||
|
|
||||||
|
|
||||||
|
### Organizing Views <a name="organizing-views"></a> |
||||||
|
|
||||||
|
Like [controllers](structure-controllers.md) and [models](structure-models.md), there are conventions to organize views. |
||||||
|
|
||||||
|
* For views rendered by a controller, they should be put under the directory `@app/views/ControllerID` by default, |
||||||
|
where `ControllerID` refers to the [controller ID](structure-controllers.md#routes). For example, if |
||||||
|
the controller class is `PostController`, the directory would be `@app/views/post`; If it is `PostCommentController`, |
||||||
|
the directory would be `@app/views/post-comment`. In case the controller belongs to a module, the directory |
||||||
|
would be `views/ControllerID` under the [[yii\base\Module::basePath|module directory]]. |
||||||
|
* For views rendered in a [widget](structure-widgets.md), they should be put under the `WidgetPath/views` directory by |
||||||
|
default, where `WidgetPath` stands for the directory containing the widget class file. |
||||||
|
* For views rendered by other objects, it is recommended that you follow the similar convention as that for widgets. |
||||||
|
|
||||||
|
You may customize these default view directories by overriding the [[yii\base\ViewContextInterface::getViewPath()]] |
||||||
|
method of controllers or widgets. |
||||||
|
|
||||||
|
|
||||||
|
## Rendering Views <a name="rendering-views"></a> |
||||||
|
|
||||||
|
You can render views in [controllers](structure-controllers.md), [widgets](structure-widgets.md), or any |
||||||
|
other places by calling view rendering methods. These methods share a similar signature shown as follows, |
||||||
|
|
||||||
|
``` |
||||||
|
/** |
||||||
|
* @param string $view view name or file path, depending on the actual rendering method |
||||||
|
* @param array $params the data to be passed to the view |
||||||
|
* @return string rendering result |
||||||
|
*/ |
||||||
|
methodName($view, $params = []) |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
### Rendering in Controllers <a name="rendering-in-controllers"></a> |
||||||
|
|
||||||
|
Within [controllers](structure-controllers.md), you may call the following controller methods to render views: |
||||||
|
|
||||||
|
* [[yii\base\Controller::render()|render()]]: renders a [named view](#named-views) and applies a [layout](#layouts) |
||||||
|
to the rendering result. |
||||||
|
* [[yii\base\Controller::renderPartial()|renderPartial()]]: renders a [named view](#named-views) without any layout. |
||||||
|
* [[yii\web\Controller::renderAjax()|renderAjax()]]: renders a [named view](#named-views) without any layout, |
||||||
|
and injects all registered JS/CSS scripts and files. It is usually used in response to AJAX Web requests. |
||||||
|
* [[yii\base\Controller::renderFile()|renderFile()]]: renders a view specified in terms of a view file path or |
||||||
|
[alias](concept-aliases.md). |
||||||
|
|
||||||
|
For example, |
||||||
|
|
||||||
|
```php |
||||||
|
namespace app\controllers; |
||||||
|
|
||||||
|
use Yii; |
||||||
|
use app\models\Post; |
||||||
|
use yii\web\Controller; |
||||||
|
use yii\web\NotFoundHttpException; |
||||||
|
|
||||||
|
class PostController extends Controller |
||||||
|
{ |
||||||
|
public function actionView($id) |
||||||
|
{ |
||||||
|
$model = Post::findOne($id); |
||||||
|
if ($model === null) { |
||||||
|
throw new NotFoundHttpException; |
||||||
|
} |
||||||
|
|
||||||
|
// renders a view named "view" and applies a layout to it |
||||||
|
return $this->render('view', [ |
||||||
|
'model' => $model, |
||||||
|
]); |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
### Rendering in Widgets <a name="rendering-in-widgets"></a> |
||||||
|
|
||||||
|
Within [widgets](structure-widgets.md), you may call the following widget methods to render views. |
||||||
|
|
||||||
|
* [[yii\base\Widget::render()|render()]]: renders a [named view](#named-views). |
||||||
|
* [[yii\base\Widget::renderFile()|renderFile()]]: renders a view specified in terms of a view file path or |
||||||
|
[alias](concept-aliases.md). |
||||||
|
|
||||||
|
For example, |
||||||
|
|
||||||
|
```php |
||||||
|
namespace app\components; |
||||||
|
|
||||||
|
use yii\base\Widget; |
||||||
|
use yii\helpers\Html; |
||||||
|
|
||||||
|
class ListWidget extends Widget |
||||||
|
{ |
||||||
|
public $items = []; |
||||||
|
|
||||||
|
public function run() |
||||||
|
{ |
||||||
|
// renders a view named "list" |
||||||
|
return $this->render('list', [ |
||||||
|
'items' => $this->items, |
||||||
|
]); |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
### Rendering in Views <a name="rendering-in-views"></a> |
||||||
|
|
||||||
|
You can render a view within another view by calling one of the following methods provided by the [[yii\base\View|view component]]: |
||||||
|
|
||||||
|
* [[yii\base\View::render()|render()]]: renders a [named view](#named-views). |
||||||
|
* [[yii\web\View::renderAjax()|renderAjax()]]: renders a [named view](#named-views) and injects all registered |
||||||
|
JS/CSS scripts and files. It is usually used in response to AJAX Web requests. |
||||||
|
* [[yii\base\View::renderFile()|renderFile()]]: renders a view specified in terms of a view file path or |
||||||
|
[alias](concept-aliases.md). |
||||||
|
|
||||||
|
For example, the following code in a view renders the `_overview.php` view file which is in the same directory |
||||||
|
as the view being currently rendered. Remember that `$this` in a view refers to the [[yii\base\View|view]] component: |
||||||
|
|
||||||
|
```php |
||||||
|
<?= $this->render('_overview') ?> |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
### Rendering in Other Places <a name="rendering-in-other-places"></a> |
||||||
|
|
||||||
|
In any place, you can get access to the [[yii\base\View|view]] application component by the expression |
||||||
|
`Yii::$app->view` and then call its aforementioned methods to render a view. For example, |
||||||
|
|
||||||
|
```php |
||||||
|
// displays the view file "@app/views/site/license.php" |
||||||
|
echo \Yii::$app->view->renderFile('@app/views/site/license.php'); |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
### Named Views <a name="named-views"></a> |
||||||
|
|
||||||
|
When you render a view, you can specify the view using either a view name or a view file path/alias. In most cases, |
||||||
|
you would use the former because it is more concise and flexible. We call views specified using names as *named views*. |
||||||
|
|
||||||
|
A view name is resolved into the corresponding view file path according to the following rules: |
||||||
|
|
||||||
|
* A view name may omit the file extension name. In this case, `.php` will be used as the extension. For example, |
||||||
|
the view name `about` corresponds to the file name `about.php`. |
||||||
|
* If the view name starts with double slashes `//`, the corresponding view file path would be `@app/views/ViewName`. |
||||||
|
That is, the view is looked for under the [[yii\base\Application::viewPath|application's view path]]. |
||||||
|
For example, `//site/about` will be resolved into `@app/views/site/about.php`. |
||||||
|
* If the view name starts with a single slash `/`, the view file path is formed by prefixing the view name |
||||||
|
with the [[yii\base\Module::viewPath|view path]] of the currently active [module](structure-modules.md). |
||||||
|
If there is no active module, `@app/views/ViewName` will be used. For example, `/user/create` will be resolved into |
||||||
|
`@app/modules/user/views/user/create.php`, if the currently active module is `user`. If there is no active module, |
||||||
|
the view file path would be `@app/views/user/create.php`. |
||||||
|
* If the view is rendered with a [[yii\base\View::context|context]] and the context implements [[yii\base\ViewContextInterface]], |
||||||
|
the view file path is formed by prefixing the [[yii\base\ViewContextInterface::getViewPath()|view path]] of the |
||||||
|
context to the view name. This mainly applies to the views rendered within controllers and widgets. For example, |
||||||
|
`site/about` will be resolved into `@app/views/site/about.php` if the context is the controller `SiteController`. |
||||||
|
* If a view is rendered within another view, the directory containing the other view file will be prefixed to |
||||||
|
the new view name to form the actual view file path. For example, `item` will be resolved into `@app/views/post/item` |
||||||
|
if it is being rendered in the view `@app/views/post/index.php`. |
||||||
|
|
||||||
|
According to the above rules, calling `$this->render('view')` in a controller `app\controllers\PostController` will |
||||||
|
actually render the view file `@app/views/post/view.php`, while calling `$this->render('_overview')` in that view |
||||||
|
will render the view file `@app/views/post/_overview.php`. |
||||||
|
|
||||||
|
|
||||||
|
### Accessing Data in Views <a name="accessing-data-in-views"></a> |
||||||
|
|
||||||
|
There are two approaches to access data within a view: push and pull. |
||||||
|
|
||||||
|
By passing the data as the second parameter to the view rendering methods, you are using the push approach. |
||||||
|
The data should be represented as an array of name-value pairs. When the view is being rendered, the PHP |
||||||
|
`extract()` function will be called on this array so that the array is extracted into variables in the view. |
||||||
|
For example, the following view rendering code in a controller will push two variables to the `report` view: |
||||||
|
`$foo = 1` and `$bar = 2`. |
||||||
|
|
||||||
|
```php |
||||||
|
echo $this->render('report', [ |
||||||
|
'foo' => 1, |
||||||
|
'bar' => 2, |
||||||
|
]); |
||||||
|
``` |
||||||
|
|
||||||
|
The pull approach actively retrieves data from the [[yii\base\View|view component]] or other objects accessible |
||||||
|
in views (e.g. `Yii::$app`). Using the code below as an example, within the view you can get the controller object |
||||||
|
by the expression `$this->context`. And as a result, it is possible for you to access any properties or methods |
||||||
|
of the controller in the `report` view, such as the controller ID shown in the following: |
||||||
|
|
||||||
|
```php |
||||||
|
The controller ID is: <?= $this->context->id ?> |
||||||
|
?> |
||||||
|
``` |
||||||
|
|
||||||
|
The push approach is usually the preferred way of accessing data in views, because it makes views less dependent |
||||||
|
on context objects. Its drawback is that you need to manually build the data array all the time, which could |
||||||
|
become tedious and error prone if a view is shared and rendered in different places. |
||||||
|
|
||||||
|
|
||||||
|
### Sharing Data among Views <a name="sharing-data-among-views"></a> |
||||||
|
|
||||||
|
The [[yii\base\View|view component]] provides the [[yii\base\View::params|params]] property that you can use |
||||||
|
to share data among views. |
||||||
|
|
||||||
|
For example, in an `about` view, you can have the following code which specifies the current segment of the |
||||||
|
breadcrumbs. |
||||||
|
|
||||||
|
```php |
||||||
|
$this->params['breadcrumbs'][] = 'About Us'; |
||||||
|
``` |
||||||
|
|
||||||
|
Then, in the [layout](#layouts) file, which is also a view, you can display the breadcrumbs using the data |
||||||
|
passed along [[yii\base\View::params|params]]: |
||||||
|
|
||||||
|
```php |
||||||
|
<?= yii\widgets\Breadcrumbs::widget([ |
||||||
|
'links' => isset($this->params['breadcrumbs']) ? $this->params['breadcrumbs'] : [], |
||||||
|
]) ?> |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
## Layouts <a name="layouts"></a> |
||||||
|
|
||||||
|
Layouts are a special type of views that represent the common parts of multiple views. For example, the pages |
||||||
|
for most Web applications share the same page header and footer. While you can repeat the same page header and footer |
||||||
|
in every view, a better way is to do this once in a layout and embed the rendering result of a content view at |
||||||
|
an appropriate place in the layout. |
||||||
|
|
||||||
|
|
||||||
|
### Creating Layouts <a name="creating-layouts"></a> |
||||||
|
|
||||||
|
Because layouts are also views, they can be created in the similar way as normal views. By default, layouts |
||||||
|
are stored in the directory `@app/views/layouts`. For layouts used within a [module](structure-modules.md), |
||||||
|
they should be stored in the `views/layouts` directory under the [[yii\base\Module::basePath|module directory]]. |
||||||
|
You may customize the default layout directory by configuring the [[yii\base\Module::layoutPath]] property of |
||||||
|
the application or modules. |
||||||
|
|
||||||
|
The following example shows how a layout looks like. Note that for illustrative purpose, we have greatly simplified |
||||||
|
the code in the layout. In practice, you may want to add more content to it, such as head tags, main menu, etc. |
||||||
|
|
||||||
|
```php |
||||||
|
<?php |
||||||
|
use yii\helpers\Html; |
||||||
|
|
||||||
|
/* @var $this yii\web\View */ |
||||||
|
/* @var $content string */ |
||||||
|
?> |
||||||
|
<?php $this->beginPage() ?> |
||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta charset="UTF-8"/> |
||||||
|
<?= Html::csrfMetaTags() ?> |
||||||
|
<title><?= Html::encode($this->title) ?></title> |
||||||
|
<?php $this->head() ?> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<?php $this->beginBody() ?> |
||||||
|
<header>My Company</header> |
||||||
|
<?= $content ?> |
||||||
|
<footer>© 2014 by My Company</footer> |
||||||
|
<?php $this->endBody() ?> |
||||||
|
</body> |
||||||
|
</html> |
||||||
|
<?php $this->endPage() ?> |
||||||
|
``` |
||||||
|
|
||||||
|
As you can see, the layout generates the HTML tags that are common to all pages. Within the `<body>` section, |
||||||
|
the layout echoes the `$content` variable which represents the rendering result of content views and is pushed |
||||||
|
into the layout when [[yii\base\Controller::render()]] is called. |
||||||
|
|
||||||
|
Most layouts should call the following methods like shown in the above code. These methods mainly trigger events |
||||||
|
about the rendering process so that scripts and tags registered in other places can be properly injected into |
||||||
|
the places where these methods are called. |
||||||
|
|
||||||
|
- [[yii\base\View::beginPage()|beginPage()]]: This method should be called at the very beginning of the layout. |
||||||
|
It triggers the [[yii\base\View::EVENT_BEGIN_PAGE|EVENT_BEGIN_PAGE]] event which indicates the beginning of a page. |
||||||
|
- [[yii\base\View::endPage()|endPage()]]: This method should be called at the end of the layout. |
||||||
|
It triggers the [[yii\base\View::EVENT_END_PAGE|EVENT_END_PAGE]] event which indicates the end of a page. |
||||||
|
- [[yii\web\View::head()|head()]]: This method should be called within the `<head>` section of an HTML page. |
||||||
|
It generates a placeholder which will be replaced with the registered head HTML code (e.g. link tags, meta tags) |
||||||
|
when a page finishes rendering. |
||||||
|
- [[yii\web\View::beginBody()|beginBody()]]: This method should be called at the beginning of the `<body>` section. |
||||||
|
It triggers the [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]] event and generates a placeholder which will |
||||||
|
be replaced by the registered HTML code (e.g. JavaScript) targeted at the body begin position. |
||||||
|
- [[yii\web\View::endBody()|endBody()]]: This method should be called at the end of the `<body>` section. |
||||||
|
It triggers the [[yii\web\View::EVENT_END_BODY|EVENT_END_BODY]] event and generates a placeholder which will |
||||||
|
be replaced by the registered HTML code (e.g. JavaScript) targeted at the body end position. |
||||||
|
|
||||||
|
|
||||||
|
### Accessing Data in Layouts <a name="accessing-data-in-layouts"></a> |
||||||
|
|
||||||
|
Within a layout, you have access to two predefined variables: `$this` and `$content`. The former refers to |
||||||
|
the [[yii\base\View|view]] component, like in normal views, while the latter contains the rendering result of a content |
||||||
|
view which is rendered by calling the [[yii\base\Controller::render()|render()]] method in controllers. |
||||||
|
|
||||||
|
If you want to access other data in layouts, you have to use the pull method as described in |
||||||
|
the [Accessing Data in Views](#accessing-data-in-views) subsection. If you want to pass data from a content view |
||||||
|
to a layout, you may use the method described in the [Sharing Data among Views](#sharing-data-among-views) subsection. |
||||||
|
|
||||||
|
|
||||||
|
### Using Layouts <a name="using-layouts"></a> |
||||||
|
|
||||||
|
As described in the [Rendering in Controllers](#rendering-in-controllers) subsection, when you render a view |
||||||
|
by calling the [[yii\base\Controller::render()|render()]] method in a controller, a layout will be applied |
||||||
|
to the rendering result. By default, the layout `@app/views/layouts/main.php` will be used. |
||||||
|
|
||||||
|
You may use a different layout by configuring either [[yii\base\Application::layout]] or [[yii\base\Controller::layout]]. |
||||||
|
The former governs the layout used by all controllers, while the latter overrides the former for individual controllers. |
||||||
|
For example, the following code makes the `post` controller to use `@app/views/layouts/post.php` as the layout |
||||||
|
when rendering its views. Other controllers, assuming their `layout` property is untouched, will still use the default |
||||||
|
`@app/views/layouts/main.php` as the layout. |
||||||
|
|
||||||
|
```php |
||||||
|
namespace app\controllers; |
||||||
|
|
||||||
|
use yii\web\Controller; |
||||||
|
|
||||||
|
class PostController extends Controller |
||||||
|
{ |
||||||
|
public $layout = 'post'; |
||||||
|
|
||||||
|
// ... |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
For controllers belonging to a module, you may also configure the module's [[yii\base\Module::layout|layout]] property to |
||||||
|
use a particular layout for these controllers. |
||||||
|
|
||||||
|
Because the `layout` property may be configured at different levels (controllers, modules, application), |
||||||
|
behind the scene Yii takes two steps to determine what is the actual layout file being used for a particular controller. |
||||||
|
|
||||||
|
In the first step, it determines the layout value and the context module: |
||||||
|
|
||||||
|
- If the [[yii\base\Controller::layout]] property of the controller is not null, use it as the layout value and |
||||||
|
the [[yii\base\Controller::module|module]] of the controller as the context module. |
||||||
|
- If [[yii\base\Controller::layout|layout]] is null, search through all ancestor modules (including the application itself) of the controller and |
||||||
|
find the first module whose [[yii\base\Module::layout|layout]] property is not null. Use that module and |
||||||
|
its [[yii\base\Module::layout|layout]] value as the context module and the chosen layout value. |
||||||
|
If such a module cannot be found, it means no layout will be applied. |
||||||
|
|
||||||
|
In the second step, it determines the actual layout file according to the layout value and the context module |
||||||
|
determined in the first step. The layout value can be: |
||||||
|
|
||||||
|
- a path alias (e.g. `@app/views/layouts/main`). |
||||||
|
- an absolute path (e.g. `/main`): the layout value starts with a slash. The actual layout file will be |
||||||
|
looked for under the application's [[yii\base\Application::layoutPath|layout path]] which defaults to |
||||||
|
`@app/views/layouts`. |
||||||
|
- a relative path (e.g. `main`): the actual layout file will be looked for under the context module's |
||||||
|
[[yii\base\Module::layoutPath|layout path]] which defaults to the `views/layouts` directory under the |
||||||
|
[[yii\base\Module::basePath|module directory]]. |
||||||
|
- the boolean value `false`: no layout will be applied. |
||||||
|
|
||||||
|
If the layout value does not contain a file extension, it will use the default one `.php`. |
||||||
|
|
||||||
|
|
||||||
|
### Nested Layouts <a name="nested-layouts"></a> |
||||||
|
|
||||||
|
Sometimes you may want to nest one layout in another. For example, in different sections of a Web site, you |
||||||
|
want to use different layouts, while all these layouts share the same basic layout that generates the overall |
||||||
|
HTML5 page structure. You can achieve this goal by calling [[yii\base\View::beginContent()|beginContent()]] and |
||||||
|
[[yii\base\View::endContent()|endContent()]] in the child layouts like the following: |
||||||
|
|
||||||
|
```php |
||||||
|
<?php $this->beginContent('@app/views/layouts/base.php'); ?> |
||||||
|
|
||||||
|
...child layout content here... |
||||||
|
|
||||||
|
<?php $this->endContent(); ?> |
||||||
|
``` |
||||||
|
|
||||||
|
As shown above, the child layout content should be enclosed within [[yii\base\View::beginContent()|beginContent()]] and |
||||||
|
[[yii\base\View::endContent()|endContent()]]. The parameter passed to [[yii\base\View::beginContent()|beginContent()]] |
||||||
|
specifies what is the parent layout. It can be either a layout file or alias. |
||||||
|
|
||||||
|
Using the above approach, you can nest layouts in more than one levels. |
||||||
|
|
||||||
|
|
||||||
|
### Using Blocks <a name="using-blocks"></a> |
||||||
|
|
||||||
|
Blocks allow you to specify the view content in one place while displaying it in another. They are often used together |
||||||
|
with layouts. For example, you can define a block in a content view and display it in the layout. |
||||||
|
|
||||||
|
You call [[yii\base\View::beginBlock()|beginBlock()]] and [[yii\base\View::endBlock()|endBlock()]] to define a block. |
||||||
|
The block can then be accessed via `$view->blocks[$blockID]`, where `$blockID` stands for a unique ID that you assign |
||||||
|
to the block when defining it. |
||||||
|
|
||||||
|
The following example shows how you can use blocks to customize specific parts of a layout in a content view. |
||||||
|
|
||||||
|
First, in a content view, define one or multiple blocks: |
||||||
|
|
||||||
|
```php |
||||||
|
... |
||||||
|
|
||||||
|
<?php $this->beginBlock('block1'); ?> |
||||||
|
|
||||||
|
...content of block1... |
||||||
|
|
||||||
|
<?php $this->endBlock(); ?> |
||||||
|
|
||||||
|
... |
||||||
|
|
||||||
|
<?php $this->beginBlock('block3'); ?> |
||||||
|
|
||||||
|
...content of block3... |
||||||
|
|
||||||
|
<?php $this->endBlock(); ?> |
||||||
|
``` |
||||||
|
|
||||||
|
Then, in the layout view, render the blocks if they are available, or display some default content if a block is |
||||||
|
not defined. |
||||||
|
|
||||||
|
```php |
||||||
|
... |
||||||
|
<?php if (isset($this->blocks['block1'])): ?> |
||||||
|
<?= $this->blocks['block1'] ?> |
||||||
|
<?php else: ?> |
||||||
|
... default content for block1 ... |
||||||
|
<?php endif; ?> |
||||||
|
|
||||||
|
... |
||||||
|
|
||||||
|
<?php if (isset($this->blocks['block2'])): ?> |
||||||
|
<?= $this->blocks['block2'] ?> |
||||||
|
<?php else: ?> |
||||||
|
... default content for block2 ... |
||||||
|
<?php endif; ?> |
||||||
|
|
||||||
|
... |
||||||
|
|
||||||
|
<?php if (isset($this->blocks['block3'])): ?> |
||||||
|
<?= $this->blocks['block3'] ?> |
||||||
|
<?php else: ?> |
||||||
|
... default content for block3 ... |
||||||
|
<?php endif; ?> |
||||||
|
... |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
## Using View Components <a name="using-view-components"></a> |
||||||
|
|
||||||
|
[[yii\base\View|View components]] provides many view-related features. While you can get view components |
||||||
|
by creating individual instances of [[yii\base\View]] or its child class, in most cases you will mainly use |
||||||
|
the `view` application component. You can configure this component in [application configurations](structure-applications.md#application-configurations) |
||||||
|
like the following: |
||||||
|
|
||||||
|
```php |
||||||
|
[ |
||||||
|
// ... |
||||||
|
'components' => [ |
||||||
|
'view' => [ |
||||||
|
'class' => 'app\components\View', |
||||||
|
], |
||||||
|
// ... |
||||||
|
], |
||||||
|
] |
||||||
|
``` |
||||||
|
|
||||||
|
View components provide the following useful view-related features, each described in more details in a separate section: |
||||||
|
|
||||||
|
* [theming](output-theming.md): allows you to develop and change the theme for your Web site. |
||||||
|
* [fragment caching](caching-fragment.md): allows you to cache a fragment within a Web page. |
||||||
|
* [client script handling](output-client-scripts.md): supports CSS and JavaScript registration and rendering. |
||||||
|
* [asset bundle handling](structure-assets.md): supports registering and rendering of [asset bundles](structure-assets.md). |
||||||
|
* [alternative template engines](tutorial-template-engines.md): allows you to use other template engines, such as |
||||||
|
[Twig](http://twig.sensiolabs.org/), [Smarty](http://www.smarty.net/). |
||||||
|
|
||||||
|
You may also frequently use the following minor yet useful features when you are developing Web pages. |
||||||
|
|
||||||
|
|
||||||
|
### Setting Page Titles <a name="setting-page-titles"></a> |
||||||
|
|
||||||
|
Every Web page should have a title. Normally the title tag is being displayed in a [layout](#layouts). However, in practice |
||||||
|
the title is often determined in content views rather than layouts. To solve this problem, [[yii\web\View]] provides |
||||||
|
the [[yii\web\View::title|title]] property for you to pass the title information from content views to layouts. |
||||||
|
|
||||||
|
To make use of this feature, in each content view, you can set the page title like the following: |
||||||
|
|
||||||
|
```php |
||||||
|
<?php |
||||||
|
$this->title = 'My page title'; |
||||||
|
?> |
||||||
|
``` |
||||||
|
|
||||||
|
Then in the layout, make sure you have the following code in the `<head>` section: |
||||||
|
|
||||||
|
```php |
||||||
|
<title><?= Html::encode($this->title) ?></title> |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
### Registering Meta Tags <a name="registering-meta-tags"></a> |
||||||
|
|
||||||
|
Web pages usually need to generate various meta tags needed by different parties. Like page titles, meta tags |
||||||
|
appear in the `<head>` section and are usually generated in layouts. |
||||||
|
|
||||||
|
If you want to specify what meta tags to generate in content views, you can call [[yii\web\View::registerMetaTag()]] |
||||||
|
in a content view, like the following: |
||||||
|
|
||||||
|
```php |
||||||
|
<?php |
||||||
|
$this->registerMetaTag(['name' => 'keywords', 'content' => 'yii, framework, php']); |
||||||
|
?> |
||||||
|
``` |
||||||
|
|
||||||
|
The above code will register a "keywords" meta tag with the view component. The registered meta tag is |
||||||
|
rendered after the layout finishes rendering. By then, the following HTML code will be inserted |
||||||
|
at the place where you call [[yii\web\View::head()]] in the layout and generate the following HTML code: |
||||||
|
|
||||||
|
```php |
||||||
|
<meta name="keywords" content="yii, framework, php"> |
||||||
|
``` |
||||||
|
|
||||||
|
Note that if you call [[yii\web\View::registerMetaTag()]] multiple times, it will register multiple meta tags, |
||||||
|
regardless whether the meta tags are the same or not. |
||||||
|
|
||||||
|
To make sure there is only a single instance of a meta tag type, you can specify a key as a second parameter when calling the method. |
||||||
|
For example, the following code registers two "description" meta tags. However, only the second one will be rendered. |
||||||
|
|
||||||
|
```html |
||||||
|
$this->registerMetaTag(['name' => 'description', 'content' => 'This is my cool website made with Yii!'], 'description'); |
||||||
|
$this->registerMetaTag(['name' => 'description', 'content' => 'This website is about funny raccoons.'], 'description'); |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
### Registering Link Tags <a name="registering-link-tags"></a> |
||||||
|
|
||||||
|
Like [meta tags](#adding-meta-tags), link tags are useful in many cases, such as customizing favicon, pointing to |
||||||
|
RSS feed or delegating OpenID to another server. You can work with link tags in the similar way as meta tags |
||||||
|
by using [[yii\web\View::registerLinkTag()]]. For example, in a content view, you can register a link tag like follows, |
||||||
|
|
||||||
|
```php |
||||||
|
$this->registerLinkTag([ |
||||||
|
'title' => 'Live News for Yii', |
||||||
|
'rel' => 'alternate', |
||||||
|
'type' => 'application/rss+xml', |
||||||
|
'href' => 'http://www.yiiframework.com/rss.xml/', |
||||||
|
]); |
||||||
|
``` |
||||||
|
|
||||||
|
The code above will result in |
||||||
|
|
||||||
|
```html |
||||||
|
<link title="Live News for Yii" rel="alternate" type="application/rss+xml" href="http://www.yiiframework.com/rss.xml/"> |
||||||
|
``` |
||||||
|
|
||||||
|
Similar as [[yii\web\View::registerMetaTag()|registerMetaTags()]], you can specify a key when calling |
||||||
|
[[yii\web\View::registerLinkTag()|registerLinkTag()]] to avoid generated repeated link tags. |
||||||
|
|
||||||
|
|
||||||
|
## View Events <a name="view-events"></a> |
||||||
|
|
||||||
|
[[yii\base\View|View components]] trigger several events during the view rendering process. You may respond |
||||||
|
to these events to inject content into views or process the rendering results before they are sent to end users. |
||||||
|
|
||||||
|
- [[yii\base\View::EVENT_BEFORE_RENDER|EVENT_BEFORE_RENDER]]: triggered at the beginning of rendering a file |
||||||
|
in a controller. Handlers of this event may set [[yii\base\ViewEvent::isValid]] to be false to cancel the rendering process. |
||||||
|
- [[yii\base\View::EVENT_AFTER_RENDER|EVENT_AFTER_RENDER]]: triggered by the call of [[yii\base\View::beginPage()]] in layouts. |
||||||
|
Handlers of this event may obtain the rendering result through [[yii\base\ViewEvent::output]] and may modify |
||||||
|
this property to change the rendering result. |
||||||
|
- [[yii\base\View::EVENT_BEGIN_PAGE|EVENT_BEGIN_PAGE]]: triggered by the call of [[yii\base\View::beginPage()]] in layouts. |
||||||
|
- [[yii\base\View::EVENT_END_PAGE|EVENT_END_PAGE]]: triggered by the call of [[yii\base\View::endPage()]] in layouts. |
||||||
|
- [[yii\web\View::EVENT_BEGIN_BODY|EVENT_BEGIN_BODY]]: triggered by the call of [[yii\web\View::beginBody()]] in layouts. |
||||||
|
- [[yii\web\View::EVENT_END_BODY|EVENT_END_BODY]]: triggered by the call of [[yii\web\View::endBody()]] in layouts. |
||||||
|
|
||||||
|
For example, the following code injects the current date at the end of the page body: |
||||||
|
|
||||||
|
```php |
||||||
|
\Yii::$app->view->on(View::EVENT_END_BODY, function () { |
||||||
|
echo date('Y-m-d'); |
||||||
|
}); |
||||||
|
``` |
||||||
|
|
||||||
|
|
||||||
|
## Rendering Static Pages <a name="rendering-static-pages"></a> |
||||||
|
|
||||||
|
Static pages refer to those Web pages whose main content are mostly static without the need of accessing |
||||||
|
dynamic data pushed from controllers. |
||||||
|
|
||||||
|
You can output static pages by putting their code in the view, and then using the code like the following in a controller: |
||||||
|
|
||||||
|
```php |
||||||
|
public function actionAbout() |
||||||
|
{ |
||||||
|
return $this->render('about'); |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
If a Web site contains many static pages, it would be very tedious repeating the similar code many times. |
||||||
|
To solve this problem, you may introduce a [standalone action](structure-controllers.md#standalone-actions) |
||||||
|
called [[yii\web\ViewAction]] in a controller. For example, |
||||||
|
|
||||||
|
```php |
||||||
|
namespace app\controllers; |
||||||
|
|
||||||
|
use yii\web\Controller; |
||||||
|
|
||||||
|
class SiteController extends Controller |
||||||
|
{ |
||||||
|
public function actions() |
||||||
|
{ |
||||||
|
return [ |
||||||
|
'page' => [ |
||||||
|
'class' => 'yii\web\ViewAction', |
||||||
|
], |
||||||
|
]; |
||||||
|
} |
||||||
|
} |
||||||
|
``` |
||||||
|
|
||||||
|
Now if you create a view named `about` under the directory `@app/views/site/pages`, you will be able to |
||||||
|
display this view by the following URL: |
||||||
|
|
||||||
|
``` |
||||||
|
http://localhost/index.php?r=site/page&view=about |
||||||
|
``` |
||||||
|
|
||||||
|
The `GET` parameter `view` tells [[yii\web\ViewAction]] which view is requested. The action will then look |
||||||
|
for this view under the directory `@app/views/site/pages`. You may configure [[yii\web\ViewAction::viewPrefix]] |
||||||
|
to change the directory for searching these views. |
||||||
|
|
||||||
|
|
||||||
|
## Best Practices <a name="best-practices"></a> |
||||||
|
|
||||||
|
Views are responsible for presenting models in the format that end users desire. In general, views |
||||||
|
|
||||||
|
* should mainly contain presentational code, such as HTML, and simple PHP code to traverse, format and render data. |
||||||
|
* should not contain code that performs DB queries. Such code should be done in models. |
||||||
|
* should avoid direct access to request data, such as `$_GET`, `$_POST`. This belongs to controllers. |
||||||
|
If request data is needed, they should be pushed into views by controllers. |
||||||
|
* may read model properties, but should not modify them. |
||||||
|
|
||||||
|
To make views more manageable, avoid creating views that are too complex or contain too much redundant code. |
||||||
|
You may use the following techniques to achieve this goal: |
||||||
|
|
||||||
|
* use [layouts](#layouts) to represent common presentational sections (e.g. page header, footer). |
||||||
|
* divide a complicated view into several smaller ones. The smaller views can be rendered and assembled into a bigger |
||||||
|
one using the rendering methods that we have described. |
||||||
|
* create and use [widgets](structure-widgets.md) as building blocks of views. |
||||||
|
* create and use helper classes to transform and format data in views. |
||||||
|
|
@ -0,0 +1,136 @@ |
|||||||
|
O'zbekchaga tarjima qilish bilan qanday ishlash kerak |
||||||
|
===================================================== |
||||||
|
|
||||||
|
Yii juda ko'p tillarga tarjima qilinayabdi shu jumladan o'zbekchaga ham. Tarjima qo'llanma va habarlarni o'z ichiga oladi. |
||||||
|
|
||||||
|
Freymvork habari |
||||||
|
---------------- |
||||||
|
|
||||||
|
Ikki turdagi habarlar bor: istisnolar, qaysiki ishlab chiquvchi nazarda tutgan va ular tarjima qilinmaydi va habarlar, qaysiki foydalanuvchilarga ko'rsatiladigan. Masalan, validatsiyaning xatoliklari. |
||||||
|
|
||||||
|
Tarjimani yangilash uchun: |
||||||
|
|
||||||
|
1. Konsolda `framework` direktoriyani ochamiz, `yii message/extract messages/config.php` ni ishga tushiramiz. |
||||||
|
3. Habarlarni `framework/messages/uz/yii.php` ga ko`chiramiz. Muhimi fayllar UTF-8 kodlashda bo'lishi kerak. |
||||||
|
4. `uz` dagi tarjimalar bilan [pull request qilamiz](https://github.com/yiisoft/yii2/blob/master/docs/internals/git-workflow.md), qolgan tillarga tegmaymiz. |
||||||
|
|
||||||
|
Tarjima fayllarda massiv joylashgan. Uning kalitlari - boshlang'ich kodlar, qiymatlari - tarjima. Agar qiymat bo'sh bo'lsa habar tarjima qilinmagan hisoblanadi. Kodda boshqa uchramaydigan habarlar tarjimasi '@@' ga o'ralgan. Ayrim habarlar uchun [sonlar bilan qo'llanilishini qo'llab-quvvatlash uchun maxsus format](../guide/i18n.md) ni ishlatish zarur. |
||||||
|
|
||||||
|
Qo'llanma |
||||||
|
--------- |
||||||
|
|
||||||
|
Qo'llanamani tarjimasi `docs/<original>-uz` da joylashgan, bu yerda <original> - original direktoriyalarga mos keladi, masalan, |
||||||
|
`guide` yoki `internals`. |
||||||
|
|
||||||
|
Agar qo'llanma tarjimasi tugagan bo'lsa, build direktoriyasida konsolni ochib va quyidagini bajarib, originaldagi oxirgi tarjimadan keyingi diff o'zgarishlarni olish mumkin: |
||||||
|
|
||||||
|
``` |
||||||
|
php build translation "../docs/guide" "../docs/guide-uz" "Uzbek guide translation report" > report_guide_uz.html |
||||||
|
``` |
||||||
|
|
||||||
|
Agar composer uchun urushsa, bosh direktoriyada `composer install` ni bajaring. |
||||||
|
|
||||||
|
Tarjima qilishdan oldin hech kim shug'ullanmayotganligini tekshiring va o'zingizga [barcha tarjima qilinayotgan hujjatlarni ro'yhatini] yozib oling |
||||||
|
//Ushbu manzilni ulardan olgandan keyin o'zgartirib qo'yish kerak bo'ladi. |
||||||
|
(https://docs.google.com/spreadsheets/d/10dS7VB_3jSxUorryRlplB7nhA59e3i2vLYmTwn_1d3I/edit?usp=sharing). |
||||||
|
|
||||||
|
Barcha o'zgarishlarni quyidagi ko'rinishda olib boramiz [pull request](https://github.com/yiisoft/yii2/blob/master/docs/internals/git-workflow.md). |
||||||
|
|
||||||
|
|
||||||
|
### Umumiy qoidalar |
||||||
|
|
||||||
|
- Ko'p terminlar o'zbekchada bitta ma'noga ega emas va o'zbekchada ko'p qo'llanilmaydigandir, shu sababli agar matnda |
||||||
|
shunday terminlar uchrasa ularni birinchi bor qo'llanilgan joyida qavs ichida ingliz tilidagi varianti |
||||||
|
ko'rsatilishi kerak; (terminlarning tarjimasini qo'llanilish variantlari quyida keltirilgan); |
||||||
|
- Agar tarjima vaqtida matnning qaysidir qismi mazmuni o'zgarayotgan bo'lsa va siz uni shunday tarjima qilish |
||||||
|
kerakligiga ishonchingiz komil bo'lmayotganday tuyulsa ushbu qismni * ichiga oling(ichidagi matn qiya holatga keladi). |
||||||
|
Bu olib tashlash/to'g'rilashlar vaqtida ushbu matnlarga alohida e'tibor qaratishga imkon beradi; |
||||||
|
- Tarjima vaqtida fakt xatoliklarni qilmang! |
||||||
|
- Matnda tashqi manbalarga murojaatlar uchraydi, agar murojaat terminni izohlash maqolasiga olib boradigan bo'lsa, u holda |
||||||
|
o'zbekchada tarjimasi bo'r bo'lgan vaziyatda o'zbekchasiga murojaat qilinadi. |
||||||
|
Masalan `http://en.wikipedia.org/wiki/Captcha` → `http://uz.wikipedia.org/wiki/Captcha`. |
||||||
|
- Sharhlar kodda tarjima qilinadi, agarda birinchi holatdagi mazmunini o'zgartirmasa; Matndagi vaqtinchalik sharhlarni |
||||||
|
imkon qadar faqat *lokal*da ishlatish kerak! Aks holda uni reliz ga tushib qolish ehtimoli bor; |
||||||
|
- Bo'limlarni tarjima qilish vaqtida `README.md` dagi tarjimani olib ketamiz; |
||||||
|
- Shaxsiy qo'shimcha-sharhlarni qo'shish imkoni bor, lekin xaosdan qochish uchun original bitta bo'lishi kerak. Bunga zarurat vaqtida sharh oxiriga |
||||||
|
"tar. shar." ni qo'shish kerak; |
||||||
|
- Hujjatni umumiy to'g'rilashni o'tkazgandan so'ng mustaqil ravishda faqat ushbu bo'limga tegsihli bo'lgan grammatikadagi, fakt xatoliklardagi o'zgarishlarni kiritish talab darajasida tavsiya etiladi. Boshqa holatlarda gaplarni to'g'rilash, yaxshilash uchun va zarur hollarda o'zgarishlarni markazlashgan tarzda barcha bo'limlar uchun amalga oshirish uchun ularni tahlilga qo'yish zarur. |
||||||
|
|
||||||
|
|
||||||
|
### Qo'llanma strukturasi |
||||||
|
|
||||||
|
Tarjima qilish vaqtida hujjatning struktura birligini to'g'ri nomlash muhim. Quyida keltirilgan strukturaga amal qilamiz : |
||||||
|
|
||||||
|
- Bob 1 |
||||||
|
- Bo'lim 1 |
||||||
|
- Bo'lim 2 |
||||||
|
- Qism bo'lim 1 |
||||||
|
- ... |
||||||
|
- Bo'lim N |
||||||
|
- Bob 2 |
||||||
|
- ... |
||||||
|
- Bob N |
||||||
|
|
||||||
|
### Maxsus habarlarni tarjimasi |
||||||
|
|
||||||
|
- Tip → Ko'rsatma |
||||||
|
- Note → Eslatma |
||||||
|
- Info → Ma'lumot |
||||||
|
|
||||||
|
### Rasmlarni tarjima qilish |
||||||
|
|
||||||
|
Qo'llanma uchun rasmlar `images` qism katalogida joylashgan. Ularning barchasi [yED](http://www.yworks.com/en/products_yed_about.html) da yaratilgan. |
||||||
|
Zarurat tug'ilgan vaqtda fayl tarjima qilinayotgan katalogning `images` katalogiga nusxalanadi va tarjima qilinib png formatida saqlanadi. |
||||||
|
|
||||||
|
Rasmlardagi yozuvlar tarjima qilinadi. |
||||||
|
|
||||||
|
### Grammatika |
||||||
|
|
||||||
|
|
||||||
|
Oxirgi variantni tashlashdan oldin uni umumiy stilini, orfografiyasini, punktlarini tekshiring. Tarjimani o'zbek tili uchun orfografiyani Wordda tekshirish imkoni bo'lmasada uning yordamida tayyorlashingiz mumkin; |
||||||
|
|
||||||
|
### Terminlar ro'yhati |
||||||
|
|
||||||
|
- action — amal. |
||||||
|
- active record — tarjimasiz. |
||||||
|
- attach handler — «qayta ishlovchini tayinlash». |
||||||
|
- attribute of the model — model atributi. |
||||||
|
- camel case — tarjimasiz. |
||||||
|
- customization — (nozik) sozlash |
||||||
|
- column — ustun (agar MO haqida gap ketayotgan bo'lsa). |
||||||
|
- content — tashkil etuvchilari. |
||||||
|
- controller — kontrollyor. |
||||||
|
- debug (mode) — kod sozlash (tartibi) (production mode ga qarang). |
||||||
|
- eager loading — ziqna yuklash uslubi/ziqna yuklash (lazy loading ga qarang). |
||||||
|
- PHP extension — PHP kengaytmasi. |
||||||
|
- field (of the table) — jadval (yoki atribut) maydoni. |
||||||
|
- framework — freymvork. |
||||||
|
- front-controller — front-kontrollyor. |
||||||
|
- getter — getter. |
||||||
|
- (event) handler — qayta ishlovchi (hodisa). |
||||||
|
- hash — xesh. |
||||||
|
- helper - yordamchi. |
||||||
|
- id — qiymatlovchi(identifikatsiyalovchi). |
||||||
|
- instance — nusxa. |
||||||
|
- lazy loading — chetga olingan yuklash (qanday kerak bo'lsa shunday yuklasymiz va erta emas). |
||||||
|
- method — metod (obektniki) //Diqqat! Obekt/klaslarda funksiyasi yo'q, faqat metodlari bor. |
||||||
|
- model — model, ma`lumotlar modeli. |
||||||
|
- model form — formalar modeli. |
||||||
|
- parameter — parametr (metod yoki funksiyada va lekin klasda emas). |
||||||
|
- to parse — qayta ishlash, agar *kontekst* tushunarsiz bo'lsa *parsing* qilish. |
||||||
|
- placeholder — marker. |
||||||
|
- production (mode) — ishlab chiqarish (rejimi) (см. debug mode). |
||||||
|
- property — xususiyati (obekt). |
||||||
|
- to render — *render* qilish, formallashtirish. |
||||||
|
- related, relation — bog'langan, bog'lanish. |
||||||
|
- resolve request — so'rovni oldindan qayta ishlash. |
||||||
|
- route — marshrut. |
||||||
|
- row (of the table) — satr(jadvallarniki). |
||||||
|
- setter — setter. |
||||||
|
- tabular input — tabli kiritish. |
||||||
|
- to validate — tekshirish. |
||||||
|
- valid — mos. |
||||||
|
- validator — validator. |
||||||
|
- validator class — validator klasi. |
||||||
|
- view — namoyish. |
||||||
|
- query builder — so'rovlar konstruktori. |
Loading…
Reference in new issue