8000 [DependencyInjection] Add support of PHP enumerations by alexandre-daubois · Pull Request #40857 · symfony/symfony · GitHub
[go: up one dir, main page]

Skip to content

[DependencyInjection] Add support of PHP enumerations #40857

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
[DependencyInjection] Add support of PHP enumerations
  • Loading branch information
alexandre-daubois authored and nicolas-grekas committed Jun 23, 2021
commit 88c69c0ec02fb35ff7e9da9f4c76218857f256a9
Original file line number Diff line number Diff line change
Expand Up @@ -1812,6 +1812,8 @@ private function dumpValue($value, bool $interpolate = true): string

return $code;
}
} elseif ($value instanceof \UnitEnum) {
return sprintf('\%s::%s', \get_class($value), $value->name);
} elseif (\is_object($value) || \is_resource($value)) {
throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -313,6 +313,9 @@ private function convertParameters(array $parameters, string $type, \DOMElement
$element->setAttribute('type', 'binary');
$text = $this->document->createTextNode(self::phpToXml(base64_encode($value)));
$element->appendChild($text);
} elseif ($value instanceof \UnitEnum) {
$element->setAttribute('type', 'constant');
$element->appendChild($this->document->createTextNode(self::phpToXml($value)));
} else {
if (\in_array($value, ['null', 'true', 'false'], true)) {
$element->setAttribute('type', 'string');
Expand Down Expand Up @@ -366,6 +369,8 @@ public static function phpToXml($value): string
return 'false';
case $value instanceof Parameter:
return '%'.$value.'%';
case $value instanceof \UnitEnum:
return sprintf('%s::%s', \get_class($value), $value->name);
case \is_object($value) || \is_resource($value):
throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,8 @@ private function dumpValue($value)
return $this->getExpressionCall((string) $value);
} elseif ($value instanceof Definition) {
return new TaggedValue('service', (new Parser())->parse("_:\n".$this->addService('_', $value), Yaml::PARSE_CUSTOM_TAGS)['_']['_']);
} elseif ($value instanceof \UnitEnum) {
return new TaggedValue('php/const', sprintf('%s::%s', \get_class($value), $value->name));
} elseif (\is_object($value) || \is_resource($value)) {
throw new RuntimeException('Unable to dump a service container if a parameter is an object or a resource.');
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@
use Symfony\Component\DependencyInjection\Tests\Compiler\Foo;
use Symfony\Component\DependencyInjection\Tests\Compiler\Wither;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CustomDefinition;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum;
use Symfony\Component\DependencyInjection\Tests\Fixtures\ScalarFactory;
use Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator;
use Symfony\Component\DependencyInjection\Tests\Fixtures\TestDefinition1;
Expand Down Expand Up @@ -1208,6 +1210,29 @@ public function testDumpHandlesObjectClassNames()
$this->assertInstanceOf(\stdClass::class, $container->get('bar'));
}

/**
* @requires PHP 8.1
*/
public function testDumpHandlesEnumeration()
{
$container = new ContainerBuilder();
$container
->register('foo', FooClassWithEnumAttribute::class)
->setPublic(true)
->addArgument(FooUnitEnum::BAR);

$container->compile();

$dumper = new PhpDumper($container);
eval('?>'.$dumper->dump([
'class' => 'Symfony_DI_PhpDumper_Test_Enumeration',
]));

$container = new \Symfony_DI_PhpDumper_Test_Enumeration();

$this->assertSame(FooUnitEnum::BAR, $container->get('foo')->getBar());
}

public function testUninitializedSyntheticReference()
{
$container = new ContainerBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
use Symfony\Component\DependencyInjection\Dumper\XmlDumper;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum;

class XmlDumperTest extends TestCase
{
Expand Down Expand Up @@ -249,4 +251,21 @@ public function testDumpAbstractServices()

$this->assertEquals(file_get_contents(self::$fixturesPath.'/xml/services_abstract.xml'), $dumper->dump());
}

/**
* @requires PHP 8.1
*/
public function testDumpHandlesEnumeration()
{
$container = new ContainerBuilder();
$container
->register(FooClassWithEnumAttribute::class, FooClassWithEnumAttribute::class)
->setPublic(true)
->addArgument(FooUnitEnum::BAR);

$container->compile();
$dumper = new XmlDumper($container);

$this->assertEquals(file_get_contents(self::$fixturesPath.'/xml/services_with_enumeration.xml'), $dumper->dump());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
use Symfony\Component\DependencyInjection\Dumper\YamlDumper;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum;
use Symfony\Component\Yaml\Parser;
use Symfony\Component\Yaml\Yaml;

Expand Down Expand Up @@ -129,6 +131,23 @@ public function testServiceClosure()
$this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_with_service_closure.yml', $dumper->dump());
}

/**
* @requires PHP 8.1
*/
public function testDumpHandlesEnumeration()
{
$container = new ContainerBuilder();
$container
->register(FooClassWithEnumAttribute::class, FooClassWithEnumAttribute::class)
->setPublic(true)
->addArgument(FooUnitEnum::BAR);

$container->compile();
$dumper = new YamlDumper($container);

$this->assertEquals(file_get_contents(self::$fixturesPath.'/yaml/services_with_enumeration.yml'), $dumper->dump());
}

private function assertEqualYamlStructure(string $expected, string $yaml, string $message = '')
{
$parser = new Parser();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<?php

namespace Symfony\Component\DependencyInjection\Tests\Fixtures;

class FooClassWithEnumAttribute
{
private FooUnitEnum $bar;

public function __construct(FooUnitEnum $bar)
{
$this->bar = $bar;
}

public function getBar(): FooUnitEnum
{
return $this->bar;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Symfony\Component\DependencyInjection\Tests\Fixtures;

enum FooUnitEnum
{
case BAR;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<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">
<services>
<service id="service_container" class="Symfony\Component\DependencyInjection\ContainerInterface" public="true" synthetic="true"/>
<service id="Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute" class="Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute" public="true">
<argument type="constant">Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAR</argument>
</service>
</services>
</container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<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">
<services>
<service id="service_container" class="Symfony\Component\DependencyInjection\ContainerInterface" public="true" synthetic="true"/>
<service id="Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute" class="Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute" public="true">
<argument type="constant">Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAZ</argument>
</service>
</services>
</container>
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

services:
service_container:
class: Symfony\Component\DependencyInjection\ContainerInterface
public: true
synthetic: true
Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute:
class: Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute
public: true
arguments: [!php/const 'Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAR']
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@

services:
service_container:
class: Symfony\Component\DependencyInjection\ContainerInterface
public: true
synthetic: true
Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute:
class: Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute
public: true
arguments: [!php/const 'Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAZ']
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
use Symfony\Component\DependencyInjection\Tests\Fixtures\Bar;
use Symfony\Component\DependencyInjection\Tests\Fixtures\BarInterface;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum;
use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy;
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype;
use Symfony\Component\ExpressionLanguage\Expression;
Expand Down Expand Up @@ -827,6 +829,32 @@ public function testInstanceof()
$this->assertSame(['foo' => [[]], 'bar' => [[]]], $definition->getTags());
}

/**
* @requires PHP 8.1
*/
public function testEnumeration()
{
$container = new ContainerBuilder();
$loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));
$loader->load('services_with_enumeration.xml');
$container->compile();

$definition = $container->getDefinition(FooClassWithEnumAttribute::class);
$this->assertSame([FooUnitEnum::BAR], $definition->getArguments());
}

/**
* @requires PHP 8.1
*/
public function testInvalidEnumeration()
{
$container = new ContainerBuilder();
$loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));

$this->expectException(\Error::class);
$loader->load('services_with_invalid_enumeration.xml');
}

public function testInstanceOfAndChildDefinitionNotAllowed()
{
$this->expectException(InvalidArgumentException::class);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
use Symfony\Component\DependencyInjection\Tests\Fixtures\Bar;
use Symfony\Component\DependencyInjection\Tests\Fixtures\BarInterface;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum;
use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy;
use Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype;
use Symfony\Component\ExpressionLanguage\Expression;
Expand Down Expand Up @@ -909,6 +911,33 @@ public function testDefaultValueOfTagged()
$this->assertNull($iteratorArgument->getIndexAttribute());
}

/**
* @requires PHP 8.1
*/
public function testEnumeration()
{
$container = new ContainerBuilder();
$loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
$loader->load('services_with_enumeration.yml');
$container->compile();

$definition = $container->getDefinition(FooClassWithEnumAttribute::class);
$this->assertSame([FooUnitEnum::BAR], $definition->getArguments());
}

/**
* @requires PHP 8.1
*/
public function testInvalidEnumeration()
{
$container = new ContainerBuilder();
$loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));

$this->expectException(InvalidArgumentException::class);
$this->expectExceptionMessage('The constant "Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum::BAZ" is not defined');
$loader->load('services_with_invalid_enumeration.yml');
}

