diff --git a/phpunit b/phpunit
index 03bf63b0aa..9141d249d2 100755
--- a/phpunit
+++ b/phpunit
@@ -13,7 +13,7 @@ if (!getenv('SYMFONY_PHPUNIT_VERSION')) {
} elseif (\PHP_VERSION_ID < 70300) {
putenv('SYMFONY_PHPUNIT_VERSION=8.5');
} else {
- putenv('SYMFONY_PHPUNIT_VERSION=9.4');
+ putenv('SYMFONY_PHPUNIT_VERSION=9.5');
}
}
if (!getenv('SYMFONY_PATCH_TYPE_DECLARATIONS')) {
diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/CoverageListenerTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/CoverageListenerTrait.php
index c1b276cea2..4ca396ece1 100644
--- a/src/Symfony/Bridge/PhpUnit/Legacy/CoverageListenerTrait.php
+++ b/src/Symfony/Bridge/PhpUnit/Legacy/CoverageListenerTrait.php
@@ -42,7 +42,7 @@ class CoverageListenerTrait
return;
}
- $annotations = $test->getAnnotations();
+ $annotations = Test::parseTestMethodAnnotations(\get_class($test), $test->getName(false));
$ignoredAnnotations = ['covers', 'coversDefaultClass', 'coversNothing'];
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/argon2i_encoder.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/argon2i_encoder.php
index 7276f97e6b..ddac043692 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/argon2i_encoder.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/argon2i_encoder.php
@@ -1,6 +1,6 @@
load('container1.php', $container);
+$this->load('container1.php');
$container->loadFromExtension('security', [
'encoders' => [
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/bcrypt_encoder.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/bcrypt_encoder.php
index 1afad79e4f..d4511aeb55 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/bcrypt_encoder.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/bcrypt_encoder.php
@@ -1,6 +1,6 @@
load('container1.php', $container);
+$this->load('container1.php');
$container->loadFromExtension('security', [
'encoders' => [
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/migrating_encoder.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/migrating_encoder.php
index 14c008be9d..c7ad9f02ab 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/migrating_encoder.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/php/migrating_encoder.php
@@ -1,6 +1,6 @@
load('container1.php', $container);
+$this->load('container1.php');
$container->loadFromExtension('security', [
'encoders' => [
diff --git a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php
index 43eaeee4c8..65e9d4e71a 100644
--- a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php
+++ b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php
@@ -110,7 +110,9 @@ class FormValidator extends ConstraintValidator
foreach ($constraints as $constraint) {
// For the "Valid" constraint, validate the data in all groups
if ($constraint instanceof Valid) {
- $validator->atPath('data')->validate($data, $constraint, $groups);
+ if (\is_object($data)) {
+ $validator->atPath('data')->validate($data, $constraint, $groups);
+ }
continue;
}
diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php
index 8469b99e1b..141e72206d 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorFunctionalTest.php
@@ -17,6 +17,7 @@ use Symfony\Component\Form\CallbackTransformer;
use Symfony\Component\Form\Exception\TransformationFailedException;
use Symfony\Component\Form\Extension\Core\Type\DateType;
use Symfony\Component\Form\Extension\Core\Type\FormType;
+use Symfony\Component\Form\Extension\Core\Type\IntegerType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\Validator\ValidatorExtension;
use Symfony\Component\Form\FormBuilderInterface;
@@ -27,6 +28,7 @@ use Symfony\Component\Validator\Constraints\Expression;
use Symfony\Component\Validator\Constraints\GroupSequence;
use Symfony\Component\Validator\Constraints\Length;
use Symfony\Component\Validator\Constraints\NotBlank;
+use Symfony\Component\Validator\Constraints\Valid;
use Symfony\Component\Validator\Mapping\ClassMetadata;
use Symfony\Component\Validator\Mapping\Factory\LazyLoadingMetadataFactory;
use Symfony\Component\Validator\Mapping\Loader\StaticMethodLoader;
@@ -290,6 +292,39 @@ class FormValidatorFunctionalTest extends TestCase
$this->assertSame('children[field2].data', $violations[1]->getPropertyPath());
}
+ public function testCascadeValidationToChildFormsWithTwoValidConstraints()
+ {
+ $form = $this->formFactory->create(ReviewType::class);
+
+ $form->submit([
+ 'rating' => 1,
+ 'title' => 'Sample Title',
+ ]);
+
+ $violations = $this->validator->validate($form);
+
+ $this->assertCount(1, $violations);
+ $this->assertSame('This value should not be blank.', $violations[0]->getMessage());
+ $this->assertSame('children[author].data.email', $violations[0]->getPropertyPath());
+ }
+
+ public function testCascadeValidationToChildFormsWithTwoValidConstraints2()
+ {
+ $form = $this->formFactory->create(ReviewType::class);
+
+ $form->submit([
+ 'title' => 'Sample Title',
+ ]);
+
+ $violations = $this->validator->validate($form);
+
+ $this->assertCount(2, $violations);
+ $this->assertSame('This value should not be blank.', $violations[0]->getMessage());
+ $this->assertSame('data.rating', $violations[0]->getPropertyPath());
+ $this->assertSame('This value should not be blank.', $violations[1]->getMessage());
+ $this->assertSame('children[author].data.email', $violations[1]->getPropertyPath());
+ }
+
public function testCascadeValidationToChildFormsUsingPropertyPathsValidatedInSequence()
{
$form = $this->formFactory->create(FormType::class, null, [
@@ -448,3 +483,62 @@ class FooType extends AbstractType
$resolver->setDefault('data_class', Foo::class);
}
}
+
+class Review
+{
+ public $rating;
+ public $title;
+ public $author;
+
+ public static function loadValidatorMetadata(ClassMetadata $metadata)
+ {
+ $metadata->addPropertyConstraint('title', new NotBlank());
+ $metadata->addPropertyConstraint('rating', new NotBlank());
+ }
+}
+
+class ReviewType extends AbstractType
+{
+ public function buildForm(FormBuilderInterface $builder, array $options)
+ {
+ $builder
+ ->add('rating', IntegerType::class, [
+ 'constraints' => [new Valid()],
+ ])
+ ->add('title')
+ ->add('author', CustomerType::class, [
+ 'constraints' => [new Valid()],
+ ])
+ ;
+ }
+
+ public function configureOptions(OptionsResolver $resolver)
+ {
+ $resolver->setDefault('data_class', Review::class);
+ }
+}
+
+class Customer
+{
+ public $email;
+
+ public static function loadValidatorMetadata(ClassMetadata $metadata)
+ {
+ $metadata->addPropertyConstraint('email', new NotBlank());
+ }
+}
+
+class CustomerType extends AbstractType
+{
+ public function buildForm(FormBuilderInterface $builder, array $options)
+ {
+ $builder
+ ->add('email')
+ ;
+ }
+
+ public function configureOptions(OptionsResolver $resolver)
+ {
+ $resolver->setDefault('data_class', Customer::class);
+ }
+}
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index 76a07f8f08..b7be4a6368 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -791,6 +791,9 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
// replace multiple new lines with a single newline
$rawChunk .= preg_replace(['/\n{2,}/S'], "\n", $token[1]);
} elseif (\in_array($token[0], [\T_COMMENT, \T_DOC_COMMENT])) {
+ if (!\in_array($rawChunk[\strlen($rawChunk) - 1], [' ', "\n", "\r", "\t"], true)) {
+ $rawChunk .= ' ';
+ }
$ignoreSpace = true;
} else {
$rawChunk .= $token[1];
@@ -798,6 +801,8 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
// The PHP-open tag already has a new-line
if (\T_OPEN_TAG === $token[0]) {
$ignoreSpace = true;
+ } else {
+ $ignoreSpace = false;
}
}
}
diff --git a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php
index ece28e00c8..a81560ca32 100644
--- a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php
@@ -227,10 +227,37 @@ class KernelTest extends TestCase
$kernel->handle($request, $type, $catch);
}
- public function testStripComments()
+ /**
+ * @dataProvider getStripCommentsCodes
+ */
+ public function testStripComments(string $source, string $expected)
{
- $source = <<<'EOF'
+ $output = Kernel::stripComments($source);
+
+ // Heredocs are preserved, making the output mixing Unix and Windows line
+ // endings, switching to "\n" everywhere on Windows to avoid failure.
+ if ('\\' === \DIRECTORY_SEPARATOR) {
+ $expected = str_replace("\r\n", "\n", $expected);
+ $output = str_replace("\r\n", "\n", $output);
+ }
+
+ $this->assertEquals($expected, $output);
+ }
+
+ public function getStripCommentsCodes(): array
+ {
+ return [
+ ['assertEquals($expected, $output);
+EOF
+ ],
+ ];
}
public function testSerialize()
diff --git a/src/Symfony/Component/Messenger/Command/StopWorkersCommand.php b/src/Symfony/Component/Messenger/Command/StopWorkersCommand.php
index 1c2fcdb6d9..7df9b9d201 100644
--- a/src/Symfony/Component/Messenger/Command/StopWorkersCommand.php
+++ b/src/Symfony/Component/Messenger/Command/StopWorkersCommand.php
@@ -50,7 +50,7 @@ The %command.name% command sends a signal to stop any messeng
Each worker command will finish the message they are currently processing
and then exit. Worker commands are *not* automatically restarted: that
-should be handled by something like supervisord.
+should be handled by a process control system.
EOF
)
;