RichWeber
10 years ago
411 changed files with 4808 additions and 1523 deletions
@ -0,0 +1,141 @@
|
||||
片段缓存 |
||||
================ |
||||
|
||||
片段缓存指的是缓存页面内容中的某个片段。例如,一个页面显示了逐年销售额的摘要表格,可以把表格缓存下来,以消除每次请求都要重新生成表格的耗时。片段缓存是基于[数据缓存](caching-data.md)实现的。 |
||||
|
||||
在[视图](structure-views.md)中使用以下结构启用片段缓存: |
||||
|
||||
```php |
||||
if ($this->beginCache($id)) { |
||||
|
||||
// ... 在此生成内容 ... |
||||
|
||||
$this->endCache(); |
||||
} |
||||
``` |
||||
|
||||
调用 [[yii\base\View::beginCache()|beginCache()]] 和 [[yii\base\View::endCache()|endcache()]] 方法包裹内容生成逻辑。如果缓存中存在该内容,[[yii\base\View::beginCache()|beginCache()]] 方法将渲染内容并返回 false,因此将跳过内容生成逻辑。否则,内容生成逻辑被执行,一直执行到 [[yii\base\View::endCache()|endCache()]] 时,生成的内容将被捕获并存储在缓存中。 |
||||
|
||||
和[[数据缓存]](caching-data.md)一样,每个片段缓存也需要全局唯一的 `$id` 标记。 |
||||
|
||||
|
||||
## 缓存选项 <a name="caching-options"></a> |
||||
|
||||
如果要为片段缓存指定额外配置项,请通过向 [[yii\base\View::beginCache()|beginCache()]] 方法第二个参数传递配置数组。在框架内部,该数组将被用来配置一个 [[yii\widget\FragmentCache]] 小部件用以实现片段缓存功能。 |
||||
|
||||
### 过期时间(duration) <a name="duration"></a> |
||||
|
||||
或许片段缓存中最常用的一个配置选项就是 [[yii\widgets\FragmentCache::duration|duration]] 了。它指定了内容被缓存的秒数。以下代码缓存内容最多一小时: |
||||
|
||||
```php |
||||
if ($this->beginCache($id, ['duration' => 3600])) { |
||||
|
||||
// ... 在此生成内容 ... |
||||
|
||||
$this->endCache(); |
||||
} |
||||
``` |
||||
|
||||
如果该选项未设置,则默认为 0,永不过期。 |
||||
|
||||
|
||||
### 依赖 <a name="dependencies"></a> |
||||
|
||||
和[[数据缓存]](caching-data.md)一样,片段缓存的内容一样可以设置缓存依赖。例如一段被缓存的文章,是否重新缓存取决于它是否被修改过。 |
||||
|
||||
通过设置 [[yii\widgets\FragmentCache::dependency|dependency]] 选项来指定依赖,该选项的值可以是一个 [[yii\caching\Dependency]] 类的派生类,也可以是创建缓存对象的配置数组。以下代码指定了一个片段缓存,它依赖于 `update_at` 字段是否被更改过的。 |
||||
|
||||
```php |
||||
$dependency = [ |
||||
'class' => 'yii\caching\DbDependency', |
||||
'sql' => 'SELECT MAX(updated_at) FROM post', |
||||
]; |
||||
|
||||
if ($this->beginCache($id, ['dependency' => $dependency])) { |
||||
|
||||
// ... 在此生成内容 ... |
||||
|
||||
$this->endCache(); |
||||
} |
||||
``` |
||||
|
||||
|
||||
### 变化 <a name="variations"></a> |
||||
|
||||
缓存的内容可能需要根据一些参数的更改而变化。例如一个 Web 应用支持多语言,同一段视图代码也许需要生成多个语言的内容。因此可以设置缓存根据应用当前语言而变化。 |
||||
|
||||
通过设置 [[yii\widgets\FragmentCache::variations|variations]] 选项来指定变化,该选项的值应该是一个标量,每个标量代表不同的变化系数。例如设置缓存根据当前语言而变化可以用以下代码: |
||||
|
||||
```php |
||||
if ($this->beginCache($id, ['variations' => [Yii::$app->language]])) { |
||||
|
||||
// ... 在此生成内容 ... |
||||
|
||||
$this->endCache(); |
||||
} |
||||
``` |
||||
|
||||
|
||||
### 开关 <a name="toggling-caching"></a> |
||||
|
||||
有时你可能只想在特定条件下开启片段缓存。例如,一个显示表单的页面,可能只需要在初次请求时缓存表单(通过 GET 请求)。随后请求所显示(通过 POST 请求)的表单不该使用缓存,因为此时表单中可能包含用户输入内容。鉴于此种情况,可以使用 [[yii\widgets\FragmentCache::enabled|enabled]] 选项来指定缓存开关,如下所示: |
||||
|
||||
```php |
||||
if ($this->beginCache($id, ['enabled' => Yii::$app->request->isGet])) { |
||||
|
||||
// ... 在此生成内容 ... |
||||
|
||||
$this->endCache(); |
||||
} |
||||
``` |
||||
|
||||
|
||||
## 缓存嵌套 <a name="nested-caching"></a> |
||||
|
||||
片段缓存可以被嵌套使用。一个片段缓存可以被另一个包裹。例如,评论被缓存在里层,同时整个评论的片段又被缓存在外层的文章中。以下代码展示了片段缓存的嵌套使用: |
||||
|
||||
```php |
||||
if ($this->beginCache($id1)) { |
||||
|
||||
// ...在此生成内容... |
||||
|
||||
if ($this->beginCache($id2, $options2)) { |
||||
|
||||
// ...在此生成内容... |
||||
|
||||
$this->endCache(); |
||||
} |
||||
|
||||
// ...在此生成内容... |
||||
|
||||
$this->endCache(); |
||||
} |
||||
``` |
||||
|
||||
可以为嵌套的缓存设置不同的配置项。例如,内层缓存和外层缓存使用不同的过期时间。甚至当外层缓存的数据过期失效了,内层缓存仍然可能提供有效的片段缓存数据。但是,反之则不然。如果外层片段缓存没有过期而被视为有效,此时即使内层片段缓存已经失效,它也将继续提供同样的缓存副本。因此,你必须谨慎处理缓存嵌套中的过期时间和依赖,否则外层的片段很有可能返回的是不符合你预期的失效数据。 |
||||
|
||||
> 译者注:外层的失效时间应该短于内层,外层的依赖条件应该低于内层,以确保最小的片段,返回的是最新的数据。 |
||||
|
||||
|
||||
## 动态内容 <a name="dynamic-content"></a> |
||||
|
||||
使用片段缓存时,可能会遇到一大段较为静态的内容中有少许动态内容的情况。例如,一个显示着菜单栏和当前用户名的页面头部。还有一种可能是缓存的内容可能包含每次请求都需要执行的 PHP 代码(例如注册资源包的代码)。这两个问题都可以使用**动态内容**功能解决。 |
||||
|
||||
动态内容的意思是这部分输出的内容不该被缓存,即便是它被包裹在片段缓存中。为了使内容保持动态,每次请求都执行 PHP 代码生成,即使这些代码已经被缓存了。 |
||||
|
||||
可以在片段缓存中调用 [[yii\base\View::renderDynamic()]] 去插入动态内容,如下所示: |
||||
|
||||
```php |
||||
if ($this->beginCache($id1)) { |
||||
|
||||
// ...在此生成内容... |
||||
|
||||
echo $this->renderDynamic('return Yii::$app->user->identity->name;'); |
||||
|
||||
// ...在此生成内容... |
||||
|
||||
$this->endCache(); |
||||
} |
||||
``` |
||||
|
||||
[[yii\base\View::renderDynamic()|renderDynamic()]] 方法接受一段 PHP 代码作为参数。代码的返回值被看作是动态内容。这段代码将在每次请求时都执行,无论其外层的片段缓存是否被存储。 |
@ -0,0 +1,108 @@
|
||||
HTTP 缓存 |
||||
============ |
||||
|
||||
除了前面章节讲到的服务器端缓存外, Web 应用还可以利用客户端缓存去节省相同页面内容的生成和传输时间。 |
||||
|
||||
通过配置 [[yii\filters\HttpCache]] 过滤器,控制器操作渲染的内容就能缓存在客户端。[[yii\filters\HttpCache|HttpCache]] 过滤器仅对 `GET` 和 `HEAD` 请求生效,它能为这些请求设置三种与缓存有关的 HTTP 头。 |
||||
|
||||
* [[yii\filters\HttpCache::lastModified|Last-Modified]] |
||||
* [[yii\filters\HttpCache::etagSeed|Etag]] |
||||
* [[yii\filters\HttpCache::cacheControlHeader|Cache-Control]] |
||||
|
||||
|
||||
## `Last-Modified` 头 <a name="last-modified"></a> |
||||
|
||||
`Last-Modified` 头使用时间戳标明页面自上次客户端缓存后是否被修改过。 |
||||
|
||||
通过配置 [[yii\filters\HttpCache::lastModified]] 属性向客户端发送 `Last-Modified` 头。该属性的值应该为 PHP callable 类型,返回的是页面修改时的 Unix 时间戳。该 callable 的参数和返回值应该如下: |
||||
|
||||
```php |
||||
/** |
||||
* @param Action $action 当前处理的操作对象 |
||||
* @param array $params “params” 属性的值 |
||||
* @return integer 页面修改时的 Unix 时间戳 |
||||
*/ |
||||
function ($action, $params) |
||||
``` |
||||
|
||||
以下是使用 `Last-Modified` 头的示例: |
||||
|
||||
```php |
||||
public function behaviors() |
||||
{ |
||||
return [ |
||||
[ |
||||
'class' => 'yii\filters\HttpCache', |
||||
'only' => ['index'], |
||||
'lastModified' => function ($action, $params) { |
||||
$q = new \yii\db\Query(); |
||||
return $q->from('post')->max('updated_at'); |
||||
}, |
||||
], |
||||
]; |
||||
} |
||||
``` |
||||
|
||||
上述代码表明 HTTP 缓存只在 `index` 操作时启用。它会基于页面最后修改时间生成一个 `Last-Modified` HTTP 头。当浏览器第一次访问 `index` 页时,服务器将会生成页面并发送至客户端浏览器。之后客户端浏览器在页面没被修改期间访问该页,服务器将不会重新生成页面,浏览器会使用之前客户端缓存下来的内容。因此服务端渲染和内容传输都将省去。 |
||||
|
||||
|
||||
## `ETag` 头 <a name="etag"></a> |
||||
|
||||
“Entity Tag”(实体标签,简称 ETag)使用一个哈希值表示页面内容。如果页面被修改过,哈希值也会随之改变。通过对比客户端的哈希值和服务器端生成的哈希值,浏览器就能判断页面是否被修改过,进而决定是否应该重新传输内容。 |
||||
|
||||
通过配置 [[yii\filters\HttpCache::etagSeed]] 属性向客户端发送 `ETag` 头。该属性的值应该为 PHP callable 类型,返回的是一段种子字符用来生成 ETag 哈希值。该 callable 的参数和返回值应该如下: |
||||
|
||||
```php |
||||
/** |
||||
* @param Action $action 当前处理的操作对象 |
||||
* @param array $params “params” 属性的值 |
||||
* @return string 一段种子字符用来生成 ETag 哈希值 |
||||
*/ |
||||
function ($action, $params) |
||||
``` |
||||
|
||||
以下是使用 `ETag` 头的示例: |
||||
|
||||
```php |
||||
public function behaviors() |
||||
{ |
||||
return [ |
||||
[ |
||||
'class' => 'yii\filters\HttpCache', |
||||
'only' => ['view'], |
||||
'etagSeed' => function ($action, $params) { |
||||
$post = $this->findModel(\Yii::$app->request->get('id')); |
||||
return serialize([$post->title, $post->content]); |
||||
}, |
||||
], |
||||
]; |
||||
} |
||||
``` |
||||
|
||||
上述代码表明 HTTP 缓存只在 `view` 操作时启用。它会基于用户请求的标题和内容生成一个 `ETag` HTTP 头。当浏览器第一次访问 `view` 页时,服务器将会生成页面并发送至客户端浏览器。之后客户端浏览器标题和内容没被修改在期间访问该页,服务器将不会重新生成页面,浏览器会使用之前客户端缓存下来的内容。因此服务端渲染和内容传输都将省去。 |
||||
|
||||
ETag 相比 `Last-Modified` 能实现更复杂和更精确的缓存策略。例如,当站点切换到另一个主题时可以使 ETag 失效。 |
||||
|
||||
复杂的 Etag 生成种子可能会违背使用 `HttpCache` 的初衷而引起不必要的性能开销,因为响应每一次请求都需要重新计算 Etag。请试着找出一个最简单的表达式去触发 Etag 失效。 |
||||
|
||||
|
||||
> 注意:为了遵循 [RFC 2616, section 13.3.4(HTTP 协议)](http://tools.ietf.org/html/rfc2616#section-13.3.4),如果同时配置了 `ETag` 和 `Last-Modified` 头,`HttpCache` 将会同时发送它们,因此它们将被同时用于客户端的缓存失效校验。 |
||||
|
||||
|
||||
## `Cache-Control` 头 <a name="cache-control"></a> |
||||
|
||||
`Cache-Control` 头指定了页面的常规缓存策略。可以通过配置 [[yii\filters\HttpCache::cacheControlHeader]] 属性发送相应的头信息。默认发送以下头: |
||||
|
||||
``` |
||||
Cache-Control: public, max-age=3600 |
||||
``` |
||||
|
||||
## 会话缓存限制器 <a name="session-cache-limiter"></a> |
||||
|
||||
当页面使 session 时,PHP 将会按照 PHP.INI 中所设置的 `session.cache_limiter` 值自动发送一些缓存相关的 HTTP 头。这些 HTTP 头有可能会干扰你原本设置的 `HttpCache` 或让其失效。为了避免此问题,默认情况下 `HttpCache` 禁止自动发送这些头。想改变这一行为,可以配置 [[yii\filters\HttpCache::sessionCacheLimiter]] 属性。该属性接受一个字符串值,包括 `public`,`private`,`private_no_expire`,和 `nocache`。请参考 PHP 手册中的[缓存限制器](http://www.php.net/manual/en/function.session-cache-limiter.php)了解这些值的含义。 |
||||
|
||||
|
||||
## SEO 影响 <a name="seo-implications"></a> |
||||
|
||||
搜索引擎趋向于遵循站点的缓存头。因为一些爬虫的抓取频率有限制,启用缓存头可以可以减少重复请求数量,增加爬虫抓取效率(译者:大意如此,但搜索引擎的排名规则不了解,好的缓存策略应该是可以为用户体验加分的)。 |
||||
|
@ -0,0 +1,40 @@
|
||||
页面缓存 |
||||
============ |
||||
|
||||
页面缓存指的是在服务器端缓存整个页面的内容。随后当同一个页面被请求时,内容将从缓存中取出,而不是重新生成。 |
||||
|
||||
页面缓存由 [[yii\filters\PageCache]] 类提供支持,该类是一个[过滤器](structure-filters.md)。它可以像这样在控制器类中使用: |
||||
|
||||
```php |
||||
public function behaviors() |
||||
{ |
||||
return [ |
||||
[ |
||||
'class' => 'yii\filters\PageCache', |
||||
'only' => ['index'], |
||||
'duration' => 60, |
||||
'variations' => [ |
||||
\Yii::$app->language, |
||||
], |
||||
'dependency' => [ |
||||
'class' => 'yii\caching\DbDependency', |
||||
'sql' => 'SELECT COUNT(*) FROM post', |
||||
], |
||||
], |
||||
]; |
||||
} |
||||
``` |
||||
|
||||
上述代码表示页面缓存只在 `index` 操作时启用,页面内容最多被缓存 60 秒,会随着当前应用的语言更改而变化。如果文章总数发生变化则缓存的页面会失效。 |
||||
|
||||
如你所见,页面缓存和[片段缓存](caching-fragment.md)极其相似。它们都支持 `duration`,`dependencies`,`variations` 和 `enabled` 配置选项。它们的主要区别是页面缓存是由[过滤器](structure-filters.md)实现,而片段缓存则是一个[小部件](structure-widgets.md)。 |
||||
|
||||
你可以在使用页面缓存的同时,使用[片段缓存](caching-fragment.md)和[动态内容](caching-fragment.md#dynamic-content)。 |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,241 @@
|
||||
事件 |
||||
====== |
||||
|
||||
事件可以将自定义代码“注入”到现有代码中的特定执行点。附加自定义代码到某个事件,当这个事件被触发时,这些代码就会自动执行。例如,邮件程序对象成功发出消息时可触发 `messageSent` 事件。如想追踪成功发送的消息,可以附加相应追踪代码到 `messageSent` 事件。 |
||||
|
||||
Yii 引入了名为 [[yii\base\Component]] 的基类以支持事件。如果一个类需要触发事件就应该继承 [[yii\base\Component]] 或其子类。 |
||||
|
||||
|
||||
事件处理器(Event Handlers) |
||||
-------------- |
||||
|
||||
事件处理器是一个[PHP 回调函数](http://www.php.net/manual/en/language.types.callable.php),当它所附加到的事件被触发时它就会执行。可以使用以下回调函数之一: |
||||
|
||||
- 字符串形式指定的 PHP 全局函数,如 `'trim'` ; |
||||
- 对象名和方法名数组形式指定的对象方法,如 `[$object, $method]` ; |
||||
- 类名和方法名数组形式指定的静态类方法,如 `[$class, $method]` ; |
||||
- 匿名函数,如 `function ($event) { ... }` 。 |
||||
|
||||
事件处理器的格式是: |
||||
|
||||
```php |
||||
function ($event) { |
||||
// $event 是 yii\base\Event 或其子类的对象 |
||||
} |
||||
``` |
||||
|
||||
通过 `$event` 参数,事件处理器就获得了以下有关事件的信息: |
||||
|
||||
- [[yii\base\Event::name|event name]]:事件名 |
||||
- [[yii\base\Event::sender|event sender]]:调用 `trigger()` 方法的对象 |
||||
- [[yii\base\Event::data|custom data]]:附加事件处理器时传入的数据,默认为空,后文详述 |
||||
|
||||
|
||||
附加事件处理器 |
||||
---------------- |
||||
|
||||
调用 [[yii\base\Component::on()]] 方法来附加处理器到事件上。如: |
||||
|
||||
```php |
||||
$foo = new Foo; |
||||
|
||||
// 处理器是全局函数 |
||||
$foo->on(Foo::EVENT_HELLO, 'function_name'); |
||||
|
||||
// 处理器是对象方法 |
||||
$foo->on(Foo::EVENT_HELLO, [$object, 'methodName']); |
||||
|
||||
// 处理器是静态类方法 |
||||
$foo->on(Foo::EVENT_HELLO, ['app\components\Bar', 'methodName']); |
||||
|
||||
// 处理器是匿名函数 |
||||
$foo->on(Foo::EVENT_HELLO, function ($event) { |
||||
//事件处理逻辑 |
||||
}); |
||||
``` |
||||
|
||||
附加事件处理器时可以提供额外数据作为 [[yii\base\Component::on()]] 方法的第三个参数。数据在事件被触发和处理器被调用时能被处理器使用。如: |
||||
|
||||
```php |
||||
// 当事件被触发时以下代码显示 "abc" |
||||
// 因为 $event->data 包括被传递到 "on" 方法的数据 |
||||
$foo->on(Foo::EVENT_HELLO, function ($event) { |
||||
echo $event->data; |
||||
}, 'abc'); |
||||
``` |
||||
|
||||
|
||||
时间处理器顺序 |
||||
----------------- |
||||
|
||||
可以附加一个或多个处理器到一个事件。当事件被触发,已附加的处理器将按附加次序依次调用。如果某个处理器需要停止其后的处理器调用,可以设置 `$event` 参数的 [yii\base\Event::handled]] 属性为真,如下: |
||||
|
||||
```php |
||||
$foo->on(Foo::EVENT_HELLO, function ($event) { |
||||
$event->handled = true; |
||||
}); |
||||
``` |
||||
|
||||
默认新附加的事件处理器排在已存在处理器队列的最后。因此,这个处理器将在事件被触发时最后一个调用。在处理器队列最前面插入新处理器将使该处理器最先调用,可以传递第四个参数 `$append` 为假并调用 [[yii\base\Component::on()]] 方法实现: |
||||
|
||||
``php |
||||
$foo->on(Foo::EVENT_HELLO, function ($event) { |
||||
// 这个处理器将被插入到处理器队列的第一位... |
||||
}, $data, false); |
||||
``` |
||||
|
||||
|
||||
触发事件 |
||||
---------- |
||||
|
||||
事件通过调用 [[yii\base\Component::trigger()]] 方法触发,此方法须传递**事件名**,还可以传递一个事件对象,用来传递参数到事件处理器。如: |
||||
|
||||
```php |
||||
namespace app\components; |
||||
|
||||
use yii\base\Component; |
||||
use yii\base\Event; |
||||
|
||||
class Foo extends Component |
||||
{ |
||||
const EVENT_HELLO = 'hello'; |
||||
|
||||
public function bar() |
||||
{ |
||||
$this->trigger(self::EVENT_HELLO); |
||||
} |
||||
} |
||||
``` |
||||
|
||||
以上代码当调用 `bar()` ,它将触发名为 `hello` 的事件。 |
||||
|
||||
> 提示:推荐使用类常量来表示事件名。上例中,常量 `EVENT_HELLO` 用来表示 `hello` 。这有两个好处。第一,它可以防止拼写错误并支持 IDE 的自动完成。第二,只要简单检查常量声明就能了解一个类支持哪些事件。 |
||||
|
||||
有时想要在触发事件时同时传递一些额外信息到事件处理器。例如,邮件程序要传递消息信息到 `messageSent` 事件的处理器以便处理器了解哪些消息被发送了。为此,可以提供一个事件对象作为 [[yii\base\Component::trigger()]] 方法的第二个参数。这个事件对象必须是 [[yii\base\Event]] 类或其子类的实例。如: |
||||
|
||||
```php |
||||
namespace app\components; |
||||
|
||||
use yii\base\Component; |
||||
use yii\base\Event; |
||||
|
||||
class MessageEvent extends Event |
||||
{ |
||||
public $message; |
||||
} |
||||
|
||||
class Mailer extends Component |
||||
{ |
||||
const EVENT_MESSAGE_SENT = 'messageSent'; |
||||
|
||||
public function send($message) |
||||
{ |
||||
// ...发送 $message 的逻辑... |
||||
|
||||
$event = new MessageEvent; |
||||
$event->message = $message; |
||||
$this->trigger(self::EVENT_MESSAGE_SENT, $event); |
||||
} |
||||
} |
||||
``` |
||||
|
||||
当 [[yii\base\Component::trigger()]] 方法被调用时,它将调用所有附加到命名事件(trigger 方法第一个参数)的事件处理器。 |
||||
|
||||
|
||||
移除事件处理器 |
||||
--------------- |
||||
|
||||
从事件移除处理器,调用 [[yii\base\Component::off()]] 方法。如: |
||||
|
||||
```php |
||||
// 处理器是全局函数 |
||||
$foo->off(Foo::EVENT_HELLO, 'function_name'); |
||||
|
||||
// 处理器是对象方法 |
||||
$foo->off(Foo::EVENT_HELLO, [$object, 'methodName']); |
||||
|
||||
// 处理器是静态类方法 |
||||
$foo->off(Foo::EVENT_HELLO, ['app\components\Bar', 'methodName']); |
||||
|
||||
// 处理器是匿名函数 |
||||
$foo->off(Foo::EVENT_HELLO, $anonymousFunction); |
||||
``` |
||||
|
||||
注意当匿名函数附加到事件后一般不要尝试移除匿名函数,除非你在某处存储了它。以上示例中,假设匿名函数存储为变量 `$anonymousFunction` 。 |
||||
|
||||
移除事件的全部处理器,简单调用 [[yii\base\Component::off()]] 即可,不需要第二个参数: |
||||
|
||||
```php |
||||
$foo->off(Foo::EVENT_HELLO); |
||||
``` |
||||
|
||||
类级别的事件处理器 |
||||
------------------- |
||||
|
||||
以上部分,我们叙述了在**实例级别**如何附加处理器到事件。有时想要一个类的所有实例而不是一个指定的实例都响应一个被触发的事件,并不是一个个附加事件处理器到每个实例,而是通过调用静态方法 [[yii\base\Event::on()]] 在**类级别**附加处理器。 |
||||
|
||||
例如,[活动记录](db-active-record.md)对象要在每次往数据库新增一条新记录时触发一个 [[yii\base\ActiveRecord::EVENT_AFTER_INSERT]] 事件。要追踪每个[活动记录](db-active-record.md)对象的新增记录完成情况,应如下写代码: |
||||
|
||||
```php |
||||
use Yii; |
||||
use yii\base\Event; |
||||
use yii\db\ActiveRecord; |
||||
|
||||
Event::on(ActiveRecord::className(), ActiveRecord::EVENT_AFTER_INSERT, function ($event) { |
||||
Yii::trace(get_class($event->sender) . ' is inserted'); |
||||
}); |
||||
``` |
||||
|
||||
每当 [[yii\base\ActiveRecord|ActiveRecord]] 或其子类的实例触发 [[yii\base\ActiveRecord::EVENT_AFTER_INSERT|EVENT_AFTER_INSERT]] 事件时,这个事件处理器都会执行。在这个处理器中,可以通过 `$event->sender` 获取触发事件的对象。 |
||||
|
||||
当对象触发事件时,它首先调用实例级别的处理器,然后才会调用类级别处理器。 |
||||
|
||||
可调用静态方法[[yii\base\Event::trigger()]]来触发一个**类级别**事件。类级别事件不与特定对象相关联。因此,它只会引起类级别事件处理器的调用。如: |
||||
|
||||
```php |
||||
use yii\base\Event; |
||||
|
||||
Event::on(Foo::className(), Foo::EVENT_HELLO, function ($event) { |
||||
echo $event->sender; // 显示 "app\models\Foo" |
||||
}); |
||||
|
||||
Event::trigger(Foo::className(), Foo::EVENT_HELLO); |
||||
``` |
||||
|
||||
注意这种情况下 `$event->sender` 指向触发事件的类名而不是对象实例。 |
||||
|
||||
> 注意:因为类级别的处理器响应类和其子类的所有实例触发的事件,必须谨慎使用,尤其是底层的基类,如 [[yii\base\Object]]。 |
||||
|
||||
移除类级别的事件处理器只需调用[[yii\base\Event::off()]],如: |
||||
|
||||
```php |
||||
// 移除 $handler |
||||
Event::off(Foo::className(), Foo::EVENT_HELLO, $handler); |
||||
|
||||
// 移除 Foo::EVENT_HELLO 事件的全部处理器 |
||||
Event::off(Foo::className(), Foo::EVENT_HELLO); |
||||
``` |
||||
|
||||
|
||||
全局事件 |
||||
------------- |
||||
|
||||
所谓**全局事件**实际上是一个基于以上叙述的事件机制的戏法。它需要一个全局可访问的单例,如[应用](structure-applications.md)实例。 |
||||
|
||||
事件触发者不调用其自身的 `trigger()` 方法,而是调用单例的 `trigger()` 方法来触发全局事件。类似地,事件处理器被附加到单例的事件。如: |
||||
|
||||
```php |
||||
use Yii; |
||||
use yii\base\Event; |
||||
use app\components\Foo; |
||||
|
||||
Yii::$app->on('bar', function ($event) { |
||||
echo get_class($event->sender); // 显示 "app\components\Foo" |
||||
}); |
||||
|
||||
Yii::$app->trigger('bar', new Event(['sender' => new Foo])); |
||||
``` |
||||
|
||||
全局事件的一个好处是当附加处理器到一个对象要触发的事件时,不需要产生该对象。相反,处理器附加和事件触发都通过单例(如应用实例)完成。 |
||||
|
||||
然而,因为全局事件的命名空间由各方共享,应合理命名全局事件,如引入一些命名空间(例:"frontend.mail.sent", "backend.mail.sent")。 |
@ -0,0 +1,527 @@
|
||||
输入验证 |
||||
================ |
||||
|
||||
一般说来,程序猿永远不应该信任从最终用户直接接收到的数据,并且使用它们之前应始终先验证其可靠性。 |
||||
|
||||
要给 [model](structure-models.md) 填充其所需的用户输入数据,你可以调用 [[yii\base\Model::validate()]] 方法验证它们。该方法会返回一个布尔值,指明是否通过验证。若没有通过,你能通过 [[yii\base\Model::errors]] 属性获取相应的报错信息。比如, |
||||
|
||||
```php |
||||
$model = new \app\models\ContactForm; |
||||
|
||||
// 用用户输入来填充模型的特性 |
||||
$model->attributes = \Yii::$app->request->post('ContactForm'); |
||||
|
||||
if ($model->validate()) { |
||||
// 若所有输入都是有效的 |
||||
} else { |
||||
// 有效性验证失败:$errors 属性就是存储错误信息的数组 |
||||
$errors = $model->errors; |
||||
} |
||||
``` |
||||
|
||||
`validate()` 方法,在幕后为执行验证操作,进行了以下步骤: |
||||
|
||||
1. 通过从 [[yii\base\Model::scenarios()]] 方法返回基于当前 [[yii\base\Model::scenario|场景(scenario)]] 的特性属性列表,算出哪些特性应该进行有效性验证。这些属性被称作 *active attributes*(激活特性)。 |
||||
2. 通过从 [[yii\base\Model::rules()]] 方法返回基于当前 [[yii\base\Model::scenario|场景(scenario)]] 的验证规则列表,这些规则被称作 *active rules*(激活规则)。 |
||||
3. 用每个激活规则去验证每个与之关联的激活特性。若失败,则记录下对应模型特性的错误信息。 |
||||
|
||||
|
||||
## 声明规则(Rules) <a name="declaring-rules"></a> |
||||
|
||||
要让 `validate()` 方法起作用,你需要声明与需验证模型特性相关的验证规则。为此,需要重写 [[yii\base\Model::rules()]] 方法。下面的例子展示了如何声明用于验证 `ContactForm` 模型的相关验证规则: |
||||
|
||||
```php |
||||
public function rules() |
||||
{ |
||||
return [ |
||||
// name,email,subject 和 body 特性是 `require`(必填)的 |
||||
[['name', 'email', 'subject', 'body'], 'required'], |
||||
|
||||
// email 特性必须是一个有效的 email 地址 |
||||
['email', 'email'], |
||||
]; |
||||
} |
||||
``` |
||||
|
||||
[[yii\base\Model::rules()|rules()]] 方法应返回一个由规则所组成的数组,每一个规则都呈现为以下这类格式的小数组: |
||||
|
||||
```php |
||||
[ |
||||
// required, specifies which attributes should be validated by this rule. |
||||
// For a single attribute, you can use the attribute name directly |
||||
// without having it in an array instead of an array |
||||
['attribute1', 'attribute2', ...], |
||||
|
||||
// required, specifies the type of this rule. |
||||
// It can be a class name, validator alias, or a validation method name |
||||
'validator', |
||||
|
||||
// optional, specifies in which scenario(s) this rule should be applied |
||||
// if not given, it means the rule applies to all scenarios |
||||
// You may also configure the "except" option if you want to apply the rule |
||||
// to all scenarios except the listed ones |
||||
'on' => ['scenario1', 'scenario2', ...], |
||||
|
||||
// optional, specifies additional configurations for the validator object |
||||
'property1' => 'value1', 'property2' => 'value2', ... |
||||
] |
||||
``` |
||||
|
||||
For each rule you must specify at least which attributes the rule applies to and what is the type of the rule. |
||||
You can specify the rule type in one of the following forms: |
||||
|
||||
* the alias of a core validator, such as `required`, `in`, `date`, etc. Please refer to |
||||
the [Core Validators](tutorial-core-validators.md) for the complete list of core validators. |
||||
* the name of a validation method in the model class, or an anonymous function. Please refer to the |
||||
[Inline Validators](#inline-validators) subsection for more details. |
||||
* the name of a validator class. Please refer to the [Standalone Validators](#standalone-validators) |
||||
subsection for more details. |
||||
|
||||
A rule can be used to validate one or multiple attributes, and an attribute may be validated by one or multiple rules. |
||||
A rule may be applied in certain [scenarios](structure-models.md#scenarios) only by specifying the `on` option. |
||||
If you do not specify an `on` option, it means the rule will be applied to all scenarios. |
||||
|
||||
When the `validate()` method is called, it does the following steps to perform validation: |
||||
|
||||
1. Determine which attributes should be validated by checking the current [[yii\base\Model::scenario|scenario]] |
||||
against the scenarios declared in [[yii\base\Model::scenarios()]]. These attributes are the active attributes. |
||||
2. Determine which rules should be applied by checking the current [[yii\base\Model::scenario|scenario]] |
||||
against the rules declared in [[yii\base\Model::rules()]]. These rules are the active rules. |
||||
3. Use each active rule to validate each active attribute which is associated with the rule. |
||||
|
||||
According to the above validation steps, 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()`. |
||||
|
||||
|
||||
### 自定义错误信息 <a name="customizing-error-messages"></a> |
||||
|
||||
Most validators have default error messages that will be added to the model being validated when its attributes |
||||
fail the validation. For example, the [[yii\validators\RequiredValidator|required]] validator will add |
||||
a message "Username cannot be blank." to a model when the `username` attribute fails the rule using this validator. |
||||
|
||||
You can customize the error message of a rule by specifying the `message` property when declaring the rule, |
||||
like the following, |
||||
|
||||
```php |
||||
public function rules() |
||||
{ |
||||
return [ |
||||
['username', 'required', 'message' => 'Please choose a username.'], |
||||
]; |
||||
} |
||||
``` |
||||
|
||||
Some validators may support additional error messages to more precisely describe different causes of |
||||
validation failures. For example, the [[yii\validators\NumberValidator|number]] validator supports |
||||
[[yii\validators\NumberValidator::tooBig|tooBig]] and [[yii\validators\NumberValidator::tooSmall|tooSmall]] |
||||
to describe the validation failure when the value being validated is too big and too small, respectively. |
||||
You may configure these error messages like configuring other properties of validators in a validation rule. |
||||
|
||||
|
||||
### 验证事件 <a name="validation-events"></a> |
||||
|
||||
When [[yii\base\Model::validate()]] is called, it will call two methods that you may override to customize |
||||
the validation process: |
||||
|
||||
* [[yii\base\Model::beforeValidate()]]: the default implementation will trigger a [[yii\base\Model::EVENT_BEFORE_VALIDATE]] |
||||
event. You may either override this method or respond to this event to do some preprocessing work |
||||
(e.g. normalizing data inputs) before the validation occurs. The method should return a boolean value indicating |
||||
whether the validation should proceed or not. |
||||
* [[yii\base\Model::afterValidate()]]: the default implementation will trigger a [[yii\base\Model::EVENT_AFTER_VALIDATE]] |
||||
event. You may either override this method or respond to this event to do some postprocessing work after |
||||
the validation is completed. |
||||
|
||||
|
||||
### 条件式验证 <a name="conditional-validation"></a> |
||||
|
||||
To validate attributes only when certain conditions apply, e.g. the validation of one attribute depends |
||||
on the value of another attribute you can use the [[yii\validators\Validator::when|when]] property |
||||
to define such conditions. For example, |
||||
|
||||
```php |
||||
[ |
||||
['state', 'required', 'when' => function($model) { |
||||
return $model->country == 'USA'; |
||||
}], |
||||
] |
||||
``` |
||||
|
||||
The [[yii\validators\Validator::when|when]] property takes a PHP callable with the following signature: |
||||
|
||||
```php |
||||
/** |
||||
* @param Model $model the model being validated |
||||
* @param string $attribute the attribute being validated |
||||
* @return boolean whether the rule should be applied |
||||
*/ |
||||
function ($model, $attribute) |
||||
``` |
||||
|
||||
If you also need to support client-side conditional validation, you should configure |
||||
the [[yii\validators\Validator::whenClient|whenClient]] property which takes a string representing a JavaScript |
||||
function whose return value determines whether to apply the rule or not. For example, |
||||
|
||||
```php |
||||
[ |
||||
['state', 'required', 'when' => function ($model) { |
||||
return $model->country == 'USA'; |
||||
}, 'whenClient' => "function (attribute, value) { |
||||
return $('#country').value == 'USA'; |
||||
}"], |
||||
] |
||||
``` |
||||
|
||||
|
||||
### 数据过滤 <a name="data-filtering"></a> |
||||
|
||||
User inputs often need to be filtered or preprocessed. For example, you may want to trim the spaces around the |
||||
`username` input. You may use validation rules to achieve this goal. |
||||
|
||||
The following examples shows how to trim the spaces in the inputs and turn empty inputs into nulls by using |
||||
the [trim](tutorial-core-validators.md#trim) and [default](tutorial-core-validators.md#default) core validators: |
||||
|
||||
```php |
||||
[ |
||||
[['username', 'email'], 'trim'], |
||||
[['username', 'email'], 'default'], |
||||
] |
||||
``` |
||||
|
||||
You may also use the more general [filter](tutorial-core-validators.md#filter) validator to perform more complex |
||||
data filtering. |
||||
|
||||
As you can see, these validation rules do not really validate the inputs. Instead, they will process the values |
||||
and save them back to the attributes being validated. |
||||
|
||||
|
||||
### 处理空输入 <a name="handling-empty-inputs"></a> |
||||
|
||||
When input data are submitted from HTML forms, you often need to assign some default values to the inputs |
||||
if they are empty. You can do so by using the [default](tutorial-core-validators.md#default) validator. For example, |
||||
|
||||
```php |
||||
[ |
||||
// set "username" and "email" as null if they are empty |
||||
[['username', 'email'], 'default'], |
||||
|
||||
// set "level" to be 1 if it is empty |
||||
['level', 'default', 'value' => 1], |
||||
] |
||||
``` |
||||
|
||||
By default, an input is considered empty if its value is an empty string, an empty array or a null. |
||||
You may customize the default empty detection logic by configuring the the [[yii\validators\Validator::isEmpty]] property |
||||
with a PHP callable. For example, |
||||
|
||||
```php |
||||
[ |
||||
['agree', 'required', 'isEmpty' => function ($value) { |
||||
return empty($value); |
||||
}], |
||||
] |
||||
``` |
||||
|
||||
> Note: Most validators do not handle empty inputs if their [[yii\base\Validator::skipOnEmpty]] property takes |
||||
the default value true. They will simply be skipped during validation if their associated attributes receive empty |
||||
inputs. Among the [core validators](tutorial-core-validators.md), only the `captcha`, `default`, `filter`, |
||||
`required`, and `trim` validators will handle empty inputs. |
||||
|
||||
|
||||
## Ad Hoc Validation <a name="ad-hoc-validation"></a> |
||||
|
||||
Sometimes you need to do *ad hoc validation* for values that are not bound to any model. |
||||
|
||||
If you only need to perform one type of validation (e.g. validating email addresses), you may call |
||||
the [[yii\validators\Validator::validate()|validate()]] method of the desired validator, like the following: |
||||
|
||||
```php |
||||
$email = 'test@example.com'; |
||||
$validator = new yii\validators\EmailValidator(); |
||||
|
||||
if ($validator->validate($email, $error)) { |
||||
echo 'Email is valid.'; |
||||
} else { |
||||
echo $error; |
||||
} |
||||
``` |
||||
|
||||
> Note: Not all validators support such kind of validation. An example is the [unique](tutorial-core-validators.md#unique) |
||||
core validator which is designed to work with a model only. |
||||
|
||||
If you need to perform multiple validations against several values, you can use [[yii\base\DynamicModel]] |
||||
which supports declaring both attributes and rules on the fly. Its usage is like the following: |
||||
|
||||
```php |
||||
public function actionSearch($name, $email) |
||||
{ |
||||
$model = DynamicModel::validateData(compact('name', 'email'), [ |
||||
[['name', 'email'], 'string', 'max' => 128], |
||||
['email', 'email'], |
||||
]); |
||||
|
||||
if ($model->hasErrors()) { |
||||
// validation fails |
||||
} else { |
||||
// validation succeeds |
||||
} |
||||
} |
||||
``` |
||||
|
||||
The [[yii\base\DynamicModel::validateData()]] method creates an instance of `DynamicModel`, defines the attributes |
||||
using the given data (`name` and `email` in this example), and then calls [[yii\base\Model::validate()]] |
||||
with the given rules. |
||||
|
||||
Alternatively, you may use the following more "classic" syntax to perform ad hoc data validation: |
||||
|
||||
```php |
||||
public function actionSearch($name, $email) |
||||
{ |
||||
$model = new DynamicModel(compact('name', 'email')); |
||||
$model->addRule(['name', 'email'], 'string', ['max' => 128]) |
||||
->addRule('email', 'email') |
||||
->validate(); |
||||
|
||||
if ($model->hasErrors()) { |
||||
// validation fails |
||||
} else { |
||||
// validation succeeds |
||||
} |
||||
} |
||||
``` |
||||
|
||||
After validation, you can check if the validation succeeds or not by calling the |
||||
[[yii\base\DynamicModel::hasErrors()|hasErrors()]] method, and then get the validation errors from the |
||||
[[yii\base\DynamicModel::errors|errors]] property, like you do with a normal model. |
||||
You may also access the dynamic attributes defined through the model instance, e.g., |
||||
`$model->name` and `$model->email`. |
||||
|
||||
|
||||
## 创建验证器(Validators) <a name="creating-validators"></a> |
||||
|
||||
Besides using the [core validators](tutorial-core-validators.md) included in the Yii releases, you may also |
||||
create your own validators. You may create inline validators or standalone validators. |
||||
|
||||
|
||||
### 行内验证器(Inline Validators) <a name="inline-validators"></a> |
||||
|
||||
An inline validator is one defined in terms of a model method or an anonymous function. The signature of |
||||
the method/function is: |
||||
|
||||
```php |
||||
/** |
||||
* @param string $attribute the attribute currently being validated |
||||
* @param array $params the additional name-value pairs given in the rule |
||||
*/ |
||||
function ($attribute, $params) |
||||
``` |
||||
|
||||
If an attribute fails the validation, the method/function should call [[yii\base\Model::addError()]] to save |
||||
the error message in the model so that it can be retrieved back later to present to end users. |
||||
|
||||
Below are some examples: |
||||
|
||||
```php |
||||
use yii\base\Model; |
||||
|
||||
class MyForm extends Model |
||||
{ |
||||
public $country; |
||||
public $token; |
||||
|
||||
public function rules() |
||||
{ |
||||
return [ |
||||
// an inline validator defined as the model method validateCountry() |
||||
['country', 'validateCountry'], |
||||
|
||||
// an inline validator defined as an anonymous function |
||||
['token', function ($attribute, $params) { |
||||
if (!ctype_alnum($this->$attribute)) { |
||||
$this->addError($attribute, 'The token must contain letters or digits.'); |
||||
} |
||||
}], |
||||
]; |
||||
} |
||||
|
||||
public function validateCountry($attribute, $params) |
||||
{ |
||||
if (!in_array($this->$attribute, ['USA', 'Web'])) { |
||||
$this->addError($attribute, 'The country must be either "USA" or "Web".'); |
||||
} |
||||
} |
||||
} |
||||
``` |
||||
|
||||
> Note: By default, inline validators will not be applied if their associated attributes receive empty inputs |
||||
or if they have already failed some validation rules. If you want to make sure a rule is always applied, |
||||
you may configure the [[yii\validators\Validator::skipOnEmpty|skipOnEmpty]] and/or [[yii\validators\Validator::skipOnError|skipOnError]] |
||||
properties to be false in the rule declarations. For example: |
||||
> ```php |
||||
[ |
||||
['country', 'validateCountry', 'skipOnEmpty' => false, 'skipOnError' => false], |
||||
] |
||||
``` |
||||
|
||||
|
||||
### 独立验证器(Standalone Validators) <a name="standalone-validators"></a> |
||||
|
||||
A standalone validator is a class extending [[yii\validators\Validator]] or its child class. You may implement |
||||
its validation logic by overriding the [[yii\validators\Validator::validateAttribute()]] method. If an attribute |
||||
fails the validation, call [[yii\base\Model::addError()]] to save the error message in the model, like you do |
||||
with [inline validators](#inline-validators). For example, |
||||
|
||||
```php |
||||
namespace app\components; |
||||
|
||||
use yii\validators\Validator; |
||||
|
||||
class CountryValidator extends Validator |
||||
{ |
||||
public function validateAttribute($model, $attribute) |
||||
{ |
||||
if (!in_array($model->$attribute, ['USA', 'Web'])) { |
||||
$this->addError($attribute, 'The country must be either "USA" or "Web".'); |
||||
} |
||||
} |
||||
} |
||||
``` |
||||
|
||||
If you want your validator to support validating a value without a model, you should also override |
||||
[[yii\validators\Validator::validate()]]. You may also override [[yii\validators\Validator::validateValue()]] |
||||
instead of `validateAttribute()` and `validate()` because by default the latter two methods are implemented |
||||
by calling `validateValue()`. |
||||
|
||||
|
||||
## 客户端验证器(Client-Side Validation) <a name="client-side-validation"></a> |
||||
|
||||
Client-side validation based on JavaScript is desirable when end users provide inputs via HTML forms, because |
||||
it allows users to find out input errors faster and thus provides better user experience. You may use or implement |
||||
a validator that supports client-side validation *in addition to* server-side validation. |
||||
|
||||
> Info: While client-side validation is desirable, it is not a must. It main purpose is to provider users better |
||||
experience. Like input data coming from end users, you should never trust client-side validation. For this reason, |
||||
you should always perform server-side validation by calling [[yii\base\Model::validate()]], like |
||||
described in the previous subsections. |
||||
|
||||
|
||||
### 使用客户端验证 <a name="using-client-side-validation"></a> |
||||
|
||||
Many [core validators](tutorial-core-validators.md) support client-side validation out-of-box. All you need to do |
||||
is just to use [[yii\widgets\ActiveForm]] to build your HTML forms. For example, `LoginForm` below declares two |
||||
rules: one uses the [required](tutorial-core-validators.md#required) core validator which is supported on both |
||||
client and server sides; the other uses the `validatePassword` inline validator which is only supported on the server |
||||
side. |
||||
|
||||
```php |
||||
namespace app\models; |
||||
|
||||
use yii\base\Model; |
||||
use app\models\User; |
||||
|
||||
class LoginForm extends Model |
||||
{ |
||||
public $username; |
||||
public $password; |
||||
|
||||
public function rules() |
||||
{ |
||||
return [ |
||||
// username and password are both required |
||||
[['username', 'password'], 'required'], |
||||
|
||||
// password is validated by validatePassword() |
||||
['password', 'validatePassword'], |
||||
]; |
||||
} |
||||
|
||||
public function validatePassword() |
||||
{ |
||||
$user = User::findByUsername($this->username); |
||||
|
||||
if (!$user || !$user->validatePassword($this->password)) { |
||||
$this->addError('password', 'Incorrect username or password.'); |
||||
} |
||||
} |
||||
} |
||||
``` |
||||
|
||||
The HTML form built by the following code contains two input fields `username` and `password`. |
||||
If you submit the form without entering anything, you will find the error messages requiring you |
||||
to enter something appear right away without any communication with the server. |
||||
|
||||
```php |
||||
<?php $form = yii\widgets\ActiveForm::begin(); ?> |
||||
<?= $form->field($model, 'username') ?> |
||||
<?= $form->field($model, 'password')->passwordInput() ?> |
||||
<?= Html::submitButton('Login') ?> |
||||
<?php yii\widgets\ActiveForm::end(); ?> |
||||
``` |
||||
|
||||
Behind the scene, [[yii\widgets\ActiveForm]] will read the validation rules declared in the model |
||||
and generate appropriate JavaScript code for validators that support client-side validation. When a user |
||||
changes the value of an input field or submit the form, the client-side validation JavaScript will be triggered. |
||||
|
||||
If you want to turn off client-side validation completely, you may configure the |
||||
[[yii\widgets\ActiveForm::enableClientValidation]] property to be false. You may also turn off client-side |
||||
validation of individual input fields by configuring their [[yii\widgets\ActiveField::enableClientValidation]] |
||||
property to be false. |
||||
|
||||
|
||||
### 实现客户端验证 <a name="implementing-client-side-validation"></a> |
||||
|
||||
To create a validator that supports client-side validation, you should implement the |
||||
[[yii\validators\Validator::clientValidateAttribute()]] method which returns a piece of JavaScript code |
||||
that performs the validation on the client side. Within the JavaScript code, you may use the following |
||||
predefined variables: |
||||
|
||||
- `attribute`: the name of the attribute being validated. |
||||
- `value`: the value being validated. |
||||
- `messages`: an array used to hold the validation error messages for the attribute. |
||||
|
||||
In the following example, we create a `StatusValidator` which validates if an input is a valid status input |
||||
against the existing status data. The validator supports both server side and client side validation. |
||||
|
||||
```php |
||||
namespace app\components; |
||||
|
||||
use yii\validators\Validator; |
||||
use app\models\Status; |
||||
|
||||
class StatusValidator extends Validator |
||||
{ |
||||
public function init() |
||||
{ |
||||
parent::init(); |
||||
$this->message = 'Invalid status input.'; |
||||
} |
||||
|
||||
public function validateAttribute($model, $attribute) |
||||
{ |
||||
$value = $model->$attribute; |
||||
if (!Status::find()->where(['id' => $value])->exists()) { |
||||
$model->addError($attribute, $this->message); |
||||
} |
||||
} |
||||
|
||||
public function clientValidateAttribute($model, $attribute, $view) |
||||
{ |
||||
$statuses = json_encode(Status::find()->select('id')->asArray()->column()); |
||||
$message = json_encode($this->message); |
||||
return <<<JS |
||||
if (!$.inArray(value, $statuses)) { |
||||
messages.push($message); |
||||
} |
||||
JS; |
||||
} |
||||
} |
||||
``` |
||||
|
||||
> Tip: The above code is given mainly to demonstrate how to support client-side validation. In practice, |
||||
you may use the [in](tutorial-core-validators.md#in) core validator to achieve the same goal. You may |
||||
write the validation rule like the following: |
||||
> ```php |
||||
[ |
||||
['status', 'in', 'range' => Status::find()->select('id')->asArray()->column()], |
||||
] |
||||
``` |
@ -0,0 +1,445 @@
|
||||
核心验证器(Core Validators) |
||||
=============== |
||||
|
||||
Yii 提供一系列常用的核心验证器,主要存在于 `yii\validators` 命名空间之下。为了避免使用冗长的类名,你可以直接用**昵称**来指定相应的核心验证器。比如你可以用 `required` 昵称代指 [[yii\validators\RequiredValidator]] 类: |
||||
|
||||
```php |
||||
public function rules() |
||||
{ |
||||
return [ |
||||
[['email', 'password'], 'required'], |
||||
]; |
||||
} |
||||
``` |
||||
|
||||
[[yii\validators\Validator::builtInValidators]] 属性声明了所有被支持的验证器昵称。 |
||||
|
||||
下面,我们将详细介绍每一款验证器的主要用法和属性。 |
||||
|
||||
|
||||
## [[yii\validators\BooleanValidator|boolean(布尔型)]] <a name="boolean"></a> |
||||
|
||||
```php |
||||
[ |
||||
// 检查 "selected" 是否为 0 或 1,无视数据类型 |
||||
['selected', 'boolean'], |
||||
|
||||
// 检查 "deleted" 是否为布尔类型,即 true 或 false |
||||
['deleted', 'boolean', 'trueValue' => true, 'falseValue' => false, 'strict' => true], |
||||
] |
||||
``` |
||||
|
||||
该验证器检查输入值是否为一个布尔值。 |
||||
|
||||
- `trueValue`: 代表**真**的值。默认为 `'1'`。 |
||||
- `falseValue`:代表**假**的值。默认为 `'0'`。 |
||||
- `strict`:是否要求待测输入必须严格匹配 `trueValue` 或 `falseValue`。默认为 `false`。 |
||||
|
||||
|
||||
> 注意:因为通过 HTML 表单传递的输入数据都是字符串类型,所以一般情况下你都需要保持 |
||||
[[yii\validators\BooleanValidator::strict|strict]] 属性为假。 |
||||
|
||||
|
||||
## [[yii\captcha\CaptchaValidator|captcha(验证码)]] <a name="captcha"></a> |
||||
|
||||
```php |
||||
[ |
||||
['verificationCode', 'captcha'], |
||||
] |
||||
``` |
||||
|
||||
该验证器通常配合 [[yii\captcha\CaptchaAction]] 以及 [[yii\captcha\Captcha]] |
||||
使用,以确保某一输入与 [[yii\captcha\Captcha|CAPTCHA]] 小部件所显示的验证代码(verification code)相同。 |
||||
|
||||
- `caseSensitive`:对验证代码的比对是否要求大小写敏感。默认为 false。 |
||||
- `captchaAction`:指向用于渲染 CAPTCHA 图片的 [[yii\captcha\CaptchaAction|CAPTCHA action]] 的 [路由](structure-controllers.md#routes)。默认为 `'site/captcha'`。 |
||||
- `skipOnEmpty`:当输入为空时,是否跳过验证。默认为 false,也就是输入值为必需项。 |
||||
|
||||
|
||||
## [[yii\validators\CompareValidator|compare(比较)]] <a name="compare"></a> |
||||
|
||||
```php |
||||
[ |
||||
// 检查 "password" 特性的值是否与 "password_repeat" 的值相同 |
||||
['password', 'compare'], |
||||
|
||||
// 检查年龄是否大于等于 30 |
||||
['age', 'compare', 'compareValue' => 30, 'operator' => '>='], |
||||
] |
||||
``` |
||||
|
||||
该验证器比较两个特定输入值之间的关系是否与 `operator` 属性所指定的相同。 |
||||
|
||||
- `compareAttribute`:用于与原特性相比较的特性名称。当该验证器被用于验证某目标特性时,该属性会默认为目标属性加后缀 `_repeat`。举例来说,若目标特性为 `password`,则该属性默认为 `password_repeat`。 |
||||
- `compareValue`:用于与输入值相比较的常量值。当该属性与 `compareAttribute` 属性同时被指定时,该属性优先被使用。 |
||||
- `operator`:比较操作符。默认为 `==`,意味着检查输入值是否与 `compareAttribute` 或 `compareValue` 的值相等。该属性支持如下操作符: |
||||
* `==`:检查两值是否相等。比对为非严格模式。 |
||||
* `===`:检查两值是否全等。比对为严格模式。 |
||||
* `!=`:检查两值是否不等。比对为非严格模式。 |
||||
* `!==`:检查两值是否不全等。比对为严格模式。 |
||||
* `>`:检查待测目标值是否大于给定被测值。 |
||||
* `>=`:检查待测目标值是否大于等于给定被测值。 |
||||
* `<`:检查待测目标值是否小于给定被测值。 |
||||
* `<=`:检查待测目标值是否小于等于给定被测值。 |
||||
|
||||
|
||||
## [[yii\validators\DateValidator|date(日期)]] <a name="date"></a> |
||||
|
||||
```php |
||||
[ |
||||
[['from', 'to'], 'date'], |
||||
] |
||||
``` |
||||
|
||||
该验证器检查输入值是否为适当格式的 date,time,或者 datetime。另外,它还可以帮你把输入值转换为一个 UNIX 时间戳并保存到 [[yii\validators\DateValidator::timestampAttribute|timestampAttribute]] 属性所指定的特性里。 |
||||
|
||||
- `format`:待测的 日期/时间 格式。请参考 |
||||
[date_create_from_format() 相关的 PHP 手册](http://www.php.net/manual/zh/datetime.createfromformat.php)了解设定格式字符串的更多细节。默认值为 `'Y-m-d'`。 |
||||
- `timestampAttribute`:用于保存用输入时间/日期转换出来的 UNIX 时间戳的特性。 |
||||
|
||||
|
||||
## [[yii\validators\DefaultValueValidator|default(默认值)]] <a name="default"></a> |
||||
|
||||
```php |
||||
[ |
||||
// 若 "age" 为空,则将其设为 null |
||||
['age', 'default', 'value' => null], |
||||
|
||||
// 若 "country" 为空,则将其设为 "USA" |
||||
['country', 'default', 'value' => 'USA'], |
||||
|
||||
// 若 "from" 和 "to" 为空,则分别给他们分配自今天起,3 天后和 6 天后的日期。 |
||||
[['from', 'to'], 'default', 'value' => function ($model, $attribute) { |
||||
return date('Y-m-d', strtotime($attribute === 'to' ? '+3 days' :'+6 days')); |
||||
}], |
||||
] |
||||
``` |
||||
|
||||
该验证器并不进行数据验证。而是,给为空的待测特性分配默认值。 |
||||
|
||||
- `value`:默认值,或一个返回默认值的 PHP Callable 对象(即回调函数)。它们会分配给检测为空的待测特性。PHP 回调方法的样式如下: |
||||
|
||||
```php |
||||
function foo($model, $attribute) { |
||||
// ... compute $value ... |
||||
return $value; |
||||
} |
||||
``` |
||||
|
||||
> 补充:如何判断待测值是否为空,被写在另外一个话题的[处理空输入](input-validation.md#handling-empty-inputs)章节。 |
||||
|
||||
|
||||
## [[yii\validators\NumberValidator|double(双精度浮点型)]] <a name="double"></a> |
||||
|
||||
```php |
||||
[ |
||||
// 检查 "salary" 是否为浮点数 |
||||
['salary', 'double'], |
||||
] |
||||
``` |
||||
|
||||
该验证器检查输入值是否为双精度浮点数。他等效于 [number](#number) 验证器。 |
||||
|
||||
- `max`:上限值(含界点)。若不设置,则验证器不检查上限。 |
||||
- `min`:下限值(含界点)。若不设置,则验证器不检查下限。 |
||||
|
||||
|
||||
## [[yii\validators\EmailValidator|email(电子邮件)]] <a name="email"></a> |
||||
|
||||
```php |
||||
[ |
||||
// 检查 "email" 是否为有效的邮箱地址 |
||||
['email', 'email'], |
||||
] |
||||
``` |
||||
|
||||
该验证器检查输入值是否为有效的邮箱地址。 |
||||
|
||||
- `allowName`:检查是否允许带名称的电子邮件地址 (e.g. `张三 <John.san@example.com>`)。 默认为 false。 |
||||
- `checkDNS`:检查邮箱域名是否存在,且有没有对应的 A 或 MX 记录。不过要知道,有的时候该项检查可能会因为临时性 DNS 故障而失败,哪怕它其实是有效的。默认为 false。 |
||||
- `enableIDN`:验证过程是否应该考虑 IDN(internationalized domain names,国际化域名,也称多语种域名,比如中文域名)。默认为 false。要注意但是为使用 IDN 验证功能,请先确保安装并开启 `intl` PHP 扩展,不然会导致抛出异常。 |
||||
|
||||
|
||||
## [[yii\validators\ExistValidator|exist(存在性)]] <a name="exist"></a> |
||||
|
||||
```php |
||||
[ |
||||
// a1 需要在 "a1" 特性所代表的字段内存在 |
||||
['a1', 'exist'], |
||||
|
||||
// a1 必需存在,但检验的是 a1 的值在字段 a2 中的存在性 |
||||
['a1', 'exist', 'targetAttribute' => 'a2'], |
||||
|
||||
// a1 和 a2 的值都需要存在,且它们都能收到错误提示 |
||||
[['a1', 'a2'], 'exist', 'targetAttribute' => ['a1', 'a2']], |
||||
|
||||
// a1 和 a2 的值都需要存在,只有 a1 能接收到错误信息 |
||||
['a1', 'exist', 'targetAttribute' => ['a1', 'a2']], |
||||
|
||||
// 通过同时在 a2 和 a3 字段中检查 a2 和 a1 的值来确定 a1 的存在性 |
||||
['a1', 'exist', 'targetAttribute' => ['a2', 'a1' => 'a3']], |
||||
|
||||
// a1 必需存在,若 a1 为数组,则其每个子元素都必须存在。 |
||||
['a1', 'exist', 'allowArray' => true], |
||||
] |
||||
``` |
||||
|
||||
该验证器检查输入值是否在某表字段中存在。它只对[活动记录](db-active-record.md)类型的模型类特性起作用,能支持对一个或多过字段的验证。 |
||||
|
||||
- `targetClass`:用于查找输入值的目标 [AR](db-active-record.md) 类。若不设置,则会使用正在进行验证的当前模型类。 |
||||
- `targetAttribute`:用于检查输入值存在性的 `targetClass` 的模型特性。 |
||||
- 若不设置,它会直接使用待测特性名(整个参数数组的首元素)。 |
||||
- 除了指定为字符串以外,你也可以用数组的形式,同时指定多个用于验证的表字段,数组的键和值都是代表字段的特性名,值表示 `targetClass` 的待测数据源字段,而键表示当前模型的待测特性名。 |
||||
- 若键和值相同,你可以只指定值。(如:`['a2']` 就代表 `['a2'=>'a2']`) |
||||
- `filter`:用于检查输入值存在性必然会进行数据库查询,而该属性为用于进一步筛选该查询的过滤条件。可以为代表额外查询条件的字符串或数组(关于查询条件的格式,请参考 [[yii\db\Query::where()]]);或者样式为 `function ($query)` 的匿名函数,`$query` 参数为你希望在该函数内进行修改的 [[yii\db\Query|Query]] 对象。 |
||||
- `allowArray`:是否允许输入值为数组。默认为 false。若该属性为 true 且输入值为数组,则数组的每个元素都必须在目标字段中存在。值得注意的是,若用吧 `targetAttribute` 设为多元素数组来验证被测值在多字段中的存在性时,该属性不能设置为 true。 |
||||
|
||||
> 译者注:[exist](#exist) 和 [unique](#unique) 验证器的机理和参数都相似,有点像一体两面的阴和阳。 |
||||
- 他们的区别是 exist 要求 `targetAttribute` 键所代表的的属性在其值所代表字段中找得到;而 unique 正相反,要求键所代表的的属性不能在其值所代表字段中被找到。 |
||||
- 从另一个角度来理解:他们都会在验证的过程中执行数据库查询,查询的条件即为where $v=$k (假设 `targetAttribute` 的其中一对键值对为 `$k => $v`)。unique 要求查询的结果数 `$count==0`,而 exist 则要求查询的结果数 `$count>0` |
||||
- 最后别忘了,unique 验证器不存在 `allowArray` 属性哦。 |
||||
|
||||
|
||||
## [[yii\validators\FileValidator|file(文件)]] <a name="file"></a> |
||||
|
||||
```php |
||||
[ |
||||
// 检查 "primaryImage" 是否为 PNG, JPG 或 GIF 格式的上传图片。 |
||||
// 文件大小必须小于 1MB |
||||
['primaryImage', 'file', 'extensions' => ['png', 'jpg', 'gif'], 'maxSize' => 1024*1024*1024], |
||||
] |
||||
``` |
||||
|
||||
该验证器检查输入值是否为一个有效的上传文件。 |
||||
|
||||
- `extensions`:可接受上传的文件扩展名列表。它可以是数组,也可以是用空格或逗号分隔各个扩展名的字符串 (e.g. "gif, jpg")。 |
||||
扩展名大小写不敏感。默认为 null,意味着所有扩展名都被接受。 |
||||
- `mimeTypes`:可接受上传的 MIME 类型列表。它可以是数组,也可以是用空格或逗号分隔各个 MIME 的字符串 (e.g. "image/jpeg, image/png")。 |
||||
Mime 类型名是大小写不敏感的。默认为 null,意味着所有 MIME 类型都被接受。 |
||||
- `minSize`:上传文件所需最少多少 Byte 的大小。默认为 null,代表没有下限。 |
||||
- `maxSize`:上传文件所需最多多少 Byte 的大小。默认为 null,代表没有上限。 |
||||
- `maxFiles`:给定特性最多能承载多少个文件。默认为 1,代表只允许单文件上传。若值大于一,那么输入值必须为包含最多 `maxFiles` 个上传文件元素的数组。 |
||||
- `checkExtensionByMimeType`:是否通过文件的 MIME 类型来判断其文件扩展。若由 MIME 判定的文件扩展与给定文件的扩展不一样,则文件会被认为无效。默认为 true,代表执行上述检测。 |
||||
|
||||
`FileValidator` 通常与 [[yii\web\UploadedFile]] 共同使用。请参考 [文件上传](input-file-upload.md)章节来了解有关文件上传与上传文件的检验的全部内容。 |
||||
|
||||
|
||||
## [[yii\validators\FilterValidator|filter(滤镜)]] <a name="filter"></a> |
||||
|
||||
```php |
||||
[ |
||||
// trim 掉 "username" 和 "email" 输入 |
||||
[['username', 'email'], 'filter', 'filter' => 'trim', 'skipOnArray' => true], |
||||
|
||||
// 标准化 "phone" 输入 |
||||
['phone', 'filter', 'filter' => function ($value) { |
||||
// 在此处标准化输入的电话号码 |
||||
return $value; |
||||
}], |
||||
] |
||||
``` |
||||
|
||||
该验证器并不进行数据验证。而是,给输入值应用一个滤镜,并在检验过程之后把它赋值回特性变量。 |
||||
|
||||
- `filter`:用于定义滤镜的 PHP 回调函数。可以为全局函数名,匿名函数,或其他。该函数的样式必须是 `function ($value) { return $newValue; }`。该属性不能省略,必须设置。 |
||||
- `skipOnArray`:是否在输入值为数组时跳过滤镜。默认为 false。请注意如果滤镜不能处理数组输入,你就应该把该属性设为 true。否则可能会导致 PHP Error 的发生。 |
||||
|
||||
> 技巧:如果你只是想要用 trim 处理下输入值,你可以直接用 [trim](#trim) 验证器的。 |
||||
|
||||
|
||||
## [[yii\validators\ImageValidator|image(图片)]] <a name="image"></a> |
||||
|
||||
```php |
||||
[ |
||||
// 检查 "primaryImage" 是否为适当尺寸的有效图片 |
||||
['primaryImage', 'image', 'extensions' => 'png, jpg', |
||||
'minWidth' => 100, 'maxWidth' => 1000, |
||||
'minHeight' => 100, 'maxHeight' => 1000, |
||||
], |
||||
] |
||||
``` |
||||
|
||||
该验证器检查输入值是否为代表有效的图片文件。它继承自 [file](#file) 验证器,并因此继承有其全部属性。除此之外,它还支持以下为图片检验而设的额外属性: |
||||
|
||||
- `minWidth`:图片的最小宽度。默认为 null,代表无下限。 |
||||
- `maxWidth`:图片的最大宽度。默认为 null,代表无上限。 |
||||
- `minHeight`:图片的最小高度。 默认为 null,代表无下限。 |
||||
- `maxHeight`:图片的最大高度。默认为 null,代表无上限。 |
||||
|
||||
|
||||
## [[yii\validators\RangeValidator|in(范围)]] <a name="in"></a> |
||||
|
||||
```php |
||||
[ |
||||
// 检查 "level" 是否为 1、2 或 3 中的一个 |
||||
['level', 'in', 'range' => [1, 2, 3]], |
||||
] |
||||
``` |
||||
|
||||
该验证器检查输入值是否存在于给定列表的范围之中。 |
||||
|
||||
- `range`:用于检查输入值的给定值列表。 |
||||
- `strict`:输入值与给定值直接的比较是否为严格模式(也就是类型与值都要相同,即全等)。默认为 false。 |
||||
- `not`:是否对验证的结果取反。默认为 false。当该属性被设置为 true,验证器检查输入值是否**不在**给定列表内。 |
||||
- `allowArray`:是否接受输入值为数组。当该值为 true 且输入值为数组时,数组内的每一个元素都必须在给定列表内存在,否则返回验证失败。 |
||||
|
||||
|
||||
## [[yii\validators\NumberValidator|integer(整数)]] <a name="integer"></a> |
||||
|
||||
```php |
||||
[ |
||||
// 检查 "age" 是否为整数 |
||||
['age', 'integer'], |
||||
] |
||||
``` |
||||
|
||||
该验证器检查输入值是否为整形。 |
||||
|
||||
- `max`:上限值(含界点)。若不设置,则验证器不检查上限。 |
||||
- `min`:下限值(含界点)。若不设置,则验证器不检查下限。 |
||||
|
||||
|
||||
## [[yii\validators\RegularExpressionValidator|match(正则表达式)]] <a name="match"></a> |
||||
|
||||
```php |
||||
[ |
||||
// 检查 "username" 是否由字母开头,且只包含单词字符 |
||||
['username', 'match', 'pattern' => '/^[a-z]\w*$/i'] |
||||
] |
||||
``` |
||||
|
||||
该验证器检查输入值是否匹配指定正则表达式。 |
||||
|
||||
- `pattern`:用于检测输入值的正则表达式。该属性是必须的,若不设置则会抛出异常。 |
||||
- `not`:是否对验证的结果取反。默认为 false,代表输入值匹配正则表达式时验证成功。如果设为 true,则输入值不匹配正则时返回匹配成功。 |
||||
|
||||
|
||||
## [[yii\validators\NumberValidator|number(数字)]] <a name="number"></a> |
||||
|
||||
```php |
||||
[ |
||||
// 检查 "salary" 是否为数字 |
||||
['salary', 'number'], |
||||
] |
||||
``` |
||||
|
||||
该验证器检查输入值是否为数字。他等效于 [double](#double) 验证器。 |
||||
|
||||
- `max`:上限值(含界点)。若不设置,则验证器不检查上限。 |
||||
- `min`:下限值(含界点)。若不设置,则验证器不检查下限。 |
||||
|
||||
|
||||
## [[yii\validators\RequiredValidator|required(必填)]] <a name="required"></a> |
||||
|
||||
```php |
||||
[ |
||||
// 检查 "username" 与 "password" 是否为空 |
||||
[['username', 'password'], 'required'], |
||||
] |
||||
``` |
||||
|
||||
该验证器检查输入值是否为空,还是已经提供了。 |
||||
|
||||
- `requiredValue`:所期望的输入值。若没设置,意味着输入不能为空。 |
||||
- `strict`:检查输入值时是否检查类型。默认为 false。当没有设置 `requiredValue` 属性时,若该属性为 true,验证器会检查输入值是否严格为 null;若该属性设为 false,该验证器会用一个更加宽松的规则检验输入值是否为空。 |
||||
|
||||
当设置了 `requiredValue` 属性时,若该属性为 true,输入值与 `requiredValue` 的比对会同时检查数据类型。 |
||||
|
||||
> 补充:如何判断待测值是否为空,被写在另外一个话题的[处理空输入](input-validation.md#handling-empty-inputs)章节。 |
||||
|
||||
|
||||
## [[yii\validators\SafeValidator|safe(安全)]] <a name="safe"></a> |
||||
|
||||
```php |
||||
[ |
||||
// 标记 "description" 为安全特性 |
||||
['description', 'safe'], |
||||
] |
||||
``` |
||||
|
||||
该验证器并不进行数据验证。而是把一个特性标记为[安全特性](structure-models.md#safe-attributes)。 |
||||
|
||||
|
||||
## [[yii\validators\StringValidator|string(字符串)]] <a name="string"></a> |
||||
|
||||
```php |
||||
[ |
||||
// 检查 "username" 是否为长度 4 到 24 之间的字符串 |
||||
['username', 'string', 'length' => [4, 24]], |
||||
] |
||||
``` |
||||
|
||||
该验证器检查输入值是否为特定长度的字符串。并检查特性的值是否为某个特定长度。 |
||||
|
||||
- `length`:指定待测输入字符串的长度限制。该属性可以被指定为以下格式之一: |
||||
* 证书:the exact length that the string should be of; |
||||
* 单元素数组:代表输入字符串的最小长度 (e.g. `[8]`)。这会重写 `min` 属性。 |
||||
* 包含两个元素的数组:代表输入字符串的最小和最大长度(e.g. `[8, 128]`)。 |
||||
这会同时重写 `min` 和 `max` 属性。 |
||||
- `min`:输入字符串的最小长度。若不设置,则代表不设下限。 |
||||
- `max`:输入字符串的最大长度。若不设置,则代表不设上限。 |
||||
- `encoding`:待测字符串的编码方式。若不设置,则使用应用自身的 [[yii\base\Application::charset|charset]] 属性值,该值默认为 `UTF-8`。 |
||||
|
||||
|
||||
## [[yii\validators\FilterValidator|trim(译为修剪/裁边)]] <a name="trim"></a> |
||||
|
||||
```php |
||||
[ |
||||
// trim 掉 "username" 和 "email" 两侧的多余空格 |
||||
[['username', 'email'], 'trim'], |
||||
] |
||||
``` |
||||
|
||||
该验证器并不进行数据验证。而是,trim 掉输入值两侧的多余空格。注意若该输入值为数组,那它会忽略掉该验证器。 |
||||
|
||||
|
||||
## [[yii\validators\UniqueValidator|unique(唯一性)]] <a name="unique"></a> |
||||
|
||||
```php |
||||
[ |
||||
// a1 需要在 "a1" 特性所代表的字段内唯一 |
||||
['a1', 'unique'], |
||||
|
||||
// a1 需要唯一,但检验的是 a1 的值在字段 a2 中的唯一性 |
||||
['a1', 'unique', 'targetAttribute' => 'a2'], |
||||
|
||||
// a1 和 a2 的组合需要唯一,且它们都能收到错误提示 |
||||
[['a1', 'a2'], 'unique', 'targetAttribute' => ['a1', 'a2']], |
||||
|
||||
// a1 和 a2 的组合需要唯一,只有 a1 能接收错误提示 |
||||
['a1', 'unique', 'targetAttribute' => ['a1', 'a2']], |
||||
|
||||
// 通过同时在 a2 和 a3 字段中检查 a2 和 a3 的值来确定 a1 的唯一性 |
||||
['a1', 'unique', 'targetAttribute' => ['a2', 'a1' => 'a3']], |
||||
] |
||||
``` |
||||
|
||||
该验证器检查输入值是否在某表字段中唯一。它只对[活动记录](db-active-record.md)类型的模型类特性起作用,能支持对一个或多过字段的验证。 |
||||
|
||||
- `targetClass`:用于查找输入值的目标 [AR](db-active-record.md) 类。若不设置,则会使用正在进行验证的当前模型类。 |
||||
- `targetAttribute`:用于检查输入值唯一性的 `targetClass` 的模型特性。 |
||||
- 若不设置,它会直接使用待测特性名(整个参数数组的首元素)。 |
||||
- 除了指定为字符串以外,你也可以用数组的形式,同时指定多个用于验证的表字段,数组的键和值都是代表字段的特性名,值表示 `targetClass` 的待测数据源字段,而键表示当前模型的待测特性名。 |
||||
- 若键和值相同,你可以只指定值。(如:`['a2']` 就代表 `['a2'=>'a2']`) |
||||
- `filter`:用于检查输入值唯一性必然会进行数据库查询,而该属性为用于进一步筛选该查询的过滤条件。可以为代表额外查询条件的字符串或数组(关于查询条件的格式,请参考 [[yii\db\Query::where()]]);或者样式为 `function ($query)` 的匿名函数,`$query` 参数为你希望在该函数内进行修改的 [[yii\db\Query|Query]] 对象。 |
||||
|
||||
> 译者注:[exist](#exist) 和 [unique](#unique) 验证器的机理和参数都相似,有点像一体两面的阴和阳。 |
||||
- 他们的区别是 exist 要求 `targetAttribute` 键所代表的的属性在其值所代表字段中找得到;而 unique 正相反,要求键所代表的的属性不能在其值所代表字段中被找到。 |
||||
- 从另一个角度来理解:他们都会在验证的过程中执行数据库查询,查询的条件即为where $v=$k (假设 `targetAttribute` 的其中一对键值对为 `$k => $v`)。unique 要求查询的结果数 `$count==0`,而 exist 则要求查询的结果数 `$count>0` |
||||
- 最后别忘了,unique 验证器不存在 `allowArray` 属性哦。 |
||||
|
||||
|
||||
## [[yii\validators\UrlValidator|url(网址)]] <a name="url"></a> |
||||
|
||||
```php |
||||
[ |
||||
// 检查 "website" 是否为有效的 URL。若没有 URI 方案,则给 "website" 特性加 "http://" 前缀 |
||||
['website', 'url', 'defaultScheme' => 'http'], |
||||
] |
||||
``` |
||||
|
||||
该验证器检查输入值是否为有效 URL。 |
||||
|
||||
- `validSchemes`:用于指定那些 URI 方案会被视为有效的数组。默认为 `['http', 'https']`,代表 `http` 和 `https` URLs 会被认为有效。 |
||||
- `defaultScheme`:若输入值没有对应的方案前缀,会使用的默认 URI 方案前缀。默认为 null,代表不修改输入值本身。 |
||||
- `enableIDN`:验证过程是否应该考虑 IDN(internationalized domain names,国际化域名,也称多语种域名,比如中文域名)。默认为 false。要注意但是为使用 IDN 验证功能,请先确保安装并开启 `intl` PHP 扩展,不然会导致抛出异常。 |
@ -0,0 +1,11 @@
|
||||
Acceptance Tests |
||||
================ |
||||
|
||||
> Note: This section is under development. |
||||
|
||||
- http://codeception.com/docs/04-AcceptanceTests |
||||
- https://github.com/yiisoft/yii2/blob/master/apps/advanced/README.md#testing |
||||
- https://github.com/yiisoft/yii2/blob/master/apps/basic/tests/README.md |
||||
|
||||
How to run php-server |
||||
--------------------- |
@ -0,0 +1,8 @@
|
||||
Functional Tests |
||||
---------------- |
||||
|
||||
> Note: This section is under development. |
||||
|
||||
- http://codeception.com/docs/05-FunctionalTests |
||||
- https://github.com/yiisoft/yii2/blob/master/apps/advanced/README.md#testing |
||||
- https://github.com/yiisoft/yii2/blob/master/apps/basic/tests/README.md |
@ -1,4 +1,37 @@
|
||||
Testing |
||||
======= |
||||
|
||||
TBD |
||||
> Note: This section is under development. |
||||
|
||||
TODO: |
||||
|
||||
- https://github.com/yiisoft/yii2/blob/master/extensions/codeception/README.md |
||||
|
||||
Testing is an important part of software development. Whether we are aware of it or not, we conduct testing continuously. |
||||
For example, when we write a class in PHP, we may debug it step by step or simply use echo or die statements to verify |
||||
that implementation is correct. In case of web application we're entering some test data in forms to ensure the page |
||||
interacts with us as expected. The testing process could be automated so that each time when we need to test something, |
||||
we just need to call up the code that perform testing for us. This is known as automated testing, which is the main topic |
||||
of testing chapters. |
||||
|
||||
The testing support provided by Yii includes: |
||||
|
||||
- [Unit testing](test-unit.md) - verifies that a single unit of code is working as expected. |
||||
- [Functional testing](test-functional.md) - verifies scenarios from a user's perspective via browser emulation. |
||||
- [Acceptance testing](test-acceptance.md) - verifies scenarios from a user's perspective in a browser. |
||||
|
||||
Yii provides ready to use test sets for all three testing types in both basic and advanced application templates. |
||||
|
||||
Test environment setup |
||||
---------------------- |
||||
|
||||
In order to run tests with Yii you need to install [Codeception](http://codeception.com/). A good way to install it is |
||||
the following: |
||||
|
||||
``` |
||||
composer global require "codeception/codeception=2.0.*" |
||||
composer global require "codeception/specify=*" |
||||
composer global require "codeception/verify=*" |
||||
``` |
||||
|
||||
That's it. Now we're able to use `codecept` from command line. |
||||
|
@ -0,0 +1,19 @@
|
||||
Unit Tests |
||||
========== |
||||
|
||||
> Note: This section is under development. |
||||
|
||||
TODO: |
||||
|
||||
- https://github.com/yiisoft/yii2/blob/master/apps/advanced/README.md#testing |
||||
- https://github.com/yiisoft/yii2/blob/master/apps/basic/tests/README.md |
||||
|
||||
A unit test verifies that a single unit of code is working as expected. In object-oriented programming, the most basic |
||||
code unit is a class. A unit test thus mainly needs to verify that each of the class interface methods works properly. |
||||
That is, given different input parameters, the test verifies the method returns expected results. |
||||
Unit tests are usually developed by people who write the classes being tested. |
||||
|
||||
Unit testing in Yii is built on top of PHPUnit and, optionally, Codeception so it's recommended to go through their docs: |
||||
|
||||
- [PHPUnit docs starting from chapter 2](http://phpunit.de/manual/current/en/writing-tests-for-phpunit.html). |
||||
- [Codeception Unit Tests](http://codeception.com/docs/06-UnitTests). |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue