Skip to content

Commit 48d452b

Browse files
committed
Support both positional and named parameters
1 parent 0efd86c commit 48d452b

File tree

11 files changed

+182
-56
lines changed

11 files changed

+182
-56
lines changed

docs/basic/bean-parameters.md

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,16 @@
22

33
Bean instances can be parameterized by a given configuration. To access the configuration add a `#[Parameter]` attribute to your Bean method.
44

5-
The `#[Parameter(name: 'paramName', key: 'config.key')]` attribute requires at least the `param` (which must match a param name of the Bean method) and the `key` which will be used to look for in the configuration array.
5+
Configuration parameters can be passed to the Bean configuration method as [named](https://www.php.net/manual/en/functions.arguments.php#functions.named-arguments)
6+
or as positional arguments. A `Parameter` will be used as a named argument when the `name` argument is set.
67

7-
In the following example the value of configuration key `configKey` gets passed to the bean configuation for the argument named `$test`.
8-
Configuration parameters are passed to the bean configuration method using [named arguments](https://www.php.net/manual/en/functions.arguments.php#functions.named-arguments):
8+
So `#[Parameter(name: 'argName', key: 'config.key)]` is a named parameter whereas `#[Parameter(key: 'config.key')]` is a positional parameter.
9+
As one might expect, the order of the positional parameters matter. Therefore, the recommended way of configuring parameters is using named parameters.
10+
Named and positional parameters can be mixed.
11+
12+
The `#[Parameter]` attribute requires at least `key` which will be used to look for in the configuration array.
13+
14+
In the following example the value of configuration key `configKey` gets passed to the Bean configuration for the argument named `$test`.
915

1016
```php
1117
<?php
@@ -19,13 +25,24 @@ use bitExpert\Disco\Helper\SampleService;
1925
class MyConfiguration
2026
{
2127
#[Bean]
22-
#[Parameter(name: 'test', key: 'configKey')]
28+
#[Parameter(name: 'test', key: 'configKey1')]
2329
public function mySampleService(string $test = '') : SampleService
2430
{
2531
$service = new SampleService();
2632
$service->setTest($test);
2733
return $service;
2834
}
35+
36+
#[Bean]
37+
#[Parameter(name: 'anotherTest', key: 'configKey2')]
38+
#[Parameter(key: 'configKey1')]
39+
public function mySampleService(string $test = '', string $anotherTest = '') : SampleService
40+
{
41+
$service = new SampleService();
42+
$service->setTest($test);
43+
$service->setAnotherTest($anotherTest);
44+
return $service;
45+
}
2946
}
3047
```
3148

@@ -34,7 +51,7 @@ The configuration array gets passed to the `\bitExpert\Disco\AnnotationBeanFacto
3451
```php
3552
<?php
3653

37-
$parameters = ['configKey' => 'This is a test.'];
54+
$parameters = ['configKey1' => 'This is a test.' 'configKey2' => 'This is another test.'];
3855

3956
$beanFactory = new \bitExpert\Disco\AnnotationBeanFactory(
4057
MyConfiguration::class,
@@ -45,6 +62,7 @@ $beanFactory = new \bitExpert\Disco\AnnotationBeanFactory(
4562
$sampleService = $beanFactory->get('mySampleService');
4663

4764
echo $sampleService->test; // Output: This is a test.
65+
echo $sampleService->anotherTest; // Output: This is another test.
4866
```
4967

5068
## Default Parameter Values

src/bitExpert/Disco/AnnotationBeanFactory.php

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,13 @@ class AnnotationBeanFactory implements BeanFactory
3232
*
3333
* @param class-string<Object> $configClassName
3434
* @param array<string, mixed> $parameters
35-
* @param BeanFactoryConfiguration $config
35+
* @param BeanFactoryConfiguration|null $config
3636
*/
3737
public function __construct(
3838
string $configClassName,
3939
array $parameters = [],
4040
BeanFactoryConfiguration $config = null
41-
)
42-
{
41+
) {
4342
if ($config === null) {
4443
$config = new BeanFactoryConfiguration(sys_get_temp_dir());
4544
}

src/bitExpert/Disco/Annotations/Parameter.php

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,37 +24,37 @@
2424
#[Attribute(Attribute::TARGET_METHOD | Attribute::IS_REPEATABLE)]
2525
final class Parameter
2626
{
27-
private string $name;
28-
2927
private string $key;
3028

29+
private ?string $name;
30+
3131
private mixed $defaultValue;
3232

3333
private bool $required;
3434

3535
/**
36-
* @param string $name
3736
* @param string $key
3837
* @param bool $required
39-
* @param mixed|null $default
38+
* @param mixed $default
39+
* @param string|null $name
4040
*/
41-
public function __construct(string $name, string $key, bool $required = true, mixed $default = null)
41+
public function __construct(string $key, bool $required = true, mixed $default = null, ?string $name = null)
4242
{
43-
Assert::minLength($name, 1);
4443
Assert::minLength($key, 1);
44+
Assert::nullOrMinLength($name, 1);
4545

46-
$this->name = $name;
4746
$this->key = $key;
47+
$this->name = $name;
4848
$this->defaultValue = $default;
4949
$this->required = $required;
5050
}
5151

5252
/**
53-
* Return the name of the parameter
53+
* Return the name of the argument or null in case of a positioned argument
5454
*
55-
* @return string
55+
* @return string|null
5656
*/
57-
public function getName(): string
57+
public function getName(): ?string
5858
{
5959
return $this->name;
6060
}

src/bitExpert/Disco/BeanFactoryConfiguration.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -144,10 +144,7 @@ public function getProxyManagerConfiguration(): Configuration
144144
{
145145
$proxyManagerConfiguration = new Configuration();
146146
$proxyManagerConfiguration->setProxiesTargetDir($this->proxyTargetDir);
147-
148-
if ($this->proxyWriterGenerator instanceof GeneratorStrategyInterface) {
149-
$proxyManagerConfiguration->setGeneratorStrategy($this->proxyWriterGenerator);
150-
}
147+
$proxyManagerConfiguration->setGeneratorStrategy($this->proxyWriterGenerator);
151148

152149
if ($this->proxyAutoloader instanceof AutoloaderInterface) {
153150
$proxyManagerConfiguration->setProxyAutoloader($this->proxyAutoloader);

src/bitExpert/Disco/Proxy/Configuration/MethodGenerator/ParameterAwareMethodGenerator.php

Lines changed: 26 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,10 @@ protected static function convertMethodParamsToString(
3232
array $methodParameters,
3333
GetParameter $parameterValuesMethod
3434
): string {
35-
$parameters = [];
35+
$positionalArgs = [];
36+
$namedArgs = [];
37+
3638
foreach ($methodParameters as $methodParameter) {
37-
/** @var Parameter $methodParameter */
3839
$defaultValue = $methodParameter->getDefaultValue();
3940
switch (\gettype($defaultValue)) {
4041
case 'string':
@@ -50,12 +51,32 @@ protected static function convertMethodParamsToString(
5051
break;
5152
}
5253

53-
$template = ($defaultValue === '') ? '$this->%s("%s", %s)' : '$this->%s("%s", %s, %s)';
5454
$required = $methodParameter->isRequired() ? 'true' : 'false';
5555
$methodName = $parameterValuesMethod->getName();
56-
$parameters[] = \sprintf($template, $methodName, $methodParameter->getKey(), $required, $defaultValue);
56+
$argName = $methodParameter->getName();
57+
58+
if (null === $argName) {
59+
$template = ($defaultValue === '') ? '$this->%s("%s", %s)' : '$this->%s("%s", %s, %s)';
60+
$positionalArgs[] = \sprintf(
61+
$template,
62+
$methodName,
63+
$methodParameter->getKey(),
64+
$required,
65+
$defaultValue
66+
);
67+
} else {
68+
$template = ($defaultValue === '') ? '%s: $this->%s("%s", %s)' : '%s: $this->%s("%s", %s, %s)';
69+
$namedArgs[] = \sprintf(
70+
$template,
71+
$argName,
72+
$methodName,
73+
$methodParameter->getKey(),
74+
$required,
75+
$defaultValue
76+
);
77+
}
5778
}
5879

59-
return \implode(', ', $parameters);
80+
return \implode(', ', [...$positionalArgs, ...$namedArgs]);
6081
}
6182
}

tests/bitExpert/Disco/AnnotationBeanFactoryUnitTest.php

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,14 +260,15 @@ public function beanFactoryPostProcessorCanBeConfiguredWithParameterizedDependen
260260
{
261261
$this->beanFactory = new AnnotationBeanFactory(
262262
BeanConfigurationWithPostProcessorAndParameterizedDependency::class,
263-
['test' => 'injectedValue']
263+
['configKey1' => 'injectedValue1', 'configKey2' => 'injectedValue2']
264264
);
265265
BeanFactoryRegistry::register($this->beanFactory);
266266

267267
/** @var SampleService $bean */
268268
$bean = $this->beanFactory->get('nonSingletonNonLazyRequestBean');
269269
self::assertInstanceOf(stdClass::class, $bean->test);
270-
self::assertEquals('injectedValue', $bean->test->property);
270+
self::assertEquals('injectedValue1', $bean->test->property1);
271+
self::assertEquals('injectedValue2', $bean->test->property2);
271272
}
272273

273274
/**
@@ -277,14 +278,62 @@ public function parameterPassedToBeanFactoryGetsInjectedInBean(): void
277278
{
278279
$this->beanFactory = new AnnotationBeanFactory(
279280
BeanConfigurationWithParameters::class,
280-
['test' => 'injectedValue']
281+
['configKey' => 'injectedValue']
281282
);
282283
BeanFactoryRegistry::register($this->beanFactory);
283284

284285
$bean = $this->beanFactory->get('sampleServiceWithParam');
285286
self::assertEquals('injectedValue', $bean->test);
286287
}
287288

289+
/**
290+
* @test
291+
*/
292+
public function parametersPassedToBeanFactoryGetsInjectedInBeanWithPositionalParams(): void
293+
{
294+
$this->beanFactory = new AnnotationBeanFactory(
295+
BeanConfigurationWithParameters::class,
296+
['configKey1' => 'injectedValue1', 'configKey2' => 'injectedValue2']
297+
);
298+
BeanFactoryRegistry::register($this->beanFactory);
299+
300+
$bean = $this->beanFactory->get('sampleServiceWithPositionalParams');
301+
self::assertEquals('injectedValue1', $bean->test);
302+
self::assertEquals('injectedValue2', $bean->anotherTest);
303+
}
304+
305+
/**
306+
* @test
307+
*/
308+
public function parametersPassedToBeanFactoryGetsInjectedInBeanWithNamedParams(): void
309+
{
310+
$this->beanFactory = new AnnotationBeanFactory(
311+
BeanConfigurationWithParameters::class,
312+
['configKey1' => 'injectedValue1', 'configKey2' => 'injectedValue2']
313+
);
314+
BeanFactoryRegistry::register($this->beanFactory);
315+
316+
$bean = $this->beanFactory->get('sampleServiceWithNamedParams');
317+
self::assertEquals('injectedValue1', $bean->test);
318+
self::assertEquals('injectedValue2', $bean->anotherTest);
319+
}
320+
321+
/**
322+
* @test
323+
*/
324+
public function parametersPassedToBeanFactoryGetsInjectedInBeanWithMixedPositionalAndNamedParams(): void
325+
{
326+
$this->beanFactory = new AnnotationBeanFactory(
327+
BeanConfigurationWithParameters::class,
328+
['configKey1' => 'injectedValue1', 'configKey2' => 'injectedValue2']
329+
);
330+
BeanFactoryRegistry::register($this->beanFactory);
331+
332+
$bean = $this->beanFactory->get('sampleServiceWithMixedPositionalAndNamedParams');
333+
self::assertEquals('injectedValue1', $bean->test);
334+
self::assertEquals('injectedValue2', $bean->anotherTest);
335+
}
336+
288337
/**
289338
* @test
290339
*/
@@ -293,7 +342,7 @@ public function nestedParameterKeyPassedToBeanFactoryGetsInjectedInBean(): void
293342
$this->beanFactory = new AnnotationBeanFactory(
294343
BeanConfigurationWithParameters::class,
295344
[
296-
'test' => [
345+
'config' => [
297346
'nested' => [
298347
'key' => 'injectedValue'
299348
]

tests/bitExpert/Disco/Annotations/ParameterUnitTest.php

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ public function emptyNameWillThrowAnnotationException(): void
2828
{
2929
$this->expectException(InvalidArgumentException::class);
3030

31-
new Parameter('', 'myParam');
31+
new Parameter(key: 'myParam', name: '');
3232
}
3333

3434
/**
@@ -38,25 +38,25 @@ public function emptyKeyWillThrowAnnotationException(): void
3838
{
3939
$this->expectException(InvalidArgumentException::class);
4040

41-
new Parameter('name', '');
41+
new Parameter(key: '');
4242
}
4343

4444
/**
4545
* @test
4646
*/
4747
public function nameIsSet(): void
4848
{
49-
$parameter = new Parameter(name: 'paramName', key: 'key');
49+
$parameter = new Parameter(name: 'argName', key: 'key');
5050

51-
self::assertSame('paramName', $parameter->getName());
51+
self::assertSame('argName', $parameter->getName());
5252
}
5353

5454
/**
5555
* @test
5656
*/
5757
public function keyIsSet(): void
5858
{
59-
$parameter = new Parameter(name: 'paramName', key: 'key');
59+
$parameter = new Parameter(name: 'argName', key: 'key');
6060

6161
self::assertSame('key', $parameter->getKey());
6262
}
@@ -78,7 +78,7 @@ public function defaultValueDefaultsToNull(): void
7878
*/
7979
public function defaultValueIsParsed(mixed $defaultValue): void
8080
{
81-
$parameter = new Parameter(name: 'paramName', key: 'myParam', default: $defaultValue);
81+
$parameter = new Parameter(name: 'argName', key: 'myParam', default: $defaultValue);
8282

8383
self::assertSame($defaultValue, $parameter->getDefaultValue());
8484
}
@@ -88,7 +88,7 @@ public function defaultValueIsParsed(mixed $defaultValue): void
8888
*/
8989
public function requireDefaultsToTrue(): void
9090
{
91-
$parameter = new Parameter(name: 'paramName', key: 'myParam');
91+
$parameter = new Parameter(name: 'argName', key: 'myParam');
9292

9393
self::assertTrue($parameter->isRequired());
9494
}
@@ -100,7 +100,7 @@ public function requireDefaultsToTrue(): void
100100
*/
101101
public function requireIsParsed(bool $requireValue): void
102102
{
103-
$parameter = new Parameter(name: 'paramName', key: 'myParam', required: $requireValue);
103+
$parameter = new Parameter(name: 'argName', key: 'myParam', required: $requireValue);
104104

105105
self::assertSame($requireValue, $parameter->isRequired());
106106
}

0 commit comments

Comments
 (0)