10000 [DependencyInjection] Add support of PHP 8.1 enumerations · symfony/symfony@9d8fa01 · GitHub
[go: up one dir, main page]

Skip to content

Commit 9d8fa01

Browse files
[DependencyInjection] Add support of PHP 8.1 enumerations
1 parent 3fd41ce commit 9d8fa01

21 files changed

+253
-3
lines changed

src/Symfony/Component/DependencyInjection/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ CHANGELOG
1717
* Add `env()` and `EnvConfigurator` in the PHP-DSL
1818
* Add support for `ConfigBuilder` in the `PhpFileLoader`
1919
* Add `ContainerConfigurator::env()` to get the current environment
20+
* Add support of PHP 8.1 enumerations
2021

2122
5.2.0
2223
-----

src/Symfony/Component/DependencyInjection/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)) {

src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -327,6 +327,9 @@ private function convertParameters(array $parameters, string $type, \DOMElement
327327
$element->setAttribute('type', 'abstract');
328328
$text = $this->document->createTextNode(self::phpToXml($value->getText()));
329329
$element->appendChild($text);
330+
} elseif ($value instanceof \UnitEnum) {
331+
$element->setAttribute('type', 'enumeration');
332+
$element->appendChild($this->document->createTextNode(self::phpToXml($value)));
330333
} else {
331334
if (\in_array($value, ['null', 'true', 'false'], true)) {
332335
$element->setAttribute('type', 'string');
@@ -380,6 +383,8 @@ public static function phpToXml($value): string
380383
return 'false';
381384
case $value instanceof Parameter:
382385
return '%'.$value.'%';
386+
case $value instanceof \UnitEnum:
387+
return sprintf('%s::%s', \get_class($value), $value->name);
383388
case \is_object($value) || \is_resource($value):
384389
throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
385390
default:

src/Symfony/Component/DependencyInjection/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 new TaggedValue('service', (new Parser())->parse("_:\n".$this->addService('_', $value), Yaml::PARSE_CUSTOM_TAGS)['_']['_']);
307307
} elseif ($value instanceof AbstractArgument) {
308308
return new TaggedValue('abstract', $value->getText());
309+
} elseif ($value instanceof \UnitEnum) {
310+
return new TaggedValue('php/enum', $value);
309311
} elseif (\is_object($value) || \is_resource($value)) {
310312
throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
311313
}

src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,7 @@ private function getArgumentsAsPhp(\DOMElement $node, string $name, string $file
550550
$arguments[$key] = $arg->nodeValue;
551551
break;
552552
case 'constant':
553+
case 'enumeration':
553554
$arguments[$key] = \constant(trim($arg->nodeValue));
554555
break;
555556
default:

src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -766,7 +766,7 @@ protected function loadFile($file)
766766
}
767767

768768
try {
769-
$configuration = $this->yamlParser->parseFile($file, Yaml::PARSE_CONSTANT | Yaml::PARSE_CUSTOM_TAGS);
769+
$configuration = $this->yamlParser->parseFile($file, Yaml::PARSE_CONSTANT | Yaml::PARSE_CUSTOM_TAGS | Yaml::PARSE_ENUMERATION);
770770
} catch (ParseException $e) {
771771
throw new InvalidArgumentException(sprintf('The file "%s" does not contain valid YAML: ', $file).$e->getMessage(), 0, $e);
772772
}
@@ -884,6 +884,13 @@ private function resolveServices($value, string $file, bool $isParameter = false
884884
if ('abstract' === $value->getTag()) {
885885
return new AbstractArgument($value->getValue());
886886
}
887+
if ('php/enum' === $value->getTag()) {
888+
if (\defined($value->getValue())) {
889+
return \constant($value->getValue());
890+
}
891+
892+
throw new InvalidArgumentException(sprintf('The enumeration case "%s" is not defined.', $value->getValue()));
893+
}
887894

888895
throw new InvalidArgumentException(sprintf('Unsupported tag "!%s".', $value->getTag()));
889896
}

src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,7 @@
299299
<xsd:enumeration value="collection" />
300300
<xsd:enumeration value="string" />
301301
<xsd:enumeration value="constant" />
302+
<xsd:enumeration value="enumeration" />
302303
<xsd:enumeration value="binary" />
303304
</xsd:restriction>
304305
</xsd:simpleType>
@@ -311,6 +312,7 @@
311312
<xsd:enumeration value="expression" />
312313
<xsd:enumeration value="string" />
313314
<xsd:enumeration value="constant" />
315+
<xsd:enumeration value="enumeration" />
314316
<xsd:enumeration value="binary" />
315317
<xsd:enumeration value="iterator" />
316318
<xsd:enumeration value="service_locator" />

src/Symfony/Component/DependencyInjection/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;
@@ -1224,6 +1226,29 @@ public function testDumpHandlesObjectClassNames()
12241226
$this->assertInstanceOf(\stdClass::class, $container->get('bar'));
12251227
}
12261228

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

src/Symfony/Component/DependencyInjection/Tests/Dumper/XmlDumperTest.php

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

2628
class XmlDumperTest extends TestCase
@@ -270,4 +272,21 @@ public function testDumpServiceWithAbstractArgument()
270272
$dumper = new XmlDumper($container);
271273
$this->assertStringEqualsFile(self::$fixturesPath.'/xml/services_with_abstract_argument.xml', $dumper->dump());
272274
}
275+
276+
/**
277+
* @requires PHP >= 8.1
278+
*/
279+
public function testDumpHandlesEnumeration()
280+
{
281+
$container = new ContainerBuilder();
282+
$container
283+
->register(FooClassWithEnumAttribute::class, FooClassWithEnumAttribute::class)
284+
->setPublic(true)
285+
->addArgument(FooUnitEnum::BAR);
286+
287+
$container->compile();
288+
$dumper = new XmlDumper($container);
289+
290+
$this->assertEquals(file_get_contents(self::$fixturesPath.'/xml/services_with_enumeration.xml'), $dumper->dump());
291+
}
273292
}

