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内部是如何被使用的?的更多相关文章

  1. AngularJS之指令中controller与link(十二)

    前言 在指令中存在controller和link属性,对这二者心生有点疑问,于是找了资料学习下. 话题 首先我们来看看代码再来分析分析. 第一次尝试 页面: <custom-directive& ...

  2. ASP.NET MVC搭建项目后台UI框架—8、将View中选择的数据行中的部分数据传入到Controller中

    目录 ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NET MVC搭建项目后台UI框架—3.面板折叠和展开 ASP.NE ...

  3. springmvc 中controller与jsp传值

    参考:springmvc 中controller与jsp传值 springMVC:将controller中数据传递到jsp页面 jsp中,死活拿不到controller中的变量. 花了半天,网上列出各 ...

  4. 详解SpringMVC中Controller的方法中参数的工作原理[附带源码分析]

    目录 前言 现象 源码分析 HandlerMethodArgumentResolver与HandlerMethodReturnValueHandler接口介绍 HandlerMethodArgumen ...

  5. Asp.net MVC 中Controller返回值类型ActionResult

    [Asp.net MVC中Controller返回值类型] 在mvc中所有的controller类都必须使用"Controller"后缀来命名并且对Action也有一定的要求: 必 ...

  6. 指令中 controller && controllerAs

    1, controller 他会暴露一个API,利用这个API可以在多个指令之间通过依赖注入进行通信. controller($scope, $element, $attrs, $tranclude) ...

  7. View中选择的数据行中的部分数据传入到Controller中

    将View中选择的数据行中的部分数据传入到Controller中   ASP.NET MVC搭建项目后台UI框架—1.后台主框架 ASP.NET MVC搭建项目后台UI框架—2.菜单特效 ASP.NE ...

  8. SpringMVC中Controller

    详解SpringMVC中Controller的方法中参数的工作原理[附带源码分析] 目录 前言 现象 源码分析 HandlerMethodArgumentResolver与HandlerMethodR ...

  9. SpringMVC中@Controller和@RequestMapping用法和其他常用注解

    一.简介 在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ,然后再把该Mo ...

随机推荐

  1. Camera 采集图像的方法

    使用 Camera 采集图像, 实现步骤如下: 需要权限: android.permission.CAMERA android.permission.WRITE_EXTERNAL_STORAGE // ...

  2. manifest节点

    xmlns:android属性——定义命名空间 这个属性定义了这个XML文件所使用的命名空间.如果需要指定特殊的命名空间,就需要手动编写代码,在Android Studio基本格式如下: xmlns: ...

  3. java代码实现简体繁体转换

    汉字分为简体和繁体字,这是众所周知的,虽然繁体字中国大陆这边用的并不会太多,但时不时的还是会使用到.那么,如何做到简体字和繁体字的转换呢?其实很简单,这里附上一个java版本的简繁体转换,用网上找的接 ...

  4. 从源码学习使用 node-delegates

    node-delegates 是 TJ 大神所写的一个简单的小工具,源码只有 157 行,作用在于将外部对象接受到的操作委托到内部属性进行处理,也可以理解为讲对象的内部属性暴露到外部,简化我们所需要书 ...

  5. vue/cli 3.0配置NODE_ENV

    原文地址 在项目开发中我们需要配置环境变量,开发环境,生产环境和测试环境.在cli 2.0的版本中我们是通过在config文件夹进行配置的,vue/cli 3.0相对简单,只需要在项目根目录创建.en ...

  6. 在vue中让某个组件重新渲染的笨方法

    在vue中,推崇的是数据驱动也就是数据更新进而使组件得以重新渲染:在某些情况下,我们想要在数据不改变的情况下,重新渲染组件:我遇到的一个情况是:同一个页面,两个tab页分别为tab1和tab2,公用了 ...

  7. css 移动端1px更细

    1.最近写项目经常遇到4个入口菜单放在一行,然后加border:1px 在移动端显示却很粗,如下图: <div class="header"> <div clas ...

  8. A New 3-bit Programming Algorithm using SLC-to-TLC Migration for 8MBs High Performance TLC NAND Flash Memory

    背景 1.2012年左右的数据SLC.MLC.TLC闪存芯片的区别:SLC = Single-Level Cell ,即1bit/cell,速度快寿命长,价格超贵(约MLC 3倍以上的价格),约10万 ...

  9. 吉首大学2019年程序设计竞赛(重现赛)- A SARS病毒 (矩阵,欧拉降幂)

    题目链接:https://ac.nowcoder.com/acm/contest/992/A 题意:求出长度为n的字符串个数,字符串由A.C.G.T组成,其中A和C必须成对出现. 思路:我们规定:   ...

  10. 16.Azkaban的安装

    工作流调度器azkaban 2.1 概述 2.1.1为什么需要工作流调度系统 l  一个完整的数据分析系统通常都是由大量任务单元组成: shell脚本程序,java程序,mapreduce程序.hiv ...