{% if collector.firewall %}
diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json
index f16293d3939ce..f336cdae7dd69 100644
--- a/src/Symfony/Bundle/SecurityBundle/composer.json
+++ b/src/Symfony/Bundle/SecurityBundle/composer.json
@@ -30,7 +30,7 @@
"symfony/security-http": "^6.2"
},
"require-dev": {
- "doctrine/annotations": "^1.10.4",
+ "doctrine/annotations": "^1.10.4|^2",
"symfony/asset": "^5.4|^6.0",
"symfony/browser-kit": "^5.4|^6.0",
"symfony/console": "^5.4|^6.0",
diff --git a/src/Symfony/Bundle/TwigBundle/composer.json b/src/Symfony/Bundle/TwigBundle/composer.json
index b587875e2529b..e7297860ff44b 100644
--- a/src/Symfony/Bundle/TwigBundle/composer.json
+++ b/src/Symfony/Bundle/TwigBundle/composer.json
@@ -36,7 +36,7 @@
"symfony/yaml": "^5.4|^6.0",
"symfony/framework-bundle": "^5.4|^6.0",
"symfony/web-link": "^5.4|^6.0",
- "doctrine/annotations": "^1.10.4"
+ "doctrine/annotations": "^1.10.4|^2"
},
"conflict": {
"symfony/framework-bundle": "<5.4",
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig
index 0c3bff7281946..ff7c3d93642dd 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig
+++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig
@@ -839,13 +839,11 @@ if (typeof Sfjs === 'undefined' || typeof Sfjs.loadToolbar === 'undefined') {
emailRows.forEach((emailRow) => {
emailRow.addEventListener('click', () => {
- emailRow.addEventListener('click', () => {
- emailRows.forEach((row) => row.classList.remove('active'));
- emailRow.classList.add('active');
+ emailRows.forEach((row) => row.classList.remove('active'));
+ emailRow.classList.add('active');
- document.querySelectorAll('.mailer-email-details').forEach((emailDetails) => emailDetails.style.display = 'none');
- document.querySelector(emailRow.getAttribute('data-target')).style.display = 'block';
- });
+ document.querySelectorAll('.mailer-email-details').forEach((emailDetails) => emailDetails.style.display = 'none');
+ document.querySelector(emailRow.getAttribute('data-target')).style.display = 'block';
});
});
},
diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php
index f791e82343f3a..e06029ee4f677 100644
--- a/src/Symfony/Component/Cache/Traits/RedisTrait.php
+++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php
@@ -202,7 +202,7 @@ public static function createConnection(string $dsn, array $options = []): \Redi
break;
}
- $sentinel = new \RedisSentinel($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout']);
+ $sentinel = new \RedisSentinel($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout'], ...\defined('Redis::OPT_NULL_MULTIBULK_AS_NULL') ? [$params['auth'] ?? ''] : []);
if ($address = $sentinel->getMasterAddrByName($params['redis_sentinel'])) {
[$host, $port] = $address;
@@ -214,7 +214,10 @@ public static function createConnection(string $dsn, array $options = []): \Redi
}
try {
- @$redis->{$connect}($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout'], ...\defined('Redis::SCAN_PREFIX') ? [['stream' => $params['ssl'] ?? null]] : []);
+ @$redis->{$connect}($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout'], ...\defined('Redis::SCAN_PREFIX') ? [[
+ 'auth' => $params['auth'] ?? '',
+ 'stream' => $params['ssl'] ?? null,
+ ]] : []);
set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
try {
diff --git a/src/Symfony/Component/Console/Helper/ProgressBar.php b/src/Symfony/Component/Console/Helper/ProgressBar.php
index b65bba2267315..0d1126097e50f 100644
--- a/src/Symfony/Component/Console/Helper/ProgressBar.php
+++ b/src/Symfony/Component/Console/Helper/ProgressBar.php
@@ -54,7 +54,6 @@ final class ProgressBar
private int $startTime;
private int $stepWidth;
private float $percent = 0.0;
- private int $formatLineCount;
private array $messages = [];
private bool $overwrite = true;
private Terminal $terminal;
@@ -442,8 +441,6 @@ private function setRealFormat(string $format)
} else {
$this->format = $format;
}
-
- $this->formatLineCount = substr_count($this->format, "\n");
}
/**
@@ -460,7 +457,7 @@ private function overwrite(string $message): void
if ($this->overwrite) {
if (null !== $this->previousMessage) {
if ($this->output instanceof ConsoleSectionOutput) {
- $messageLines = explode("\n", $message);
+ $messageLines = explode("\n", $this->previousMessage);
$lineCount = \count($messageLines);
foreach ($messageLines as $messageLine) {
$messageLineLength = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $messageLine));
@@ -470,13 +467,11 @@ private function overwrite(string $message): void
}
$this->output->clear($lineCount);
} else {
- if ('' !== $this->previousMessage) {
- // only clear upper lines when last call was not a clear
- for ($i = 0; $i < $this->formatLineCount; ++$i) {
- $this->cursor->moveToColumn(1);
- $this->cursor->clearLine();
- $this->cursor->moveUp();
- }
+ $lineCount = substr_count($this->previousMessage, "\n");
+ for ($i = 0; $i < $lineCount; ++$i) {
+ $this->cursor->moveToColumn(1);
+ $this->cursor->clearLine();
+ $this->cursor->moveUp();
}
$this->cursor->moveToColumn(1);
diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php
index c82c3eb188418..248d97be897f2 100644
--- a/src/Symfony/Component/Console/Tests/ApplicationTest.php
+++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php
@@ -2005,6 +2005,10 @@ public function testSetSignalsToDispatchEvent()
public function testSignalableCommandInterfaceWithoutSignals()
{
+ if (!\defined('SIGUSR1')) {
+ $this->markTestSkipped('SIGUSR1 not available');
+ }
+
$command = new SignableCommand(false);
$dispatcher = new EventDispatcher();
diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php
index b8d29a1e8969e..b8f6aa5dcda71 100644
--- a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php
+++ b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php
@@ -424,8 +424,8 @@ public function testOverwriteWithAnsiSectionOutput()
rewind($output->getStream());
$this->assertSame(
" \033[44;37m 0/50\033[0m [>---------------------------] 0%".\PHP_EOL.
- "\x1b[1A\x1b[0J"." \033[44;37m 1/50\033[0m [>---------------------------] 2%".\PHP_EOL.
- "\x1b[1A\x1b[0J"." \033[44;37m 2/50\033[0m [=>--------------------------] 4%".\PHP_EOL,
+ "\x1b[1A\x1b[0J \033[44;37m 1/50\033[0m [>---------------------------] 2%".\PHP_EOL.
+ "\x1b[1A\x1b[0J \033[44;37m 2/50\033[0m [=>--------------------------] 4%".\PHP_EOL,
stream_get_contents($output->getStream())
);
putenv('COLUMNS=120');
@@ -460,6 +460,28 @@ public function testOverwriteMultipleProgressBarsWithSectionOutputs()
);
}
+ public function testOverwritWithNewlinesInMessage()
+ {
+ ProgressBar::setFormatDefinition('test', '%current%/%max% [%bar%] %percent:3s%% %message% Fruitcake marzipan toffee. Cupcake gummi bears tart dessert ice cream chupa chups cupcake chocolate bar sesame snaps. Croissant halvah cookie jujubes powder macaroon. Fruitcake bear claw bonbon jelly beans oat cake pie muffin Fruitcake marzipan toffee.');
+
+ $bar = new ProgressBar($output = $this->getOutputStream(), 50, 0);
+ $bar->setFormat('test');
+ $bar->start();
+ $bar->display();
+ $bar->setMessage("Twas brillig, and the slithy toves. Did gyre and gimble in the wabe: All mimsy were the borogoves, And the mome raths outgrabe.\nBeware the Jabberwock, my son! The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun The frumious Bandersnatch!");
+ $bar->advance();
+ $bar->setMessage("He took his vorpal sword in hand; Long time the manxome foe he sought— So rested he by the Tumtum tree And stood awhile in thought.\nAnd, as in uffish thought he stood, The Jabberwock, with eyes of flame, Came whiffling through the tulgey wood, And burbled as it came!");
+ $bar->advance();
+
+ rewind($output->getStream());
+ $this->assertEquals(
+ " 0/50 [>] 0% %message% Fruitcake marzipan toffee. Cupcake gummi bears tart dessert ice cream chupa chups cupcake chocolate bar sesame snaps. Croissant halvah cookie jujubes powder macaroon. Fruitcake bear claw bonbon jelly beans oat cake pie muffin Fruitcake marzipan toffee.\x1b[1G\x1b[2K 1/50 [>] 2% Twas brillig, and the slithy toves. Did gyre and gimble in the wabe: All mimsy were the borogoves, And the mome raths outgrabe.
+Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun The frumious Bandersnatch! Fruitcake marzipan toffee. Cupcake gummi bears tart dessert ice cream chupa chups cupcake chocolate bar sesame snaps. Croissant halvah cookie jujubes powder macaroon. Fruitcake bear claw bonbon jelly beans oat cake pie muffin Fruitcake marzipan toffee.\x1b[1G\x1b[2K\x1b[1A\x1b[1G\x1b[2K 2/50 [>] 4% He took his vorpal sword in hand; Long time the manxome foe he sought— So rested he by the Tumtum tree And stood awhile in thought.
+And, as in uffish thought he stood, The Jabberwock, with eyes of flame, Came whiffling through the tulgey wood, And burbled as it came! Fruitcake marzipan toffee. Cupcake gummi bears tart dessert ice cream chupa chups cupcake chocolate bar sesame snaps. Croissant halvah cookie jujubes powder macaroon. Fruitcake bear claw bonbon jelly beans oat cake pie muffin Fruitcake marzipan toffee.",
+ stream_get_contents($output->getStream())
+ );
+ }
+
public function testOverwriteWithSectionOutputWithNewlinesInMessage()
{
$sections = [];
@@ -480,7 +502,7 @@ public function testOverwriteWithSectionOutputWithNewlinesInMessage()
rewind($output->getStream());
$this->assertEquals(
' 0/50 [>] 0% %message% Fruitcake marzipan toffee. Cupcake gummi bears tart dessert ice cream chupa chups cupcake chocolate bar sesame snaps. Croissant halvah cookie jujubes powder macaroon. Fruitcake bear claw bonbon jelly beans oat cake pie muffin Fruitcake marzipan toffee.'.\PHP_EOL.
- "\x1b[6A\x1b[0J 1/50 [>] 2% Twas brillig, and the slithy toves. Did gyre and gimble in the wabe: All mimsy were the borogoves, And the mome raths outgrabe.
+ "\x1b[3A\x1b[0J 1/50 [>] 2% Twas brillig, and the slithy toves. Did gyre and gimble in the wabe: All mimsy were the borogoves, And the mome raths outgrabe.
Beware the Jabberwock, my son! The jaws that bite, the claws that catch! Beware the Jubjub bird, and shun The frumious Bandersnatch! Fruitcake marzipan toffee. Cupcake gummi bears tart dessert ice cream chupa chups cupcake chocolate bar sesame snaps. Croissant halvah cookie jujubes powder macaroon. Fruitcake bear claw bonbon jelly beans oat cake pie muffin Fruitcake marzipan toffee.".\PHP_EOL.
"\x1b[6A\x1b[0J 2/50 [>] 4% He took his vorpal sword in hand; Long time the manxome foe he sought— So rested he by the Tumtum tree And stood awhile in thought.
And, as in uffish thought he stood, The Jabberwock, with eyes of flame, Came whiffling through the tulgey wood, And burbled as it came! Fruitcake marzipan toffee. Cupcake gummi bears tart dessert ice cream chupa chups cupcake chocolate bar sesame snaps. Croissant halvah cookie jujubes powder macaroon. Fruitcake bear claw bonbon jelly beans oat cake pie muffin Fruitcake marzipan toffee.".\PHP_EOL,
diff --git a/src/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php b/src/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php
index 0b2767a8e8088..3c77cf091c6fd 100644
--- a/src/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php
+++ b/src/Symfony/Component/CssSelector/Parser/Tokenizer/TokenizerPatterns.php
@@ -49,22 +49,22 @@ public function __construct()
$this->identifierPattern = '-?(?:'.$this->nmStartPattern.')(?:'.$this->nmCharPattern.')*';
$this->hashPattern = '#((?:'.$this->nmCharPattern.')+)';
$this->numberPattern = '[+-]?(?:[0-9]*\.[0-9]+|[0-9]+)';
- $this->quotedStringPattern = '([^\n\r\f%s]|'.$this->stringEscapePattern.')*';
+ $this->quotedStringPattern = '([^\n\r\f\\\\%s]|'.$this->stringEscapePattern.')*';
}
public function getNewLineEscapePattern(): string
{
- return '~^'.$this->newLineEscapePattern.'~';
+ return '~'.$this->newLineEscapePattern.'~';
}
public function getSimpleEscapePattern(): string
{
- return '~^'.$this->simpleEscapePattern.'~';
+ return '~'.$this->simpleEscapePattern.'~';
}
public function getUnicodeEscapePattern(): string
{
- return '~^'.$this->unicodeEscapePattern.'~i';
+ return '~'.$this->unicodeEscapePattern.'~i';
}
public function getIdentifierPattern(): string
diff --git a/src/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php b/src/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
index 48a67f5ab6678..77ce5d58258a2 100644
--- a/src/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
+++ b/src/Symfony/Component/CssSelector/Tests/Parser/ParserTest.php
@@ -138,6 +138,16 @@ public function getParserTestData()
['div:not(div.foo)', ['Negation[Element[div]:not(Class[Element[div].foo])]']],
['td ~ th', ['CombinedSelector[Element[td] ~ Element[th]]']],
['.foo[data-bar][data-baz=0]', ["Attribute[Attribute[Class[Element[*].foo][data-bar]][data-baz = '0']]"]],
+ ['div#foo\.bar', ['Hash[Element[div]#foo.bar]']],
+ ['div.w-1\/3', ['Class[Element[div].w-1/3]']],
+ ['#test\:colon', ['Hash[Element[*]#test:colon]']],
+ [".a\xc1b", ["Class[Element[*].a\xc1b]"]],
+ // unicode escape: \22 == "
+ ['*[aval="\'\22\'"]', ['Attribute[Element[*][aval = \'\'"\'\']]']],
+ ['*[aval="\'\22 2\'"]', ['Attribute[Element[*][aval = \'\'"2\'\']]']],
+ // unicode escape: \20 == (space)
+ ['*[aval="\'\20 \'"]', ['Attribute[Element[*][aval = \'\' \'\']]']],
+ ["*[aval=\"'\\20\r\n '\"]", ['Attribute[Element[*][aval = \'\' \'\']]']],
];
}
diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
index e930724810ae9..62c3f253ad23c 100644
--- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
+++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
@@ -30,7 +30,7 @@
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\ExpressionLanguage;
-use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface as ProxyDumper;
+use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\DumperInterface;
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\LazyServiceDumper;
use Symfony\Component\DependencyInjection\LazyProxy\PhpDumper\NullDumper;
use Symfony\Component\DependencyInjection\Loader\FileLoader;
@@ -90,7 +90,8 @@ class PhpDumper extends Dumper
private array $exportedVariables = [];
private string $baseClass;
private string $class;
- private ProxyDumper $proxyDumper;
+ private DumperInterface $proxyDumper;
+ private bool $hasProxyDumper = true;
public function __construct(ContainerBuilder $container)
{
@@ -104,9 +105,10 @@ public function __construct(ContainerBuilder $container)
/**
* Sets the dumper to be used when dumping proxies in the generated container.
*/
- public function setProxyDumper(ProxyDumper $proxyDumper)
+ public function setProxyDumper(DumperInterface $proxyDumper)
{
$this->proxyDumper = $proxyDumper;
+ $this->hasProxyDumper = !$proxyDumper instanceof NullDumper;
}
/**
@@ -165,7 +167,7 @@ public function dump(array $options = []): string|array
$this->initializeMethodNamesMap('Container' === $baseClass ? Container::class : $baseClass);
- if ($this->getProxyDumper() instanceof NullDumper) {
+ if (!$this->hasProxyDumper) {
(new AnalyzeServiceReferencesPass(true, false))->process($this->container);
(new CheckCircularReferencesPass())->process($this->container);
}
@@ -390,14 +392,14 @@ class %s extends {$options['class']}
/**
* Retrieves the currently set proxy dumper or instantiates one.
*/
- private function getProxyDumper(): ProxyDumper
+ private function getProxyDumper(): DumperInterface
{
return $this->proxyDumper ??= new LazyServiceDumper($this->class);
}
private function analyzeReferences()
{
- (new AnalyzeServiceReferencesPass(false, !$this->getProxyDumper() instanceof NullDumper))->process($this->container);
+ (new AnalyzeServiceReferencesPass(false, $this->hasProxyDumper))->process($this->container);
$checkedNodes = [];
$this->circularReferences = [];
$this->singleUsePrivateIds = [];
@@ -424,13 +426,13 @@ private function collectCircularReferences(string $sourceId, array $edges, array
foreach ($edges as $edge) {
$node = $edge->getDestNode();
$id = $node->getId();
- if ($sourceId === $id || !$node->getValue() instanceof Definition || $edge->isLazy() || $edge->isWeak()) {
+ if ($sourceId === $id || !$node->getValue() instanceof Definition || $edge->isWeak()) {
continue;
}
if (isset($path[$id])) {
$loop = null;
- $loopByConstructor = $edge->isReferencedByConstructor();
+ $loopByConstructor = $edge->isReferencedByConstructor() && !$edge->isLazy();
$pathInLoop = [$id, []];
foreach ($path as $k => $pathByConstructor) {
if (null !== $loop) {
@@ -444,7 +446,7 @@ private function collectCircularReferences(string $sourceId, array $edges, array
}
$this->addCircularReferences($id, $loop, $loopByConstructor);
} elseif (!isset($checkedNodes[$id])) {
- $this->collectCircularReferences($id, $node->getOutEdges(), $checkedNodes, $loops, $path, $edge->isReferencedByConstructor());
+ $this->collectCircularReferences($id, $node->getOutEdges(), $checkedNodes, $loops, $path, $edge->isReferencedByConstructor() && !$edge->isLazy());
} elseif (isset($loops[$id])) {
// we already had detected loops for this edge
// let's check if we have a common ancestor in one of the detected loops
@@ -465,7 +467,7 @@ private function collectCircularReferences(string $sourceId, array $edges, array
// we can now build the loop
$loop = null;
- $loopByConstructor = $edge->isReferencedByConstructor();
+ $loopByConstructor = $edge->isReferencedByConstructor() && !$edge->isLazy();
foreach ($fillPath as $k => $pathByConstructor) {
if (null !== $loop) {
$loop[] = $k;
@@ -968,7 +970,7 @@ private function addInlineReference(string $id, Definition $definition, string $
return '';
}
- $hasSelfRef = isset($this->circularReferences[$id][$targetId]) && !isset($this->definitionVariables[$definition]);
+ $hasSelfRef = isset($this->circularReferences[$id][$targetId]) && !isset($this->definitionVariables[$definition]) && !($this->hasProxyDumper && $definition->isLazy());
if ($hasSelfRef && !$forConstructor && !$forConstructor = !$this->circularReferences[$id][$targetId]) {
$code = $this->addInlineService($id, $definition, $definition);
@@ -1011,7 +1013,7 @@ private function addInlineService(string $id, Definition $definition, Definition
if ($isSimpleInstance = $isRootInstance = null === $inlineDef) {
foreach ($this->serviceCalls as $targetId => [$callCount, $behavior, $byConstructor]) {
- if ($byConstructor && isset($this->circularReferences[$id][$targetId]) && !$this->circularReferences[$id][$targetId]) {
+ if ($byConstructor && isset($this->circularReferences[$id][$targetId]) && !$this->circularReferences[$id][$targetId] && !($this->hasProxyDumper && $definition->isLazy())) {
$code .= $this->addInlineReference($id, $definition, $targetId, $forConstructor);
}
}
@@ -1291,7 +1293,7 @@ protected function load($file, $lazyLoad = true)
}
foreach ($this->container->getDefinitions() as $definition) {
- if (!$definition->isLazy() || $this->getProxyDumper() instanceof NullDumper) {
+ if (!$definition->isLazy() || !$this->hasProxyDumper) {
continue;
}
@@ -1469,7 +1471,7 @@ private function addInlineRequires(bool $hasProxyClasses): string
foreach ($hotPathServices as $id => $tags) {
$definition = $this->container->getDefinition($id);
- if ($definition->isLazy() && !$this->getProxyDumper() instanceof NullDumper) {
+ if ($definition->isLazy() && $this->hasProxyDumper) {
continue;
}
@@ -2259,15 +2261,10 @@ private function isProxyCandidate(Definition $definition, ?bool &$asGhostObject,
{
$asGhostObject = false;
- if (!$definition->isLazy() || ($proxyDumper = $this->getProxyDumper()) instanceof NullDumper) {
+ if (!$definition->isLazy() || !$this->hasProxyDumper) {
return null;
}
- $bag = $this->container->getParameterBag();
- $definition = (clone $definition)
- ->setClass($bag->resolveValue($definition->getClass()))
- ->setTags(($definition->hasTag('proxy') ? ['proxy' => $bag->resolveValue($definition->getTag('proxy'))] : []) + $definition->getTags());
-
- return $proxyDumper->isProxyCandidate($definition, $asGhostObject, $id) ? $definition : null;
+ return $this->getProxyDumper()->isProxyCandidate($definition, $asGhostObject, $id) ? $definition : null;
}
}
diff --git a/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/DumperInterface.php b/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/DumperInterface.php
index d3b9d77a236d0..520977763f3ad 100644
--- a/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/DumperInterface.php
+++ b/src/Symfony/Component/DependencyInjection/LazyProxy/PhpDumper/DumperInterface.php
@@ -35,6 +35,8 @@ public function getProxyFactoryCode(Definition $definition, string $id, string $
/**
* Generates the code for the lazy proxy.
+ *
+ * @param string|null $id
*/
public function getProxyCode(Definition $definition/* , string $id = null */): string;
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Config/ContainerParametersResourceCheckerTest.php b/src/Symfony/Component/DependencyInjection/Tests/Config/ContainerParametersResourceCheckerTest.php
index 08ff5c797e185..3563a313814db 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Config/ContainerParametersResourceCheckerTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Config/ContainerParametersResourceCheckerTest.php
@@ -51,7 +51,7 @@ public function testIsFresh(callable $mockContainer, $expected)
$this->assertSame($expected, $this->resourceChecker->isFresh($this->resource, time()));
}
- public function isFreshProvider()
+ public static function isFreshProvider()
{
yield 'not fresh on missing parameter' => [function (MockObject $container) {
$container->method('hasParameter')->with('locales')->willReturn(false);
@@ -62,11 +62,11 @@ public function isFreshProvider()
}, false];
yield 'fresh on every identical parameters' => [function (MockObject $container) {
- $container->expects($this->exactly(2))->method('hasParameter')->willReturn(true);
- $container->expects($this->exactly(2))->method('getParameter')
+ $container->expects(self::exactly(2))->method('hasParameter')->willReturn(true);
+ $container->expects(self::exactly(2))->method('getParameter')
->withConsecutive(
- [$this->equalTo('locales')],
- [$this->equalTo('default_locale')]
+ [self::equalTo('locales')],
+ [self::equalTo('default_locale')]
)
->willReturnMap([
['locales', ['fr', 'en']],
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
index 870d448fc0c76..d752c27abecc6 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
@@ -281,9 +281,8 @@ public function testDumpAsFilesWithLazyFactoriesInlined()
$container = new ContainerBuilder();
$container->setParameter('container.dumper.inline_factories', true);
$container->setParameter('container.dumper.inline_class_loader', true);
- $container->setParameter('lazy_foo_class', \Bar\FooClass::class);
- $container->register('lazy_foo', '%lazy_foo_class%')
+ $container->register('lazy_foo', \Bar\FooClass::class)
->addArgument(new Definition(\Bar\FooLazyClass::class))
->setPublic(true)
->setLazy(true);
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_lazy_inlined_factories.txt b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_lazy_inlined_factories.txt
index b606736e93f02..cbe0412198ba7 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_lazy_inlined_factories.txt
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_lazy_inlined_factories.txt
@@ -73,7 +73,7 @@ class ProjectServiceContainer extends Container
/**
* Gets the public 'lazy_foo' shared service.
*
- * @return object A %lazy_foo_class% instance
+ * @return \Bar\FooClass
*/
protected function getLazyFooService($lazyLoad = true)
{
@@ -145,7 +145,6 @@ class ProjectServiceContainer extends Container
return [
'container.dumper.inline_factories' => true,
'container.dumper.inline_class_loader' => true,
- 'lazy_foo_class' => 'Bar\\FooClass',
];
}
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php
index 9762e7411df37..ec41d87a99987 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_private.php
@@ -489,7 +489,13 @@ protected function getBar6Service()
*/
protected function getDoctrine_ListenerService()
{
- return $this->privates['doctrine.listener'] = new \stdClass(($this->services['doctrine.entity_manager'] ?? $this->getDoctrine_EntityManagerService()));
+ $a = ($this->services['doctrine.entity_manager'] ?? $this->getDoctrine_EntityManagerService());
+
+ if (isset($this->privates['doctrine.listener'])) {
+ return $this->privates['doctrine.listener'];
+ }
+
+ return $this->privates['doctrine.listener'] = new \stdClass($a);
}
/**
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php
index bff47395118b4..9dac86afcd55b 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_almost_circular_public.php
@@ -283,11 +283,16 @@ protected function getDoctrine_EntityListenerResolverService()
*/
protected function getDoctrine_EntityManagerService()
{
- $a = new \stdClass();
- $a->resolver = ($this->services['doctrine.entity_listener_resolver'] ?? $this->getDoctrine_EntityListenerResolverService());
- $a->flag = 'ok';
+ $a = ($this->services['doctrine.entity_listener_resolver'] ?? $this->getDoctrine_EntityListenerResolverService());
+
+ if (isset($this->services['doctrine.entity_manager'])) {
+ return $this->services['doctrine.entity_manager'];
+ }
+ $b = new \stdClass();
+ $b->resolver = $a;
+ $b->flag = 'ok';
- return $this->services['doctrine.entity_manager'] = \FactoryChecker::create($a);
+ return $this->services['doctrine.entity_manager'] = \FactoryChecker::create($b);
}
/**
@@ -297,7 +302,13 @@ protected function getDoctrine_EntityManagerService()
*/
protected function getDoctrine_ListenerService()
{
- return $this->services['doctrine.listener'] = new \stdClass(($this->services['doctrine.entity_manager'] ?? $this->getDoctrine_EntityManagerService()));
+ $a = ($this->services['doctrine.entity_manager'] ?? $this->getDoctrine_EntityManagerService());
+
+ if (isset($this->services['doctrine.listener'])) {
+ return $this->services['doctrine.listener'];
+ }
+
+ return $this->services['doctrine.listener'] = new \stdClass($a);
}
/**
@@ -493,7 +504,13 @@ protected function getLoggerService()
*/
protected function getMailer_TransportService()
{
- return $this->services['mailer.transport'] = ($this->services['mailer.transport_factory'] ?? $this->getMailer_TransportFactoryService())->create();
+ $a = ($this->services['mailer.transport_factory'] ?? $this->getMailer_TransportFactoryService());
+
+ if (isset($this->services['mailer.transport'])) {
+ return $this->services['mailer.transport'];
+ }
+
+ return $this->services['mailer.transport'] = $a->create();
}
/**
@@ -516,7 +533,13 @@ protected function getMailer_TransportFactoryService()
*/
protected function getMailer_TransportFactory_AmazonService()
{
- return $this->services['mailer.transport_factory.amazon'] = new \stdClass(($this->services['monolog.logger_2'] ?? $this->getMonolog_Logger2Service()));
+ $a = ($this->services['monolog.logger_2'] ?? $this->getMonolog_Logger2Service());
+
+ if (isset($this->services['mailer.transport_factory.amazon'])) {
+ return $this->services['mailer.transport_factory.amazon'];
+ }
+
+ return $this->services['mailer.transport_factory.amazon'] = new \stdClass($a);
}
/**
diff --git a/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTest.php
index 737d682207628..0fbd9196ff556 100644
--- a/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTest.php
+++ b/src/Symfony/Component/DomCrawler/Tests/AbstractCrawlerTest.php
@@ -19,7 +19,7 @@
abstract class AbstractCrawlerTest extends TestCase
{
- abstract public function getDoctype(): string;
+ abstract public static function getDoctype(): string;
protected function createCrawler($node = null, string $uri = null, string $baseHref = null)
{
diff --git a/src/Symfony/Component/DomCrawler/Tests/Html5ParserCrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/Html5ParserCrawlerTest.php
index 374c3ca9493df..7990f5bb48ff5 100644
--- a/src/Symfony/Component/DomCrawler/Tests/Html5ParserCrawlerTest.php
+++ b/src/Symfony/Component/DomCrawler/Tests/Html5ParserCrawlerTest.php
@@ -13,7 +13,7 @@
class Html5ParserCrawlerTest extends AbstractCrawlerTest
{
- public function getDoctype(): string
+ public static function getDoctype(): string
{
return '';
}
diff --git a/src/Symfony/Component/DomCrawler/Tests/NativeParserCrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/NativeParserCrawlerTest.php
index a17562f735580..c0cac9e8b603f 100644
--- a/src/Symfony/Component/DomCrawler/Tests/NativeParserCrawlerTest.php
+++ b/src/Symfony/Component/DomCrawler/Tests/NativeParserCrawlerTest.php
@@ -13,7 +13,7 @@
class NativeParserCrawlerTest extends AbstractCrawlerTest
{
- public function getDoctype(): string
+ public static function getDoctype(): string
{
return '';
}
diff --git a/src/Symfony/Component/ErrorHandler/phpunit.xml.dist b/src/Symfony/Component/ErrorHandler/phpunit.xml.dist
index b5b52f5a5208f..b23ccab51b8a7 100644
--- a/src/Symfony/Component/ErrorHandler/phpunit.xml.dist
+++ b/src/Symfony/Component/ErrorHandler/phpunit.xml.dist
@@ -10,7 +10,6 @@
>
-
diff --git a/src/Symfony/Component/Finder/Tests/GitignoreTest.php b/src/Symfony/Component/Finder/Tests/GitignoreTest.php
index 63f3b76cd5f75..65b52057937b9 100644
--- a/src/Symfony/Component/Finder/Tests/GitignoreTest.php
+++ b/src/Symfony/Component/Finder/Tests/GitignoreTest.php
@@ -55,7 +55,7 @@ public function testToRegex(array $gitignoreLines, array $matchingCases, array $
}
}
- public function provider(): array
+ public static function provider(): array
{
$cases = [
[
@@ -394,7 +394,7 @@ public function provider(): array
public function providerExtended(): array
{
- $basicCases = $this->provider();
+ $basicCases = self::provider();
$cases = [];
foreach ($basicCases as $case) {
diff --git a/src/Symfony/Component/Finder/Tests/Iterator/SizeRangeFilterIteratorTest.php b/src/Symfony/Component/Finder/Tests/Iterator/SizeRangeFilterIteratorTest.php
index 129d565d55b8c..25a6b8a2d75a2 100644
--- a/src/Symfony/Component/Finder/Tests/Iterator/SizeRangeFilterIteratorTest.php
+++ b/src/Symfony/Component/Finder/Tests/Iterator/SizeRangeFilterIteratorTest.php
@@ -41,7 +41,7 @@ public function getAcceptData()
];
return [
- [[new NumberComparator('< 1K'), new NumberComparator('> 0.5K')], $this->toAbsolute($lessThan1KGreaterThan05K)],
+ [[new NumberComparator('< 1K'), new NumberComparator('> 0.5K')], self::toAbsolute($lessThan1KGreaterThan05K)],
];
}
}
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php b/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php
index 86b55ebe83d13..0bc3ebe94399b 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/BaseType.php
@@ -13,6 +13,7 @@
use Symfony\Component\Form\AbstractRendererEngine;
use Symfony\Component\Form\AbstractType;
+use Symfony\Component\Form\Exception\LogicException;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
@@ -62,8 +63,16 @@ public function buildView(FormView $view, FormInterface $form, array $options)
if (!$labelFormat) {
$labelFormat = $view->parent->vars['label_format'];
}
+
+ $rootFormAttrOption = $form->getRoot()->getConfig()->getOption('form_attr');
+ if ($options['form_attr'] || $rootFormAttrOption) {
+ $options['attr']['form'] = \is_string($rootFormAttrOption) ? $rootFormAttrOption : $form->getRoot()->getName();
+ if (empty($options['attr']['form'])) {
+ throw new LogicException('"form_attr" option must be a string identifier on root form when it has no id.');
+ }
+ }
} else {
- $id = $name;
+ $id = \is_string($options['form_attr']) ? $options['form_attr'] : $name;
$fullName = $name;
$uniqueBlockPrefix = '_'.$blockName;
@@ -126,6 +135,7 @@ public function configureOptions(OptionsResolver $resolver)
'translation_domain' => null,
'auto_initialize' => true,
'priority' => 0,
+ 'form_attr' => false,
]);
$resolver->setAllowedTypes('block_prefix', ['null', 'string']);
@@ -133,6 +143,7 @@ public function configureOptions(OptionsResolver $resolver)
$resolver->setAllowedTypes('row_attr', 'array');
$resolver->setAllowedTypes('label_html', 'bool');
$resolver->setAllowedTypes('priority', 'int');
+ $resolver->setAllowedTypes('form_attr', ['bool', 'string']);
$resolver->setInfo('priority', 'The form rendering priority (higher priorities will be rendered first)');
}
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
index 7b5cffe821441..a1f9b6dda8dcf 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php
@@ -84,16 +84,6 @@ public function buildView(FormView $view, FormInterface $form, array $options)
}
$helpTranslationParameters = array_merge($view->parent->vars['help_translation_parameters'], $helpTranslationParameters);
-
- $rootFormAttrOption = $form->getRoot()->getConfig()->getOption('form_attr');
- if ($options['form_attr'] || $rootFormAttrOption) {
- $view->vars['attr']['form'] = \is_string($rootFormAttrOption) ? $rootFormAttrOption : $form->getRoot()->getName();
- if (empty($view->vars['attr']['form'])) {
- throw new LogicException('"form_attr" option must be a string identifier on root form when it has no id.');
- }
- }
- } elseif (\is_string($options['form_attr'])) {
- $view->vars['id'] = $options['form_attr'];
}
$formConfig = $form->getConfig();
@@ -201,7 +191,6 @@ public function configureOptions(OptionsResolver $resolver)
'is_empty_callback' => null,
'getter' => null,
'setter' => null,
- 'form_attr' => false,
]);
$resolver->setAllowedTypes('label_attr', 'array');
@@ -213,7 +202,6 @@ public function configureOptions(OptionsResolver $resolver)
$resolver->setAllowedTypes('is_empty_callback', ['null', 'callable']);
$resolver->setAllowedTypes('getter', ['null', 'callable']);
$resolver->setAllowedTypes('setter', ['null', 'callable']);
- $resolver->setAllowedTypes('form_attr', ['bool', 'string']);
$resolver->setInfo('getter', 'A callable that accepts two arguments (the view data and the current form field) and must return a value.');
$resolver->setInfo('setter', 'A callable that accepts three arguments (a reference to the view data, the submitted value and the current form field).');
diff --git a/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php b/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php
index 61b8dc379148a..1d33451d45293 100644
--- a/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php
+++ b/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php
@@ -65,7 +65,7 @@ public function getNormalizedIniPostMaxSize(): string
$this->request = null;
}
- public function methodExceptGetProvider()
+ public static function methodExceptGetProvider()
{
return [
['POST'],
@@ -79,7 +79,7 @@ public function methodProvider()
{
return array_merge([
['GET'],
- ], $this->methodExceptGetProvider());
+ ], self::methodExceptGetProvider());
}
/**
diff --git a/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php b/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php
index d0037bbfbda37..a5e97eeb69165 100644
--- a/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php
+++ b/src/Symfony/Component/Form/Tests/Command/DebugCommandTest.php
@@ -206,7 +206,7 @@ public function provideCompletionSuggestions(): iterable
yield 'form_type' => [
[''],
- $this->getCoreTypes(),
+ self::getCoreTypes(),
];
yield 'option for FQCN' => [
@@ -225,6 +225,7 @@ public function provideCompletionSuggestions(): iterable
'translation_domain',
'auto_initialize',
'priority',
+ 'form_attr',
],
];
@@ -244,6 +245,7 @@ public function provideCompletionSuggestions(): iterable
'translation_domain',
'auto_initialize',
'priority',
+ 'form_attr',
],
];
@@ -258,7 +260,7 @@ public function provideCompletionSuggestions(): iterable
];
}
- private function getCoreTypes(): array
+ private static function getCoreTypes(): array
{
$coreExtension = new CoreExtension();
$loadTypesRefMethod = (new \ReflectionObject($coreExtension))->getMethod('loadTypes');
diff --git a/src/Symfony/Component/Form/Tests/DependencyInjection/FormPassTest.php b/src/Symfony/Component/Form/Tests/DependencyInjection/FormPassTest.php
index af94dd7e32487..6c73abe370d7e 100644
--- a/src/Symfony/Component/Form/Tests/DependencyInjection/FormPassTest.php
+++ b/src/Symfony/Component/Form/Tests/DependencyInjection/FormPassTest.php
@@ -285,15 +285,15 @@ public function privateTaggedServicesProvider()
function (ContainerBuilder $container) {
$formTypes = $container->getDefinition('form.extension')->getArgument(0);
- $this->assertInstanceOf(Reference::class, $formTypes);
+ self::assertInstanceOf(Reference::class, $formTypes);
$locator = $container->getDefinition((string) $formTypes);
$expectedLocatorMap = [
'stdClass' => new ServiceClosureArgument(new Reference('my.type')),
];
- $this->assertInstanceOf(Definition::class, $locator);
- $this->assertEquals($expectedLocatorMap, $locator->getArgument(0));
+ self::assertInstanceOf(Definition::class, $locator);
+ self::assertEquals($expectedLocatorMap, $locator->getArgument(0));
},
],
[
@@ -301,7 +301,7 @@ function (ContainerBuilder $container) {
Type1TypeExtension::class,
'form.type_extension',
function (ContainerBuilder $container) {
- $this->assertEquals(
+ self::assertEquals(
['Symfony\Component\Form\Extension\Core\Type\FormType' => new IteratorArgument([new Reference('my.type_extension')])],
$container->getDefinition('form.extension')->getArgument(1)
);
@@ -309,7 +309,7 @@ function (ContainerBuilder $container) {
['extended_type' => 'Symfony\Component\Form\Extension\Core\Type\FormType'],
],
['my.guesser', 'stdClass', 'form.type_guesser', function (ContainerBuilder $container) {
- $this->assertEquals(new IteratorArgument([new Reference('my.guesser')]), $container->getDefinition('form.extension')->getArgument(2));
+ self::assertEquals(new IteratorArgument([new Reference('my.guesser')]), $container->getDefinition('form.extension')->getArgument(2));
}],
];
}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php
index eccaa22a136f3..0412dc321a0f6 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToRfc3339TransformerTest.php
@@ -37,7 +37,7 @@ protected function tearDown(): void
$this->dateTimeWithoutSeconds = null;
}
- public function allProvider()
+ public static function allProvider()
{
return [
['UTC', 'UTC', '2010-02-03 04:05:06 UTC', '2010-02-03T04:05:06Z'],
@@ -51,12 +51,12 @@ public function allProvider()
public function transformProvider()
{
- return $this->allProvider();
+ return self::allProvider();
}
public function reverseTransformProvider()
{
- return array_merge($this->allProvider(), [
+ return array_merge(self::allProvider(), [
// format without seconds, as appears in some browsers
['UTC', 'UTC', '2010-02-03 04:05:00 UTC', '2010-02-03T04:05Z'],
['America/New_York', 'Asia/Hong_Kong', '2010-02-03 04:05:00 America/New_York', '2010-02-03T17:05+08:00'],
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ButtonTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ButtonTypeTest.php
index 654e04649e9f1..dcff028026482 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ButtonTypeTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ButtonTypeTest.php
@@ -13,6 +13,8 @@
use Symfony\Component\Form\Button;
use Symfony\Component\Form\Exception\BadMethodCallException;
+use Symfony\Component\Form\Exception\LogicException;
+use Symfony\Component\Form\Extension\Core\Type\FormType;
/**
* @author Bernhard Schussek
@@ -36,4 +38,65 @@ public function testSubmitNullUsesDefaultEmptyData($emptyData = 'empty', $expect
$this->expectExceptionMessage('Buttons do not support empty data.');
parent::testSubmitNullUsesDefaultEmptyData($emptyData, $expectedData);
}
+
+ public function testFormAttrOnRoot()
+ {
+ $view = $this->factory
+ ->createNamedBuilder('parent', FormType::class, null, [
+ 'form_attr' => true,
+ ])
+ ->add('child1', $this->getTestedType())
+ ->add('child2', $this->getTestedType())
+ ->getForm()
+ ->createView();
+ $this->assertArrayNotHasKey('form', $view->vars['attr']);
+ $this->assertSame($view->vars['id'], $view['child1']->vars['attr']['form']);
+ $this->assertSame($view->vars['id'], $view['child2']->vars['attr']['form']);
+ }
+
+ public function testFormAttrOnChild()
+ {
+ $view = $this->factory
+ ->createNamedBuilder('parent')
+ ->add('child1', $this->getTestedType(), [
+ 'form_attr' => true,
+ ])
+ ->add('child2', $this->getTestedType())
+ ->getForm()
+ ->createView();
+ $this->assertArrayNotHasKey('form', $view->vars['attr']);
+ $this->assertSame($view->vars['id'], $view['child1']->vars['attr']['form']);
+ $this->assertArrayNotHasKey('form', $view['child2']->vars['attr']);
+ }
+
+ public function testFormAttrAsBoolWithNoId()
+ {
+ $this->expectException(LogicException::class);
+ $this->expectErrorMessage('form_attr');
+ $this->factory
+ ->createNamedBuilder('', FormType::class, null, [
+ 'form_attr' => true,
+ ])
+ ->add('child1', $this->getTestedType())
+ ->add('child2', $this->getTestedType())
+ ->getForm()
+ ->createView();
+ }
+
+ public function testFormAttrAsStringWithNoId()
+ {
+ $stringId = 'custom-identifier';
+ $view = $this->factory
+ ->createNamedBuilder('', FormType::class, null, [
+ 'form_attr' => $stringId,
+ ])
+ ->add('child1', $this->getTestedType())
+ ->add('child2', $this->getTestedType())
+ ->getForm()
+ ->createView();
+ $this->assertArrayNotHasKey('form', $view->vars['attr']);
+ $this->assertSame($stringId, $view->vars['id']);
+ $this->assertSame($view->vars['id'], $view['child1']->vars['attr']['form']);
+ $this->assertSame($view->vars['id'], $view['child2']->vars['attr']['form']);
+ }
}
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index 358dab3aed06a..0e62c045bd532 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -75,11 +75,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
*/
private static array $freshCache = [];
- public const VERSION = '6.2.2';
- public const VERSION_ID = 60202;
+ public const VERSION = '6.2.3';
+ public const VERSION_ID = 60203;
public const MAJOR_VERSION = 6;
public const MINOR_VERSION = 2;
- public const RELEASE_VERSION = 2;
+ public const RELEASE_VERSION = 3;
public const EXTRA_VERSION = '';
public const END_OF_MAINTENANCE = '07/2023';
diff --git a/src/Symfony/Component/HttpKernel/Tests/Debug/FileLinkFormatterTest.php b/src/Symfony/Component/HttpKernel/Tests/Debug/FileLinkFormatterTest.php
index d24958c6c5de5..57605c1ae4ec2 100644
--- a/src/Symfony/Component/HttpKernel/Tests/Debug/FileLinkFormatterTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/Debug/FileLinkFormatterTest.php
@@ -27,9 +27,17 @@ public function testWhenNoFileLinkFormatAndNoRequest()
public function testAfterUnserialize()
{
+ $ide = $_ENV['SYMFONY_IDE'] ?? $_SERVER['SYMFONY_IDE'] ?? null;
+ $_ENV['SYMFONY_IDE'] = $_SERVER['SYMFONY_IDE'] = null;
$sut = unserialize(serialize(new FileLinkFormatter()));
$this->assertFalse($sut->format('/kernel/root/src/my/very/best/file.php', 3));
+
+ if (null === $ide) {
+ unset($_ENV['SYMFONY_IDE'], $_SERVER['SYMFONY_IDE']);
+ } else {
+ $_ENV['SYMFONY_IDE'] = $_SERVER['SYMFONY_IDE'] = $ide;
+ }
}
public function testWhenFileLinkFormatAndNoRequest()
diff --git a/src/Symfony/Component/HttpKernel/phpunit.xml.dist b/src/Symfony/Component/HttpKernel/phpunit.xml.dist
index a72dcbcca2979..7e2c738f869f1 100644
--- a/src/Symfony/Component/HttpKernel/phpunit.xml.dist
+++ b/src/Symfony/Component/HttpKernel/phpunit.xml.dist
@@ -10,7 +10,6 @@
>
-
diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php
index c69ec5d110a63..990d77b7a5ed0 100644
--- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php
+++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php
@@ -345,6 +345,10 @@ private function readPropertiesUntil(array $zval, PropertyPathInterface $propert
}
$propertyValues[] = $zval;
+
+ if ($isNullSafe && null === $zval[self::VALUE]) {
+ break;
+ }
}
return $propertyValues;
diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php
index 5fa7a25d6b62a..bf6a7684bde14 100644
--- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php
+++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php
@@ -569,6 +569,11 @@ public function getValidReadPropertyPaths(): iterable
yield [(object) [], 'foo?', null];
yield [(object) ['foo' => (object) ['firstName' => 'Bernhard']], 'foo.bar?', null];
yield [(object) ['foo' => (object) ['firstName' => 'Bernhard']], 'foo.bar?.baz?', null];
+ yield [(object) ['foo' => null], 'foo?.bar', null];
+ yield [(object) ['foo' => null], 'foo?.bar.baz', null];
+ yield [(object) ['foo' => (object) ['bar' => null]], 'foo?.bar?.baz', null];
+ yield [(object) ['foo' => (object) ['bar' => null]], 'foo.bar?.baz', null];
+ yield [(object) ['foo' => ['bar' => null]], 'foo[bar?].baz', null];
yield [[], '[foo?]', null];
yield [['foo' => ['firstName' => 'Bernhard']], '[foo][bar?]', null];
yield [['foo' => ['firstName' => 'Bernhard']], '[foo][bar?][baz?]', null];
diff --git a/src/Symfony/Component/PropertyInfo/composer.json b/src/Symfony/Component/PropertyInfo/composer.json
index 07b3ecfb7c34b..1eff92d7fb4eb 100644
--- a/src/Symfony/Component/PropertyInfo/composer.json
+++ b/src/Symfony/Component/PropertyInfo/composer.json
@@ -32,7 +32,7 @@
"symfony/dependency-injection": "^5.4|^6.0",
"phpdocumentor/reflection-docblock": "^5.2",
"phpstan/phpdoc-parser": "^1.0",
- "doctrine/annotations": "^1.10.4"
+ "doctrine/annotations": "^1.10.4|^2"
},
"conflict": {
"phpdocumentor/reflection-docblock": "<5.2",
diff --git a/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderWithAnnotationsTest.php b/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderWithAnnotationsTest.php
index b7399df353ef0..e2843a0a39843 100644
--- a/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderWithAnnotationsTest.php
+++ b/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderWithAnnotationsTest.php
@@ -26,7 +26,9 @@ protected function configureRoute(Route $route, \ReflectionClass $class, \Reflec
{
}
};
- AnnotationRegistry::registerLoader('class_exists');
+ if (method_exists(AnnotationRegistry::class, 'registerLoader')) {
+ AnnotationRegistry::registerLoader('class_exists');
+ }
}
public function testDefaultRouteName()
diff --git a/src/Symfony/Component/Routing/composer.json b/src/Symfony/Component/Routing/composer.json
index be4bce3ebdf4c..787a8c30cb127 100644
--- a/src/Symfony/Component/Routing/composer.json
+++ b/src/Symfony/Component/Routing/composer.json
@@ -24,7 +24,7 @@
"symfony/yaml": "^5.4|^6.0",
"symfony/expression-language": "^5.4|^6.0",
"symfony/dependency-injection": "^5.4|^6.0",
- "doctrine/annotations": "^1.12",
+ "doctrine/annotations": "^1.12|^2",
"psr/log": "^1|^2|^3"
},
"conflict": {
diff --git a/src/Symfony/Component/Serializer/composer.json b/src/Symfony/Component/Serializer/composer.json
index 2c5995f2e0898..dfb0a928dadb8 100644
--- a/src/Symfony/Component/Serializer/composer.json
+++ b/src/Symfony/Component/Serializer/composer.json
@@ -20,7 +20,7 @@
"symfony/polyfill-ctype": "~1.8"
},
"require-dev": {
- "doctrine/annotations": "^1.12",
+ "doctrine/annotations": "^1.12|^2",
"phpdocumentor/reflection-docblock": "^3.2|^4.0|^5.0",
"symfony/cache": "^5.4|^6.0",
"symfony/config": "^5.4|^6.0",
diff --git a/src/Symfony/Component/Translation/Extractor/Visitor/ConstraintVisitor.php b/src/Symfony/Component/Translation/Extractor/Visitor/ConstraintVisitor.php
index 6552a66d5a32d..3c6458440b9f8 100644
--- a/src/Symfony/Component/Translation/Extractor/Visitor/ConstraintVisitor.php
+++ b/src/Symfony/Component/Translation/Extractor/Visitor/ConstraintVisitor.php
@@ -72,6 +72,7 @@ public function enterNode(Node $node): ?Node
return null;
}
+ $messages = [];
$options = $arg->value;
/** @var Node\Expr\ArrayItem $item */
diff --git a/src/Symfony/Component/Validator/Constraints/IbanValidator.php b/src/Symfony/Component/Validator/Constraints/IbanValidator.php
index d80bf36794de6..43b62b5d392f8 100644
--- a/src/Symfony/Component/Validator/Constraints/IbanValidator.php
+++ b/src/Symfony/Component/Validator/Constraints/IbanValidator.php
@@ -102,7 +102,7 @@ class IbanValidator extends ConstraintValidator
'MK' => 'MK\d{2}\d{3}[\dA-Z]{10}\d{2}', // Macedonia, Former Yugoslav Republic of
'ML' => 'ML\d{2}[A-Z]{1}\d{23}', // Mali
'MQ' => 'FR\d{2}\d{5}\d{5}[\dA-Z]{11}\d{2}', // Martinique
- 'MR' => 'MR13\d{5}\d{5}\d{11}\d{2}', // Mauritania
+ 'MR' => 'MR\d{2}\d{5}\d{5}\d{11}\d{2}', // Mauritania
'MT' => 'MT\d{2}[A-Z]{4}\d{5}[\dA-Z]{18}', // Malta
'MU' => 'MU\d{2}[A-Z]{4}\d{2}\d{2}\d{12}\d{3}[A-Z]{3}', // Mauritius
'MZ' => 'MZ\d{2}\d{21}', // Mozambique
@@ -127,7 +127,7 @@ class IbanValidator extends ConstraintValidator
'SN' => 'SN\d{2}[A-Z]{1}\d{23}', // Senegal
'TF' => 'FR\d{2}\d{5}\d{5}[\dA-Z]{11}\d{2}', // French Southern Territories
'TL' => 'TL\d{2}\d{3}\d{14}\d{2}', // Timor-Leste
- 'TN' => 'TN59\d{2}\d{3}\d{13}\d{2}', // Tunisia
+ 'TN' => 'TN\d{2}\d{2}\d{3}\d{13}\d{2}', // Tunisia
'TR' => 'TR\d{2}\d{5}[\dA-Z]{1}[\dA-Z]{16}', // Turkey
'UA' => 'UA\d{2}\d{6}[\dA-Z]{19}', // Ukraine
'VA' => 'VA\d{2}\d{3}\d{15}', // Vatican City State
diff --git a/src/Symfony/Component/Validator/composer.json b/src/Symfony/Component/Validator/composer.json
index 63cb9e3a9745e..2691295eada91 100644
--- a/src/Symfony/Component/Validator/composer.json
+++ b/src/Symfony/Component/Validator/composer.json
@@ -38,7 +38,7 @@
"symfony/property-access": "^5.4|^6.0",
"symfony/property-info": "^5.4|^6.0",
"symfony/translation": "^5.4|^6.0",
- "doctrine/annotations": "^1.13",
+ "doctrine/annotations": "^1.13|^2",
"egulias/email-validator": "^2.1.10|^3"
},
"conflict": {
diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/CasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/CasterTest.php
index f4be025c351fe..66cd5fbeda660 100644
--- a/src/Symfony/Component/VarDumper/Tests/Caster/CasterTest.php
+++ b/src/Symfony/Component/VarDumper/Tests/Caster/CasterTest.php
@@ -22,7 +22,7 @@ class CasterTest extends TestCase
{
use VarDumperTestTrait;
- private $referenceArray = [
+ private static $referenceArray = [
'null' => null,
'empty' => false,
'public' => 'pub',
@@ -38,12 +38,12 @@ class CasterTest extends TestCase
public function testFilter($filter, $expectedDiff, $listedProperties = null)
{
if (null === $listedProperties) {
- $filteredArray = Caster::filter($this->referenceArray, $filter);
+ $filteredArray = Caster::filter(self::$referenceArray, $filter);
} else {
- $filteredArray = Caster::filter($this->referenceArray, $filter, $listedProperties);
+ $filteredArray = Caster::filter(self::$referenceArray, $filter, $listedProperties);
}
- $this->assertSame($expectedDiff, array_diff_assoc($this->referenceArray, $filteredArray));
+ $this->assertSame($expectedDiff, array_diff_assoc(self::$referenceArray, $filteredArray));
}
public function provideFilter()
@@ -126,7 +126,7 @@ public function provideFilter()
],
[
Caster::EXCLUDE_NOT_IMPORTANT | Caster::EXCLUDE_VERBOSE,
- $this->referenceArray,
+ self::$referenceArray,
['public', "\0*\0protected"],
],
[
diff --git a/src/Symfony/Component/VarExporter/Internal/Exporter.php b/src/Symfony/Component/VarExporter/Internal/Exporter.php
index 57c229eb14d2b..24f587b7fcb90 100644
--- a/src/Symfony/Component/VarExporter/Internal/Exporter.php
+++ b/src/Symfony/Component/VarExporter/Internal/Exporter.php
@@ -151,6 +151,7 @@ public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount
}
if (null !== $sleep) {
if (!isset($sleep[$n]) || ($i && $c !== $class)) {
+ unset($arrayValue[$name]);
continue;
}
$sleep[$n] = false;
@@ -166,6 +167,9 @@ public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount
}
}
}
+ if (method_exists($class, '__unserialize')) {
+ $properties = $arrayValue;
+ }
prepare_value:
$objectsPool[$value] = [$id = \count($objectsPool)];
diff --git a/src/Symfony/Component/VarExporter/ProxyHelper.php b/src/Symfony/Component/VarExporter/ProxyHelper.php
index ba24c4afb08a0..c323f0b2cd9b0 100644
--- a/src/Symfony/Component/VarExporter/ProxyHelper.php
+++ b/src/Symfony/Component/VarExporter/ProxyHelper.php
@@ -129,7 +129,7 @@ public static function generateLazyProxy(?\ReflectionClass $class, array $interf
}
foreach ($methodReflectors as $method) {
- if ($method->isStatic() || isset($methods[$lcName = strtolower($method->name)])) {
+ if (($method->isStatic() && !$method->isAbstract()) || isset($methods[$lcName = strtolower($method->name)])) {
continue;
}
if ($method->isFinal()) {
@@ -145,7 +145,9 @@ public static function generateLazyProxy(?\ReflectionClass $class, array $interf
$signature = self::exportSignature($method);
$parentCall = $method->isAbstract() ? "throw new \BadMethodCallException('Cannot forward abstract method \"{$method->class}::{$method->name}()\".')" : "parent::{$method->name}(...\\func_get_args())";
- if (str_ends_with($signature, '): never') || str_ends_with($signature, '): void')) {
+ if ($method->isStatic()) {
+ $body = " $parentCall;";
+ } elseif (str_ends_with($signature, '): never') || str_ends_with($signature, '): void')) {
$body = <<lazyObjectReal)) {
\$this->lazyObjectReal->{$method->name}(...\\func_get_args());
diff --git a/src/Symfony/Component/VarExporter/Tests/Fixtures/__unserialize-but-no-__serialize.php b/src/Symfony/Component/VarExporter/Tests/Fixtures/__unserialize-but-no-__serialize.php
new file mode 100644
index 0000000000000..987999b8d2cfa
--- /dev/null
+++ b/src/Symfony/Component/VarExporter/Tests/Fixtures/__unserialize-but-no-__serialize.php
@@ -0,0 +1,15 @@
+ 'ccc',
+ ],
+ ]
+);
diff --git a/src/Symfony/Component/VarExporter/Tests/ProxyHelperTest.php b/src/Symfony/Component/VarExporter/Tests/ProxyHelperTest.php
index 260980d94f870..7745a77146fb3 100644
--- a/src/Symfony/Component/VarExporter/Tests/ProxyHelperTest.php
+++ b/src/Symfony/Component/VarExporter/Tests/ProxyHelperTest.php
@@ -147,6 +147,11 @@ public function foo2(?\Symfony\Component\VarExporter\Tests\Bar $b): \Symfony\Com
return throw new \BadMethodCallException('Cannot forward abstract method "Symfony\Component\VarExporter\Tests\TestForProxyHelperInterface2::foo2()".');
}
+
+ public static function foo3(): string
+ {
+ throw new \BadMethodCallException('Cannot forward abstract method "Symfony\Component\VarExporter\Tests\TestForProxyHelperInterface2::foo3()".');
+ }
}
// Help opcache.preload discover always-needed symbols
@@ -236,6 +241,8 @@ public function foo1(): ?Bar;
interface TestForProxyHelperInterface2
{
public function foo2(?Bar $b): self;
+
+ public static function foo3(): string;
}
class TestSignatureFQ extends \stdClass
diff --git a/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php b/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php
index 4baef45db35cf..6dd133c3b909d 100644
--- a/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php
+++ b/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php
@@ -233,6 +233,8 @@ public function provideExport()
yield ['php74-serializable', new Php74Serializable()];
+ yield ['__unserialize-but-no-__serialize', new __UnserializeButNo__Serialize()];
+
yield ['unit-enum', [FooUnitEnum::Bar], true];
yield ['readonly', new FooReadonly('k', 'v')];
}
@@ -437,3 +439,18 @@ public function unserialize($ser)
class ArrayObject extends \ArrayObject
{
}
+
+class __UnserializeButNo__Serialize
+{
+ public $foo;
+
+ public function __construct()
+ {
+ $this->foo = 'ccc';
+ }
+
+ public function __unserialize(array $data): void
+ {
+ $this->foo = $data['foo'];
+ }
+}
diff --git a/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php b/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php
index 5c04414273815..47d5d6ff276f6 100644
--- a/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php
+++ b/src/Symfony/Component/Workflow/Dumper/PlantUmlDumper.php
@@ -11,7 +11,6 @@
namespace Symfony\Component\Workflow\Dumper;
-use InvalidArgumentException;
use Symfony\Component\Workflow\Definition;
use Symfony\Component\Workflow\Marking;
use Symfony\Component\Workflow\Metadata\MetadataStoreInterface;
@@ -57,7 +56,7 @@ class PlantUmlDumper implements DumperInterface
public function __construct(string $transitionType)
{
if (!\in_array($transitionType, self::TRANSITION_TYPES, true)) {
- throw new InvalidArgumentException("Transition type '$transitionType' does not exist.");
+ throw new \InvalidArgumentException("Transition type '$transitionType' does not exist.");
}
$this->transitionType = $transitionType;
}
@@ -209,9 +208,7 @@ private function getState(string $place, Definition $definition, Marking $markin
$description = $workflowMetadata->getMetadata('description', $place);
if (null !== $description) {
- $output .= ' as '.$place.
- \PHP_EOL.
- $place.' : '.$description;
+ $output .= \PHP_EOL.$placeEscaped.' : '.$description;
}
return $output;
diff --git a/src/Symfony/Component/Workflow/Tests/Dumper/PlantUmlDumperTest.php b/src/Symfony/Component/Workflow/Tests/Dumper/PlantUmlDumperTest.php
index 85c67969b8488..0c750fc750255 100644
--- a/src/Symfony/Component/Workflow/Tests/Dumper/PlantUmlDumperTest.php
+++ b/src/Symfony/Component/Workflow/Tests/Dumper/PlantUmlDumperTest.php
@@ -12,9 +12,12 @@
namespace Symfony\Component\Workflow\Tests\Dumper;
use PHPUnit\Framework\TestCase;
+use Symfony\Component\Workflow\Definition;
use Symfony\Component\Workflow\Dumper\PlantUmlDumper;
use Symfony\Component\Workflow\Marking;
+use Symfony\Component\Workflow\Metadata\InMemoryMetadataStore;
use Symfony\Component\Workflow\Tests\WorkflowBuilderTrait;
+use Symfony\Component\Workflow\Transition;
class PlantUmlDumperTest extends TestCase
{
@@ -63,6 +66,34 @@ public function provideStateMachineDefinitionWithoutMarking()
yield [$this->createComplexStateMachineDefinition(), $marking, 'complex-state-machine-marking', 'SimpleDiagram'];
}
+ public function testDumpWorkflowWithSpacesInTheStateNamesAndDescription()
+ {
+ $dumper = new PlantUmlDumper(PlantUmlDumper::WORKFLOW_TRANSITION);
+
+ // The graph looks like:
+ //
+ // +---------+ t 1 +----------+ |
+ // | place a | -----> | place b | |
+ // +---------+ +----------+ |
+ $places = ['place a', 'place b'];
+
+ $transitions = [];
+ $transition = new Transition('t 1', 'place a', 'place b');
+ $transitions[] = $transition;
+
+ $placesMetadata = [];
+ $placesMetadata['place a'] = [
+ 'description' => 'My custom place description',
+ ];
+ $inMemoryMetadataStore = new InMemoryMetadataStore([], $placesMetadata);
+ $definition = new Definition($places, $transitions, null, $inMemoryMetadataStore);
+
+ $dump = $dumper->dump($definition, null, ['title' => 'SimpleDiagram']);
+ $dump = str_replace(\PHP_EOL, "\n", $dump.\PHP_EOL);
+ $file = $this->getFixturePath('simple-workflow-with-spaces', PlantUmlDumper::WORKFLOW_TRANSITION);
+ $this->assertStringEqualsFile($file, $dump);
+ }
+
private function getFixturePath($name, $transitionType)
{
return __DIR__.'/../fixtures/puml/'.$transitionType.'/'.$name.'.puml';
diff --git a/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-marking.puml b/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-marking.puml
index 0ea138f83f725..1e8a2ea0f6b86 100644
--- a/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-marking.puml
+++ b/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-marking.puml
@@ -17,8 +17,8 @@ skinparam agent {
}
state "a" <>
state "b" <>
-state "c" <> as c
-c : My custom place description
+state "c" <>
+"c" : My custom place description
agent "t1"
agent "t2"
"a" -[#Purple]-> "t1": "My custom transition label 2"
diff --git a/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-nomarking.puml b/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-nomarking.puml
index 02e7f396eacb3..b57dc5b1fab43 100644
--- a/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-nomarking.puml
+++ b/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-nomarking.puml
@@ -17,8 +17,8 @@ skinparam agent {
}
state "a" <>
state "b"
-state "c" <> as c
-c : My custom place description
+state "c" <>
+"c" : My custom place description
agent "t1"
agent "t2"
"a" -[#Purple]-> "t1": "My custom transition label 2"
diff --git a/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-with-spaces.puml b/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-with-spaces.puml
new file mode 100644
index 0000000000000..0e20d27198024
--- /dev/null
+++ b/src/Symfony/Component/Workflow/Tests/fixtures/puml/square/simple-workflow-with-spaces.puml
@@ -0,0 +1,23 @@
+@startuml
+allow_mixing
+title SimpleDiagram
+skinparam titleBorderRoundCorner 15
+skinparam titleBorderThickness 2
+skinparam state {
+ BackgroundColor<> #87b741
+ BackgroundColor<> #3887C6
+ BorderColor #3887C6
+ BorderColor<> Black
+ FontColor<> White
+}
+skinparam agent {
+ BackgroundColor #ffffff
+ BorderColor #3887C6
+}
+state "place a" <>
+"place a" : My custom place description
+state "place b"
+agent "t 1"
+"place a" --> "t 1"
+"t 1" --> "place b"
+@enduml