Yii2 结构指引
概述
同laravel一样,yii应用也有两个入口,分别是
web
基础应用 和console
控制台应用
-
入口脚本
- 定义全局常量
- 注册
Composer
自动加载器 - 包含
Yii
类文件 - 加载应用配置
- 创建一个应用实例并配置
- 调用
yii\base\Application::run($config)
来处理请求
-
应用主体
- 实例化
(new yii\web\Application($config))->run()
- 属性
- 必要属性
id, basePath
- 重要属性
aliases
,bootstrap
- 可将模块ID加入到
bootstrap
数组中 - bootsrap 属性中每个组件需要指定以下一项
- 应用 组件 ID
- 模块 ID
- 类名
- 配置数组
- 创建并返回一个组件的无名称函数
catchAll
属性 仅Web applications
网页应用支持- 指定一个要处理所有用户请求的 控制器方法, 通常在维护模式下使用,同一个方法处理所有用户请求
如果模块 ID 和应用组件 ID 同名,优先使用应用组件 ID 在启动阶段,每个组件都会实例化。如果组件类实现接口
yii\base\BootstrapInterface
,也会调用 bootstrap() 方法
- 指定一个要处理所有用户请求的 控制器方法, 通常在维护模式下使用,同一个方法处理所有用户请求
- 可将模块ID加入到
- 必要属性
- 实例化
-
应用组件
components
配置- 每一个应用组件指定一个key-value对的数组,key代表组件ID, value代表组件类名或 配置
- 应用中注册的组件,可以通过表达式 \Yii::$app->ComponentID 全局访问
-
属性
controllerMap
- 指定一个控制器 ID 到任意控制器类
- 数组的键代表控制器ID, 数组的值代表对应的类名
-
属性
controllerNamespace
- 该属性指定控制器类默认的命名空间,默认为
app\controllers
- 该属性指定控制器类默认的命名空间,默认为
-
属性
modules
,键为模块id -
language
,name
,全局可访问的参数params
-
sourceLanguage, timeZone
语言,时区 -
实用属性
charset
应用使用的字符集defaultRoute
该属性指定未配置的请求的响应 路由 规则,可能包含模块 ID,控制器 ID,动作 IDextensions
该属性用数组列表指定应用安装和使用的 扩展, 默认使用@vendor/yiisoft/extensions.php
文件返回的数组layout,layoutPath,runtimePath,viewPath,vendorPath,enableCoreCommands
应用事件
- 应用在处理请求过程中会触发的事件
on eventName
语法配置事件处理代码
- 事件
EVENT_BEFORE_REQUEST
EVENT_AFTER_REQUEST
EVENT_BEFORE_ACTION
EVENT_AFTER_ACTION
- 流程
- 应用主体对象触发
beforeAction
事件 --> 模块触发 --> 控制器触发 - 注意 模块 和 控制器 都会触发 afterAction 事件。 这些对象的触发顺序和
beforeAction
相反
- 应用主体对象触发
任何一个事件处理中设置 yii\base\ActionEvent::$isValid 设置为 false 会停止触发后面的事件
应用组件
- 应用主体是服务定位器, 它部署一组提供各种不同功能的 应用组件 来处理请求
- 访问已注册到应用上的组件实例
\Yii::$app->componentID
- 应用组件在 应用主体配置
yii\base\Application::$components
属性
应用组件就像全局变量,谨慎注册太多应用组件 一个应用组件只会在第一次访问时实例化, 如果处理请求过程没有访问的话就不实例化
- 可以使用闭包来引导启动自定义的组件
- 核心应用组件(类似laravel中的应用启动数组)
request
组件 用来收集用户请求并解析 路由db
代表一个可以执行数据库操作的数据库连接assetManager
管理资源包和资源发布errorHandler:
处理 PHP 错误和异常formatter:
格式化输出显示给终端用户的数据i18n
: 支持信息翻译和格式化log
: 管理日志对象yii\swiftmailer\Mailer
支持生成邮件结构并发送response
: 代表发送给用户的响应session
: 代表会话信息urlManager
: 支持URL地址解析和创建user
: 代表认证登录用户信息,仅在Web applications
网页应用中可用view
: 支持渲染视图
控制器
- 继承
yii\base\Controller
类的对象,负责处理请求和生成响应 - 动作
- 控制器由 操作 组成,它是执行终端用户请求的最基础的单元, 一个控制器可有一个或多个操作
- 路由
- 终端用户通过所谓的路由寻找到动作
- 模块ID: 仅存在于控制器属于非应用的模块
- 控制器ID: 同应用(或同模块如果为模块下的控制)
- 操作ID: 同控制器下唯一标识操作的字符串
- 创建
- 控制器应继承
yii\web\Controller
或它的子类 - 继承
yii\console\Controller
或它的子类 - 控制器ID 应仅包含英文小写字母、数字、下划线、中横杠和正斜杠
- 控制器应继承
- 控制器布署
- 通过配置
controller map
来强制上述的控制器ID和类名对应, - 应用场景 在使用第三方不能掌控类名的控制器上
- 通过配置
- 创建动作
- 内联操作 无需重用的情况下优先使用
- 独立操作
继承 yii\base\Action
或它的子类的类- 主要用于多个控制器重用,或重构为扩展
- 应用场景如
yii\web\ViewAction
,yii\web\ErrorAction
要使用独立操作,需要通过控制器中覆盖
yii\base\Controller::actions()
方法在action map中申明 创建的独立操作类,必须实现公有的名称为run()
的方法,与操作方法类似
- 动作结果
- 返回值可为 响应 对象,作为响应发送给终端用户
- 对于
Web applications
网页应用,返回值可为任意数据, 它赋值给yii\web\Response::$data
- 对于
console applications
控制台应用,返回值可为整数, 表示命令行下执行的exit status
退出状态
- 动作参数,对于Web
applications
网页应用, 每个动作参数的值从$_GET中获得,参数名作为键 - 默认动作
- 当路由 只包含控制器ID, 会使用所请求的控制器的默认操作
- 由控制器中的
$defaultAction
指定默认动作
- 控制器生命周期
- 应用主体 --> 请求路由 --> 创建控制器
- 控制器
init()
方法被调用 - 创建操作对象
- 未提供ID,使用
default action ID
默认操作ID - 在
action map
(控制器actions方法) 找到操作ID, 会创建一个独立操作 - 操作ID对应操作方法,会创建一个内联操作
- 否则会抛出
yii\base\InvalidRouteException
异常
- 未提供ID,使用
- 控制器按顺序调用应用主体、模块(如果控制器属于模块)、 控制器的 beforeAction() 方法
- 任意一个调用返回false,后面未调用的
beforeAction()
会跳过并且操作执行会被取消 - 默认情况下每个
beforeAction()
方法会触发一个 beforeAction 事件
- 任意一个调用返回false,后面未调用的
- 控制器执行操作
- 控制器按顺序调用控制器、模块(如果控制器属于模块)、应用主体的 afterAction() 方法
- 应用主体获取操作结果并赋值给响应
- 控制器
- 应用主体 --> 请求路由 --> 创建控制器
- 小结
- 访问请求数据
- 根据请求数据调用模型方法和其他服务组件
- 使用视图构造响应
- 不应处理被模型处理的请求数据
- 应避免嵌入html或其他代码,这些代码最好在视图中处理
模型类
- 代表业务数据,规则和逻辑的对象
yii\base\Model
类特性- 属性
- 定义 覆盖
attriutes()
指定模型所拥有的属性 或定义非静态公有成员变量 - 实现了
ArrayAccess
数组访问,ArrayIterator
数组迭代器
- 定义 覆盖
- 属性标签
$model->getAttributeLabel('name')
- 通过使用模型的 scenario场景, 可对相同的属性返回不同的标签
- 块赋值
- 验证规则
- 数据导出
- 属性
- 场景
- 在不同的场景下, 模型可能会使用不同的业务规则和逻辑
- 例如
email
属性在注册时强制要求有,但在登陆时不需要 - 使用
yii\base\Model::$scenario
属性保持使用场景的跟踪 - 可以通过覆盖
yii\base\Model::scenarios()
方法来自定义行为 - 场景特性主要在验证 和 属性块赋值 中使用
- 验证规则
- 调用
yii\base\Model::validate()
来验证接收到的数据 - 使用
yii\base\Model::rules()
申明的验证规则 - 使用
yii\base\Model::$errors
属性保存错误
- 调用
- 非安全属性验证
- 在
scenarios()
方法中属性名加一个惊叹号!
- 应用场景 在某些情况下,可能想验证一个属性但不想让他是安全
- 在
- 数据导出
- 模型转换成数组
yii\base\Model::attributes()
- 数组转换成需要的格式
- 通常使用 数据转换器如
yii\web\JsonResponseFormatter
- 更灵活和强大的将模型转换为数组的方式是使用
yii\base\Model::toArray()
方法
- 通常使用 数据转换器如
- 模型转换成数组
- 字段
- 可以通过覆盖
fields()
和/或extraFields()
方法来改变这种行为 fields()
方法定义的字段是默认字段, 表示toArray()
方法默认会返回这些字段- 应用场景 通常使用覆盖
fields()
方法过滤掉 一些包含敏感信息的字段
- 可以通过覆盖
- 实践
- 模型是代表业务数据、规则和逻辑的中心地方,通常在很多地方重用
- 不应直接访问请求,session和其他环境数据, 这些数据应该由控制器传入到模型
- 单个模型中避免太多的 场景
- 常用策略 定义可被多个 应用主体 或 模块 共享的模型基类集合。 这些模型类应包含通用的最小规则集合和逻辑
- 通过继承对应的模型基类来定义具体的模型类,具体模型类包含应用主体或模块指定的规则和逻辑
视图
- 视图模板为PHP脚本文件, 主要包含HTML代码和展示类PHP代码,通过view应用组件来管理渲染视图
- 组织视图
- 控制器渲染的视图文件默认放在
@app/views/ControllerID
目录下 - 对于 小部件 渲染的视图文件默认放在
WidgetPath/views
目录 - 可覆盖控制器或小部件的
yii\base\ViewContextInterface::getViewPath()
方法来自定义视图文件默认目录
- 控制器渲染的视图文件默认放在
- 控制器中渲染
render()
: 渲染一个 视图名 并使用一个 布局 返回到渲染结果renderPartial()
: 渲染一个 视图名 并且不使用布局renderAjax()
: 渲染一个 视图名 并且不使用布局renderFile()
: 渲染一个视图文件目录或 别名下的视图文件
- 小部件中渲染
render()
: 渲染一个 视图名.renderFile()
: 渲染一个视图文件目录或 别名下的视图文件
- 视图中渲染
- 调用view component视图组件提供的以下方法
render()
: 渲染一个 视图名renderAjax()
: 渲染一个 视图名 并注入所有注册的JS/CSS脚本和文件
- 其他地方渲染
Yii::$app->view
访问 view 应用组件
- 视图名规则
- 可省略文件扩展名
- 以双斜杠 // 开头,对应的视图文件路径为
@app/views/ViewName
- 视图名以单斜杠/开始,视图文件路径以当前使用模块 的
view path
开始
- 视图中访问数据
- 推送方式 是通过视图渲染方法的第二个参数传递数据,据格式应为名称-值的数组
- 拉取方式 可让视图从
view component
视图组件或其他对象中主动获得数据(如Yii::app),app),‘this->context->id
view component
视图组件提供params
参数属性来让不同视图共享数据- 布局中访问数据,可使用两个预定义变量
$this
和$content
- 前者对应和普通视图类似的view 视图组件 后者包含调用render()方法渲染内容视图的结果
- 视图事件
模块化
- 创建模块
- 存在一个模块类文件,该文件所在目录称之为
base_path
- 每个模块都有一个继承 yii\base\Module 的模块类,该类可被自动加载
- 应用主体实例 类似会创建该模块类唯一实例,模块实例用来帮模块内代码共享数据和组件
- 通常模块块类
init()
方法包含很多初始化模块属性代码
- 存在一个模块类文件,该文件所在目录称之为
- 引导启动模块
- 模块加入到应用主体的
bootstrap
属性中 - 配置
modules
项,值为数组,键为模块名,值模块类
- 模块加入到应用主体的
- 模块嵌套
- 子模块必须在父模块
modules
属性中申明 - 模块在大型项目中常备使用,这些项目的特性可分组
- 子模块必须在父模块
过滤器
- 除了控制器外,可在 模块或应用主体 中申明过滤器
在模块或应用主体中申明过滤器,在only 和 except 属性中使用路由 代替动作 ID, 因在模块或应用主体中只用动作ID并不能唯一指定到具体动作
-
过滤器是 控制器动作 执行之前或之后执行的对象
-
应用场景 权限验证,内容压缩过滤器可在动作执行之后发给终端用户之前压缩响应内容
-
使用
- 过滤器 本质上是一类特殊的行为,可在控制器的
behaviors()
方法来声明过滤器 - 控制器类的过滤器默认应用到该类的 所有 动作,
only
属性则明确指定
- 过滤器 本质上是一类特殊的行为,可在控制器的
-
多个过滤器执行规则
- 预过滤
- 执行应用主体 --> 模块级别 --> 控制器 --> 若过滤器终止后续不再执行
- 成功通过预过滤器则进入执行动作
- 后过滤 倒序执行控制器过滤器--> 倒序模块中 --> 倒序执行应用主体中 behaviors() 列出的过滤器
- 预过滤
-
创建过滤器
- 若返回值为
false
则之后的过滤器和动作不会执行 - 继承
yii\base\ActionFilter
类并覆盖beforeAction()
或afterAction()
方法来创建动作的过滤器
- 若返回值为
-
核心过滤器(类似于java的概念,laravel中的是中间件)
- Yii 核心过滤器在
yii\filters
命名空间下 AccessControl
提供基于rules
规则的访问控制- 决定允许还是拒绝请求动作的执行,若无答合的规则,则访问被拒绝
- 应用场景 比如用户 IP 地址、登录状态等等)的规则,
- 认证方法过滤器
- 认证方法过滤器类在
yii\filters\auth
命名空间下 - 认证方法过滤器通过
HTTP Basic Auth
或OAuth 2
来认证一个用户 - 如
yii\filters\auth\HttpBasicAuth
来认证一个用户user identity class
类必须 实现findIdentityByAccessToken()
方法
ContentNegotiator
支持响应内容格式处理和语言处理- 通过
GET
参数和Accept HTTP
头部来决定响应内容格式和语言 - 亦可在应用主体上配置。
- 如果请求中没有检测到内容格式和语言, 使用 formats 和 languages 第一个配置项
- 通过
- 认证方法过滤器类在
HttpCache
利用Last-Modified
和Etag HTTP
头实现客户端缓存PageCache
实现服务器端整个页面的缓存RateLimiter
根据 漏桶算法 来实现速率限制,主要用在实现RESTful APIs
VerbFilter
检查请求动作的 HTTP 请求方式是否允许执行, 如果不允许,会抛出 HTTP 405异常Cors filter
应在授权/认证过滤器之前定义, 以保证CORS
头部被发送- 若要将CORS过滤器添加到 API 中的
yii\rest\ActiveController
类, 还要检查REST Controllers
中的部分
- Yii 核心过滤器在
小部件Widgets
- 在视图中使用的可重用单元, 使用面向对象方式创建复杂和可配置用户界面单元
- Yii提供许多优秀的小部件
- 比如
active form,menu, jQuery UI widgets, Twitter Bootstrap widgets
- 比如
- 使用
- 在视图中可调用
yii\base\Widget::widget()
方法使用小部件 - 小部件会在
begin()
和end()
执行处分别起止标签
- 在视图中可调用
调用
yii\base\Widget::end()
的时候,一些小部件将使用 输出缓冲 来调整封闭的内容
- 小部件的全局默认值可以通过 DI 容器配置, 如
\Yii::$container->set(xx,yy)
- 创建小部件
widget()
方法- 继承
yii\base\Widget
类,覆盖init()
或run()
方法 - 前者属性赋值,后者返回小部件生成渲染结果的代码,通常大段代码采用
render
方法
- 继承
begin()
和end()
方法- PHP 输出缓冲
ob_start()
在init()
启动 - 所有在
init()
和run()
方法之间的输出内容都会被获取,并在run()
处理和返回
- PHP 输出缓冲
- 流程
begin
时会创建 一个新的小部件实例,并在构造结构时调用init 方法- 在
end
方法时,会调用run
方法并输出结果
- 小结
- 通常逻辑代码在小部件类,展示内容在视图中
- 小部件设计是独立的,丢弃它不需要额外的处理
- 小部件是可以重用的类,视图只是应用中使用的普通PHP脚本
前端资源(Assets)
-
Yii 中的资源是和 Web 页面相关的文件,通常放在 web 可访问的目录下,直接被 Web 服务器调用
-
在视图中注册一个资源包, 在渲染 Web 页面时会包含包中的 CSS 和 JavaScript 文件
-
定义资源包
- 资源包 放在一个目录下的资源集合
- 资源包指定为继承
yii\web\AssetBundle
的 PHP 类, 包名为可自动加载的 PHP 类名 - 在资源包类中,要指定资源所在位置,包含的文件,以及其他包的依赖关系
-
资源位置
- 源资源,发布资源,外部资源
- 推荐 指定
basePath
而不是sourcePath
-
资源依赖 通过
$depends
属性来指定 -
资源选项
- 可指定 cssOptions 和 jsOptions 属性来自定义页面包含 CSS 和 JavaScript 文件的方式,
- 这些属性值会分别传递给
yii\web\View::registerCssFile()
和yii\web\View::registerJsFile()
方法 - 默认情况下,当发布资源包时,所有在
yii\web\AssetBundle::$sourcePath
目录里的内容都会发布
-
使用资源包
- 在视图中调用
yii\web\AssetBundle::register()
方法注册资源 - 在视图模板可使用如下代码注册资源包
use app\assets\AppAsset;AppAsset::register($this);
- 在其他地方注册资源包,应提供视图对,如在小部件类中注册资源包, 可以通过
$this->view
获取视图对象
- 在视图中调用
-
动态资源包
- 应用场景 语言本地化覆盖
yii\web\AssetBundle::init()
方法来实现 - 特定资源包 通过
yii\web\AssetBundle::register()
返回的实例进行调整
- 应用场景 语言本地化覆盖
-
自定义资源包
assetManager
- Yii 通过配置名为
assetManager
的应用组件来使用yii\web\AssetManager
, 配置$bundles
属性自定义资源包行为 - 在应用配置中配置
assetManager
设置cdn资源,sourcePath
则一定不要发布该资源 - 资源包组件-->管理器-->bundles-->资源包类名-->对应的配置数组
- 在
yii\web\AssetBundle::init()
方法内或在注册的资源包对象上进行的调整优先于AssetManager
配置
- Yii 通过配置名为
-
资源映射 “修复”多个资源包中资源文件的错误或者不兼容
$assetMap
属性 -
发布资源
assetManager
- 可
basePath
和baseUrl
属性自定义发布位置 - 可使用符号链接(若系统允许)
'linkAssets' => true,
- 资源包放在 Web 不能访问的目录, 当视图注册资源时资源会被拷贝到一个 Web 可访问的目录中
- 可
-
清除缓存
'appendTimestamp' => true
-
常用资源包
yii\web\YiiAsset
包含 yii.js 文件yii\web\JqueryAsset
包含 jQuery Bower 包的 jquery.js 文件yii\bootstrap\BootstrapAsset
包含 Twitter Bootstrap 框架的 CSS 文件yii\bootstrap\BootstrapPluginAsset
JavaScript 文件yii\jui\JuiAsset
包含 jQuery UI 库的 CSS 和 JavaScript 文件
-
资源转换
yii\web\AssetManager::$converter
自定义预处理命令和支持的扩展语法yii\web\AssetConverter::$commands
属性指定支持的扩展语法
-
合并和压缩
asset manager
资源管理器asset
命令 自动处理资源包命令(生成相应配置文件)yii asset/template assets.php
jsCompressor 和 cssCompressor
定控制台命令或PHP回调函数来处理合并和压缩
- 资源包分组
- 指出输出的bundles包分组,
allShared,allBackEnd,allFrontEnd
- 指出输出的bundles包分组,
扩展
- 类的自举引导
bootstrapping class
(自举类)实现yii\base\BootstrapInterface
接口- 实现
bootstrap
方法,接收主体应用参数, 置于myname\mywidget
命名空间之下 - 应用场景 扩展可响应应用的
beginRequest
事件,做一些环境的设置工作 - 将自举类在 composer.json 文件中列出来,每一个请求的自举过程中,自动实例化自举类并调用其 bootstrap() 方法
- 操作数据库
- 在需要访问数据库的类中申明一个 db 属性,该属性扩展使用哪个DB连接
- 提供 数据迁移 来操作数据库的结构修改,而不是使用SQL文本文件
- 尽量使迁移文件适用于不同的 DBMS
- 在迁移文件中避免使用 Active Record
- 使用Assets
- 手动这些 asset 文件拷贝到特定的 Web 可以读取的文件夹
- 申明一个 asset bundle 并依靠 asset 发布机制自动将这些文件
- 国际化和本地化
- 扩展为终端用户显示信息,这些信息应该用 Yii::t() 包装起来,以便可以进行翻译
- 若扩展显示数字、日期等,用 yii\i18n\Formatter 中适当的格式化规则做格式化
本作品采用《CC 协议》,转载必须注明作者和本文链接
推荐文章: