控制器方法的依赖注入实现 [ 2.0 版本 ]
当前控制器方法仅支持GET请求参数的自动注入。
Yii自身有服务定位及容器的支持,于是便想着在控制器方法中实现对象的自动注入,以达到这样的使用效果:
<?php
namespace app\controllers;
use app\models\User;
use app\components\Request;
use app\components\Controller;
class TestController extends Controller
{
public function actionIndex(User $user, Request $req)
{
echo $user->username;
echo $req === \Yii::$app->request ? 'ok' : 'some errors';
}
}
实现思路:
GET请求参数的自动注入,是通过\yii\web\Controller::bindActionParams
在实现,于是通过自定义的基础控制器,覆写该方法以实现。
<?php
namespace app\components;
use Yii;
use yii\db\ActiveRecord;
use yii\base\InlineAction;
use yii\web\NotFoundHttpException;
use yii\web\BadRequestHttpException;
/**
* Global base Controller
*/
abstract class Controller extends \yii\web\Controller
{
/**
* ActiveRecord 查询主键名
* @var string
*/
protected $arDiPrimaryKey = 'id';
/**
* @inheritDoc 覆写以实现方法依赖注入
* Binds the parameters to the action.
* This method is invoked by [[\yii\base\Action]] when it begins to run with the given parameters.
* This method will check the parameter names that the action requires and return
* the provided parameters according to the requirement. If there is any missing parameter,
* an exception will be thrown.
* @param \yii\base\Action $action the action to be bound with parameters
* @param array $params the parameters to be bound to the action
* @return array the valid parameters that the action can run with.
* @throws BadRequestHttpException if there are missing or invalid parameters.
*/
public function bindActionParams($action, $params)
{
if ($action instanceof InlineAction) {
$method = new \ReflectionMethod($this, $action->actionMethod);
} else {
$method = new \ReflectionMethod($action, 'run');
}
$args = [];
$missing = [];
$actionParams = [];
$classHint = null;
foreach ($method->getParameters() as $param) {
$name = $param->getName();
if (array_key_exists($name, $params)) {
if ($param->isArray()) {
$args[] = $actionParams[$name] = (array) $params[$name];
} elseif (!is_array($params[$name])) {
$args[] = $actionParams[$name] = $params[$name];
} else {
throw new BadRequestHttpException(Yii::t('yii', 'Invalid data received for parameter "{param}".', [
'param' => $name,
]));
}
unset($params[$name]);
} elseif ($param->isDefaultValueAvailable()) {
$args[] = $actionParams[$name] = $param->getDefaultValue();
} elseif ($classHint = $param->getClass()) {
if ($classHint->isSubclassOf(ActiveRecord::class)) {
$args[] = $actionParams[$name] =
$this->findModel($classHint->name, isset($params[$this->arDiPrimaryKey]) ? $params[$this->arDiPrimaryKey] : null);
} else {
foreach (Yii::$app->getComponents() as $compId => $component) {
if (isset($component['class']) && $component['class'] === $classHint->name) {
$actionParams[$name] = Yii::$app->get($compId);
break;
}
}
if (! isset($actionParams[$name])) {
$actionParams[$name] = Yii::createObject($classHint->name);
}
$args[] = $actionParams[$name];
}
} else {
$missing[] = $name;
}
}
if (!empty($missing)) {
throw new BadRequestHttpException(Yii::t('yii', 'Missing required parameters: {params}', [
'params' => implode(', ', $missing),
]));
}
$this->actionParams = $actionParams;
return $args;
}
/**
* Finds the ActiveRecord model based on its primary key value.
* If the model is not found, a 404 HTTP exception will be thrown.
* @param integer|string|null $pkValue
* @return ActiveRecord the loaded model
* @throws NotFoundHttpException if the model cannot be found
*/
protected function findModel($className, $pkValue)
{
if (null === $pkValue) {
return new $className();
}
if (null !== ($model = $className::findOne($pkValue))) {
return $model;
} else {
throw new NotFoundHttpException('The requested page does not exist.');
}
}
}
关键点在60行至76行。
代码很清楚,不过多解释了。
python
注册时间:2016-05-01
最后登录:2020-12-15
在线时长:18小时25分
最后登录:2020-12-15
在线时长:18小时25分
- 粉丝3
- 金钱3555
- 威望30
- 积分4035
共 0 条评论