Skip to content

Commit a0d0f95

Browse files
[Config] Add ArrayNodeDefinition::acceptAndWrap() to list alternative types that should be accepted and wrapped in an array
1 parent d83abf0 commit a0d0f95

File tree

17 files changed

+286
-305
lines changed

17 files changed

+286
-305
lines changed

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php

Lines changed: 173 additions & 176 deletions
Large diffs are not rendered by default.

src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2291,10 +2291,6 @@ private function registerLockConfiguration(array $config, ContainerBuilder $cont
22912291
// Generate stores
22922292
$storeDefinitions = [];
22932293
foreach ($resourceStores as $resourceStore) {
2294-
if (null === $resourceStore) {
2295-
$resourceStore = 'null';
2296-
}
2297-
22982294
$storeDsn = $container->resolveEnvPlaceholders($resourceStore, null, $usedEnvs);
22992295
if (!$usedEnvs && !str_contains($resourceStore, ':') && !\in_array($resourceStore, ['flock', 'semaphore', 'in-memory', 'null'], true)) {
23002296
$resourceStore = new Reference($resourceStore);

src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php

Lines changed: 0 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -72,36 +72,6 @@ public function testAssetPackageCannotHavePathAndUrl()
7272
});
7373
}
7474

75-
public function testWorkflowValidationPlacesIsArray()
76-
{
77-
$this->expectException(InvalidConfigurationException::class);
78-
$this->expectExceptionMessage('The "places" option must be an array or a "FQCN::glob" pattern in workflow configuration.');
79-
$this->createContainerFromClosure(function ($container) {
80-
$container->loadFromExtension('framework', [
81-
'workflows' => [
82-
'article' => [
83-
'places' => null,
84-
],
85-
],
86-
]);
87-
});
88-
}
89-
90-
public function testWorkflowValidationTransitonsIsArray()
91-
{
92-
$this->expectException(InvalidConfigurationException::class);
93-
$this->expectExceptionMessage('The "transitions" option must be an array in workflow configuration.');
94-
$this->createContainerFromClosure(function ($container) {
95-
$container->loadFromExtension('framework', [
96-
'workflows' => [
97-
'article' => [
98-
'transitions' => null,
99-
],
100-
],
101-
]);
102-
});
103-
}
104-
10575
public function testWorkflowValidationStateMachine()
10676
{
10777
$this->expectException(InvalidDefinitionException::class);

src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php

Lines changed: 20 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ public function getConfigTreeBuilder(): TreeBuilder
5757
$rootNode
5858
->docUrl('https://symfony.com/doc/{version:major}.{version:minor}/reference/configuration/security.html', 'symfony/security-bundle')
5959
->beforeNormalization()
60-
->always()
61-
->then(function ($v) {
60+
->ifArray()
61+
->then(static function ($v) {
6262
if (isset($v['hide_user_not_found']) && isset($v['expose_security_errors'])) {
6363
throw new InvalidConfigurationException('You cannot use both "hide_user_not_found" and "expose_security_errors" at the same time.');
6464
}
@@ -80,7 +80,7 @@ public function getConfigTreeBuilder(): TreeBuilder
8080
->setDeprecated('symfony/security-bundle', '7.3', 'The "%node%" option is deprecated and will be removed in 8.0. Use the "expose_security_errors" option instead.')
8181
->end()
8282
->enumNode('expose_security_errors')
83-
->beforeNormalization()->ifString()->then(fn ($v) => ExposeSecurityLevel::tryFrom($v))->end()
83+
->beforeNormalization()->ifString()->then(static fn ($v) => ExposeSecurityLevel::tryFrom($v))->end()
8484
->values(ExposeSecurityLevel::cases())
8585
->defaultValue(ExposeSecurityLevel::None)
8686
->end()
@@ -129,11 +129,7 @@ private function addRoleHierarchySection(ArrayNodeDefinition $rootNode): void
129129
->useAttributeAsKey('id')
130130
->prototype('array')
131131
->performNoDeepMerging()
132-
->beforeNormalization()->ifString()->then(fn ($v) => ['value' => $v])->end()
133-
->beforeNormalization()
134-
->ifTrue(fn ($v) => \is_array($v) && isset($v['value']))
135-
->then(fn ($v) => preg_split('/\s*,\s*/', $v['value']))
136-
->end()
132+
->beforeNormalization()->ifString()->then(static fn ($v) => preg_split('/\s*,\s*/', $v))->end()
137133
->prototype('scalar')->end()
138134
->end()
139135
->end()
@@ -159,7 +155,7 @@ private function addAccessControlSection(ArrayNodeDefinition $rootNode): void
159155
->scalarNode('host')->defaultNull()->end()
160156
->integerNode('port')->defaultNull()->end()
161157
->arrayNode('ips', 'ip')
162-
->beforeNormalization()->ifString()->then(fn ($v) => [$v])->end()
158+
->acceptAndWrap(['string'])
163159
->prototype('scalar')->end()
164160
->end()
165161
->arrayNode('attributes', 'attribute')
@@ -168,14 +164,14 @@ private function addAccessControlSection(ArrayNodeDefinition $rootNode): void
168164
->end()
169165
->scalarNode('route')->defaultNull()->end()
170166
->arrayNode('methods', 'method')
171-
->beforeNormalization()->ifString()->then(fn ($v) => preg_split('/\s*,\s*/', $v))->end()
167+
->beforeNormalization()->ifString()->then(static fn ($v) => preg_split('/\s*,\s*/', $v))->end()
172168
->prototype('scalar')->end()
173169
->end()
174170
->scalarNode('allow_if')->defaultNull()->end()
175171
->end()
176172
->children()
177173
->arrayNode('roles', 'role')
178-
->beforeNormalization()->ifString()->then(fn ($v) => preg_split('/\s*,\s*/', $v))->end()
174+
->beforeNormalization()->ifString()->then(static fn ($v) => preg_split('/\s*,\s*/', $v))->end()
179175
->prototype('scalar')->end()
180176
->end()
181177
->end()
@@ -205,12 +201,12 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto
205201
->scalarNode('pattern')
206202
->beforeNormalization()
207203
->ifArray()
208-
->then(fn ($v) => \sprintf('(?:%s)', implode('|', $v)))
204+
->then(static fn ($v) => \sprintf('(?:%s)', implode('|', $v)))
209205
->end()
210206
->end()
211207
->scalarNode('host')->end()
212208
->arrayNode('methods')
213-
->beforeNormalization()->ifString()->then(fn ($v) => preg_split('/\s*,\s*/', $v))->end()
209+
->beforeNormalization()->ifString()->then(static fn ($v) => preg_split('/\s*,\s*/', $v))->end()
214210
->prototype('scalar')->end()
215211
->end()
216212
->booleanNode('security')->defaultTrue()->end()
@@ -233,11 +229,11 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto
233229
->treatTrueLike([])
234230
->canBeUnset()
235231
->beforeNormalization()
236-
->ifTrue(fn ($v): bool => \is_array($v) && (isset($v['csrf_token_manager']) xor isset($v['enable_csrf'])))
237-
->then(function (array $v): array {
232+
->ifArray()
233+
->then(static function ($v) {
238234
if (isset($v['csrf_token_manager'])) {
239-
$v['enable_csrf'] = true;
240-
} elseif ($v['enable_csrf']) {
235+
$v['enable_csrf'] ??= true;
236+
} elseif ($v['enable_csrf'] ?? false) {
241237
$v['csrf_token_manager'] = 'security.csrf.token_manager';
242238
}
243239

@@ -254,7 +250,7 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto
254250
->booleanNode('invalidate_session')->defaultTrue()->end()
255251
->arrayNode('clear_site_data')
256252
->performNoDeepMerging()
257-
->beforeNormalization()->ifString()->then(fn ($v) => $v ? array_map('trim', explode(',', $v)) : [])->end()
253+
->beforeNormalization()->ifString()->then(static fn ($v) => $v ? array_map('trim', explode(',', $v)) : [])->end()
258254
->enumPrototype()
259255
->values([
260256
'*', 'cache', 'cookies', 'storage', 'executionContexts',
@@ -265,9 +261,10 @@ private function addFirewallsSection(ArrayNodeDefinition $rootNode, array $facto
265261
->children()
266262
->arrayNode('delete_cookies', 'delete_cookie')
267263
->normalizeKeys(false)
264+
->acceptAndWrap(['string'])
268265
->beforeNormalization()
269-
->ifTrue(fn ($v) => \is_array($v) && \is_int(key($v)))
270-
->then(fn ($v) => array_map(fn ($v) => ['name' => $v], $v))
266+
->ifArray()
267+
->then(static fn ($v) => array_map(static fn ($v) => \is_string($v) ? ['name' => $v] : $v, $v))
271268
->end()
272269
->useAttributeAsKey('name')
273270
->prototype('array')
@@ -379,10 +376,7 @@ private function addProvidersSection(ArrayNodeDefinition $rootNode): void
379376
->arrayNode('chain')
380377
->children()
381378
->arrayNode('providers', 'provider')
382-
->beforeNormalization()
383-
->ifString()
384-
->then(fn ($v) => preg_split('/\s*,\s*/', $v))
385-
->end()
379+
->beforeNormalization()->ifString()->then(static fn ($v) => preg_split('/\s*,\s*/', $v))->end()
386380
->prototype('scalar')->end()
387381
->end()
388382
->end()
@@ -427,7 +421,7 @@ private function addPasswordHashersSection(ArrayNodeDefinition $rootNode): void
427421
->prototype('array')
428422
->canBeUnset()
429423
->performNoDeepMerging()
430-
->beforeNormalization()->ifString()->then(fn ($v) => ['algorithm' => $v])->end()
424+
->acceptAndWrap(['string'], 'algorithm')
431425
->children()
432426
->scalarNode('algorithm')
433427
->cannotBeEmpty()
@@ -437,8 +431,8 @@ private function addPasswordHashersSection(ArrayNodeDefinition $rootNode): void
437431
->end()
438432
->end()
439433
->arrayNode('migrate_from')
434+
->acceptAndWrap(['string'])
440435
->prototype('scalar')->end()
441-
->beforeNormalization()->castToArray()->end()
442436
->end()
443437
->scalarNode('hash_algorithm')->info('Name of hashing algorithm for PBKDF2 (i.e. sha256, sha512, etc..) See hash_algos() for a list of supported algorithms.')->defaultValue('sha512')->end()
444438
->scalarNode('key_length')->defaultValue(40)->end()

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcTokenHandlerFactory.php

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -99,24 +99,28 @@ public function addConfiguration(NodeBuilder $node): void
9999
->thenInvalid('You must set either "discovery" or "key" or "keyset".')
100100
->end()
101101
->beforeNormalization()
102-
->ifTrue(static fn ($v) => isset($v['algorithm']) && \is_string($v['algorithm']))
102+
->ifArray()
103103
->then(static function ($v) {
104-
if (isset($v['algorithms'])) {
104+
if (isset($v['algorithms']) && isset($v['algorithm'])) {
105105
throw new InvalidConfigurationException('You cannot use both "algorithm" and "algorithms" at the same time.');
106106
}
107-
$v['algorithms'] = [$v['algorithm']];
108-
unset($v['algorithm']);
107+
if (\is_string($v['algorithm'] ?? null)) {
108+
$v['algorithms'] = [$v['algorithm']];
109+
unset($v['algorithm']);
110+
}
109111

110112
return $v;
111113
})
112114
->end()
113115
->beforeNormalization()
114-
->ifTrue(static fn ($v) => isset($v['key']) && \is_string($v['key']))
116+
->ifArray()
115117
->then(static function ($v) {
116-
if (isset($v['keyset'])) {
118+
if (isset($v['keyset']) && isset($v['key'])) {
117119
throw new InvalidConfigurationException('You cannot use both "key" and "keyset" at the same time.');
118120
}
119-
$v['keyset'] = \sprintf('{"keys":[%s]}', $v['key']);
121+
if (\is_string($v['key'] ?? null)) {
122+
$v['keyset'] = \sprintf('{"keys":[%s]}', $v['key']);
123+
}
120124

121125
return $v;
122126
})

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/AccessToken/OidcUserInfoTokenHandlerFactory.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ public function addConfiguration(NodeBuilder $node): void
6565
->arrayNode($this->getKey())
6666
->beforeNormalization()
6767
->ifString()
68-
->then(fn ($v) => ['claim' => 'sub', 'base_uri' => $v])
68+
->then(static fn ($v) => ['claim' => 'sub', 'base_uri' => $v])
6969
->end()
7070
->children()
7171
->scalarNode('base_uri')

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AccessTokenFactory.php

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -47,39 +47,28 @@ public function addConfiguration(NodeDefinition $node): void
4747
$builder
4848
->scalarNode('realm')->defaultNull()->end()
4949
->arrayNode('token_extractors', 'token_extractor')
50-
->beforeNormalization()
51-
->ifString()
52-
->then(fn ($v) => [$v])
53-
->end()
50+
->acceptAndWrap(['string'])
5451
->cannotBeEmpty()
55-
->defaultValue([
56-
'security.access_token_extractor.header',
57-
])
52+
->defaultValue(['security.access_token_extractor.header'])
5853
->scalarPrototype()->end()
5954
->end()
6055
;
6156

6257
$tokenHandlerNodeBuilder = $builder
6358
->arrayNode('token_handler')
64-
->example([
65-
'id' => 'App\Security\CustomTokenHandler',
66-
])
67-
68-
->beforeNormalization()
69-
->ifString()
70-
->then(fn ($v) => ['id' => $v])
71-
->end()
59+
->example(['id' => 'App\Security\CustomTokenHandler'])
60+
->acceptAndWrap(['string'], 'id')
7261

73-
->beforeNormalization()
74-
->ifTrue(fn ($v) => \is_array($v) && 1 < \count($v))
75-
->then(fn () => throw new InvalidConfigurationException('You cannot configure multiple token handlers.'))
62+
->validate()
63+
->ifTrue(static fn ($v) => \is_array($v) && 1 < \count($v))
64+
->then(static fn () => throw new InvalidConfigurationException('You cannot configure multiple token handlers.'))
7665
->end()
7766

7867
// "isRequired" must be set otherwise the following custom validation is not called
7968
->isRequired()
80-
->beforeNormalization()
81-
->ifTrue(fn ($v) => \is_array($v) && !$v)
82-
->then(fn () => throw new InvalidConfigurationException('You must set a token handler.'))
69+
->validate()
70+
->ifTrue(static fn ($v) => \is_array($v) && !$v)
71+
->then(static fn () => throw new InvalidConfigurationException('You must set a token handler.'))
8372
->end()
8473

8574
->children()

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -133,9 +133,7 @@ public function addConfiguration(NodeDefinition $node): void
133133
->end()
134134
->scalarNode('service')->end()
135135
->arrayNode('user_providers', 'user_provider')
136-
->beforeNormalization()
137-
->ifString()->then(fn ($v) => [$v])
138-
->end()
136+
->acceptAndWrap(['string'])
139137
->prototype('scalar')->end()
140138
->end()
141139
->booleanNode('catch_exceptions')->defaultTrue()->end()
@@ -147,11 +145,9 @@ public function addConfiguration(NodeDefinition $node): void
147145
->defaultValue(['password'])
148146
->end()
149147
->arrayNode('token_provider')
150-
->beforeNormalization()
151-
->ifString()->then(fn ($v) => ['service' => $v])
152-
->end()
148+
->acceptAndWrap(['string'], 'service')
153149
->children()
154-
->scalarNode('service')->info('The service ID of a custom rememberme token provider.')->end()
150+
->scalarNode('service')->info('The service ID of a custom remember-me token provider.')->end()
155151
->arrayNode('doctrine')
156152
->canBeEnabled()
157153
->children()

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/UserProvider/InMemoryFactory.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider;
1313

14+
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
1415
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
1516
use Symfony\Component\DependencyInjection\ChildDefinition;
1617
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -42,6 +43,9 @@ public function getKey(): string
4243
return 'memory';
4344
}
4445

46+
/**
47+
* @param ArrayNodeDefinition $node
48+
*/
4549
public function addConfiguration(NodeDefinition $node): void
4650
{
4751
$node
@@ -53,7 +57,7 @@ public function addConfiguration(NodeDefinition $node): void
5357
->children()
5458
->scalarNode('password')->defaultNull()->end()
5559
->arrayNode('roles')
56-
->beforeNormalization()->ifString()->then(fn ($v) => preg_split('/\s*,\s*/', $v))->end()
60+
->beforeNormalization()->ifString()->then(static fn ($v) => preg_split('/\s*,\s*/', $v))->end()
5761
->prototype('scalar')->end()
5862
->end()
5963
->end()

src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/UserProvider/LdapFactory.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
namespace Symfony\Bundle\SecurityBundle\DependencyInjection\Security\UserProvider;
1313

14+
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
1415
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
1516
use Symfony\Component\DependencyInjection\ChildDefinition;
1617
use Symfony\Component\DependencyInjection\ContainerBuilder;
@@ -45,6 +46,9 @@ public function getKey(): string
4546
return 'ldap';
4647
}
4748

49+
/**
50+
* @param ArrayNodeDefinition $node
51+
*/
4852
public function addConfiguration(NodeDefinition $node): void
4953
{
5054
$node
@@ -57,7 +61,7 @@ public function addConfiguration(NodeDefinition $node): void
5761
->prototype('scalar')->end()
5862
->end()
5963
->arrayNode('default_roles', 'default_role')
60-
->beforeNormalization()->ifString()->then(fn ($v) => preg_split('/\s*,\s*/', $v))->end()
64+
->beforeNormalization()->ifString()->then(static fn ($v) => preg_split('/\s*,\s*/', $v))->end()
6165
->requiresAtLeastOneElement()
6266
->prototype('scalar')->end()
6367
->end()

0 commit comments

Comments
 (0)