-
Notifications
You must be signed in to change notification settings - Fork 38
/
Copy pathblog2.sql
254 lines (214 loc) · 196 KB
/
blog2.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
-- phpMyAdmin SQL Dump
-- version 4.3.13.3
-- http://www.phpmyadmin.net
--
-- Host: localhost
-- Generation Time: 2015-10-22 11:19:39
-- 服务器版本: 5.6.26
-- PHP Version: 5.5.27
SET SQL_MODE = "NO_AUTO_VALUE_ON_ZERO";
SET time_zone = "+00:00";
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
--
-- Database: `blog2`
--
-- --------------------------------------------------------
--
-- 表的结构 `tbl_comment`
--
CREATE TABLE IF NOT EXISTS `tbl_comment` (
`id` int(11) NOT NULL,
`content` text COLLATE utf8_unicode_ci NOT NULL,
`status` int(11) NOT NULL,
`create_time` int(11) DEFAULT NULL,
`author` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`email` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`url` varchar(128) COLLATE utf8_unicode_ci DEFAULT NULL,
`post_id` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=96 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
--
-- 转存表中的数据 `tbl_comment`
--
INSERT INTO `tbl_comment` (`id`, `content`, `status`, `create_time`, `author`, `email`, `url`, `post_id`) VALUES
(88, '假设你想通过 RESTful 风格的 API 来展示用户数据。用户数据被存储在用户DB表, 你已经创建了 yii\\db\\ActiveRecord 类 app\\models\\User 来访问该用户数据.', 2, 1443004317, '宋小宝', '[email protected]', '', 41),
(89, 'yii\\db\\Query::one() 方法只返回查询结果当中的第一条数据, 条件语句中不会加上 LIMIT 1 条件。如果你清楚的知道查询将会只返回一行或几行数据 (例如, 如果你是通过某些主键来查询的),这很好也提倡这样做。但是,如果查询结果 有机会返回大量的数据时,那么你应该显示调用 limit(1) 方法,以改善性能。 例如, (new \\yii\\db\\Query())->from(''user'')->limit(1)->one()。', 2, 1443004455, '马奇芳', '[email protected]', '', 39),
(90, '传说中的沙发。', 2, 1443004561, '萨芬', '[email protected]', '', 34),
(91, '当你在调用 yii\\db\\Query::all() 方法时,它将返回一个以连续的整型数值为索引的数组。 而有时候你可能希望使用一个特定的字段或者表达式的值来作为索引结果集数组。那么你可以在调用 yii\\db\\Query::all() 之前使用 yii\\db\\Query::indexBy() 方法来达到这个目的。', 2, 1443047988, '陈天桥', '[email protected]', '', 39),
(92, '如需使用表达式的值做为索引,那么只需要传递一个匿名函数给 yii\\db\\Query::indexBy() 方法即可', 2, 1443049673, 'kiki', '[email protected]', '', 39),
(93, 'yii\\db\\Query::one() 方法只返回查询结果当中的第一条数据, 条件语句中不会加上 LIMIT 1 条', 2, 1443927141, 'csc', '[email protected]', '', 39),
(94, '你应该在 响应格式 部分中过滤掉这些字段。', 1, 1444267750, '万剑', '[email protected]', 'www.wj.com', 41),
(95, '适合用常规格式显示一个模型(例如在一个表格的一行中显示模型的每个属性)。', 1, 1444377054, 'testing', '[email protected]', 'www.baidu.com', 36);
-- --------------------------------------------------------
--
-- 表的结构 `tbl_lookup`
--
CREATE TABLE IF NOT EXISTS `tbl_lookup` (
`id` int(11) NOT NULL,
`name` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`code` int(11) NOT NULL,
`type` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`position` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
--
-- 转存表中的数据 `tbl_lookup`
--
INSERT INTO `tbl_lookup` (`id`, `name`, `code`, `type`, `position`) VALUES
(1, '草稿', 1, 'PostStatus', 1),
(2, '已发布', 2, 'PostStatus', 2),
(3, '已归档', 3, 'PostStatus', 3),
(4, '待审核', 1, 'CommentStatus', 1),
(5, '已审核', 2, 'CommentStatus', 2);
-- --------------------------------------------------------
--
-- 表的结构 `tbl_post`
--
CREATE TABLE IF NOT EXISTS `tbl_post` (
`id` int(11) NOT NULL,
`title` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`content` text COLLATE utf8_unicode_ci NOT NULL,
`tags` text COLLATE utf8_unicode_ci,
`status` int(11) NOT NULL,
`create_time` int(11) DEFAULT NULL,
`update_time` int(11) DEFAULT NULL,
`author_id` int(11) NOT NULL
) ENGINE=InnoDB AUTO_INCREMENT=43 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
--
-- 转存表中的数据 `tbl_post`
--
INSERT INTO `tbl_post` (`id`, `title`, `content`, `tags`, `status`, `create_time`, `update_time`, `author_id`) VALUES
(32, 'Yii2小部件详解', '<div id="content">\r\n <h1>小部件</h1>\r\n<p>小部件是在 <a href="/doc/guide/2.0/structure-views">视图</a> 中使用的可重用单元,使用面向对象方式创建复杂和可配置用户界面单元。\r\n例如,日期选择器小部件可生成一个精致的允许用户选择日期的日期选择器,\r\n你只需要在视图中插入如下代码:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-preprocessor"><?php</span>\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">jui</span>\\<span class="hljs-title">DatePicker</span>;\r\n<span class="hljs-preprocessor">?></span>\r\n<span class="hljs-preprocessor"><?</span>= DatePicker::widget([<span class="hljs-string">''name''</span> => <span class="hljs-string">''date''</span>]) <span class="hljs-preprocessor">?></span>\r\n</code></pre>\r\n<p>Yii提供许多优秀的小部件,比如yii\\widgets\\ActiveForm, [yii\\widgets\\Menu|menu]],\r\n<a href="/doc/guide/2.0/widget-jui">jQuery UI widgets</a>, <a href="/doc/guide/2.0/widget-bootstrap">Twitter Bootstrap widgets</a>。\r\n接下来介绍小部件的基本知识,如果你想了解某个小部件请参考对应的类API文档。</p>\r\n<h2>使用小部件 <span></span></h2>\r\n<p>小部件基本上在<a href="/doc/guide/2.0/structure-views">views</a>中使用,在视图中可调用 yii\\base\\Widget::widget() 方法使用小部件。\r\n该方法使用 <a href="/doc/guide/2.0/concept-configurations">配置</a> 数组初始化小部件并返回小部件渲染后的结果。\r\n例如如下代码插入一个日期选择器小部件,它配置为使用俄罗斯语,输入框内容为<code>$model</code>的<code>from_date</code>属性值。</p>\r\n<pre><code class="language-php hljs"><span class="hljs-preprocessor"><?php</span>\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">jui</span>\\<span class="hljs-title">DatePicker</span>;\r\n<span class="hljs-preprocessor">?></span>\r\n<span class="hljs-preprocessor"><?</span>= DatePicker::widget([\r\n <span class="hljs-string">''model''</span> => <span class="hljs-variable">$model</span>,\r\n <span class="hljs-string">''attribute''</span> => <span class="hljs-string">''from_date''</span>,\r\n <span class="hljs-string">''language''</span> => <span class="hljs-string">''ru''</span>,\r\n <span class="hljs-string">''clientOptions''</span> => [\r\n <span class="hljs-string">''dateFormat''</span> => <span class="hljs-string">''yy-mm-dd''</span>,\r\n ],\r\n]) <span class="hljs-preprocessor">?></span>\r\n</code></pre>\r\n<p>一些小部件可在yii\\base\\Widget::begin() 和 yii\\base\\Widget::end() 调用中使用数据内容。Some widgets can take a block of content which should be enclosed between the invocation of\r\n例如如下代码使用yii\\widgets\\ActiveForm小部件生成一个登录表单,\r\n小部件会在<code>begin()</code> 和0 <code>end()</code>执行处分别生成<code><form></code>的开始标签和结束标签,中间的任何代码也会被渲染。</p>\r\n<pre><code class="language-php hljs"><span class="hljs-preprocessor"><?php</span>\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">widgets</span>\\<span class="hljs-title">ActiveForm</span>;\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">helpers</span>\\<span class="hljs-title">Html</span>;\r\n<span class="hljs-preprocessor">?></span>\r\n\r\n<span class="hljs-preprocessor"><?php</span> <span class="hljs-variable">$form</span> = ActiveForm::begin([<span class="hljs-string">''id''</span> => <span class="hljs-string">''login-form''</span>]); <span class="hljs-preprocessor">?></span>\r\n\r\n <span class="hljs-preprocessor"><?</span>= <span class="hljs-variable">$form</span>->field(<span class="hljs-variable">$model</span>, <span class="hljs-string">''username''</span>) <span class="hljs-preprocessor">?></span>\r\n\r\n <span class="hljs-preprocessor"><?</span>= <span class="hljs-variable">$form</span>->field(<span class="hljs-variable">$model</span>, <span class="hljs-string">''password''</span>)->passwordInput() <span class="hljs-preprocessor">?></span>\r\n\r\n <div <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">form</span>-<span class="hljs-title">group</span>">\r\n <?= <span class="hljs-title">Html</span>::<span class="hljs-title">submitButton</span>(''<span class="hljs-title">Login</span>'') ?>\r\n </<span class="hljs-title">div</span>>\r\n\r\n<?<span class="hljs-title">php</span> <span class="hljs-title">ActiveForm</span>::<span class="hljs-title">end</span>(); ?>\r\n</span></code></pre>\r\n<p>注意和调用 yii\\base\\Widget::widget() 返回渲染结果不同,\r\n调用 yii\\base\\Widget::begin() 方法返回一个可组建小部件内容的小部件实例。</p>\r\n<h2>创建小部件 <span></span></h2>\r\n<h2>Creating Widgets <span></span></h2>\r\n<p>继承 yii\\base\\Widget 类并覆盖 yii\\base\\Widget::init() 和/或\r\nyii\\base\\Widget::run() 方法可创建小部件。通常<code>init()</code> 方法处理小部件属性,\r\n<code>run()</code> 方法包含小部件生成渲染结果的代码。\r\n渲染结果可在<code>run()</code>方法中直接"echoed"输出或以字符串返回。</p>\r\n<p>如下代码中<code>HelloWidget</code>编码并显示赋给<code>message</code> 属性的值,\r\n如果属性没有被赋值,默认会显示"Hello World"。</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">namespace</span> <span class="hljs-title">app</span>\\<span class="hljs-title">components</span>;\r\n\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">base</span>\\<span class="hljs-title">Widget</span>;\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">helpers</span>\\<span class="hljs-title">Html</span>;\r\n\r\n<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HelloWidget</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Widget</span>\r\n</span>{\r\n <span class="hljs-keyword">public</span> <span class="hljs-variable">$message</span>;\r\n\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">init</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">parent</span>::init();\r\n <span class="hljs-keyword">if</span> (<span class="hljs-variable">$this</span>->message === <span class="hljs-keyword">null</span>) {\r\n <span class="hljs-variable">$this</span>->message = <span class="hljs-string">''Hello World''</span>;\r\n }\r\n }\r\n\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> Html::encode(<span class="hljs-variable">$this</span>->message);\r\n }\r\n}\r\n</code></pre>\r\n<p>使用这个小部件只需在视图中简单使用如下代码:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-preprocessor"><?php</span>\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">app</span>\\<span class="hljs-title">components</span>\\<span class="hljs-title">HelloWidget</span>;\r\n<span class="hljs-preprocessor">?></span>\r\n<span class="hljs-preprocessor"><?</span>= HelloWidget::widget([<span class="hljs-string">''message''</span> => <span class="hljs-string">''Good morning''</span>]) <span class="hljs-preprocessor">?></span>\r\n</code></pre>\r\n<p>以下是另一种可在<code>begin()</code> 和 <code>end()</code>调用中使用的<code>HelloWidget</code>,HTML编码内容然后显示。</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">namespace</span> <span class="hljs-title">app</span>\\<span class="hljs-title">components</span>;\r\n\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">base</span>\\<span class="hljs-title">Widget</span>;\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">helpers</span>\\<span class="hljs-title">Html</span>;\r\n\r\n<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">HelloWidget</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Widget</span>\r\n</span>{\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">init</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">parent</span>::init();\r\n ob_start();\r\n }\r\n\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-variable">$content</span> = ob_get_clean();\r\n <span class="hljs-keyword">return</span> Html::encode(<span class="hljs-variable">$content</span>);\r\n }\r\n}\r\n</code></pre>\r\n<p>如上所示,PHP输出缓冲在<code>init()</code>启动,所有在<code>init()</code> 和 <code>run()</code>方法之间的输出内容都会被获取,并在<code>run()</code>处理和返回。</p>\r\n<blockquote><p>补充: 当你调用 yii\\base\\Widget::begin() 时会创建一个新的小部件实例并在构造结束时调用<code>init()</code>方法,\r\n 在<code>end()</code>时会调用<code>run()</code>方法并输出返回结果。</p>\r\n</blockquote>\r\n<p>如下代码显示如何使用这种 <code>HelloWidget</code>:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-preprocessor"><?php</span>\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">app</span>\\<span class="hljs-title">components</span>\\<span class="hljs-title">HelloWidget</span>;\r\n<span class="hljs-preprocessor">?></span>\r\n<span class="hljs-preprocessor"><?php</span> HelloWidget::begin(); <span class="hljs-preprocessor">?></span>\r\n\r\n content that may contain <tag><span class="hljs-string">''s\r\n\r\n<?php HelloWidget::end(); ?>\r\n</span></code></pre>\r\n<p>有时小部件需要渲染很多内容,一种更好的办法是将内容放入一个<a href="/doc/guide/2.0/structure-views">视图</a>文件,\r\n然后调用yii\\base\\Widget::render()方法渲染该视图文件,例如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">run</span><span class="hljs-params">()</span>\r\n</span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$this</span>->render(<span class="hljs-string">''hello''</span>);\r\n}\r\n</code></pre>\r\n<p>小部件的视图文件默认存储在<code>WidgetPath/views</code>目录,<code>WidgetPath</code>代表小部件类文件所在的目录。\r\n假如上述示例小部件类文件在<code>@app/components</code>下,会渲染<code>@app/components/views/hello.php</code>视图文件。 You may override\r\n可以覆盖yii\\base\\Widget::getViewPath()方法自定义视图文件所在路径。</p>\r\n<h2>最佳实践 <span></span></h2>\r\n<p>小部件是面向对象方式来重用视图代码。</p>\r\n<p>创建小部件时仍需要遵循MVC模式,通常逻辑代码在小部件类,展示内容在<a href="/doc/guide/2.0/structure-views">视图</a>中。</p>\r\n<p>小部件设计时应是独立的,也就是说使用一个小部件时候,可以直接丢弃它而不需要额外的处理。\r\n但是当小部件需要外部资源如CSS, JavaScript, 图片等会比较棘手,\r\n幸运的时候Yii提供 <a href="/doc/guide/2.0/structure-asset-bundles">资源包</a> 来解决这个问题。</p>\r\n<p>当一个小部件只包含视图代码,它和<a href="/doc/guide/2.0/structure-views">视图</a>很相似,\r\n实际上,在这种情况下,唯一的区别是小部件是可以重用类,视图只是应用中使用的普通PHP脚本。</p>\r\n </div>', 'Yii2,小部件,widget', 2, 1442998314, 1442998314, 1),
(33, 'Yii2安装 ', '<div id="content">\r\n\r\n<p>你可以通过两种方式安装 Yii:使用 <a href="https://getcomposer.org/">Composer</a> 或下载一个归档文件。推荐使用前者,这样只需执行一条简单的命令就可以安装新的<a href="/doc/guide/2.0/structure-extensions">扩展</a>或更新 Yii 了。</p>\r\n<blockquote><p>注意:和 Yii 1 不同,以标准方式安装 Yii 2 时会同时下载并安装框架本身和一个应用程序的基本骨架。</p>\r\n</blockquote>\r\n<h2>通过 Composer 安装 <span></span></h2>\r\n<p>如果还没有安装 Composer,你可以按 <a href="https://getcomposer.org/download/">getcomposer.org</a> 中的方法安装。在 Linux 和 Mac OS X 中可以运行如下命令:</p>\r\n<pre><code class="hljs groovy">curl -sS <span class="hljs-string">https:</span><span class="hljs-comment">//getcomposer.org/installer | php</span>\r\nmv composer.phar <span class="hljs-regexp">/usr/</span>local<span class="hljs-regexp">/bin/</span>composer\r\n</code></pre>\r\n<p>在 Windows 中,你需要下载并运行 <a href="https://getcomposer.org/Composer-Setup.exe">Composer-Setup.exe</a>。</p>\r\n<p>如果遇到任何问题或者想更深入地学习 Composer,请参考 <a href="https://getcomposer.org/doc/">Composer 文档(英文)</a>,<a href="https://github.com/5-say/composer-doc-cn">Composer 中文</a>。</p>\r\n<p>如果你已经安装有 Composer 请确保使用的是最新版本,你可以用 <code>composer self-update</code> 命令更新 Composer 为最新版本。</p>\r\n<p>Composer 安装后,切换到一个可通过 Web 访问的目录,执行如下命令即可安装 Yii :</p>\r\n<pre><code class="hljs armasm"><span class="hljs-label">composer</span> <span class="hljs-preprocessor">global</span> <span class="hljs-preprocessor">require</span> <span class="hljs-string">"fxp/composer-asset-plugin:~1.0.0"</span>\r\n<span class="hljs-label">composer</span> create-project --prefer-dist yiisoft/yii2-app-<span class="hljs-keyword">basic </span><span class="hljs-keyword">basic\r\n</span></code></pre>\r\n<p>第一条命令安装 <a href="https://github.com/francoispluchino/composer-asset-plugin/">Composer asset plugin</a>,它是通过 Composer 管理 bower 和 npm 包所必须的,此命令全局生效,一劳永逸。\r\n第二条命令会将 Yii 安装在名为 <code>basic</code> 的目录中,你也可以随便选择其他名称。</p>\r\n<blockquote><p>注意:在安装过程中 Composer 可能会询问你 GitHub 账户的登录信息,因为可能在使用中超过了 GitHub API \r\n(对匿名用户的)使用限制。因为 Composer 需要为所有扩展包从 GitHub \r\n中获取大量信息,所以超限非常正常。(译注:也意味着作为程序猿没有 GitHub 账号,就真不能愉快地玩耍了)登陆 GitHub \r\n之后可以得到更高的 API 限额,这样 Composer 才能正常运行。更多细节请参考 <a href="https://getcomposer.org/doc/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens">Composer \r\n文档</a>(该段 Composer \r\n中文文档<a href="https://github.com/5-say/composer-doc-cn/blob/master/cn-introduction/articles/troubleshooting.md#api-rate-limit-and-oauth-tokens">期待您的参与</a>)。</p>\r\n</blockquote>\r\n<blockquote><p>技巧:如果你想安装 Yii 的最新开发版本,可以使用以下命令代替,它添加了一个 <a href="https://getcomposer.org/doc/04-schema.md#minimum-stability">stability 选项</a>(<a href="https://github.com/5-say/composer-doc-cn/blob/master/cn-introduction/04-schema.md#minimum-stability">中文版</a>):</p>\r\n<pre><code class="hljs sql">composer <span class="hljs-operator"><span class="hljs-keyword">create</span>-<span class="hljs-keyword">project</span> <span class="hljs-comment">--prefer-dist --stability=dev yiisoft/yii2-app-basic basic</span>\r\n</span></code></pre>\r\n<p>注意,Yii 的开发版(dev 版)不应该用于生产环境中,它可能会破坏运行中的代码。</p>\r\n</blockquote>\r\n<h2>通过归档文件安装 <span></span></h2>\r\n<p>通过归档文件安装 Yii 包括三个步骤:</p>\r\n<ol><li>从 <a href="http://www.yiiframework.com/download/">yiiframework.com</a> 下载归档文件。</li>\r\n<li>将下载的文件解压缩到 Web 目录中。</li>\r\n<li><p>修改 <code>config/web.php</code> 文件,给 <code>cookieValidationKey</code> 配置项添加一个密钥(若你通过 Composer 安装,则此步骤会自动完成):</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// !!! 在下面插入一段密钥(若为空) - 以供 cookie validation 的需要</span>\r\n<span class="hljs-string">''cookieValidationKey''</span> => <span class="hljs-string">''在此处输入你的密钥''</span>,\r\n</code></pre>\r\n</li>\r\n</ol><h2>其他安装方式 <span></span></h2>\r\n<p>上文介绍了两种安装 Yii 的方法,安装的同时也会创建一个立即可用的 Web 应用程序。对于小的项目或用于学习上手,这都是一个不错的起点。</p>\r\n<p>但是其他的安装方式也存在:</p>\r\n<ul><li>如果你只想安装核心框架,然后从零开始构建整个属于你自己的应用程序模版,可以参考<a href="/doc/guide/2.0/tutorial-start-from-scratch">从头构建自定义模版</a>一节的介绍。</li>\r\n<li>如果你要开发一个更复杂的应用,可以更好地适用于团队开发环境的,可以考虑安装<a href="/doc/guide/2.0/tutorial-advanced-app">高级应用模版</a>。</li>\r\n</ul><h2>验证安装的结果 <span></span></h2>\r\n<p>安装完成后,就可以使用浏览器通过如下 URL 访问刚安装完的 Yii 应用了:</p>\r\n<pre><code class="hljs elixir"><span class="hljs-symbol">http:</span>/<span class="hljs-regexp">/localhost/basic</span><span class="hljs-regexp">/web/index</span>.php\r\n</code></pre>\r\n<p>这个 URL 假设你将 Yii 安装到了一个位于 Web 文档根目录下的 <code>basic</code> 目录中,且该 Web 服务器正运行在你自己的电脑上(<code>localhost</code>)。你可能需要将其调整为适应自己的安装环境。</p>\r\n<p><img src="/docs/guide/2.0/images/start-app-installed.png" alt="Yii 安装成功"></p>\r\n<p>你应该可以在浏览器中看到如上所示的 “Congratulations!” 页面。如果没有,请通过以下任意一种方式,检查当前 PHP 环境是否满足 Yii 最基本需求:</p>\r\n<ul><li>通过浏览器访问 URL <code>http://localhost/basic/requirements.php</code></li>\r\n<li><p>执行如下命令:</p>\r\n<pre><code class="hljs stylus">cd basic\r\nphp requirements<span class="hljs-class">.php</span>\r\n</code></pre>\r\n</li>\r\n</ul><p>你需要配置好 PHP 安装环境,使其符合 Yii 的最小需求。主要是需要 PHP 5.4 以上版本。如果应用需要用到数据库,那还要安装 <a href="http://www.php.net/manual/zh/pdo.installation.php">PDO PHP 扩展</a> 和相应的数据库驱动(例如访问 MySQL 数据库所需的 <code>pdo_mysql</code>)。</p>\r\n<h2>配置 Web 服务器 <span></span></h2>\r\n<p>>补充:如果你现在只是要试用 Yii 而不是将其部署到生产环境中,本小节可以跳过。</p>\r\n<p>通过上述方法安装的应用程序在 Windows,Max OS X,Linux 中的 <a href="http://httpd.apache.org/">Apache HTTP 服务器</a>或 <a href="http://nginx.org/">Nginx HTTP 服务器</a>且PHP版本为5.4或更高都可以直接运行。Yii 2.0 也兼容 Facebook 公司的 <a href="http://hhvm.com/">HHVM</a>,由于 HHVM 和标准 PHP 在边界案例上有些地方略有不同,在使用 HHVM 时需稍作处理。</p>\r\n<p>在生产环境的服务器上,你可能会想配置服务器让应用程序可以通过 URL <code>http://www.example.com/index.php</code> 访问而不是 <code>http://www.example.com/basic/web/index.php</code>。这种配置需要将 Web 服务器的文档根目录指向 <code>basic/web</code> 目录。可能你还会想隐藏掉 URL 中的 <code>index.php</code>,具体细节在 <a href="/doc/guide/2.0/runtime-url-handling">URL 解析和生成</a>一章中有介绍,你将学到如何配置 Apache 或 Nginx 服务器实现这些目标。</p>\r\n<p>>补充:将 <code>basic/web</code> 设置为文档根目录,可以防止终端用户访问 <code>basic/web</code> 相邻目录中的私有应用代码和敏感数据文件。禁止对其他目录的访问是一个不错的安全改进。</p>\r\n<p>>补充:如果你的应用程序将来要运行在共享虚拟主机环境中,没有修改其 Web 服务器配置的权限,你依然可以通过调整应用的结构来提升安全性。详情请参考<a href="/doc/guide/2.0/tutorial-shared-hosting">共享主机环境</a> 一章。</p>\r\n<h3>推荐使用的 Apache 配置 <span></span></h3>\r\n<p>在 Apache 的 <code>httpd.conf</code> 文件或在一个虚拟主机配置文件中使用如下配置。注意,你应该将 <code>path/to/basic/web</code> 替换为实际的 <code>basic/web</code> 目录。</p>\r\n<pre><code class="hljs apache"><span class="hljs-comment"># 设置文档根目录为 “basic/web”</span>\r\n<span class="hljs-keyword"><span class="hljs-common">DocumentRoot</span></span> <span class="hljs-string">"path/to/basic/web"</span>\r\n\r\n<span class="hljs-tag"><Directory "path/to/basic/web"></span>\r\n <span class="hljs-comment"># 开启 mod_rewrite 用于美化 URL 功能的支持(译注:对应 pretty URL 选项)</span>\r\n <span class="hljs-keyword"><span class="hljs-common">RewriteEngine</span></span> <span class="hljs-literal">on</span>\r\n <span class="hljs-comment"># 如果请求的是真实存在的文件或目录,直接访问</span>\r\n <span class="hljs-keyword"><span class="hljs-common">RewriteCond</span></span> <span class="hljs-cbracket">%{REQUEST_FILENAME}</span> !-f\r\n <span class="hljs-keyword"><span class="hljs-common">RewriteCond</span></span> <span class="hljs-cbracket">%{REQUEST_FILENAME}</span> !-d\r\n <span class="hljs-comment"># 如果请求的不是真实文件或目录,分发请求至 index.php</span>\r\n <span class="hljs-keyword"><span class="hljs-common">RewriteRule</span></span> . index.php\r\n\r\n <span class="hljs-comment"># ...其它设置...</span>\r\n<span class="hljs-tag"></Directory></span>\r\n</code></pre>\r\n<h3>推荐使用的 Nginx 配置 <span></span></h3>\r\n<p>为了使用 <a href="http://wiki.nginx.org/">Nginx</a>,你应该已经将 PHP 安装为 <a href="http://php.net/install.fpm">FPM SAPI</a> 了。使用如下 Nginx 配置,将 <code>path/to/basic/web</code> 替换为实际的 <code>basic/web</code> 目录,<code>mysite.local</code> 替换为实际的主机名以提供服务。</p>\r\n<pre><code class="hljs nginx"><span class="hljs-title">server</span> {\r\n <span class="hljs-title">charset</span> utf-<span class="hljs-number">8</span>;\r\n <span class="hljs-title">client_max_body_size</span> <span class="hljs-number">128M</span>;\r\n\r\n <span class="hljs-title">listen</span> <span class="hljs-number">80</span>; <span class="hljs-comment">## 监听 ipv4 上的 80 端口</span>\r\n <span class="hljs-comment">#listen [::]:80 default_server ipv6only=on; ## 监听 ipv6 上的 80 端口</span>\r\n\r\n <span class="hljs-title">server_name</span> mysite.local;\r\n <span class="hljs-title">root</span> /path/to/basic/web;\r\n <span class="hljs-title">index</span> index.php;\r\n\r\n <span class="hljs-title">access_log</span> /path/to/basic/log/access.log main;\r\n <span class="hljs-title">error_log</span> /path/to/basic/log/error.log;\r\n\r\n <span class="hljs-title">location</span> / {\r\n <span class="hljs-comment"># 如果找不到真实存在的文件,把请求分发至 index.php</span>\r\n <span class="hljs-title">try_files</span> <span class="hljs-variable">$uri</span> <span class="hljs-variable">$uri</span>/ /index.php?<span class="hljs-variable">$args</span>;\r\n }\r\n\r\n <span class="hljs-comment"># 若取消下面这段的注释,可避免 Yii 接管不存在文件的处理过程(404)</span>\r\n <span class="hljs-comment">#location ~ \\.(js|css|png|jpg|gif|swf|ico|pdf|mov|fla|zip|rar)$ {</span>\r\n <span class="hljs-comment"># try_files $uri =404;</span>\r\n <span class="hljs-comment">#}</span>\r\n <span class="hljs-comment">#error_page 404 /404.html;</span>\r\n\r\n <span class="hljs-title">location</span> <span class="hljs-regexp">~ \\.php$</span> {\r\n <span class="hljs-title">include</span> fastcgi.conf;\r\n <span class="hljs-title">fastcgi_pass</span> <span class="hljs-number">127.0.0.1:9000</span>;\r\n <span class="hljs-comment">#fastcgi_pass unix:/var/run/php5-fpm.sock;</span>\r\n <span class="hljs-title">try_files</span> <span class="hljs-variable">$uri</span> =<span class="hljs-number">404</span>;\r\n }\r\n\r\n <span class="hljs-title">location</span> <span class="hljs-regexp">~ /\\.(ht|svn|git)</span> {\r\n <span class="hljs-title">deny</span> all;\r\n }\r\n}\r\n</code></pre>\r\n<p>使用该配置时,你还应该在 <code>php.ini</code> 文件中设置 <code>cgi.fix_pathinfo=0</code> ,能避免掉很多不必要的 <code>stat()</code> 系统调用。</p>\r\n<p>还要注意当运行一个 HTTPS 服务器时,需要添加 <code>fastcgi_param HTTPS on;</code> 一行,这样 Yii 才能正确地判断连接是否安全。</p>\r\n </div>', '安装 ,Yii2,Composer', 2, 1442998501, 1442999620, 1),
(34, 'ActiveRecord 详解(上)', '<div id="content">\r\n \r\n<p><a href="http://zh.wikipedia.org/wiki/Active_Record">Active Record</a> (活动记录,以下简称AR)提供了一个面向对象的接口,\r\n用以访问数据库中的数据。一个 AR 类关联一张数据表,\r\n每个 AR 对象对应表中的一行,对象的属性(即 AR 的特性Attribute)映射到数据行的对应列。\r\n一条活动记录(AR对象)对应数据表的一行,AR对象的属性则映射该行的相应列。\r\n您可以直接以面向对象的方式来操纵数据表中的数据,妈妈再不用担心我需要写原生 SQL 语句啦。</p>\r\n<p>例如,假定 <code>Customer</code> AR 类关联着 <code>customer</code> 表,且该类的 <code>name</code> 属性代表 <code>customer</code> 表的 <code>name</code> 列。\r\n你可以写以下代码来哉 <code>customer</code> 表里插入一行新的记录:</p>\r\n<p>用 AR 而不是原生的 SQL 语句去执行数据库查询,可以调用直观方法来实现相同目标。如,调用 yii\\db\\ActiveRecord::save() 方法将执行插入或更新轮询,将在该 AR 类关联的数据表新建或更新一行数据:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$customer</span> = <span class="hljs-keyword">new</span> Customer();\r\n<span class="hljs-variable">$customer</span>->name = <span class="hljs-string">''Qiang''</span>;\r\n<span class="hljs-variable">$customer</span>->save(); <span class="hljs-comment">// 一行新数据插入 customer 表</span>\r\n</code></pre>\r\n<p>上面的代码和使用下面的原生 SQL 语句是等效的,但显然前者更直观,\r\n更不易出错,并且面对不同的数据库系统(DBMS, Database Management System)时更不容易产生兼容性问题。</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$db</span>->createCommand(<span class="hljs-string">''INSERT INTO customer (name) VALUES (:name)''</span>, [\r\n <span class="hljs-string">'':name''</span> => <span class="hljs-string">''Qiang''</span>,\r\n])->execute();\r\n</code></pre>\r\n<p>下面是所有目前被 Yii 的 AR 功能所支持的数据库列表:</p>\r\n<ul><li>MySQL 4.1 及以上:通过 yii\\db\\ActiveRecord</li>\r\n<li>PostgreSQL 7.3 及以上:通过 yii\\db\\ActiveRecord</li>\r\n<li>SQLite 2 和 3:通过 yii\\db\\ActiveRecord</li>\r\n<li>Microsoft SQL Server 2010 及以上:通过 yii\\db\\ActiveRecord</li>\r\n<li>Oracle: 通过 yii\\db\\ActiveRecord</li>\r\n<li>CUBRID 9.1 及以上:通过 yii\\db\\ActiveRecord</li>\r\n<li>Sphinx:通过 yii\\sphinx\\ActiveRecord,需求 <code>yii2-sphinx</code> 扩展</li>\r\n<li>ElasticSearch:通过 yii\\elasticsearch\\ActiveRecord,需求 <code>yii2-elasticsearch</code> 扩展</li>\r\n<li>Redis 2.6.12 及以上:通过 yii\\redis\\ActiveRecord,需求 <code>yii2-redis</code> 扩展</li>\r\n<li>MongoDB 1.3.0 及以上:通过 yii\\mongodb\\ActiveRecord,需求 <code>yii2-mongodb</code> 扩展</li>\r\n</ul><p>如你所见,Yii 不仅提供了对关系型数据库的 AR 支持,还提供了 NoSQL 数据库的支持。\r\n在这个教程中,我们会主要描述对关系型数据库的 AR 用法。\r\n然而,绝大多数的内容在 NoSQL 的 AR 里同样适用。</p>\r\n<h2>声明 AR 类</h2>\r\n<p>要想声明一个 AR 类,你需要扩展 yii\\db\\ActiveRecord 基类,\r\n并实现 <code>tableName</code> 方法,返回与之相关联的的数据表的名称:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">namespace</span> <span class="hljs-title">app</span>\\<span class="hljs-title">models</span>;\r\n\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">db</span>\\<span class="hljs-title">ActiveRecord</span>;\r\n\r\n<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span>\r\n</span>{\r\n <span class="hljs-comment">/**\r\n * <span class="hljs-doctag">@return</span> string 返回该AR类关联的数据表名\r\n */</span>\r\n <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tableName</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-string">''customer''</span>;\r\n }\r\n}\r\n</code></pre>\r\n<h2>访问列数据</h2>\r\n<p>AR 把相应数据行的每一个字段映射为 AR 对象的一个个特性变量(Attribute)\r\n一个特性就好像一个普通对象的公共属性一样(public property)。\r\n特性变量的名称和对应字段的名称是一样的,且大小姓名。</p>\r\n<p>使用以下语法读取列的值:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// "id" 和 "mail" 是 $customer 对象所关联的数据表的对应字段名</span>\r\n<span class="hljs-variable">$id</span> = <span class="hljs-variable">$customer</span>->id;\r\n<span class="hljs-variable">$email</span> = <span class="hljs-variable">$customer</span>->email;\r\n</code></pre>\r\n<p>要改变列值,只要给关联属性赋新值并保存对象即可:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$customer</span>->email = <span class="hljs-string">''[email protected]''</span>;\r\n<span class="hljs-variable">$customer</span>->save();\r\n</code></pre>\r\n<h2>建立数据库连接</h2>\r\n<p>AR 用一个 yii\\db\\Connection 对象与数据库交换数据。\r\n默认的,它使用 <code>db</code> 组件作为其连接对象。详见<a href="/doc/guide/2.0/database-basics">数据库基础</a>章节,\r\n你可以在应用程序配置文件中设置下 <code>db</code> 组件,就像这样,</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">return</span> [\r\n <span class="hljs-string">''components''</span> => [\r\n <span class="hljs-string">''db''</span> => [\r\n <span class="hljs-string">''class''</span> => <span class="hljs-string">''yii\\db\\Connection''</span>,\r\n <span class="hljs-string">''dsn''</span> => <span class="hljs-string">''mysql:host=localhost;dbname=testdb''</span>,\r\n <span class="hljs-string">''username''</span> => <span class="hljs-string">''demo''</span>,\r\n <span class="hljs-string">''password''</span> => <span class="hljs-string">''demo''</span>,\r\n ],\r\n ],\r\n];\r\n</code></pre>\r\n<p>如果在你的应用中应用了不止一个数据库,且你需要给你的 AR 类使用不同的数据库链接(DB connection)\r\n,你可以覆盖掉 yii\\db\\ActiveRecord::getDb() 方法:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span>\r\n</span>{\r\n <span class="hljs-comment">// ...</span>\r\n\r\n <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getDb</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> \\Yii::<span class="hljs-variable">$app</span>->db2; <span class="hljs-comment">// 使用名为 "db2" 的应用组件</span>\r\n }\r\n}\r\n</code></pre>\r\n<h2>查询数据</h2>\r\n<p>AR 提供了两种方法来构建 DB 查询并向 AR 实例里填充数据:</p>\r\n<ul><li>yii\\db\\ActiveRecord::find()</li>\r\n<li>yii\\db\\ActiveRecord::findBySql()</li>\r\n</ul><p>以上两个方法都会返回 yii\\db\\ActiveQuery 实例,该类继承自yii\\db\\Query,\r\n因此,他们都支持同一套灵活且强大的 DB 查询方法,如 <code>where()</code>,<code>join()</code>,<code>orderBy()</code>,等等。 \r\n下面的这些案例展示了一些可能的玩法:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// 取回所有活跃客户(状态为 *active* 的客户)并以他们的 ID 排序:</span>\r\n<span class="hljs-variable">$customers</span> = Customer::find()\r\n ->where([<span class="hljs-string">''status''</span> => Customer::STATUS_ACTIVE])\r\n ->orderBy(<span class="hljs-string">''id''</span>)\r\n ->all();\r\n\r\n<span class="hljs-comment">// 返回ID为1的客户:</span>\r\n<span class="hljs-variable">$customer</span> = Customer::find()\r\n ->where([<span class="hljs-string">''id''</span> => <span class="hljs-number">1</span>])\r\n ->one();\r\n\r\n<span class="hljs-comment">// 取回活跃客户的数量:</span>\r\n<span class="hljs-variable">$count</span> = Customer::find()\r\n ->where([<span class="hljs-string">''status''</span> => Customer::STATUS_ACTIVE])\r\n ->count();\r\n\r\n<span class="hljs-comment">// 以客户ID索引结果集:</span>\r\n<span class="hljs-variable">$customers</span> = Customer::find()->indexBy(<span class="hljs-string">''id''</span>)->all();\r\n<span class="hljs-comment">// $customers 数组以 ID 为索引</span>\r\n\r\n<span class="hljs-comment">// 用原生 SQL 语句检索客户:</span>\r\n<span class="hljs-variable">$sql</span> = <span class="hljs-string">''SELECT * FROM customer''</span>;\r\n<span class="hljs-variable">$customers</span> = Customer::findBySql(<span class="hljs-variable">$sql</span>)->all();\r\n</code></pre>\r\n<blockquote><p>小技巧:在上面的代码中,<code>Customer::STATUS_ACTIVE</code> 是一个在 <code>Customer</code> 类里定义的常量。(译注:这种常量的值一般都是tinyint)相较于直接在代码中写死字符串或数字,使用一个更有意义的常量名称是一种更好的编程习惯。</p>\r\n</blockquote>\r\n<p>有两个快捷方法:<code>findOne</code> 和 <code>findAll()</code> 用来返回一个或者一组<code>ActiveRecord</code>实例。前者返回第一个匹配到的实例,后者返回所有。\r\n例如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// 返回 id 为 1 的客户</span>\r\n<span class="hljs-variable">$customer</span> = Customer::findOne(<span class="hljs-number">1</span>);\r\n\r\n<span class="hljs-comment">// 返回 id 为 1 且状态为 *active* 的客户</span>\r\n<span class="hljs-variable">$customer</span> = Customer::findOne([\r\n <span class="hljs-string">''id''</span> => <span class="hljs-number">1</span>,\r\n <span class="hljs-string">''status''</span> => Customer::STATUS_ACTIVE,\r\n]);\r\n\r\n<span class="hljs-comment">// 返回id为1、2、3的一组客户</span>\r\n<span class="hljs-variable">$customers</span> = Customer::findAll([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]);\r\n\r\n<span class="hljs-comment">// 返回所有状态为 "deleted" 的客户</span>\r\n<span class="hljs-variable">$customer</span> = Customer::findAll([\r\n <span class="hljs-string">''status''</span> => Customer::STATUS_DELETED,\r\n]);\r\n</code></pre>\r\n<h3>以数组形式获取数据</h3>\r\n<p>有时候,我们需要处理很大量的数据,这时可能需要用一个数组来存储取到的数据,\r\n从而节省内存。你可以用 <code>asArray()</code> 函数做到这一点:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// 以数组而不是对象形式取回客户信息:</span>\r\n<span class="hljs-variable">$customers</span> = Customer::find()\r\n ->asArray()\r\n ->all();\r\n<span class="hljs-comment">// $customers 的每个元素都是键值对数组</span>\r\n</code></pre>\r\n<h3>批量获取数据</h3>\r\n<p>在 <a href="/doc/guide/2.0/query-builder">Query Builder(查询构造器)</a> 里,我们已经解释了当需要从数据库中查询大量数据时,你可以用 <em>batch query(批量查询)</em>来限制内存的占用。\r\n你可能也想在 AR 里使用相同的技巧,比如这样……</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// 一次提取 10 个客户信息</span>\r\n<span class="hljs-keyword">foreach</span> (Customer::find()->batch(<span class="hljs-number">10</span>) <span class="hljs-keyword">as</span> <span class="hljs-variable">$customers</span>) {\r\n <span class="hljs-comment">// $customers 是 10 个或更少的客户对象的数组</span>\r\n}\r\n<span class="hljs-comment">// 一次提取 10 个客户并一个一个地遍历处理</span>\r\n<span class="hljs-keyword">foreach</span> (Customer::find()->each(<span class="hljs-number">10</span>) <span class="hljs-keyword">as</span> <span class="hljs-variable">$customer</span>) {\r\n <span class="hljs-comment">// $customer 是一个 ”Customer“ 对象</span>\r\n}\r\n<span class="hljs-comment">// 贪婪加载模式的批处理查询</span>\r\n<span class="hljs-keyword">foreach</span> (Customer::find()->with(<span class="hljs-string">''orders''</span>)->each() <span class="hljs-keyword">as</span> <span class="hljs-variable">$customer</span>) {\r\n}\r\n</code></pre>\r\n<h2>操作数据</h2>\r\n<p>AR 提供以下方法插入、更新和删除与 AR 对象关联的那张表中的某一行:</p>\r\n<ul><li>yii\\db\\ActiveRecord::save()</li>\r\n<li>yii\\db\\ActiveRecord::insert()</li>\r\n<li>yii\\db\\ActiveRecord::update()</li>\r\n<li>yii\\db\\ActiveRecord::delete()</li>\r\n</ul><p>AR 同时提供了一下静态方法,可以应用在与某 AR 类所关联的整张表上。\r\n用这些方法的时候千万要小心,因为他们作用于整张表!\r\n比如,<code>deleteAll()</code> 会删除掉表里<strong>所有</strong>的记录。</p>\r\n<ul><li>yii\\db\\ActiveRecord::updateCounters()</li>\r\n<li>yii\\db\\ActiveRecord::updateAll()</li>\r\n<li>yii\\db\\ActiveRecord::updateAllCounters()</li>\r\n<li>yii\\db\\ActiveRecord::deleteAll()</li>\r\n</ul><p>下面的这些例子里,详细展现了如何使用这些方法:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// 插入新客户的记录</span>\r\n<span class="hljs-variable">$customer</span> = <span class="hljs-keyword">new</span> Customer();\r\n<span class="hljs-variable">$customer</span>->name = <span class="hljs-string">''James''</span>;\r\n<span class="hljs-variable">$customer</span>->email = <span class="hljs-string">''[email protected]''</span>;\r\n<span class="hljs-variable">$customer</span>->save(); <span class="hljs-comment">// 等同于 $customer->insert();</span>\r\n\r\n<span class="hljs-comment">// 更新现有客户记录</span>\r\n<span class="hljs-variable">$customer</span> = Customer::findOne(<span class="hljs-variable">$id</span>);\r\n<span class="hljs-variable">$customer</span>->email = <span class="hljs-string">''[email protected]''</span>;\r\n<span class="hljs-variable">$customer</span>->save(); <span class="hljs-comment">// 等同于 $customer->update();</span>\r\n\r\n<span class="hljs-comment">// 删除已有客户记录</span>\r\n<span class="hljs-variable">$customer</span> = Customer::findOne(<span class="hljs-variable">$id</span>);\r\n<span class="hljs-variable">$customer</span>->delete();\r\n\r\n<span class="hljs-comment">// 删除多个年龄大于20,性别为男(Male)的客户记录</span>\r\nCustomer::deleteAll(<span class="hljs-string">''age > :age AND gender = :gender''</span>, [<span class="hljs-string">'':age''</span> => <span class="hljs-number">20</span>, <span class="hljs-string">'':gender''</span> => <span class="hljs-string">''M''</span>]);\r\n\r\n<span class="hljs-comment">// 所有客户的age(年龄)字段加1:</span>\r\nCustomer::updateAllCounters([<span class="hljs-string">''age''</span> => <span class="hljs-number">1</span>]);\r\n</code></pre>\r\n<blockquote><p>须知:<code>save()</code> 方法会调用 <code>insert()</code> 和 <code>update()</code> 中的一个,\r\n用哪个取决于当前 AR 对象是不是新对象(在函数内部,他会检查 yii\\db\\ActiveRecord::isNewRecord 的值)。\r\n若 AR 对象是由 <code>new</code> 操作符 初始化出来的,<code>save()</code> 方法会在表里<em>插入</em>一条数据;\r\n如果一个 AR 是由 <code>find()</code> 方法获取来的,\r\n则 <code>save()</code> 会<em>更新</em>表里的对应行记录。</p>\r\n</blockquote>\r\n<h3>数据输入与有效性验证</h3>\r\n<p>由于AR继承自yii\\base\\Model,所以它同样也支持<a href="/doc/guide/2.0/model">Model</a>的数据输入、验证等特性。例如,你可以声明一个rules方法用来覆盖掉yii\\base\\Model::rules()里的;你也可以给AR实例批量赋值;你也可以通过调用yii\\base\\Model::validate()执行数据验证。</p>\r\n<p>当你调用 <code>save()</code>、<code>insert()</code>、<code>update()</code> 这三个方法时,会自动调用yii\\base\\Model::validate()方法。如果验证失败,数据将不会保存进数据库。</p>\r\n<p>下面的例子演示了如何使用AR 获取/验证用户输入的数据并将他们保存进数据库:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// 新建一条记录</span>\r\n<span class="hljs-variable">$model</span> = <span class="hljs-keyword">new</span> Customer;\r\n<span class="hljs-keyword">if</span> (<span class="hljs-variable">$model</span>->load(Yii::<span class="hljs-variable">$app</span>->request->post()) && <span class="hljs-variable">$model</span>->save()) {\r\n <span class="hljs-comment">// 获取用户输入的数据,验证并保存</span>\r\n}\r\n\r\n<span class="hljs-comment">// 更新主键为$id的AR</span>\r\n<span class="hljs-variable">$model</span> = Customer::findOne(<span class="hljs-variable">$id</span>);\r\n<span class="hljs-keyword">if</span> (<span class="hljs-variable">$model</span> === <span class="hljs-keyword">null</span>) {\r\n <span class="hljs-keyword">throw</span> <span class="hljs-keyword">new</span> NotFoundHttpException;\r\n}\r\n<span class="hljs-keyword">if</span> (<span class="hljs-variable">$model</span>->load(Yii::<span class="hljs-variable">$app</span>->request->post()) && <span class="hljs-variable">$model</span>->save()) {\r\n <span class="hljs-comment">// 获取用户输入的数据,验证并保存</span>\r\n}\r\n</code></pre>\r\n<h3>读取默认值</h3>\r\n<p>你的表列也许定义了默认值。有时候,你可能需要在使用web表单的时候给AR预设一些值。如果你需要这样做,可以在显示表单内容前通过调用<code>loadDefaultValues()</code>方法来实现:\r\n<code>`</code>php\r\n$customer = new Customer();\r\n$customer->loadDefaultValues();\r\n// ... 渲染 $customer 的 HTML 表单 ...\r\n<code>`</code></p> </div>', 'Yii,ActiveRecord,', 2, 1443000145, 1443000145, 1);
INSERT INTO `tbl_post` (`id`, `title`, `content`, `tags`, `status`, `create_time`, `update_time`, `author_id`) VALUES
(35, 'Active Record 详解(下)', '<div id="content">\r\n\r\n<h2>AR的生命周期</h2>\r\n<p>理解AR的生命周期对于你操作数据库非常重要。生命周期通常都会有些典型的事件存在。对于开发AR的behaviors来说非常有用。</p>\r\n<p>当你实例化一个新的AR对象时,我们将获得如下的生命周期:</p>\r\n<ol><li>constructor</li>\r\n<li>yii\\db\\ActiveRecord::init(): 会触发一个 yii\\db\\ActiveRecord::EVENT_INIT 事件</li>\r\n</ol><p>当你通过 yii\\db\\ActiveRecord::find() 方法查询数据时,每个AR实例都将有以下生命周期:</p>\r\n<ol><li>constructor</li>\r\n<li>yii\\db\\ActiveRecord::init(): 会触发一个 yii\\db\\ActiveRecord::EVENT_INIT 事件</li>\r\n<li>yii\\db\\ActiveRecord::afterFind(): 会触发一个 yii\\db\\ActiveRecord::EVENT_AFTER_FIND 事件</li>\r\n</ol><p>当通过 yii\\db\\ActiveRecord::save() 方法写入或者更新数据时, 我们将获得如下生命周期:</p>\r\n<ol><li>yii\\db\\ActiveRecord::beforeValidate(): 会触发一个 yii\\db\\ActiveRecord::EVENT_BEFORE_VALIDATE 事件</li>\r\n<li>yii\\db\\ActiveRecord::afterValidate(): 会触发一个 yii\\db\\ActiveRecord::EVENT_AFTER_VALIDATE 事件</li>\r\n<li>yii\\db\\ActiveRecord::beforeSave(): 会触发一个 yii\\db\\ActiveRecord::EVENT_BEFORE_INSERT 或 yii\\db\\ActiveRecord::EVENT_BEFORE_UPDATE 事件</li>\r\n<li>执行实际的数据写入或更新</li>\r\n<li>yii\\db\\ActiveRecord::afterSave(): 会触发一个 yii\\db\\ActiveRecord::EVENT_AFTER_INSERT 或 yii\\db\\ActiveRecord::EVENT_AFTER_UPDATE 事件</li>\r\n</ol><p>最后,当调用 yii\\db\\ActiveRecord::delete() 删除数据时, 我们将获得如下生命周期:</p>\r\n<ol><li>yii\\db\\ActiveRecord::beforeDelete(): 会触发一个 yii\\db\\ActiveRecord::EVENT_BEFORE_DELETE 事件</li>\r\n<li>执行实际的数据删除</li>\r\n<li>yii\\db\\ActiveRecord::afterDelete(): 会触发一个 yii\\db\\ActiveRecord::EVENT_AFTER_DELETE 事件</li>\r\n</ol><h2>查询关联的数据</h2>\r\n<p>使用 AR 方法也可以查询数据表的关联数据(如,选出表A的数据可以拉出表B的关联数据)。\r\n有了 AR,\r\n返回的关联数据连接就像连接关联主表的 AR 对象的属性一样。</p>\r\n<p>建立关联关系后,通过 <code>$customer->orders</code> 可以获取\r\n一个 <code>Order</code> 对象的数组,该数组代表当前客户对象的订单集。</p>\r\n<p>定义关联关系使用一个可以返回 yii\\db\\ActiveQuery 对象的 getter 方法,\r\nyii\\db\\ActiveQuery对象有关联上下文的相关信息,因此可以只查询关联数据。</p>\r\n<p>例如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> <span class="hljs-keyword">extends</span> \\<span class="hljs-title">yii</span>\\<span class="hljs-title">db</span>\\<span class="hljs-title">ActiveRecord</span>\r\n</span>{\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getOrders</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-comment">// 客户和订单通过 Order.customer_id -> id 关联建立一对多关系</span>\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$this</span>->hasMany(Order::className(), [<span class="hljs-string">''customer_id''</span> => <span class="hljs-string">''id''</span>]);\r\n }\r\n}\r\n\r\n<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Order</span> <span class="hljs-keyword">extends</span> \\<span class="hljs-title">yii</span>\\<span class="hljs-title">db</span>\\<span class="hljs-title">ActiveRecord</span>\r\n</span>{\r\n <span class="hljs-comment">// 订单和客户通过 Customer.id -> customer_id 关联建立一对一关系</span>\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getCustomer</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$this</span>->hasOne(Customer::className(), [<span class="hljs-string">''id''</span> => <span class="hljs-string">''customer_id''</span>]);\r\n }\r\n}\r\n</code></pre>\r\n<p>以上使用了 yii\\db\\ActiveRecord::hasMany() 和 yii\\db\\ActiveRecord::hasOne() 方法。\r\n以上两例分别是关联数据多对一关系和一对一关系的建模范例。\r\n如,一个客户有很多订单,一个订单只归属一个客户。\r\n两个方法都有两个参数并返回 yii\\db\\ActiveQuery 对象。</p>\r\n<ul><li><code>$class</code>:关联模型类名,它必须是一个完全合格的类名。</li>\r\n<li><code>$link</code>: 两个表的关联列,应为键值对数组的形式。\r\n数组的键是 <code>$class</code> 关联表的列名,\r\n而数组值是关联类 $class 的列名。\r\n基于表外键定义关联关系是最佳方法。</li>\r\n</ul><p>建立关联关系后,获取关联数据和获取组件属性一样简单,\r\n执行以下相应getter方法即可:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// 取得客户的订单</span>\r\n<span class="hljs-variable">$customer</span> = Customer::findOne(<span class="hljs-number">1</span>);\r\n<span class="hljs-variable">$orders</span> = <span class="hljs-variable">$customer</span>->orders; <span class="hljs-comment">// $orders 是 Order 对象数组</span>\r\n</code></pre>\r\n<p>以上代码实际执行了以下两条 SQL 语句:</p>\r\n<pre><code class="language-sql hljs"><span class="hljs-operator">SELECT * <span class="hljs-keyword">FROM</span> customer <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">id</span>=<span class="hljs-number">1</span>;</span>\r\n<span class="hljs-operator">SELECT * <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">order</span> <span class="hljs-keyword">WHERE</span> customer_id=<span class="hljs-number">1</span>;</span>\r\n</code></pre>\r\n<blockquote><p>提示:再次用表达式 <code>$customer->orders</code>将不会执行第二次 SQL 查询,\r\nSQL 查询只在该表达式第一次使用时执行。\r\n数据库访问只返回缓存在内部前一次取回的结果集,如果你想查询新的\r\n关联数据,先要注销现有结果集:<code>unset($customer->orders);</code>。</p>\r\n</blockquote>\r\n<p>有时候需要在关联查询中传递参数,如不需要返回客户全部订单,\r\n只需要返回购买金额超过设定值的大订单,\r\n通过以下getter方法声明一个关联数据 <code>bigOrders</code> :</p>\r\n<pre><code class="language-php hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> <span class="hljs-keyword">extends</span> \\<span class="hljs-title">yii</span>\\<span class="hljs-title">db</span>\\<span class="hljs-title">ActiveRecord</span>\r\n</span>{\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getBigOrders</span><span class="hljs-params">(<span class="hljs-variable">$threshold</span> = <span class="hljs-number">100</span>)</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$this</span>->hasMany(Order::className(), [<span class="hljs-string">''customer_id''</span> => <span class="hljs-string">''id''</span>])\r\n ->where(<span class="hljs-string">''subtotal > :threshold''</span>, [<span class="hljs-string">'':threshold''</span> => <span class="hljs-variable">$threshold</span>])\r\n ->orderBy(<span class="hljs-string">''id''</span>);\r\n }\r\n}\r\n</code></pre>\r\n<p><code>hasMany()</code> 返回 yii\\db\\ActiveQuery 对象,该对象允许你通过\r\nyii\\db\\ActiveQuery 方法定制查询。</p>\r\n<p>如上声明后,执行 <code>$customer->bigOrders</code> 就返回\r\n总额大于100的订单。使用以下代码更改设定值:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$orders</span> = <span class="hljs-variable">$customer</span>->getBigOrders(<span class="hljs-number">200</span>)->all();\r\n</code></pre>\r\n<p>>注意:关联查询返回的是 yii\\db\\ActiveQuery 的实例,如果像特性(如类属性)那样连接关联数据,\r\n返回的结果是关联查询的结果,即 yii\\db\\ActiveRecord 的实例,\r\n或者是数组,或者是 null ,取决于关联关系的多样性。如,<code>$customer->getOrders()</code> 返回\r\n<code>ActiveQuery</code> 实例,而 <code>$customer->orders</code> 返回<code>Order</code> 对象数组\r\n(如果查询结果为空则返回空数组)。</p>\r\n<h2>中间关联表</h2>\r\n<p>有时,两个表通过中间表关联,定义这样的关联关系, 可以通过调用 yii\\db\\ActiveQuery::via() 方法或 yii\\db\\ActiveQuery::viaTable() 方法来定制 yii\\db\\ActiveQuery 对象 。</p>\r\n<p>举例而言,如果 <code>order</code> 表和 <code>item</code> 表通过中间表 <code>order_item</code> 关联起来, 可以在 <code>Order</code> 类声明 <code>items</code> 关联关系取代中间表:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Order</span> <span class="hljs-keyword">extends</span> \\<span class="hljs-title">yii</span>\\<span class="hljs-title">db</span>\\<span class="hljs-title">ActiveRecord</span>\r\n</span>{\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getItems</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$this</span>->hasMany(Item::className(), [<span class="hljs-string">''id''</span> => <span class="hljs-string">''item_id''</span>])\r\n ->viaTable(<span class="hljs-string">''order_item''</span>, [<span class="hljs-string">''order_id''</span> => <span class="hljs-string">''id''</span>]);\r\n }\r\n}\r\n</code></pre>\r\n<p>两个方法是相似的,除了 yii\\db\\ActiveQuery::via() 方法的第一个参数是使用 AR 类中定义的关联名。 以上方法取代了中间表,等价于:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Order</span> <span class="hljs-keyword">extends</span> \\<span class="hljs-title">yii</span>\\<span class="hljs-title">db</span>\\<span class="hljs-title">ActiveRecord</span>\r\n</span>{\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getOrderItems</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$this</span>->hasMany(OrderItem::className(), [<span class="hljs-string">''order_id''</span> => <span class="hljs-string">''id''</span>]);\r\n }\r\n\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getItems</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$this</span>->hasMany(Item::className(), [<span class="hljs-string">''id''</span> => <span class="hljs-string">''item_id''</span>])\r\n ->via(<span class="hljs-string">''orderItems''</span>);\r\n }\r\n}\r\n</code></pre>\r\n<h2>延迟加载和即时加载(又称惰性加载与贪婪加载)</h2>\r\n<p>如前所述,当你第一次连接关联对象时, AR 将执行一个数据库查询 来检索请求数据并填充到关联对象的相应属性。 如果再次连接相同的关联对象,不再执行任何查询语句,这种数据库查询的执行方法称为“延迟加载”。如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// SQL executed: SELECT * FROM customer WHERE id=1</span>\r\n<span class="hljs-variable">$customer</span> = Customer::findOne(<span class="hljs-number">1</span>);\r\n<span class="hljs-comment">// SQL executed: SELECT * FROM order WHERE customer_id=1</span>\r\n<span class="hljs-variable">$orders</span> = <span class="hljs-variable">$customer</span>->orders;\r\n<span class="hljs-comment">// 没有 SQL 语句被执行</span>\r\n<span class="hljs-variable">$orders2</span> = <span class="hljs-variable">$customer</span>->orders; <span class="hljs-comment">//取回上次查询的缓存数据</span>\r\n</code></pre>\r\n<p>延迟加载非常实用,但是,在以下场景中使用延迟加载会遭遇性能问题:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// SQL executed: SELECT * FROM customer LIMIT 100</span>\r\n<span class="hljs-variable">$customers</span> = Customer::find()->limit(<span class="hljs-number">100</span>)->all();\r\n\r\n<span class="hljs-keyword">foreach</span> (<span class="hljs-variable">$customers</span> <span class="hljs-keyword">as</span> <span class="hljs-variable">$customer</span>) {\r\n <span class="hljs-comment">// SQL executed: SELECT * FROM order WHERE customer_id=...</span>\r\n <span class="hljs-variable">$orders</span> = <span class="hljs-variable">$customer</span>->orders;\r\n <span class="hljs-comment">// ...处理 $orders...</span>\r\n}\r\n</code></pre>\r\n<p>假设数据库查出的客户超过100个,以上代码将执行多少条 SQL 语句? 101 条!第一条 SQL 查询语句取回100个客户,然后, 每个客户要执行一条 SQL 查询语句以取回该客户的所有订单。</p>\r\n<p>为解决以上性能问题,可以通过调用 yii\\db\\ActiveQuery::with() 方法使用即时加载解决。</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// SQL executed: SELECT * FROM customer LIMIT 100;</span>\r\n<span class="hljs-comment">// SELECT * FROM orders WHERE customer_id IN (1,2,...)</span>\r\n<span class="hljs-variable">$customers</span> = Customer::find()->limit(<span class="hljs-number">100</span>)\r\n ->with(<span class="hljs-string">''orders''</span>)->all();\r\n\r\n<span class="hljs-keyword">foreach</span> (<span class="hljs-variable">$customers</span> <span class="hljs-keyword">as</span> <span class="hljs-variable">$customer</span>) {\r\n <span class="hljs-comment">// 没有 SQL 语句被执行</span>\r\n <span class="hljs-variable">$orders</span> = <span class="hljs-variable">$customer</span>->orders;\r\n <span class="hljs-comment">// ...处理 $orders...</span>\r\n}\r\n</code></pre>\r\n<p>如你所见,同样的任务只需要两个 SQL 语句。\r\n>须知:通常,即时加载 N 个关联关系而通过 via() 或者 viaTable() 定义了 M 个关联关系, 将有 1+M+N 条 SQL 查询语句被执行:一个查询取回主表行数, 一个查询给每一个 (M) 中间表,一个查询给每个 (N) 关联表。\r\n注意:当用即时加载定制 select() 时,确保连接 到关联模型的列都被包括了,否则,关联模型不会载入。如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$orders</span> = Order::find()->select([<span class="hljs-string">''id''</span>, <span class="hljs-string">''amount''</span>])->with(<span class="hljs-string">''customer''</span>)->all();\r\n<span class="hljs-comment">// $orders[0]->customer 总是空的,使用以下代码解决这个问题:</span>\r\n<span class="hljs-variable">$orders</span> = Order::find()->select([<span class="hljs-string">''id''</span>, <span class="hljs-string">''amount''</span>, <span class="hljs-string">''customer_id''</span>])->with(<span class="hljs-string">''customer''</span>)->all();\r\n</code></pre>\r\n<p>有时候,你想自由的自定义关联查询,延迟加载和即时加载都可以实现,如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$customer</span> = Customer::findOne(<span class="hljs-number">1</span>);\r\n<span class="hljs-comment">// 延迟加载: SELECT * FROM order WHERE customer_id=1 AND subtotal>100</span>\r\n<span class="hljs-variable">$orders</span> = <span class="hljs-variable">$customer</span>->getOrders()->where(<span class="hljs-string">''subtotal>100''</span>)->all();\r\n\r\n<span class="hljs-comment">// 即时加载: SELECT * FROM customer LIMIT 100</span>\r\n<span class="hljs-comment">// SELECT * FROM order WHERE customer_id IN (1,2,...) AND subtotal>100</span>\r\n<span class="hljs-variable">$customers</span> = Customer::find()->limit(<span class="hljs-number">100</span>)->with([\r\n <span class="hljs-string">''orders''</span> => <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(<span class="hljs-variable">$query</span>)</span> </span>{\r\n <span class="hljs-variable">$query</span>->andWhere(<span class="hljs-string">''subtotal>100''</span>);\r\n },\r\n])->all();\r\n</code></pre>\r\n<h2>逆关系</h2>\r\n<p>关联关系通常成对定义,如:Customer 可以有个名为 orders 关联项, 而 Order 也有个名为customer 的关联项:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span>\r\n</span>{\r\n ....\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getOrders</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$this</span>->hasMany(Order::className(), [<span class="hljs-string">''customer_id''</span> => <span class="hljs-string">''id''</span>]);\r\n }\r\n}\r\n\r\n<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Order</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span>\r\n</span>{\r\n ....\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getCustomer</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$this</span>->hasOne(Customer::className(), [<span class="hljs-string">''id''</span> => <span class="hljs-string">''customer_id''</span>]);\r\n }\r\n}\r\n</code></pre>\r\n<p>如果我们执行以下查询,可以发现订单的 customer 和 找到这些订单的客户对象并不是同一个。连接 customer->orders 将触发一条 SQL 语句 而连接一个订单的 customer 将触发另一条 SQL 语句。</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// SELECT * FROM customer WHERE id=1</span>\r\n<span class="hljs-variable">$customer</span> = Customer::findOne(<span class="hljs-number">1</span>);\r\n<span class="hljs-comment">// 输出 "不相同"</span>\r\n<span class="hljs-comment">// SELECT * FROM order WHERE customer_id=1</span>\r\n<span class="hljs-comment">// SELECT * FROM customer WHERE id=1</span>\r\n<span class="hljs-keyword">if</span> (<span class="hljs-variable">$customer</span>->orders[<span class="hljs-number">0</span>]->customer === <span class="hljs-variable">$customer</span>) {\r\n <span class="hljs-keyword">echo</span> <span class="hljs-string">''相同''</span>;\r\n} <span class="hljs-keyword">else</span> {\r\n <span class="hljs-keyword">echo</span> <span class="hljs-string">''不相同''</span>;\r\n}\r\n</code></pre>\r\n<p>为避免多余执行的后一条语句,我们可以为 customer或 orders 关联关系定义相反的关联关系,通过调用 yii\\db\\ActiveQuery::inverseOf() 方法可以实现。</p>\r\n<pre><code class="language-php hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Customer</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span>\r\n</span>{\r\n ....\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getOrders</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$this</span>->hasMany(Order::className(), [<span class="hljs-string">''customer_id''</span> => <span class="hljs-string">''id''</span>])->inverseOf(<span class="hljs-string">''customer''</span>);\r\n }\r\n}\r\n</code></pre>\r\n<p>现在我们同样执行上面的查询,我们将得到:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// SELECT * FROM customer WHERE id=1</span>\r\n<span class="hljs-variable">$customer</span> = Customer::findOne(<span class="hljs-number">1</span>);\r\n<span class="hljs-comment">// 输出相同</span>\r\n<span class="hljs-comment">// SELECT * FROM order WHERE customer_id=1</span>\r\n<span class="hljs-keyword">if</span> (<span class="hljs-variable">$customer</span>->orders[<span class="hljs-number">0</span>]->customer === <span class="hljs-variable">$customer</span>) {\r\n <span class="hljs-keyword">echo</span> <span class="hljs-string">''相同''</span>;\r\n} <span class="hljs-keyword">else</span> {\r\n <span class="hljs-keyword">echo</span> <span class="hljs-string">''不相同''</span>;\r\n}\r\n</code></pre>\r\n<p>以上我们展示了如何在延迟加载中使用相对关联关系, 相对关系也可以用在即时加载中:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// SELECT * FROM customer</span>\r\n<span class="hljs-comment">// SELECT * FROM order WHERE customer_id IN (1, 2, ...)</span>\r\n<span class="hljs-variable">$customers</span> = Customer::find()->with(<span class="hljs-string">''orders''</span>)->all();\r\n<span class="hljs-comment">// 输出相同</span>\r\n<span class="hljs-keyword">if</span> (<span class="hljs-variable">$customers</span>[<span class="hljs-number">0</span>]->orders[<span class="hljs-number">0</span>]->customer === <span class="hljs-variable">$customers</span>[<span class="hljs-number">0</span>]) {\r\n <span class="hljs-keyword">echo</span> <span class="hljs-string">''相同''</span>;\r\n} <span class="hljs-keyword">else</span> {\r\n <span class="hljs-keyword">echo</span> <span class="hljs-string">''不相同''</span>;\r\n}\r\n</code></pre>\r\n<p>>注意:相对关系不能在包含中间表的关联关系中定义。 即是,如果你的关系是通过yii\\db\\ActiveQuery::via() 或 yii\\db\\ActiveQuery::viaTable()方法定义的, 就不能调用yii\\db\\ActiveQuery::inverseOf()方法了。</p>\r\n<h2> JOIN 类型关联查询</h2>\r\n<p>使用关系数据库时,普遍要做的是连接多个表并明确地运用各种 JOIN 查询。\r\nJOIN SQL语句的查询条件和参数,使用 yii\\db\\ActiveQuery::joinWith()\r\n可以重用已定义关系并调用\r\n而不是使用 yii\\db\\ActiveQuery::join() 来实现目标。</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// 查找所有订单并以客户 ID 和订单 ID 排序,并贪婪加载 "customer" 表</span>\r\n<span class="hljs-variable">$orders</span> = Order::find()->joinWith(<span class="hljs-string">''customer''</span>)->orderBy(<span class="hljs-string">''customer.id, order.id''</span>)->all();\r\n<span class="hljs-comment">// 查找包括书籍的所有订单,并以 `INNER JOIN` 的连接方式即时加载 "books" 表</span>\r\n<span class="hljs-variable">$orders</span> = Order::find()->innerJoinWith(<span class="hljs-string">''books''</span>)->all();\r\n</code></pre>\r\n<p>以上,方法 yii\\db\\ActiveQuery::innerJoinWith() 是访问 <code>INNER JOIN</code> 类型的 yii\\db\\ActiveQuery::joinWith() 的快捷方式。</p>\r\n<p>可以连接一个或多个关联关系,可以自由使用查询条件到关联查询,\r\n也可以嵌套连接关联查询。如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// 连接多重关系</span>\r\n<span class="hljs-comment">// 找出24小时内注册客户包含书籍的订单</span>\r\n<span class="hljs-variable">$orders</span> = Order::find()->innerJoinWith([\r\n <span class="hljs-string">''books''</span>,\r\n <span class="hljs-string">''customer''</span> => <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(<span class="hljs-variable">$query</span>)</span> </span>{\r\n <span class="hljs-variable">$query</span>->where(<span class="hljs-string">''customer.created_at > ''</span> . (time() - <span class="hljs-number">24</span> * <span class="hljs-number">3600</span>));\r\n }\r\n])->all();\r\n<span class="hljs-comment">// 连接嵌套关系:连接 books 表及其 author 列</span>\r\n<span class="hljs-variable">$orders</span> = Order::find()->joinWith(<span class="hljs-string">''books.author''</span>)->all();\r\n</code></pre>\r\n<p>代码背后, Yii 先执行一条 JOIN SQL 语句把满足 JOIN SQL 语句查询条件的主要模型查出,\r\n然后为每个关系执行一条查询语句,\r\nbing填充相应的关联记录。</p>\r\n<p>yii\\db\\ActiveQuery::joinWith() 和 yii\\db\\ActiveQuery::with() 的区别是\r\n前者连接主模型类和关联模型类的数据表来检索主模型,\r\n而后者只查询和检索主模型类。\r\n检索主模型</p>\r\n<p>由于这个区别,你可以应用只针对一条 JOIN SQL 语句起效的查询条件。\r\n如,通过关联模型的查询条件过滤主模型,如前例,\r\n可以使用关联表的列来挑选主模型数据,</p>\r\n<p>当使用 yii\\db\\ActiveQuery::joinWith() 方法时可以响应没有歧义的列名。\r\nIn the above examples, we use <code>item.id</code> and <code>order.id</code> to disambiguate the <code>id</code> column references\r\n因为订单表和项目表都包括 <code>id</code> 列。</p>\r\n<p>当连接关联关系时,关联关系默认使用即时加载。你可以\r\n通过传参数 <code>$eagerLoading</code> 来决定在指定关联查询中是否使用即时加载。</p>\r\n<p>默认 yii\\db\\ActiveQuery::joinWith() 使用左连接来连接关联表。\r\n你也可以传 <code>$joinType</code> 参数来定制连接类型。\r\n你也可以使用 yii\\db\\ActiveQuery::innerJoinWith()。</p>\r\n<p>以下是 <code>INNER JOIN</code> 的简短例子:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// 查找包括书籍的所有订单,但 "books" 表不使用即时加载</span>\r\n<span class="hljs-variable">$orders</span> = Order::find()->innerJoinWith(<span class="hljs-string">''books''</span>, <span class="hljs-keyword">false</span>)->all();\r\n<span class="hljs-comment">// 等价于:</span>\r\n<span class="hljs-variable">$orders</span> = Order::find()->joinWith(<span class="hljs-string">''books''</span>, <span class="hljs-keyword">false</span>, <span class="hljs-string">''INNER JOIN''</span>)->all();\r\n</code></pre>\r\n<p>有时连接两个表时,需要在关联查询的 ON 部分指定额外条件。\r\n这可以通过调用 yii\\db\\ActiveQuery::onCondition() 方法实现:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">User</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span>\r\n</span>{\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getBooks</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$this</span>->hasMany(Item::className(), [<span class="hljs-string">''owner_id''</span> => <span class="hljs-string">''id''</span>])->onCondition([<span class="hljs-string">''category_id''</span> => <span class="hljs-number">1</span>]);\r\n }\r\n}\r\n</code></pre>\r\n<p>在上面, yii\\db\\ActiveRecord::hasMany() 方法回传了一个 yii\\db\\ActiveQuery 对象,\r\n当你用 yii\\db\\ActiveQuery::joinWith() 执行一条查询时,取决于正被调用的是哪个 yii\\db\\ActiveQuery::onCondition(),\r\n返回 <code>category_id</code> 为 1 的 items </p>\r\n<p>当你用 yii\\db\\ActiveQuery::joinWith() 进行一次查询时,“on-condition”条件会被放置在相应查询语句的 ON 部分,\r\n如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// SELECT user.* FROM user LEFT JOIN item ON item.owner_id=user.id AND category_id=1</span>\r\n<span class="hljs-comment">// SELECT * FROM item WHERE owner_id IN (...) AND category_id=1</span>\r\n<span class="hljs-variable">$users</span> = User::find()->joinWith(<span class="hljs-string">''books''</span>)->all();\r\n</code></pre>\r\n<p>注意:如果通过 yii\\db\\ActiveQuery::with() 进行贪婪加载或使用惰性加载的话,则 on 条件会被放置在对应 SQL语句的 <code>WHERE</code> 部分。\r\n因为,此时此处并没有发生 JOIN 查询。比如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// SELECT * FROM user WHERE id=10</span>\r\n<span class="hljs-variable">$user</span> = User::findOne(<span class="hljs-number">10</span>);\r\n<span class="hljs-comment">// SELECT * FROM item WHERE owner_id=10 AND category_id=1</span>\r\n<span class="hljs-variable">$books</span> = <span class="hljs-variable">$user</span>->books;\r\n</code></pre>\r\n<h2>关联表操作</h2>\r\n<p>AR 提供了下面两个方法用来建立和解除两个关联对象之间的关系:</p>\r\n<ul><li>yii\\db\\ActiveRecord::link()</li>\r\n<li>yii\\db\\ActiveRecord::unlink()</li>\r\n</ul><p>例如,给定一个customer和order对象,我们可以通过下面的代码使得customer对象拥有order对象:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$customer</span> = Customer::findOne(<span class="hljs-number">1</span>);\r\n<span class="hljs-variable">$order</span> = <span class="hljs-keyword">new</span> Order();\r\n<span class="hljs-variable">$order</span>->subtotal = <span class="hljs-number">100</span>;\r\n<span class="hljs-variable">$customer</span>->link(<span class="hljs-string">''orders''</span>, <span class="hljs-variable">$order</span>);\r\n</code></pre>\r\n<p>yii\\db\\ActiveRecord::link() 调用上述将设置 customer_id 的顺序是 $customer 的主键值,然后调用 yii\\db\\ActiveRecord::save() 要将顺序保存到数据库中。</p>\r\n<h2>作用域</h2>\r\n<p>当你调用yii\\db\\ActiveRecord::find() 或 yii\\db\\ActiveRecord::findBySql()方法时,将会返回一个yii\\db\\ActiveQuery实例。之后,你可以调用其他查询方法,如 yii\\db\\ActiveQuery::where(),yii\\db\\ActiveQuery::orderBy(), 进一步的指定查询条件。</p>\r\n<p>有时候你可能需要在不同的地方使用相同的查询方法。如果出现这种情况,你应该考虑定义所谓的作用域。作用域是本质上要求一组的查询方法来修改查询对象的自定义查询类中定义的方法。 之后你就可以像使用普通方法一样使用作用域。</p>\r\n<p>只需两步即可定义一个作用域。首先给你的model创建一个自定义的查询类,在此类中定义的所需的范围方法。例如,给Comment模型创建一个 CommentQuery类,然后在CommentQuery类中定义一个active()的方法为作用域,像下面的代码:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">namespace</span> <span class="hljs-title">app</span>\\<span class="hljs-title">models</span>;\r\n\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">db</span>\\<span class="hljs-title">ActiveQuery</span>;\r\n\r\n<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">CommentQuery</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveQuery</span>\r\n</span>{\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">active</span><span class="hljs-params">(<span class="hljs-variable">$state</span> = true)</span>\r\n </span>{\r\n <span class="hljs-variable">$this</span>->andWhere([<span class="hljs-string">''active''</span> => <span class="hljs-variable">$state</span>]);\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$this</span>;\r\n }\r\n}\r\n</code></pre>\r\n<p>重点:</p>\r\n<ol><li>类必须继承 yii\\db\\ActiveQuery (或者是其他的 ActiveQuery ,比如 yii\\mongodb\\ActiveQuery)。</li>\r\n<li>必须是一个public类型的方法且必须返回 $this 实现链式操作。可以传入参数。</li>\r\n<li>检查 yii\\db\\ActiveQuery 对于修改查询条件是非常有用的方法。</li>\r\n</ol><p>其次,覆盖yii\\db\\ActiveRecord::find() 方法使其返回自定义的查询对象而不是常规的yii\\db\\ActiveQuery。对于上述例子,你需要编写如下代码:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">namespace</span> <span class="hljs-title">app</span>\\<span class="hljs-title">models</span>;\r\n\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">db</span>\\<span class="hljs-title">ActiveRecord</span>;\r\n\r\n<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Comment</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span>\r\n</span>{\r\n <span class="hljs-comment">/**\r\n * <span class="hljs-doctag">@inheritdoc</span>\r\n * <span class="hljs-doctag">@return</span> CommentQuery\r\n */</span>\r\n <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">find</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-keyword">new</span> CommentQuery(get_called_class());\r\n }\r\n}\r\n</code></pre>\r\n<p>就这样,现在你可以使用自定义的作用域方法了:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$comments</span> = Comment::find()->active()->all();\r\n<span class="hljs-variable">$inactiveComments</span> = Comment::find()->active(<span class="hljs-keyword">false</span>)->all();\r\n</code></pre>\r\n<p>你也能在定义的关联里使用作用域方法,比如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Post</span> <span class="hljs-keyword">extends</span> \\<span class="hljs-title">yii</span>\\<span class="hljs-title">db</span>\\<span class="hljs-title">ActiveRecord</span>\r\n</span>{\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getActiveComments</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$this</span>->hasMany(Comment::className(), [<span class="hljs-string">''post_id''</span> => <span class="hljs-string">''id''</span>])->active();\r\n\r\n }\r\n}\r\n</code></pre>\r\n<p>或者在执行关联查询的时候使用(on-the-fly 是啥?):</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$posts</span> = Post::find()->with([\r\n <span class="hljs-string">''comments''</span> => <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(<span class="hljs-variable">$q</span>)</span> </span>{\r\n <span class="hljs-variable">$q</span>->active();\r\n }\r\n])->all();\r\n</code></pre>\r\n<h3>默认作用域</h3>\r\n<p>如果你之前用过 Yii 1.1 就应该知道默认作用域的概念。一个默认的作用域可以作用于所有查询。你可以很容易的通过重写yii\\db\\ActiveRecord::find()方法来定义一个默认作用域,例如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">find</span><span class="hljs-params">()</span>\r\n</span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-keyword">parent</span>::find()->where([<span class="hljs-string">''deleted''</span> => <span class="hljs-keyword">false</span>]);\r\n}\r\n</code></pre>\r\n<p>注意,你之后所有的查询都不能用 yii\\db\\ActiveQuery::where(),但是可以用 yii\\db\\ActiveQuery::andWhere() 和 yii\\db\\ActiveQuery::orWhere(),他们不会覆盖掉默认作用域。(译注:如果你要使用默认作用域,就不能在 xxx::find()后使用where()方法,你必须使用andXXX()或者orXXX()系的方法,否则默认作用域不会起效果,至于原因,打开where()方法的代码一看便知)</p>\r\n<h2>事务操作</h2>\r\n<p>当执行几个相关联的数据库操作的时候</p>\r\n<p>TODO: FIXME: WIP, TBD, <a href="https://github.com/yiisoft/yii2/issues/226">https://github.com/yiisoft/yii2/issues/226</a></p>\r\n<p>, yii\\db\\ActiveRecord::afterSave(), yii\\db\\ActiveRecord::beforeDelete() and/or yii\\db\\ActiveRecord::afterDelete() 生命周期周期方法(life cycle methods 我觉得这句翻译成“模板方法”会不会更好点?)。开发者可以通过重写yii\\db\\ActiveRecord::save()方法然后在控制器里使用事务操作,严格地说是似乎不是一个好的做法 (召回"瘦控制器 / 肥模型"基本规则)。</p>\r\n<p>这些方法在这里(如果你不明白自己实际在干什么,请不要使用他们),Models:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Feature</span> <span class="hljs-keyword">extends</span> \\<span class="hljs-title">yii</span>\\<span class="hljs-title">db</span>\\<span class="hljs-title">ActiveRecord</span>\r\n</span>{\r\n <span class="hljs-comment">// ...</span>\r\n\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getProduct</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$this</span>->hasOne(Product::className(), [<span class="hljs-string">''id''</span> => <span class="hljs-string">''product_id''</span>]);\r\n }\r\n}\r\n\r\n<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Product</span> <span class="hljs-keyword">extends</span> \\<span class="hljs-title">yii</span>\\<span class="hljs-title">db</span>\\<span class="hljs-title">ActiveRecord</span>\r\n</span>{\r\n <span class="hljs-comment">// ...</span>\r\n\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getFeatures</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$this</span>->hasMany(Feature::className(), [<span class="hljs-string">''product_id''</span> => <span class="hljs-string">''id''</span>]);\r\n }\r\n}\r\n</code></pre>\r\n<p>重写 yii\\db\\ActiveRecord::save() 方法:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProductController</span> <span class="hljs-keyword">extends</span> \\<span class="hljs-title">yii</span>\\<span class="hljs-title">web</span>\\<span class="hljs-title">Controller</span>\r\n</span>{\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">actionCreate</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-comment">// <span class="hljs-doctag">FIXME:</span> <span class="hljs-doctag">TODO:</span> WIP, TBD</span>\r\n }\r\n}\r\n</code></pre>\r\n<p>(译注:我觉得上面应该是原手册里的bug)</p>\r\n<p>在控制器层使用事务:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProductController</span> <span class="hljs-keyword">extends</span> \\<span class="hljs-title">yii</span>\\<span class="hljs-title">web</span>\\<span class="hljs-title">Controller</span>\r\n</span>{\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">actionCreate</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-comment">// <span class="hljs-doctag">FIXME:</span> <span class="hljs-doctag">TODO:</span> WIP, TBD</span>\r\n }\r\n}\r\n</code></pre>\r\n<p>作为这些脆弱方法的替代,你应该使用原子操作方案特性。</p>\r\n<pre><code class="language-php hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Feature</span> <span class="hljs-keyword">extends</span> \\<span class="hljs-title">yii</span>\\<span class="hljs-title">db</span>\\<span class="hljs-title">ActiveRecord</span>\r\n</span>{\r\n <span class="hljs-comment">// ...</span>\r\n\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getProduct</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$this</span>->hasOne(Product::className(), [<span class="hljs-string">''product_id''</span> => <span class="hljs-string">''id''</span>]);\r\n }\r\n\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">scenarios</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> [\r\n <span class="hljs-string">''userCreates''</span> => [\r\n <span class="hljs-string">''attributes''</span> => [<span class="hljs-string">''name''</span>, <span class="hljs-string">''value''</span>],\r\n <span class="hljs-string">''atomic''</span> => [<span class="hljs-keyword">self</span>::OP_INSERT],\r\n ],\r\n ];\r\n }\r\n}\r\n\r\n<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Product</span> <span class="hljs-keyword">extends</span> \\<span class="hljs-title">yii</span>\\<span class="hljs-title">db</span>\\<span class="hljs-title">ActiveRecord</span>\r\n</span>{\r\n <span class="hljs-comment">// ...</span>\r\n\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">getFeatures</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$this</span>->hasMany(Feature::className(), [<span class="hljs-string">''id''</span> => <span class="hljs-string">''product_id''</span>]);\r\n }\r\n\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">scenarios</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> [\r\n <span class="hljs-string">''userCreates''</span> => [\r\n <span class="hljs-string">''attributes''</span> => [<span class="hljs-string">''title''</span>, <span class="hljs-string">''price''</span>],\r\n <span class="hljs-string">''atomic''</span> => [<span class="hljs-keyword">self</span>::OP_INSERT],\r\n ],\r\n ];\r\n }\r\n\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">afterValidate</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">parent</span>::afterValidate();\r\n <span class="hljs-comment">// <span class="hljs-doctag">FIXME:</span> <span class="hljs-doctag">TODO:</span> WIP, TBD</span>\r\n }\r\n\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">afterSave</span><span class="hljs-params">(<span class="hljs-variable">$insert</span>)</span>\r\n </span>{\r\n <span class="hljs-keyword">parent</span>::afterSave(<span class="hljs-variable">$insert</span>);\r\n <span class="hljs-keyword">if</span> (<span class="hljs-variable">$this</span>->getScenario() === <span class="hljs-string">''userCreates''</span>) {\r\n <span class="hljs-comment">// <span class="hljs-doctag">FIXME:</span> <span class="hljs-doctag">TODO:</span> WIP, TBD</span>\r\n }\r\n }\r\n}\r\n</code></pre>\r\n<p>Controller里的代码将变得很简洁:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProductController</span> <span class="hljs-keyword">extends</span> \\<span class="hljs-title">yii</span>\\<span class="hljs-title">web</span>\\<span class="hljs-title">Controller</span>\r\n</span>{\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">actionCreate</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-comment">// <span class="hljs-doctag">FIXME:</span> <span class="hljs-doctag">TODO:</span> WIP, TBD</span>\r\n }\r\n}\r\n</code></pre>\r\n<p>控制器非常简洁:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">ProductController</span> <span class="hljs-keyword">extends</span> \\<span class="hljs-title">yii</span>\\<span class="hljs-title">web</span>\\<span class="hljs-title">Controller</span>\r\n</span>{\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">actionCreate</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-comment">// <span class="hljs-doctag">FIXME:</span> <span class="hljs-doctag">TODO:</span> WIP, TBD</span>\r\n }\r\n}\r\n</code></pre>\r\n<h2>乐观锁(Optimistic Locks)</h2>\r\n<p>TODO</p>\r\n<h2>被污染属性</h2>\r\n<p>当你调用yii\\db\\ActiveRecord::save()用于保存活动记录(Active Record)实例时,只有被污染的属性才会被保存。一个属性是否认定为被污染取决于它的值自从最后一次从数据库加载或者最近一次保存到数据库后到现在是否被修改过。注意:无论活动记录(Active Record)是否有被污染属性,数据验证始终会执行。</p>\r\n<p>活动记录(Active Record)会自动维护一个污染数据列表。它的工作方式是通过维护一个较旧属性值版本,并且将它们与最新的进行比较。你可以通过调用yii\\db\\ActiveRecord::getDirtyAttributes()来获取当前的污染属性。你也可以调用yii\\db\\ActiveRecord::markAttributeDirty()来显示的标记一个属性为污染属性。</p>\r\n<p>如果你对最近一次修改前的属性值感兴趣,你可以调用yii\\db\\ActiveRecord::getOldAttributes() 或 yii\\db\\ActiveRecord::getOldAttribute()。</p>\r\n<h2>另见</h2>\r\n<ul><li><a href="/doc/guide/2.0/model">模型(Model)</a></li>\r\n<li>yii\\db\\ActiveRecord</li>\r\n</ul> </div>', 'Yii2,ActiveRecord', 2, 1443000262, 1443000294, 1),
(36, 'DetailView', '<div id="content">\r\n\r\n<p>yii\\widgets\\DetailView 小部件显示的是单一 yii\\widgets\\DetailView::$model 数据的详情。</p>\r\n<p>它非常适合用常规格式显示一个模型(例如在一个表格的一行中显示模型的每个属性)。\r\n这里说的模型可以是 \\yii\\base\\Model 或者其子类的一个实例,例如子类 <a href="/doc/guide/2.0/db-active-record">active record</a>,也可以是一个关联数组。</p>\r\n<p>DetailView使用 yii\\widgets\\DetailView::$attributes 属性来决定显示模型哪些属性以及如何格式化。\r\n可用的格式化选项,见 <a href="/doc/guide/2.0/output-formatting">formatter section</a> 章节。</p>\r\n<p>一个典型的DetailView的使用方法如下:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">echo</span> DetailView::widget([\r\n <span class="hljs-string">''model''</span> => <span class="hljs-variable">$model</span>,\r\n <span class="hljs-string">''attributes''</span> => [\r\n <span class="hljs-string">''title''</span>, <span class="hljs-comment">// title attribute (in plain text)</span>\r\n <span class="hljs-string">''description:html''</span>, <span class="hljs-comment">// description attribute formatted as HTML</span>\r\n [ <span class="hljs-comment">// the owner name of the model</span>\r\n <span class="hljs-string">''label''</span> => <span class="hljs-string">''Owner''</span>,\r\n <span class="hljs-string">''value''</span> => <span class="hljs-variable">$model</span>->owner->name,\r\n ],\r\n <span class="hljs-string">''created_at:datetime''</span>, <span class="hljs-comment">// creation date formatted as datetime</span>\r\n ],\r\n]);\r\n</code></pre>\r\n </div>', 'Yii2,DetailView', 2, 1443001778, 1443001892, 1),
(37, 'ListView', '\r\n<p>yii\\widgets\\ListView 小部件用于显示数据提供者 <a href="/doc/guide/2.0/output-data-providers">data provider</a> 提供的数据。\r\n每个数据模型用指定的视图文件 yii\\widgets\\ListView::$itemView 来渲染。\r\n因为它提供开箱即用式的(译者注:封装好的)分页、排序以及过滤这样一些特性,所以它可以很方便地为最终用户显示信息并同时创建数据管理界面。</p>\r\n<p>一个典型的用法如下例所示:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">widgets</span>\\<span class="hljs-title">ListView</span>;\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">data</span>\\<span class="hljs-title">ActiveDataProvider</span>;\r\n\r\n<span class="hljs-variable">$dataProvider</span> = <span class="hljs-keyword">new</span> ActiveDataProvider([\r\n <span class="hljs-string">''query''</span> => Post::find(),\r\n <span class="hljs-string">''pagination''</span> => [\r\n <span class="hljs-string">''pageSize''</span> => <span class="hljs-number">20</span>,\r\n ],\r\n]);\r\n<span class="hljs-keyword">echo</span> ListView::widget([\r\n <span class="hljs-string">''dataProvider''</span> => <span class="hljs-variable">$dataProvider</span>,\r\n <span class="hljs-string">''itemView''</span> => <span class="hljs-string">''_post''</span>,\r\n]);\r\n</code></pre>\r\n<p><code>_post</code> 视图文件可包含如下代码:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-preprocessor"><?php</span>\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">helpers</span>\\<span class="hljs-title">Html</span>;\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">helpers</span>\\<span class="hljs-title">HtmlPurifier</span>;\r\n<span class="hljs-preprocessor">?></span>\r\n<div <span class="hljs-class"><span class="hljs-keyword">class</span>="<span class="hljs-title">post</span>">\r\n <<span class="hljs-title">h2</span>><?= <span class="hljs-title">Html</span>::<span class="hljs-title">encode</span>($<span class="hljs-title">model</span>-><span class="hljs-title">title</span>) ?></<span class="hljs-title">h2</span>>\r\n \r\n <?= <span class="hljs-title">HtmlPurifier</span>::<span class="hljs-title">process</span>($<span class="hljs-title">model</span>-><span class="hljs-title">text</span>) ?> \r\n</<span class="hljs-title">div</span>>\r\n</span></code></pre>\r\n<p>在上面的视图文件中,当前的数据模型 <code>$model</code> 是可用的。另外,下面的这些变量也是可用的:</p>\r\n<ul><li><code>$key</code>:混合类型,键的值与数据项相关联。</li>\r\n<li><code>$index</code>:整型,是由数据提供者返回的数组中以0起始的数据项的索引。</li>\r\n<li><code>$widget</code>:类型是ListView,是小部件的实例。</li>\r\n</ul><p>假如你需要传递附加数据到每一个视图中,你可以像下面这样用 yii\\widgets\\ListView::$viewParams 属性传递键值对:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">echo</span> ListView::widget([\r\n <span class="hljs-string">''dataProvider''</span> => <span class="hljs-variable">$dataProvider</span>,\r\n <span class="hljs-string">''itemView''</span> => <span class="hljs-string">''_post''</span>,\r\n <span class="hljs-string">''viewParams''</span> => [\r\n <span class="hljs-string">''fullView''</span> => <span class="hljs-keyword">true</span>,\r\n <span class="hljs-string">''context''</span> => <span class="hljs-string">''main-page''</span>,\r\n <span class="hljs-comment">// ...</span>\r\n ],\r\n]);\r\n</code></pre>\r\n<p>在视图中,上述这些附加数据也是可以作为变量来使用的。</p>\r\n', 'Yii2,ListView', 2, 1443001837, 1443001878, 1);
INSERT INTO `tbl_post` (`id`, `title`, `content`, `tags`, `status`, `create_time`, `update_time`, `author_id`) VALUES
(38, 'GridView', '\r\n<p>数据网格或者说 GridView 小部件是Yii中最强大的部件之一。如果你需要快速建立系统的管理后台,\r\nGridView 非常有用。它从数据提供者 <a href="/doc/guide/2.0/output-data-providers">data provider</a> 中取得数据并使用 yii\\grid\\GridView::columns 属性的一组列配置,在一个表格中渲染每一行数据。</p>\r\n<p>表中的每一行代表一个数据项的数据,并且一列通常表示该项的属性(某些列可以对应于属性或静态文本的复杂表达式)。</p>\r\n<p>使用GridView的最少代码如下:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">grid</span>\\<span class="hljs-title">GridView</span>;\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">data</span>\\<span class="hljs-title">ActiveDataProvider</span>;\r\n\r\n<span class="hljs-variable">$dataProvider</span> = <span class="hljs-keyword">new</span> ActiveDataProvider([\r\n <span class="hljs-string">''query''</span> => Post::find(),\r\n <span class="hljs-string">''pagination''</span> => [\r\n <span class="hljs-string">''pageSize''</span> => <span class="hljs-number">20</span>,\r\n ],\r\n]);\r\n<span class="hljs-keyword">echo</span> GridView::widget([\r\n <span class="hljs-string">''dataProvider''</span> => <span class="hljs-variable">$dataProvider</span>,\r\n]);\r\n</code></pre>\r\n<p>上面的代码首先创建了一个数据提供者,然后使用GridView显示每一行的每个属性,每一行的数据是从数据提供者取来的。\r\n展现出来的表格封装了排序以及分页功能。</p>\r\n<h3>表格列</h3>\r\n<p>表格的列是通过 yii\\grid\\Column 类来配置的,这个类是通过 GridView 配置项中的 yii\\grid\\GridView::columns \r\n属性配置的。根据列的类别和设置的不同,各列能够以不同方式展示数据。\r\n默认的列类是 yii\\grid\\DataColumn,用于展现模型的某个属性,\r\n并且可以排序和过滤。</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">echo</span> GridView::widget([\r\n <span class="hljs-string">''dataProvider''</span> => <span class="hljs-variable">$dataProvider</span>,\r\n <span class="hljs-string">''columns''</span> => [\r\n [<span class="hljs-string">''class''</span> => <span class="hljs-string">''yii\\grid\\SerialColumn''</span>],\r\n <span class="hljs-comment">// 数据提供者中所含数据所定义的简单的列</span>\r\n <span class="hljs-comment">// 使用的是模型的列的数据</span>\r\n <span class="hljs-string">''id''</span>,\r\n <span class="hljs-string">''username''</span>,\r\n <span class="hljs-comment">// 更复杂的列数据</span>\r\n [\r\n <span class="hljs-string">''class''</span> => <span class="hljs-string">''yii\\grid\\DataColumn''</span>, <span class="hljs-comment">//由于是默认类型,可以省略 </span>\r\n <span class="hljs-string">''value''</span> => <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(<span class="hljs-variable">$data</span>)</span> </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$data</span>->name; <span class="hljs-comment">// 如果是数组数据则为 $data[''name''] ,例如,使用 SqlDataProvider 的情形。</span>\r\n },\r\n ],\r\n ],\r\n]);\r\n</code></pre>\r\n<p>请注意,假如配置中没有指定 yii\\grid\\GridView::columns 属性,那么Yii会试图显示数据提供者的模型中所有可能的列。</p>\r\n<h3>列类</h3>\r\n<p>通过使用不同类,网格列可以自定义:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">echo</span> GridView::widget([\r\n <span class="hljs-string">''dataProvider''</span> => <span class="hljs-variable">$dataProvider</span>,\r\n <span class="hljs-string">''columns''</span> => [\r\n [\r\n <span class="hljs-string">''class''</span> => <span class="hljs-string">''yii\\grid\\SerialColumn''</span>, <span class="hljs-comment">// <-- 这里</span>\r\n <span class="hljs-comment">// 你还可以在此配置其他属性</span>\r\n ],\r\n</code></pre>\r\n<p>除了我们下面将要展开讨论的Yii自带的列类,你还可以创建你自己的列类。</p>\r\n<p>每个列类是从 yii\\grid\\Column 扩展而来,\r\n从而在配置网格列的时候,你可以设置一些公共的选项。</p>\r\n<ul><li>yii\\grid\\Column::header 允许为头部行设置内容。</li>\r\n<li>yii\\grid\\Column::footer 允许为尾部行设置内容。</li>\r\n<li>yii\\grid\\Column::visible 定义某个列是否可见</li>\r\n<li><p>yii\\grid\\Column::content 允许你传递一个有效的PHP回调来为一行返回数据,格式如下:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(<span class="hljs-variable">$model</span>, <span class="hljs-variable">$key</span>, <span class="hljs-variable">$index</span>, <span class="hljs-variable">$column</span>)</span> </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-string">''a string''</span>;\r\n}\r\n</code></pre>\r\n</li>\r\n</ul><p>你可以传递数组来指定各种容器式的HTML选项:</p>\r\n<ul><li>yii\\grid\\Column::headerOptions</li>\r\n<li>yii\\grid\\Column::footerOptions</li>\r\n<li>yii\\grid\\Column::filterOptions</li>\r\n<li>yii\\grid\\Column::contentOptions</li>\r\n</ul><h4>数据列 <span></span></h4>\r\n<p>yii\\grid\\DataColumn 用于显示和排序数据。这是默认的列的类型,\r\n所以在使用 DataColumn 为列类时,可省略类的指定(译者注:不需要''class''选项的意思)。</p>\r\n<p>数据列的主要配置项是 yii\\grid\\DataColumn::format 属性。它的值对应于 <code>formatter</code> <a href="/doc/guide/2.0/structure-application-components">application component</a> 应用组件里面的一些方法,\r\n默认是使用 \\yii\\i18n\\Formatter 应用组件:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">echo</span> GridView::widget([\r\n <span class="hljs-string">''columns''</span> => [\r\n [\r\n <span class="hljs-string">''attribute''</span> => <span class="hljs-string">''name''</span>,\r\n <span class="hljs-string">''format''</span> => <span class="hljs-string">''text''</span>\r\n ],\r\n [\r\n <span class="hljs-string">''attribute''</span> => <span class="hljs-string">''birthday''</span>,\r\n <span class="hljs-string">''format''</span> => [<span class="hljs-string">''date''</span>, <span class="hljs-string">''php:Y-m-d''</span>]\r\n ],\r\n ],\r\n]); \r\n</code></pre>\r\n<p>在上面的代码中,<code>text</code> 对应于 \\yii\\i18n\\Formatter::asText()。列的值作为第一个参数传递。在第二列的定义中,<code>date</code> 对应于 \\yii\\i18n\\Formatter::asDate()。\r\n同样地,列值也是通过第一个参数传递的,而 ''php:Y-m-d'' 用作第二个参数的值。</p>\r\n<p>可用的格式化方法列表,请参照 <a href="/doc/guide/2.0/output-formatting">section about Data Formatting</a>。</p>\r\n<p>数据列配置,还有一个”快捷格式化串”的方法,详情见API文档 yii\\grid\\GridView::columns。\r\n(译者注:举例说明, <code>"name:text:Name"</code> 快捷格式化串,表示列名为 <code>name</code> 格式为 <code>text</code> 显示标签是 <code>Name</code>) </p>\r\n<h4>动作列</h4>\r\n<p>yii\\grid\\ActionColumn 用于显示一些动作按钮,如每一行的更新、删除操作。</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">echo</span> GridView::widget([\r\n <span class="hljs-string">''dataProvider''</span> => <span class="hljs-variable">$dataProvider</span>,\r\n <span class="hljs-string">''columns''</span> => [\r\n [\r\n <span class="hljs-string">''class''</span> => <span class="hljs-string">''yii\\grid\\ActionColumn''</span>,\r\n <span class="hljs-comment">// you may configure additional properties here</span>\r\n ],\r\n</code></pre>\r\n<p>可配置的属性如下:</p>\r\n<ul><li>yii\\grid\\ActionColumn::controller 是应该执行这些动作的控制器ID。\r\n如果没有设置,它将使用当前控制器。</li>\r\n<li>yii\\grid\\ActionColumn::template 定义在动作列中使用的构建每个单元格的模板。\r\n在大括号内括起来的的令牌被当做是控制器的 action 方法ID (在动作列的上下文中也称作<em>按钮名称</em>)。\r\n它们将会被 yii\\grid\\ActionColumn::$buttons 中指定的对应按钮的关联的渲染回调函数替代。\r\n例如,令牌 <code>{view}</code> 将被 <code>buttons[''view'']</code> 关联的渲染回调函数的返回结果所替换。\r\n如果没有找到回调函数,令牌将被替换成一个空串。默认的令牌有 <code>{view} {update} {delete}</code> 。</li>\r\n<li><p>yii\\grid\\ActionColumn::buttons 是一个按钮的渲染回调数数组。数组中的键是按钮的名字(没有花括号),并且值是对应的按钮渲染回调函数。\r\n这些回调函数须使用下面这种原型:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(<span class="hljs-variable">$url</span>, <span class="hljs-variable">$model</span>, <span class="hljs-variable">$key</span>)</span> </span>{\r\n <span class="hljs-comment">// return the button HTML code</span>\r\n}\r\n</code></pre>\r\n<p>在上面的代码中,<code>$url</code> 是列为按钮创建的URL,<code>$model</code>是当前要渲染的模型对象,并且 <code>$key</code> 是在数据提供者数组中模型的键。</p>\r\n</li>\r\n</ul><ul><li>yii\\grid\\ActionColumn::urlCreator 是使用指定的模型信息来创建一个按钮URL的回调函数。\r\n该回调的原型和 yii\\grid\\ActionColumn::createUrl() 是一样的。\r\n假如这个属性没有设置,按钮的URL将使用 yii\\grid\\ActionColumn::createUrl() 来创建。</li>\r\n</ul><h4>复选框列</h4>\r\n<p>yii\\grid\\CheckboxColumn 显示一个复选框列。</p>\r\n<p>想要添加一个复选框到网格视图中,将它添加到 yii\\grid\\GridView::$columns 的配置中,如下所示:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">echo</span> GridView::widget([\r\n <span class="hljs-string">''dataProvider''</span> => <span class="hljs-variable">$dataProvider</span>,\r\n <span class="hljs-string">''columns''</span> => [\r\n <span class="hljs-comment">// ...</span>\r\n [\r\n <span class="hljs-string">''class''</span> => <span class="hljs-string">''yii\\grid\\CheckboxColumn''</span>,\r\n <span class="hljs-comment">// 你可以在这配置更多的属性</span>\r\n ],\r\n ],\r\n</code></pre>\r\n<p>用户可点击复选框来选择网格中的一些行。被选择的行可通过调用下面的JavaScript代码来获得:</p>\r\n<pre><code class="language-javascript hljs"><span class="hljs-keyword">var</span> keys = $(<span class="hljs-string">''#grid''</span>).yiiGridView(<span class="hljs-string">''getSelectedRows''</span>);\r\n<span class="hljs-comment">// keys 为一个由与被选行相关联的键组成的数组</span>\r\n</code></pre>\r\n<h4>序号列</h4>\r\n<p>yii\\grid\\SerialColumn 渲染行号,以 <code>1</code> 起始并自动增长。</p>\r\n<p>使用方法和下面的例子一样简单:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">echo</span> GridView::widget([\r\n <span class="hljs-string">''dataProvider''</span> => <span class="hljs-variable">$dataProvider</span>,\r\n <span class="hljs-string">''columns''</span> => [\r\n [<span class="hljs-string">''class''</span> => <span class="hljs-string">''yii\\grid\\SerialColumn''</span>], <span class="hljs-comment">// <-- here</span>\r\n <span class="hljs-comment">// ...</span>\r\n</code></pre>\r\n<h3>数据排序</h3>\r\n<blockquote><p>注意:这部分正在开发中。</p>\r\n<ul><li><a href="https://github.com/yiisoft/yii2/issues/1576">https://github.com/yiisoft/yii2/issues/1576</a></li>\r\n</ul></blockquote>\r\n<h3>数据过滤</h3>\r\n<p>为了过滤数据的 GridView 需要一个模型 <a href="/doc/guide/2.0/structure-models">model</a> 来 从过滤表单接收数据,以及调整数据提供者的查询对象,以满足搜索条件。\r\n使用活动记录 <a href="/doc/guide/2.0/db-active-record">active records</a> 时,通常的做法是\r\n创建一个能够提供所需功能的搜索模型类(可以使用 <a href="/doc/guide/2.0/start-gii">Gii</a> 来生成)。\r\n这个类为搜索定义了验证规则并且提供了一个将会返回数据提供者对象的 <code>search()</code> 方法。</p>\r\n<p>为了给 <code>Post</code> 模型增加搜索能力,我们可以像下面的例子一样创建 <code>PostSearch</code> 模型:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-preprocessor"><?php</span>\r\n\r\n<span class="hljs-keyword">namespace</span> <span class="hljs-title">app</span>\\<span class="hljs-title">models</span>;\r\n\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">Yii</span>;\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">base</span>\\<span class="hljs-title">Model</span>;\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">data</span>\\<span class="hljs-title">ActiveDataProvider</span>;\r\n\r\n<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">PostSearch</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">Post</span>\r\n</span>{\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">rules</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-comment">// 只有在 rules() 函数中声明的字段才可以搜索</span>\r\n <span class="hljs-keyword">return</span> [\r\n [[<span class="hljs-string">''id''</span>], <span class="hljs-string">''integer''</span>],\r\n [[<span class="hljs-string">''title''</span>, <span class="hljs-string">''creation_date''</span>], <span class="hljs-string">''safe''</span>],\r\n ];\r\n }\r\n\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">scenarios</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-comment">// 旁路在父类中实现的 scenarios() 函数</span>\r\n <span class="hljs-keyword">return</span> Model::scenarios();\r\n }\r\n\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">search</span><span class="hljs-params">(<span class="hljs-variable">$params</span>)</span>\r\n </span>{\r\n <span class="hljs-variable">$query</span> = Post::find();\r\n\r\n <span class="hljs-variable">$dataProvider</span> = <span class="hljs-keyword">new</span> ActiveDataProvider([\r\n <span class="hljs-string">''query''</span> => <span class="hljs-variable">$query</span>,\r\n ]);\r\n\r\n <span class="hljs-comment">// 从参数的数据中加载过滤条件,并验证</span>\r\n <span class="hljs-keyword">if</span> (!(<span class="hljs-variable">$this</span>->load(<span class="hljs-variable">$params</span>) && <span class="hljs-variable">$this</span>->validate())) {\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$dataProvider</span>;\r\n }\r\n\r\n <span class="hljs-comment">// 增加过滤条件来调整查询对象</span>\r\n <span class="hljs-variable">$query</span>->andFilterWhere([<span class="hljs-string">''id''</span> => <span class="hljs-variable">$this</span>->id]);\r\n <span class="hljs-variable">$query</span>->andFilterWhere([<span class="hljs-string">''like''</span>, <span class="hljs-string">''title''</span>, <span class="hljs-variable">$this</span>->title])\r\n ->andFilterWhere([<span class="hljs-string">''like''</span>, <span class="hljs-string">''creation_date''</span>, <span class="hljs-variable">$this</span>->creation_date]);\r\n\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$dataProvider</span>;\r\n }\r\n}\r\n\r\n</code></pre>\r\n<p>你可以在控制器中使用如下方法为网格视图获取数据提供者:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$searchModel</span> = <span class="hljs-keyword">new</span> PostSearch();\r\n<span class="hljs-variable">$dataProvider</span> = <span class="hljs-variable">$searchModel</span>->search(Yii::<span class="hljs-variable">$app</span>->request->get());\r\n\r\n<span class="hljs-keyword">return</span> <span class="hljs-variable">$this</span>->render(<span class="hljs-string">''myview''</span>, [\r\n <span class="hljs-string">''dataProvider''</span> => <span class="hljs-variable">$dataProvider</span>,\r\n <span class="hljs-string">''searchModel''</span> => <span class="hljs-variable">$searchModel</span>,\r\n]);\r\n</code></pre>\r\n<p>然后你在视图中将 <code>$dataProvider</code> 和 <code>$searchModel</code> 对象分派给 GridView 小部件:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">echo</span> GridView::widget([\r\n <span class="hljs-string">''dataProvider''</span> => <span class="hljs-variable">$dataProvider</span>,\r\n <span class="hljs-string">''filterModel''</span> => <span class="hljs-variable">$searchModel</span>,\r\n <span class="hljs-string">''columns''</span> => [\r\n <span class="hljs-comment">// ...</span>\r\n ],\r\n]);\r\n</code></pre>\r\n<h3>处理关系型模型</h3>\r\n<p>当我们在一个网格视图中显示活动数据的时候,你可能会遇到这种情况,就是显示关联表的列的值,例如:发帖者的名字,而不是显示他的 <code>id</code>。\r\n当 <code>Post</code> 模型有一个关联的属性名(译者注: <code>Post</code> 模型中用 <code>hasOne</code> 定义 <code>getAuthor()</code> 函数)\r\n叫 <code>author</code> 并且作者模型(译者注:本例的作者模型是 <code>users</code> )有一个属性叫 <code>name</code>,那么你可以通过在 yii\\grid\\GridView::$columns \r\n中定义属性名为 <code>author.name</code> 来处理。这时的网格视图能显示作者名了,但是默认是不支持按作者名排序和过滤的。\r\n你需要调整上个章节介绍的 <code>PostSearch</code> 模型,以添加此功能。</p>\r\n<p>为了使关联列能够排序,你需要连接关系表,以及添加排序规则到数据提供者的排序组件中:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span> = Post::find();\r\n<span class="hljs-variable">$dataProvider</span> = <span class="hljs-keyword">new</span> ActiveDataProvider([\r\n <span class="hljs-string">''query''</span> => <span class="hljs-variable">$query</span>,\r\n]);\r\n\r\n<span class="hljs-comment">// 连接与 `users` 表相关联的 `author` 表</span>\r\n<span class="hljs-comment">// 并将 `users` 表的别名设为 `author`</span>\r\n<span class="hljs-variable">$query</span>->joinWith([<span class="hljs-string">''author''</span> => <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(<span class="hljs-variable">$query</span>)</span> </span>{ <span class="hljs-variable">$query</span>->from([<span class="hljs-string">''author''</span> => <span class="hljs-string">''users''</span>]); }]);\r\n<span class="hljs-comment">// 使得关联字段可以排序</span>\r\n<span class="hljs-variable">$dataProvider</span>->sort->attributes[<span class="hljs-string">''author.name''</span>] = [\r\n <span class="hljs-string">''asc''</span> => [<span class="hljs-string">''author.name''</span> => SORT_ASC],\r\n <span class="hljs-string">''desc''</span> => [<span class="hljs-string">''author.name''</span> => SORT_DESC],\r\n];\r\n\r\n<span class="hljs-comment">// ...</span>\r\n</code></pre>\r\n<p>过滤也需要像上面一样调用joinWith方法。你也需要在属性和规则中定义该列,就像下面这样:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">attributes</span><span class="hljs-params">()</span>\r\n</span>{\r\n <span class="hljs-comment">// 添加关联字段到可搜索属性集合</span>\r\n <span class="hljs-keyword">return</span> array_merge(<span class="hljs-keyword">parent</span>::attributes(), [<span class="hljs-string">''author.name''</span>]);\r\n}\r\n\r\n<span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">rules</span><span class="hljs-params">()</span>\r\n</span>{\r\n <span class="hljs-keyword">return</span> [\r\n [[<span class="hljs-string">''id''</span>], <span class="hljs-string">''integer''</span>],\r\n [[<span class="hljs-string">''title''</span>, <span class="hljs-string">''creation_date''</span>, <span class="hljs-string">''author.name''</span>], <span class="hljs-string">''safe''</span>],\r\n ];\r\n}\r\n</code></pre>\r\n<p>然后在 <code>search()</code> 方法中,你仅需要添加一个额外过滤条件:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span>->andFilterWhere([<span class="hljs-string">''LIKE''</span>, <span class="hljs-string">''author.name''</span>, <span class="hljs-variable">$this</span>->getAttribute(<span class="hljs-string">''author.name''</span>)]);\r\n</code></pre>\r\n<blockquote><p>信息:在上面的代码中,我们使用相同的字符串作为关联名称和表别名;\r\n然而,当你的表别名和关联名称不相同的时候,你得注意在哪使用你的别名,在哪使用你的关联名称。\r\n一个简单的规则是在每个构建数据库查询的地方使用别名,而在所有其他和定义相关的诸如:<code>attributes()</code> 和 <code>rules()</code> 等地方使用关联名称。</p>\r\n<p>例如,你使用 <code>au</code> 作为作者关系表的别名,那么联查语句就要写成像下面这样:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span>->joinWith([<span class="hljs-string">''author''</span> => <span class="hljs-function"><span class="hljs-keyword">function</span><span class="hljs-params">(<span class="hljs-variable">$query</span>)</span> </span>{ <span class="hljs-variable">$query</span>->from([<span class="hljs-string">''au''</span> => <span class="hljs-string">''users''</span>]); }]);\r\n</code></pre>\r\n<p>当别名已经在关联函数中定义了时,也可以只调用 <code>$query->joinWith([''author'']);</code>。</p>\r\n<p>在过滤条件中,别名必须使用,但属性名称保持不变:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span>->andFilterWhere([<span class="hljs-string">''LIKE''</span>, <span class="hljs-string">''au.name''</span>, <span class="hljs-variable">$this</span>->getAttribute(<span class="hljs-string">''author.name''</span>)]);\r\n</code></pre>\r\n<p>排序定义也同样如此:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$dataProvider</span>->sort->attributes[<span class="hljs-string">''author.name''</span>] = [\r\n <span class="hljs-string">''asc''</span> => [<span class="hljs-string">''au.name''</span> => SORT_ASC],\r\n <span class="hljs-string">''desc''</span> => [<span class="hljs-string">''au.name''</span> => SORT_DESC],\r\n];\r\n</code></pre>\r\n<p>同样,当指定使用 yii\\data\\Sort::defaultOrder 来排序的时候,你需要使用关联名称替代别名:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$dataProvider</span>->sort->defaultOrder = [<span class="hljs-string">''author.name''</span> => SORT_ASC];\r\n</code></pre>\r\n</blockquote>\r\n<blockquote><p>信息:更多关于 <code>joinWith</code> 和在后台执行查询的相关信息,\r\n可以查看 <a href="/doc/guide/2.0/db-active-record#joining-with-relations">active record docs on joining with relations</a>。</p>\r\n</blockquote>\r\n<h4>SQL视图用于过滤、排序和显示数据</h4>\r\n<p>还有另外一种方法可以更快、更有用 - SQL 视图。例如,我们要在 <code>GridView</code> \r\n中显示用户和他们的简介,可以这样创建 SQL 视图:</p>\r\n<pre><code class="language-sql hljs"><span class="hljs-operator"><span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">OR</span> <span class="hljs-keyword">REPLACE</span> <span class="hljs-keyword">VIEW</span> vw_user_info <span class="hljs-keyword">AS</span>\r\n SELECT <span class="hljs-keyword">user</span>.*, user_profile.lastname, user_profile.firstname\r\n <span class="hljs-keyword">FROM</span> <span class="hljs-keyword">user</span>, user_profile\r\n <span class="hljs-keyword">WHERE</span> <span class="hljs-keyword">user</span>.<span class="hljs-keyword">id</span> = user_profile.user_id\r\n</span></code></pre>\r\n<p>然后你需要创建活动记录模型来代表这个视图:</p>\r\n<pre><code class="language-php hljs">\r\n<span class="hljs-keyword">namespace</span> <span class="hljs-title">app</span>\\<span class="hljs-title">models</span>\\<span class="hljs-title">views</span>\\<span class="hljs-title">grid</span>;\r\n\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">db</span>\\<span class="hljs-title">ActiveRecord</span>;\r\n\r\n<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserView</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveRecord</span>\r\n</span>{\r\n\r\n <span class="hljs-comment">/**\r\n * <span class="hljs-doctag">@inheritdoc</span>\r\n */</span>\r\n <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">tableName</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-string">''vw_user_info''</span>;\r\n }\r\n\r\n <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">primaryKey</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> [<span class="hljs-string">''id''</span>];\r\n }\r\n\r\n <span class="hljs-comment">/**\r\n * <span class="hljs-doctag">@inheritdoc</span>\r\n */</span>\r\n <span class="hljs-keyword">public</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">rules</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> [\r\n <span class="hljs-comment">// 在这定义你的规则</span>\r\n ];\r\n }\r\n\r\n <span class="hljs-comment">/**\r\n * <span class="hljs-doctag">@inheritdoc</span>\r\n */</span>\r\n <span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-title">attributeLabels</span><span class="hljs-params">()</span>\r\n </span>{\r\n <span class="hljs-keyword">return</span> [\r\n <span class="hljs-comment">// 在这定义你的属性标签</span>\r\n ];\r\n }\r\n\r\n\r\n}\r\n</code></pre>\r\n<p>之后你可以使用这个 UserView 活动记录和搜索模型,无需附加的排序和过滤属性的规则。\r\n所有属性都可开箱即用。请注意,这种方法有利有弊:</p>\r\n<ul><li>你不需要指定不同排序和过滤条件,一切都包装好了;</li>\r\n<li>它可以更快,因为数据的大小,SQL查询的执行(对于每个关联数据你都不需要额外的查询)都得到优化;</li>\r\n<li>因为在SQL视图中这仅仅是一个简单的映射UI,所以在你的实体中,它可能缺乏某方面的逻辑,所以,假如你有一些诸如 <code>isActive</code>、<code>isDeleted</code> 或者其他影响到UI的方法,\r\n你也需要在这个类中复制他们。</li>\r\n</ul><h3>单个页面多个网格视图部件</h3>\r\n<p>你可以在一个单独页面中使用多个网格视图,但是一些额外的配置是必须的,为的就是它们相互之间不干扰。\r\n当使用多个网格视图实例的时候,你必须要为生成的排序和分页对象配置不同的参数名,以便于每个网格视图有它们各自独立的排序和分页。\r\n你可以通过设置 yii\\data\\Sort::sortParam 和 yii\\data\\Pagination::pageParam,对应于数据提供者的\r\nyii\\data\\BaseDataProvider::$sort 和 yii\\data\\BaseDataProvider::$pagination 实例。</p>\r\n<p>假如我们想要同时显示 <code>Post</code> 和 <code>User</code> 模型,这两个模型已经在 <code>$userProvider</code> 和 <code>$postProvider</code> 这两个数据提供者中准备好,\r\n具体做法如下:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">grid</span>\\<span class="hljs-title">GridView</span>;\r\n\r\n<span class="hljs-variable">$userProvider</span>->pagination->pageParam = <span class="hljs-string">''user-page''</span>;\r\n<span class="hljs-variable">$userProvider</span>->sort->sortParam = <span class="hljs-string">''user-sort''</span>;\r\n\r\n<span class="hljs-variable">$postProvider</span>->pagination->pageParam = <span class="hljs-string">''post-page''</span>;\r\n<span class="hljs-variable">$postProvider</span>->sort->sortParam = <span class="hljs-string">''post-sort''</span>;\r\n\r\n<span class="hljs-keyword">echo</span> <span class="hljs-string">''<h1>Users</h1>''</span>;\r\n<span class="hljs-keyword">echo</span> GridView::widget([\r\n <span class="hljs-string">''dataProvider''</span> => <span class="hljs-variable">$userProvider</span>,\r\n]);\r\n\r\n<span class="hljs-keyword">echo</span> <span class="hljs-string">''<h1>Posts</h1>''</span>;\r\n<span class="hljs-keyword">echo</span> GridView::widget([\r\n <span class="hljs-string">''dataProvider''</span> => <span class="hljs-variable">$postProvider</span>,\r\n]);\r\n</code></pre>\r\n<h3>Using GridView with Pjax</h3>\r\n<blockquote><p>注意: 这部分正在开发中。</p>\r\n</blockquote>\r\n<p>待定</p>', 'Yii2,GridView', 2, 1443001924, 1443001924, 1);
INSERT INTO `tbl_post` (`id`, `title`, `content`, `tags`, `status`, `create_time`, `update_time`, `author_id`) VALUES
(39, '查询构建器', '<div id="content">\r\n\r\n<p>查询构建器建立在 <a href="/doc/guide/2.0/db-dao">Database Access Objects</a> 基础之上,可让你创建\r\n程序化的、DBMS无关的SQL语句。相比于原生的SQL语句,查询构建器可以帮你\r\n写出可读性更强的SQL相关的代码,并生成安全性更强的SQL语句。</p>\r\n<p>使用查询构建器通常包含以下两个步骤:</p>\r\n<ol><li>创建一个 yii\\db\\Query 对象来代表一条 SELECT SQL 语句的不同子句(例如 <code>SELECT</code>, <code>FROM</code>)。</li>\r\n<li>执行 yii\\db\\Query 的一个查询方法(例如:<code>all()</code>)从数据库当中检索数据。</li>\r\n</ol><p>如下所示代码是查询构造器的一个典型用法:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$rows</span> = (<span class="hljs-keyword">new</span> \\yii\\db\\Query())\r\n ->select([<span class="hljs-string">''id''</span>, <span class="hljs-string">''email''</span>])\r\n ->from(<span class="hljs-string">''user''</span>)\r\n ->where([<span class="hljs-string">''last_name''</span> => <span class="hljs-string">''Smith''</span>])\r\n ->limit(<span class="hljs-number">10</span>)\r\n ->all();\r\n</code></pre>\r\n<p>上面的代码将会生成并执行如下的SQL语句,其中 <code>:last_name</code> 参数绑定了\r\n字符串 <code>''Smith''</code>。</p>\r\n<pre><code class="language-sql hljs"><span class="hljs-operator">SELECT <span class="hljs-string">`id`</span>, <span class="hljs-string">`email`</span> \r\n<span class="hljs-keyword">FROM</span> <span class="hljs-string">`user`</span>\r\n<span class="hljs-keyword">WHERE</span> <span class="hljs-string">`last_name`</span> = :last_name\r\n<span class="hljs-keyword">LIMIT</span> <span class="hljs-number">10</span>\r\n</span></code></pre>\r\n<blockquote><p>提示: 你平时更多的时候会使用 yii\\db\\Query 而不是 [yii\\db\\QueryBuilder]]。\r\n 当你调用其中一个查询方法时,后者将会被前者隐式的调用。yii\\db\\QueryBuilder主要负责将\r\n DBMS 不相关的 yii\\db\\Query 对象转换成 DBMS 相关的 SQL 语句(例如,\r\n 以不同的方式引用表或字段名称)。</p>\r\n</blockquote>\r\n<h2>创建查询 <span></span></h2>\r\n<p>为了创建一个 yii\\db\\Query 对象,你需要调用不同的查询构建方法来代表SQL语句的不同子句。\r\n这些方法的名称集成了在SQL语句相应子句中使用的关键字。例如,为了指定 SQL 语句当中的\r\n<code>FROM</code> 子句,你应该调用 <code>from()</code> 方法。所有的查询构建器方法返回的是查询对象本身,\r\n也就是说,你可以把多个方法的调用串联起来。</p>\r\n<p>接下来,我们会对这些查询构建器方法进行一一讲解:</p>\r\n<h3>yii\\db\\Query::select() <span></span></h3>\r\n<p>yii\\db\\Query::select() 方法用来指定 SQL 语句当中的 <code>SELECT</code> 子句。\r\n你可以像下面的例子一样使用一个数组或者字符串来定义需要查询的字段。当 SQL 语句\r\n是由查询对象生成的时候,被查询的字段名称将会自动的被引号括起来。</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span>->select([<span class="hljs-string">''id''</span>, <span class="hljs-string">''email''</span>]);\r\n\r\n<span class="hljs-comment">// 等同于:</span>\r\n\r\n<span class="hljs-variable">$query</span>->select(<span class="hljs-string">''id, email''</span>);\r\n</code></pre>\r\n<p>就像写原生 SQL 语句一样,被选取的字段可以包含表前缀,以及/或者字段别名。\r\n例如: </p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span>->select([<span class="hljs-string">''user.id AS user_id''</span>, <span class="hljs-string">''email''</span>]);\r\n\r\n<span class="hljs-comment">// 等同于:</span>\r\n\r\n<span class="hljs-variable">$query</span>->select(<span class="hljs-string">''user.id AS user_id, email''</span>);\r\n</code></pre>\r\n<p>如果使用数组格式来指定字段,你可以使用数组的键值来表示字段的别名。\r\n例如,上面的代码可以被重写为如下形式:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span>->select([<span class="hljs-string">''user_id''</span> => <span class="hljs-string">''user.id''</span>, <span class="hljs-string">''email''</span>]);\r\n</code></pre>\r\n<p>如果你在组建查询时没有调用 yii\\db\\Query::select() 方法,那么选择的将是 <code>''*''</code> ,\r\n也即选取的是所有的字段。</p>\r\n<p>除了字段名称以外,你还可以选择数据库的表达式。当你使用到包含逗号的数据库表达式的时候,\r\n你必须使用数组的格式,以避免自动的错误的引号添加。例如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span>->select([<span class="hljs-string">"CONCAT(first_name, '' '', last_name) AS full_name"</span>, <span class="hljs-string">''email''</span>]); \r\n</code></pre>\r\n<p>从 2.0.1 的版本开始你就可以使用子查询了。在定义每一个子查询的时候,\r\n你应该使用 yii\\db\\Query 对象。例如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$subQuery</span> = (<span class="hljs-keyword">new</span> Query())->select(<span class="hljs-string">''COUNT(*)''</span>)->from(<span class="hljs-string">''user''</span>);\r\n\r\n<span class="hljs-comment">// SELECT `id`, (SELECT COUNT(*) FROM `user`) AS `count` FROM `post`</span>\r\n<span class="hljs-variable">$query</span> = (<span class="hljs-keyword">new</span> Query())->select([<span class="hljs-string">''id''</span>, <span class="hljs-string">''count''</span> => <span class="hljs-variable">$subQuery</span>])->from(<span class="hljs-string">''post''</span>);\r\n</code></pre>\r\n<p>你应该调用 yii\\db\\Query::distinct() 方法来去除重复行,如下所示:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// SELECT DISTINCT `user_id` ...</span>\r\n<span class="hljs-variable">$query</span>->select(<span class="hljs-string">''user_id''</span>)->distinct();\r\n</code></pre>\r\n<p>你可以调用 yii\\db\\Query::addSelect() 方法来选取附加字段,例如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span>->select([<span class="hljs-string">''id''</span>, <span class="hljs-string">''username''</span>])\r\n ->addSelect([<span class="hljs-string">''email''</span>]);\r\n</code></pre>\r\n<h3>yii\\db\\Query::from() <span></span></h3>\r\n<p>yii\\db\\Query::from() 方法指定了 SQL 语句当中的 <code>FROM</code> 子句。例如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// SELECT * FROM `user`</span>\r\n<span class="hljs-variable">$query</span>->from(<span class="hljs-string">''user''</span>);\r\n</code></pre>\r\n<p>你可以通过字符串或者数组的形式来定义被查询的表名称。就像你写原生的 SQL 语句一样,\r\n表名称里面可包含数据库前缀,以及/或者表别名。例如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span>->from([<span class="hljs-string">''public.user u''</span>, <span class="hljs-string">''public.post p''</span>]);\r\n\r\n<span class="hljs-comment">// 等同于:</span>\r\n\r\n<span class="hljs-variable">$query</span>->from(<span class="hljs-string">''public.user u, public.post p''</span>);\r\n</code></pre>\r\n<p>如果你使用的是数组的格式,那么你同样可以用数组的键值来定义表别名,如下所示:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span>->from([<span class="hljs-string">''u''</span> => <span class="hljs-string">''public.user''</span>, <span class="hljs-string">''p''</span> => <span class="hljs-string">''public.post''</span>]);\r\n</code></pre>\r\n<p>除了表名以外,你还可以从子查询中再次查询,这里的子查询是由 yii\\db\\Query 创建的对象。\r\n例如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$subQuery</span> = (<span class="hljs-keyword">new</span> Query())->select(<span class="hljs-string">''id''</span>)->from(<span class="hljs-string">''user''</span>)->where(<span class="hljs-string">''status=1''</span>);\r\n\r\n<span class="hljs-comment">// SELECT * FROM (SELECT `id` FROM `user` WHERE status=1) u </span>\r\n<span class="hljs-variable">$query</span>->from([<span class="hljs-string">''u''</span> => <span class="hljs-variable">$subQuery</span>]);\r\n</code></pre>\r\n<h3>yii\\db\\Query::where() <span></span></h3>\r\n<p>yii\\db\\Query::where() 方法定义了 SQL 语句当中的 <code>WHERE</code> 子句。\r\n你可以使用如下三种格式来定义 <code>WHERE</code> 条件:</p>\r\n<ul><li>字符串格式,例如:<code>''status=1''</code></li>\r\n<li>哈希格式,例如: <code>[''status'' => 1, ''type'' => 2]</code></li>\r\n<li>操作符格式,例如:<code>[''like'', ''name'', ''test'']</code></li>\r\n</ul><h4>字符串格式 <span></span></h4>\r\n<p>在定义非常简单的查询条件的时候,字符串格式是最合适的。它看起来和原生 SQL 语句差不多。例如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span>->where(<span class="hljs-string">''status=1''</span>);\r\n\r\n<span class="hljs-comment">// 或者使用参数绑定来绑定动态参数值</span>\r\n<span class="hljs-variable">$query</span>->where(<span class="hljs-string">''status=:status''</span>, [<span class="hljs-string">'':status''</span> => <span class="hljs-variable">$status</span>]);\r\n</code></pre>\r\n<p>千万不要像如下的例子一样直接在条件语句当中嵌入变量,特别是当这些变量来源于终端用户输入的时候,\r\n因为这样我们的软件将很容易受到 SQL 注入的攻击。</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// 危险!千万别这样干,除非你非常的确定 $status 是一个整型数值。</span>\r\n<span class="hljs-variable">$query</span>->where(<span class="hljs-string">"status=$status"</span>);\r\n</code></pre>\r\n<p>当使用参数绑定的时候,你可以调用 yii\\db\\Query::params() 或者 yii\\db\\Query::addParams() 方法\r\n来分别绑定不同的参数。</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span>->where(<span class="hljs-string">''status=:status''</span>)\r\n ->addParams([<span class="hljs-string">'':status''</span> => <span class="hljs-variable">$status</span>]);\r\n</code></pre>\r\n<h4>哈希格式 <span></span></h4>\r\n<p>哈希格式最适合用来指定多个 <code>AND</code> 串联起来的简单的"等于断言"子条件。\r\n它是以数组的形式来书写的,数组的键表示字段的名称,而数组的值则表示\r\n这个字段需要匹配的值。例如:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// ...WHERE (`status` = 10) AND (`type` IS NULL) AND (`id` IN (4, 8, 15))</span>\r\n<span class="hljs-variable">$query</span>->where([\r\n <span class="hljs-string">''status''</span> => <span class="hljs-number">10</span>,\r\n <span class="hljs-string">''type''</span> => <span class="hljs-keyword">null</span>,\r\n <span class="hljs-string">''id''</span> => [<span class="hljs-number">4</span>, <span class="hljs-number">8</span>, <span class="hljs-number">15</span>],\r\n]);\r\n</code></pre>\r\n<p>就像你所看到的一样,查询构建器非常的智能,能恰当地处理数值当中的空值和数组。</p>\r\n<p>你也可以像下面那样在子查询当中使用哈希格式: </p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$userQuery</span> = (<span class="hljs-keyword">new</span> Query())->select(<span class="hljs-string">''id''</span>)->from(<span class="hljs-string">''user''</span>);\r\n\r\n<span class="hljs-comment">// ...WHERE `id` IN (SELECT `id` FROM `user`)</span>\r\n<span class="hljs-variable">$query</span>->where([<span class="hljs-string">''id''</span> => <span class="hljs-variable">$userQuery</span>]);\r\n</code></pre>\r\n<h4>操作符格式 <span></span></h4>\r\n<p>操作符格式允许你指定类程序风格的任意条件语句,如下所示:</p>\r\n<pre><code class="language-php hljs">[操作符, 操作数<span class="hljs-number">1</span>, 操作数<span class="hljs-number">2</span>, ...]\r\n</code></pre>\r\n<p>其中每个操作数可以是字符串格式、哈希格式或者嵌套的操作符格式,而操作符可以是如下列表中的一个:</p>\r\n<ul><li><p><code>and</code>: 操作数会被 <code>AND</code> 关键字串联起来。例如,<code>[''and'', ''id=1'', ''id=2'']</code> \r\n将会生成 <code>id=1 AND id=2</code>。如果操作数是一个数组,它也会按上述规则转换成\r\n字符串。例如,<code>[''and'', ''type=1'', [''or'', ''id=1'', ''id=2'']]</code> \r\n将会生成 <code>type=1 AND (id=1 OR id=2)</code>。\r\n这个方法不会自动加引号或者转义。</p>\r\n</li>\r\n<li><p><code>or</code>: 用法和 <code>and</code> 操作符类似,这里就不再赘述。</p>\r\n</li>\r\n<li><p><code>between</code>: 第一个操作数为字段名称,第二个和第三个操作数代表的是这个字段\r\n的取值范围。例如,<code>[''between'', ''id'', 1, 10]</code> 将会生成\r\n<code>id BETWEEN 1 AND 10</code>。</p>\r\n</li>\r\n<li><p><code>not between</code>: 用法和 <code>BETWEEN</code> 操作符类似,这里就不再赘述。</p>\r\n</li>\r\n</ul><ul><li><p><code>in</code>: 第一个操作数应为字段名称或者 DB 表达式。第二个操作符既可以是一个数组,\r\n也可以是一个 <code>Query</code> 对象。它会转换成<code>IN</code> 条件语句。如果第二个操作数是一个\r\n数组,那么它代表的是字段或 DB 表达式的取值范围。如果第二个操作数是 <code>Query</code> \r\n对象,那么这个子查询的结果集将会作为第一个操作符的字段或者 DB 表达式的取值范围。\r\n例如, <code>[''in'', ''id'', [1, 2, 3]]</code> 将生成 <code>id IN (1, 2, 3)</code>。\r\n该方法将正确地为字段名加引号以及为取值范围转义。<code>in</code> 操作符还支持组合字段,此时,\r\n操作数1应该是一个字段名数组,而操作数2应该是一个数组或者 <code>Query</code> 对象,\r\n代表这些字段的取值范围。</p>\r\n</li>\r\n<li><p><code>not in</code>: 用法和 <code>in</code> 操作符类似,这里就不再赘述。</p>\r\n</li>\r\n<li><p><code>like</code>: 第一个操作数应为一个字段名称或 DB 表达式,第二个操作数可以使字符串或数组,\r\n代表第一个操作数需要模糊查询的值。比如,<code>[''like'', ''name'', ''tester'']</code> 会生成\r\n<code>name LIKE ''%tester%''</code>。 如果范围值是一个数组,那么将会生成用 <code>AND</code> 串联起来的\r\n多个 <code>like</code> 语句。例如,<code>[''like'', ''name'', [''test'', ''sample'']]</code> 将会生成\r\n<code>name LIKE ''%test%'' AND name LIKE ''%sample%''</code>。\r\n你也可以提供第三个可选的操作数来指定应该如何转义数值当中的特殊字符。\r\n该操作数是一个从需要被转义的特殊字符到转义副本的数组映射。\r\n如果没有提供这个操作数,将会使用默认的转义映射。如果需要禁用转义的功能,\r\n只需要将参数设置为 <code>false</code> 或者传入一个空数组即可。需要注意的是,\r\n当使用转义映射(又或者没有提供第三个操作数的时候),第二个操作数的值的前后\r\n将会被加上百分号。</p>\r\n</li>\r\n</ul><p> > 注意:当使用 PostgreSQL 的时候你还可以使用 <a href="http://www.postgresql.org/docs/8.3/static/functions-matching.html#FUNCTIONS-LIKE"><code>ilike</code></a>,\r\n > 该方法对大小写不敏感。</p>\r\n<ul><li><p><code>or like</code>: 用法和 <code>like</code> 操作符类似,区别在于当第二个操作数为数组时,\r\n会使用 <code>OR</code> 来串联多个 <code>LIKE</code> 条件语句。</p>\r\n</li>\r\n<li><p><code>not like</code>: 用法和 <code>like</code> 操作符类似,区别在于会使用 <code>NOT LIKE</code>\r\n来生成条件语句。</p>\r\n</li>\r\n<li><p><code>or not like</code>: 用法和 <code>not like</code> 操作符类似,区别在于会使用 <code>OR</code> \r\n来串联多个 <code>NOT LIKE</code> 条件语句。</p>\r\n</li>\r\n<li><p><code>exists</code>: 需要一个操作数,该操作数必须是代表子查询 yii\\db\\Query 的一个实例,\r\n它将会构建一个 <code>EXISTS (sub-query)</code> 表达式。</p>\r\n</li>\r\n<li><p><code>not exists</code>: 用法和 <code>exists</code> 操作符类似,它将创建一个 <code>NOT EXISTS (sub-query)</code> 表达式。</p>\r\n</li>\r\n<li><p><code>></code>, <code><=</code>, 或者其他包含两个操作数的合法 DB 操作符: 第一个操作数必须为字段的名称,\r\n而第二个操作数则应为一个值。例如,<code>[''>'', ''age'', 10]</code> 将会生成 <code>age>10</code>。</p>\r\n</li>\r\n</ul><h4>附加条件 <span></span></h4>\r\n<p>你可以使用 yii\\db\\Query::andWhere() 或者 yii\\db\\Query::orWhere() 在原有条件的基础上\r\n附加额外的条件。你可以多次调用这些方法来分别追加不同的条件。\r\n例如,</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$status</span> = <span class="hljs-number">10</span>;\r\n<span class="hljs-variable">$search</span> = <span class="hljs-string">''yii''</span>;\r\n\r\n<span class="hljs-variable">$query</span>->where([<span class="hljs-string">''status''</span> => <span class="hljs-variable">$status</span>]);\r\n\r\n<span class="hljs-keyword">if</span> (!<span class="hljs-keyword">empty</span>(<span class="hljs-variable">$search</span>)) {\r\n <span class="hljs-variable">$query</span>->andWhere([<span class="hljs-string">''like''</span>, <span class="hljs-string">''title''</span>, <span class="hljs-variable">$search</span>]);\r\n}\r\n</code></pre>\r\n<p>如果 <code>$search</code> 不为空,那么将会生成如下 SQL 语句:</p>\r\n<pre><code class="language-sql hljs">... WHERE (`status` = 10) AND (`title` LIKE ''%yii%'')\r\n</code></pre>\r\n<h4>过滤条件 <span></span></h4>\r\n<p>当 <code>WHERE</code> 条件来自于用户的输入时,你通常需要忽略用户输入的空值。\r\n例如,在一个可以通过用户名或者邮箱搜索的表单当中,用户名或者邮箱\r\n输入框没有输入任何东西,这种情况下你想要忽略掉对应的搜索条件,\r\n那么你就可以使用 yii\\db\\Query::filterWhere() 方法来实现这个目的:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// $username 和 $email 来自于用户的输入</span>\r\n<span class="hljs-variable">$query</span>->filterWhere([\r\n <span class="hljs-string">''username''</span> => <span class="hljs-variable">$username</span>,\r\n <span class="hljs-string">''email''</span> => <span class="hljs-variable">$email</span>, \r\n]);\r\n</code></pre>\r\n<p>yii\\db\\Query::filterWhere() 和 yii\\db\\Query::where() 唯一的不同就在于,前者\r\n将忽略在条件当中的<a href="#hash-format">hash format</a>的空值。所以如果 <code>$email</code> 为空而 <code>$username</code> \r\n不为空,那么上面的代码最终将生产如下 SQL <code>...WHERE username=:username</code>。 </p>\r\n<blockquote><p>提示:当一个值为 null、空数组、空字符串或者一个只包含空白字符时,那么它将被判定为空值。</p>\r\n</blockquote>\r\n<p>类似于 [yii\\db\\Query::andWhere()|andWhere()]] 和 yii\\db\\Query::orWhere(),\r\n你可以使用 yii\\db\\Query::andFilterWhere() 和 yii\\db\\Query::orFilterWhere() 方法\r\n来追加额外的过滤条件。</p>\r\n<h3>yii\\db\\Query::orderBy() <span></span></h3>\r\n<p>yii\\db\\Query::orderBy() 方法是用来指定 SQL 语句当中的 <code>ORDER BY</code> 子句的。例如,</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// ... ORDER BY `id` ASC, `name` DESC</span>\r\n<span class="hljs-variable">$query</span>->orderBy([\r\n <span class="hljs-string">''id''</span> => SORT_ASC,\r\n <span class="hljs-string">''name''</span> => SORT_DESC,\r\n]);\r\n</code></pre>\r\n<p>如上所示,数组当中的键指代的是字段名称,而数组当中的值则表示的是排序的方式。\r\nPHP 的常量 <code>SORT_ASC</code> 指的是升序排列,<code>SORT_DESC</code> 指的则是降序排列。</p>\r\n<p>如果 <code>ORDER BY</code> 仅仅包含简单的字段名称,你可以使用字符串来声明它,\r\n就像写原生的 SQL 语句一样。例如,</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span>->orderBy(<span class="hljs-string">''id ASC, name DESC''</span>);\r\n</code></pre>\r\n<blockquote><p>注意:当 <code>ORDER BY</code> 语句包含一些 DB 表达式的时候,你应该使用数组的格式。</p>\r\n</blockquote>\r\n<p>你可以调用 [yii\\db\\Query::addOrderBy()|addOrderBy()]] 来为 <code>ORDER BY</code> 片断添加额外的子句。\r\n例如,</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span>->orderBy(<span class="hljs-string">''id ASC''</span>)\r\n ->addOrderBy(<span class="hljs-string">''name DESC''</span>);\r\n</code></pre>\r\n<h3>yii\\db\\Query::groupBy() <span></span></h3>\r\n<p>yii\\db\\Query::groupBy() 方法是用来指定 SQL 语句当中的 <code>GROUP BY</code> 片断的。例如,</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// ... GROUP BY `id`, `status`</span>\r\n<span class="hljs-variable">$query</span>->groupBy([<span class="hljs-string">''id''</span>, <span class="hljs-string">''status''</span>]);\r\n</code></pre>\r\n<p>如果 <code>GROUP BY</code> 仅仅包含简单的字段名称,你可以使用字符串来声明它,\r\n就像写原生的 SQL 语句一样。例如,</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span>->groupBy(<span class="hljs-string">''id, status''</span>);\r\n</code></pre>\r\n<blockquote><p>注意:当 <code>GROUP BY</code> 语句包含一些 DB 表达式的时候,你应该使用数组的格式。</p>\r\n</blockquote>\r\n<p>你可以调用 [yii\\db\\Query::addOrderBy()|addOrderBy()]] 来为 <code>GROUP BY</code> \r\n子句添加额外的字段。例如,</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span>->groupBy([<span class="hljs-string">''id''</span>, <span class="hljs-string">''status''</span>])\r\n ->addGroupBy(<span class="hljs-string">''age''</span>);\r\n</code></pre>\r\n<h3>yii\\db\\Query::having() <span></span></h3>\r\n<p>yii\\db\\Query::having() 方法是用来指定 SQL 语句当中的 <code>HAVING</code> 子句。它带有一个条件,\r\n和 <a href="#where">where()</a> 中指定条件的方法一样。例如,</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// ... HAVING `status` = 1</span>\r\n<span class="hljs-variable">$query</span>->having([<span class="hljs-string">''status''</span> => <span class="hljs-number">1</span>]);\r\n</code></pre>\r\n<p>请查阅 <a href="#where">where()</a> 的文档来获取更多有关于如何指定一个条件的细节。</p>\r\n<p>你可以调用 yii\\db\\Query::andHaving() 或者 yii\\db\\Query::orHaving() \r\n方法来为 <code>HAVING</code> 子句追加额外的条件,例如,</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// ... HAVING (`status` = 1) AND (`age` > 30)</span>\r\n<span class="hljs-variable">$query</span>->having([<span class="hljs-string">''status''</span> => <span class="hljs-number">1</span>])\r\n ->andHaving([<span class="hljs-string">''>''</span>, <span class="hljs-string">''age''</span>, <span class="hljs-number">30</span>]);\r\n</code></pre>\r\n<h3>yii\\db\\Query::limit() 和 yii\\db\\Query::offset() <span></span></h3>\r\n<p>yii\\db\\Query::limit() 和 yii\\db\\Query::offset() 是用来指定 SQL 语句当中\r\n的 <code>LIMIT</code> 和 <code>OFFSET</code> 子句的。例如,</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// ... LIMIT 10 OFFSET 20</span>\r\n<span class="hljs-variable">$query</span>->limit(<span class="hljs-number">10</span>)->offset(<span class="hljs-number">20</span>);\r\n</code></pre>\r\n<p>如果你指定了一个无效的 limit 或者 offset(例如,一个负数),那么它将会被忽略掉。</p>\r\n<blockquote><p>提示:在不支持 <code>LIMIT</code> 和 <code>OFFSET</code> 的 DBMS 中(例如,MSSQL),\r\n 查询构建器将生成一条模拟 <code>LIMIT</code>/<code>OFFSET</code> 行为的 SQL 语句。</p>\r\n</blockquote>\r\n<h3>yii\\db\\Query::join() <span></span></h3>\r\n<table><thead><tr><th>[yii\\db\\Query::join()|join()]] 是用来指定 SQL 语句当中的 <code>JOIN</code> 子句的。例如,</th></tr></thead><tbody><tr><td><code>`</code>php</td></tr><tr><td>// ... LEFT JOIN <code>post</code> ON <code>post</code>.<code>user_id</code> = <code>user</code>.<code>id</code></td></tr><tr><td>$query->join(''LEFT JOIN'', ''post'', ''post.user_id = user.id'');</td></tr><tr><td><code>`</code></td></tr></tbody></table><p>yii\\db\\Query::join() 带有四个参数:</p>\r\n<ul><li><code>$type</code>: 连接类型,例如:<code>''INNER JOIN''</code>, <code>''LEFT JOIN''</code>。</li>\r\n<li><code>$table</code>: 将要连接的表名称。</li>\r\n<li><code>$on</code>: 可选参数,连接条件,即 <code>ON</code> 子句。请查阅 <a href="#where">where()</a> \r\n获取更多有关于条件定义的细节。</li>\r\n<li><code>$params</code>: 可选参数,与连接条件绑定的参数。</li>\r\n</ul><p>你可以分别调用如下的快捷方法来指定 <code>INNER JOIN</code>, <code>LEFT JOIN</code> 和 <code>RIGHT JOIN</code>。</p>\r\n<ul><li>yii\\db\\Query::innerJoin()</li>\r\n<li>yii\\db\\Query::leftJoin()</li>\r\n<li>yii\\db\\Query::rightJoin()</li>\r\n</ul><p>例如,</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span>->leftJoin(<span class="hljs-string">''post''</span>, <span class="hljs-string">''post.user_id = user.id''</span>);\r\n</code></pre>\r\n<p>可以通过多次调用如上所述的连接方法来连接多张表,每连接一张表调用一次。</p>\r\n<p>除了连接表以外,你还可以连接子查询。方法如下,将需要被连接的子查询指定\r\n为一个 yii\\db\\Query 对象,例如,</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$subQuery</span> = (<span class="hljs-keyword">new</span> \\yii\\db\\Query())->from(<span class="hljs-string">''post''</span>);\r\n<span class="hljs-variable">$query</span>->leftJoin([<span class="hljs-string">''u''</span> => <span class="hljs-variable">$subQuery</span>], <span class="hljs-string">''u.id = author_id''</span>);\r\n</code></pre>\r\n<p>在这个例子当中,你应该将子查询放到一个数组当中,而数组当中的键,则为这个子查询的别名。</p>\r\n<h3>yii\\db\\Query::union() <span></span></h3>\r\n<p>yii\\db\\Query::union() 方法是用来指定 SQL 语句当中的 <code>UNION</code> 子句的。例如,</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query1</span> = (<span class="hljs-keyword">new</span> \\yii\\db\\Query())\r\n ->select(<span class="hljs-string">"id, category_id AS type, name"</span>)\r\n ->from(<span class="hljs-string">''post''</span>)\r\n ->limit(<span class="hljs-number">10</span>);\r\n\r\n<span class="hljs-variable">$query2</span> = (<span class="hljs-keyword">new</span> \\yii\\db\\Query())\r\n ->select(<span class="hljs-string">''id, type, name''</span>)\r\n ->from(<span class="hljs-string">''user''</span>)\r\n ->limit(<span class="hljs-number">10</span>);\r\n\r\n<span class="hljs-variable">$query1</span>->union(<span class="hljs-variable">$query2</span>);\r\n</code></pre>\r\n<p>你可以通过多次调用 yii\\db\\Query::union() 方法来追加更多的 <code>UNION</code> 子句。</p>\r\n<h2>查询方法 <span></span></h2>\r\n<p>yii\\db\\Query 提供了一整套的用于不同查询目的的方法。</p>\r\n<ul><li>yii\\db\\Query::all(): 将返回一个由行组成的数组,每一行是一个由名称和值构成的关联数组(译者注:省略键的数组称为索引数组)。</li>\r\n<li>yii\\db\\Query::one(): 返回结果集的第一行。</li>\r\n<li>yii\\db\\Query::column(): 返回结果集的第一列。</li>\r\n<li>yii\\db\\Query::scalar(): 返回结果集的第一行第一列的标量值。</li>\r\n<li>yii\\db\\Query::exists(): 返回一个表示该查询是否包结果集的值。</li>\r\n<li>yii\\db\\Query::count(): 返回 <code>COUNT</code> 查询的结果。</li>\r\n<li>其它集合查询方法: 包括 yii\\db\\Query::sum(), yii\\db\\Query::average(),\r\nyii\\db\\Query::max(), yii\\db\\Query::min() 等. <code>$q</code> 是一个必选参数,\r\n既可以是一个字段名称,又可以是一个 DB 表达式。</li>\r\n</ul><p>例如,</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// SELECT `id`, `email` FROM `user`</span>\r\n<span class="hljs-variable">$rows</span> = (<span class="hljs-keyword">new</span> \\yii\\db\\Query())\r\n ->select([<span class="hljs-string">''id''</span>, <span class="hljs-string">''email''</span>])\r\n ->from(<span class="hljs-string">''user''</span>)\r\n ->all();\r\n \r\n<span class="hljs-comment">// SELECT * FROM `user` WHERE `username` LIKE `%test%`</span>\r\n<span class="hljs-variable">$row</span> = (<span class="hljs-keyword">new</span> \\yii\\db\\Query())\r\n ->from(<span class="hljs-string">''user''</span>)\r\n ->where([<span class="hljs-string">''like''</span>, <span class="hljs-string">''username''</span>, <span class="hljs-string">''test''</span>])\r\n ->one();\r\n</code></pre>\r\n<blockquote><p>注意:yii\\db\\Query::one() 方法只返回查询结果当中的第一条数据,\r\n 条件语句中不会加上 <code>LIMIT 1</code> 条件。如果你清楚的知道查询将会只返回一行或几行数据\r\n (例如, 如果你是通过某些主键来查询的),这很好也提倡这样做。但是,如果查询结果\r\n 有机会返回大量的数据时,那么你应该显示调用 <code>limit(1)</code> 方法,以改善性能。\r\n 例如, <code>(new \\yii\\db\\Query())->from(''user'')->limit(1)->one()</code>。</p>\r\n</blockquote>\r\n<p>所有的这些查询方法都有一个可选的参数 <code>$db</code>, 该参数指代的是 yii\\db\\Connection,\r\n执行一个 DB 查询时会用到。如果你省略了这个参数,那么 <code>db</code> <a href="/doc/guide/2.0/structure-application-components">application component</a> 将会被用作\r\n默认的 DB 连接。 如下是另外一个使用 <code>count()</code> 查询的例子:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// 执行 SQL: SELECT COUNT(*) FROM `user` WHERE `last_name`=:last_name</span>\r\n<span class="hljs-variable">$count</span> = (<span class="hljs-keyword">new</span> \\yii\\db\\Query())\r\n ->from(<span class="hljs-string">''user''</span>)\r\n ->where([<span class="hljs-string">''last_name''</span> => <span class="hljs-string">''Smith''</span>])\r\n ->count();\r\n</code></pre>\r\n<p>当你调用 yii\\db\\Query 当中的一个查询方法的时候,实际上内在的运作机制如下: </p>\r\n<ul><li>在当前 yii\\db\\Query 的构造基础之上,调用 yii\\db\\QueryBuilder 来生成一条 SQL 语句;</li>\r\n<li>利用生成的 SQL 语句创建一个 yii\\db\\Command 对象; </li>\r\n<li>调用 yii\\db\\Command 的查询方法(例如,<code>queryAll()</code>)来执行这条 SQL 语句,并检索数据。</li>\r\n</ul><p>有时候,你也许想要测试或者使用一个由 yii\\db\\Query 对象创建的 SQL 语句。\r\n你可以使用以下的代码来达到目的:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$command</span> = (<span class="hljs-keyword">new</span> \\yii\\db\\Query())\r\n ->select([<span class="hljs-string">''id''</span>, <span class="hljs-string">''email''</span>])\r\n ->from(<span class="hljs-string">''user''</span>)\r\n ->where([<span class="hljs-string">''last_name''</span> => <span class="hljs-string">''Smith''</span>])\r\n ->limit(<span class="hljs-number">10</span>)\r\n ->createCommand();\r\n \r\n<span class="hljs-comment">// 打印 SQL 语句</span>\r\n<span class="hljs-keyword">echo</span> <span class="hljs-variable">$command</span>->sql;\r\n<span class="hljs-comment">// 打印被绑定的参数</span>\r\nprint_r(<span class="hljs-variable">$command</span>->params);\r\n\r\n<span class="hljs-comment">// 返回查询结果的所有行</span>\r\n<span class="hljs-variable">$rows</span> = <span class="hljs-variable">$command</span>->queryAll();\r\n</code></pre>\r\n<h3>索引查询结果 <span></span></h3>\r\n<p>当你在调用 yii\\db\\Query::all() 方法时,它将返回一个以连续的整型数值为索引的数组。\r\n而有时候你可能希望使用一个特定的字段或者表达式的值来作为索引结果集数组。那么你可以在调用 yii\\db\\Query::all() \r\n之前使用 yii\\db\\Query::indexBy() 方法来达到这个目的。\r\n例如,</p>\r\n<pre><code class="language-php hljs"><span class="hljs-comment">// 返回 [100 => [''id'' => 100, ''username'' => ''...'', ...], 101 => [...], 103 => [...], ...]</span>\r\n<span class="hljs-variable">$query</span> = (<span class="hljs-keyword">new</span> \\yii\\db\\Query())\r\n ->from(<span class="hljs-string">''user''</span>)\r\n ->limit(<span class="hljs-number">10</span>)\r\n ->indexBy(<span class="hljs-string">''id''</span>)\r\n ->all();\r\n</code></pre>\r\n<p>如需使用表达式的值做为索引,那么只需要传递一个匿名函数给 yii\\db\\Query::indexBy() 方法即可:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span> = (<span class="hljs-keyword">new</span> \\yii\\db\\Query())\r\n ->from(<span class="hljs-string">''user''</span>)\r\n ->indexBy(<span class="hljs-function"><span class="hljs-keyword">function</span> <span class="hljs-params">(<span class="hljs-variable">$row</span>)</span> </span>{\r\n <span class="hljs-keyword">return</span> <span class="hljs-variable">$row</span>[<span class="hljs-string">''id''</span>] . <span class="hljs-variable">$row</span>[<span class="hljs-string">''username''</span>];\r\n })->all();\r\n</code></pre>\r\n<p>该匿名函数将带有一个包含了当前行的数据的 <code>$row</code> 参数,并且返回用作当前行索引的\r\n标量值(译者注:就是简单的数值或者字符串,而不是其他复杂结构,例如数组)。</p>\r\n<h3>批处理查询 <span></span></h3>\r\n<p>当需要处理大数据的时候,像 yii\\db\\Query::all() 这样的方法就不太合适了,\r\n因为它们会把所有数据都读取到内存上。为了保持较低的内存需求, Yii 提供了一个\r\n所谓的批处理查询的支持。批处理查询会利用数据游标将数据以批为单位取出来。</p>\r\n<p>批处理查询的用法如下:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">db</span>\\<span class="hljs-title">Query</span>;\r\n\r\n<span class="hljs-variable">$query</span> = (<span class="hljs-keyword">new</span> Query())\r\n ->from(<span class="hljs-string">''user''</span>)\r\n ->orderBy(<span class="hljs-string">''id''</span>);\r\n\r\n<span class="hljs-keyword">foreach</span> (<span class="hljs-variable">$query</span>->batch() <span class="hljs-keyword">as</span> <span class="hljs-variable">$users</span>) {\r\n <span class="hljs-comment">// $users 是一个包含100条或小于100条用户表数据的数组</span>\r\n}\r\n\r\n<span class="hljs-comment">// or if you want to iterate the row one by one</span>\r\n<span class="hljs-keyword">foreach</span> (<span class="hljs-variable">$query</span>->each() <span class="hljs-keyword">as</span> <span class="hljs-variable">$user</span>) {\r\n <span class="hljs-comment">// $user 指代的是用户表当中的其中一行数据</span>\r\n}\r\n</code></pre>\r\n<p>yii\\db\\Query::batch() 和 yii\\db\\Query::each() 方法将会返回一个实现了<code>Iterator</code> \r\n接口 yii\\db\\BatchQueryResult 的对象,可以用在 <code>foreach</code> 结构当中使用。在第一次迭代取数据的时候,\r\n数据库会执行一次 SQL 查询,然后在剩下的迭代中,将直接从结果集中批量获取数据。默认情况下,\r\n一批的大小为 100,也就意味着一批获取的数据是 100 行。你可以通过给 <code>batch()</code> \r\n或者 <code>each()</code> 方法的第一个参数传值来改变每批行数的大小。</p>\r\n<p>相对于 yii\\db\\Query::all() 方法,批处理查询每次只读取 100 行的数据到内存。\r\n如果你在处理完这些数据后及时丢弃这些数据,那么批处理查询可以很好的帮助降低内存的占用率。</p>\r\n<p>如果你通过 yii\\db\\Query::indexBy() 方法为查询结果指定了索引字段,那么批处理查询将仍然保持相对应的索引方案,例如,</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$query</span> = (<span class="hljs-keyword">new</span> \\yii\\db\\Query())\r\n ->from(<span class="hljs-string">''user''</span>)\r\n ->indexBy(<span class="hljs-string">''username''</span>);\r\n\r\n<span class="hljs-keyword">foreach</span> (<span class="hljs-variable">$query</span>->batch() <span class="hljs-keyword">as</span> <span class="hljs-variable">$users</span>) {\r\n <span class="hljs-comment">// $users 的 “username” 字段将会成为索引</span>\r\n}\r\n\r\n<span class="hljs-keyword">foreach</span> (<span class="hljs-variable">$query</span>->each() <span class="hljs-keyword">as</span> <span class="hljs-variable">$username</span> => <span class="hljs-variable">$user</span>) {\r\n}\r\n</code></pre>\r\n </div>', '查询构建器,DAO,', 2, 1443002072, 1443002072, 1),
(40, '使用 Gii 生成代码', '<div id="content">\r\n\r\n<p>本章将介绍如何使用 <a href="http://www.yiichina.comhttp://www.yiichina.com/doc/guide/2.0/tool-gii">Gii</a> 去自动生成 Web 站点常用功能的代码。使用 Gii 生成代码非常简单,只要按照 Gii 页面上的介绍输入正确的信息即可。</p>\r\n<p>贯穿本章节,你将会学到:</p>\r\n<ul><li>在你的应用中开启 Gii</li>\r\n<li>使用 Gii 去生成活动记录类</li>\r\n<li>使用 Gii 去生成数据表操作的增查改删(CRUD)代码</li>\r\n<li>自定义 Gii 生成的代码</li>\r\n</ul><h2>开始 Gii <span></span></h2>\r\n<p><a href="http://www.yiichina.comhttp://www.yiichina.com/doc/guide/2.0/tool-gii">Gii</a> 是 Yii 中的一个<a href="http://www.yiichina.comhttp://www.yiichina.com/doc/guide/2.0/structure-modules">模块</a>。可以通过配置应用的 yii\\base\\Application::modules 属性开启它。通常来讲在 <code>config/web.php</code> 文件中会有以下配置代码:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-variable">$config</span> = [ ... ];\r\n\r\n<span class="hljs-keyword">if</span> (YII_ENV_DEV) {\r\n <span class="hljs-variable">$config</span>[<span class="hljs-string">''bootstrap''</span>][] = <span class="hljs-string">''gii''</span>;\r\n <span class="hljs-variable">$config</span>[<span class="hljs-string">''modules''</span>][<span class="hljs-string">''gii''</span>] = <span class="hljs-string">''yii\\gii\\Module''</span>;\r\n}\r\n</code></pre>\r\n<p>这段配置表明,如果当前是<a href="http://www.yiichina.comhttp://www.yiichina.com/doc/guide/2.0/concept-configurations#environment-constants">开发环境</a>,应用会包含 <code>gii</code> 模块,模块类是 yii\\gii\\Module。</p>\r\n<p>如果你检查应用的<a href="http://www.yiichina.comhttp://www.yiichina.com/doc/guide/2.0/structure-entry-scripts">入口脚本</a> <code>web/index.php</code>,将看到这行代码将 <code>YII_ENV_DEV</code> 设为 true:</p>\r\n<pre><code class="language-php hljs">defined(<span class="hljs-string">''YII_ENV''</span>) <span class="hljs-keyword">or</span> define(<span class="hljs-string">''YII_ENV''</span>, <span class="hljs-string">''dev''</span>);\r\n</code></pre>\r\n<p>鉴于这行代码的定义,应用处于开发模式下,按照上面的配置会打开 Gii 模块。你可以直接通过 URL 访问 Gii:</p>\r\n<pre><code class="hljs groovy"><span class="hljs-string">http:</span><span class="hljs-comment">//hostname/index.php?r=gii</span>\r\n</code></pre>\r\n<blockquote><p>补充: 如果你通过本机以外的机器访问 Gii,请求会被出于安全原因拒绝。你可以配置 Gii 为其添加允许访问的 IP 地址:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-string">''gii''</span> => [\r\n <span class="hljs-string">''class''</span> => <span class="hljs-string">''yii\\gii\\Module''</span>,\r\n <span class="hljs-string">''allowedIPs''</span> => [<span class="hljs-string">''127.0.0.1''</span>, <span class="hljs-string">''::1''</span>, <span class="hljs-string">''192.168.0.*''</span>, <span class="hljs-string">''192.168.178.20''</span>] <span class="hljs-comment">// 按需调整这里</span>\r\n],\r\n</code></pre>\r\n</blockquote>\r\n<p><img src="http://www.yiichina.comhttp://www.yiichina.com/docs/guide/2.0/images/start-gii.png" alt="Gii"></p>\r\n<h2>生成活动记录类 <span></span></h2>\r\n<p>选择 “Model Generator” (点击 Gii 首页的链接)去生成活动记录类。并像这样填写表单:</p>\r\n<ul><li>Table Name: <code>country</code></li>\r\n<li>Model Class: <code>Country</code></li>\r\n</ul><p><img src="http://www.yiichina.comhttp://www.yiichina.com/docs/guide/2.0/images/start-gii-model.png" alt="模型生成器"></p>\r\n<p>然后点击 “Preview” 按钮。你会看到 <code>models/Country.php</code> 被列在将要生成的文件列表中。可以点击文件名预览内容。</p>\r\n<p>如果你已经创建过同样的文件,使用 Gii 会覆写它,点击文件名旁边的 <code>diff</code> 能查看现有文件与将要生成的文件的内容区别。</p>\r\n<p><img src="http://www.yiichina.comhttp://www.yiichina.com/docs/guide/2.0/images/start-gii-model-preview.png" alt="模型生成器预览"></p>\r\n<p>想要覆写已存在文件,选中 “overwrite” 下的复选框然后点击 “Generator”。如果是新文件,只点击 “Generator” 就好。</p>\r\n<p>接下来你会看到一个包含已生成文件的说明页面。如果生成过程中覆写过文件,还会有一条信息说明代码是重新生成覆盖的。</p>\r\n<h2>生成 CRUD 代码 <span></span></h2>\r\n<p>CRUD 代表增,查,改,删操作,这是绝大多数 Web 站点常用的数据处理方式。选择 Gii 中的 “CRUD Generator” (点击 Gii 首页的链接)去创建 CRUD 功能。本例 “country” 中需要这样填写表单:</p>\r\n<ul><li>Model Class: <code>app\\models\\Country</code></li>\r\n<li>Search Model Class: <code>app\\models\\CountrySearch</code></li>\r\n<li>Controller Class: <code>app\\controllers\\CountryController</code></li>\r\n</ul><p><img src="http://www.yiichina.comhttp://www.yiichina.com/docs/guide/2.0/images/start-gii-crud.png" alt="CRUD 生成器"></p>\r\n<p>然后点击 “Preview” 按钮。你会看到下述将要生成的文件列表。</p>\r\n<p>[[NEED THE IMAGE HERE / 等待官方补充图片]]</p>\r\n<p>如果你之前创建过 <code>controllers/CountryController.php</code> 和 <code>views/country/index.php</code> 文件(在指南的使用数据库章节),选中 “overwrite” 下的复选框覆写它们(之前的文件没能全部支持 CRUD)。</p>\r\n<h2>试运行 <span></span></h2>\r\n<p>用浏览器访问下面的 URL 查看生成代码的运行:</p>\r\n<pre><code class="hljs fortran">http://hostname/<span class="hljs-built_in">index</span>.php?r=country/<span class="hljs-built_in">index</span>\r\n</code></pre>\r\n<p>可以看到一个栅格显示着从数据表中读取的国家数据。支持在列头对数据进行排序,输入筛选条件进行筛选。</p>\r\n<p>可以浏览详情,编辑,或删除栅格中的每个国家。还可以点击栅格上方的 “Create Country” 按钮通过表单创建新国家。</p>\r\n<p><img src="http://www.yiichina.com/docs/guide/2.0/images/start-gii-country-grid.png" alt="国家的数据栅格"></p>\r\n<p><img src="http://www.yiichina.com/docs/guide/2.0/images/start-gii-country-update.png" alt="编辑一个国家"></p>\r\n<p>下面列出由 Gii 生成的文件,以便你研习功能和实现,或修改它们。</p>\r\n<ul><li>控制器:<code>controllers/CountryController.php</code></li>\r\n<li>模型:<code>models/Country.php</code> 和 <code>models/CountrySearch.php</code></li>\r\n<li>视图:<code>views/country/*.php</code></li>\r\n</ul><blockquote><p>补充:Gii 被设计成高度可定制和可扩展的代码生成工具。使用它可以大幅提高应用开发速度。请参考 <a href="http://www.yiichina.com/doc/guide/2.0/tool-gii">Gii</a> 章节了解更多内容。</p>\r\n</blockquote>\r\n<h2>总结 <span></span></h2>\r\n<p>本章学习了如何使用 Gii 去生成为数据表中数据实现完整 CRUD 功能的代码。</p>\r\n </div>', 'Yii2,Gii', 2, 1443002396, 1443002507, 1),
(41, 'RESTful Web服务', '<div id="content">\r\n<p>Yii 提供了一整套用来简化实现 RESTful 风格的 Web Service 服务的 API。\r\n特别是,Yii 支持以下关于 RESTful 风格的 API:</p>\r\n<ul><li>支持 <a href="/doc/guide/2.0/db-active-record">Active Record</a> 类的通用API的快速原型</li>\r\n<li>涉及的响应格式(在默认情况下支持 JSON 和 XML)</li>\r\n<li>支持可选输出字段的定制对象序列化</li>\r\n<li>适当的格式的数据采集和验证错误</li>\r\n<li>支持 <a href="http://en.wikipedia.org/wiki/HATEOAS">HATEOAS</a></li>\r\n<li>有适当HTTP动词检查的高效的路由</li>\r\n<li>内置<code>OPTIONS</code>和<code>HEAD</code>动词的支持</li>\r\n<li>认证和授权</li>\r\n<li>数据缓存和HTTP缓存</li>\r\n<li>速率限制</li>\r\n</ul><p>如下, 我们用一个例子来说明如何用最少的编码来建立一套RESTful风格的API。</p>\r\n<p>假设你想通过 RESTful 风格的 API 来展示用户数据。用户数据被存储在用户DB表,\r\n你已经创建了 yii\\db\\ActiveRecord 类 <code>app\\models\\User</code> 来访问该用户数据.</p>\r\n<h2>创建一个控制器 <span></span></h2>\r\n<p>首先,创建一个控制器类 <code>app\\controllers\\UserController</code> 如下,</p>\r\n<pre><code class="language-php hljs"><span class="hljs-keyword">namespace</span> <span class="hljs-title">app</span>\\<span class="hljs-title">controllers</span>;\r\n\r\n<span class="hljs-keyword">use</span> <span class="hljs-title">yii</span>\\<span class="hljs-title">rest</span>\\<span class="hljs-title">ActiveController</span>;\r\n\r\n<span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">UserController</span> <span class="hljs-keyword">extends</span> <span class="hljs-title">ActiveController</span>\r\n</span>{\r\n <span class="hljs-keyword">public</span> <span class="hljs-variable">$modelClass</span> = <span class="hljs-string">''app\\models\\User''</span>;\r\n}\r\n</code></pre>\r\n<p>控制器类扩展自 yii\\rest\\ActiveController。通过指定 yii\\rest\\ActiveController::modelClass\r\n作为 <code>app\\models\\User</code>, 控制器就能知道使用哪个模型去获取和处理数据。</p>\r\n<h2>配置URL规则 <span></span></h2>\r\n<p>然后,修改有关在应用程序配置的<code>urlManager</code>组件的配置:</p>\r\n<pre><code class="language-php hljs"><span class="hljs-string">''urlManager''</span> => [\r\n <span class="hljs-string">''enablePrettyUrl''</span> => <span class="hljs-keyword">true</span>,\r\n <span class="hljs-string">''enableStrictParsing''</span> => <span class="hljs-keyword">true</span>,\r\n <span class="hljs-string">''showScriptName''</span> => <span class="hljs-keyword">false</span>,\r\n <span class="hljs-string">''rules''</span> => [\r\n [<span class="hljs-string">''class''</span> => <span class="hljs-string">''yii\\rest\\UrlRule''</span>, <span class="hljs-string">''controller''</span> => <span class="hljs-string">''user''</span>],\r\n ],\r\n]\r\n</code></pre>\r\n<p>上面的配置主要是为<code>user</code>控制器增加一个 URL 规则。这样,\r\n用户的数据就能通过美化的 URL 和有意义的 http 动词进行访问和操作。</p>\r\n<h2>尝试 <span></span></h2>\r\n<p>随着以上所做的最小的努力,你已经完成了创建用于访问用户数据\r\n的 RESTful 风格的 API。你所创建的 API 包括:</p>\r\n<ul><li><code>GET /users</code>: 逐页列出所有用户</li>\r\n<li><code>HEAD /users</code>: 显示用户列表的概要信息</li>\r\n<li><code>POST /users</code>: 创建一个新用户</li>\r\n<li><code>GET /users/123</code>: 返回用户 123 的详细信息</li>\r\n<li><code>HEAD /users/123</code>: 显示用户 123 的概述信息</li>\r\n<li><code>PATCH /users/123</code> and <code>PUT /users/123</code>: 更新用户123</li>\r\n<li><code>DELETE /users/123</code>: 删除用户123</li>\r\n<li><code>OPTIONS /users</code>: 显示关于末端 <code>/users</code> 支持的动词</li>\r\n<li><code>OPTIONS /users/123</code>: 显示有关末端 <code>/users/123</code> 支持的动词</li>\r\n</ul><blockquote><p>补充:Yii 将在末端使用的控制器的名称自动变为复数。(译注:个人感觉这里应该变为注意)</p>\r\n</blockquote>\r\n<p>你可以访问你的API用<code>curl</code>命令如下,</p>\r\n<pre><code class="hljs cpp">$ curl -i -H <span class="hljs-string">"Accept:application/json"</span> <span class="hljs-string">"http://localhost/users"</span>\r\n\r\nHTTP/<span class="hljs-number">1.1</span> <span class="hljs-number">200</span> OK\r\nDate: Sun, <span class="hljs-number">02</span> Mar <span class="hljs-number">2014</span> <span class="hljs-number">05</span>:<span class="hljs-number">31</span>:<span class="hljs-number">43</span> GMT\r\nServer: Apache/<span class="hljs-number">2.2</span><span class="hljs-number">.26</span> (Unix) DAV/<span class="hljs-number">2</span> PHP/<span class="hljs-number">5.4</span><span class="hljs-number">.20</span> mod_ssl/<span class="hljs-number">2.2</span><span class="hljs-number">.26</span> OpenSSL/<span class="hljs-number">0.9</span><span class="hljs-number">.8</span>y\r\nX-Powered-By: PHP/<span class="hljs-number">5.4</span><span class="hljs-number">.20</span>\r\nX-Pagination-Total-Count: <span class="hljs-number">1000</span>\r\nX-Pagination-Page-Count: <span class="hljs-number">50</span>\r\nX-Pagination-Current-Page: <span class="hljs-number">1</span>\r\nX-Pagination-Per-Page: <span class="hljs-number">20</span>\r\nLink: <http:<span class="hljs-comment">//localhost/users?page=1>; rel=self, </span>\r\n <http:<span class="hljs-comment">//localhost/users?page=2>; rel=next, </span>\r\n <http:<span class="hljs-comment">//localhost/users?page=50>; rel=last</span>\r\nTransfer-Encoding: chunked\r\nContent-Type: application/json; charset=UTF-<span class="hljs-number">8</span>\r\n\r\n[\r\n {\r\n <span class="hljs-string">"id"</span>: <span class="hljs-number">1</span>,\r\n ...\r\n },\r\n {\r\n <span class="hljs-string">"id"</span>: <span class="hljs-number">2</span>,\r\n ...\r\n },\r\n ...\r\n]\r\n</code></pre>\r\n<p>试着改变可接受的内容类型为<code>application/xml</code>,你会看到结果以 XML 格式返回:</p>\r\n<pre><code class="hljs xml">$ curl -i -H "Accept:application/xml" "http://localhost/users"\r\n\r\nHTTP/1.1 200 OK\r\nDate: Sun, 02 Mar 2014 05:31:43 GMT\r\nServer: Apache/2.2.26 (Unix) DAV/2 PHP/5.4.20 mod_ssl/2.2.26 OpenSSL/0.9.8y\r\nX-Powered-By: PHP/5.4.20\r\nX-Pagination-Total-Count: 1000\r\nX-Pagination-Page-Count: 50\r\nX-Pagination-Current-Page: 1\r\nX-Pagination-Per-Page: 20\r\nLink: <span class="hljs-tag"><<span class="hljs-title">http:</span>//<span class="hljs-attribute">localhost</span>/<span class="hljs-attribute">users</span>?<span class="hljs-attribute">page</span>=<span class="hljs-value">1</span>></span>; rel=self, \r\n <span class="hljs-tag"><<span class="hljs-title">http:</span>//<span class="hljs-attribute">localhost</span>/<span class="hljs-attribute">users</span>?<span class="hljs-attribute">page</span>=<span class="hljs-value">2</span>></span>; rel=next, \r\n <span class="hljs-tag"><<span class="hljs-title">http:</span>//<span class="hljs-attribute">localhost</span>/<span class="hljs-attribute">users</span>?<span class="hljs-attribute">page</span>=<span class="hljs-value">50</span>></span>; rel=last\r\nTransfer-Encoding: chunked\r\nContent-Type: application/xml\r\n\r\n<span class="hljs-pi"><?xml version="1.0" encoding="UTF-8"?></span>\r\n<span class="hljs-tag"><<span class="hljs-title">response</span>></span>\r\n <span class="hljs-tag"><<span class="hljs-title">item</span>></span>\r\n <span class="hljs-tag"><<span class="hljs-title">id</span>></span>1<span class="hljs-tag"></<span class="hljs-title">id</span>></span>\r\n ...\r\n <span class="hljs-tag"></<span class="hljs-title">item</span>></span>\r\n <span class="hljs-tag"><<span class="hljs-title">item</span>></span>\r\n <span class="hljs-tag"><<span class="hljs-title">id</span>></span>2<span class="hljs-tag"></<span class="hljs-title">id</span>></span>\r\n ...\r\n <span class="hljs-tag"></<span class="hljs-title">item</span>></span>\r\n ...\r\n<span class="hljs-tag"></<span class="hljs-title">response</span>></span>\r\n</code></pre>\r\n<blockquote><p>技巧:你还可以通过 Web 浏览器中输入 URL <code>http://localhost/users</code> 来访问你的 API。\r\n 尽管如此,你可能需要一些浏览器插件来发送特定的 headers 请求。</p>\r\n</blockquote>\r\n<p>如你所见,在 headers 响应,有关于总数,页数的信息,等等。\r\n还有一些链接,让你导航到其他页面的数据。例如: <code>http://localhost/users?page=2</code>\r\n会给你的用户数据的下一个页面。</p>\r\n<p>使用 <code>fields</code> 和 <code>expand</code> 参数,你也可以指定哪些字段应该包含在结果内。\r\n例如:URL <code>http://localhost/users?fields=id,email</code> 将只返回 <code>id</code> 和 <code>email</code> 字段。</p>\r\n<blockquote><p>补充:你可能已经注意到了 <code>http://localhost/users</code> 的结果包括一些敏感字段,\r\n例如 <code>password_hash</code>, <code>auth_key</code> 你肯定不希望这些出现在你的 API 结果中。\r\n你应该在 <a href="/doc/guide/2.0/rest-response-formatting">响应格式</a> 部分中过滤掉这些字段。</p>\r\n</blockquote>\r\n<h2>总结 <span></span></h2>\r\n<p>使用 Yii 框架的 RESTful 风格的 API, 在控制器的操作中实现API末端,使用\r\n控制器来组织末端接口为一个单一的资源类型。</p>\r\n<p>从 yii\\base\\Model 类扩展的资源被表示为数据模型。\r\n如果你在使用(关系或非关系)数据库,推荐你使用 yii\\db\\ActiveRecord\r\n来表示资源。</p>\r\n<p>你可以使用 yii\\rest\\UrlRule 简化路由到你的 API 末端。</p>\r\n<p>为了方便维护你的WEB前端和后端,建议你开发接口作为一个单独的应用程序,虽然这不是必须的。</p>\r\n </div>', 'Yii,RESTful Web服务', 2, 1443002869, 1443002869, 1),
(42, 'Yii2.0视频教程', ' <div class="post">\r\n \r\n <div class="title">\r\n \r\n \r\n\r\n <div class="desc">\r\n <p>本教程共2小时10分钟左右。结合了个人博客的例子,高效、系统、完整地讲解了Yii2.0框架的核心知识点,让学习Yii框架的过程变得轻松一点、愉快一点。<br>\r\n Tips:请用超清模式播放。</p>\r\n </div>\r\n \r\n </div>\r\n \r\n \r\n <div class="content">\r\n \r\n \r\n <ul class="list-unstyled">\r\n \r\n <li><h3>1、 课程简介</h3>\r\n <ul class="list-unstyled lilevel2">\r\n <li><a href="/yii2/clip1.php" target="_blank"> 1.1 Yii框架介绍和教程讲解安排(<em>4分20秒</em>)<span class="glyphicon glyphicon-facetime-video" aria-hidden="true"></span> 在线观看 </a></li>\r\n </ul> \r\n </li>\r\n \r\n <li><h3>2、 创建博客原型</h3>\r\n \r\n <ul class="list-unstyled lilevel2">\r\n \r\n <li> <a href="/yii2/clip2.php" target="_blank"> 2.1 安装(<em>3分50秒</em>)<span class="glyphicon glyphicon-facetime-video" aria-hidden="true"></span> 在线观看 </a></li>\r\n <li> <a href="/yii2/clip3.php" target="_blank"> 2.2 Yii运行原理初探(<em>10分40秒</em>)<span class="glyphicon glyphicon-facetime-video" aria-hidden="true"></span> 在线观看 </a></li>\r\n <li> <a href="/yii2/clip4.php" target="_blank"> 2.3 博客系统需求和数据库(<em>4分40秒</em>)<span class="glyphicon glyphicon-facetime-video" aria-hidden="true"></span> 在线观看 </a></li>\r\n <li> <a href="/yii2/clip5.php" target="_blank"> 2.4 Gii生成博客原型(<em>7分50秒</em>)<span class="glyphicon glyphicon-facetime-video" aria-hidden="true"></span> 在线观看 </a></li>\r\n \r\n </ul>\r\n \r\n </li>\r\n \r\n \r\n <li><h3>3、 通过分析代码学习Yii知识</h3>\r\n <ul class="list-unstyled lilevel2">\r\n <li><a href="/yii2/clip6.php" target="_blank"> 3.1 文章查看功能的代码分析(<em>21分10秒</em>)<span class="glyphicon glyphicon-facetime-video" aria-hidden="true"></span> 在线观看 </a></li>\r\n <li><a href="/yii2/clip7.php" target="_blank"> 3.2 文章新增和修改功能的代码分析(<em>16分00秒</em>)<span class="glyphicon glyphicon-facetime-video" aria-hidden="true"></span> 在线观看 </a></li>\r\n <li><a href="/yii2/clip8.php" target="_blank"> 3.3 文章管理功能的代码分析(<em>24分20秒</em>)<span class="glyphicon glyphicon-facetime-video" aria-hidden="true"></span> 在线观看 </a></li>\r\n </ul>\r\n </li> \r\n <li><h3>4、 完善博客原型</h3>\r\n <ul class="list-unstyled lilevel2">\r\n <li><a href="/yii2/clip9.php" target="_blank"> 4.1 完善博客系统的后台功能(<em>23分20秒</em>)<span class="glyphicon glyphicon-facetime-video" aria-hidden="true"></span> 在线观看 </a></li>\r\n <li><a href="/yii2/clip10.php" target="_blank"> 4.2 完善博客系统的前台部分以及总结(<em>18分40秒</em>)<span class="glyphicon glyphicon-facetime-video" aria-hidden="true"></span> 在线观看 </a></li>\r\n </ul>\r\n </li>\r\n </ul>\r\n\r\n </div> \r\n\r\n </div>\r\n', 'Yii2,视频教程,教程', 2, 1445512144, 1445512144, 1);
-- --------------------------------------------------------
--
-- 表的结构 `tbl_tag`
--
CREATE TABLE IF NOT EXISTS `tbl_tag` (
`id` int(11) NOT NULL,
`name` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`frequency` int(11) DEFAULT '1'
) ENGINE=InnoDB AUTO_INCREMENT=76 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
--
-- 转存表中的数据 `tbl_tag`
--
INSERT INTO `tbl_tag` (`id`, `name`, `frequency`) VALUES
(60, 'Yii', 113),
(61, 'RESTful Web服务', 57),
(62, 'Yii2', 293),
(63, 'Gii', 59),
(64, '查询构建器', 54),
(65, 'DAO', 54),
(66, 'GridView', 57),
(67, 'ListView', 57),
(68, 'DetailView', 57),
(69, 'ActiveRecord', 113),
(70, '安装', 4),
(71, 'Composer', 4),
(72, '小部件', 1),
(73, 'widget', 1),
(74, '视频教程', 1),
(75, '教程', 1);
-- --------------------------------------------------------
--
-- 表的结构 `tbl_user`
--
CREATE TABLE IF NOT EXISTS `tbl_user` (
`id` int(11) NOT NULL,
`username` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`password` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`email` varchar(128) COLLATE utf8_unicode_ci NOT NULL,
`profile` text COLLATE utf8_unicode_ci
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
--
-- 转存表中的数据 `tbl_user`
--
INSERT INTO `tbl_user` (`id`, `username`, `password`, `email`, `profile`) VALUES
(1, '魏曦', '$2a$10$JTJf6/XqC94rrOtzuF397OHa4mbmZrVTBOQCmYD9U.obZRUut4BoC', '[email protected]', NULL),
(2, '程城', 'tim2000', '[email protected]', 'hello this is profile'),
(3, 'haoxc', 'haoxc', '[email protected]', 'haoxinc');
--
-- Indexes for dumped tables
--
--
-- Indexes for table `tbl_comment`
--
ALTER TABLE `tbl_comment`
ADD PRIMARY KEY (`id`), ADD KEY `FK_comment_post` (`post_id`);
--
-- Indexes for table `tbl_lookup`
--
ALTER TABLE `tbl_lookup`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `tbl_post`
--
ALTER TABLE `tbl_post`
ADD PRIMARY KEY (`id`), ADD KEY `FK_post_author` (`author_id`);
--
-- Indexes for table `tbl_tag`
--
ALTER TABLE `tbl_tag`
ADD PRIMARY KEY (`id`);
--
-- Indexes for table `tbl_user`
--
ALTER TABLE `tbl_user`
ADD PRIMARY KEY (`id`);
--
-- AUTO_INCREMENT for dumped tables
--
--
-- AUTO_INCREMENT for table `tbl_comment`
--
ALTER TABLE `tbl_comment`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=96;
--
-- AUTO_INCREMENT for table `tbl_lookup`
--
ALTER TABLE `tbl_lookup`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=6;
--
-- AUTO_INCREMENT for table `tbl_post`
--
ALTER TABLE `tbl_post`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=43;
--
-- AUTO_INCREMENT for table `tbl_tag`
--
ALTER TABLE `tbl_tag`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=76;
--
-- AUTO_INCREMENT for table `tbl_user`
--
ALTER TABLE `tbl_user`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT,AUTO_INCREMENT=4;
--
-- 限制导出的表
--
--
-- 限制表 `tbl_comment`
--
ALTER TABLE `tbl_comment`
ADD CONSTRAINT `FK_comment_post` FOREIGN KEY (`post_id`) REFERENCES `tbl_post` (`id`) ON DELETE CASCADE;
--
-- 限制表 `tbl_post`
--
ALTER TABLE `tbl_post`
ADD CONSTRAINT `FK_post_author` FOREIGN KEY (`author_id`) REFERENCES `tbl_user` (`id`) ON DELETE CASCADE;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;