Skip to content

Commit 73ec557

Browse files
Merge branch '5.3' into 5.4
* 5.3: (22 commits) [DI] fix fixture [ErrorHandler] fix handling buffered SilencedErrorContext [HttpClient] fix Psr18Client when allow_url_fopen=0 [DependencyInjection] Add support of PHP enumerations [Cache] handle prefixed redis connections when clearing pools [Cache] fix eventual consistency when using RedisTagAwareAdapter with a cluster [Uid] Prevent double validation in Uuid::fromString() with base32 values [Uid] Fix fromString() with low base58 values [Validator][Translation] Add ExpressionLanguageSyntax en and fr [HttpKernel] [HttpCache] Keep s-maxage=0 from ESI sub-responses Avoid broken action URL in text notification mail Fix references to CheckRememberMeConditionsListener [DependencyInjection] accept service locator definitions with no class [Cache] Disable locking on Windows by default [DependencyInjection] Fix binding "iterable $foo" when using the PHP-DSL [Config] fix tracking default values that reference the parent class [DependencyInjection] fix accepted types on FactoryTrait::factory() Fix special char used to create cache key [Runtime] Fix project dir variable when vendor not in project root [VarDumper] Fix tests for PHP 8.1 ...
2 parents a64df4a + e421c4f commit 73ec557

22 files changed

+212
-7
lines changed

Compiler/CheckDefinitionValidityPass.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ public function process(ContainerBuilder $container)
4444
}
4545

4646
// non-synthetic, non-abstract service has class
47-
if (!$definition->isAbstract() && !$definition->isSynthetic() && !$definition->getClass() && (!$definition->getFactory() || !preg_match(FileLoader::ANONYMOUS_ID_REGEXP, $id))) {
47+
if (!$definition->isAbstract() && !$definition->isSynthetic() && !$definition->getClass() && !$definition->hasTag('container.service_locator') && (!$definition->getFactory() || !preg_match(FileLoader::ANONYMOUS_ID_REGEXP, $id))) {
4848
if ($definition->getFactory()) {
4949
throw new RuntimeException(sprintf('Please add the class to service "%s" even if it is constructed by a factory since we might need to add method calls based on compile-time checks.', $id));
5050
}

Compiler/ResolveBindingsPass.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ protected function processValue($value, bool $isRoot = false)
135135
}
136136

137137
if (null !== $bindingValue && !$bindingValue instanceof Reference && !$bindingValue instanceof Definition && !$bindingValue instanceof TaggedIteratorArgument && !$bindingValue instanceof ServiceLocatorArgument) {
138-
throw new InvalidArgumentException(sprintf('Invalid value for binding key "%s" for service "%s": expected null, "%s", "%s", "%s" or ServiceLocatorArgument, "%s" given.', $key, $this->currentId, Reference::class, Definition::class, TaggedIteratorArgument::class, get_debug_type($bindingValue)));
138+
throw new InvalidArgumentException(sprintf('Invalid value for binding key "%s" for service "%s": expected "%s", "%s", "%s", "%s" or null, "%s" given.', $key, $this->currentId, Reference::class, Definition::class, TaggedIteratorArgument::class, ServiceLocatorArgument::class, get_debug_type($bindingValue)));
139139
}
140140
}
141141

Dumper/PhpDumper.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1871,6 +1871,8 @@ private function dumpValue($value, bool $interpolate = true): string
18711871

