Skip to content

Typed variadic arguments fail to be injected #30888

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: 2.4-develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,13 @@ private function getResolvedArgument(string $requestedType, array $parameter, ar
}

if ($isVariadic) {
return is_array($argument) ? $argument : [$argument];
$variadicArguments = is_array($argument) ? $argument : [$argument];

foreach ($variadicArguments as &$variadicArgument) {
$this->resolveArgument($variadicArgument, $paramType, $paramDefault, $paramName, $requestedType);
};

return $variadicArguments;
}

$this->resolveArgument($argument, $paramType, $paramDefault, $paramName, $requestedType);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ public function create($requestedType, array $arguments = [])
*
* Argument key meanings:
*
* _vdic_: variadic argument
* _i_: shared instance of a class or interface
* _ins_: non-shared instance of a class or interface
* _v_: non-array literal value
Expand All @@ -73,7 +74,21 @@ public function create($requestedType, array $arguments = [])
* _d_: default value in case environment variable specified by _a_ does not exist
*/
foreach ($args as $key => &$argument) {
if (isset($arguments[$key])) {
if (isset($argument['_vdic_'])) {
// Process variadic
if (isset($arguments[$key])) {
$argument = (array)$arguments[$key];
} else {
$argument = (array)$argument['_vdic_'];
$this->parseArray($argument);
}
unset($args[$key]);
if (count($argument)) {
array_push($args, ...array_values($argument));
}
// Variadic argument is always the last one
break;
} elseif (isset($arguments[$key])) {
$argument = $arguments[$key];
} elseif (isset($argument['_i_'])) {
$argument = $this->get($argument['_i_']);
Expand Down
26 changes: 26 additions & 0 deletions setup/src/Magento/Setup/Module/Di/Compiler/ArgumentsResolver.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,15 @@ class ArgumentsResolver
'_vac_' => true,
];

/**
* Variadic pattern used for configuration
*
* @var array
*/
private $variadicPattern = [
'_vdic_' => [],
];

/**
* Configured argument pattern used for configuration
*
Expand Down Expand Up @@ -89,11 +98,26 @@ public function getResolvedConstructorArguments($instanceType, $constructor)
if (!$constructor) {
return null;
}

$configuredArguments = $this->getConfiguredArguments($instanceType);

$arguments = [];
/** @var ConstructorArgument $constructorArgument */
foreach ($constructor as $constructorArgument) {
if ($constructorArgument->isVariadic()) {
$argument = $this->variadicPattern;
$variadicArguments = $configuredArguments[$constructorArgument->getName()] ?? [];

foreach ($variadicArguments as $variadicArgument) {
$argument['_vdic_'][] = $this->getConfiguredArgument($variadicArgument, $constructorArgument);
}

$arguments[$constructorArgument->getName()] = $argument;

// Variadic argument is always the last one
break;
}

$argument = $this->getNonObjectArgument(null);
if (!$constructorArgument->isRequired()) {
$argument = $this->getNonObjectArgument($constructorArgument->getDefaultValue());
Expand All @@ -107,8 +131,10 @@ public function getResolvedConstructorArguments($instanceType, $constructor)
$constructorArgument
);
}

$arguments[$constructorArgument->getName()] = $argument;
}

return $arguments;
}

Expand Down
16 changes: 16 additions & 0 deletions setup/src/Magento/Setup/Module/Di/Compiler/ConstructorArgument.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ class ConstructorArgument
*/
private $defaultValue;

/**
* @var bool
*/
private $isVariadic;

/**
* @param array $configuration
*/
Expand All @@ -38,6 +43,7 @@ public function __construct(array $configuration)
$this->type = $configuration[1];
$this->isRequired = $configuration[2];
$this->defaultValue = $configuration[3];
$this->isVariadic = $configuration[4];
}

/**
Expand Down Expand Up @@ -79,4 +85,14 @@ public function getDefaultValue()
{
return $this->defaultValue;
}

/**
* Returns argument is variadic
*
* @return bool
*/
public function isVariadic(): bool
{
return $this->isVariadic;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ public function testGetResolvedArgumentsConstructorFormat()
$expectedResultDefault = $this->getResolvedSimpleConfigExpectation();

$constructor = [
new ConstructorArgument(['type_dependency', 'Type\Dependency', true, null]),
new ConstructorArgument(['type_dependency_shared', 'Type\Dependency\Shared', true, null]),
new ConstructorArgument(['value', null, false, 'value']),
new ConstructorArgument(['value_array', null, false, ['default_value1', 'default_value2']]),
new ConstructorArgument(['value_null', null, false, null]),
new ConstructorArgument(['type_dependency', 'Type\Dependency', true, null, false]),
new ConstructorArgument(['type_dependency_shared', 'Type\Dependency\Shared', true, null, false]),
new ConstructorArgument(['value', null, false, 'value', false]),
new ConstructorArgument(['value_array', null, false, ['default_value1', 'default_value2', false]]),
new ConstructorArgument(['value_null', null, false, null, false]),
];
$this->diContainerConfig->expects($this->any())
->method('isShared')
Expand Down Expand Up @@ -68,13 +68,13 @@ public function testGetResolvedArgumentsConstructorConfiguredFormat()
$expectedResultConfigured = $this->getResolvedConfigurableConfigExpectation();

$constructor = [
new ConstructorArgument(['type_dependency_configured', 'Type\Dependency', true, null]),
new ConstructorArgument(['type_dependency_shared_configured', 'Type\Dependency\Shared', true, null]),
new ConstructorArgument(['global_argument', null, false, null]),
new ConstructorArgument(['global_argument_def', null, false, []]),
new ConstructorArgument(['value_configured', null, false, 'value']),
new ConstructorArgument(['value_array_configured', null, false, []]),
new ConstructorArgument(['value_null', null, false, null]),
new ConstructorArgument(['type_dependency_configured', 'Type\Dependency', true, null, false]),
new ConstructorArgument(['type_dependency_shared_configured', 'Type\Dependency\Shared', true, null, false]),
new ConstructorArgument(['global_argument', null, false, null, false]),
new ConstructorArgument(['global_argument_def', null, false, [], false]),
new ConstructorArgument(['value_configured', null, false, 'value', false]),
new ConstructorArgument(['value_array_configured', null, false, [], false]),
new ConstructorArgument(['value_null', null, false, null, false]),
];

$this->diContainerConfig->expects($this->any())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ class ConstructorArgumentTest extends TestCase
{
public function testInterface()
{
$argument = ['configuration', 'array', true, null];
$argument = ['configuration', 'array', true, null, false];
$model = new ConstructorArgument($argument);
$this->assertEquals($argument[0], $model->getName());
$this->assertEquals($argument[1], $model->getType());
$this->assertTrue($model->isRequired());
$this->assertNull($model->getDefaultValue());
$this->assertFalse($model->isVariadic());
}
}