src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.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\YamlDumper;
2323
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
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
use Symfony\Component\Yaml\Parser;
2729
use Symfony\Component\Yaml\Yaml;
@@ -130,6 +132,23 @@ public function testDumpServiceWithAbstractArgument()
130132
$this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_with_abstract_argument.yml', $dumper->dump());
131133
}
132134

135+
/**
136+
* @requires PHP >= 8.1
137+
*/
138+
public function testDumpHandlesEnumeration()
139+
{
140+
$container = new ContainerBuilder();
141+
$container
142+
->register(FooClassWithEnumAttribute::class, FooClassWithEnumAttribute::class)
143+
->setPublic(true)
144+
->addArgument(FooUnitEnum::BAR);
145+
146+
$container->compile();
147+
$dumper = new YamlDumper($container);
148+
149+
$this->assertEquals(file_get_contents(self::$fixturesPath.'/yaml/services_with_enumeration.yml'), $dumper->dump());
150+
}
151+
133152
private function assertEqualYamlStructure(string $expected, string $yaml, string $message = '')
134153
{
135154
$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+
}
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+
}
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="enumeration">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="enumeration">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/enum]
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/enum 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/enum Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAZ]

src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php

Lines changed: 28 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\FooWithAbstractArgument;
4244
use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy;
4345
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype;
@@ -858,6 +860,32 @@ public function testInstanceof()
858860
$this->assertSame(['foo' => [[]], 'bar' => [[]]], $definition->getTags());
859861
}
860862

863+
/**
864+
* @requires PHP >= 8.1
865+
*/
866+
public function testEnumeration()
867+
{
868+
$container = new ContainerBuilder();
869+
$loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));
870+
$loader->load('services_with_enumeration.xml');
871+
$container->compile();
872+
873+
$definition = $container->getDefinition(FooClassWithEnumAttribute::class);
874+
$this->assertSame([FooUnitEnum::BAR], $definition->getArguments());
875+
}
876+
877+
/**
878+
* @requires PHP >= 8.1
879+
*/
880+
public function testInvalidEnumeration()
881+
{
882+
$container = new ContainerBuilder();
883+
$loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));
884+
885+
$this->expectException(\Error::class);
886+
$loader->load('services_with_invalid_enumeration.xml');
887+
}
888+
861889
public function testInstanceOfAndChildDefinition()
862890
{
863891
$container = new ContainerBuilder();

src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
use Symfony\Component\DependencyInjection\Tests\Fixtures\Bar;
3838
use Symfony\Component\DependencyInjection\Tests\Fixtures\BarInterface;
3939
use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
40+
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute;
41+
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum;
4042
use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy;
4143
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype;
4244
use Symfony\Component\ExpressionLanguage\Expression;
@@ -910,6 +912,46 @@ public function testDefaultValueOfTagged()
910912
$this->assertNull($iteratorArgument->getIndexAttribute());
911913
}
912914

915+
/**
916+
* @requires PHP >= 8.1
917+
*/
918+
public function testEnumeration()
919+
{
920+
$container = new ContainerBuilder();
921+
$loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
922+
$loader->load('services_with_enumeration.yml');
923+
$container->compile();
924+
925+
$definition = $container->getDefinition(FooClassWithEnumAttribute::class);
926+
$this->assertSame([FooUnitEnum::BAR], $definition->getArguments());
927+
}
928+
929+
/**
930+
* @requires PHP >= 8.1
931+
*/
932+
public function testEmptyEnumeration()
933+
{
934+
$container = new ContainerBuilder();
935+
$loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
936+
937+
$this->expectException(InvalidArgumentException::class);
938+
$this->expectExceptionMessage('Using the !php/enum tag without a value is forbidden');
939+
$loader->load('services_with_empty_enumeration.yml');
940+
}
941+
942+
/**
943+
* @requires PHP >= 8.1
944+
*/
945+
public function testInvalidEnumeration()
946+
{
947+
$container = new ContainerBuilder();
948+
$loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
949+
950+
$this->expectException(InvalidArgumentException::class);
951+
$this->expectExceptionMessage('The enumeration case "Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAZ" is not defined');
952+
$loader->load('services_with_invalid_enumeration.yml');
953+
}
954+
913955
public function testReturnsClone()
914956
{
915957
$container = new ContainerBuilder();

0 commit comments

Comments
 (0)
0