diff --git a/lib/internal/Magento/Framework/ObjectManager/Factory/AbstractFactory.php b/lib/internal/Magento/Framework/ObjectManager/Factory/AbstractFactory.php index b57f4665aff21..545a06f3d9480 100644 --- a/lib/internal/Magento/Framework/ObjectManager/Factory/AbstractFactory.php +++ b/lib/internal/Magento/Framework/ObjectManager/Factory/AbstractFactory.php @@ -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); diff --git a/lib/internal/Magento/Framework/ObjectManager/Factory/Compiled.php b/lib/internal/Magento/Framework/ObjectManager/Factory/Compiled.php index b219d93b0f0fa..2c98cc3ee4c4d 100644 --- a/lib/internal/Magento/Framework/ObjectManager/Factory/Compiled.php +++ b/lib/internal/Magento/Framework/ObjectManager/Factory/Compiled.php @@ -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 @@ -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_']); diff --git a/setup/src/Magento/Setup/Module/Di/Compiler/ArgumentsResolver.php b/setup/src/Magento/Setup/Module/Di/Compiler/ArgumentsResolver.php index 7a6d34fbcbe07..1b7b277164149 100644 --- a/setup/src/Magento/Setup/Module/Di/Compiler/ArgumentsResolver.php +++ b/setup/src/Magento/Setup/Module/Di/Compiler/ArgumentsResolver.php @@ -59,6 +59,15 @@ class ArgumentsResolver '_vac_' => true, ]; + /** + * Variadic pattern used for configuration + * + * @var array + */ + private $variadicPattern = [ + '_vdic_' => [], + ]; + /** * Configured argument pattern used for configuration * @@ -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()); @@ -107,8 +131,10 @@ public function getResolvedConstructorArguments($instanceType, $constructor) $constructorArgument ); } + $arguments[$constructorArgument->getName()] = $argument; } + return $arguments; } diff --git a/setup/src/Magento/Setup/Module/Di/Compiler/ConstructorArgument.php b/setup/src/Magento/Setup/Module/Di/Compiler/ConstructorArgument.php index 051e1cd4bfaba..2f65683454fb8 100644 --- a/setup/src/Magento/Setup/Module/Di/Compiler/ConstructorArgument.php +++ b/setup/src/Magento/Setup/Module/Di/Compiler/ConstructorArgument.php @@ -29,6 +29,11 @@ class ConstructorArgument */ private $defaultValue; + /** + * @var bool + */ + private $isVariadic; + /** * @param array $configuration */ @@ -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]; } /** @@ -79,4 +85,14 @@ public function getDefaultValue() { return $this->defaultValue; } + + /** + * Returns argument is variadic + * + * @return bool + */ + public function isVariadic(): bool + { + return $this->isVariadic; + } } diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/ArgumentsResolverTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/ArgumentsResolverTest.php index 8e22200b4bc05..b2f9fa0bb018d 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/ArgumentsResolverTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/ArgumentsResolverTest.php @@ -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') @@ -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()) diff --git a/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/ConstructorArgumentTest.php b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/ConstructorArgumentTest.php index c4ca51858c941..312e12cbb8733 100644 --- a/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/ConstructorArgumentTest.php +++ b/setup/src/Magento/Setup/Test/Unit/Module/Di/Compiler/ConstructorArgumentTest.php @@ -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()); } }