Yii2 官方给出的方案是基于url的版本控制,但是我们的versoin放在header里面,需要通过header来进行版本控制,实现如下:
首先在基类中实现actions,actions是针对controller的action扩展,看源码可以知道,在createAction中会先检查actionMap,而actionMap=actions(),也就是说actions里面的配置优先于controller的inline actions,这样我们就可以通过检查版本跳到对应的扩展action,然后通过配置参数再次跳到当前controller的其他内部action
基类actions实现
public function actions()
{
$parent = parent::actions();
$actions = (new Version())->convertActionMap();
return array_merge($parent, $actions);
}
Version类的实现
class Version extends Object
{
// 根据自己的header版本标识相应改动
public $versionParam = "Appver";
public $actionMap = null;
// 外部扩展action接口,可以放到配置中去
public $class = 'frontend\models\VersionControl';
public function getVersion()
{
return Yii::$app->getRequest()->getHeaders()->get($this->versionParam);
}
public function getActionMap()
{
if ($this->actionMap === null) {
$version = $this->getVersion();
$now = '';
$action_map = [];
$version_map = Yii::$app->params['version_map'] ?? [];
foreach ($version_map as $v => $map) {
if ($version >= $v) {
if ($v >= $now) {
$action_map = ArrayHelper::merge($map, $action_map);
} else {
$action_map = ArrayHelper::merge($action_map, $map);
}
$now = $v;
}
}
$controller = Yii::$app->controller->id;
$this->actionMap = $action_map[$controller] ?? [];
}
return $this->actionMap;
}
public function convertActionMap() {
$action_map = $this->getActionMap();
foreach ($action_map as $key => $map) {
$action_map[$key] = [
'class' => $this->class,
'action' => $map,
];
}
return $action_map;
}
}
VersionControl的实现
class VersionControl extends Action
{
public $action;
public function run()
{
// 只是一层跳转从端上访问的action跳到别的action
return $this->controller->runAction($this->action);
}
}
Params的配置
'version_map' => [
'1.1.1' => [ // 版本
'login' => [ // 控制器id
'index' => 'index1', // 旧action => 新action
],
],
],