Skip to content

Commit c79c6a2

Browse files
bobvandevijverfabpot
authored andcommitted
[Config] Do not generate unreachable configuration paths
1 parent e092b46 commit c79c6a2

File tree

10 files changed

+344
-18
lines changed

10 files changed

+344
-18
lines changed

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

Lines changed: 30 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,13 @@ private function handleArrayNode(ArrayNode $node, ClassBuilder $class, string $n
127127
$class->addRequire($childClass);
128128
$this->classes[] = $childClass;
129129

130+
$nodeTypes = $this->getParameterTypes($node);
131+
$paramType = $this->getParamType($nodeTypes);
132+
130133
$hasNormalizationClosures = $this->hasNormalizationClosures($node);
131134
$comment = $this->getComment($node);
132-
if ($hasNormalizationClosures) {
133-
$comment = \sprintf(" * @template TValue\n * @param TValue \$value\n%s", $comment);
135+
if ($hasNormalizationClosures && 'array' !== $paramType) {
136+
$comment = \sprintf(" * @template TValue of %s\n * @param TValue \$value\n%s", $paramType, $comment);
134137
$comment .= \sprintf(' * @return %s|$this'."\n", $childClass->getFqcn());
135138
$comment .= \sprintf(' * @psalm-return (TValue is array ? %s : static)'."\n ", $childClass->getFqcn());
136139
}
@@ -142,8 +145,7 @@ private function handleArrayNode(ArrayNode $node, ClassBuilder $class, string $n
142145
$node->getName(),
143146
$this->getType($childClass->getFqcn(), $hasNormalizationClosures)
144147
);
145-
$nodeTypes = $this->getParameterTypes($node);
146-
$body = $hasNormalizationClosures ? '
148+
$body = $hasNormalizationClosures && 'array' !== $paramType ? '
147149
COMMENTpublic function NAME(PARAM_TYPE $value = []): CLASS|static
148150
{
149151
if (!\is_array($value)) {
@@ -178,7 +180,7 @@ private function handleArrayNode(ArrayNode $node, ClassBuilder $class, string $n
178180
'COMMENT' => $comment,
179181
'PROPERTY' => $property->getName(),
180182
'CLASS' => $childClass->getFqcn(),
181-
'PARAM_TYPE' => \in_array('mixed', $nodeTypes, true) ? 'mixed' : implode('|', $nodeTypes),
183+
'PARAM_TYPE' => $paramType,
182184
]);
183185

184186
$this->buildNode($node, $childClass, $this->getSubNamespace($childClass));
@@ -218,10 +220,11 @@ private function handlePrototypedArrayNode(PrototypedArrayNode $node, ClassBuild
218220

219221
$nodeParameterTypes = $this->getParameterTypes($node);
220222
$prototypeParameterTypes = $this->getParameterTypes($prototype);
223+
$noKey = null === $key = $node->getKeyAttribute();
221224
if (!$prototype instanceof ArrayNode || ($prototype instanceof PrototypedArrayNode && $prototype->getPrototype() instanceof ScalarNode)) {
222225
$class->addUse(ParamConfigurator::class);
223226
$property = $class->addProperty($node->getName());
224-
if (null === $key = $node->getKeyAttribute()) {
227+
if ($noKey) {
225228
// This is an array of values; don't use singular name
226229
$nodeTypesWithoutArray = array_filter($nodeParameterTypes, static fn ($type) => 'array' !== $type);
227230
$body = '
@@ -242,7 +245,7 @@ public function NAME(PARAM_TYPE $value): static
242245
'PROPERTY' => $property->getName(),
243246
'PROTOTYPE_TYPE' => implode('|', $prototypeParameterTypes),
244247
'EXTRA_TYPE' => $nodeTypesWithoutArray ? '|'.implode('|', $nodeTypesWithoutArray) : '',
245-
'PARAM_TYPE' => \in_array('mixed', $nodeParameterTypes, true) ? 'mixed' : 'ParamConfigurator|'.implode('|', $nodeParameterTypes),
248+
'PARAM_TYPE' => $this->getParamType($nodeParameterTypes, true),
246249
]);
247250
} else {
248251
$body = '
@@ -259,7 +262,7 @@ public function NAME(string $VAR, TYPE $VALUE): static
259262

260263
$class->addMethod($methodName, $body, [
261264
'PROPERTY' => $property->getName(),
262-
'TYPE' => \in_array('mixed', $prototypeParameterTypes, true) ? 'mixed' : 'ParamConfigurator|'.implode('|', $prototypeParameterTypes),
265+
'TYPE' => $this->getParamType($prototypeParameterTypes, true),
263266
'VAR' => '' === $key ? 'key' : $key,
264267
'VALUE' => 'value' === $key ? 'data' : 'value',
265268
]);
@@ -280,18 +283,27 @@ public function NAME(string $VAR, TYPE $VALUE): static
280283
$this->getType($childClass->getFqcn().'[]', $hasNormalizationClosures)
281284
);
282285

286+
$paramType = $this->getParamType($noKey ? $nodeParameterTypes : $prototypeParameterTypes);
287+
283288
$comment = $this->getComment($node);
289+
<<<<<<< HEAD
284290
if ($hasNormalizationClosures) {
285291
$comment = \sprintf(" * @template TValue\n * @param TValue \$value\n%s", $comment);
286292
$comment .= \sprintf(' * @return %s|$this'."\n", $childClass->getFqcn());
287293
$comment .= \sprintf(' * @psalm-return (TValue is array ? %s : static)'."\n ", $childClass->getFqcn());
294+
=======
295+
if ($hasNormalizationClosures && 'array' !== $paramType) {
296+
$comment = sprintf(" * @template TValue of %s\n * @param TValue \$value\n%s", $paramType, $comment);
297+
$comment .= sprintf(' * @return %s|$this'."\n", $childClass->getFqcn());
298+
$comment .= sprintf(' * @psalm-return (TValue is array ? %s : static)'."\n ", $childClass->getFqcn());
299+
>>>>>>> 100c683018d ([Config] Do not generate unreachable configuration paths)
288300
}
289301
if ('' !== $comment) {
290302
$comment = "/**\n$comment*/\n";
291303
}
292304

293-
if (null === $key = $node->getKeyAttribute()) {
294-
$body = $hasNormalizationClosures ? '
305+
if ($noKey) {
306+
$body = $hasNormalizationClosures && 'array' !== $paramType ? '
295307
COMMENTpublic function NAME(PARAM_TYPE $value = []): CLASS|static
296308
{
297309
$this->_usedProperties[\'PROPERTY\'] = true;
@@ -313,10 +325,10 @@ public function NAME(string $VAR, TYPE $VALUE): static
313325
'COMMENT' => $comment,
314326
'PROPERTY' => $property->getName(),
315327
'CLASS' => $childClass->getFqcn(),
316-
'PARAM_TYPE' => \in_array('mixed', $nodeParameterTypes, true) ? 'mixed' : implode('|', $nodeParameterTypes),
328+
'PARAM_TYPE' => $paramType,
317329
]);
318330
} else {
319-
$body = $hasNormalizationClosures ? '
331+
$body = $hasNormalizationClosures && 'array' !== $paramType ? '
320332
COMMENTpublic function NAME(string $VAR, PARAM_TYPE $VALUE = []): CLASS|static
321333
{
322334
if (!\is_array($VALUE)) {
@@ -352,7 +364,7 @@ public function NAME(string $VAR, TYPE $VALUE): static
352364
'CLASS' => $childClass->getFqcn(),
353365
'VAR' => '' === $key ? 'key' : $key,
354366
'VALUE' => 'value' === $key ? 'data' : 'value',
355-
'PARAM_TYPE' => \in_array('mixed', $prototypeParameterTypes, true) ? 'mixed' : implode('|', $prototypeParameterTypes),
367+
'PARAM_TYPE' => $paramType,
356368
]);
357369
}
358370

@@ -597,4 +609,9 @@ private function getType(string $classType, bool $hasNormalizationClosures): str
597609
{
598610
return $classType.($hasNormalizationClosures ? '|scalar' : '');
599611
}
612+
613+
private function getParamType(array $types, bool $withParamConfigurator = false): string
614+
{
615+
return \in_array('mixed', $types, true) ? 'mixed' : ($withParamConfigurator ? 'ParamConfigurator|' : '').implode('|', $types);
616+
}
600617
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
use Symfony\Config\ArrayValuesConfig;
13+
14+
return static function (ArrayValuesConfig $config) {
15+
$config->transports('foo')->dsn('bar');
16+
$config->transports('bar', ['dsn' => 'foobar']);
17+
18+
$config->errorPages()->withTrace(false);
19+
};
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
return [
13+
'transports' => [
14+
'foo' => [
15+
'dsn' => 'bar',
16+
],
17+
'bar' => [
18+
'dsn' => 'foobar',
19+
],
20+
],
21+
'error_pages' => [
22+
'with_trace' => false,
23+
]
24+
];
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<?php
2+
3+
namespace Symfony\Component\Config\Tests\Builder\Fixtures;
4+
5+
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
6+
use Symfony\Component\Config\Definition\ConfigurationInterface;
7+
8+
class ArrayValues implements ConfigurationInterface
9+
{
10+
public function getConfigTreeBuilder(): TreeBuilder
11+
{
12+
$tb = new TreeBuilder('array_values');
13+
$rootNode = $tb->getRootNode();
14+
$rootNode
15+
->children()
16+
->arrayNode('transports')
17+
->normalizeKeys(false)
18+
->useAttributeAsKey('name')
19+
->arrayPrototype()
20+
->beforeNormalization()
21+
->ifString()
22+
->then(function (string $dsn) {
23+
return ['dsn' => $dsn];
24+
})
25+
->end()
26+
->fixXmlConfig('option')
27+
->children()
28+
->scalarNode('dsn')->end()
29+
->end()
30+
->end()
31+
->end()
32+
->arrayNode('error_pages')
33+
->canBeEnabled()
34+
->children()
35+
->booleanNode('with_trace')->end()
36+
->end()
37+
->end()
38+
->end();
39+
40+
return $tb;
41+
}
42+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
<?php
2+
3+
namespace Symfony\Config\ArrayValues;
4+
5+
use Symfony\Component\Config\Loader\ParamConfigurator;
6+
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
7+
8+
/**
9+
* This class is automatically generated to help in creating a config.
10+
*/
11+
class ErrorPagesConfig
12+
{
13+
private $enabled;
14+
private $withTrace;
15+
private $_usedProperties = [];
16+
17+
/**
18+
* @default false
19+
* @param ParamConfigurator|bool $value
20+
* @return $this
21+
*/
22+
public function enabled($value): static
23+
{
24+
$this->_usedProperties['enabled'] = true;
25+
$this->enabled = $value;
26+
27+
return $this;
28+
}
29+
30+
/**
31+
* @default null
32+
* @param ParamConfigurator|bool $value
33+
* @return $this
34+
*/
35+
public function withTrace($value): static
36+
{
37+
$this->_usedProperties['withTrace'] = true;
38+
$this->withTrace = $value;
39+
40+
return $this;
41+
}
42+
43+
public function __construct(array $value = [])
44+
{
45+
if (array_key_exists('enabled', $value)) {
46+
$this->_usedProperties['enabled'] = true;
47+
$this->enabled = $value['enabled'];
48+
unset($value['enabled']);
49+
}
50+
51+
if (array_key_exists('with_trace', $value)) {
52+
$this->_usedProperties['withTrace'] = true;
53+
$this->withTrace = $value['with_trace'];
54+
unset($value['with_trace']);
55+
}
56+
57+
if ([] !== $value) {
58+
throw new InvalidConfigurationException(sprintf('The following keys are not supported by "%s": ', __CLASS__).implode(', ', array_keys($value)));
59+
}
60+
}
61+
62+
public function toArray(): array
63+
{
64+
$output = [];
65+
if (isset($this->_usedProperties['enabled'])) {
66+
$output['enabled'] = $this->enabled;
67+
}
68+
if (isset($this->_usedProperties['withTrace'])) {
69+
$output['with_trace'] = $this->withTrace;
70+
}
71+
72+
return $output;
73+
}
74+
75+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
<?php
2+
3+
namespace Symfony\Config\ArrayValues;
4+
5+
use Symfony\Component\Config\Loader\ParamConfigurator;
6+
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
7+
8+
/**
9+
* This class is automatically generated to help in creating a config.
10+
*/
11+
class TransportsConfig
12+
{
13+
private $dsn;
14+
private $_usedProperties = [];
15+
16+
/**
17+
* @default null
18+
* @param ParamConfigurator|mixed $value
19+
* @return $this
20+
*/
21+
public function dsn($value): static
22+
{
23+
$this->_usedProperties['dsn'] = true;
24+
$this->dsn = $value;
25+
26+
return $this;
27+
}
28+
29+
public function __construct(array $value = [])
30+
{
31+
if (array_key_exists('dsn', $value)) {
32+
$this->_usedProperties['dsn'] = true;
33+
$this->dsn = $value['dsn'];
34+
unset($value['dsn']);
35+
}
36+
37+
if ([] !== $value) {
38+
throw new InvalidConfigurationException(sprintf('The following keys are not supported by "%s": ', __CLASS__).implode(', ', array_keys($value)));
39+
}
40+
}
41+
42+
public function toArray(): array
43+
{
44+
$output = [];
45+
if (isset($this->_usedProperties['dsn'])) {
46+
$output['dsn'] = $this->dsn;
47+
}
48+
49+
return $output;
50+
}
51+
52+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy