Skip to content

Commit 58e1092

Browse files
authored
Deduct return type from environment variable processors (#346)
Fixes #345
1 parent 0fe09bf commit 58e1092

File tree

4 files changed

+77
-20
lines changed

4 files changed

+77
-20
lines changed

src/Handler/ParameterBagHandler.php

+7-19
Original file line numberDiff line numberDiff line change
@@ -42,30 +42,18 @@ public static function afterMethodCallAnalysis(AfterMethodCallAnalysisEvent $eve
4242
}
4343

4444
$argument = $expr->args[0]->value->value;
45+
4546
try {
46-
$parameter = self::$containerMeta->getParameter($argument);
47-
} catch (ParameterNotFoundException $e) {
47+
$parameterTypes = self::$containerMeta->guessParameterType($argument);
48+
} catch (ParameterNotFoundException) {
4849
// maybe emit ParameterNotFound issue
4950
return;
5051
}
5152

52-
// @todo find a better way to calculate return type
53-
switch (gettype($parameter)) {
54-
case 'string':
55-
$event->setReturnTypeCandidate(new Union([Atomic::create('string')]));
56-
break;
57-
case 'boolean':
58-
$event->setReturnTypeCandidate(new Union([Atomic::create('bool')]));
59-
break;
60-
case 'integer':
61-
$event->setReturnTypeCandidate(new Union([Atomic::create('int')]));
62-
break;
63-
case 'double':
64-
$event->setReturnTypeCandidate(new Union([Atomic::create('float')]));
65-
break;
66-
case 'array':
67-
$event->setReturnTypeCandidate(new Union([Atomic::create('array')]));
68-
break;
53+
if (null === $parameterTypes || [] === $parameterTypes) {
54+
return;
6955
}
56+
57+
$event->setReturnTypeCandidate(new Union(array_map(fn (string $parameterType): Atomic => Atomic::create($parameterType), $parameterTypes)));
7058
}
7159
}

src/Symfony/ContainerMeta.php

+38
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
use Symfony\Component\DependencyInjection\Argument\ServiceClosureArgument;
1010
use Symfony\Component\DependencyInjection\ContainerBuilder;
1111
use Symfony\Component\DependencyInjection\Definition;
12+
use Symfony\Component\DependencyInjection\EnvVarProcessor;
1213
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
14+
use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException;
1315
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
1416
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
1517
use Symfony\Component\DependencyInjection\Reference;
@@ -69,6 +71,29 @@ public function getParameter(string $key): mixed
6971
return $this->container->getParameter($key);
7072
}
7173

74+
/**
75+
* @throw ParameterNotFoundException
76+
*
77+
* @return ?array<string>
78+
*/
79+
public function guessParameterType(string $key): ?array
80+
{
81+
$parameter = $this->getParameter($key);
82+
83+
if (is_string($parameter) && str_starts_with($parameter, '%env(')) {
84+
return $this->envParameterType($parameter);
85+
}
86+
87+
return match (gettype($parameter)) {
88+
'string' => ['string'],
89+
'boolean' => ['bool'],
90+
'integer' => ['int'],
91+
'double' => ['float'],
92+
'array' => ['array'],
93+
default => null,
94+
};
95+
}
96+
7297
/**
7398
* @return array<string>
7499
*/
@@ -168,4 +193,17 @@ private function getDefinition(string $id): Definition
168193

169194
return $definition;
170195
}
196+
197+
private function envParameterType(string $envParameter): ?array
198+
{
199+
// extract bool from %env(bool:ENV_PARAM)%, string from %env(string:ENV_PARAM)%
200+
$type = preg_match('/^%env\((\w+):/', $envParameter, $matches) ? $matches[1] : null;
201+
202+
$envVarTypes = EnvVarProcessor::getProvidedTypes();
203+
if (!isset($envVarTypes[$type])) {
204+
return null;
205+
}
206+
207+
return explode('|', $envVarTypes[$type]);
208+
}
171209
}

tests/acceptance/container.xml

+6
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,12 @@
2121
</parameter>
2222
</parameter>
2323
</parameter>
24+
<parameter key="env_param_bool">%env(bool:ENV_PARAM)%</parameter>
25+
<parameter key="env_param_string">%env(string:ENV_PARAM)%</parameter>
26+
<parameter key="env_param_custom_type">%env(custom_type:ENV_PARAM)%</parameter>
27+
<parameter key="env_param_json">%env(json:ENV_PARAM)%</parameter>
28+
<parameter key="env_param_enum">%env(enum:ENV_PARAM)%</parameter>
29+
<parameter key="env_param_url">%env(url:ENV_PARAM)%</parameter>
2430
</parameters>
2531
<services>
2632
<service id="doctrine.orm.entity_manager" alias="doctrine.orm.default_entity_manager" public="true"/>

tests/unit/Symfony/ContainerMetaTest.php

+26-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,32 @@ public function testGetParameter(): void
117117
], $this->containerMeta->getParameter('nested_collection'));
118118
}
119119

120-
public function testGetParameterP(): void
120+
/**
121+
* @dataProvider guessParameterTypeProvider
122+
*/
123+
public function testGuessParameterType(?array $expectedTypes, string $parameterName): void
124+
{
125+
$this->assertSame($expectedTypes, $this->containerMeta->guessParameterType($parameterName));
126+
}
127+
128+
public function guessParameterTypeProvider(): iterable
129+
{
130+
yield [['string'], 'kernel.environment'];
131+
yield [['bool'], 'debug_enabled'];
132+
yield [['string'], 'version'];
133+
yield [['int'], 'integer_one'];
134+
yield [['float'], 'pi'];
135+
yield [['array'], 'collection1'];
136+
yield [['array'], 'nested_collection'];
137+
yield [['bool'], 'env_param_bool'];
138+
yield [['string'], 'env_param_string'];
139+
yield [null, 'env_param_custom_type'];
140+
yield [['array'], 'env_param_json'];
141+
yield [['BackedEnum'], 'env_param_enum'];
142+
yield [['array'], 'env_param_url'];
143+
}
144+
145+
public function testGetParameterNonExistent(): void
121146
{
122147
$this->expectException(ParameterNotFoundException::class);
123148
$this->containerMeta->getParameter('non_existent');

0 commit comments

Comments
 (0)