Yii2 Yes It is
关于Yii
Yii 是什么
Yii 是一个高性能,基于组件的 PHP 框架,用于快速开发现代 Web 应用程序。 名字 Yii (读作 易)在中文里有“极致简单与不断演变”两重含义, 也可看作 Yes It Is! 的缩写。
Yii 版本
Yii 当前有两个主要版本:1.1 和 2.0。 1.1 版是上代的老版本,现在处于维护状态。 2.0 版是一个完全重写的版本,采用了最新的技术和协议,包括依赖包管理器 Composer
、PHP 代码规范 PSR
、命名空间
、Traits(特质)
等等。 2.0 版代表新一代框架,是未来几年中我们的主要开发版本。
安装 Yii
- 通过 Composer 安装
1 | composer create-project --prefer-dist yiisoft/yii2-app-basic Yii2 |
验证安装的结果
当安装完成之后, 或配置你的Web服务器(看下面的文章)或使用内置Web Server, 当在项目 web 目录下可以通过下面的命令:
1 | php yii serve |
应用结构
- Yii2 项目根目录
- assets
- commands 控制台命令类目录
- config 应用配置及其它配置目录
- console.php 控制台应用配置信息
- web.php Web 应用配置信息
- controllers 控制器类目录
- mail 邮件类目录
- models 模型类目录
- runtime Yii 在运行时生成的文件,例如日志和缓存文件
- tests 单元测试
- vagrant
- vendor 已经安装的 Composer 包,包括 Yii 框架自身
- views 视图目录
- web Web 应用根目录,包含 Web 入口文件
- assets Yii 发布的资源文件(javascript 和 css)
- index.php 应用入口文件
- widgets
- composer.json Composer 配置文件, 描述包信息
- composer.lock
- yii
一般来说,应用中的文件可被分为两类:在 basic/web 下的和在其它目录下的。 前者可以直接通过 HTTP 访问(例如浏览器),后者不能也不应该被直接访问。一般来说,应用中的文件可被分为两类:在 basic/web 下的和在其它目录下的。 前者可以直接通过 HTTP 访问(例如浏览器),后者不能也不应该被直接访问。
请求生命周期
- 用户提交指向 入口脚本
web/index.php
的请求
- 入口脚本会加载
配置数组
并创建一个应用
实例用于处理该请求
- 应用会通过
request(请求)
应用组件解析被请求的路由
- 应用创建一个
controller(控制器)
实例具体处理请求
- 控制器会创建一个
action(动作)
实例并为该动作执行相关的Filters(访问过滤器)
- 如果任何一个过滤器验证失败, 该动作会被取消
- 如果全部的过滤器都通过, 该动作就会被执行
- 动作后悔加载一个
数据模型
, 一般是从数据库中加载
- 动作后悔渲染一个
View(视图)
, 并为其提供所需的数据模型
- 渲染得到的结果会返回给
response(响应)
应用组件
- 响应组件会把渲染结果发回给用户的浏览器
说声 Hello
这个章节,你将会掌握三件事:
- 如何创建一个动作去响应请求,
- 如何创建一个视图去构造响应内容,
- 以及一个应用如何分派请求给动作。
创建动作
操作必须声明在控制器中。为了简单起见, 你可以直接在 SiteController
控制器里声明 say
操作。 这个控制器是由文件 controllers/SiteController.php
定义的。以下是一个操作的声明:
1 |
|
创建视图
视图是你用来生成响应内容的脚本。为了说 “Hello”, 你需要创建一个 say
视图,以便显示从操作方法中传来的 message
参数。
1 |
|
say
视图应该存为 views/site/say.php
文件。当一个操作中调用了 render()
方法时, 它将会按 views/控制器 ID/视图名.php
路径加载 PHP
文件。
试运行
创建完动作和视图后,你就可以通过下面的 URL 访问新页面了:
1 | http://hostname/index.php?r=site/say&message=Hello+World |
使用表单
这个章节,你将会掌握三件事:
- 创建一个模型代表用户通过表单输入的数据
- 声明规则去验证输入的数据
- 在视图中生成一个 HTML 表单
创建模型
模型类 EntryForm
代表从用户那请求的数据, 该类如下所示并存储在 models/EntryForm.php
文件中。
1 |
|
创建动作
下面你得在 site
控制器中创建一个 entry
操作用于新建的模型。
1 |
|
表达式
Yii::$app
代表应用实例,它是一个全局可访问的单例。 同时它也是一个服务定位器, 能提供request
,response
,db
等等特定功能的组件。 在上面的代码里就是使用request
组件来访问应用实例收到的$_POST
数据。
创建视图
最后创建两个视图文件 entry-confirm
和 entry
。 他们会被刚才创建的 entry
操作渲染。
entry-confirm
视图简单地显示提交的 name
和 email
数据。视图文件应该保存在 views/site/entry-confirm.php
。
1 |
|
entry
视图显示一个 HTML 表单。视图文件应该保存在 views/site/entry.php
。
1 |
|
尝试下
用浏览器访问下面的 URL 看它能否工作:
1 | http://hostname/index.php?r=site/entry |
使用数据库
这个章节,你将会掌握四件事:
- 配置一个数据库连接
- 定义一个活动记录类
- 使用活动记录从数据库中查询数据
- 以分页方式在视图中显示数据
准备数据库
首先创建一个名为 yii2
的数据库,应用将从这个数据库中读取数据。
然后在数据库中创建一个名为 country
的表并插入简单的数据。可以执行下面的语句:
1 | CREATE TABLE `country` ( |
此时便有了一个名为 yii2
的数据库,在这个数据库中有一个包含三个字段的数据表 country
,表中有十行数据。
配置数据库连接
开始之前,请确保你已经安装了 PHP PDO 扩展和你所使用的数据库的 PDO 驱动(例如 MySQL 的 pdo_mysql)。 对于使用关系型数据库来讲,这是基本要求。
1 | php -m // 查看即可 |
驱动和扩展安装可用后,打开 config/db.php
修改里面的配置参数对应你的数据库配置。 该文件默认包含这些内容:
1 |
|
上面配置的数据库连接可以在应用中通过
Yii::$app->db
表达式访问。
创建活动记录
创建一个继承自活动记录类的类 Country
, 把它放在 models/Country.php
文件,去代表和读取 country
表的数据。
1 |
|
这个 Country
类继承自 yii\db\ActiveRecord
。你不用在里面写任何代码。 只需要像现在这样,Yii
就能根据类名去猜测对应的数据表名。
使用 Country
类可以很容易地操作 country
表数据,就像这段代码:
1 | use app\models\Country; |
创建动作
新控制器名为 CountryController
,并在其中创建一个 index
操作, 如下:
1 |
|
创建视图
在 views
目录下先创建一个名为 country
的子目录。 这个目录存储所有由 country
控制器渲染的视图。在 views/country
目录下 创建一个名为 index.php
的视图文件,内容如下:
1 |
|
试运行
浏览器访问下面的 URL 看看能否工作:
1 | http://hostname/index.php?r=country/index |
打印SQL
1 | // 1、查询结构 |
使用 Gii 生成代码
本章节, 你将学到:
- 在你的应用中开启 Gii
- 使用 Gii 去生成活动记录类
- 使用 Gii 去生成数据表操作的增查改删(CRUD)代码
- 自定义 Gii 生成的代码
开始 Gii
Gii
是 Yii
中的一个模块。 可以通过配置应用的 modules
属性开启它。通常来讲在 config/web.php
文件中会有以下配置代码:
1 | $config = [ ... ]; |
这段配置表明,如果当前是开发环境, 应用会包含 gii
模块,模块类是 yii\gii\Module
。
如果你检查应用的入口脚本 web/index.php
, 将看到这行代码将 YII_ENV_DEV
设为 true
:
1 | defined('YII_ENV') or define('YII_ENV', 'dev'); |
鉴于这行代码的定义,应用处于开发模式下,按照上面的配置会打开 Gii
模块。你可以直接通过 URL
访问 Gii
:
1 | http://hostname/index.php?r=gii |
信息: 如果你通过本机以外的机器访问 Gii,请求会被出于安全原因拒绝。 你可以配置 Gii 为其添加允许访问的 IP 地址:
1 | 'gii' => [ |
生成活动记录类
选择 “Model Generator”
(点击 Gii
首页的链接)去生成活动记录类。并像这样填写表单:
- Table Name:
country
- Model Class:
Country
然后点击 “Preview”
按钮。你会看到 models/Country.php
被列在将要生成的文件列表中。可以点击文件名预览内容。
如果你已经创建过同样的文件,使用 Gii
会覆写它, 点击文件名旁边的 diff
能查看现有文件与将要 生成的文件的内容区别。
想要覆写已存在文件,选中 “overwrite”
下的复选框然后点击 “Generator”
。如果是新文件,只点击 “Generator”
就好。
接下来你会看到一个包含已生成文件的说明页面。如果生成过程中覆写过文件, 还会有一条信息说明代码是重新生成覆盖的。
Generating code using template “/Users/caoxl/WWW/Yii2/vendor/yiisoft/yii2-gii/src/generators/model/default”…
overwrote models/Country.php
done!
生成 CRUD 代码
CRUD
代表增,查,改,删操作,这是绝大多数 Web
站点常用的数据处理方式。选择 Gii
中的 “CRUD Generator”
(点击 Gii
首页的链接)去创建 CRUD
功能。本例 “country”
中需要这样填写表单:
- Model Class:
app\models\Country
- Search Model Class:
app\models\CountrySearch
- Controller Class:
app\controllers\CountryController
如果你之前创建过 controllers/CountryController.php
和 views/country/index.php
文件(在指南的使用数据库章节), 选中 “overwrite”
下的复选框覆写它们(之前的文件没能全部支持 CRUD
)。
Generating code using template “/Users/caoxl/WWW/Yii2/vendor/yiisoft/yii2-gii/src/generators/crud/default”…
overwrote controllers/CountryController.php
generated models/CountrySearch.php
generated views/country/_form.php
generated views/country/_search.php
generated views/country/create.php
overwrote views/country/index.php
generated views/country/update.php
generated views/country/view.php
done!
试运行
用浏览器访问下面的 URL
查看生成代码的运行:
1 | http://hostname/index.php?r=country/index |
下面列出由 Gii
生成的文件,以便你研习功能和实现, 或修改它们。
- 控制器:
controllers/CountryController.php
- 模型:
models/Country.php
和models/CountrySearch.php
- 视图:
views/country/*.php
应用结构
入口脚本
入口脚本主要完成以下工作:
- 定义全局常量;
- 注册
Composer
自动加载器; - 包含
Yii
类文件; - 加载应用配置;
- 创建一个应用实例并配置;
- 调用
yii\base\Application::run()
来处理请求。
Web 应用
1 |
|
当运行
入口脚本
处理请求时, 应用主体会经历以下生命周期:- 入口脚本加载应用主体配置数组。
- 入口脚本创建一个应用主体实例:
- 调用
preInit()
配置几个高级别应用主体属性, 比如basePath
。 - 注册
error handler
错误处理方法。 - 配置应用主体属性。
- 调用
init()
初始化,该函数会调用bootstrap()
运行引导启动组件。
- 入口脚本调用
yii\base\Application::run()
运行应用主体:
- 触发
EVENT_BEFORE_REQUEST
事件。 - 处理请求:解析请求 路由 和相关参数; 创建路由指定的模块、控制器和动作对应的类,并运行动作。
- 触发
EVENT_AFTER_REQUEST
事件。 - 发送响应到终端用户。
- 入口脚本调用
- 入口脚本接收应用主体传来的退出状态并完成请求的处理。
过滤器
过滤器是 控制器动作 执行之前或之后执行的对象。
使用过滤器
过滤器本质上是一类特殊的 行为
, 所以使用过滤器
和 使用行为
一样。 可以在控制器类中覆盖它的 behaviors()
方法来声明过滤器,如下所示:
1 | public function behaviors() |
当一个动作有多个过滤器时,根据以下规则先后执行:
- 预过滤
- 按顺序执行应用主体中
behaviors()
列出的过滤器。 - 按顺序执行模块中
behaviors()
列出的过滤器。 - 按顺序执行控制器中
behaviors()
列出的过滤器。 - 如果任意过滤器终止动作执行, 后面的过滤器(包括预过滤和后过滤)不再执行。
- 按顺序执行应用主体中
- 成功通过预过滤后执行动作。
- 后过滤
- 倒序执行控制器中
behaviors()
列出的过滤器。 - 倒序执行模块中
behaviors()
列出的过滤器。 - 倒序执行应用主体中
behaviors()
列出的过滤器。
- 倒序执行控制器中
创建过滤器
1 | namespace app\components; |
扩展
核心扩展
yiisoft/yii2-apidoc
: 提供了一个可扩展的、高效的 API 文档生成器。核心框架的 API 文档也是用它生成的。yiisoft/yii2-authclient
: 提供了一套常用的认证客户端,例如 Facebook OAuth2 客户端、GitHub OAuth2 客户端。yiisoft/yii2-bootstrap
: 提供了一套挂件,封装了 Bootstrap 的组件和插件。yiisoft/yii2-codeception
: 提供了基于 Codeception 的测试支持。yiisoft/yii2-debug
: 提供了对 Yii 应用的调试支持。当使用该扩展是, 在每个页面的底部将显示一个调试工具条。 该扩展还提供了一个独立的页面,以显示更详细的调试信息。yiisoft/yii2-elasticsearch
: 提供对 Elasticsearch 的使用支持。它包含基本的查询/搜索支持, 并实现了 Active Record 模式让你可以将活动记录 存储在 Elasticsearch 中。yiisoft/yii2-faker
: 提供了使用 Faker 的支持,为你生成模拟数据。yiisoft/yii2-gii
: 提供了一个基于页面的代码生成器,具有高可扩展性,并能用来快速生成模型、 表单、模块、CRUD 等。yiisoft/yii2-httpclient
: 提供 HTTP 客户端。yiisoft/yii2-imagine
: 提供了基于 Imagine 的常用图像处理功能。yiisoft/yii2-jui
: 提供了一套封装 JQuery UI 的挂件以及它们的交互。yiisoft/yii2-mongodb
: 提供了对 MongoDB 的使用支持。它包含基本 的查询、活动记录、数据迁移、缓存、代码生成等特性。yiisoft/yii2-queue
: 通过队列异步提供运行任务的支持。 它支持基于 DB,Redis,RabbitMQ,AMQP,Beanstalk 和 Gearman 的队列。yiisoft/yii2-redis
: 提供了对 redis 的使用支持。它包含基本的 查询、活动记录、缓存等特性。yiisoft/yii2-shell
: 提供基于 psysh 的交互式 shell。yiisoft/yii2-smarty
: 提供了一个基于 Smarty 的模板引擎。yiisoft/yii2-sphinx
: 提供了对 Sphinx 的使用支持。它包含基本的 查询、活动记录、代码生成等特性。yiisoft/yii2-swiftmailer
: 提供了基于 swiftmailer 的邮件发送功能。yiisoft/yii2-twig
: 提供了一个基于 Twig 的模板引擎。
以下官方扩展适用于 Yii 2.1 及以上版本。 您不需要为 Yii 2.0 安装它们,因为它们包含在核心框架中。
yiisoft/yii2-captcha
: 提供 CAPTCHA。yiisoft/yii2-jquery
: 为 jQuery 提供支持。yiisoft/yii2-maskedinput
: 提供基于 jQuery Input Mask plugin 的格式化输入小部件。yiisoft/yii2-mssql
: 提供对使用 MSSQL 的支持。yiisoft/yii2-oracle
: 提供对使用 Oracle 的支持。yiisoft/yii2-rest
: 提供对 REST API 的支持。
请求处理
请求
请求参数
要获取请求参数,你可以调用 request
组件的 get()
方法和 post()
方法。 他们分别返回 $_GET
和 $_POST
的值。例如,
1 | $request = Yii::$app->request; |
请求方法
你可以通过 Yii::$app->request->method
表达式来获取当前请求使用的HTTP方法。
1 | $request = Yii::$app->request; |
请求URLs
假设被请求的 URL
是 http://example.com/admin/index.php/product?id=100
, 你可以像下面描述的那样获取 URL
的各个部分:
url
:返回/admin/index.php/product?id=100
, 此URL
不包括主机信息部分。absoluteUrl
:返回http://example.com/admin/index.php/product?id=100
, 包含host info
的整个URL。hostInfo
:返回http://example.com
, 只有主机信息部分。pathInfo
:返回/product
, 这个是入口脚本之后,问号之前(查询字符串)的部分。queryString
:返回id=100
,问号之后的部分。baseUrl
:返回/admin
,主机信息之后, 入口脚本之前的部分。scriptUrl
:返回/admin/index.php
,没有路径信息和查询字符串部分。serverName
:返回example.com
,URL 中的主机名。serverPort
:返回80
,这是web
服务中使用的端口。
响应
状态码
1 | Yii::$app->response->statusCode = 200; |
尽管如此,大多数情况下不需要明确设置状态码, 因为 yii\web\Response::$statusCode
状态码默认为 200
, 如果需要指定请求失败,可抛出对应的 HTTP
异常,如下所示:
1 | throw new \yii\web\NotFoundHttpException; |
HTTP 头部
可在 response
组件中操控 header collection
来发送 HTTP
头部信息, 例如:
1 | $headers = Yii::$app->response->headers; |
响应主体
如果已有格式化好的主体字符串,可赋值到响应的 yii\web\Response::$content
属性, 例如:
1 | Yii::$app->response->content = 'hello world!'; |
发送响应
在 yii\web\Response::send()
方法调用前响应中的内容不会发送给用户, 该方法默认在 yii\base\Application::run()
结尾自动调用,尽管如此,可以明确调用该方法强制立即发送响应。
yii\web\Response::send()
方法使用以下步骤来发送响应:
- 触发
yii\web\Response::EVENT_BEFORE_SEND
事件。 - 调用
yii\web\Response::prepare()
来格式化response data
为response content
。 - 触发
yii\web\Response::EVENT_AFTER_PREPARE
事件。 - 调用
yii\web\Response::sendHeaders()
来发送注册的HTTP头 - 调用
yii\web\Response::sendContent()
来发送响应主体内容 - 触发
yii\web\Response::EVENT_AFTER_SEND
事件。
Sessions 和 Cookies
Sessions
开启和关闭 Sessions
1 | $session = Yii::$app->session; |
访问 Session 数据
1 | $session = Yii::$app->session; |
Cookies
读取 Cookies
1 | // 从 "request" 组件中获取 cookie 集合(yii\web\CookieCollection) |
发送 Cookies
1 | // 从 "response" 组件中获取 cookie 集合(yii\web\CookieCollection) |
错误处理
Yii
内置了一个 error handler
错误处理器,它使错误处理更方便, Yii错误处理器
做以下工作来提升错误处理效果
使用错误处理器
error handler
注册成一个名称为errorHandler
应用组件, 可以在应用配置中配置它类似如下:
1 | return [ |
日志
日志消息
记录日志消息就跟调用下面的日志方法一样简单:
Yii::trace()
:记录一条消息去跟踪一段代码是怎样运行的。这主要在开发的时候使用。Yii::info()
:记录一条消息来传达一些有用的信息。Yii::warning()
:记录一个警告消息用来指示一些已经发生的意外。Yii::error()
:记录一个致命的错误,这个错误应该尽快被检查。
Restful web 服务
助手类
Array 助手(ArrayHelper)
获取值(Getting Values)
1 | $value = ArrayHelper::getValue($array, 'foo.bar.name'); |
设定值(Setting values)
1 | $array = [ |
检查键名的存在(Checking Existence of Keys)
1 | $data1 = [ |
多维排序(Multidimensional Sorting)
1 | $data = [ |
对象转换为数组(Converting Objects to Arrays)
1 | $posts = Post::find()->limit(10)->all(); |
Html 助手(Html)
生成标签(Generating Tags)
1 | Html::tag('p', Html::encode($user->name), ['class' => 'username']) |
生成 CSS 类和样式(Forming CSS Classes and Styles)
1 | $options = ['class' => 'btn btn-default']; |
创建表单(Creating Forms)
1 | Html::beginForm(['order/update', 'id' => $id], 'post', ['enctype' => 'multipart/form-data']) |
Url 助手(Url)
获得通用 URL(Getting Common URLs)
有两种获取通用 URLS
的方法 :当前请求的 home URL
和 base URL
。
- 为了获取
home URL
,使用如下代码:
1 | $relativeHomeUrl = Url::home(); |
- 如下代码可以获得当前请求的
base URL
:
1 | $relativeBaseUrl = Url::base(); |
创建 URLs(Creating URLs)
1 | $url = Url::toRoute(['product/view', 'id' => 42]); |
记住 URLs(Remember URLs)
1 | // 记住当前 URL |
检查相对 URLs(Checking Relative URLs)
1 | $isRelative = Url::isRelative('test/it'); |