public function testReturnsClone()
{
$container = new ContainerBuilder();
Expand Down
2 changes: 2 additions & 0 deletions src/Symfony/Component/Yaml/Inline.php
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ public static function dump($value, int $flags = 0): string
return self::dumpNull($flags);
case $value instanceof \DateTimeInterface:
return $value->format('c');
case $value instanceof \UnitEnum:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we add new things in the Yaml component, I'd really appreciate to add some tests there covering this kind of feature

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added one here. Not sure if there's another one to add? This one should be enough if I'm right.

Copy link
Member
@derrabus derrabus Jun 6, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to adjust the DI component's composer.json?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, the current composer.json seems good with "^4.4|^5.0"

return sprintf('!php/const %s::%s', \get_class($value), $value->name);
case \is_object($value):
if ($value instanceof TaggedValue) {
return '!'.$value->getTag().' '.self::dump($value->getValue(), $flags);
Expand Down
8 changes: 8 additions & 0 deletions src/Symfony/Component/Yaml/Tests/Fixtures/FooUnitEnum.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Symfony\Component\Yaml\Tests\Fixtures;

enum FooUnitEnum
{
case BAR;
}
9 changes: 9 additions & 0 deletions src/Symfony/Component/Yaml/Tests/InlineTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
use Symfony\Component\Yaml\Exception\ParseException;
use Symfony\Component\Yaml\Inline;
use Symfony\Component\Yaml\Tag\TaggedValue;
use Symfony\Component\Yaml\Tests\Fixtures\FooUnitEnum;
use Symfony\Component\Yaml\Yaml;

class InlineTest extends TestCase
Expand Down Expand Up @@ -577,6 +578,14 @@ public function testDumpDateTime($dateTime, $expected)
$this->assertSame($expected, Inline::dump($dateTime));
}

/**
* @requires PHP 8.1
*/
public function testDumpUnitEnum()
{
$this->assertSame("!php/const Symfony\Component\Yaml\Tests\Fixtures\FooUnitEnum::BAR", Inline::dump(FooUnitEnum::BAR));
}

public function getDateTimeDumpTests()
{
$tests = [];
Expand Down
0