Browse Source

Fix #19031: Fix displaying console help for parameters with declared types

tags/2.0.44
Anton 3 years ago committed by GitHub
parent
commit
766cf701e5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      framework/CHANGELOG.md
  2. 89
      framework/console/Controller.php
  3. 22
      tests/framework/console/ControllerTest.php
  4. 11
      tests/framework/console/FakeController.php
  5. 2
      tests/framework/console/controllers/HelpControllerTest.php

1
framework/CHANGELOG.md

@ -31,6 +31,7 @@ Yii Framework 2 Change Log
- Bug #18988: Fix default value of `yii\console\controllers\MessageController::$translator` (WinterSilence)
- Bug #18993: Load defaults by `attributes()` in `yii\db\ActiveRecord::loadDefaultValues()` (WinterSilence)
- Bug #19021: Fix return type in PhpDoc `yii\db\Migration` functions `up()`, `down()`, `safeUp()` and `safeDown()` (WinterSilence, rhertogh)
- Bug #19031: Fix displaying console help for parameters with declared types (WinterSilence)
- Bug #19030: Add DI container usage to `yii\base\Widget::end()` (papppeter)

89
framework/console/Controller.php

@ -542,60 +542,69 @@ class Controller extends \yii\base\Controller
* The returned value should be an array. The keys are the argument names, and the values are
* the corresponding help information. Each value must be an array of the following structure:
*
* - required: boolean, whether this argument is required.
* - type: string, the PHP type of this argument.
* - default: string, the default value of this argument
* - comment: string, the comment of this argument
* - required: bool, whether this argument is required
* - type: string|null, the PHP type(s) of this argument
* - default: mixed, the default value of this argument
* - comment: string, the description of this argument
*
* The default implementation will return the help information extracted from the doc-comment of
* the parameters corresponding to the action method.
* The default implementation will return the help information extracted from the Reflection or
* DocBlock of the parameters corresponding to the action method.
*
* @param Action $action
* @param Action $action the action instance
* @return array the help information of the action arguments
*/
public function getActionArgsHelp($action)
{
$method = $this->getActionMethodReflection($action);
$tags = $this->parseDocCommentTags($method);
$params = isset($tags['param']) ? (array) $tags['param'] : [];
$tags['param'] = isset($tags['param']) ? (array) $tags['param'] : [];
$phpDocParams = [];
foreach ($tags['param'] as $i => $tag) {
if (preg_match('/^(?<type>\S+)(\s+\$(?<name>\w+))?(?<comment>.*)/us', $tag, $matches) === 1) {
$key = empty($matches['name']) ? $i : $matches['name'];
$phpDocParams[$key] = ['type' => $matches['type'], 'comment' => $matches['comment']];
}
}
unset($tags);
$args = [];
/** @var \ReflectionParameter $reflection */
foreach ($method->getParameters() as $i => $reflection) {
if (PHP_VERSION_ID >= 80000) {
$class = $reflection->getType();
} else {
$class = $reflection->getClass();
}
if ($class !== null) {
continue;
/** @var \ReflectionParameter $parameter */
foreach ($method->getParameters() as $i => $parameter) {
$type = null;
$comment = '';
if (PHP_MAJOR_VERSION > 5 && $parameter->hasType()) {
$reflectionType = $parameter->getType();
if (PHP_VERSION_ID >= 70100) {
$types = method_exists($reflectionType, 'getTypes') ? $reflectionType->getTypes() : [$reflectionType];
foreach ($types as $key => $reflectionType) {
$types[$key] = $reflectionType->getName();
}
$type = implode('|', $types);
} else {
$type = (string) $reflectionType;
}
}
$name = $reflection->getName();
$tag = isset($params[$i]) ? $params[$i] : '';
if (preg_match('/^(\S+)\s+(\$\w+\s+)?(.*)/s', $tag, $matches)) {
$type = $matches[1];
$comment = $matches[3];
} else {
$type = null;
$comment = $tag;
// find PhpDoc tag by property name or position
$key = isset($phpDocParams[$parameter->name]) ? $parameter->name : (isset($phpDocParams[$i]) ? $i : null);
if ($key !== null) {
$comment = $phpDocParams[$key]['comment'];
if ($type === null && !empty($phpDocParams[$key]['type'])) {
$type = $phpDocParams[$key]['type'];
}
}
if ($reflection->isDefaultValueAvailable()) {
$args[$name] = [
'required' => false,
'type' => $type,
'default' => $reflection->getDefaultValue(),
'comment' => $comment,
];
} else {
$args[$name] = [
'required' => true,
'type' => $type,
'default' => null,
'comment' => $comment,
];
// if type still not detected, then using type of default value
if ($type === null && $parameter->isDefaultValueAvailable() && $parameter->getDefaultValue() !== null) {
$type = gettype($parameter->getDefaultValue());
}
$args[$parameter->name] = [
'required' => !$parameter->isOptional(),
'type' => $type,
'default' => $parameter->isDefaultValueAvailable() ? $parameter->getDefaultValue() : null,
'comment' => $comment,
];
}
return $args;

22
tests/framework/console/ControllerTest.php

@ -286,18 +286,24 @@ class ControllerTest extends TestCase
$this->assertEquals(FakeHelpController::getActionIndexLastCallParams(), ['news/posts/index']);
}
/**
* Tests if action help does not include (class) type hinted arguments.
* @see #10372
* @see https://github.com/yiisoft/yii2/issues/19028
*/
public function testHelpSkipsTypeHintedArguments()
public function testGetActionArgsHelp()
{
$controller = new FakeController('fake', Yii::$app);
$help = $controller->getActionArgsHelp($controller->createAction('with-complex-type-hint'));
$this->assertArrayNotHasKey('typedArgument', $help);
$this->assertArrayHasKey('simpleArgument', $help);
$help = $controller->getActionArgsHelp($controller->createAction('aksi2'));
$this->assertArrayHasKey('values', $help);
if (PHP_MAJOR_VERSION > 5) {
// declared type
$this->assertEquals('array', $help['values']['type']);
} else {
$this->markTestSkipped('Can not test declared type of parameter $values on PHP < 7.0');
}
$this->assertArrayHasKey('value', $help);
// PHPDoc type
$this->assertEquals('string', $help['value']['type']);
}
public function testGetActionHelpSummaryOnNull()

11
tests/framework/console/FakeController.php

@ -57,9 +57,13 @@ class FakeController extends Controller
public function actionAksi1($fromParam, $other = 'default')
{
return[$fromParam, $other];
return [$fromParam, $other];
}
/**
* @param string $value the string value
* @return array
*/
public function actionAksi2(array $values, $value)
{
return [$values, $value];
@ -89,11 +93,6 @@ class FakeController extends Controller
return func_get_args();
}
public function actionWithComplexTypeHint(self $typedArgument, $simpleArgument)
{
return $simpleArgument;
}
public function actionStatus($status = 0)
{
return $status;

2
tests/framework/console/controllers/HelpControllerTest.php

@ -123,7 +123,7 @@ STRING
]);
$result = Console::stripAnsiFormat($this->runControllerAction('list-action-options', ['action' => 'help/list-action-options']));
$this->assertEqualsWithoutLE(<<<'STRING'
action:route to action
action: route to action
--interactive: whether to run the command interactively.
--color: whether to enable ANSI color in the output.If not set, ANSI color will only be enabled for terminals that support it.

Loading…
Cancel
Save