diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md
index 54095a8d37ae5..95a0cf8e54cdd 100644
--- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md
+++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md
@@ -1,6 +1,11 @@
CHANGELOG
=========
+7.2
+---
+
+ * Add `binary_flags` parameter and argument types in `XmlFileLoader`
+
7.1
---
diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
index f2f464305f7ff..4404d45c234a5 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php
@@ -623,6 +623,10 @@ private function getArgumentsAsPhp(\DOMElement $node, string $name, string $file
case 'constant':
$arguments[$key] = \constant(trim($arg->nodeValue));
break;
+ case 'binary_flags':
+ $constants = \array_map(\constant(...), \array_map(trim(...), \explode('|', $arg->nodeValue)));
+ $arguments[$key] = \array_reduce($constants, static fn ($carry, $item) => $carry | $item, 0);
+ break;
default:
$arguments[$key] = XmlUtils::phpize($trim ? trim($arg->nodeValue) : $arg->nodeValue);
}
diff --git a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd
index c071e3466613c..4679bb55f02f4 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd
+++ b/src/Symfony/Component/DependencyInjection/Loader/schema/dic/services/services-1.0.xsd
@@ -342,6 +342,7 @@
+
@@ -354,6 +355,7 @@
+
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooClassWithFlags.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooClassWithFlags.php
new file mode 100644
index 0000000000000..bbee77cae6413
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/FooClassWithFlags.php
@@ -0,0 +1,14 @@
+
+
+
+ Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithFlags::FLAG_A
+
+
+
+
+ Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithFlags::FLAG_A | Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithFlags::FLAG_C
+
+
+
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_invalid_binary_flags.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_invalid_binary_flags.xml
new file mode 100644
index 0000000000000..add1782de2ec5
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_with_invalid_binary_flags.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+ Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithFlags::WRONG_FLAG
+
+
+
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php
index 64df6cc7f79b5..b0fcec8dd7773 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php
@@ -40,6 +40,7 @@
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\FooClassWithFlags;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooWithAbstractArgument;
use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy;
@@ -964,6 +965,26 @@ public function testInvalidEnumeration()
$loader->load('services_with_invalid_enumeration.xml');
}
+ public function testBinaryFlags()
+ {
+ $container = new ContainerBuilder();
+ $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));
+ $loader->load('services_with_binary_flags.xml');
+ $container->compile();
+
+ $definition = $container->getDefinition(FooClassWithFlags::class);
+ $this->assertSame([FooClassWithFlags::FLAG_A | FooClassWithFlags::FLAG_C], $definition->getArguments());
+ }
+
+ public function testInvalidBinaryFlags()
+ {
+ $container = new ContainerBuilder();
+ $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml'));
+
+ $this->expectException(\Error::class);
+ $loader->load('services_with_invalid_binary_flags.xml');
+ }
+
public function testInstanceOfAndChildDefinition()
{
$container = new ContainerBuilder();
diff --git a/src/Symfony/Component/Yaml/CHANGELOG.md b/src/Symfony/Component/Yaml/CHANGELOG.md
index 05b23cd7b06fe..15bf4feb54401 100644
--- a/src/Symfony/Component/Yaml/CHANGELOG.md
+++ b/src/Symfony/Component/Yaml/CHANGELOG.md
@@ -5,6 +5,7 @@ CHANGELOG
---
* Deprecate parsing duplicate mapping keys whose value is `null`
+ * Add support for binary flags with the `!!binary_flags` tag
7.1
---
diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php
index 58d389866f52e..241722fc6b750 100644
--- a/src/Symfony/Component/Yaml/Inline.php
+++ b/src/Symfony/Component/Yaml/Inline.php
@@ -681,6 +681,15 @@ private static function evaluateScalar(string $scalar, int $flags, array &$refer
return (float) substr($scalar, 8);
case str_starts_with($scalar, '!!binary '):
return self::evaluateBinaryScalar(substr($scalar, 9));
+ case str_starts_with($scalar, '!!binary_flags '):
+ if (self::$constantSupport) {
+ return self::evaluateBinaryFlags(substr($scalar, 15));
+ }
+ if (self::$exceptionOnInvalidType) {
+ throw new ParseException(\sprintf('The string "%s" could not be parsed as binary flags. Did you forget to pass the "Yaml::PARSE_CONSTANT" flag to the parser?', $scalar), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename);
+ }
+
+ return null;
}
throw new ParseException(\sprintf('The string "%s" could not be parsed as it uses an unsupported built-in tag.', $scalar), self::$parsedLineNumber, $scalar, self::$parsedFilename);
@@ -797,6 +806,28 @@ public static function evaluateBinaryScalar(string $scalar): string
return base64_decode($parsedBinaryData, true);
}
+ public static function evaluateBinaryFlags(string $flags): int
+ {
+ $constants = \explode('|', $flags);
+ $result = 0;
+
+ foreach ($constants as $rawConstant) {
+ $rawConstant = \trim($rawConstant);
+ if (!\defined($rawConstant)) {
+ throw new ParseException(\sprintf('The constant "%s" is not defined.', $rawConstant), self::$parsedLineNumber + 1, $flags, self::$parsedFilename);
+ }
+
+ $constant = \constant($rawConstant);
+ if (!\is_int($constant)) {
+ throw new ParseException(\sprintf('The constant "%s" is not an integer.', $rawConstant), self::$parsedLineNumber + 1, $flags, self::$parsedFilename);
+ }
+
+ $result |= $constant;
+ }
+
+ return $result;
+ }
+
private static function isBinaryString(string $value): bool
{
return !preg_match('//u', $value) || preg_match('/[^\x00\x07-\x0d\x1B\x20-\xff]/', $value);
diff --git a/src/Symfony/Component/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php
index e58ca51149c14..6d29f9a05d3f4 100644
--- a/src/Symfony/Component/Yaml/Tests/InlineTest.php
+++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php
@@ -119,6 +119,42 @@ public function testParsePhpEnumThrowsExceptionOnInvalidType()
Inline::parse('!php/enum SomeEnum::Foo', Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE);
}
+ public function testParseSingleBinaryFlag()
+ {
+ $this->assertSame(Yaml::PARSE_CONSTANT, Inline::parse('!!binary_flags Symfony\Component\Yaml\Yaml::PARSE_CONSTANT', Yaml::PARSE_CONSTANT));
+ }
+
+ public function testParseMultipleBinaryFlags()
+ {
+ $this->assertSame(Yaml::PARSE_CONSTANT | Yaml::PARSE_CUSTOM_TAGS, Inline::parse('!!binary_flags Symfony\Component\Yaml\Yaml::PARSE_CONSTANT | Symfony\Component\Yaml\Yaml::PARSE_CUSTOM_TAGS', Yaml::PARSE_CONSTANT));
+ }
+
+ public function testParseBinaryFlagsThrowsExceptionWhenUndefined()
+ {
+ $this->expectException(ParseException::class);
+ $this->expectExceptionMessage('The constant "WRONG_CONSTANT" is not defined');
+ Inline::parse('!!binary_flags WRONG_CONSTANT', Yaml::PARSE_CONSTANT);
+ }
+
+ public function testParseBinaryFlagsThrowsExceptionWhenNotAnInt()
+ {
+ $this->expectException(ParseException::class);
+ $this->expectExceptionMessage('The constant "DIRECTORY_SEPARATOR" is not an integer');
+ Inline::parse('!!binary_flags DIRECTORY_SEPARATOR', Yaml::PARSE_CONSTANT);
+ }
+
+ public function testParseBinaryFlagsWithoutFlags()
+ {
+ $this->assertNull(Inline::parse('!!binary_flags PHP_INT_MAX'));
+ }
+
+ public function testParseBinaryFlagsWithoutOptionToParseConstants()
+ {
+ $this->expectException(ParseException::class);
+ $this->expectExceptionMessageMatches('/The string "!!binary_flags PHP_INT_MAX" could not be parsed as binary flags.*/');
+ Inline::parse('!!binary_flags PHP_INT_MAX', Yaml::PARSE_EXCEPTION_ON_INVALID_TYPE);
+ }
+
/**
* @dataProvider getTestsForDump
*/