Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e3c72bb

Browse files
committed
Allow scalar configuration in PHP Configuration
1 parent 432c2ef commit e3c72bb

File tree

7 files changed

+112
-59
lines changed

7 files changed

+112
-59
lines changed

src/Symfony/Component/Config/Builder/ConfigBuilderGenerator.php

+53-42
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
use Symfony\Component\Config\Definition\ArrayNode;
1515
use Symfony\Component\Config\Definition\BaseNode;
1616
use Symfony\Component\Config\Definition\BooleanNode;
17+
use Symfony\Component\Config\Definition\Builder\ExprBuilder;
1718
use Symfony\Component\Config\Definition\ConfigurationInterface;
1819
use Symfony\Component\Config\Definition\EnumNode;
1920
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
@@ -141,8 +142,9 @@ private function handleArrayNode(ArrayNode $node, ClassBuilder $class, string $n
141142
$node->getName(),
142143
$this->getType($childClass->getFqcn(), $hasNormalizationClosures)
143144
);
145+
$nodeTypes = $this->getParameterTypes($node);
144146
$body = $hasNormalizationClosures ? '
145-
COMMENTpublic function NAME(mixed $value = []): CLASS|static
147+
COMMENTpublic function NAME(PARAM_TYPE $value = []): CLASS|static
146148
{
147149
if (!\is_array($value)) {
148150
$this->_usedProperties[\'PROPERTY\'] = true;
@@ -172,7 +174,12 @@ private function handleArrayNode(ArrayNode $node, ClassBuilder $class, string $n
172174
return $this->PROPERTY;
173175
}';
174176
$class->addUse(InvalidConfigurationException::class);
175-
$class->addMethod($node->getName(), $body, ['COMMENT' => $comment, 'PROPERTY' => $property->getName(), 'CLASS' => $childClass->getFqcn()]);
177+
$class->addMethod($node->getName(), $body, [
178+
'COMMENT' => $comment,
179+
'PROPERTY' => $property->getName(),
180+
'CLASS' => $childClass->getFqcn(),
181+
'PARAM_TYPE' => \in_array('mixed', $nodeTypes, true) ? 'mixed' : implode('|', $nodeTypes),
182+
]);
176183

177184
$this->buildNode($node, $childClass, $this->getSubNamespace($childClass));
178185
}
@@ -209,19 +216,21 @@ private function handlePrototypedArrayNode(PrototypedArrayNode $node, ClassBuild
209216
$methodName = $name;
210217
$hasNormalizationClosures = $this->hasNormalizationClosures($node) || $this->hasNormalizationClosures($prototype);
211218

212-
$parameterType = $this->getParameterType($prototype);
213-
if (null !== $parameterType || $prototype instanceof ScalarNode) {
219+
$nodeParameterTypes = $this->getParameterTypes($node);
220+
$prototypeParameterTypes = $this->getParameterTypes($prototype);
221+
if (!($prototype instanceof ArrayNode && (!$prototype instanceof PrototypedArrayNode || !$prototype->getPrototype() instanceof ScalarNode))) {
214222
$class->addUse(ParamConfigurator::class);
215223
$property = $class->addProperty($node->getName());
216224
if (null === $key = $node->getKeyAttribute()) {
217225
// This is an array of values; don't use singular name
226+
$nodeTypesWithoutArray = array_filter($nodeParameterTypes, static fn ($type) => 'array' !== $type);
218227
$body = '
219228
/**
220-
* @param PHPDOC_TYPE $value
229+
* @param ParamConfigurator|list<ParamConfigurator|PROTOTYPE_TYPE>EXTRA_TYPE $value
221230
*
222231
* @return $this
223232
*/
224-
public function NAME(TYPE $value): static
233+
public function NAME(PARAM_TYPE $value): static
225234
{
226235
$this->_usedProperties[\'PROPERTY\'] = true;
227236
$this->PROPERTY = $value;
@@ -231,8 +240,9 @@ public function NAME(TYPE $value): static
231240

232241
$class->addMethod($node->getName(), $body, [
233242
'PROPERTY' => $property->getName(),
234-
'TYPE' => $hasNormalizationClosures ? 'mixed' : 'ParamConfigurator|array',
235-
'PHPDOC_TYPE' => $hasNormalizationClosures ? 'mixed' : sprintf('ParamConfigurator|list<ParamConfigurator|%s>', '' === $parameterType ? 'mixed' : $parameterType),
243+
'PROTOTYPE_TYPE' => implode('|', $prototypeParameterTypes),
244+
'EXTRA_TYPE' => $nodeTypesWithoutArray ? '|'.implode('|', $nodeTypesWithoutArray) : '',
245+
'PARAM_TYPE' => \in_array('mixed', $nodeParameterTypes, true) ? 'mixed' : 'ParamConfigurator|'.implode('|', $nodeParameterTypes),
236246
]);
237247
} else {
238248
$body = '
@@ -249,7 +259,7 @@ public function NAME(string $VAR, TYPE $VALUE): static
249259

250260
$class->addMethod($methodName, $body, [
251261
'PROPERTY' => $property->getName(),
252-
'TYPE' => $hasNormalizationClosures || '' === $parameterType ? 'mixed' : 'ParamConfigurator|'.$parameterType,
262+
'TYPE' => \in_array('mixed', $prototypeParameterTypes, true) ? 'mixed' : 'ParamConfigurator|'.implode('|', $prototypeParameterTypes),
253263
'VAR' => '' === $key ? 'key' : $key,
254264
'VALUE' => 'value' === $key ? 'data' : 'value',
255265
]);
@@ -282,7 +292,7 @@ public function NAME(string $VAR, TYPE $VALUE): static
282292

283293
if (null === $key = $node->getKeyAttribute()) {
284294
$body = $hasNormalizationClosures ? '
285-
COMMENTpublic function NAME(mixed $value = []): CLASS|static
295+
COMMENTpublic function NAME(PARAM_TYPE $value = []): CLASS|static
286296
{
287297
$this->_usedProperties[\'PROPERTY\'] = true;
288298
if (!\is_array($value)) {
@@ -299,10 +309,15 @@ public function NAME(string $VAR, TYPE $VALUE): static
299309
300310
return $this->PROPERTY[] = new CLASS($value);
301311
}';
302-
$class->addMethod($methodName, $body, ['COMMENT' => $comment, 'PROPERTY' => $property->getName(), 'CLASS' => $childClass->getFqcn()]);
312+
$class->addMethod($methodName, $body, [
313+
'COMMENT' => $comment,
314+
'PROPERTY' => $property->getName(),
315+
'CLASS' => $childClass->getFqcn(),
316+
'PARAM_TYPE' => \in_array('mixed', $nodeParameterTypes, true) ? 'mixed' : implode('|', $nodeParameterTypes),
317+
]);
303318
} else {
304319
$body = $hasNormalizationClosures ? '
305-
COMMENTpublic function NAME(string $VAR, mixed $VALUE = []): CLASS|static
320+
COMMENTpublic function NAME(string $VAR, PARAM_TYPE $VALUE = []): CLASS|static
306321
{
307322
if (!\is_array($VALUE)) {
308323
$this->_usedProperties[\'PROPERTY\'] = true;
@@ -337,6 +352,7 @@ public function NAME(string $VAR, TYPE $VALUE): static
337352
'CLASS' => $childClass->getFqcn(),
338353
'VAR' => '' === $key ? 'key' : $key,
339354
'VALUE' => 'value' === $key ? 'data' : 'value',
355+
'PARAM_TYPE' => \in_array('mixed', $prototypeParameterTypes, true) ? 'mixed' : implode('|', $prototypeParameterTypes),
340356
]);
341357
}
342358

@@ -364,35 +380,33 @@ public function NAME($value): static
364380
$class->addMethod($node->getName(), $body, ['PROPERTY' => $property->getName(), 'COMMENT' => $comment]);
365381
}
366382

367-
private function getParameterType(NodeInterface $node): ?string
383+
private function getParameterTypes(NodeInterface $node): array
368384
{
369-
if ($node instanceof BooleanNode) {
370-
return 'bool';
371-
}
372-
373-
if ($node instanceof IntegerNode) {
374-
return 'int';
375-
}
376-
377-
if ($node instanceof FloatNode) {
378-
return 'float';
379-
}
380-
381-
if ($node instanceof EnumNode) {
382-
return '';
383-
}
384-
385-
if ($node instanceof PrototypedArrayNode && $node->getPrototype() instanceof ScalarNode) {
386-
// This is just an array of variables
387-
return 'array';
385+
$paramTypes = [];
386+
if ($node instanceof BaseNode) {
387+
$types = $node->getNormalizedTypes();
388+
if (\in_array(ExprBuilder::TYPE_ANY, $types, true)) {
389+
$paramTypes[] = 'mixed';
390+
}
391+
if (\in_array(ExprBuilder::TYPE_STRING, $types, true)) {
392+
$paramTypes[] = 'string';
393+
}
388394
}
389-
390-
if ($node instanceof VariableNode) {
391-
// mixed
392-
return '';
395+
if ($node instanceof BooleanNode) {
396+
$paramTypes[] = 'bool';
397+
} elseif ($node instanceof IntegerNode) {
398+
$paramTypes[] = 'int';
399+
} elseif ($node instanceof FloatNode) {
400+
$paramTypes[] = 'float';
401+
} elseif ($node instanceof EnumNode) {
402+
$paramTypes[] = 'mixed';
403+
} elseif ($node instanceof ArrayNode) {
404+
$paramTypes[] = 'array';
405+
} elseif ($node instanceof VariableNode) {
406+
$paramTypes[] = 'mixed';
393407
}
394408

395-
return null;
409+
return array_unique($paramTypes);
396410
}
397411

398412
private function getComment(BaseNode $node): string
@@ -416,11 +430,8 @@ private function getComment(BaseNode $node): string
416430
return var_export($a, true);
417431
}, $node->getValues())))."\n";
418432
} else {
419-
$parameterType = $this->getParameterType($node);
420-
if (null === $parameterType || '' === $parameterType) {
421-
$parameterType = 'mixed';
422-
}
423-
$comment .= ' * @param ParamConfigurator|'.$parameterType.' $value'."\n";
433+
$parameterTypes = $this->getParameterTypes($node);
434+
$comment .= ' * @param ParamConfigurator|'.implode('|', $parameterTypes).' $value'."\n";
424435
}
425436
} else {
426437
foreach ((array) ($node->getExample() ?? []) as $example) {

src/Symfony/Component/Config/Definition/BaseNode.php

+19
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ abstract class BaseNode implements NodeInterface
3232
protected $name;
3333
protected $parent;
3434
protected $normalizationClosures = [];
35+
protected $normalizedTypes = [];
3536
protected $finalValidationClosures = [];
3637
protected $allowOverwrite = true;
3738
protected $required = false;
@@ -212,6 +213,24 @@ public function setNormalizationClosures(array $closures)
212213
$this->normalizationClosures = $closures;
213214
}
214215

216+
/**
217+
* Sets the list of type supported by normalization.
218+
* see ExprBuilder::TYPE_* constants.
219+
*/
220+
public function setNormalizedTypes(array $types)
221+
{
222+
$this->normalizedTypes = $types;
223+
}
224+
225+
/**
226+
* Gets the list of type supported by normalization.
227+
* see ExprBuilder::TYPE_* constants.
228+
*/
229+
public function getNormalizedTypes(): array
230+
{
231+
return $this->normalizedTypes;
232+
}
233+
215234
/**
216235
* Sets the closures used for final validation.
217236
*

src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php

+1
Original file line numberDiff line numberDiff line change
@@ -405,6 +405,7 @@ protected function createNode(): NodeInterface
405405

406406
if (null !== $this->normalization) {
407407
$node->setNormalizationClosures($this->normalization->before);
408+
$node->setNormalizedTypes($this->normalization->declaredTypes);
408409
$node->setXmlRemappings($this->normalization->remappings);
409410
}
410411

src/Symfony/Component/Config/Definition/Builder/ExprBuilder.php

+29-14
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@
2121
*/
2222
class ExprBuilder
2323
{
24+
public const TYPE_ANY = 'any';
25+
public const TYPE_STRING = 'string';
26+
public const TYPE_NULL = 'null';
27+
public const TYPE_ARRAY = 'array';
28+
2429
protected $node;
30+
public $allowedTypes;
2531
public $ifPart;
2632
public $thenPart;
2733

@@ -37,7 +43,8 @@ public function __construct(NodeDefinition $node)
3743
*/
3844
public function always(\Closure $then = null): static
3945
{
40-
$this->ifPart = function () { return true; };
46+
$this->ifPart = static function () { return true; };
47+
$this->allowedTypes = self::TYPE_ANY;
4148

4249
if (null !== $then) {
4350
$this->thenPart = $then;
@@ -56,10 +63,11 @@ public function always(\Closure $then = null): static
5663
public function ifTrue(\Closure $closure = null): static
5764
{
5865
if (null === $closure) {
59-
$closure = function ($v) { return true === $v; };
66+
$closure = static function ($v) { return true === $v; };
6067
}
6168

6269
$this->ifPart = $closure;
70+
$this->allowedTypes = self::TYPE_ANY;
6371

6472
return $this;
6573
}
@@ -71,7 +79,8 @@ public function ifTrue(\Closure $closure = null): static
7179
*/
7280
public function ifString(): static
7381
{
74-
$this->ifPart = function ($v) { return \is_string($v); };
82+
$this->ifPart = static function ($v) { return \is_string($v); };
83+
$this->allowedTypes = self::TYPE_STRING;
7584

7685
return $this;
7786
}
@@ -83,7 +92,8 @@ public function ifString(): static
8392
*/
8493
public function ifNull(): static
8594
{
86-
$this->ifPart = function ($v) { return null === $v; };
95+
$this->ifPart = static function ($v) { return null === $v; };
96+
$this->allowedTypes = self::TYPE_NULL;
8797

8898
return $this;
8999
}
@@ -95,7 +105,8 @@ public function ifNull(): static
95105
*/
96106
public function ifEmpty(): static
97107
{
98-
$this->ifPart = function ($v) { return empty($v); };
108+
$this->ifPart = static function ($v) { return empty($v); };
109+
$this->allowedTypes = self::TYPE_ANY;
99110

100111
return $this;
101112
}
@@ -107,7 +118,8 @@ public function ifEmpty(): static
107118
*/
108119
public function ifArray(): static
109120
{
110-
$this->ifPart = function ($v) { return \is_array($v); };
121+
$this->ifPart = static function ($v) { return \is_array($v); };
122+
$this->allowedTypes = self::TYPE_ARRAY;
111123

112124
return $this;
113125
}
@@ -119,7 +131,8 @@ public function ifArray(): static
119131
*/
120132
public function ifInArray(array $array): static
121133
{
122-
$this->ifPart = function ($v) use ($array) { return \in_array($v, $array, true); };
134+
$this->ifPart = static function ($v) use ($array) { return \in_array($v, $array, true); };
135+
$this->allowedTypes = self::TYPE_ANY;
123136

124137
return $this;
125138
}
@@ -131,7 +144,8 @@ public function ifInArray(array $array): static
131144
*/
132145
public function ifNotInArray(array $array): static
133146
{
134-
$this->ifPart = function ($v) use ($array) { return !\in_array($v, $array, true); };
147+
$this->ifPart = static function ($v) use ($array) { return !\in_array($v, $array, true); };
148+
$this->allowedTypes = self::TYPE_ANY;
135149

136150
return $this;
137151
}
@@ -143,8 +157,9 @@ public function ifNotInArray(array $array): static
143157
*/
144158
public function castToArray(): static
145159
{
146-
$this->ifPart = function ($v) { return !\is_array($v); };
147-
$this->thenPart = function ($v) { return [$v]; };
160+
$this->ifPart = static function ($v) { return !\is_array($v); };
161+
$this->allowedTypes = self::TYPE_ANY;
162+
$this->thenPart = static function ($v) { return [$v]; };
148163

149164
return $this;
150165
}
@@ -168,7 +183,7 @@ public function then(\Closure $closure): static
168183
*/
169184
public function thenEmptyArray(): static
170185
{
171-
$this->thenPart = function () { return []; };
186+
$this->thenPart = static function () { return []; };
172187

173188
return $this;
174189
}
@@ -184,7 +199,7 @@ public function thenEmptyArray(): static
184199
*/
185200
public function thenInvalid(string $message): static
186201
{
187-
$this->thenPart = function ($v) use ($message) { throw new \InvalidArgumentException(sprintf($message, json_encode($v))); };
202+
$this->thenPart = static function ($v) use ($message) { throw new \InvalidArgumentException(sprintf($message, json_encode($v))); };
188203

189204
return $this;
190205
}
@@ -198,7 +213,7 @@ public function thenInvalid(string $message): static
198213
*/
199214
public function thenUnset(): static
200215
{
201-
$this->thenPart = function () { throw new UnsetKeyException('Unsetting key.'); };
216+
$this->thenPart = static function () { throw new UnsetKeyException('Unsetting key.'); };
202217

203218
return $this;
204219
}
@@ -231,7 +246,7 @@ public static function buildExpressions(array $expressions): array
231246
if ($expr instanceof self) {
232247
$if = $expr->ifPart;
233248
$then = $expr->thenPart;
234-
$expressions[$k] = function ($v) use ($if, $then) {
249+
$expressions[$k] = static function ($v) use ($if, $then) {
235250
return $if($v) ? $then($v) : $v;
236251
};
237252
}

src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php

+6
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,13 @@ public function getNode(bool $forceRootNode = false): NodeInterface
106106
}
107107

108108
if (null !== $this->normalization) {
109+
$allowedTypes = [];
110+
foreach ($this->normalization->before as $expr) {
111+
$allowedTypes[] = $expr->allowedTypes;
112+
}
113+
$allowedTypes = array_unique($allowedTypes);
109114
$this->normalization->before = ExprBuilder::buildExpressions($this->normalization->before);
115+
$this->normalization->declaredTypes = $allowedTypes;
110116
}
111117

112118
if (null !== $this->validation) {

src/Symfony/Component/Config/Definition/Builder/NormalizationBuilder.php

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class NormalizationBuilder
2020
{
2121
protected $node;
2222
public $before = [];
23+
public $declaredTypes = [];
2324
public $remappings = [];
2425

2526
public function __construct(NodeDefinition $node)

0 commit comments

Comments
 (0)