18721872
return $code;
18731873
}
1874+
} elseif ($value instanceof \UnitEnum) {
1875+
return sprintf('\%s::%s', \get_class($value), $value->name);
18741876
} elseif ($value instanceof AbstractArgument) {
18751877
throw new RuntimeException($value->getTextWithContext());
18761878
} elseif (\is_object($value) || \is_resource($value)) {

Dumper/XmlDumper.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,9 @@ private function convertParameters(array $parameters, string $type, \DOMElement
324324
$element->setAttribute('type', 'binary');
325325
$text = $this->document->createTextNode(self::phpToXml(base64_encode($value)));
326326
$element->appendChild($text);
327+
} elseif ($value instanceof \UnitEnum) {
328+
$element->setAttribute('type', 'constant');
329+
$element->appendChild($this->document->createTextNode(self::phpToXml($value)));
327330
} elseif ($value instanceof AbstractArgument) {
328331
$element->setAttribute('type', 'abstract');
329332
$text = $this->document->createTextNode(self::phpToXml($value->getText()));
@@ -381,6 +384,8 @@ public static function phpToXml($value): string
381384
return 'false';
382385
case $value instanceof Parameter:
383386
return '%'.$value.'%';
387+
case $value instanceof \UnitEnum:
388+
return sprintf('%s::%s', \get_class($value), $value->name);
384389
case \is_object($value) || \is_resource($value):
385390
throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
386391
default:

Dumper/YamlDumper.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,8 @@ private function dumpValue($value)
306306
return $this->getExpressionCall((string) $value);
307307
} elseif ($value instanceof Definition) {
308308
return new TaggedValue('service', (new Parser())->parse("_:\n".$this->addService('_', $value), Yaml::PARSE_CUSTOM_TAGS)['_']['_']);
309+
} elseif ($value instanceof \UnitEnum) {
310+
return new TaggedValue('php/const', sprintf('%s::%s', \get_class($value), $value->name));
309311
} elseif ($value instanceof AbstractArgument) {
310312
return new TaggedValue('abstract', $value->getText());
311313
} elseif (\is_object($value) || \is_resource($value)) {

Loader/Configurator/Traits/BindTrait.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ trait BindTrait
3434
final public function bind(string $nameOrFqcn, $valueOrRef): self
3535
{
3636
$valueOrRef = static::processValue($valueOrRef, true);
37-
if (!preg_match('/^(?:(?:array|bool|float|int|string)[ \t]*+)?\$/', $nameOrFqcn) && !$valueOrRef instanceof Reference) {
37+
if (!preg_match('/^(?:(?:array|bool|float|int|string|iterable)[ \t]*+)?\$/', $nameOrFqcn) && !$valueOrRef instanceof Reference) {
3838
throw new InvalidArgumentException(sprintf('Invalid binding for service "%s": named arguments must start with a "$", and FQCN must map to references. Neither applies to binding "%s".', $this->id, $nameOrFqcn));
3939
}
4040
$bindings = $this->definition->getBindings();

Loader/Configurator/Traits/FactoryTrait.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,14 @@
1212
namespace Symfony\Component\DependencyInjection\Loader\Configurator\Traits;
1313

1414
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
15+
use Symfony\Component\DependencyInjection\Loader\Configurator\ReferenceConfigurator;
1516

1617
trait FactoryTrait
1718
{
1819
/**
1920
* Sets a factory.
2021
*
21-
* @param string|array $factory A PHP callable reference
22+
* @param string|array|ReferenceConfigurator $factory A PHP callable reference
2223
*
2324
* @return $this
2425
*/

Tests/Compiler/CheckDefinitionValidityPassTest.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,16 @@ public function testProcessDetectsNonSyntheticNonAbstractDefinitionWithoutClass(
3737
$this->process($container);
3838
}
3939

40+
public function testProcessAcceptsServiceLocatorWithoutClass()
41+
{
42+
$container = new ContainerBuilder();
43+
$container->register('a')->addTag('container.service_locator');
44+
45+
$this->process($container);
46+
47+
$this->addToAssertionCount(1);
48+
}
49+
4050
public function testProcessDetectsFactoryWithoutClass()
4151
{
4252
$container = new ContainerBuilder();

Tests/Dumper/PhpDumperTest.php

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@
4242
use Symfony\Component\DependencyInjection\Tests\Compiler\Foo;
4343
use Symfony\Component\DependencyInjection\Tests\Compiler\Wither;
4444
use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition;
45+
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute;
46+
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum;
4547
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooWithAbstractArgument;
4648
use Symfony\Component\DependencyInjection\Tests\Fixtures\ScalarFactory;
4749
use Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator;
@@ -1228,6 +1230,29 @@ public function testDumpHandlesObjectClassNames()
12281230
$this->assertInstanceOf(\stdClass::class, $container->get('bar'));
12291231
}
12301232

1233+
/**
1234+
* @requires PHP 8.1
1235+
*/
1236+
public function testDumpHandlesEnumeration()
1237+
{
1238+
$container = new ContainerBuilder();
1239+
$container
1240+
->register('foo', FooClassWithEnumAttribute::class)
1241+
->setPublic(true)
1242+
->addArgument(FooUnitEnum::BAR);
1243+
1244+
$container->compile();
1245+
1246+
$dumper = new PhpDumper($container);
1247+
eval('?>'.$dumper->dump([
1248+
'class' => 'Symfony_DI_PhpDumper_Test_Enumeration',
1249+
]));
1250+
1251+
$container = new \Symfony_DI_PhpDumper_Test_Enumeration();
1252+
1253+
$this->assertSame(FooUnitEnum::BAR, $container->get('foo')->getBar());
1254+
}
1255+
12311256
public function testUninitializedSyntheticReference()
12321257
{
12331258
$container = new ContainerBuilder();

Tests/Dumper/XmlDumperTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
use Symfony\Component\DependencyInjection\Dumper\XmlDumper;
2323
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
2424
use Symfony\Component\DependencyInjection\Reference;
25+
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute;
26+
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum;
2527
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooWithAbstractArgument;
2628

2729
class XmlDumperTest extends TestCase
@@ -272,6 +274,23 @@ public function testDumpAbstractServices()
272274
$this->assertEquals(file_get_contents(self::$fixturesPath.'/xml/services_abstract.xml'), $dumper->dump());
273275
}
274276

277+
/**
278+
* @requires PHP 8.1
279+
*/
280+
public function testDumpHandlesEnumeration()
281+
{
282+
$container = new ContainerBuilder();
283+
$container
284+
->register(FooClassWithEnumAttribute::class, FooClassWithEnumAttribute::class)
285+
->setPublic(true)
286+
->addArgument(FooUnitEnum::BAR);
287+
288+
$container->compile();
289+
$dumper = new XmlDumper($container);
290+
291+
$this->assertEquals(file_get_contents(self::$fixturesPath.'/xml/services_with_enumeration.xml'), $dumper->dump());
292+
}
293+
275294
public function testDumpServiceWithAbstractArgument()
276295
{
277296
$container = new ContainerBuilder();

Tests/Dumper/YamlDumperTest.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
use Symfony\Component\DependencyInjection\Dumper\YamlDumper;
2424
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
2525
use Symfony\Component\DependencyInjection\Reference;
26+
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute;
27+
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum;
2628
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooWithAbstractArgument;
2729
use Symfony\Component\Yaml\Parser;
2830
use Symfony\Component\Yaml\Yaml;
@@ -131,6 +133,23 @@ public function testServiceClosure()
131133
$this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_with_service_closure.yml', $dumper->dump());
132134
}
133135

136+
/**
137+
* @requires PHP 8.1
138+
*/
139+
public function testDumpHandlesEnumeration()
140+
{
141+
$container = new ContainerBuilder();
142+
$container
143+
->register(FooClassWithEnumAttribute::class, FooClassWithEnumAttribute::class)
144+
->setPublic(true)
145+
->addArgument(FooUnitEnum::BAR);
146+
147+
$container->compile();
148+
$dumper = new YamlDumper($container);
149+
150+
$this->assertEquals(file_get_contents(self::$fixturesPath.'/yaml/services_with_enumeration.yml'), $dumper->dump());
151+
}
152+
134153
public function testDumpServiceWithAbstractArgument()
135154
{
136155
$container = new ContainerBuilder();
@@ -142,7 +161,6 @@ public function testDumpServiceWithAbstractArgument()
142161
$this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_with_abstract_argument.yml', $dumper->dump());
143162
}
144163

145-
146164
private function assertEqualYamlStructure(string $expected, string $yaml, string $message = '')
147165
{
148166
$parser = new Parser();
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<?php
2+
3+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
4+
5+
class FooClassWithEnumAttribute
6+
{
7+
private FooUnitEnum $bar;
8+
9+
public function __construct(FooUnitEnum $bar)
10+
{
11+
$this->bar = $bar;
12+
}
13+
14+
public function getBar(): FooUnitEnum
15+
{
16+
return $this->bar;
17+
}
18+
}

Tests/Fixtures/FooUnitEnum.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
namespace Symfony\Component\DependencyInjection\Tests\Fixtures;
4+
5+
enum FooUnitEnum
6+
{
7+
case BAR;
8+
}

Tests/Fixtures/Prototype/Foo.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
#[When(env: 'dev')]
99
class Foo implements FooInterface, Sub\BarInterface
1010
{
11-
public function __construct($bar = null)
11+
public function __construct($bar = null, iterable $foo = null)
1212
{
1313
}
1414

Tests/Fixtures/config/defaults.expected.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,14 @@ services:
1515
- t: { a: b }
1616
autowire: true
1717
autoconfigure: true
18-
arguments: ['@bar']
18+
arguments: ['@bar', !tagged_iterator foo]
1919
bar:
2020
class: Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Foo
2121
public: true
2222
tags:
2323
- t: { a: b }
2424
autowire: true
25+
arguments: [null, !tagged_iterator foo]
2526
calls:
2627
- [setFoo, ['@bar']]
2728

Tests/Fixtures/config/defaults.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
->autowire()
1515
->tag('t', ['a' => 'b'])
1616
->bind(Foo::class, service('bar'))
17+
->bind('iterable $foo', tagged_iterator('foo'))
1718
->public();
1819

1920
$s->set(Foo::class)->args([service('bar')])->public();
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd">
3+
<services>
4+
<service id="service_container" class="Symfony\Component\DependencyInjection\ContainerInterface" public="true" synthetic="true"/>
5+
<service id="Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute" class="Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute" public="true">
6+
<argument type="constant">Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAR</argument>
7+
</service>
8+
</services>
9+
</container>
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<container xmlns="http://symfony.com/schema/dic/services" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd">
3+
<services>
4+
<service id="service_container" class="Symfony\Component\DependencyInjection\ContainerInterface" public="true" synthetic="true"/>
5+
<service id="Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute" class="Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute" public="true">
6+
<argument type="constant">Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAZ</argument>
7+
</service>
8+
</services>
9+
</container>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
services:
3+
service_container:
4+
class: Symfony\Component\DependencyInjection\ContainerInterface
5+
public: true
6+
synthetic: true
7+
Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute:
8+
class: Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute
9+
public: true
10+
arguments: [!php/const 'Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAR']
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
2+
services:
3+
service_container:
4+
class: Symfony\Component\DependencyInjection\ContainerInterface
5+
public: true
6+
synthetic: true
7+
Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute:
8+
class: Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute
9+
public: true
10+
arguments: [!php/const 'Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAZ']

Tests/Loader/XmlFileLoaderTest.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
use Symfony\Component\DependencyInjection\Tests\Fixtures\Bar;
4040
use Symfony\Component\DependencyInjection\Tests\Fixtures\BarInterface;
4141
use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
42+
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute;
43+
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum;
4244
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooWithAbstractArgument;
4345
use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy;
4446
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype;
@@ -905,6 +907,32 @@ public function testInstanceof()
905907
$this->assertSame(['foo' => [[]], 'bar' => [[]]], $definition->getTags());
906908
}
907909

910+
/**
911+
* @requires PHP 8.1
912+
*/
913+
public function testEnumeration()
914+
{
915+
$container = new ContainerBuilder();
916+
$loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));
917+
$loader->load('services_with_enumeration.xml');
918+
$container->compile();
919+
920+
$definition = $container->getDefinition(FooClassWithEnumAttribute::class);
921+
$this->assertSame([FooUnitEnum::BAR], $definition->getArguments());
922+
}
923+
924+
/**
925+
* @requires PHP 8.1
926+
*/
927+
public function testInvalidEnumeration()
928+
{
929+
$container = new ContainerBuilder();
930+
$loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));
931+
932+
$this->expectException(\Error::class);
933+
$loader->load('services_with_invalid_enumeration.xml');
934+
}
935+
908936
public function testInstanceOfAndChildDefinition()
909937
{
910938
$container = new ContainerBuilder();

Tests/Loader/YamlFileLoaderTest.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@
3838
use Symfony\Component\DependencyInjection\Tests\Fixtures\Bar;
3939
use Symfony\Component\DependencyInjection\Tests\Fixtures\BarInterface;
4040
use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
41+
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute;
42+
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum;
4143
use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy;
4244
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype;
4345
use Symfony\Component\ExpressionLanguage\Expression;
@@ -957,6 +959,33 @@ public function testDefaultValueOfTagged()
957959
$this->assertNull($iteratorArgument->getIndexAttribute());
958960
}
959961

962+
/**
963+
* @requires PHP 8.1
964+
*/
965+
public function testEnumeration()
966+
{
967+
$container = new ContainerBuilder();
968+
$loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
969+
$loader->load('services_with_enumeration.yml');
970+
$container->compile();
971+
972+
$definition = $container->getDefinition(FooClassWithEnumAttribute::class);
973+
$this->assertSame([FooUnitEnum::BAR], $definition->getArguments());
974+
}
975+
976+
/**
977+
* @requires PHP 8.1
978+
*/
979+
public function testInvalidEnumeration()
980+
{
981+
$container = new ContainerBuilder();
982+
$loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
983+
984+
$this->expectException(InvalidArgumentException::class);
985+
$this->expectExceptionMessage('The constant "Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAZ" is not defined');
986+
$loader->load('services_with_invalid_enumeration.yml');
987+
}
988+
960989
public function testReturnsClone()
961990
{
962991
$container = new ContainerBuilder();

0 commit comments

Comments
 (0)