Commit 35a3a3e1 by Qiang Xue

Merge pull request #4237 from yii2-chinesization/master

docs/guide/concept-components.md typo and docs/guide-zh-CN/* adjusted.
parents 038d5a53 e121091f
......@@ -60,7 +60,7 @@ Yii 2.0 权威指南
* **已定稿** [属性(Property)](concept-properties.md)
* **已定稿** [事件(Event)](concept-events.md)
* **已定稿** [行为(Behavior)](concept-behaviors.md)
* **已定稿** [配置(Configs)](concept-configurations.md)
* **已定稿** [配置(Configurations)](concept-configurations.md)
* **已定稿** [类自动加载(Autoloading)](concept-autoloading.md)
* **已定稿** [别名(Alias)](concept-alias.md)
* **已定稿** [服务定位器(Service Locator)](concept-service-locator.md)
......
类自动加载(Autoloading)
=================
Yii 依靠[类自动加载机制(http://www.php.net/manual/en/language.oop5.autoload.php)来定位和包含所需的类文件。它提供一个高性能且完美支持[PSR-4 标准](https://github.com/php-fig/fig-standards/blob/master/proposed/psr-4-autoloader/psr-4-autoloader.md)[中文汉化](https://github.com/hfcorriez/fig-standards/blob/zh_CN/%E6%8E%A5%E5%8F%97/PSR-4-autoloader.md))的自动加载器。该自动加载器会在包含 `Yii.php` 文件时安装好。
Yii 依靠[类自动加载机制(http://www.php.net/manual/en/language.oop5.autoload.php)来定位和包含所需的类文件。它提供一个高性能且完美支持[PSR-4 标准](https://github.com/php-fig/fig-standards/blob/master/proposed/psr-4-autoloader/psr-4-autoloader.md)[中文汉化](https://github.com/hfcorriez/fig-standards/blob/zh_CN/%E6%8E%A5%E5%8F%97/PSR-4-autoloader.md))的自动加载器。该自动加载器会在引入框架文件 `Yii.php` 时安装好。
> 注意:为了简化叙述,本篇文档中我们只会提及类的自动加载。不过,要记得文中的描述同样也适用于接口和Trait(特质)的自动加载哦。
......@@ -9,7 +9,7 @@ Yii 依靠[类自动加载机制(http://www.php.net/manual/en/language.oop5.auto
使用 Yii 自动加载器 <a name="using-yii-autoloader"></a>
------------------------
要使用 Yii 的类自动加载器,你需要在创建和命名尼德类的时候遵循两个简单的规则:
要使用 Yii 的类自动加载器,你需要在创建和命名类的时候遵循两个简单的规则:
* 每个类都必须置于命名空间之下 (比如 `foo\bar\MyClass`)。
* 每个类都必须保存为单独文件,且其完整路径能用以下算法取得:
......@@ -19,21 +19,18 @@ Yii 依靠[类自动加载机制(http://www.php.net/manual/en/language.oop5.auto
$classFile = Yii::getAlias('@' . str_replace('\\', '/', $className) . '.php');
```
举例来说,若某个类名为 `foo\bar\MyClass`,对应类的文件路径[别名](concept-aliases.md)会是
`@foo/bar/MyClass.php`。为了让该别名能被正确解析为文件路径,`@foo``@foo/bar`
举例来说,若某个类名为 `foo\bar\MyClass`,对应类的文件路径[别名](concept-aliases.md)会是 `@foo/bar/MyClass.php`。为了让该别名能被正确解析为文件路径,`@foo``@foo/bar`
中的一个必须是[根别名](concept-aliases.md#defining-aliases)
当我们使用[基本应用模版](start-basic.md)时,你可以把你的类放置在顶级命名空间 `app` 下,这样它们就可以被 Yii
自动加载,而无需定义一个新的别名。这是因为 `@app` 本身是一个[预定义别名](concept-aliases.md#predefined-aliases),且类似于 `app\components\MyClass` 这样的类名,基于我们刚才所提到的算法,可以正确解析出 `AppBasePath/components/MyClass.php` 路径。
当我们使用[基本应用模版](start-basic.md)时,可以把你的类放置在顶级命名空间 `app` 下,这样它们就可以被 Yii 自动加载,而无需定义一个新的别名。这是因为 `@app` 本身是一个[预定义别名](concept-aliases.md#predefined-aliases),且类似于 `app\components\MyClass` 这样的类名,基于我们刚才所提到的算法,可以正确解析出 `AppBasePath/components/MyClass.php` 路径。
[高级应用模版](tutorial-advanced-app.md)里,每一逻辑层级会使用他自己的根别名。比如,在前端层,会使用 `@frontend`
而后端层会使用 `@backend`。因此,你可以把前端的类放在 `frontend` 命名空间,而后端的类放在 `backend`。 这样这些类就可以被 Yii 自动加载了。
[高级应用模版](tutorial-advanced-app.md)里,每一逻辑层级会使用他自己的根别名。比如,前端层会使用 `@frontend` 而后端层会使用 `@backend`。因此,你可以把前端的类放在 `frontend` 命名空间,而后端的类放在 `backend`。 这样这些类就可以被 Yii 自动加载了。
类映射表(Class Map) <a name="class-map"></a>
---------
Yii 类自动加载器支持 **类映射表** 功能,该功能会建立一个从类的名字到类文件路径的映射。当自动加载器加载一个文件时,他首先检查映射表里有没有该类。如果有,对应的文件路径就直接加载了,省掉了进一步的检查。它可以让类的自动加载变得炒鸡快!事实上,所有的 Yii 核心类都是这样加载的。
Yii 类自动加载器支持**类映射表**功能,该功能会建立一个从类的名字到类文件路径的映射。当自动加载器加载一个文件时,他首先检查映射表里有没有该类。如果有,对应的文件路径就直接加载了,省掉了进一步的检查。这让类的自动加载变得超级快。事实上所有的 Yii 核心类都是这样加载的。
你可以用 `Yii::$classMap` 方法向映射表中添加类,
......@@ -47,10 +44,9 @@ Yii::$classMap['foo\bar\MyClass'] = 'path/to/MyClass.php';
用其他自动加载器 <a name="using-other-autoloaders"></a>
-----------------------
因为 Yii 完全支持 Composer 成为一个依赖包管理器,所以推荐你也同时安装 Composer 的自动加载器,如果你用了一些自带自动加载器的第三方类库,你应该也安装下它们。
因为 Yii 完全支持 Composer 管理依赖包,所以推荐你也同时安装 Composer 的自动加载器,如果你用了一些自带自动加载器的第三方类库,你应该也安装下它们。
在你同时使用其他自动加载器和 Yii 自动加载器的时候,你应该在其他自动加载器安装成功 **之后**,再包含`Yii.php`
文件。这将使 Yii 成为第一个响应任何类自动加载请求的自动加载器。举例来说,以下代码提取自[基本应用模版](start-basic.md)[入口脚本](structure-entry-scripts.md) 。第一行安装了 Composer 的自动加载器,第二行才是 Yii 的自动加载器:
当你同时使用其他自动加载器和 Yii 自动加载器时,应该在其他自动加载器安装成功**之后**,再包含 `Yii.php` 文件。这将使 Yii 成为第一个响应任何类自动加载请求的自动加载器。举例来说,以下代码提取自[基本应用模版](start-basic.md)[入口脚本](structure-entry-scripts.md) 。第一行安装了 Composer 的自动加载器,第二行才是 Yii 的自动加载器:
```php
require(__DIR__ . '/../vendor/autoload.php');
......
行为(Behavior)
=========
行为(Behavior)是 [[yii\base\Behmixinsavior]] 或其子类的实例。 Behavior 也被称为
[Mixin(Mix In可以理解为包含若干个类的部分方法和属性的混合类,英文维基)](http://en.wikipedia.org/wiki/Mixin),允许你增强已有
[[yii\base\Component|组件]] 类的功能,而无需改变类的继承结构。当一个行为被配属到组件之上是,他会向组件“注入”他的属性与方法,就好像这些方法原本就定义在组件里一样。此外,行为能响应由组件所触发的[事件](basic-events.md),从而自定义或调整组件内默认的代码执行。
> 译者注:mixin直译为‘混入’,trait直译为‘特质’,为避免翻译上的问题,今后我们还是采用英文术语。
使用行为 <a name="using-behaviors"></a>
---------------
要使用行为,你首先需要把它配属到某个[[yii\base\Component|组件]]上。我们会在接下来的章节内讲解如何配属一个行为。
行为被配属到组件之后,它的用法是很直截了当的。
可以通过行为所配属的组件,访问它的 *public* 成员变量或由 getter 和/或 setter 定义的[属性](concept-properties.md),就像这样:
```php
// "prop1" 是一个定义在行为类中的属性
echo $component->prop1;
$component->prop1 = $value;
```
与之相似的,你也可以调用行为类的 *public* 方法,
```php
// foo() 是一个定义在行为类中的公共方法
$component->foo();
```
如你所见,尽管 `$component` 并没有定义 `prop1``bar()`,它们依旧好像是组件自身定义的一部分一样。
如果两个行为都定义了一样的属性或方法,并且它们都配属到同一个组件,那么先附加上的行为在属性或方法被访问时就有优先权。
当行为配属到组件时可以关联一个行为名。此时就能使用这个名称来访问行为对象,如下所示:
```php
$behavior = $component->getBehavior('myBehavior');
```
也能获取组件所配属的所有行为:
```php
$behaviors = $component->getBehaviors();
```
配属行为 <a name="attaching-behaviors"></a>
-------------------
可以选择静态或动态地配属行为到 [[yii\base\Component|组件]]。在具体实践中,前者更常见。
要静态配属行为,重写目标组件类的 [[yii\base\Component::behaviors()|behaviors()]] 方法即可。如:
```php
namespace app\models;
use yii\db\ActiveRecord;
use app\components\MyBehavior;
class User extends ActiveRecord
{
public function behaviors()
{
return [
// 匿名行为 => 行为类名
MyBehavior::className(),
// 命名行为 => 行为类名
'myBehavior2' => MyBehavior::className(),
// 匿名行为 => 配置数组
[
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
],
// 命名行为 => 配置数组
'myBehavior4' => [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
]
];
}
}
```
[[yii\base\Component::behaviors()|behaviors()]] 方法应该返回一个包含所有行为[配置信息](concept-configurations.md)的列表。每个行为的配置信息可以是行为的类名也可以是其配置数组。
通过为行为配置信息指定相应的键名,可以给行为关联一个名称。这种行为称为**命名行为**。在上例中存在两个命名行为:`myBehavior2``myBehavior4` 。同理如果行为没有关联名称就是**匿名行为**
要动态地配属行为,只需调用目标组件的 [[yii\base\Component::attachBehavior()]] 方法即可,如:
```php
use app\components\MyBehavior;
// 配属一个行为对象
$component->attachBehavior('myBehavior1', new MyBehavior);
// 配属行为类
$component->attachBehavior('myBehavior2', MyBehavior::className());
// 配属一个配置数组
$component->attachBehavior('myBehavior3', [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
]);
```
你也可以通过 [[yii\base\Component::attachBehaviors()]] 方法一次性配属多个行为。比如:
```php
$component->attachBehaviors([
'myBehavior1' => new MyBehavior, // 一个命名行为
MyBehavior::className(), // 一个匿名行为
]);
```
如下所示,你也可以通过[配置数组](concept-configurations.md)配属行为。更多细节,请参考[配置(Configs)](concept-configurations.md#configuration-format)章节。
```php
[
'as myBehavior2' => MyBehavior::className(),
'as myBehavior3' => [
'class' => MyBehavior::className(),
'prop1' => 'value1',
'prop2' => 'value2',
],
]
```
拆卸行为 <a name="detaching-behaviors"></a>
-------------------
要拆卸行为,可以用行为的键名调用 [[yii\base\Component::detachBehavior()]] 方法:
```php
$component->detachBehavior('myBehavior1');
```
也可以一次性拆卸掉**所有**的行为:
```php
$component->detachBehaviors();
```
定义行为 <a name="defining-behaviors"></a>
------------------
要定义一个行为,只需创建新类,继承 [[yii\base\Behavior]] 或其子类。比如,
```php
namespace app\components;
use yii\base\Model;
use yii\base\Behavior;
class MyBehavior extends Behavior
{
public $prop1;
private $_prop2;
public function getProp2()
{
return $this->_prop2;
}
public function setProp2($value)
{
$this->_prop2 = $value;
}
public function foo()
{
// ...
}
}
```
以上代码定义了行为类 `app\components\MyBehavior` 并为要附加行为的组件提供了两个属性 `prop1``prop2` 和一个方法 `foo()`。注意,属性 `prop2` 是通过 getter `getProp2()` 和 setter `setProp2()` 定义的。能这样用是因为 [[yii\base\Behavior]] 的祖先类是 [[yii\base\Object]],此祖先类支持用 getter 和 setter 方法定义[属性](concept-properties.md)
在行为类之中,你可以通过 [[yii\base\Behavior::owner]] 属性访问行为的组件。
如果你的行为需要响应其所配属的组件中触发的事件,它需要重写 [[yii\base\Behavior::events()]] 方法。像这样,
```php
namespace app\components;
use yii\db\ActiveRecord;
use yii\base\Behavior;
class MyBehavior extends Behavior
{
// ...
public function events()
{
return [
ActiveRecord::EVENT_BEFORE_VALIDATE => 'beforeValidate',
];
}
public function beforeValidate($event)
{
// ...
}
}
```
[[yii\base\Behavior::events()|events()]] 方法需返回一个事件列表和它们相应的处理器。上例声明了 [[yii\db\ActiveRecord::EVENT_BEFORE_VALIDATE|EVENT_BEFORE_VALIDATE]] 事件和它的处理器 `beforeValidate()` 。当指定一个事件处理器时,要使用以下格式之一:
* 一条指向行为类的方法名的字符串,如上例所示;
* 一个包含对象或类名,以及方法名的数组,如 `[$object, 'methodName']`
* 一个匿名函数
事件处理器方法的特征格式如下,其中 `$event` 指向事件参数。关于事件的更多细节请参考[事件](concept-events.md)
```php
function ($event) {
}
```
使用 `TimestampBehavior` <a name="using-timestamp-behavior"></a>
-------------------------
最后让我们来看看 [[yii\behaviors\TimestampBehavior]] 作为具体实践案例,这个行为支持在 [[yii\db\ActiveRecord|Active Record]] 保存时自动更新它的时间戳类型的 attribute(特性)。
首先,配属这个行为到目标 [[yii\db\ActiveRecord|Active Record]] 类:
```php
namespace app\models\User;
use yii\db\ActiveRecord;
use yii\behaviors\TimestampBehavior;
class User extends ActiveRecord
{
// ...
public function behaviors()
{
return [
[
'class' => TimestampBehavior::className(),
'attributes' => [
ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'],
ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'],
],
],
];
}
}
```
以上行为的配置指定了下面的两条规则:
* 当记录插入时,行为应该要当前时间戳赋值给 `created_at``updated_at` 属性;
* 当记录更新时,行为应该要当前时间戳赋值给 `updated_at` 属性。
放置上述代码之后,如果有一个 `User` 对象且需要保存,你会发现它的 `created_at``updated_at` 属性已经自动填充了当前时间戳:
```php
$user = new User;
$user->email = 'test@example.com';
$user->save();
echo $user->created_at; // shows the current timestamp
```
[[yii\behaviors\TimestampBehavior|TimestampBehavior]] 同时提供一个很好用的名为 [[yii\behaviors\TimestampBehavior::touch()|touch()]] 的方法,该方法会把当前时间戳赋值给指定 attribute 并将其存入数据库:
```php
$user->touch('login_time');
```
与 Traits 的对比 <a name="comparison-with-traits"></a>
----------------------
尽管行为在 "注入" 属性和方法到主类方面类似于 [traits](http://www.php.net/traits) ,它们在很多方面却不相同。如上所述,它们各有利弊。它们更像是互补的而不是相互替代。
### Behavior 的优势 <a name="pros-for-behaviors"></a>
Behavior 类像普通类支持继承。另一方面,Traits 可以视之为一种 PHP 提供语言级支持的复制粘贴功能,它不支持继承。
Behavior 无须修改组件类就可动态配属到组件或拆除。要使用 trait,就必须修改引用它的类本身。
Behavior 是可配置的而 traits 不行。
Behaviors 可以通过响应事件来自定义组件代码的执行。
当不同 Behavior 附加到同一组件产生命名冲突时,这个冲突会以“先附加行为的优先”的方式自动解决。而由不同 traits 引发的命名冲突需要通过手工重命名冲突属性或方法来解决。
### Traits 的优势 <a name="pros-for-traits"></a>
Trait 比 behaviors 性能好很多很多,因为行为本身就是对象,他需要占用双倍的时间和内存。
作为语言架构的一部分,IDE 对 Trait 更加友好
组件(Component)
==========
组件是 Yii 应用的主要基石之一。组件是 [[yii\base\Component]] 类或其子类的实例。三个它能提供,其他类不能的主要功能有:
组件是 Yii 应用的主要基石。是 [[yii\base\Component]] 类或其子类的实例。三个用以区分它和其它类的主要功能有:
* [属性(Property)](concept-properties.md)
* [事件(Event)](concept-events.md)
* [行为(Behavior)](concept-behaviors.md)
或单独使用,或彼此配合,总之这些功能的应用让 Yii 的类变得更加灵活和易用。就拿一个叫 [[yii\jui\DatePicker|日期选择器]]
的小部件来举例吧,这是个方便你在 [视图](structure-view.md) 中生成一个交互式日期选择器的 UI 组件,你们自己看这样的调用方式是不是很屌:
或单独使用,或彼此配合,这些功能的应用让 Yii 的类变得更加灵活和易用。以小部件 [[yii\jui\DatePicker|日期选择器]] 来举例,这是个方便你在 [视图](structure-view.md) 中生成一个交互式日期选择器的 UI 组件:
```php
use yii\jui\DatePicker;
......@@ -22,17 +21,15 @@ echo DatePicker::widget([
]);
```
正因为这个小部件继承自 [[yii\base\Component]],所以它的各项属性改写起来就会很容易……
这个小部件继承自 [[yii\base\Component]],它的各项属性改写起来会很容易。
虽然组件非常屌爆,但是他们比常规的对象(Object)要稍微重量级一点点,因为他们要使用额外的内存和 CPU 时间来支持这些功能,尤其是
[事件](concept-events.md)[行为](concept-behaviors.md) 这俩货。如果你的组件不需要这两项功能,你可以考虑继承 [[yii\base\Object]]
而不是 [[yii\base\Component]]。这样一来,你的组件就可以像普通 PHP 对象一样高效了。同时,它还依旧支持[属性(Property)](concept-properties.md)功能!
正是因为组件功能的强大,他们比常规的对象(Object)稍微重量级一点,因为他们要使用额外的内存和 CPU 时间来处理 [事件](concept-events.md)[行为](concept-behaviors.md) 。如果你不需要这两项功能,可以继承 [[yii\base\Object]] 而不是 [[yii\base\Component]]。这样组件可以像普通 PHP 对象一样高效,同时还支持[属性(Property)](concept-properties.md)功能。
你继承 [[yii\base\Component]] 或 [[yii\base\Object]] 时,我们推荐你使用如下的编码风格:
继承 [[yii\base\Component]] 或 [[yii\base\Object]] 时,推荐你使用如下的编码风格:
- 若你需要重写构造器(Constructor),指定一个 `$config` 参数,作为构造器的 *最后一个* 参数,然后把它传递给父类的构造器。(译者注:`parent::__construct($config = [])`,用于把属性配置信息传递回父类。可选参数放最后是 PSR 的规范之一)
- 永远在你重写的构造*结尾处* 调用一下父类的构造器
- 如果你重写了 [[yii\base\Object::init()]] 方法,请确保你在 `init` 方法的 *开头处* 调用了父类的 `init` 方法。
- 若你需要重写构造方法(Constructor),传入 `$config` 作为构造器方法**最后一个**参数,然后把它传递给父类的构造方法。
- 永远在你重写的构造方法**结尾处**调用一下父类的构造方法
- 如果你重写了 [[yii\base\Object::init()]] 方法,请确保你在 `init` 方法的**开头处**调用了父类的 `init` 方法。
例子如下:
......@@ -62,7 +59,7 @@ class MyClass extends Object
}
```
另外,为了让你的组件可以在创建实例时[能被正确配置](concept-configurations.md),请遵照以下操作流程。举例
另外,为了让组件可以在创建实例时[能被正确配置](concept-configurations.md),请遵照以下操作流程
```php
$component = new MyClass(1, 2, ['prop1' => 3, 'prop2' => 4]);
......@@ -74,14 +71,14 @@ $component = \Yii::createObject([
], [1, 2]);
```
> 补充:虽然调用 [[Yii::createObject()]] 的方法看起来更加复杂,但是这主要是因为它更加灵活强大,这货是基于高大上的[依赖注入容器](concept-di-container.md)的一种实现
> 补充:尽管调用 [[Yii::createObject()]] 的方法看起来更加复杂,但这主要因为它更加灵活强大,它是基于[依赖注入容器](concept-di-container.md)实现的
每个 [[yii\base\Object]] 类的生命周期是这样度过的
[[yii\base\Object]] 类执行时的生命周期如下
1. 构造内的预初始化过程。你可以在这儿给各属性设置缺省值。
2. 通过 `$config` 配置对象。配置的过程可能会覆盖掉先前在构造内设置的默认值。
3.[[yii\base\Object::init()|init()]] 方法内进行初始化的收尾工作。你可以通过重写此方法,进行一些良品检验呀,属性的标准化呀,之类的事情
1. 构造方法内的预初始化过程。你可以在这儿给各属性设置缺省值。
2. 通过 `$config` 配置对象。配置的过程可能会覆盖掉先前在构造方法内设置的默认值。
3.[[yii\base\Object::init()|init()]] 方法内进行初始化后的收尾工作。你可以通过重写此方法,进行一些良品检验,属性的初始化之类的工作
4. 对象方法调用。
前三步都是在对象的构造器内发生的。这意味着一旦你获得了一个对象实例,那么它已经初始化为了一个妥妥的状态,放心大胆的用吧
前三步都是在对象的构造方法内发生的。这意味着一旦你获得了一个对象实例,那么它就已经初始化就绪可供使用
配置
=============
在 Yii 中,创建新对象和初始化已存在对象时广泛使用配置。配置通常包含被创建对象的类名和一组将要赋值给对象[属性](concept-properties.md)的初始值。还可能包含一组将被附加到对象[事件](concept-events.md)上的句柄。和一组将被附加到对象上的[行为](concept-behaviors.md)
以下代码中的配置被用来创建并初始化一个数据库连接:
```php
$config = [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=127.0.0.1;dbname=demo',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
];
$db = Yii::createObject($config);
```
[[Yii::createObject()]] 方法接受一个配置并根据配置中指定的类名创建对象。对象实例化后,剩余的参数被用来初始化对象的属性,事件处理和行为。
对于已存在的对象,可以使用 [[Yii::configure()]] 方法根据配置去初始化其属性,就像这样:
```php
Yii::configure($object, $config);
```
请注意,如果配置一个已存在的对象,那么配置数组中不应该包含指定类名的 `class` 元素。
## 配置的格式 <a name="configuration-format"></a>
一个配置的格式可以描述为以下形式:
```php
[
'class' => 'ClassName',
'propertyName' => 'propertyValue',
'on eventName' => $eventHandler,
'as behaviorName' => $behaviorConfig,
]
```
其中
* `class` 元素指定了将要创建的对象的完全限定类名。
* `propertyName` 元素指定了对象属性的初始值。键名是属性名,值是该属性对应的初始值。只有公共成员变量以及通过 getter/setter 定义的[属性](concept-properties.md)可以被配置。
* `on eventName` 元素指定了附加到对象[事件](concept-events.md)上的句柄是什么。请注意,数组的键名由 `on ` 前缀加事件名组成。请参考[事件](concept-events.md)章节了解事件句柄格式。
* `as behaviorName` 元素指定了附加到对象的[行为](concept-behaviors.md)。请注意,数组的键名由 `as ` 前缀加行为名组成。`$behaviorConfig` 表示创建行为的配置信息,格式与我们现在总体叙述的配置格式一样。
下面是一个配置了初始化属性值,事件句柄和行为的示例:
```php
[
'class' => 'app\components\SearchEngine',
'apiKey' => 'xxxxxxxx',
'on search' => function ($event) {
Yii::info("搜索的关键词: " . $event->keyword);
},
'as indexer' => [
'class' => 'app\components\IndexerBehavior',
// ... 初始化属性值 ...
],
]
```
## 使用配置
Yii 中的配置可以用在很多场景。本章开头我们展示了如何使用 [[Yii::creatObject()]] 根据配置信息创建对象。本小节将介绍配置的两种主要用法 —— 配置应用与配置小部件。
### 应用的配置 <a name="application-configurations"></a>
[应用](structure-applications.md)的配置可能是最复杂的配置之一。因为 [[yii\web\Application|application]] 类拥有很多可配置的属性和事件。更重要的是它的 [[yii\web\Application::components|components]] 属性可以接收配置数组并通过应用注册为组件。以下是一个针对[基础应用模板](start-basic.md)的应用配置概要:
```php
$config = [
'id' => 'basic',
'basePath' => dirname(__DIR__),
'extensions' => require(__DIR__ . '/../vendor/yiisoft/extensions.php'),
'components' => [
'cache' => [
'class' => 'yii\caching\FileCache',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
],
'log' => [
'class' => 'yii\log\Dispatcher',
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
],
],
],
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=stay2',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
],
];
```
配置中没有 `class` 键的原因是这段配置应用在下面的入口脚本中,类名已经指定了。
```php
(new yii\web\Application($config))->run();
```
更多关于应用 `components` 属性配置的信息可以查阅[应用](structure-applications.md)以及[服务定位器](concept-service-locator.md)章节。
### 小部件的配置 <a name="widget-configurations"></a>
使用[小部件](structure-widgets.md)时,常常需要配置以便自定义其属性。 [[yii\base\Widget::widget()]] 和 [[yii\base\Widget::beginWidget()]] 方法都可以用来创建小部件。它们可以接受配置数组:
```php
use yii\widgets\Menu;
echo Menu::widget([
'activateItems' => false,
'items' => [
['label' => 'Home', 'url' => ['site/index']],
['label' => 'Products', 'url' => ['product/index']],
['label' => 'Login', 'url' => ['site/login'], 'visible' => Yii::$app->user->isGuest],
],
]);
```
上述代码创建了一个小部件 `Menu` 并将其 `activateItems` 属性初始化为 false。`item` 属性也配置成了将要显示的菜单条目。
请注意,代码中已经给出了类名 `yii\widgets\Menu',配置数组**不应该**再包含 `class` 键。
## 配置文件 <a name="configuration-files"></a>
当配置的内容十分复杂,通用做法是将其存储在一或多个 PHP 文件中,这些文件被称为**配置文件**。一个配置文件返回的是 PHP 数组。例如,像这样把应用配置信息存储在名为 `web.php` 的文件中:
```php
return [
'id' => 'basic',
'basePath' => dirname(__DIR__),
'extensions' => require(__DIR__ . '/../vendor/yiisoft/extensions.php'),
'components' => require(__DIR__ . '/components.php'),
];
```
鉴于 `components` 配置也很复杂,上述代码把它们存储在单独的 `components.php` 文件中,并且包含在 `web.php` 里。`components.php` 的内容如下:
```php
return [
'cache' => [
'class' => 'yii\caching\FileCache',
],
'mailer' => [
'class' => 'yii\swiftmailer\Mailer',
],
'log' => [
'class' => 'yii\log\Dispatcher',
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [
[
'class' => 'yii\log\FileTarget',
],
],
],
'db' => [
'class' => 'yii\db\Connection',
'dsn' => 'mysql:host=localhost;dbname=stay2',
'username' => 'root',
'password' => '',
'charset' => 'utf8',
],
];
```
仅仅需要 “require”,就可以取得一个配置文件的配置内容,像这样:
```php
$config = require('path/to/web.php');
(new yii\web\Application($config))->run();
```
## 默认配置 <a name="default-configurations"></a>
[[Yii::createObject()]] 方法基于[依赖注入容器](concept-di-container.md)实现。使用 [[Yii::creatObject()]] 创建对象时,可以附加一系列**默认配置**到指定类的任何实例。默认配置还可以在[入口脚本](runtime-bootstrapping.md)中调用 `Yii::$container->set()` 来定义。
例如,如果你想自定义 [[yii\widgets\LinkPager]] 小部件,以便让分页器最多只显示 5 个翻页按钮(默认是 10 个),你可以用下述代码实现:
```php
\Yii::$container->set('yii\widgets\LinkPager', [
'maxButtonCount' => 5,
]);
```
不使用默认配置的话,你就得在任何使用分页器的地方,都配置 `maxButtonCount` 的值。
## 环境常量 <a name="environment-constants"></a>
配置经常要随着应用运行的不同环境更改。例如在开发环境中,你可能使用名为 `mydb_dev` 的数据库,而生产环境则使用 `mydb_prod` 数据库。为了便于切换使用环境,Yii 提供了一个定义在入口脚本中的 `YII_ENV` 常量。如下:
```php
defined('YII_ENV') or define('YII_ENV', 'dev');
```
你可以把 `YII_ENV` 定义成以下任何一种值:
- `prod`:生产环境。常量 `YII_ENV_PROD` 将被看作 true。如果你没修改过,这就是 `YII_ENV` 的默认值。
- `dev`:开发环境。常量 `YII_ENV_DEV` 将被看作 true。
- `test`:测试环境。常量 `YII_ENV_TEST` 将被看作 true。
有了这些环境常量,你就可以根据当下应用运行环境的不同,进行差异化配置。例如,应用可以包含下述代码只在开发环境中开启[调试工具](tool-debugger.md)。
```php
$config = [...];
if (YII_ENV_DEV) {
// 根据 `dev` 环境进行的配置调整
$config['bootstrap'][] = 'debug';
$config['modules']['debug'] = 'yii\debug\Module';
}
return $config;
```
\ No newline at end of file
属性(Property)
==========
PHP 中,类的成员变量也被称为 *属性(properties)*。它们是类定义的一部分,并用来表现一个实例的状态(比如,用于区分某类的各个实例)。在具体实践中,你会常常想用一个稍微特殊些的方法实现属性的读写。例如,如果你想要去掉赋值给 `label` 属性的字符串前后的空格,就可以用以下代码实现:
在 PHP 中,类的成员变量也被称为**属性(properties)**。它们是类定义的一部分,用来表现一个实例的状态(也就是区分类的不同实例)。在具体实践中,常常会想用一个稍微特殊些的方法实现属性的读写。例如,要对 `label` 属性执行 trim 操作,可以用以下代码实现:
```php
$object->label = trim($label);
```
以上代码的缺点是,只要需要修改 `label` 属性就必须再次调用 `trim()` 函数。若将来提出了对 `label`
属性的新要求,比如首字母大写等,你就被迫必须修改所有给 `label`
属性赋值的代码。这种代码的重复会导致 bug,且这这种实践显然是你想要尽力避免的。
上述代码的缺点是只要修改 `label` 属性就必须再次调用 `trim()` 函数。若将来需要用其它方式处理 `label` 属性,比如首字母大写,就不得不修改所有给 `label` 属性赋值的代码。这种代码的重复会导致 bug,这种实践显然需要尽可能避免。
为解决该问题,Yii 引入了一个名为 [[yii\base\Object]] 的基类,它支持基于类内的 *getter**setter*
(读取器和设定器)方法来定义属性。如果某类需要支持这个特性,只需要继承自 [[yii\base\Object]] 或其子类即可。
为解决该问题,Yii 引入了一个名为 [[yii\base\Object]] 的基类,它支持基于类内的 **getter****setter**(读取器和设定器)方法来定义属性。如果某类需要支持这个特性,只需要继承 [[yii\base\Object]] 或其子类即可。
> 补充:几乎每个 Yii 框架的核心类都继承自 [[yii\base\Object]] 或其子类。这意味着无论何时在核心类中见到一个
getter 或 setter 方法,都可以像调用属性一样调用它。
> 补充:几乎每个 Yii 框架的核心类都继承自 [[yii\base\Object]] 或其子类。这意味着只要在核心类中见到 getter 或 setter 方法,就可以像调用属性一样调用它。
getter 方法是方法名以 `get` 开头的方法,而 setter 方法名以 `set` 开头。方法名中 `get``set` 后面的部分就定义了该属性的名字。如下面代码所示,一个 getter 方法 `getLabel()` 或 setter 方法 `setLabel()`
就定义了一个名为 `label` 的属性:
getter 方法是名称以 `get` 开头的方法,而 setter 方法名以 `set` 开头。方法名中 `get``set` 后面的部分就定义了该属性的名字。如下面代码所示,getter 方法 `getLabel()` 和 setter 方法 `setLabel()` 操作的是 `label` 属性,:
```php
namespace app\components;
......@@ -41,10 +36,9 @@ class Foo extend Object
}
```
(详细解释:getter 和 setter 方法创建了一个名为 `label` 的属性,在这个例子里,它指向一个私有的内部属性 `_label`译者注:习惯上一般把私有属性都定义为 `_` 下划线开头的名字。
(详细解释:getter 和 setter 方法创建了一个名为 `label` 的属性,在这个例子里,它指向一个私有的内部属性 `_label`。)
getters/setters 定义的属性能像类成员变量那样使用。两者主要的区别是:当这种属性被读取时,对应的 getter
方法将被调用;而当属性被赋值时,对应的 setter 方法就调用。如:
getter/setter 定义的属性用法与类成员变量一样。两者主要的区别是:当这种属性被读取时,对应的 getter 方法将被调用;而当属性被赋值时,对应的 setter 方法就调用。如:
```php
// 等效于 $label = $object->getLabel();
......@@ -54,15 +48,13 @@ $label = $object->label;
$object->label = 'abc';
```
只定义了 getter 没有 setter 的属性是*只读属性*。尝试赋值给这样的属性将导致 [[yii\base\InvalidCallException|InvalidCallException]]
(无效调用)异常。类似的,只有 setter 方法而没有 getter 方法定义的属性是*只写属性*,尝试读取这种属性也会触发异常。使用只写属性的情况几乎没有。
只定义了 getter 没有 setter 的属性是**只读属性**。尝试赋值给这样的属性将导致 [[yii\base\InvalidCallException|InvalidCallException]] (无效调用)异常。类似的,只有 setter 方法而没有 getter 方法定义的属性是**只写属性**,尝试读取这种属性也会触发异常。使用只写属性的情况几乎没有。
通过 getter 和 setter 定义的属性也有一些特殊规则和限制:
* 这类属性的名字是 *不区分大小写* 的。如,`$object->label``$object->Label` 是同一个属性。因为 PHP 方法名是不区分大小写的。
* 如果此类属性名和类成员变量相同,以后者为准。例如,假设以上 `Foo` 类有个 `label` 成员变量,然后给
`$object->label = 'abc'` 赋值,将赋给成员变量而不是 setter `setLabel()` 方法。
* 这类属性的名字是**不区分大小写**的。如,`$object->label``$object->Label` 是同一个属性。因为 PHP 方法名是不区分大小写的。
* 如果此类属性名和类成员变量相同,以后者为准。例如,假设以上 `Foo` 类有个 `label` 成员变量,然后给 `$object->label = 'abc'` 赋值,将赋给成员变量而不是 setter `setLabel()` 方法。
* 这类属性不支持可见性(访问限制)。定义属性的 getter 和 setter 方法是 public、protected 还是 private 对属性的可见性没有任何影响。
* 这类属性的 getter 和 setter 方法只能定义为 *非静态*的,若定义为静态方法(static)则不会以相同方式处理。
* 这类属性的 getter 和 setter 方法只能定义为**非静态**的,若定义为静态方法(static)则不会以相同方式处理。
回到开头处提到的问题,与其处处要调用 `trim()` 函数,现在我们只需在 setter `setLabel()` 方法内调用一次。如果 label 首字母变成大写的新要求来了,我们只需要修改`setLabel()` 方法,而无须接触任何其它代码。
\ No newline at end of file
回到开头提到的问题,与其处处要调用 `trim()` 函数,现在我们只需在 setter `setLabel()` 方法内调用一次。如果 label 首字母变成大写的新要求来了,我们只需要修改`setLabel()` 方法,而无须接触任何其它代码。
\ No newline at end of file
......@@ -11,7 +11,7 @@
安装
------------
Yii 2.0 完全拥抱 [Composer](https://getcomposer.org/),它是事实上的 PHP 包管理工具。核心框架以及扩展的安装都通过 Composer 来处理。想要了解更多如何安装 Yii 2.0 请参阅本指南的 [安装 Yii](start-installation.md) 章节。如果你想创建新扩展,或者把你已有的 Yii 1.1 的扩展改写成兼容 2.0 的版本,你可以参考 [创建扩展](extend-creating-extensions.md) 章节。
Yii 2.0 完全拥抱 [Composer](https://getcomposer.org/),它是PHP中的一个依赖管理工具。核心框架以及扩展的安装都通过 Composer 来处理。想要了解更多如何安装 Yii 2.0 请参阅本指南的 [安装 Yii](start-installation.md) 章节。如果你想创建新扩展,或者把你已有的 Yii 1.1 的扩展改写成兼容 2.0 的版本,你可以参考 [创建扩展](extend-creating-extensions.md) 章节。
PHP 需求
......
Yii 是什么
===========
Yii 是一个高性能,基于组件的 PHP 框架,用于快速开发现代 Web 应用程序。名字 Yii (读作
`易`)在中文里有“极致简单与不断变化”两重含义,也可看作 **Yes It Is**!的缩写
Yii 是一个高性能,基于组件的 PHP 框架,用于快速开发现代 Web 应用程序。名字 Yii (读作 `易`)在中文里有“极致简单与不断变化”两重含义,也可看作 **Yes It Is**! 的缩写。
Yii 最适合做什么?
---------------------
Yii 是一个通用的 Web 编程框架,即可以用于开发各种基于 PHP 的
Web 应用。因为基于组件的框架结构和设计精巧的缓存支持,Yii 特别适合开发大型应用,如门户网站、论坛、内容管理系统(CMS)、电子商务项目和 RESTful Web 服务等。
Yii 是一个通用的 Web 编程框架,即可以用于开发各种基于 PHP 的 Web 应用。因为基于组件的框架结构和设计精巧的缓存支持,Yii 特别适合开发大型应用,如门户网站、论坛、内容管理系统(CMS)、电子商务项目和 RESTful Web 服务等。
Yii 和其他框架相比呢?
-------------------------------------------
- 和其他 PHP 框架类似,Yii 实现了 MVC(Model-View-Controller)设计模式并基于该模式组织代码。
- Yii 的代码简洁优雅,这是 Yii 的编程哲学。它永远不会为了要迎合某个设计模式而对代码进行过度的设计。
- Yii 是一个全栈框架,提供了大量久经考验,开箱即用的特性,例如:对关系型和 NoSQL 数据库都提供了查询生成器(QueryBuilders)和 ActiveRecord;RESTful API 的开发支持;多层缓存支持等等。
- Yii 是一个全栈框架,提供了大量久经考验,开箱即用的特性,例如:对关系型和 NoSQL 数据库都提供了查询生成器(QueryBuilders)和 ActiveRecord;RESTful API 的开发支持;多层缓存支持等等。
- Yii 非常易于扩展。你可以自定义或替换几乎任何一处核心代码。你还会受益于它坚实可靠的扩展架构,使用、再开发或再发布扩展。
- 高性能始终是 Yii 的首要目标之一。
Yii 不是一场独角戏,它有一个[强大的开发者团队](http://www.yiiframework.com/about/)提供支持,也有一个庞大的专家社区,持续不断地对 Yii 的开发作出贡献。Yii 开发者团队始终对 Web 开发最新潮流和其他框架及项目中的最佳实践和特性保持密切的关注,那些有意义的最佳实践及特性会被不定期的整合进核心框架中,并提供简单优雅的接口。
Yii 不是一场独角戏,它由一个[强大的开发者团队](http://www.yiiframework.com/about/)提供支持,也有一个庞大的专家社区,持续不断地对 Yii 的开发作出贡献。Yii 开发者团队始终对 Web 开发最新潮流和其他框架及项目中的最佳实践和特性保持密切关注,那些有意义的最佳实践及特性会被不定期的整合进核心框架中,并提供简单优雅的接口。
Yii 版本
------------
Yii 当前有两个主要版本:1.1 和 2.0。 1.1 版是上代的老版本,现在处于维护状态。2.0 版是一个完全重写的版本,采用了最新的技术和协议,包括依赖包管理器(Composer)、PHP 代码规范(PSR)、命名空间、Traits(特质)等等。 2.0 版代表了最新一代框架,是未来几年中我们的主要开发版本。本指南主要基于
2.0 版本编写。
Yii 当前有两个主要版本:1.1 和 2.0。 1.1 版是上代的老版本,现在处于维护状态。2.0 版是一个完全重写的版本,采用了最新的技术和协议,包括依赖包管理器(Composer)、PHP 代码规范(PSR)、命名空间、Traits(特质)等等。 2.0 版代表了最新一代框架,是未来几年中我们的主要开发版本。本指南主要基于 2.0 版编写。
系统要求和先决条件
------------------------------
Yii 2.0 需要 PHP 5.4.0 或以上版本支持。你可以通过运行任何 Yii 发行包中附带的系统要求检查器查看每个具体特性所需的 PHP 配
置。
Yii 2.0 需要 PHP 5.4.0 或以上版本支持。你可以通过运行任何 Yii 发行包中附带的系统要求检查器查看每个具体特性所需的 PHP 配置。
使用 Yii 需要对面向对象编程(OOP)有基本了解,因为 Yii 是一个纯面向对象的框架。Yii 2.0 还使用了 PHP 的最新特性,例如 [命名空间](http://www.php.net/manual/en/language.namespaces.php)
[Trait(特质)](http://www.php.net/manual/en/language.oop5.traits.php)。理解这些概念将有助于你更快地掌握 Yii 2.0。
使用 Yii 需要对面向对象编程(OOP)有基本了解,因为 Yii 是一个纯面向对象的框架。Yii 2.0 还使用了 PHP 的最新特性,例如 [命名空间](http://www.php.net/manual/en/language.namespaces.php)[Trait(特质)](http://www.php.net/manual/en/language.oop5.traits.php)。理解这些概念将有助于你更快地掌握 Yii 2.0。
使用数据库
======================
节将介绍如何如何创建一个从数据表 `country` 中获取国家数据并显示出来的页面。为了实现这个目标,你将会配置一个数据库连接,创建一个[活动记录](db-active-record.md)类,并且创建一个[操作](structure-controllers.md)及一个[视图](structure-views.md)
节将介绍如何如何创建一个从数据表 `country` 中获取国家数据并显示出来的页面。为了实现这个目标,你将会配置一个数据库连接,创建一个[活动记录](db-active-record.md)类,并且创建一个[操作](structure-controllers.md)及一个[视图](structure-views.md)
贯穿整个节,你将会学到:
贯穿整个节,你将会学到:
* 配置一个数据库连接
* 定义一个活动记录类
* 使用活动记录从数据库中查询数据
* 以分页方式在视图中显示数据
请注意,为了掌握本小节你应该具备最基本的数据库知识和使用经验。尤其是你应该知道如何创建数据库,如何通过数据库终端执行 SQL 语句。
请注意,为了掌握本章你应该具备最基本的数据库知识和使用经验。尤其是应该知道如何创建数据库,如何通过数据库终端执行 SQL 语句。
准备数据库 <a name="preparing-database"></a>
--------------------
首先创建一个名为 `yii2basic` 的数据库,你的应用将从这个数据库中获取数据。你可以创建 SQLite,MySQL,PostregSQL,MSSQL 或 Oracle 数据库,Yii 内置多种数据库支持。简单起见后面的内容将以 MySQL 为例做演示。
首先创建一个名为 `yii2basic` 的数据库,应用将从这个数据库中获取数据。你可以创建 SQLite,MySQL,PostregSQL,MSSQL 或 Oracle 数据库,Yii 内置多种数据库支持。简单起见后面的内容将以 MySQL 为例做演示。
然后在数据库中创建一个名为 `country` 的表并插入简单的数据。可以执行下面的语句:
......@@ -64,7 +64,7 @@ return [
上面配置的数据库连接可以在应用中通过 `Yii::$app->db` 访问。
> 补充:`config/db.php` 将被包含在应用配置文件 `config/web.php` 中,后者指定了整个[应用](structure-applications.md)如何初始化。请参考[配置](concept-configurations.md)节了解更多信息。
> 补充:`config/db.php` 将被包含在应用配置文件 `config/web.php` 中,后者指定了整个[应用](structure-applications.md)如何初始化。请参考[配置](concept-configurations.md)节了解更多信息。
创建活动记录 <a name="creating-active-record"></a>
......@@ -86,9 +86,9 @@ class Country extends ActiveRecord
这个 `Country` 类继承自 [[yii\db\ActiveRecord]]。你不用在里面写任何代码。只需要像现在这样,Yii 就能根据类名去猜测对应的数据表名。
> 补充:如果类名和数据表名不能直接对应,可以重写 [[yii\db\ActiveRecord::tableName()|tableName()]] 方法去显式指定相关表名。
> 补充:如果类名和数据表名不能直接对应,可以重写 [[yii\db\ActiveRecord::tableName()|tableName()]] 方法去显式指定相关表名。
使用 `Country`可以很容易地操作 `country` 表数据,就像这段代码:
使用 `Country` 类可以很容易地操作 `country` 表数据,就像这段代码:
```php
use app\models\Country;
......@@ -107,7 +107,7 @@ $country->name = 'U.S.A.';
$country->save();
```
> 补充:活动记录是面向对象、功能强大的访问和操作数据库数据的方式。你可以在[活动记录](db-active-record.md)节了解更多信息。除此之外你还可以使用另一种更原生的称做[数据访问对象](db-dao)的方法操作数据库数据。
> 补充:活动记录是面向对象、功能强大的访问和操作数据库数据的方式。你可以在[活动记录](db-active-record.md)节了解更多信息。除此之外你还可以使用另一种更原生的称做[数据访问对象](db-dao)的方法操作数据库数据。
创建操作 <a name="creating-action"></a>
......@@ -210,6 +210,6 @@ http://hostname/index.php?r=country/index&page=2
总结 <a name="summary"></a>
-------
节中你学到了如何使用数据库。你还学到了如何取出并使用 [[yii\data\Pagination]] 和 [[yii\widgets\LinkPager]] 显示数据。
节中你学到了如何使用数据库。你还学到了如何取出并使用 [[yii\data\Pagination]] 和 [[yii\widgets\LinkPager]] 显示数据。
下一小节中你会学到如何使用 Yii 中强大的代码生成器 [Gii](tool-gii.md),去帮助你实现一些常用的功能需求,例如增查改善(CRUD)数据表中的数据。事实上你之前所写的代码全部都可以由 Gii 自动生成:)
\ No newline at end of file
下一章中你会学到如何使用 Yii 中强大的代码生成器 [Gii](tool-gii.md),去帮助你实现一些常用的功能需求,例如增查改删(CRUD)数据表中的数据。事实上你之前所写的代码全部都可以由 Gii 自动生成。
\ No newline at end of file
使用表单
==================
小节将介绍如何创建一个从用户那搜集数据的表单页面。该页将显示一个包含 name 输入框和 email 输入框的表单。当搜集完这两部分信息后,页面将会显示用户输入的信息。
章节将介绍如何创建一个从用户那搜集数据的表单页。该页将显示一个包含 name 输入框和 email 输入框的表单。当搜集完这两部分信息后,页面将会显示用户输入的信息。
为了实现这个目标,除了创建一个[操作](structure-controllers.md)和两个[视图](structure-views)外,还需要创建一个[模型](structure-models.md)
为了实现这个目标,除了创建一个[操作](structure-controllers.md)和两个[视图](structure-views)外,还需要创建一个[模型](structure-models.md)
贯穿整个小节,你将会学到:
* 创建一个[模型](structure-models.md)表示用户通过表单输入的数据
* 创建一个[模型](structure-models.md)代表用户通过表单输入的数据
* 声明规则去验证输入的数据
*[视图](structure-views.md)中生成一个 HTML 表单
......@@ -15,7 +15,7 @@
创建模型 <a name="creating-model"></a>
----------------
模型类 `EntryForm` 代表从用户那请求的数据,该类如下所示并存储在 `models/EntryForm.php` 文件中。请参考[类自动加载](concept-autoloading.md)节获取更多关于类命名约定的介绍。
模型类 `EntryForm` 代表从用户那请求的数据,该类如下所示并存储在 `models/EntryForm.php` 文件中。请参考[类自动加载](concept-autoloading.md)节获取更多关于类命名约定的介绍。
```php
<?php
......@@ -48,7 +48,7 @@ class EntryForm extends Model
* `name``email` 值都是必须的
* `mail` 的值必须满足 email 地址验证
如果你有一个从用户那搜集数据的 `EntryForm` 对象,你可以调用它的 [[yii\base\Model::validate()|validate()]] 方法触发数据验证。如果有数据验证失败,将把 [[yii\base\Model::hasErrors|hasErrors]] 属性设为 ture,想要知道具体发生什么错误就调用 [[yii\base\Model::getErrors|getErrors]]。
如果你有一个从用户那搜集数据的 `EntryForm` 对象,你可以调用它的 [[yii\base\Model::validate()|validate()]] 方法触发数据验证。如果有数据验证失败,将把 [[yii\base\Model::hasErrors|hasErrors]] 属性设为 ture,想要知道具体发生什么错误就调用 [[yii\base\Model::getErrors|getErrors]]。
```php
<?php
......@@ -104,7 +104,7 @@ class SiteController extends Controller
> 补充:表达式 `Yii::$app` 代表[应用](structure-applications.md)实例,它是一个全局可访问的单例。同时它也是一个[服务定位器](concept-service-locator.md),能提供 `request`,`response`,`db` 等等特定功能的组件。在上面的代码里就是使用 `request` 组件来访问应用实例收到的 `$_POST` 数据。
用户提交表单后,操作将会渲染一个名为 `entry-confirm` 的视图去确认用户输入的数据。如果没填表单就提交,或数据包含错误(译者:如 email 格式不对),`entry` 视图将会渲染输出,连同表单一起输出的还有验证错误的信息。
用户提交表单后,操作将会渲染一个名为 `entry-confirm` 的视图去确认用户输入的数据。如果没填表单就提交,或数据包含错误(译者:如 email 格式不对),`entry` 视图将会渲染输出,连同表单一起输出的还有验证错误的详细信息。
> 注意:在这个简单例子里我们只是呈现了有效数据的确认页面。实践中你应该考虑使用 [[yii\web\Controller::refresh()|refresh()]] 或 [[yii\web\Controller::redirect()|redirect()]] 去避免[表单重复提交问题](http://en.wikipedia.org/wiki/Post/Redirect/Get)。
......@@ -160,11 +160,11 @@ use yii\widgets\ActiveForm;
http://hostname/index.php?r=site/entry
```
你会看到一个包含两个输入框的表单的页面。每个输入框的前面都有一个标签指明应该输入的数据类型。如果什么都不填就点击提交按钮,或填入格式不正确的 email 地址,将会看到在对应的输入框下显示错误信息。
你会看到一个包含两个输入框的表单的页面。每个输入框的前面都有一个标签指明应该输入的数据类型。如果什么都不填就点击提交按钮,或填入格式不正确的 email 地址,将会看到在对应的输入框下显示错误信息。
![验证错误的表单](images/start-form-validation.png)
输入有效的 name 和 email 信息并提交后,将会看到一个显示你所提交数据的确认页面。
输入有效的 name 和 email 信息并提交后,将会看到一个显示你所提交数据的确认页面。
![输入数据的确认页](images/start-entry-confirmation.png)
......@@ -193,8 +193,8 @@ http://hostname/index.php?r=site/entry
总结 <a name="summary"></a>
-------
小节指南中你接触了 MVC 设计模式的每个部分。你学到了如何创建一个模型代表用户数据并验证它的有效性。
章节指南中你接触了 MVC 设计模式的每个部分。学到了如何创建一个模型代表用户数据并验证它的有效性。
你还学到了如何从用户那获取数据并在浏览器上回显给用户。这本来是开发应用的过程中比较耗时的任务,好在 Yii 提供了强大的小部件让它变得如此简单。
下一小节你将学习如何使用数据库,几乎每个应用都需要数据库。
下一你将学习如何使用数据库,几乎每个应用都需要数据库。
使用 Gii 生成代码
========================
节将介绍如何使用 [Gii](tool-gii.md) 去自动生成 Web 站点常用功能的代码。使用 Gii 生成代码非常简单,只要按照 Gii 页面上的介绍输入正确的信息即可。
节将介绍如何使用 [Gii](tool-gii.md) 去自动生成 Web 站点常用功能的代码。使用 Gii 生成代码非常简单,只要按照 Gii 页面上的介绍输入正确的信息即可。
贯穿本节,你将会学到:
贯穿本节,你将会学到:
* 在你的应用中开启 Gii
* 使用 Gii 去生成活动记录类
......@@ -14,7 +14,7 @@
开始 Gii <a name="starting-gii"></a>
------------
[Gii](tool-gii.md) 是 Yii 中的一个[模块](structure-modules.md)可以通过配置应用的 [[yii\base\Application::modules|modules]] 属性开启它。通常来讲在 `config/web.php` 文件中会有以下配置代码:
[Gii](tool-gii.md) 是 Yii 中的一个[模块](structure-modules.md)。可以通过配置应用的 [[yii\base\Application::modules|modules]] 属性开启它。通常来讲在 `config/web.php` 文件中会有以下配置代码:
```php
$config = [ ... ];
......@@ -98,7 +98,7 @@ http://hostname/index.php?r=country/index
![编辑一个国家](images/start-gii-country-update.png)
下面列出由 Gii 生成的文件,以便你也许想研习功能和实现,或修改它们。
下面列出由 Gii 生成的文件,以便你研习功能和实现,或修改它们。
* 控制器:`controllers/CountryController.php`
* 模型:`models/Country.php``models/CountrySearch.php`
......@@ -110,4 +110,4 @@ http://hostname/index.php?r=country/index
总结 <a name="summary"></a>
-------
小节学习了如何使用 Gii 去生成为数据表中数据实现完整 CRUD 功能的代码。
学习了如何使用 Gii 去生成为数据表中数据实现完整 CRUD 功能的代码。
说声 Hello
============
小节描述如何在你的应用中创建一个新的 “Hello” 页面。为了做到这点,你将会创建一个[操作](structure-controllers.md#creating-actions)和一个[视图](structure-views.md)
章节描述了如何在你的应用中创建一个新的 “Hello” 页面。为了做到这点,将会创建一个[操作](structure-controllers.md#creating-actions)和一个[视图](structure-views.md)
* 应用将会分派页面请求给操作
* 操作将会依次渲染视图呈现 “Hello” 给最终用户
贯穿整个节,你将会掌握三件事:
贯穿整个节,你将会掌握三件事:
1. 如何创建一个[操作](structure-controllers.md)去响应请求,
2. 如何创建一个[视图](structure-views.md)去构造响应内容,
......@@ -16,9 +16,9 @@
创建操作 <a name="creating-action"></a>
------------------
为了说 “Hello”,需要创建一个 `say` [操作](structure-controllers.md#creating-actions),从请求中接收 `message` 参数并显示给最终用户。如果请求没有提供 `message` 参数,操作将显示默认参数 “Hello”。
为了说 “Hello”,需要创建一个 `say` [操作](structure-controllers.md#creating-actions),从请求中接收 `message` 参数并显示给最终用户。如果请求没有提供 `message` 参数,操作将显示默认参数 “Hello”。
> 补充:[操作](structure-controllers.md#creating-actions)是最终用户可以直接访问并执行的对象。操作被组织在[控制器](structure-controllers.md)中。一个操作的执行结果就是最终用户将会收到的响应内容。
> 补充:[操作](structure-controllers.md#creating-actions)是最终用户可以直接访问并执行的对象。操作被组织在[控制器](structure-controllers.md)中。一个操作的执行结果就是最终用户收到的响应内容。
操作必须声明在[控制器](structure-controllers.md)中。为了简单起见,你可以直接在 `SiteController` 控制器里声明 `say` 操作。这个控制器是由文件 `controllers/SiteController.php` 定义的。以下是一个操作的声明:
......@@ -44,7 +44,7 @@ class SiteController extends Controller
涉及到给操作命名时,你应该理解 Yii 如何处理操作 ID。操作 ID 总是被以小写处理,如果一个操作 ID 由多个单词组成,单词之间将由连字符连接(如 `create-comment`)。操作 ID 映射为方法名时移除了连字符,将每个单词首字母大写,并加上 `action` 前缀。 例子:操作 ID `create-comment` 相当于方法名 `actionCreateComment`
上述代码中的操作方法接受一个参数 `$message`,它的默认值是 `“Hello”`(就像你设置其它 PHP 函数或方法的默认值一样)。当应用接收到请求并确定由 `say` 操作来响应请求时,应用将从请求的参数中寻找对应值传入进来。换句话说,如果请求包含一个 `message` 参数,它的值是 `“Goodybye”`, 操作方法中的 `$message` 变量也将被填充为 `“Goodbye”`
上述代码中的操作方法接受一个参数 `$message`,它的默认值是 `“Hello”`(就像你设置 PHP 中其它函数或方法的默认值一样)。当应用接收到请求并确定由 `say` 操作来响应请求时,应用将从请求的参数中寻找对应值传入进来。换句话说,如果请求包含一个 `message` 参数,它的值是 `“Goodybye”`, 操作方法中的 `$message` 变量也将被填充为 `“Goodbye”`
在操作方法中,[[yii\web\Controller::render()|render()]] 被用来渲染一个名为 `say`[视图](structure-views.md)文件。 `message` 参数也被传入视图,这样就可以在里面使用。操作方法会返回渲染结果。结果会被应用接收并显示给最终用户的浏览器(作为整页 HTML 的一部分)。
......@@ -63,7 +63,7 @@ use yii\helpers\Html;
`say` 视图应该存为 `views/site/say.php` 文件。当一个操作中调用了 [[yii\web\Controller::render()|render()]] 方法时,它将会按 `views/控制器 ID/视图名.php` 路径加载 PHP 文件。
注意以上代码,`message` 参数在输出之前被 [[yii\helpers\Html::encode()|HTML-encoded]] 方法处理过。这非常有必要,当参数来自于最终用户时,参数中的恶意 JavaScript 代码会导致[跨站脚本(XSS)攻击](http://en.wikipedia.org/wiki/Cross-site_scripting)
注意以上代码,`message` 参数在输出之前被 [[yii\helpers\Html::encode()|HTML-encoded]] 方法处理过。这很有必要,当参数来自于最终用户时,参数中可能隐含的恶意 JavaScript 代码会导致[跨站脚本(XSS)攻击](http://en.wikipedia.org/wiki/Cross-site_scripting)
当然了,你大概会在 `say` 视图里放入更多内容。内容可以由 HTML 标签,纯文本,甚至 PHP 语句组成。实际上 `say` 视图就是一个由 [[yii\web\Controller::render()|render()]] 执行的 PHP 脚本。视图脚本输出的内容将会作为响应结果返回给应用。应用将依次输出结果给最终用户。
......@@ -85,7 +85,7 @@ http://hostname/index.php?r=site/say&message=Hello+World
> 补充:新页面和其它页面使用同样的头部和尾部是因为 [[yii\web\Controller::render()|render()]] 方法会自动把 `say` 视图执行的结果嵌入称为[布局](structure-views.md#layouts)的文件中,本例中是 `views/layouts/main.php`。
上面 URL 中的参数 `r` 需要更多解释。它代表[路由](runtime-routing.md),整个应用级的,指向特定操作的独立 ID。路由格式是 `控制器 ID/操作 ID`。应用接受请求的时候会检查参数,使用控制器 ID 去确定哪个控制器应该被用来处理请求。然后相应控制器将使用操作 ID 去确定哪个操作方法将被用来做具体工作。上述例子中,路由 `site/say` 将被解析至 `SiteController` 控制器和其中的 `say` 操作。因此 `SiteController::actionSay()` 方法将被调用处理请求。
上面 URL 中的参数 `r` 需要更多解释。它代表[路由](runtime-routing.md)整个应用级的,指向特定操作的独立 ID。路由格式是 `控制器 ID/操作 ID`。应用接受请求的时候会检查参数,使用控制器 ID 去确定哪个控制器应该被用来处理请求。然后相应控制器将使用操作 ID 去确定哪个操作方法将被用来做具体工作。上述例子中,路由 `site/say` 将被解析至 `SiteController` 控制器和其中的 `say` 操作。因此 `SiteController::actionSay()` 方法将被调用处理请求。
> 补充:与操作一样,一个应用中控制器同样有唯一的 ID。控制器 ID 和操作 ID 使用同样的命名规则。控制器的类名源自于控制器 ID,移除了连字符,每个单词首字母大写,并加上 `Controller` 后缀。例子:控制器 ID `post-comment` 相当于控制器类名 `PostCommentController`。
......@@ -93,8 +93,8 @@ http://hostname/index.php?r=site/say&message=Hello+World
总结 <a name="summary"></a>
-------
在本小节你已经接触了 MVC 设计模式中的控制器和视图部分。你创建了一个操作作为控制器的一部分去处理特定请求。然后你又创建了一个视图去构造响应内容。在这个小例子中,没有模型调用,唯一涉及到数据的地方是 `message` 参数。
通过本章节你接触了 MVC 设计模式中的控制器和视图部分。创建了一个操作作为控制器的一部分去处理特定请求。然后又创建了一个视图去构造响应内容。在这个小例子中,没有模型调用,唯一涉及到数据的地方是 `message` 参数。
你同样学习了 Yii 路由的相关内容,它是用户请求与控制器操作之间的桥梁。
在下一节,你将学习如何创建一个模型,以及添加一个包含 HTML 表单的页面。
下一章,你将学习如何创建一个模型,以及添加一个包含 HTML 表单的页面。
......@@ -60,7 +60,7 @@ Composer 安装后,切换到一个可通过 Web 访问的目录,执行如下
http://localhost/basic/web/index.php
```
这个 URL 假设你将 Yii 安装到了一个位于 Web 服务器根目录下的 `basic` 目录中,且该 Web 服务器正运行在你自己的电脑上 (`localhost`)。你可能需要将其调整为适应自己的安装环境。
这个 URL 假设你将 Yii 安装到了一个位于 Web 文档根目录下的 `basic` 目录中,且该 Web 服务器正运行在你自己的电脑上 (`localhost`)。你可能需要将其调整为适应自己的安装环境。
![Yii 安装成功](images/start-app-installed.png)
......@@ -84,7 +84,7 @@ http://localhost/basic/web/index.php
通过上述方法安装的应用程序在 Windows,Max OS X, Linux 中的 [Apache HTTP 服务器](http://httpd.apache.org/)或 [Nginx HTTP 服务器](http://nginx.org/) 上都可以直接运行。
在生产环境的服务器上,你可能会想配置服务器让应用程序可以通过 URL `http://www.example.com/index.php` 访问而不是 `http://www.example.com/basic/web/index.php`。这种配置需要将 Web 服务器的根目录指向 `basic/web` 目录。可能你还会想隐藏掉 URL 中的 `index.php`,具体细节在 [URL 解析和生成](runtime-url-handling.md) 一章中有介绍,你将学到如何配置 Apache 或 Nginx 服务器实现这些目标。
在生产环境的服务器上,你可能会想配置服务器让应用程序可以通过 URL `http://www.example.com/index.php` 访问而不是 `http://www.example.com/basic/web/index.php`。这种配置需要将 Web 服务器的文档根目录指向 `basic/web` 目录。可能你还会想隐藏掉 URL 中的 `index.php`,具体细节在 [URL 解析和生成](runtime-url-handling.md) 一章中有介绍,你将学到如何配置 Apache 或 Nginx 服务器实现这些目标。
>补充:将 `basic/web` 设置为文档根目录,可以防止终端用户访问 `basic/web` 相邻目录中的私有应用程序代码和敏感数据文件。禁止对其他目录的访问是一个切实可行的安全改进。
......
更上一层楼
=============
通篇阅读完整个“入门”章节,你就完成了一个完整 Yii 应用的创建。在此过程中你学到了如何实现一些常用功能,例如通过 HTML 表单从用户那获取数据,从数据库中获取数据并以分页形式显示。你还学到了如何通过 [Gii](tool-gii.md) 去自动生成代码。使用 Gii 生成代码把 Web 开发中多数繁杂的过程转化为仅仅填写几个表单就行。
通篇阅读完整个“入门”板块,你就完成了一个完整 Yii 应用的创建。在此过程中你学到了如何实现一些常用功能,例如通过 HTML 表单从用户那获取数据,从数据库中获取数据并以分页形式显示。你还学到了如何通过 [Gii](tool-gii.md) 去自动生成代码。使用 Gii 生成代码把 Web 开发中多数繁杂的过程转化为仅仅填写几个表单就行。
节将介绍一些有助于更好使用 Yii 的资源:
节将介绍一些有助于更好使用 Yii 的资源:
* 文档
- 权威指南:
顾名思义,指南详细描述了 Yii 的工作原理并提供了如何使用它的常规引导。这是最重要的 Yii 辅助资料,强烈建议在开始写 Yii 代码之前阅读。
顾名思义,指南详细描述了 Yii 的工作原理并提供了如何使用它的常规引导。这是最重要的 Yii 辅助资料,强烈建议在开始写 Yii 代码之前阅读。
- 类参考手册:
描述了 Yii 中每个类的用法。在编码过程中这极为有用,能够帮你理清某个特定类,方法,和属性的用法。类参考手册最好在整个框架的语境下去理解。
- Wiki 文章:
......
运行应用
====================
安装 Yii 后,你就有了一个运行中的 Yii 应用,根据不同配置,可以通过 `http://hostname/basic/web/index.php``http://hostname/index.php` 访问。本小节将介绍应用的内建功能,如何组织代码,以及一般情况下应用如何处理请求。
安装 Yii 后,就有了一个运行中的 Yii 应用,根据配置的不同,可以通过 `http://hostname/basic/web/index.php``http://hostname/index.php` 访问。本章节将介绍应用的内建功能,如何组织代码,以及一般情况下应用如何处理请求。
> 补充:为简单起见,在整个“入门”章节中都假定你已经把 `basic/web` 设为 Web 服务器根目录并配置完毕,你访问应用的地址会是 `http://lostname/index.php` 或类似的。请按需调整 URL。
> 补充:为简单起见,在整个“入门”板块都假定你已经把 `basic/web` 设为 Web 服务器根目录并配置完毕,你访问应用的地址会是 `http://lostname/index.php` 或类似的。请按需调整 URL。
功能 <a name="functionality"></a>
-------------
......@@ -11,14 +11,13 @@
一个安装完的基本应用包含四页:
* 主页,当你访问 `http://hostname/index.php` 时显示,
* “About” 页
* “About” 页,
* “Contact” 页, 显示一个联系表单,允许终端用户通过 Email 联系你,
* “Login” 页, 显示一个登录表单,用来验证终端用户。试着使用 “admin/admin” 登录,你可以看到当前是登录状态,已经可以“退出登录”了。
* “Login” 页, 显示一个登录表单,用来验证终端用户。试着用 “admin/admin” 登录,你可以看到当前是登录状态,已经可以“退出登录”了。
这些页面使用同一个头部和尾部。头部包含了一个可以在不同页面间切换的导航栏。
在浏览器底部可以看到一个工具栏。
这是个 Yii 提供的很有用的[调试工具](tool-debugger.md),可以记录并显示大量的调试信息,例如日志信息,响应状态,数据库查询等等。
在浏览器底部可以看到一个工具栏。这是 Yii 提供的很有用的[调试工具](tool-debugger.md),可以记录并显示大量的调试信息,例如日志信息,响应状态,数据库查询等等。
应用结构 <a name="application-structure"></a>
......@@ -44,13 +43,14 @@ basic/ 应用根目录
```
一般来说,应用中的文件可被分为两类:在 `basic/web` 下的和在其它目录下的。前者可以直接通过 HTTP 访问(例如浏览器),后者不能也不应该被直接访问。
Yii 实现了[模型-视图-控制器 (MVC)](http://wikipedia.org/wiki/Model-view-controller)设计模式,这点在上述目录结构中也得以体现。 `models` 目录包含了所有[模型类](structure-models.md)`views` 目录包含了所有[视图脚本](structure-views.md)`controllers` 目录包含了所有[控制器类](structure-controllers.md)
以下图表展示了一个应用的静态结构:
![应用静态结构](images/application-structure.png)
每个应用都有一个入口脚本 `web/index.php`,这应该是整个应用中唯一可以访问的 PHP 脚本。入口脚本接受一个 Web 请求并创建[应用](structure-application.md)实例去处理它。 [应用](structure-applications.md)在它的[组建](concept-components.md)辅助下解析请求,并分派请求至 MVC 元素。[视图](structure-views.md)使用[小部件](structure-widgets.md)去创建复杂和动态的用户界面。
每个应用都有一个入口脚本 `web/index.php`,这是整个应用中唯一可以访问的 PHP 脚本。入口脚本接受一个 Web 请求并创建[应用](structure-application.md)实例去处理它。 [应用](structure-applications.md)在它的[组建](concept-components.md)辅助下解析请求,并分派请求至 MVC 元素。[视图](structure-views.md)使用[小部件](structure-widgets.md)去创建复杂和动态的用户界面。
请求生命周期 <a name="request-lifecycle"></a>
......@@ -60,8 +60,8 @@ Yii 实现了[模型-视图-控制器 (MVC)](http://wikipedia.org/wiki/Model-vie
![请求生命周期](images/application-lifecycle.png)
1. 用户向 [入口脚本](structure-entry-scripts.md) `web/index.php` 发起请求。
2. 入口脚本加载应用 [配置](concept-configurations.md)并创建一个[应用](structure-applications.md)实例去处理请求。
1. 用户向[入口脚本](structure-entry-scripts.md) `web/index.php` 发起请求。
2. 入口脚本加载应用[配置](concept-configurations.md)并创建一个[应用](structure-applications.md)实例去处理请求。
3. 应用通过[请求](runtime-request.md)组件解析请求的[路由](runtime-routing.md)
4. 应用创建一个[控制器](structure-controllers.md)实例去处理请求。
5. 控制器创建一个[操作](structure-controllers.md)实例并针对操作执行过滤器。
......
......@@ -67,7 +67,7 @@ class MyClass extends Object
}
```
Following these guideliness will make your components [configurable](concept-configurations.md) when they are instantiated. For example:
Following these guidelines will make your components [configurable](concept-configurations.md) when they are created. For example:
```php
$component = new MyClass(1, 2, ['prop1' => 3, 'prop2' => 4]);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment