第二层内功 - Action

  • 作者:KK

  • 发表日期:2017.4.8


说在前面

MVC模式下我们通常第一时间就在控制器的方法里写代码,在Yii里将这个写代码的地方定义了一个叫Action的概念,比如下面就有2个Action:

class UserController extends \yii\web\Controller{
	
	public function actionRegister(){
		//注册处理
	}
	
	public function actionLogin(){
		//登录处理
	}
}

我们日常交流中就说“这个控制器里有2个方法分别处理注册和登录业务”,在Yii里应该说“这个控制器里有2个Action……”

方法就方法,干嘛要套个别的名头上去?且看下面


Action映射

先定义一个类继承yii\base\Action

namespace app\actions;

class Login extends \yii\base\Action{
	public function run(){
		echo '登录处理';
	}
}

然后控制器可以这样:

class UserController extends \yii\web\Controller{
	//这个方法是重点!!!!
	public function actions(){
		return [
			//将login映射到指定的类
			'login' => 'app\actions\Login'
		];
	}

	public function actionRegister(){
		//注册处理
	}
}

此时看上去只有?r=user/register能访问到actionRegister方法

但实际上?r=user/login也能访问,它会执行app\actions\Login::run,因为控制器的actions方法进行了actionID映射,它里面的意思是说:如果收到请求的actionID是login的话,那就大概这样:

$action = new \app\actions\Login();
$action->run();

这样就实现了将login逻辑剥离到一个独立的类里处理了,而且这个类还能被别的地方重用

假如登录逻辑的代码很长很复杂,写在这个Controller那加上别的业务代码量就会变得很大,我们可以尝试这样封装一下,我个人曾经也遇到过这样的项目,登录逻辑很复杂很长,而且登录后又要做一些事情


访问控制器

如果有多个控制器都定义了actions方法来映射到同一个Action类,那这个Action怎么知道是哪个控制器调用了自己呢?那就是$this->controller属性:

echo $this->controller->id;
var_dump($this->controller);

访问actionId

$this->id


返回值

将业务逻辑封装到独立的Action中后,这个Action处理完业务要返回数据给前端时,做法跟平时控制器的方法是一模一样的,比如return 123return $this->controller->render('login')或renderPartial等都行


属性注入

其实actions方法进行映射时也能进行属性注入,比如一个Action定义了$a、$b属性,那映射时可以这么来:

public function actions(){
	return [
		'login' => [
			//变成了数组
			'class' => 'app\actions\Login',
			'a' => 'value a',
			'b' => 'value b',
		]
	];
}

这样如果有多个控制器都将各自的请求映射给同一个Action时,但各个控制器的actions方法可以注入不同的属性值,以此来让这个Action能依据不同的属性值来进行不同的工作逻辑控制

实际上这种需求很少,首先定义成独立Action的需求就很更少,所以这个只要知道一下就好


好了,那为何叫Action

简单地说,如果将login方法定义成了一个独立的类(如上面的app\actions\Login),那这个类已经不能说它是控制器的login方法了

而是login业务通过一个类的逻辑来实现了而已,这个逻辑体叫什么呢,于是官方就起名为Action(行动)