Skip to content

Commit 9a8d3aa

Browse files
Merge branch '7.2' into 7.3
* 7.2: [DependencyInjection] Fix `ServiceLocatorTagPass` indexes handling Improve docblock on compile() [VarDumper] Fix dumping LazyObjectState when using VarExporter v8 Allow NumberToLocalizedStringTransformer empty values [Intl] Ensure data consistency between alpha and numeric codes [Intl] Add missing currency (NOK) localization (en_NO)
2 parents cf3b527 + 068726c commit 9a8d3aa

File tree

14 files changed

+155
-164
lines changed

14 files changed

+155
-164
lines changed

src/Symfony/Component/DependencyInjection/Attribute/AsTaggedItem.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020
class AsTaggedItem
2121
{
2222
/**
23-
* @param string|null $index The property or method to use to index the item in the locator
24-
* @param int|null $priority The priority of the item; the higher the number, the earlier the tagged service will be located in the locator
23+
* @param string|null $index The property or method to use to index the item in the iterator/locator
24+
* @param int|null $priority The priority of the item; the higher the number, the earlier the tagged service will be located in the iterator/locator
2525
*/
2626
public function __construct(
2727
public ?string $index = null,

src/Symfony/Component/DependencyInjection/Compiler/PriorityTaggedServiceTrait.php

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -88,8 +88,7 @@ private function findAndSortTaggedServices(string|TaggedIteratorArgument $tagNam
8888
if (null === $index && null === $defaultIndex && $defaultPriorityMethod && $reflector) {
8989
$defaultIndex = PriorityTaggedServiceUtil::getDefault($serviceId, $reflector, $defaultIndexMethod ?? 'getDefaultName', $tagName, $indexAttribute, $checkTaggedItem);
9090
}
91-
$decorated = $definition->getTag('container.decorator')[0]['id'] ?? null;
92-
$index = $index ?? $defaultIndex ?? $defaultIndex = $decorated ?? $serviceId;
91+
$index ??= $defaultIndex ??= $definition->getTag('container.decorator')[0]['id'] ?? $serviceId;
9392

9493
$services[] = [$priority, ++$i, $index, $serviceId, $class];
9594
}

src/Symfony/Component/DependencyInjection/Compiler/ServiceLocatorTagPass.php

Lines changed: 36 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,41 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
5454
$value->setClass(ServiceLocator::class);
5555
}
5656

57-
$services = $value->getArguments()[0] ?? null;
57+
$values = $value->getArguments()[0] ?? null;
58+
$services = [];
5859

59-
if ($services instanceof TaggedIteratorArgument) {
60-
$services = $this->findAndSortTaggedServices($services, $this->container);
61-
}
62-
63-
if (!\is_array($services)) {
60+
if ($values instanceof TaggedIteratorArgument) {
61+
foreach ($this->findAndSortTaggedServices($values, $this->container) as $k => $v) {
62+
$services[$k] = new ServiceClosureArgument($v);
63+
}
64+
} elseif (!\is_array($values)) {
6465
throw new InvalidArgumentException(\sprintf('Invalid definition for service "%s": an array of references is expected as first argument when the "container.service_locator" tag is set.', $this->currentId));
66+
} else {
67+
$i = 0;
68+
69+
foreach ($values as $k => $v) {
70+
if ($v instanceof ServiceClosureArgument) {
71+
$services[$k] = $v;
72+
continue;
73+
}
74+
75+
if ($i === $k) {
76+
if ($v instanceof Reference) {
77+
$k = (string) $v;
78+
}
79+
++$i;
80+
} elseif (\is_int($k)) {
81+
$i = null;
82+
}
83+
84+
$services[$k] = new ServiceClosureArgument($v);
85+
}
86+
if (\count($services) === $i) {
87+
ksort($services);
88+
}
6589
}
6690

67-
$value->setArgument(0, self::map($services));
91+
$value->setArgument(0, $services);
6892

6993
$id = '.service_locator.'.ContainerBuilder::hash($value);
7094

@@ -83,8 +107,12 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
83107

84108
public static function register(ContainerBuilder $container, array $map, ?string $callerId = null): Reference
85109
{
110+
foreach ($map as $k => $v) {
111+
$map[$k] = new ServiceClosureArgument($v);
112+
}
113+
86114
$locator = (new Definition(ServiceLocator::class))
87-
->addArgument(self::map($map))
115+
->addArgument($map)
88116
->addTag('container.service_locator');
89117

90118
if (null !== $callerId && $container->hasDefinition($callerId)) {
@@ -109,29 +137,4 @@ public static function register(ContainerBuilder $container, array $map, ?string
109137

110138
return new Reference($id);
111139
}
112-
113-
public static function map(array $services): array
114-
{
115-
$i = 0;
116-
117-
foreach ($services as $k => $v) {
118-
if ($v instanceof ServiceClosureArgument) {
119-
continue;
120-
}
121-
122-
if ($i === $k) {
123-
if ($v instanceof Reference) {
124-
unset($services[$k]);
125-
$k = (string) $v;
126-
}
127-
++$i;
128-
} elseif (\is_int($k)) {
129-
$i = null;
130-
}
131-
132-
$services[$k] = new ServiceClosureArgument($v);
133-
}
134-
135-
return $services;
136-
}
137140
}

src/Symfony/Component/DependencyInjection/ContainerBuilder.php

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -790,10 +790,11 @@ public function parameterCannotBeEmpty(string $name, string $message): void
790790
* * The parameter bag is frozen;
791791
* * Extension loading is disabled.
792792
*
793-
* @param bool $resolveEnvPlaceholders Whether %env()% parameters should be resolved using the current
794-
* env vars or be replaced by uniquely identifiable placeholders.
795-
* Set to "true" when you want to use the current ContainerBuilder
796-
* directly, keep to "false" when the container is dumped instead.
793+
* @param bool $resolveEnvPlaceholders Whether %env()% parameters should be resolved at build time using
794+
* the current env var values (true), or be resolved at runtime based
795+
* on the environment (false). In general, this should be set to "true"
796+
* when you want to use the current ContainerBuilder directly, and to
797+
* "false" when the container is dumped instead.
797798
*/
798799
public function compile(bool $resolveEnvPlaceholders = false): void
799800
{

src/Symfony/Component/DependencyInjection/Tests/Compiler/ServiceLocatorTagPassTest.php

Lines changed: 61 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,26 @@ public function testProcessValue()
8686
$this->assertSame(CustomDefinition::class, \get_class($locator('inlines.service')));
8787
}
8888

89+
public function testServiceListIsOrdered()
90+
{
91+
$container = new ContainerBuilder();
92+
93+
$container->register('bar', CustomDefinition::class);
94+
$container->register('baz', CustomDefinition::class);
95+
96+
$container->register('foo', ServiceLocator::class)
97+
->setArguments([[
98+
new Reference('baz'),
99+
new Reference('bar'),
100+
]])
101+
->addTag('container.service_locator')
102+
;
103+
104+
(new ServiceLocatorTagPass())->process($container);
105+
106+
$this->assertSame(['bar', 'baz'], array_keys($container->getDefinition('foo')->getArgument(0)));
107+
}
108+
89109
public function testServiceWithKeyOverwritesPreviousInheritedKey()
90110
{
91111
$container = new ContainerBuilder();
@@ -170,6 +190,27 @@ public function testTaggedServices()
170190
$this->assertSame(TestDefinition2::class, $locator('baz')::class);
171191
}
172192

193+
public function testTaggedServicesKeysAreKept()
194+
{
195+
$container = new ContainerBuilder();
196+
197+
$container->register('bar', TestDefinition1::class)->addTag('test_tag', ['index' => 0]);
198+
$container->register('baz', TestDefinition2::class)->addTag('test_tag', ['index' => 1]);
199+
200+
$container->register('foo', ServiceLocator::class)
201+
->setArguments([new TaggedIteratorArgument('test_tag', 'index', null, true)])
202+
->addTag('container.service_locator')
203+
;
204+
205+
(new ServiceLocatorTagPass())->process($container);
206+
207+
/** @var ServiceLocator $locator */
208+
$locator = $container->get('foo');
209+
210+
$this->assertSame(TestDefinition1::class, $locator(0)::class);
211+
$this->assertSame(TestDefinition2::class, $locator(1)::class);
212+
}
213+
173214
public function testIndexedByServiceIdWithDecoration()
174215
{
175216
$container = new ContainerBuilder();
@@ -201,15 +242,33 @@ public function testIndexedByServiceIdWithDecoration()
201242
static::assertInstanceOf(DecoratedService::class, $locator->get(Service::class));
202243
}
203244

204-
public function testDefinitionOrderIsTheSame()
245+
public function testServicesKeysAreKept()
205246
{
206247
$container = new ContainerBuilder();
207248
$container->register('service-1');
208249
$container->register('service-2');
250+
$container->register('service-3');
209251

210252
$locator = ServiceLocatorTagPass::register($container, [
211-
new Reference('service-2'),
212253
new Reference('service-1'),
254+
'service-2' => new Reference('service-2'),
255+
'foo' => new Reference('service-3'),
256+
]);
257+
$locator = $container->getDefinition($locator);
258+
$factories = $locator->getArguments()[0];
259+
260+
static::assertSame([0, 'service-2', 'foo'], array_keys($factories));
261+
}
262+
263+
public function testDefinitionOrderIsTheSame()
264+
{
265+
$container = new ContainerBuilder();
266+
$container->register('service-1');
267+
$container->register('service-2');
268+
269+
$locator = ServiceLocatorTagPass::register($container, [
270+
'service-2' => new Reference('service-2'),
271+
'service-1' => new Reference('service-1'),
213272
]);
214273
$locator = $container->getDefinition($locator);
215274
$factories = $locator->getArguments()[0];

src/Symfony/Component/Form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@ public function __construct(
3939
/**
4040
* Transforms a normalized format into a localized money string.
4141
*
42-
* @param int|float|null $value Normalized number
42+
* @param int|float|string|null $value Normalized number
4343
*
4444
* @throws TransformationFailedException if the given value is not numeric or
4545
* if the value cannot be transformed
4646
*/
4747
public function transform(mixed $value): string
4848
{
49-
if (null !== $value && 1 !== $this->divisor) {
49+
if (null !== $value && '' !== $value && 1 !== $this->divisor) {
5050
if (!is_numeric($value)) {
5151
throw new TransformationFailedException('Expected a numeric.');
5252
}

src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@ public function __construct(
4141
/**
4242
* Transforms a number type into localized number.
4343
*
44-
* @param int|float|null $value Number value
44+
* @param int|float|string|null $value Number value
4545
*
4646
* @throws TransformationFailedException if the given value is not numeric
4747
* or if the value cannot be transformed
4848
*/
4949
public function transform(mixed $value): string
5050
{
51-
if (null === $value) {
51+
if (null === $value || '' === $value) {
5252
return '';
5353
}
5454

src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,13 @@ public function testTransformExpectsNumeric()
5454
$transformer->transform('abcd');
5555
}
5656

57+
public function testTransformEmptyString()
58+
{
59+
$transformer = new MoneyToLocalizedStringTransformer(null, null, null, 100);
60+
61+
$this->assertSame('', $transformer->transform(''));
62+
}
63+
5764
public function testTransformEmpty()
5865
{
5966
$transformer = new MoneyToLocalizedStringTransformer();

src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public static function provideTransformations()
4949
{
5050
return [
5151
[null, '', 'de_AT'],
52+
['', '', 'de_AT'],
5253
[1, '1', 'de_AT'],
5354
[1.5, '1,5', 'de_AT'],
5455
[1234.5, '1234,5', 'de_AT'],

src/Symfony/Component/Intl/Data/Generator/RegionDataGenerator.php

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,7 +160,7 @@ protected function generateDataForMeta(BundleEntryReaderInterface $reader, strin
160160
$alpha3ToAlpha2 = array_flip($alpha2ToAlpha3);
161161
asort($alpha3ToAlpha2);
162162

163-
$alpha2ToNumeric = $this->generateAlpha2ToNumericMapping($metadataBundle);
163+
$alpha2ToNumeric = $this->generateAlpha2ToNumericMapping(array_flip($this->regionCodes), $metadataBundle);
164164
$numericToAlpha2 = [];
165165
foreach ($alpha2ToNumeric as $alpha2 => $numeric) {
166166
// Add underscore prefix to force keys with leading zeros to remain as string keys.
@@ -231,7 +231,7 @@ private function generateAlpha2ToAlpha3Mapping(array $countries, ArrayAccessible
231231
return $alpha2ToAlpha3;
232232
}
233233

234-
private function generateAlpha2ToNumericMapping(ArrayAccessibleResourceBundle $metadataBundle): array
234+
private function generateAlpha2ToNumericMapping(array $countries, ArrayAccessibleResourceBundle $metadataBundle): array
235235
{
236236
$aliases = iterator_to_array($metadataBundle['alias']['territory']);
237237

@@ -250,6 +250,10 @@ private function generateAlpha2ToNumericMapping(ArrayAccessibleResourceBundle $m
250250
continue;
251251
}
252252

253+
if (!isset($countries[$data['replacement']])) {
254+
continue;
255+
}
256+
253257
if ('deprecated' === $data['reason']) {
254258
continue;
255259
}

0 commit comments

Comments
 (0)