Внедрение зависимостей в InlineAction

Предварительное обсуждение найденных ошибок перед отправкой их авторам фреймворка, а также внесение новых предложений.
Ответить
yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Внедрение зависимостей в InlineAction

Сообщение yiiliveext »

Собственно вопрос в том, почему это не реализовано. Рефлексия там уже есть, затрат почти никаких, добавить десяток строк.
Тесты не писал, но вроде все работает так.

Код: Выделить всё

public function bindActionParams($action, $params)
    {
        if ($action instanceof InlineAction) {
            $method = new \ReflectionMethod($this, $action->actionMethod);
        } else {
            $method = new \ReflectionMethod($action, 'run');
        }

        $args = [];
        $missing = [];
        $actionParams = [];
        foreach ($method->getParameters() as $param) {
            $name = $param->getName();
            $class = $param->getClass();
            if (array_key_exists($name, $params) && $class === null) {
                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();
            } else {
                if ($class !== null) {
                    $className = $class->getName();
                    try {
                        $args[] = Yii::$container->get($className);
                    } catch (NotInstantiableException $e) {
                        $missing[] = $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;
    }

Аватара пользователя
samdark
Администратор
Сообщения: 9334
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Внедрение зависимостей в InlineAction

Сообщение samdark »

На момент отклонения похожего предложения команда Yii считала, что это не очень хорошая идея. В Yii 3 я сделал. Вероятно, будет нормально внедрить это в Yii 2 как штуку, которая сделает переход чуть менее болезненным.

yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Внедрение зависимостей в InlineAction

Сообщение yiiliveext »

samdark писал(а):
2019.12.09, 00:12
На момент отклонения похожего предложения команда Yii считала, что это не очень хорошая идея. В Yii 3 я сделал. Вероятно, будет нормально внедрить это в Yii 2 как штуку, которая сделать переход чуть менее болезненным.
Если делать в Yii2 приложение полностью отказавшись от сервис-локатора, то вещь весьма полезная, позволяет не грузить лишние зависимости в конструкторе контроллера. Хоть можно, конечно, отнаследоваться от \yii\web\Controller и подменить метод, но перспективы такого подхода непонятны, лучше если это будет делать фреймворк.

yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Внедрение зависимостей в InlineAction

Сообщение yiiliveext »

Посмотрел, php вроде как кеширует рефлексию по одному и тому же объекту, так что можно сделать более корректный вариант.
\yii\web\Controller

Код: Выделить всё

public function bindActionParams($action, $params)
    {
        if ($action instanceof InlineAction) {
            $method = new \ReflectionMethod($this, $action->actionMethod);
        } else {
            $method = new \ReflectionMethod($action, 'run');
        }

        $args = [];
        $missing = [];
        $actionParams = [];
        foreach ($method->getParameters() as $param) {
            $name = $param->getName();
            $class = $param->getClass();
            if ($class === null) {
                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();
                } else {
                    $missing[] = $name;
                }
            }
        }

        if (!empty($missing)) {
            throw new BadRequestHttpException(Yii::t('yii', 'Missing required parameters: {params}', [
                'params' => implode(', ', $missing),
            ]));
        }

        $this->actionParams = $actionParams;

        return $args;
    }


\yii\baser\InlineAction

Код: Выделить всё

public function runWithParams($params)
    {
        $args = $this->controller->bindActionParams($this, $params);
        Yii::debug('Running action: ' . get_class($this->controller) . '::' . $this->actionMethod . '()', __METHOD__);
        if (Yii::$app->requestedParams === null) {
            Yii::$app->requestedParams = $args;
        }

        return Yii::$container->invoke([$this->controller, $this->actionMethod], $args);
    }
Ну и аналогично заменить в \yii\base\Action и \yii\console\Controller


Аватара пользователя
samdark
Администратор
Сообщения: 9334
Зарегистрирован: 2009.04.02, 13:46
Откуда: Воронеж
Контактная информация:

Re: Внедрение зависимостей в InlineAction

Сообщение samdark »

Pull request с тестами будет в тему.

yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Внедрение зависимостей в InlineAction

Сообщение yiiliveext »

samdark писал(а):
2019.12.09, 23:38
Pull request с тестами будет в тему.
Хорошо, сделаю.

Tommi
Сообщения: 87
Зарегистрирован: 2013.08.01, 13:44

Re: Внедрение зависимостей в InlineAction

Сообщение Tommi »

Передумали?

yiiliveext
Сообщения: 910
Зарегистрирован: 2019.08.13, 01:49

Re: Внедрение зависимостей в InlineAction

Сообщение yiiliveext »

Tommi писал(а):
2020.01.10, 17:21
Передумали?
Нет, есть еще ряд доработок кроме этой, на которые надо дописать тесты, и потом скопом несколько пул-риквестов сделаю.
До конца следующей недели думаю управлюсь.

Tommi
Сообщения: 87
Зарегистрирован: 2013.08.01, 13:44

Re: Внедрение зависимостей в InlineAction

Сообщение Tommi »

yiiliveext писал(а):
2020.01.11, 23:23
До конца следующей недели думаю управлюсь.
управился? 4 месяца прошло

Ответить