From 6ea76cafc273757d527edee5435e7809cc3ba9bf Mon Sep 17 00:00:00 2001 From: Santiago San Martin Date: Mon, 28 Apr 2025 21:14:38 -0300 Subject: [PATCH 01/57] Fix: exclude remember_me from security login authenticators --- .../Bundle/SecurityBundle/Security.php | 3 +- .../SecurityBundle/Tests/SecurityTest.php | 48 ++++++++++++++++++- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Security.php b/src/Symfony/Bundle/SecurityBundle/Security.php index acb30adba8adf..6b5286f2ea868 100644 --- a/src/Symfony/Bundle/SecurityBundle/Security.php +++ b/src/Symfony/Bundle/SecurityBundle/Security.php @@ -188,8 +188,7 @@ private function getAuthenticator(?string $authenticatorName, string $firewallNa $firewallAuthenticatorLocator = $this->authenticators[$firewallName]; if (!$authenticatorName) { - $authenticatorIds = array_keys($firewallAuthenticatorLocator->getProvidedServices()); - + $authenticatorIds = array_filter(array_keys($firewallAuthenticatorLocator->getProvidedServices()), fn (string $authenticatorId) => $authenticatorId !== \sprintf('security.authenticator.remember_me.%s', $firewallName)); if (!$authenticatorIds) { throw new LogicException(sprintf('No authenticator was found for the firewall "%s".', $firewallName)); } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/SecurityTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/SecurityTest.php index 35bd329b2297e..c150730c2a8cb 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/SecurityTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/SecurityTest.php @@ -155,7 +155,10 @@ public function testLogin() $firewallAuthenticatorLocator ->expects($this->once()) ->method('getProvidedServices') - ->willReturn(['security.authenticator.custom.dev' => $authenticator]) + ->willReturn([ + 'security.authenticator.custom.dev' => $authenticator, + 'security.authenticator.remember_me.main' => $authenticator + ]) ; $firewallAuthenticatorLocator ->expects($this->once()) @@ -274,6 +277,49 @@ public function testLoginWithoutRequestContext() $security->login($user); } + public function testLoginFailsWhenTooManyAuthenticatorsFound() + { + $request = new Request(); + $authenticator = $this->createMock(AuthenticatorInterface::class); + $requestStack = $this->createMock(RequestStack::class); + $firewallMap = $this->createMock(FirewallMap::class); + $firewall = new FirewallConfig('main', 'main'); + $userAuthenticator = $this->createMock(UserAuthenticatorInterface::class); + $user = $this->createMock(UserInterface::class); + $userChecker = $this->createMock(UserCheckerInterface::class); + + $container = $this->createMock(ContainerInterface::class); + $container + ->expects($this->atLeastOnce()) + ->method('get') + ->willReturnMap([ + ['request_stack', $requestStack], + ['security.firewall.map', $firewallMap], + ['security.authenticator.managers_locator', $this->createContainer('main', $userAuthenticator)], + ['security.user_checker_locator', $this->createContainer('main', $userChecker)], + ]) + ; + + $requestStack->expects($this->once())->method('getCurrentRequest')->willReturn($request); + $firewallMap->expects($this->once())->method('getFirewallConfig')->willReturn($firewall); + + $firewallAuthenticatorLocator = $this->createMock(ServiceProviderInterface::class); + $firewallAuthenticatorLocator + ->expects($this->once()) + ->method('getProvidedServices') + ->willReturn([ + 'security.authenticator.custom.main' => $authenticator, + 'security.authenticator.other.main' => $authenticator + ]) + ; + + $security = new Security($container, ['main' => $firewallAuthenticatorLocator]); + + $this->expectException(\LogicException::class); + $this->expectExceptionMessage('Too many authenticators were found for the current firewall "main". You must provide an instance of "Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface" to login programmatically. The available authenticators for the firewall "main" are "security.authenticator.custom.main" ,"security.authenticator.other.main'); + $security->login($user); + } + public function testLogout() { $request = new Request(); From f03e549086e1c2fd1bf1ef9752557e3ab7ec9617 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 10 May 2025 14:15:19 +0200 Subject: [PATCH 02/57] Bump Symfony version to 7.3.0 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index d09c86966dbe2..b5a41236d1899 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -73,12 +73,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static array $freshCache = []; - public const VERSION = '7.3.0-BETA2'; + public const VERSION = '7.3.0-DEV'; public const VERSION_ID = 70300; public const MAJOR_VERSION = 7; public const MINOR_VERSION = 3; public const RELEASE_VERSION = 0; - public const EXTRA_VERSION = 'BETA2'; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '05/2025'; public const END_OF_LIFE = '01/2026'; From bcf20bc4f698c93581f8b4067c8ee3950fb737f2 Mon Sep 17 00:00:00 2001 From: Athorcis Date: Mon, 28 Apr 2025 13:34:00 +0200 Subject: [PATCH 03/57] [HttpFoundation] Fix: Encode path in X-Accel-Redirect header we need to encode the path in X-Accel-Redirect header, otherwise nginx fail when certain characters are present in it (like % or ?) https://github.com/rack/rack/issues/1306 --- .../Component/HttpFoundation/BinaryFileResponse.php | 2 +- .../HttpFoundation/Tests/BinaryFileResponseTest.php | 11 ++++++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php index 41a244b818836..c22f283cba444 100644 --- a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php +++ b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php @@ -229,7 +229,7 @@ public function prepare(Request $request): static $path = $location.substr($path, \strlen($pathPrefix)); // Only set X-Accel-Redirect header if a valid URI can be produced // as nginx does not serve arbitrary file paths. - $this->headers->set($type, $path); + $this->headers->set($type, rawurlencode($path)); $this->maxlen = 0; break; } diff --git a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php index c7d47a4d70a35..8f298b77f7218 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php @@ -314,7 +314,15 @@ public function testXAccelMapping($realpath, $mapping, $virtual) $property->setValue($response, $file); $response->prepare($request); - $this->assertEquals($virtual, $response->headers->get('X-Accel-Redirect')); + $header = $response->headers->get('X-Accel-Redirect'); + + if ($virtual) { + // Making sure the path doesn't contain characters unsupported by nginx + $this->assertMatchesRegularExpression('/^([^?%]|%[0-9A-F]{2})*$/', $header); + $header = rawurldecode($header); + } + + $this->assertEquals($virtual, $header); } public function testDeleteFileAfterSend() @@ -361,6 +369,7 @@ public static function getSampleXAccelMappings() ['/home/Foo/bar.txt', '/var/www/=/files/,/home/Foo/=/baz/', '/baz/bar.txt'], ['/home/Foo/bar.txt', '"/var/www/"="/files/", "/home/Foo/"="/baz/"', '/baz/bar.txt'], ['/tmp/bar.txt', '"/var/www/"="/files/", "/home/Foo/"="/baz/"', null], + ['/var/www/var/www/files/foo%.txt', '/var/www/=/files/', '/files/var/www/files/foo%.txt'], ]; } From 0df0873e698de2a29d294ae857680f15090d8495 Mon Sep 17 00:00:00 2001 From: Santiago San Martin Date: Sun, 11 May 2025 19:35:25 -0300 Subject: [PATCH 04/57] fix(security): allow multiple Security attributes when applicable --- .../TraceableAccessDecisionManager.php | 2 +- .../TraceableAccessDecisionManagerTest.php | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Core/Authorization/TraceableAccessDecisionManager.php b/src/Symfony/Component/Security/Core/Authorization/TraceableAccessDecisionManager.php index a03e2d0ca749b..0ef062f6cc37d 100644 --- a/src/Symfony/Component/Security/Core/Authorization/TraceableAccessDecisionManager.php +++ b/src/Symfony/Component/Security/Core/Authorization/TraceableAccessDecisionManager.php @@ -54,7 +54,7 @@ public function decide(TokenInterface $token, array $attributes, mixed $object = $this->accessDecisionStack[] = $accessDecision; try { - return $accessDecision->isGranted = $this->manager->decide($token, $attributes, $object, $accessDecision); + return $accessDecision->isGranted = $this->manager->decide($token, $attributes, $object, $accessDecision, $allowMultipleAttributes); } finally { $this->strategy = $accessDecision->strategy; $currentLog = array_pop($this->currentLog); diff --git a/src/Symfony/Component/Security/Core/Tests/Authorization/TraceableAccessDecisionManagerTest.php b/src/Symfony/Component/Security/Core/Tests/Authorization/TraceableAccessDecisionManagerTest.php index f5313bb541c22..4bd9a01ac4097 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authorization/TraceableAccessDecisionManagerTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authorization/TraceableAccessDecisionManagerTest.php @@ -11,12 +11,14 @@ namespace Symfony\Component\Security\Core\Tests\Authorization; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; use Symfony\Component\Security\Core\Authorization\AccessDecisionManager; use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; use Symfony\Component\Security\Core\Authorization\TraceableAccessDecisionManager; use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface; +use Symfony\Component\Security\Core\Exception\InvalidArgumentException; use Symfony\Component\Security\Core\Tests\Fixtures\DummyVoter; class TraceableAccessDecisionManagerTest extends TestCase @@ -276,4 +278,48 @@ public function testCustomAccessDecisionManagerReturnsEmptyStrategy() $this->assertEquals('-', $adm->getStrategy()); } + + public function testThrowsExceptionWhenMultipleAttributesNotAllowed() + { + $accessDecisionManager = new AccessDecisionManager(); + $traceableAccessDecisionManager = new TraceableAccessDecisionManager($accessDecisionManager); + /** @var TokenInterface&MockObject $tokenMock */ + $tokenMock = $this->createMock(TokenInterface::class); + + $this->expectException(InvalidArgumentException::class); + $traceableAccessDecisionManager->decide($tokenMock, ['attr1', 'attr2']); + } + + /** + * @dataProvider allowMultipleAttributesProvider + */ + public function testAllowMultipleAttributes(array $attributes, bool $allowMultipleAttributes) + { + $accessDecisionManager = new AccessDecisionManager(); + $traceableAccessDecisionManager = new TraceableAccessDecisionManager($accessDecisionManager); + /** @var TokenInterface&MockObject $tokenMock */ + $tokenMock = $this->createMock(TokenInterface::class); + + $isGranted = $traceableAccessDecisionManager->decide($tokenMock, $attributes, null, null, $allowMultipleAttributes); + + $this->assertFalse($isGranted); + } + + public function allowMultipleAttributesProvider(): \Generator + { + yield [ + ['attr1'], + false, + ]; + + yield [ + ['attr1'], + true, + ]; + + yield [ + ['attr1', 'attr2', 'attr3'], + true, + ]; + } } From acc7563015718d2eff97f1096f0038a4b4ebe960 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 12 May 2025 09:26:05 +0200 Subject: [PATCH 05/57] fix lowest allowed Workflow component version --- src/Symfony/Bundle/FrameworkBundle/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index b3c81b28700a3..316c595ffa2bb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -108,7 +108,7 @@ "symfony/validator": "<6.4", "symfony/web-profiler-bundle": "<6.4", "symfony/webhook": "<7.2", - "symfony/workflow": "<7.3" + "symfony/workflow": "<7.3.0-beta2" }, "autoload": { "psr-4": { "Symfony\\Bundle\\FrameworkBundle\\": "" }, From c7206a95d15ef511c1a4371f9db25cc53ccc1999 Mon Sep 17 00:00:00 2001 From: Santiago San Martin Date: Wed, 23 Apr 2025 18:56:44 -0300 Subject: [PATCH 06/57] Fix: prevent "Cannot traverse an already closed generator" error by materializing Traversable input --- .../Serializer/Encoder/CsvEncoder.php | 4 ++++ .../Tests/Encoder/CsvEncoderTest.php | 24 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php b/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php index 8f9c3cff0fb3c..07043d946d751 100644 --- a/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php +++ b/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php @@ -65,6 +65,10 @@ public function encode(mixed $data, string $format, array $context = []): string } elseif (empty($data)) { $data = [[]]; } else { + if ($data instanceof \Traversable) { + // Generators can only be iterated once — convert to array to allow multiple traversals + $data = iterator_to_array($data); + } // Sequential arrays of arrays are considered as collections $i = 0; foreach ($data as $key => $value) { diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php index c0be73a8bd685..cde6d333e99f0 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php @@ -710,4 +710,28 @@ public function testEndOfLinePassedInConstructor() $encoder = new CsvEncoder([CsvEncoder::END_OF_LINE => "\r\n"]); $this->assertSame("foo,bar\r\nhello,test\r\n", $encoder->encode($value, 'csv')); } + + /** @dataProvider provideIterable */ + public function testIterable(mixed $data) + { + $this->assertEquals(<<<'CSV' + foo,bar + hello,"hey ho" + hi,"let's go" + + CSV, $this->encoder->encode($data, 'csv')); + } + + public static function provideIterable() + { + $data = [ + ['foo' => 'hello', 'bar' => 'hey ho'], + ['foo' => 'hi', 'bar' => 'let\'s go'], + ]; + + yield 'array' => [$data]; + yield 'array iterator' => [new \ArrayIterator($data)]; + yield 'iterator aggregate' => [new \IteratorIterator(new \ArrayIterator($data))]; + yield 'generator' => [(fn (): \Generator => yield from $data)()]; + } } From ac859046995ac7c5070184ee88cb5b45696a7685 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 12 May 2025 10:58:22 +0200 Subject: [PATCH 07/57] use use statements instead of FQCNs --- .../DependencyInjection/FrameworkExtensionTestCase.php | 5 +++-- .../DependencyInjection/PhpFrameworkExtensionTest.php | 9 ++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php index 1899d5239eb4d..990e1e8c252d4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php @@ -92,6 +92,7 @@ use Symfony\Component\Validator\Validator\ValidatorInterface; use Symfony\Component\Webhook\Client\RequestParser; use Symfony\Component\Webhook\Controller\WebhookController; +use Symfony\Component\Workflow\DependencyInjection\WorkflowValidatorPass; use Symfony\Component\Workflow\Exception\InvalidDefinitionException; use Symfony\Component\Workflow\Metadata\InMemoryMetadataStore; use Symfony\Component\Workflow\WorkflowEvents; @@ -291,7 +292,7 @@ public function testWorkflows() DefinitionValidator::$called = false; $container = $this->createContainerFromFile('workflows', compile: false); - $container->addCompilerPass(new \Symfony\Component\Workflow\DependencyInjection\WorkflowValidatorPass()); + $container->addCompilerPass(new WorkflowValidatorPass()); $container->compile(); $this->assertTrue($container->hasDefinition('workflow.article'), 'Workflow is registered as a service'); @@ -410,7 +411,7 @@ public function testWorkflowAreValidated() $this->expectException(InvalidDefinitionException::class); $this->expectExceptionMessage('A transition from a place/state must have an unique name. Multiple transitions named "go" from place/state "first" were found on StateMachine "my_workflow".'); $container = $this->createContainerFromFile('workflow_not_valid', compile: false); - $container->addCompilerPass(new \Symfony\Component\Workflow\DependencyInjection\WorkflowValidatorPass()); + $container->addCompilerPass(new WorkflowValidatorPass()); $container->compile(); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php index d2bd2b38eb313..f69a53932711c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php @@ -20,7 +20,10 @@ use Symfony\Component\RateLimiter\CompoundRateLimiterFactory; use Symfony\Component\RateLimiter\RateLimiterFactoryInterface; use Symfony\Component\Validator\Constraints\Email; +use Symfony\Component\Workflow\Definition; +use Symfony\Component\Workflow\DependencyInjection\WorkflowValidatorPass; use Symfony\Component\Workflow\Exception\InvalidDefinitionException; +use Symfony\Component\Workflow\Validator\DefinitionValidatorInterface; class PhpFrameworkExtensionTest extends FrameworkExtensionTestCase { @@ -128,7 +131,7 @@ public function testWorkflowValidationStateMachine() ], ], ]); - $container->addCompilerPass(new \Symfony\Component\Workflow\DependencyInjection\WorkflowValidatorPass()); + $container->addCompilerPass(new WorkflowValidatorPass()); }); } @@ -456,13 +459,13 @@ public static function emailValidationModeProvider() } } -class WorkflowValidatorWithConstructor implements \Symfony\Component\Workflow\Validator\DefinitionValidatorInterface +class WorkflowValidatorWithConstructor implements DefinitionValidatorInterface { public function __construct(bool $enabled) { } - public function validate(\Symfony\Component\Workflow\Definition $definition, string $name): void + public function validate(Definition $definition, string $name): void { } } From 3e8c9b29164f639ef24f478ed9f16335621c3ba4 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Tue, 13 May 2025 09:45:01 +0200 Subject: [PATCH 08/57] [Security] Make data provider static --- .../Tests/Authorization/TraceableAccessDecisionManagerTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Security/Core/Tests/Authorization/TraceableAccessDecisionManagerTest.php b/src/Symfony/Component/Security/Core/Tests/Authorization/TraceableAccessDecisionManagerTest.php index 4bd9a01ac4097..496d970cd1f00 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authorization/TraceableAccessDecisionManagerTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authorization/TraceableAccessDecisionManagerTest.php @@ -305,7 +305,7 @@ public function testAllowMultipleAttributes(array $attributes, bool $allowMultip $this->assertFalse($isGranted); } - public function allowMultipleAttributesProvider(): \Generator + public static function allowMultipleAttributesProvider(): \Generator { yield [ ['attr1'], From 9efc70222e92cc3134e607e4fd6152f97c898c26 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 4 May 2025 21:59:38 +0200 Subject: [PATCH 09/57] document the array shape of the content option --- .../Bridge/Mercure/MercureOptions.php | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/Symfony/Component/Notifier/Bridge/Mercure/MercureOptions.php b/src/Symfony/Component/Notifier/Bridge/Mercure/MercureOptions.php index 4f3f80c0d7649..85a513cee6901 100644 --- a/src/Symfony/Component/Notifier/Bridge/Mercure/MercureOptions.php +++ b/src/Symfony/Component/Notifier/Bridge/Mercure/MercureOptions.php @@ -22,6 +22,21 @@ final class MercureOptions implements MessageOptionsInterface /** * @param string|string[]|null $topics + * @param array{ + * badge?: string, + * body?: string, + * data?: mixed, + * dir?: 'auto'|'ltr'|'rtl', + * icon?: string, + * image?: string, + * lang?: string, + * renotify?: bool, + * requireInteraction?: bool, + * silent?: bool, + * tag?: string, + * timestamp?: int, + * vibrate?: int|list, + * }|null $content */ public function __construct( string|array|null $topics = null, @@ -62,6 +77,23 @@ public function getRetry(): ?int return $this->retry; } + /** + * @return array{ + * badge?: string, + * body?: string, + * data?: mixed, + * dir?: 'auto'|'ltr'|'rtl', + * icon?: string, + * image?: string, + * lang?: string, + * renotify?: bool, + * requireInteraction?: bool, + * silent?: bool, + * tag?: string, + * timestamp?: int, + * vibrate?: int|list, + * }|null + */ public function getContent(): ?array { return $this->content; From 59a4ae92d2d6baeac7d9224041171c045ccfc63f Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Mon, 12 May 2025 15:44:05 -0400 Subject: [PATCH 10/57] [Console] Invokable command `#[Option]` adjustments - `#[Option] ?string $opt = null` as `VALUE_REQUIRED` - `#[Option] bool|string $opt = false` as `VALUE_OPTIONAL` - `#[Option] ?string $opt = ''` throws exception - allow `#[Option] ?array $opt = null` - more tests... --- .../Component/Console/Attribute/Option.php | 74 ++++++++++++----- .../Tests/Command/InvokableCommandTest.php | 79 +++++++++++++++---- 2 files changed, 118 insertions(+), 35 deletions(-) diff --git a/src/Symfony/Component/Console/Attribute/Option.php b/src/Symfony/Component/Console/Attribute/Option.php index 4aea4831e9ac6..19c82317033c4 100644 --- a/src/Symfony/Component/Console/Attribute/Option.php +++ b/src/Symfony/Component/Console/Attribute/Option.php @@ -22,6 +22,7 @@ class Option { private const ALLOWED_TYPES = ['string', 'bool', 'int', 'float', 'array']; + private const ALLOWED_UNION_TYPES = ['bool|string', 'bool|int', 'bool|float']; private string|bool|int|float|array|null $default = null; private array|\Closure $suggestedValues; @@ -56,18 +57,8 @@ public static function tryFrom(\ReflectionParameter $parameter): ?self return null; } - $type = $parameter->getType(); $name = $parameter->getName(); - - if (!$type instanceof \ReflectionNamedType) { - throw new LogicException(\sprintf('The parameter "$%s" must have a named type. Untyped, Union or Intersection types are not supported for command options.', $name)); - } - - $self->typeName = $type->getName(); - - if (!\in_array($self->typeName, self::ALLOWED_TYPES, true)) { - throw new LogicException(\sprintf('The type "%s" of parameter "$%s" is not supported as a command option. Only "%s" types are allowed.', $self->typeName, $name, implode('", "', self::ALLOWED_TYPES))); - } + $type = $parameter->getType(); if (!$parameter->isDefaultValueAvailable()) { throw new LogicException(\sprintf('The option parameter "$%s" must declare a default value.', $name)); @@ -80,16 +71,26 @@ public static function tryFrom(\ReflectionParameter $parameter): ?self $self->default = $parameter->getDefaultValue(); $self->allowNull = $parameter->allowsNull(); - if ('bool' === $self->typeName && $self->allowNull && \in_array($self->default, [true, false], true)) { - throw new LogicException(\sprintf('The option parameter "$%s" must not be nullable when it has a default boolean value.', $name)); + if ($type instanceof \ReflectionUnionType) { + return $self->handleUnion($type); } - if ('string' === $self->typeName && null === $self->default) { - throw new LogicException(\sprintf('The option parameter "$%s" must not have a default of null.', $name)); + if (!$type instanceof \ReflectionNamedType) { + throw new LogicException(\sprintf('The parameter "$%s" must have a named type. Untyped or Intersection types are not supported for command options.', $name)); } - if ('array' === $self->typeName && $self->allowNull) { - throw new LogicException(\sprintf('The option parameter "$%s" must not be nullable.', $name)); + $self->typeName = $type->getName(); + + if (!\in_array($self->typeName, self::ALLOWED_TYPES, true)) { + throw new LogicException(\sprintf('The type "%s" of parameter "$%s" is not supported as a command option. Only "%s" types are allowed.', $self->typeName, $name, implode('", "', self::ALLOWED_TYPES))); + } + + if ('bool' === $self->typeName && $self->allowNull && \in_array($self->default, [true, false], true)) { + throw new LogicException(\sprintf('The option parameter "$%s" must not be nullable when it has a default boolean value.', $name)); + } + + if ($self->allowNull && null !== $self->default) { + throw new LogicException(\sprintf('The option parameter "$%s" must either be not-nullable or have a default of null.', $name)); } if ('bool' === $self->typeName) { @@ -97,11 +98,10 @@ public static function tryFrom(\ReflectionParameter $parameter): ?self if (false !== $self->default) { $self->mode |= InputOption::VALUE_NEGATABLE; } + } elseif ('array' === $self->typeName) { + $self->mode = InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY; } else { - $self->mode = $self->allowNull ? InputOption::VALUE_OPTIONAL : InputOption::VALUE_REQUIRED; - if ('array' === $self->typeName) { - $self->mode |= InputOption::VALUE_IS_ARRAY; - } + $self->mode = InputOption::VALUE_REQUIRED; } if (\is_array($self->suggestedValues) && !\is_callable($self->suggestedValues) && 2 === \count($self->suggestedValues) && ($instance = $parameter->getDeclaringFunction()->getClosureThis()) && $instance::class === $self->suggestedValues[0] && \is_callable([$instance, $self->suggestedValues[1]])) { @@ -129,6 +129,14 @@ public function resolveValue(InputInterface $input): mixed { $value = $input->getOption($this->name); + if (null === $value && \in_array($this->typeName, self::ALLOWED_UNION_TYPES, true)) { + return true; + } + + if ('array' === $this->typeName && $this->allowNull && [] === $value) { + return null; + } + if ('bool' !== $this->typeName) { return $value; } @@ -139,4 +147,28 @@ public function resolveValue(InputInterface $input): mixed return $value ?? $this->default; } + + private function handleUnion(\ReflectionUnionType $type): self + { + $types = array_map( + static fn(\ReflectionType $t) => $t instanceof \ReflectionNamedType ? $t->getName() : null, + $type->getTypes(), + ); + + sort($types); + + $this->typeName = implode('|', array_filter($types)); + + if (!\in_array($this->typeName, self::ALLOWED_UNION_TYPES, true)) { + throw new LogicException(\sprintf('The union type for parameter "$%s" is not supported as a command option. Only "%s" types are allowed.', $this->name, implode('", "', self::ALLOWED_UNION_TYPES))); + } + + if (false !== $this->default) { + throw new LogicException(\sprintf('The option parameter "$%s" must have a default value of false.', $this->name)); + } + + $this->mode = InputOption::VALUE_OPTIONAL; + + return $this; + } } diff --git a/src/Symfony/Component/Console/Tests/Command/InvokableCommandTest.php b/src/Symfony/Component/Console/Tests/Command/InvokableCommandTest.php index 88f1b78701e0a..917e2f88f1655 100644 --- a/src/Symfony/Component/Console/Tests/Command/InvokableCommandTest.php +++ b/src/Symfony/Component/Console/Tests/Command/InvokableCommandTest.php @@ -79,6 +79,7 @@ public function testCommandInputOptionDefinition() #[Option(shortcut: 'v')] bool $verbose = false, #[Option(description: 'User groups')] array $groups = [], #[Option(suggestedValues: [self::class, 'getSuggestedRoles'])] array $roles = ['ROLE_USER'], + #[Option] string|bool $opt = false, ): int { return 0; }); @@ -86,7 +87,8 @@ public function testCommandInputOptionDefinition() $timeoutInputOption = $command->getDefinition()->getOption('idle'); self::assertSame('idle', $timeoutInputOption->getName()); self::assertNull($timeoutInputOption->getShortcut()); - self::assertTrue($timeoutInputOption->isValueOptional()); + self::assertTrue($timeoutInputOption->isValueRequired()); + self::assertFalse($timeoutInputOption->isValueOptional()); self::assertFalse($timeoutInputOption->isNegatable()); self::assertNull($timeoutInputOption->getDefault()); @@ -120,6 +122,14 @@ public function testCommandInputOptionDefinition() self::assertTrue($rolesInputOption->hasCompletion()); $rolesInputOption->complete(new CompletionInput(), $suggestions = new CompletionSuggestions()); self::assertSame(['ROLE_ADMIN', 'ROLE_USER'], array_map(static fn (Suggestion $s) => $s->getValue(), $suggestions->getValueSuggestions())); + + $optInputOption = $command->getDefinition()->getOption('opt'); + self::assertSame('opt', $optInputOption->getName()); + self::assertNull($optInputOption->getShortcut()); + self::assertFalse($optInputOption->isValueRequired()); + self::assertTrue($optInputOption->isValueOptional()); + self::assertFalse($optInputOption->isNegatable()); + self::assertFalse($optInputOption->getDefault()); } public function testInvalidArgumentType() @@ -136,7 +146,7 @@ public function testInvalidArgumentType() public function testInvalidOptionType() { $command = new Command('foo'); - $command->setCode(function (#[Option] object $any) {}); + $command->setCode(function (#[Option] ?object $any = null) {}); $this->expectException(LogicException::class); $this->expectExceptionMessage('The type "object" of parameter "$any" is not supported as a command option. Only "string", "bool", "int", "float", "array" types are allowed.'); @@ -262,14 +272,30 @@ public function testNonBinaryInputOptions(array $parameters, array $expected) $command = new Command('foo'); $command->setCode(function ( #[Option] string $a = '', - #[Option] ?string $b = '', - #[Option] array $c = [], - #[Option] array $d = ['a', 'b'], + #[Option] array $b = [], + #[Option] array $c = ['a', 'b'], + #[Option] bool|string $d = false, + #[Option] ?string $e = null, + #[Option] ?array $f = null, + #[Option] int $g = 0, + #[Option] ?int $h = null, + #[Option] float $i = 0.0, + #[Option] ?float $j = null, + #[Option] bool|int $k = false, + #[Option] bool|float $l = false, ) use ($expected): int { $this->assertSame($expected[0], $a); $this->assertSame($expected[1], $b); $this->assertSame($expected[2], $c); $this->assertSame($expected[3], $d); + $this->assertSame($expected[4], $e); + $this->assertSame($expected[5], $f); + $this->assertSame($expected[6], $g); + $this->assertSame($expected[7], $h); + $this->assertSame($expected[8], $i); + $this->assertSame($expected[9], $j); + $this->assertSame($expected[10], $k); + $this->assertSame($expected[11], $l); return 0; }); @@ -279,9 +305,18 @@ public function testNonBinaryInputOptions(array $parameters, array $expected) public static function provideNonBinaryInputOptions(): \Generator { - yield 'defaults' => [[], ['', '', [], ['a', 'b']]]; - yield 'with-value' => [['--a' => 'x', '--b' => 'y', '--c' => ['z'], '--d' => ['c', 'd']], ['x', 'y', ['z'], ['c', 'd']]]; - yield 'without-value' => [['--b' => null], ['', null, [], ['a', 'b']]]; + yield 'defaults' => [ + [], + ['', [], ['a', 'b'], false, null, null, 0, null, 0.0, null, false, false], + ]; + yield 'with-value' => [ + ['--a' => 'x', '--b' => ['z'], '--c' => ['c', 'd'], '--d' => 'v', '--e' => 'w', '--f' => ['q'], '--g' => 1, '--h' => 2, '--i' => 3.1, '--j' => 4.2, '--k' => 5, '--l' => 6.3], + ['x', ['z'], ['c', 'd'], 'v', 'w', ['q'], 1, 2, 3.1, 4.2, 5, 6.3], + ]; + yield 'without-value' => [ + ['--d' => null, '--k' => null, '--l' => null], + ['', [], ['a', 'b'], true, null, null, 0, null, 0.0, null, true, true], + ]; } /** @@ -312,13 +347,29 @@ function (#[Option] ?bool $a = true) {}, function (#[Option] ?bool $a = false) {}, 'The option parameter "$a" must not be nullable when it has a default boolean value.', ]; - yield 'nullable-string' => [ - function (#[Option] ?string $a = null) {}, - 'The option parameter "$a" must not have a default of null.', + yield 'invalid-union-type' => [ + function (#[Option] array|bool $a = false) {}, + 'The union type for parameter "$a" is not supported as a command option. Only "bool|string", "bool|int", "bool|float" types are allowed.', + ]; + yield 'union-type-cannot-allow-null' => [ + function (#[Option] string|bool|null $a = null) {}, + 'The union type for parameter "$a" is not supported as a command option. Only "bool|string", "bool|int", "bool|float" types are allowed.', + ]; + yield 'union-type-default-true' => [ + function (#[Option] string|bool $a = true) {}, + 'The option parameter "$a" must have a default value of false.', + ]; + yield 'union-type-default-string' => [ + function (#[Option] string|bool $a = 'foo') {}, + 'The option parameter "$a" must have a default value of false.', + ]; + yield 'nullable-string-not-null-default' => [ + function (#[Option] ?string $a = 'foo') {}, + 'The option parameter "$a" must either be not-nullable or have a default of null.', ]; - yield 'nullable-array' => [ - function (#[Option] ?array $a = null) {}, - 'The option parameter "$a" must not be nullable.', + yield 'nullable-array-not-null-default' => [ + function (#[Option] ?array $a = []) {}, + 'The option parameter "$a" must either be not-nullable or have a default of null.', ]; } From 941c05187ab6ed54a464a16ac053b11f610dd9ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Sun, 11 May 2025 20:09:09 +0200 Subject: [PATCH 11/57] [Config] Fix generated comment for multiline "info" --- .../Config/Builder/ConfigBuilderGenerator.php | 18 +++++++++--------- .../Builder/Fixtures/NodeInitialValues.php | 8 +++++++- .../Messenger/TransportsConfig.php | 3 +++ 3 files changed, 19 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/Config/Builder/ConfigBuilderGenerator.php b/src/Symfony/Component/Config/Builder/ConfigBuilderGenerator.php index d43d814ebd38b..9649c8d82cbb9 100644 --- a/src/Symfony/Component/Config/Builder/ConfigBuilderGenerator.php +++ b/src/Symfony/Component/Config/Builder/ConfigBuilderGenerator.php @@ -413,39 +413,39 @@ private function getComment(BaseNode $node): string { $comment = ''; if ('' !== $info = (string) $node->getInfo()) { - $comment .= ' * '.$info."\n"; + $comment .= $info."\n"; } if (!$node instanceof ArrayNode) { foreach ((array) ($node->getExample() ?? []) as $example) { - $comment .= ' * @example '.$example."\n"; + $comment .= '@example '.$example."\n"; } if ('' !== $default = $node->getDefaultValue()) { - $comment .= ' * @default '.(null === $default ? 'null' : var_export($default, true))."\n"; + $comment .= '@default '.(null === $default ? 'null' : var_export($default, true))."\n"; } if ($node instanceof EnumNode) { - $comment .= sprintf(' * @param ParamConfigurator|%s $value', implode('|', array_unique(array_map(fn ($a) => !$a instanceof \UnitEnum ? var_export($a, true) : '\\'.ltrim(var_export($a, true), '\\'), $node->getValues()))))."\n"; + $comment .= sprintf('@param ParamConfigurator|%s $value', implode('|', array_unique(array_map(fn ($a) => !$a instanceof \UnitEnum ? var_export($a, true) : '\\'.ltrim(var_export($a, true), '\\'), $node->getValues()))))."\n"; } else { $parameterTypes = $this->getParameterTypes($node); - $comment .= ' * @param ParamConfigurator|'.implode('|', $parameterTypes).' $value'."\n"; + $comment .= '@param ParamConfigurator|'.implode('|', $parameterTypes).' $value'."\n"; } } else { foreach ((array) ($node->getExample() ?? []) as $example) { - $comment .= ' * @example '.json_encode($example)."\n"; + $comment .= '@example '.json_encode($example)."\n"; } if ($node->hasDefaultValue() && [] != $default = $node->getDefaultValue()) { - $comment .= ' * @default '.json_encode($default)."\n"; + $comment .= '@default '.json_encode($default)."\n"; } } if ($node->isDeprecated()) { - $comment .= ' * @deprecated '.$node->getDeprecation($node->getName(), $node->getParent()->getName())['message']."\n"; + $comment .= '@deprecated '.$node->getDeprecation($node->getName(), $node->getParent()->getName())['message']."\n"; } - return $comment; + return $comment ? ' * '.str_replace("\n", "\n * ", rtrim($comment, "\n"))."\n" : ''; } /** diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues.php index 153af57be9b5b..5c1259c20edd8 100644 --- a/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues.php +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues.php @@ -38,7 +38,13 @@ public function getConfigTreeBuilder(): TreeBuilder ->arrayPrototype() ->fixXmlConfig('option') ->children() - ->scalarNode('dsn')->end() + ->scalarNode('dsn') + ->info(<<<'INFO' + The DSN to use. This is a required option. + The info is used to describe the DSN, + it can be multi-line. + INFO) + ->end() ->scalarNode('serializer')->defaultNull()->end() ->arrayNode('options') ->normalizeKeys(false) diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues/Symfony/Config/NodeInitialValues/Messenger/TransportsConfig.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues/Symfony/Config/NodeInitialValues/Messenger/TransportsConfig.php index b9d8b48db3556..6a98166eccc94 100644 --- a/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues/Symfony/Config/NodeInitialValues/Messenger/TransportsConfig.php +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues/Symfony/Config/NodeInitialValues/Messenger/TransportsConfig.php @@ -16,6 +16,9 @@ class TransportsConfig private $_usedProperties = []; /** + * The DSN to use. This is a required option. + * The info is used to describe the DSN, + * it can be multi-line. * @default null * @param ParamConfigurator|mixed $value * @return $this From 594025893a06fbd451992204efab8e8301f74df0 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 14 May 2025 09:14:36 +0200 Subject: [PATCH 12/57] remove no longer used service definition --- src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.php index 7a3a95739b0f2..f1dc560ab76f8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.php @@ -45,7 +45,6 @@ tagged_iterator('mailer.transport_factory'), ]) - ->set('mailer.default_transport', TransportInterface::class) ->alias('mailer.default_transport', 'mailer.transports') ->alias(TransportInterface::class, 'mailer.default_transport') From 60cba4531731d74e98ff0395b2f1a9601b55e237 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Sat, 29 Mar 2025 18:18:47 +0100 Subject: [PATCH 13/57] [JsonPath] Add `JsonPathAssertionsTrait` and related constraints --- .../JsonPath/Test/JsonPathAssertionsTrait.php | 80 ++++++++ .../JsonPath/Test/JsonPathContains.php | 43 ++++ .../Component/JsonPath/Test/JsonPathCount.php | 40 ++++ .../JsonPath/Test/JsonPathEquals.php | 40 ++++ .../JsonPath/Test/JsonPathNotContains.php | 43 ++++ .../JsonPath/Test/JsonPathNotEquals.php | 40 ++++ .../JsonPath/Test/JsonPathNotSame.php | 40 ++++ .../Component/JsonPath/Test/JsonPathSame.php | 40 ++++ .../Test/JsonPathAssertionsTraitTest.php | 191 ++++++++++++++++++ 9 files changed, 557 insertions(+) create mode 100644 src/Symfony/Component/JsonPath/Test/JsonPathAssertionsTrait.php create mode 100644 src/Symfony/Component/JsonPath/Test/JsonPathContains.php create mode 100644 src/Symfony/Component/JsonPath/Test/JsonPathCount.php create mode 100644 src/Symfony/Component/JsonPath/Test/JsonPathEquals.php create mode 100644 src/Symfony/Component/JsonPath/Test/JsonPathNotContains.php create mode 100644 src/Symfony/Component/JsonPath/Test/JsonPathNotEquals.php create mode 100644 src/Symfony/Component/JsonPath/Test/JsonPathNotSame.php create mode 100644 src/Symfony/Component/JsonPath/Test/JsonPathSame.php create mode 100644 src/Symfony/Component/JsonPath/Tests/Test/JsonPathAssertionsTraitTest.php diff --git a/src/Symfony/Component/JsonPath/Test/JsonPathAssertionsTrait.php b/src/Symfony/Component/JsonPath/Test/JsonPathAssertionsTrait.php new file mode 100644 index 0000000000000..42d35339a5760 --- /dev/null +++ b/src/Symfony/Component/JsonPath/Test/JsonPathAssertionsTrait.php @@ -0,0 +1,80 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\JsonPath\Test; + +use PHPUnit\Framework\Assert; +use PHPUnit\Framework\ExpectationFailedException; +use Symfony\Component\JsonPath\JsonPath; + +/** + * @author Alexandre Daubois + * + * @experimental + */ +trait JsonPathAssertionsTrait +{ + /** + * @throws ExpectationFailedException + */ + final public static function assertJsonPathEquals(mixed $expectedValue, JsonPath|string $jsonPath, string $json, string $message = ''): void + { + Assert::assertThat($expectedValue, new JsonPathEquals($jsonPath, $json), $message); + } + + /** + * @throws ExpectationFailedException + */ + final public static function assertJsonPathNotEquals(mixed $expectedValue, JsonPath|string $jsonPath, string $json, string $message = ''): void + { + Assert::assertThat($expectedValue, new JsonPathNotEquals($jsonPath, $json), $message); + } + + /** + * @throws ExpectationFailedException + */ + final public static function assertJsonPathCount(int $expectedCount, JsonPath|string $jsonPath, string $json, string $message = ''): void + { + Assert::assertThat($expectedCount, new JsonPathCount($jsonPath, $json), $message); + } + + /** + * @throws ExpectationFailedException + */ + final public static function assertJsonPathSame(mixed $expectedValue, JsonPath|string $jsonPath, string $json, string $message = ''): void + { + Assert::assertThat($expectedValue, new JsonPathSame($jsonPath, $json), $message); + } + + /** + * @throws ExpectationFailedException + */ + final public static function assertJsonPathNotSame(mixed $expectedValue, JsonPath|string $jsonPath, string $json, string $message = ''): void + { + Assert::assertThat($expectedValue, new JsonPathNotSame($jsonPath, $json), $message); + } + + /** + * @throws ExpectationFailedException + */ + final public static function assertJsonPathContains(mixed $expectedValue, JsonPath|string $jsonPath, string $json, bool $strict = true, string $message = ''): void + { + Assert::assertThat($expectedValue, new JsonPathContains($jsonPath, $json, $strict), $message); + } + + /** + * @throws ExpectationFailedException + */ + final public static function assertJsonPathNotContains(mixed $expectedValue, JsonPath|string $jsonPath, string $json, bool $strict = true, string $message = ''): void + { + Assert::assertThat($expectedValue, new JsonPathNotContains($jsonPath, $json, $strict), $message); + } +} diff --git a/src/Symfony/Component/JsonPath/Test/JsonPathContains.php b/src/Symfony/Component/JsonPath/Test/JsonPathContains.php new file mode 100644 index 0000000000000..e043b90a40637 --- /dev/null +++ b/src/Symfony/Component/JsonPath/Test/JsonPathContains.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\JsonPath\Test; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\JsonPath\JsonCrawler; +use Symfony\Component\JsonPath\JsonPath; + +/** + * @author Alexandre Daubois + * + * @experimental + */ +class JsonPathContains extends Constraint +{ + public function __construct( + private JsonPath|string $jsonPath, + private string $json, + private bool $strict = true, + ) { + } + + public function toString(): string + { + return \sprintf('is found in elements at JSON path "%s"', $this->jsonPath); + } + + protected function matches(mixed $other): bool + { + $result = (new JsonCrawler($this->json))->find($this->jsonPath); + + return \in_array($other, $result, $this->strict); + } +} diff --git a/src/Symfony/Component/JsonPath/Test/JsonPathCount.php b/src/Symfony/Component/JsonPath/Test/JsonPathCount.php new file mode 100644 index 0000000000000..8c973a8309345 --- /dev/null +++ b/src/Symfony/Component/JsonPath/Test/JsonPathCount.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\JsonPath\Test; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\JsonPath\JsonCrawler; +use Symfony\Component\JsonPath\JsonPath; + +/** + * @author Alexandre Daubois + * + * @experimental + */ +class JsonPathCount extends Constraint +{ + public function __construct( + private JsonPath|string $jsonPath, + private string $json, + ) { + } + + public function toString(): string + { + return \sprintf('matches expected count of JSON path "%s"', $this->jsonPath); + } + + protected function matches(mixed $other): bool + { + return $other === \count((new JsonCrawler($this->json))->find($this->jsonPath)); + } +} diff --git a/src/Symfony/Component/JsonPath/Test/JsonPathEquals.php b/src/Symfony/Component/JsonPath/Test/JsonPathEquals.php new file mode 100644 index 0000000000000..56825434b5faa --- /dev/null +++ b/src/Symfony/Component/JsonPath/Test/JsonPathEquals.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\JsonPath\Test; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\JsonPath\JsonCrawler; +use Symfony\Component\JsonPath\JsonPath; + +/** + * @author Alexandre Daubois + * + * @experimental + */ +class JsonPathEquals extends Constraint +{ + public function __construct( + private JsonPath|string $jsonPath, + private string $json, + ) { + } + + public function toString(): string + { + return \sprintf('equals JSON path "%s" result', $this->jsonPath); + } + + protected function matches(mixed $other): bool + { + return (new JsonCrawler($this->json))->find($this->jsonPath) == $other; + } +} diff --git a/src/Symfony/Component/JsonPath/Test/JsonPathNotContains.php b/src/Symfony/Component/JsonPath/Test/JsonPathNotContains.php new file mode 100644 index 0000000000000..721d60fa29984 --- /dev/null +++ b/src/Symfony/Component/JsonPath/Test/JsonPathNotContains.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\JsonPath\Test; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\JsonPath\JsonCrawler; +use Symfony\Component\JsonPath\JsonPath; + +/** + * @author Alexandre Daubois + * + * @experimental + */ +class JsonPathNotContains extends Constraint +{ + public function __construct( + private JsonPath|string $jsonPath, + private string $json, + private bool $strict = true, + ) { + } + + public function toString(): string + { + return \sprintf('is not found in elements at JSON path "%s"', $this->jsonPath); + } + + protected function matches(mixed $other): bool + { + $result = (new JsonCrawler($this->json))->find($this->jsonPath); + + return !\in_array($other, $result, $this->strict); + } +} diff --git a/src/Symfony/Component/JsonPath/Test/JsonPathNotEquals.php b/src/Symfony/Component/JsonPath/Test/JsonPathNotEquals.php new file mode 100644 index 0000000000000..d149dbb59c441 --- /dev/null +++ b/src/Symfony/Component/JsonPath/Test/JsonPathNotEquals.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\JsonPath\Test; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\JsonPath\JsonCrawler; +use Symfony\Component\JsonPath\JsonPath; + +/** + * @author Alexandre Daubois + * + * @experimental + */ +class JsonPathNotEquals extends Constraint +{ + public function __construct( + private JsonPath|string $jsonPath, + private string $json, + ) { + } + + public function toString(): string + { + return \sprintf('does not equal JSON path "%s" result', $this->jsonPath); + } + + protected function matches(mixed $other): bool + { + return (new JsonCrawler($this->json))->find($this->jsonPath) != $other; + } +} diff --git a/src/Symfony/Component/JsonPath/Test/JsonPathNotSame.php b/src/Symfony/Component/JsonPath/Test/JsonPathNotSame.php new file mode 100644 index 0000000000000..248ac456fcbef --- /dev/null +++ b/src/Symfony/Component/JsonPath/Test/JsonPathNotSame.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\JsonPath\Test; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\JsonPath\JsonCrawler; +use Symfony\Component\JsonPath\JsonPath; + +/** + * @author Alexandre Daubois + * + * @experimental + */ +class JsonPathNotSame extends Constraint +{ + public function __construct( + private JsonPath|string $jsonPath, + private string $json, + ) { + } + + public function toString(): string + { + return \sprintf('is not identical to JSON path "%s" result', $this->jsonPath); + } + + protected function matches(mixed $other): bool + { + return (new JsonCrawler($this->json))->find($this->jsonPath) !== $other; + } +} diff --git a/src/Symfony/Component/JsonPath/Test/JsonPathSame.php b/src/Symfony/Component/JsonPath/Test/JsonPathSame.php new file mode 100644 index 0000000000000..469922d8a0b90 --- /dev/null +++ b/src/Symfony/Component/JsonPath/Test/JsonPathSame.php @@ -0,0 +1,40 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\JsonPath\Test; + +use PHPUnit\Framework\Constraint\Constraint; +use Symfony\Component\JsonPath\JsonCrawler; +use Symfony\Component\JsonPath\JsonPath; + +/** + * @author Alexandre Daubois + * + * @experimental + */ +class JsonPathSame extends Constraint +{ + public function __construct( + private JsonPath|string $jsonPath, + private string $json, + ) { + } + + public function toString(): string + { + return \sprintf('is identical to JSON path "%s" result', $this->jsonPath); + } + + protected function matches(mixed $other): bool + { + return (new JsonCrawler($this->json))->find($this->jsonPath) === $other; + } +} diff --git a/src/Symfony/Component/JsonPath/Tests/Test/JsonPathAssertionsTraitTest.php b/src/Symfony/Component/JsonPath/Tests/Test/JsonPathAssertionsTraitTest.php new file mode 100644 index 0000000000000..62d64b53e1e8d --- /dev/null +++ b/src/Symfony/Component/JsonPath/Tests/Test/JsonPathAssertionsTraitTest.php @@ -0,0 +1,191 @@ +getMessage()); + + $thrown = true; + } + + self::assertTrue($thrown); + } + + public function testAssertJsonPathNotEqualsOk() + { + self::assertJsonPathNotEquals([2], '$.a[2]', self::getSimpleCollectionCrawlerData()); + } + + public function testAssertJsonPathNotEqualsKo() + { + $thrown = false; + try { + self::assertJsonPathNotEquals([1], '$.a[2]', self::getSimpleCollectionCrawlerData()); + } catch (AssertionFailedError $exception) { + self::assertMatchesRegularExpression('/Failed asserting that .+ does not equal JSON path "\$\.a\[2]" result./s', $exception->getMessage()); + + $thrown = true; + } + + self::assertTrue($thrown); + } + + public function testAssertJsonPathCountOk() + { + self::assertJsonPathCount(6, '$.a[*]', self::getSimpleCollectionCrawlerData()); + } + + public function testAssertJsonPathCountOkWithFilter() + { + self::assertJsonPathCount(2, '$.book[?(@.price > 25)]', <<getMessage()); + + $thrown = true; + } + + self::assertTrue($thrown); + } + + public function testAssertJsonPathSameOk() + { + self::assertJsonPathSame([1], '$.a[2]', self::getSimpleCollectionCrawlerData()); + } + + public function testAssertJsonPathSameKo() + { + $thrown = false; + try { + self::assertJsonPathSame([2], '$.a[2]', self::getSimpleCollectionCrawlerData()); + } catch (AssertionFailedError $exception) { + self::assertMatchesRegularExpression('/Failed asserting that .+ is identical to JSON path "\$\.a\[2]" result\./s', $exception->getMessage()); + + $thrown = true; + } + + self::assertTrue($thrown); + } + + public function testAssertJsonPathHasNoTypeCoercion() + { + $thrown = false; + try { + self::assertJsonPathSame(['1'], '$.a[2]', self::getSimpleCollectionCrawlerData()); + } catch (AssertionFailedError $exception) { + self::assertMatchesRegularExpression('/Failed asserting that .+ is identical to JSON path "\$\.a\[2]" result\./s', $exception->getMessage()); + + $thrown = true; + } + + self::assertTrue($thrown); + } + + public function testAssertJsonPathNotSameOk() + { + self::assertJsonPathNotSame([2], '$.a[2]', self::getSimpleCollectionCrawlerData()); + } + + public function testAssertJsonPathNotSameKo() + { + $thrown = false; + try { + self::assertJsonPathNotSame([1], '$.a[2]', self::getSimpleCollectionCrawlerData()); + } catch (AssertionFailedError $exception) { + self::assertMatchesRegularExpression('/Failed asserting that .+ is not identical to JSON path "\$\.a\[2]" result\./s', $exception->getMessage()); + + $thrown = true; + } + + self::assertTrue($thrown); + } + + public function testAssertJsonPathNotSameHasNoTypeCoercion() + { + self::assertJsonPathNotSame(['1'], '$.a[2]', self::getSimpleCollectionCrawlerData()); + } + + public function testAssertJsonPathContainsOk() + { + self::assertJsonPathContains(1, '$.a[*]', self::getSimpleCollectionCrawlerData()); + } + + public function testAssertJsonPathContainsKo() + { + $thrown = false; + try { + self::assertJsonPathContains(0, '$.a[*]', self::getSimpleCollectionCrawlerData()); + } catch (AssertionFailedError $exception) { + self::assertSame('Failed asserting that 0 is found in elements at JSON path "$.a[*]".', $exception->getMessage()); + + $thrown = true; + } + + self::assertTrue($thrown); + } + + public function testAssertJsonPathNotContainsOk() + { + self::assertJsonPathNotContains(0, '$.a[*]', self::getSimpleCollectionCrawlerData()); + } + + public function testAssertJsonPathNotContainsKo() + { + $thrown = false; + try { + self::assertJsonPathNotContains(1, '$.a[*]', self::getSimpleCollectionCrawlerData()); + } catch (AssertionFailedError $exception) { + self::assertSame('Failed asserting that 1 is not found in elements at JSON path "$.a[*]".', $exception->getMessage()); + + $thrown = true; + } + + self::assertTrue($thrown); + } + + private static function getSimpleCollectionCrawlerData(): string + { + return << Date: Fri, 2 May 2025 14:12:20 +0200 Subject: [PATCH 14/57] [FrameworkBundle] skip messenger deduplication middlerware registration when no "default" lock is configured --- .../DependencyInjection/FrameworkExtension.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 385a4caf38ded..fce6ba65c53ed 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -569,9 +569,9 @@ public function load(array $configs, ContainerBuilder $container): void $container->removeDefinition('console.command.scheduler_debug'); } - // messenger depends on validation being registered + // messenger depends on validation, and lock being registered if ($messengerEnabled) { - $this->registerMessengerConfiguration($config['messenger'], $container, $loader, $this->readConfigEnabled('validation', $container, $config['validation']), $this->readConfigEnabled('lock', $container, $config['lock'])); + $this->registerMessengerConfiguration($config['messenger'], $container, $loader, $this->readConfigEnabled('validation', $container, $config['validation']), $this->readConfigEnabled('lock', $container, $config['lock']) && ($config['lock']['resources']['default'] ?? false)); } else { $container->removeDefinition('console.command.messenger_consume_messages'); $container->removeDefinition('console.command.messenger_stats'); From d12048430640bb2c83accae64a2cb38ea784adea Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 14 May 2025 12:40:11 +0200 Subject: [PATCH 15/57] normalize string values to a single ExposeSecurityLevel instance --- .../SecurityBundle/DependencyInjection/MainConfiguration.php | 2 +- .../Tests/DependencyInjection/MainConfigurationTest.php | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index 9b7414de5e532..2b31b70a208bb 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -76,7 +76,7 @@ public function getConfigTreeBuilder(): TreeBuilder ->setDeprecated('symfony/security-bundle', '7.3', 'The "%node%" option is deprecated and will be removed in 8.0. Use the "expose_security_errors" option instead.') ->end() ->enumNode('expose_security_errors') - ->beforeNormalization()->ifString()->then(fn ($v) => ['value' => ExposeSecurityLevel::tryFrom($v)])->end() + ->beforeNormalization()->ifString()->then(fn ($v) => ExposeSecurityLevel::tryFrom($v))->end() ->values(ExposeSecurityLevel::cases()) ->defaultValue(ExposeSecurityLevel::None) ->end() diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php index 6479e56a668e7..926abc5c7731c 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php @@ -254,6 +254,9 @@ public static function provideHideUserNotFoundData(): iterable yield [['expose_security_errors' => ExposeSecurityLevel::None], ExposeSecurityLevel::None]; yield [['expose_security_errors' => ExposeSecurityLevel::AccountStatus], ExposeSecurityLevel::AccountStatus]; yield [['expose_security_errors' => ExposeSecurityLevel::All], ExposeSecurityLevel::All]; + yield [['expose_security_errors' => 'none'], ExposeSecurityLevel::None]; + yield [['expose_security_errors' => 'account_status'], ExposeSecurityLevel::AccountStatus]; + yield [['expose_security_errors' => 'all'], ExposeSecurityLevel::All]; } /** From 752b41de7450a2575937f2c70c9477e82eef2c25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Tue, 13 May 2025 23:01:05 +0200 Subject: [PATCH 16/57] [TwigBundle] Improve error when autoconfiguring a class with both ExtensionInterface and Twig callable attribute --- .../Compiler/AttributeExtensionPass.php | 11 +++ .../Functional/AttributeExtensionTest.php | 76 +++++++++++++++---- 2 files changed, 72 insertions(+), 15 deletions(-) diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/AttributeExtensionPass.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/AttributeExtensionPass.php index 24f760802bc94..354874866a0ae 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/AttributeExtensionPass.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/AttributeExtensionPass.php @@ -14,10 +14,13 @@ use Symfony\Component\DependencyInjection\ChildDefinition; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\LogicException; use Twig\Attribute\AsTwigFilter; use Twig\Attribute\AsTwigFunction; use Twig\Attribute\AsTwigTest; +use Twig\Extension\AbstractExtension; use Twig\Extension\AttributeExtension; +use Twig\Extension\ExtensionInterface; /** * Register an instance of AttributeExtension for each service using the @@ -33,6 +36,14 @@ final class AttributeExtensionPass implements CompilerPassInterface public static function autoconfigureFromAttribute(ChildDefinition $definition, AsTwigFilter|AsTwigFunction|AsTwigTest $attribute, \ReflectionMethod $reflector): void { + $class = $reflector->getDeclaringClass(); + if ($class->implementsInterface(ExtensionInterface::class)) { + if ($class->isSubclassOf(AbstractExtension::class)) { + throw new LogicException(\sprintf('The class "%s" cannot extend "%s" and use the "#[%s]" attribute on method "%s()", choose one or the other.', $class->name, AbstractExtension::class, $attribute::class, $reflector->name)); + } + throw new LogicException(\sprintf('The class "%s" cannot implement "%s" and use the "#[%s]" attribute on method "%s()", choose one or the other.', $class->name, ExtensionInterface::class, $attribute::class, $reflector->name)); + } + $definition->addTag(self::TAG); // The service must be tagged as a runtime to call non-static methods diff --git a/src/Symfony/Bundle/TwigBundle/Tests/Functional/AttributeExtensionTest.php b/src/Symfony/Bundle/TwigBundle/Tests/Functional/AttributeExtensionTest.php index 81ce2cbe97bca..8b4e4555f36a0 100644 --- a/src/Symfony/Bundle/TwigBundle/Tests/Functional/AttributeExtensionTest.php +++ b/src/Symfony/Bundle/TwigBundle/Tests/Functional/AttributeExtensionTest.php @@ -11,11 +11,15 @@ namespace Symfony\Bundle\TwigBundle\Tests\Functional; +use PHPUnit\Framework\Attributes\After; +use PHPUnit\Framework\Attributes\Before; +use PHPUnit\Framework\Attributes\BeforeClass; use Symfony\Bundle\FrameworkBundle\FrameworkBundle; use Symfony\Bundle\TwigBundle\Tests\TestCase; use Symfony\Bundle\TwigBundle\TwigBundle; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\LogicException; use Symfony\Component\Filesystem\Filesystem; use Symfony\Component\HttpKernel\Kernel; use Twig\Attribute\AsTwigFilter; @@ -23,23 +27,23 @@ use Twig\Attribute\AsTwigTest; use Twig\Environment; use Twig\Error\RuntimeError; +use Twig\Extension\AbstractExtension; use Twig\Extension\AttributeExtension; class AttributeExtensionTest extends TestCase { - public function testExtensionWithAttributes() + /** @beforeClass */ + #[BeforeClass] + public static function assertTwigVersion(): void { if (!class_exists(AttributeExtension::class)) { self::markTestSkipped('Twig 3.21 is required.'); } + } - $kernel = new class('test', true) extends Kernel - { - public function registerBundles(): iterable - { - return [new FrameworkBundle(), new TwigBundle()]; - } - + public function testExtensionWithAttributes() + { + $kernel = new class extends AttributeExtensionKernel { public function registerContainerConfiguration(LoaderInterface $loader): void { $loader->load(static function (ContainerBuilder $container) { @@ -53,11 +57,6 @@ public function registerContainerConfiguration(LoaderInterface $loader): void $container->setAlias('twig_test', 'twig')->setPublic(true); }); } - - public function getProjectDir(): string - { - return sys_get_temp_dir().'/'.Kernel::VERSION.'/AttributeExtension'; - } }; $kernel->boot(); @@ -73,10 +72,30 @@ public function getProjectDir(): string $twig->getRuntime(StaticExtensionWithAttributes::class); } + public function testInvalidExtensionClass() + { + $kernel = new class extends AttributeExtensionKernel { + public function registerContainerConfiguration(LoaderInterface $loader): void + { + $loader->load(static function (ContainerBuilder $container) { + $container->register(InvalidExtensionWithAttributes::class, InvalidExtensionWithAttributes::class) + ->setAutoconfigured(true); + }); + } + }; + + $this->expectException(LogicException::class); + $this->expectExceptionMessage('The class "Symfony\Bundle\TwigBundle\Tests\Functional\InvalidExtensionWithAttributes" cannot extend "Twig\Extension\AbstractExtension" and use the "#[Twig\Attribute\AsTwigFilter]" attribute on method "funFilter()", choose one or the other.'); + + $kernel->boot(); + } + + /** * @before * @after */ + #[Before, After] protected function deleteTempDir() { if (file_exists($dir = sys_get_temp_dir().'/'.Kernel::VERSION.'/AttributeExtension')) { @@ -85,6 +104,24 @@ protected function deleteTempDir() } } +abstract class AttributeExtensionKernel extends Kernel +{ + public function __construct() + { + parent::__construct('test', true); + } + + public function registerBundles(): iterable + { + return [new FrameworkBundle(), new TwigBundle()]; + } + + public function getProjectDir(): string + { + return sys_get_temp_dir().'/'.Kernel::VERSION.'/AttributeExtension'; + } +} + class StaticExtensionWithAttributes { #[AsTwigFilter('foo')] @@ -112,10 +149,19 @@ public function __construct(private bool $prefix) { } - #[AsTwigFilter('foo')] - #[AsTwigFunction('foo')] + #[AsTwigFilter('prefix_foo')] + #[AsTwigFunction('prefix_foo')] public function prefix(string $value): string { return $this->prefix.$value; } } + +class InvalidExtensionWithAttributes extends AbstractExtension +{ + #[AsTwigFilter('fun')] + public function funFilter(): string + { + return 'fun'; + } +} From 0c71a93e0bfc29e2dd47c785843ffa7a5406cc0c Mon Sep 17 00:00:00 2001 From: Vladimir Pakhomchik Date: Wed, 14 May 2025 12:41:00 +0200 Subject: [PATCH 17/57] Fixed lazy-loading ghost objects generation with property hooks with default values. --- .../Component/VarExporter/ProxyHelper.php | 2 +- .../LazyProxy/HookedWithDefaultValue.php | 16 +++++++++++++--- .../VarExporter/Tests/LazyGhostTraitTest.php | 12 +++++++++--- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/VarExporter/ProxyHelper.php b/src/Symfony/Component/VarExporter/ProxyHelper.php index e3a38b14a139b..862e0332a0ff8 100644 --- a/src/Symfony/Component/VarExporter/ProxyHelper.php +++ b/src/Symfony/Component/VarExporter/ProxyHelper.php @@ -80,7 +80,7 @@ public static function generateLazyGhost(\ReflectionClass $class): string .($p->isProtected() ? 'protected' : 'public') .($p->isProtectedSet() ? ' protected(set)' : '') ." {$type} \${$name}" - .($p->hasDefaultValue() ? ' = '.$p->getDefaultValue() : '') + .($p->hasDefaultValue() ? ' = '.VarExporter::export($p->getDefaultValue()) : '') ." {\n"; foreach ($p->getHooks() as $hook => $method) { diff --git a/src/Symfony/Component/VarExporter/Tests/Fixtures/LazyProxy/HookedWithDefaultValue.php b/src/Symfony/Component/VarExporter/Tests/Fixtures/LazyProxy/HookedWithDefaultValue.php index 1281109e7228d..7d49049ac449a 100644 --- a/src/Symfony/Component/VarExporter/Tests/Fixtures/LazyProxy/HookedWithDefaultValue.php +++ b/src/Symfony/Component/VarExporter/Tests/Fixtures/LazyProxy/HookedWithDefaultValue.php @@ -4,8 +4,18 @@ class HookedWithDefaultValue { - public int $backedWithDefault = 321 { - get => $this->backedWithDefault; - set => $this->backedWithDefault = $value; + public int $backedIntWithDefault = 321 { + get => $this->backedIntWithDefault; + set => $this->backedIntWithDefault = $value; + } + + public string $backedStringWithDefault = '321' { + get => $this->backedStringWithDefault; + set => $this->backedStringWithDefault = $value; + } + + public bool $backedBoolWithDefault = false { + get => $this->backedBoolWithDefault; + set => $this->backedBoolWithDefault = $value; } } diff --git a/src/Symfony/Component/VarExporter/Tests/LazyGhostTraitTest.php b/src/Symfony/Component/VarExporter/Tests/LazyGhostTraitTest.php index 3f7513c270b5f..a80c007b53c87 100644 --- a/src/Symfony/Component/VarExporter/Tests/LazyGhostTraitTest.php +++ b/src/Symfony/Component/VarExporter/Tests/LazyGhostTraitTest.php @@ -516,16 +516,22 @@ public function testPropertyHooksWithDefaultValue() $initialized = true; }); - $this->assertSame(321, $object->backedWithDefault); + $this->assertSame(321, $object->backedIntWithDefault); + $this->assertSame('321', $object->backedStringWithDefault); + $this->assertSame(false, $object->backedBoolWithDefault); $this->assertTrue($initialized); $initialized = false; $object = $this->createLazyGhost(HookedWithDefaultValue::class, function ($instance) use (&$initialized) { $initialized = true; }); - $object->backedWithDefault = 654; + $object->backedIntWithDefault = 654; + $object->backedStringWithDefault = '654'; + $object->backedBoolWithDefault = true; $this->assertTrue($initialized); - $this->assertSame(654, $object->backedWithDefault); + $this->assertSame(654, $object->backedIntWithDefault); + $this->assertSame('654', $object->backedStringWithDefault); + $this->assertSame(true, $object->backedBoolWithDefault); } /** From 7dbe4bd2fc1b0351aad66feb04402395952e3941 Mon Sep 17 00:00:00 2001 From: Lauris Binde Date: Tue, 13 May 2025 18:57:21 +0200 Subject: [PATCH 18/57] [Validator] Review Latvian translations --- .../Validator/Resources/translations/validators.lv.xlf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf index db61de4f486d5..d16d43bf8a7e6 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf @@ -468,11 +468,11 @@ This value is not a valid slug. - Šī vērtība nav derīgs slug. + Šī vērtība nav derīgs URL slug. This value is not a valid Twig template. - This value is not a valid Twig template. + Šī vērtība nav derīgs Twig šablons. From f758e2677a619333c064bd7de4a7054606d2c0cf Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 15 May 2025 09:08:55 +0200 Subject: [PATCH 19/57] forbid to use "hide_user_not_found" and "expose_security_errors" at the same time "hide_user_not_found" will not have any effect if "expose_security_errors" is set. Throwing an exception early will improve DX and avoid WTF moments where one might be wondering why the "hide_user_not_found" option doesn't change anything. --- .../DependencyInjection/MainConfiguration.php | 4 ++++ .../DependencyInjection/MainConfigurationTest.php | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index 2b31b70a208bb..0a2d32c9f3f4d 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -59,6 +59,10 @@ public function getConfigTreeBuilder(): TreeBuilder ->beforeNormalization() ->always() ->then(function ($v) { + if (isset($v['hide_user_not_found']) && isset($v['expose_security_errors'])) { + throw new InvalidConfigurationException('You cannot use both "hide_user_not_found" and "expose_security_errors" at the same time.'); + } + if (isset($v['hide_user_not_found']) && !isset($v['expose_security_errors'])) { $v['expose_security_errors'] = $v['hide_user_not_found'] ? ExposeSecurityLevel::None : ExposeSecurityLevel::All; } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php index 926abc5c7731c..6904a21b18113 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/MainConfigurationTest.php @@ -283,4 +283,18 @@ public static function provideHideUserNotFoundLegacyData(): iterable yield [['hide_user_not_found' => true], ExposeSecurityLevel::None, true]; yield [['hide_user_not_found' => false], ExposeSecurityLevel::All, false]; } + + public function testCannotUseHideUserNotFoundAndExposeSecurityErrorsAtTheSameTime() + { + $processor = new Processor(); + $configuration = new MainConfiguration([], []); + + $this->expectException(InvalidConfigurationException::class); + $this->expectExceptionMessage('You cannot use both "hide_user_not_found" and "expose_security_errors" at the same time.'); + + $processor->processConfiguration($configuration, [static::$minimalConfig + [ + 'hide_user_not_found' => true, + 'expose_security_errors' => ExposeSecurityLevel::None, + ]]); + } } From 6174d091cc605e6e0c1770e41bc89304f4eb130f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 15 May 2025 15:18:10 +0200 Subject: [PATCH 20/57] [DependencyInjection] Fix missing binding for ServiceCollectionInterface when declaring a service subscriber --- .../Compiler/RegisterServiceSubscribersPass.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php b/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php index 87470c39894e4..89b822bc53b44 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php @@ -20,6 +20,7 @@ use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\TypedReference; use Symfony\Contracts\Service\Attribute\SubscribedService; +use Symfony\Contracts\Service\ServiceCollectionInterface; use Symfony\Contracts\Service\ServiceProviderInterface; use Symfony\Contracts\Service\ServiceSubscriberInterface; @@ -134,6 +135,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed $value->setBindings([ PsrContainerInterface::class => new BoundArgument($locatorRef, false), ServiceProviderInterface::class => new BoundArgument($locatorRef, false), + ServiceCollectionInterface::class => new BoundArgument($locatorRef, false), ] + $value->getBindings()); return parent::processValue($value); From fc10d48fdf6598e491bbb256ed990cd5f8f9e452 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 15 May 2025 17:29:37 +0200 Subject: [PATCH 21/57] [WebLink] Hint that prerender is deprecated --- src/Symfony/Bridge/Twig/Extension/WebLinkExtension.php | 8 ++++++-- src/Symfony/Component/WebLink/Link.php | 6 ++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Extension/WebLinkExtension.php b/src/Symfony/Bridge/Twig/Extension/WebLinkExtension.php index 11eca517c5d69..c8640a4ea5f00 100644 --- a/src/Symfony/Bridge/Twig/Extension/WebLinkExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/WebLinkExtension.php @@ -46,7 +46,7 @@ public function getFunctions(): array /** * Adds a "Link" HTTP header. * - * @param string $rel The relation type (e.g. "preload", "prefetch", "prerender" or "dns-prefetch") + * @param string $rel The relation type (e.g. "preload", "prefetch", or "dns-prefetch") * @param array $attributes The attributes of this link (e.g. "['as' => true]", "['pr' => 0.5]") * * @return string The relation URI @@ -117,7 +117,11 @@ public function prefetch(string $uri, array $attributes = []): string } /** - * Indicates to the client that it should prerender this resource . + * Indicates to the client that it should prerender this resource. + * + * This feature is deprecated and superseded by the Speculation Rules API. + * + * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/prerender * * @param array $attributes The attributes of this link (e.g. "['as' => true]", "['pr' => 0.5]") * diff --git a/src/Symfony/Component/WebLink/Link.php b/src/Symfony/Component/WebLink/Link.php index 5eab61346e925..ebad518efb170 100644 --- a/src/Symfony/Component/WebLink/Link.php +++ b/src/Symfony/Component/WebLink/Link.php @@ -98,6 +98,12 @@ class Link implements EvolvableLinkInterface public const REL_PREDECESSOR_VERSION = 'predecessor-version'; public const REL_PREFETCH = 'prefetch'; public const REL_PRELOAD = 'preload'; + + /** + * This feature is deprecated and superseded by the Speculation Rules API. + * + * @see https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Attributes/rel/prerender + */ public const REL_PRERENDER = 'prerender'; public const REL_PREV = 'prev'; public const REL_PREVIEW = 'preview'; From 193b69c18a66858981b42b68b7691237aabacc0b Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 16 May 2025 10:43:03 +0200 Subject: [PATCH 22/57] simplify Webhook constraint --- src/Symfony/Component/Notifier/Bridge/Smsbox/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Notifier/Bridge/Smsbox/composer.json b/src/Symfony/Component/Notifier/Bridge/Smsbox/composer.json index 259fb81e9bcae..0b1907fb71f15 100644 --- a/src/Symfony/Component/Notifier/Bridge/Smsbox/composer.json +++ b/src/Symfony/Component/Notifier/Bridge/Smsbox/composer.json @@ -31,7 +31,7 @@ "symfony/polyfill-php83": "^1.28" }, "require-dev": { - "symfony/webhook": "^6.4|^7.0|^7.2" + "symfony/webhook": "^6.4|^7.0" }, "autoload": { "psr-4": { From d51f563ed3c0d6029c2219620e91fb4cf3088b1d Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 15 May 2025 09:25:30 +0200 Subject: [PATCH 23/57] let the SlugValidator accept AsciiSlugger results --- .../Component/Validator/Constraints/Slug.php | 2 +- .../Tests/Constraints/SlugValidatorTest.php | 19 ++++++++++++++++--- src/Symfony/Component/Validator/composer.json | 1 + 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/Slug.php b/src/Symfony/Component/Validator/Constraints/Slug.php index 52a5d94c2d93b..55d847ccb618b 100644 --- a/src/Symfony/Component/Validator/Constraints/Slug.php +++ b/src/Symfony/Component/Validator/Constraints/Slug.php @@ -25,7 +25,7 @@ class Slug extends Constraint public const NOT_SLUG_ERROR = '14e6df1e-c8ab-4395-b6ce-04b132a3765e'; public string $message = 'This value is not a valid slug.'; - public string $regex = '/^[a-z0-9]+(?:-[a-z0-9]+)*$/'; + public string $regex = '/^[a-z0-9]+(?:-[a-z0-9]+)*$/i'; #[HasNamedArguments] public function __construct( diff --git a/src/Symfony/Component/Validator/Tests/Constraints/SlugValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/SlugValidatorTest.php index e8d210b8377e3..f88bff3e167ef 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/SlugValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/SlugValidatorTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Validator\Tests\Constraints; +use Symfony\Component\String\Slugger\AsciiSlugger; use Symfony\Component\Validator\Constraints\Slug; use Symfony\Component\Validator\Constraints\SlugValidator; use Symfony\Component\Validator\Exception\UnexpectedValueException; @@ -47,6 +48,7 @@ public function testExpectsStringCompatibleType() * @testWith ["test-slug"] * ["slug-123-test"] * ["slug"] + * ["TestSlug"] */ public function testValidSlugs($slug) { @@ -56,8 +58,7 @@ public function testValidSlugs($slug) } /** - * @testWith ["NotASlug"] - * ["Not a slug"] + * @testWith ["Not a slug"] * ["not-á-slug"] * ["not-@-slug"] */ @@ -91,7 +92,7 @@ public function testCustomRegexInvalidSlugs($slug) /** * @testWith ["slug"] - * @testWith ["test1234"] + * ["test1234"] */ public function testCustomRegexValidSlugs($slug) { @@ -101,4 +102,16 @@ public function testCustomRegexValidSlugs($slug) $this->assertNoViolation(); } + + /** + * @testWith ["PHP"] + * ["Symfony is cool"] + * ["Lorem ipsum dolor sit amet"] + */ + public function testAcceptAsciiSluggerResults(string $text) + { + $this->validator->validate((new AsciiSlugger())->slug($text), new Slug()); + + $this->assertNoViolation(); + } } diff --git a/src/Symfony/Component/Validator/composer.json b/src/Symfony/Component/Validator/composer.json index 5177d37d2955a..0eaac5f6bf735 100644 --- a/src/Symfony/Component/Validator/composer.json +++ b/src/Symfony/Component/Validator/composer.json @@ -38,6 +38,7 @@ "symfony/mime": "^6.4|^7.0", "symfony/property-access": "^6.4|^7.0", "symfony/property-info": "^6.4|^7.0", + "symfony/string": "^6.4|^7.0", "symfony/translation": "^6.4.3|^7.0.3", "symfony/type-info": "^7.1", "egulias/email-validator": "^2.1.10|^3|^4" From 85ef2a31d4e4afaa1e7240d1d8639c0ec351c0be Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 16 May 2025 11:31:49 +0200 Subject: [PATCH 24/57] add test for DatePointType converting database string to PHP value --- .../Bridge/Doctrine/Tests/Types/DatePointTypeTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Types/DatePointTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Types/DatePointTypeTest.php index 6900de3f168b9..84b265ed6502c 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Types/DatePointTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Types/DatePointTypeTest.php @@ -76,6 +76,14 @@ public function testDateTimeImmutableConvertsToPHPValue() $this->assertSame($expected->format($format), $actual->format($format)); } + public function testDatabaseValueConvertsToPHPValue() + { + $actual = $this->type->convertToPHPValue('2025-03-03 12:13:14', new PostgreSQLPlatform()); + + $this->assertInstanceOf(DatePoint::class, $actual); + $this->assertSame('2025-03-03 12:13:14', $actual->format('Y-m-d H:i:s')); + } + public function testGetName() { $this->assertSame('date_point', $this->type->getName()); From 88b322e144d380f61e0182a242e6e2a4efdcb9d7 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 16 May 2025 15:57:08 +0200 Subject: [PATCH 25/57] [FrameworkBundle] Fix declaring fiel-attr tags in xml config files --- .../DependencyInjection/Configuration.php | 1 + .../Resources/config/schema/symfony-1.0.xsd | 2 +- .../Fixtures/php/form_csrf_field_attr.php | 22 +++++++++++++++++++ ...ield_name.xml => form_csrf_field_attr.xml} | 8 ++++++- .../form_csrf_under_form_sets_field_name.xml | 15 ------------- .../Fixtures/yml/form_csrf_field_attr.yml | 16 ++++++++++++++ .../FrameworkExtensionTestCase.php | 11 ++++++++++ 7 files changed, 58 insertions(+), 17 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/form_csrf_field_attr.php rename src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/{form_csrf_sets_field_name.xml => form_csrf_field_attr.xml} (67%) delete mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/form_csrf_under_form_sets_field_name.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/form_csrf_field_attr.yml diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 50c093f28f17e..5154393f2769e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -252,6 +252,7 @@ private function addFormSection(ArrayNodeDefinition $rootNode, callable $enableI ->arrayNode('field_attr') ->performNoDeepMerging() ->normalizeKeys(false) + ->useAttributeAsKey('name') ->scalarPrototype()->end() ->defaultValue(['data-controller' => 'csrf-protection']) ->end() diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index 491cd1e4ffb7c..e99022acf7c45 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -79,7 +79,7 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/form_csrf_field_attr.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/form_csrf_field_attr.php new file mode 100644 index 0000000000000..103ee4797a1b8 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/form_csrf_field_attr.php @@ -0,0 +1,22 @@ +loadFromExtension('framework', [ + 'annotations' => false, + 'http_method_override' => false, + 'handle_all_throwables' => true, + 'php_errors' => ['log' => true], + 'csrf_protection' => [ + 'enabled' => true, + ], + 'form' => [ + 'csrf_protection' => [ + 'field-attr' => [ + 'data-foo' => 'bar', + 'data-bar' => 'baz', + ], + ], + ], + 'session' => [ + 'storage_factory_id' => 'session.storage.factory.native', + ], +]); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/form_csrf_sets_field_name.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/form_csrf_field_attr.xml similarity index 67% rename from src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/form_csrf_sets_field_name.xml rename to src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/form_csrf_field_attr.xml index 4a05e9d33294e..1889703bec2a9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/form_csrf_sets_field_name.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/form_csrf_field_attr.xml @@ -9,7 +9,13 @@ - + + + + bar + baz + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/form_csrf_under_form_sets_field_name.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/form_csrf_under_form_sets_field_name.xml deleted file mode 100644 index 09ef0ee167eb4..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/form_csrf_under_form_sets_field_name.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/form_csrf_field_attr.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/form_csrf_field_attr.yml new file mode 100644 index 0000000000000..db519977548c4 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/form_csrf_field_attr.yml @@ -0,0 +1,16 @@ +framework: + annotations: false + http_method_override: false + handle_all_throwables: true + php_errors: + log: true + csrf_protection: + enabled: true + form: + csrf_protection: + enabled: true + field_attr: + data-foo: bar + data-bar: baz + session: + storage_factory_id: session.storage.factory.native diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php index 7bf66512d2b2b..655f9180eceb2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php @@ -1413,6 +1413,17 @@ public function testFormsCanBeEnabledWithoutCsrfProtection() $this->assertFalse($container->getParameter('form.type_extension.csrf.enabled')); } + public function testFormCsrfFieldAttr() + { + $container = $this->createContainerFromFile('form_csrf_field_attr'); + + $expected = [ + 'data-foo' => 'bar', + 'data-bar' => 'baz', + ]; + $this->assertSame($expected, $container->getParameter('form.type_extension.csrf.field_attr')); + } + public function testStopwatchEnabledWithDebugModeEnabled() { $container = $this->createContainerFromFile('default_config', [ From 72171c0543e3e84b70e6bc0ff1ef6373f254c917 Mon Sep 17 00:00:00 2001 From: matlec Date: Wed, 14 May 2025 19:55:19 +0200 Subject: [PATCH 26/57] [DependencyInjection] Make `DefinitionErrorExceptionPass` consider `IGNORE_ON_UNINITIALIZED_REFERENCE` and `RUNTIME_EXCEPTION_ON_INVALID_REFERENCE` the same --- .../Compiler/DefinitionErrorExceptionPass.php | 5 ++++- .../Tests/Compiler/DefinitionErrorExceptionPassTest.php | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/DefinitionErrorExceptionPass.php b/src/Symfony/Component/DependencyInjection/Compiler/DefinitionErrorExceptionPass.php index b6a2cf907ee9b..204401cd2c8ee 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/DefinitionErrorExceptionPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/DefinitionErrorExceptionPass.php @@ -65,7 +65,10 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed } if ($value instanceof Reference && $this->currentId !== $targetId = (string) $value) { - if (ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE === $value->getInvalidBehavior()) { + if ( + ContainerInterface::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE === $value->getInvalidBehavior() + || ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $value->getInvalidBehavior() + ) { $this->sourceReferences[$targetId][$this->currentId] ??= true; } else { $this->sourceReferences[$targetId][$this->currentId] = false; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/DefinitionErrorExceptionPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/DefinitionErrorExceptionPassTest.php index 9ab5c27fcf763..5ed7be315114a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/DefinitionErrorExceptionPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/DefinitionErrorExceptionPassTest.php @@ -64,6 +64,9 @@ public function testSkipNestedErrors() $container->register('foo', 'stdClass') ->addArgument(new Reference('bar', ContainerBuilder::RUNTIME_EXCEPTION_ON_INVALID_REFERENCE)); + $container->register('baz', 'stdClass') + ->addArgument(new Reference('bar', ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE)); + $pass = new DefinitionErrorExceptionPass(); $pass->process($container); From 032a5770d623448300ea2a0768b2c5841b1c8a30 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 17 May 2025 18:06:41 +0200 Subject: [PATCH 27/57] Provide missing translations thanks to Gemini --- .../Validator/Resources/translations/validators.af.xlf | 2 +- .../Validator/Resources/translations/validators.ar.xlf | 2 +- .../Validator/Resources/translations/validators.az.xlf | 2 +- .../Validator/Resources/translations/validators.be.xlf | 2 +- .../Validator/Resources/translations/validators.bg.xlf | 2 +- .../Validator/Resources/translations/validators.bs.xlf | 2 +- .../Validator/Resources/translations/validators.ca.xlf | 2 +- .../Validator/Resources/translations/validators.cs.xlf | 2 +- .../Validator/Resources/translations/validators.cy.xlf | 2 +- .../Validator/Resources/translations/validators.da.xlf | 2 +- .../Validator/Resources/translations/validators.el.xlf | 2 +- .../Validator/Resources/translations/validators.es.xlf | 2 +- .../Validator/Resources/translations/validators.et.xlf | 2 +- .../Validator/Resources/translations/validators.eu.xlf | 2 +- .../Validator/Resources/translations/validators.fa.xlf | 2 +- .../Validator/Resources/translations/validators.fi.xlf | 2 +- .../Validator/Resources/translations/validators.fr.xlf | 2 +- .../Validator/Resources/translations/validators.gl.xlf | 2 +- .../Validator/Resources/translations/validators.he.xlf | 2 +- .../Validator/Resources/translations/validators.hr.xlf | 2 +- .../Validator/Resources/translations/validators.hu.xlf | 2 +- .../Validator/Resources/translations/validators.hy.xlf | 2 +- .../Validator/Resources/translations/validators.id.xlf | 2 +- .../Validator/Resources/translations/validators.it.xlf | 2 +- .../Validator/Resources/translations/validators.ja.xlf | 2 +- .../Validator/Resources/translations/validators.lb.xlf | 2 +- .../Validator/Resources/translations/validators.lt.xlf | 2 +- .../Validator/Resources/translations/validators.mk.xlf | 2 +- .../Validator/Resources/translations/validators.mn.xlf | 2 +- .../Validator/Resources/translations/validators.my.xlf | 2 +- .../Validator/Resources/translations/validators.nb.xlf | 2 +- .../Validator/Resources/translations/validators.nl.xlf | 2 +- .../Validator/Resources/translations/validators.nn.xlf | 2 +- .../Validator/Resources/translations/validators.no.xlf | 2 +- .../Validator/Resources/translations/validators.pt.xlf | 2 +- .../Validator/Resources/translations/validators.pt_BR.xlf | 2 +- .../Validator/Resources/translations/validators.ro.xlf | 2 +- .../Validator/Resources/translations/validators.ru.xlf | 2 +- .../Validator/Resources/translations/validators.sk.xlf | 2 +- .../Validator/Resources/translations/validators.sl.xlf | 2 +- .../Validator/Resources/translations/validators.sq.xlf | 2 +- .../Validator/Resources/translations/validators.sr_Cyrl.xlf | 2 +- .../Validator/Resources/translations/validators.sr_Latn.xlf | 2 +- .../Validator/Resources/translations/validators.sv.xlf | 2 +- .../Validator/Resources/translations/validators.th.xlf | 2 +- .../Validator/Resources/translations/validators.tl.xlf | 2 +- .../Validator/Resources/translations/validators.tr.xlf | 2 +- .../Validator/Resources/translations/validators.uk.xlf | 2 +- .../Validator/Resources/translations/validators.ur.xlf | 2 +- .../Validator/Resources/translations/validators.uz.xlf | 2 +- .../Validator/Resources/translations/validators.vi.xlf | 2 +- .../Validator/Resources/translations/validators.zh_CN.xlf | 2 +- .../Validator/Resources/translations/validators.zh_TW.xlf | 2 +- 53 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf index de23860799dc6..270f85355e82f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Hierdie waarde is nie 'n geldige Twig-sjabloon nie. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf index f1792bb427644..8e068ef17429d 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + هذه القيمة ليست نموذج Twig صالح. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf index ab15702b6f30a..8721507fbe97b 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Bu dəyər etibarlı Twig şablonu deyil. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf index 5f4448d1b433e..aa0e67bd8c2fc 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Гэта значэнне не з'яўляецца сапраўдным шаблонам Twig. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf index 333187eef9826..4717830d50925 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Тази стойност не е валиден Twig шаблон. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.bs.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.bs.xlf index e27274a36f216..46a6aa049e04a 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.bs.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.bs.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Ova vrijednost nije važeći Twig šablon. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf index 5506b4672974b..15d047c31a9fc 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Aquest valor no és una plantilla Twig vàlida. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf index 87a03badd9f15..c4fd950203c21 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Tato hodnota není platná šablona Twig. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf index 98e481b67b70d..0fc87d313fbe2 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Nid yw'r gwerth hwn yn dempled Twig dilys. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.da.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.da.xlf index 976ee850e4325..eabf4450f34f5 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.da.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.da.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Denne værdi er ikke en gyldig Twig-skabelon. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf index fe490aacddb40..d8298f530b58d 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Αυτή η τιμή δεν είναι έγκυρο πρότυπο Twig. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf index 2bd3433990ded..b428fd8c19463 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Este valor no es una plantilla Twig válida. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf index 1317d41955a47..bbc0b5692b043 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + See väärtus ei ole kehtiv Twig'i mall. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.eu.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.eu.xlf index f92ab9638581f..d5be082cd4043 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.eu.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.eu.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Balio hau ez da Twig txantiloi baliozko bat. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf index 73a97fb3cae28..cc8b3d8f0a135 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + این مقدار یک قالب معتبر Twig نیست. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf index 044beb1c44cc4..714a7a08b81e8 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Tämä arvo ei ole kelvollinen Twig-malli. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf index 07953955b92d5..fe92eb2e76aef 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Cette valeur n'est pas un modèle Twig valide. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf index c85e942f36040..1b2303774119f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Este valor non é un modelo Twig válido. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.he.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.he.xlf index 8a985737485b4..ec792b699bdf5 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.he.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.he.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + ערך זה אינו תבנית Twig חוקית. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf index 10985f3df18a8..17a4c88f105b0 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Ova vrijednost nije valjani Twig predložak. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf index 2a3472dd94a2d..39e3acac818bc 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Ez az érték nem érvényes Twig sablon. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hy.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hy.xlf index 0c3953a27dc29..a1dbb93b419a3 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hy.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hy.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Այս արժեքը վավեր Twig ձևանմուշ չէ: diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf index 7c8a3c8dfb808..669a2afa5efd2 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Nilai ini bukan templat Twig yang valid. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf index 5258cf7d3ec7a..102cbc9beb7cd 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Questo valore non è un template Twig valido. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf index ae0e734b45c67..fe928e89604a0 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + この値は有効な Twig テンプレートではありません。 diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf index 2961aec0b0ef2..81bd7de6f717e 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Dëse Wäert ass kee valabelen Twig-Template. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf index 9c56c8377cdd8..f9e9f9e220d21 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Ši reikšmė nėra tinkamas „Twig“ šablonas. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.mk.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.mk.xlf index 7d9a63dbd7e36..6c39949aa1e09 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.mk.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.mk.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Оваа вредност не е валиден Twig шаблон. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.mn.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.mn.xlf index 222526fe24b19..b3ee44b43b417 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.mn.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.mn.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Энэ утга нь Twig-ийн хүчинтэй загвар биш юм. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.my.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.my.xlf index 90b6648acc594..e82ab3b19c8e1 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.my.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.my.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + ဤတန်ဖိုးသည် မှန်ကန်သော Twig တင်းပလိတ်မဟုတ်ပါ။ diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf index 0997c1af56a14..b0281532b4c61 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Denne verdien er ikke en gyldig Twig-mal. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf index 820bb69aae42e..10086869427df 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Deze waarde is geen geldige Twig-template. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nn.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nn.xlf index 6a36a1cc2571f..6cb8812b596f1 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nn.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nn.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Denne verdien er ikkje ein gyldig Twig-mal. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf index 0997c1af56a14..b0281532b4c61 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Denne verdien er ikke en gyldig Twig-mal. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf index 0d685d524cd69..5732702d7bcde 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Este valor não é um modelo Twig válido. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf index 3dbdd4ea2d675..a755b2363a314 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Este valor não é um modelo Twig válido. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf index bed709ceaf927..56d20634736e7 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Această valoare nu este un șablon Twig valid. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf index 5fc8d14d833ae..dff7ecbbb84c6 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Это значение не является допустимым шаблоном Twig. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf index 253b4cd8c37d1..c8d9d912a1750 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Táto hodnota nie je platná šablóna Twig. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf index 669d8e85d8a5c..b4cc222ad74d3 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Ta vrednost ni veljavna predloga Twig. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf index 1933143261af8..7ae80b937a37c 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf @@ -481,7 +481,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Kjo vlerë nuk është një shabllon Twig i vlefshëm. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf index d36e83ca62785..fa355e47664bc 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Ова вредност није важећи Twig шаблон. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf index ba9092a1c0c4c..61704f6eaaf12 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Ova vrednost nije važeći Twig šablon. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf index 8ed255071e270..c88ffc5823278 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Det här värdet är inte en giltig Twig-mall. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.th.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.th.xlf index de5008674af45..26371cd6a8bf7 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.th.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.th.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + ค่านี้ไม่ใช่เทมเพลต Twig ที่ถูกต้อง diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.tl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.tl.xlf index 310a7a20563ae..ef1e2ad845caf 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.tl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.tl.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Ang halagang ito ay hindi isang balidong Twig template. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf index 0bf57d80b7ca4..2cf33ab33c7af 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Bu değer geçerli bir Twig şablonu değil. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf index 2110eb48e7dfe..eb4a0db9ec6d0 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Це значення не є дійсним шаблоном Twig. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ur.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ur.xlf index 280b1488d2cf8..6a28566ca062e 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ur.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ur.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + یہ قدر ایک درست Twig سانچہ نہیں ہے۔ diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf index da07805f689c2..b54fee24a3cdf 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Bu qiymat yaroqli Twig shabloni emas. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf index 048be7f2c4336..8bc1e4c3e078d 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + Giá trị này không phải là một mẫu Twig hợp lệ. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf index 24a89c15b8b91..ff41473e1555e 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + 此值不是有效的 Twig 模板。 diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf index 783461efa4c7f..7c44889bf8724 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - This value is not a valid Twig template. + 此值不是有效的 Twig 模板。 From 388e97f48ef2a01010778a972ef5e2b723df043c Mon Sep 17 00:00:00 2001 From: Joseph Bielawski Date: Sat, 17 May 2025 18:49:07 +0200 Subject: [PATCH 28/57] Update Mailer Azure bridge API docs link --- src/Symfony/Component/Mailer/Bridge/Azure/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Mailer/Bridge/Azure/README.md b/src/Symfony/Component/Mailer/Bridge/Azure/README.md index acd9cc25abb53..36b81fccfa385 100644 --- a/src/Symfony/Component/Mailer/Bridge/Azure/README.md +++ b/src/Symfony/Component/Mailer/Bridge/Azure/README.md @@ -21,8 +21,8 @@ where: Resources --------- - * [Microsoft Azure (ACS) Email API Docs](https://learn.microsoft.com/en-us/rest/api/communication/dataplane/email/send) + * [Microsoft Azure (ACS) Email API Docs](https://learn.microsoft.com/en-us/rest/api/communication/email/email/send) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) - in the [main Symfony repository](https://github.com/symfony/symfony) \ No newline at end of file + in the [main Symfony repository](https://github.com/symfony/symfony) From 5789965374fc8052fd7448cfb0024250a1cfc820 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Mon, 19 May 2025 10:27:13 +0200 Subject: [PATCH 29/57] Revert Slug constraint This commit reverts #58542. --- src/Symfony/Component/Validator/CHANGELOG.md | 1 - .../Component/Validator/Constraints/Slug.php | 42 ------- .../Validator/Constraints/SlugValidator.php | 47 ------- .../Validator/Tests/Constraints/SlugTest.php | 47 ------- .../Tests/Constraints/SlugValidatorTest.php | 117 ------------------ 5 files changed, 254 deletions(-) delete mode 100644 src/Symfony/Component/Validator/Constraints/Slug.php delete mode 100644 src/Symfony/Component/Validator/Constraints/SlugValidator.php delete mode 100644 src/Symfony/Component/Validator/Tests/Constraints/SlugTest.php delete mode 100644 src/Symfony/Component/Validator/Tests/Constraints/SlugValidatorTest.php diff --git a/src/Symfony/Component/Validator/CHANGELOG.md b/src/Symfony/Component/Validator/CHANGELOG.md index ae1ae20da804d..a7363d7f59c19 100644 --- a/src/Symfony/Component/Validator/CHANGELOG.md +++ b/src/Symfony/Component/Validator/CHANGELOG.md @@ -8,7 +8,6 @@ CHANGELOG * Deprecate defining custom constraints not supporting named arguments * Deprecate passing an array of options to the constructors of the constraint classes, pass each option as a dedicated argument instead * Add support for ratio checks for SVG files to the `Image` constraint - * Add the `Slug` constraint * Add support for the `otherwise` option in the `When` constraint * Add support for multiple fields containing nested constraints in `Composite` constraints * Add the `stopOnFirstError` option to the `Unique` constraint to validate all elements diff --git a/src/Symfony/Component/Validator/Constraints/Slug.php b/src/Symfony/Component/Validator/Constraints/Slug.php deleted file mode 100644 index 55d847ccb618b..0000000000000 --- a/src/Symfony/Component/Validator/Constraints/Slug.php +++ /dev/null @@ -1,42 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Validator\Constraints; - -use Symfony\Component\Validator\Attribute\HasNamedArguments; -use Symfony\Component\Validator\Constraint; - -/** - * Validates that a value is a valid slug. - * - * @author Raffaele Carelle - */ -#[\Attribute(\Attribute::TARGET_PROPERTY | \Attribute::TARGET_METHOD | \Attribute::IS_REPEATABLE)] -class Slug extends Constraint -{ - public const NOT_SLUG_ERROR = '14e6df1e-c8ab-4395-b6ce-04b132a3765e'; - - public string $message = 'This value is not a valid slug.'; - public string $regex = '/^[a-z0-9]+(?:-[a-z0-9]+)*$/i'; - - #[HasNamedArguments] - public function __construct( - ?string $regex = null, - ?string $message = null, - ?array $groups = null, - mixed $payload = null, - ) { - parent::__construct([], $groups, $payload); - - $this->message = $message ?? $this->message; - $this->regex = $regex ?? $this->regex; - } -} diff --git a/src/Symfony/Component/Validator/Constraints/SlugValidator.php b/src/Symfony/Component/Validator/Constraints/SlugValidator.php deleted file mode 100644 index b914cad31b466..0000000000000 --- a/src/Symfony/Component/Validator/Constraints/SlugValidator.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Validator\Constraints; - -use Symfony\Component\Validator\Constraint; -use Symfony\Component\Validator\ConstraintValidator; -use Symfony\Component\Validator\Exception\UnexpectedTypeException; -use Symfony\Component\Validator\Exception\UnexpectedValueException; - -/** - * @author Raffaele Carelle - */ -class SlugValidator extends ConstraintValidator -{ - public function validate(mixed $value, Constraint $constraint): void - { - if (!$constraint instanceof Slug) { - throw new UnexpectedTypeException($constraint, Slug::class); - } - - if (null === $value || '' === $value) { - return; - } - - if (!\is_scalar($value) && !$value instanceof \Stringable) { - throw new UnexpectedValueException($value, 'string'); - } - - $value = (string) $value; - - if (0 === preg_match($constraint->regex, $value)) { - $this->context->buildViolation($constraint->message) - ->setParameter('{{ value }}', $this->formatValue($value)) - ->setCode(Slug::NOT_SLUG_ERROR) - ->addViolation(); - } - } -} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/SlugTest.php b/src/Symfony/Component/Validator/Tests/Constraints/SlugTest.php deleted file mode 100644 index a2c5b07d3f873..0000000000000 --- a/src/Symfony/Component/Validator/Tests/Constraints/SlugTest.php +++ /dev/null @@ -1,47 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Validator\Tests\Constraints; - -use PHPUnit\Framework\TestCase; -use Symfony\Component\Validator\Constraints\Slug; -use Symfony\Component\Validator\Mapping\ClassMetadata; -use Symfony\Component\Validator\Mapping\Loader\AttributeLoader; - -class SlugTest extends TestCase -{ - public function testAttributes() - { - $metadata = new ClassMetadata(SlugDummy::class); - $loader = new AttributeLoader(); - self::assertTrue($loader->loadClassMetadata($metadata)); - - [$bConstraint] = $metadata->properties['b']->getConstraints(); - self::assertSame('myMessage', $bConstraint->message); - self::assertSame(['Default', 'SlugDummy'], $bConstraint->groups); - - [$cConstraint] = $metadata->properties['c']->getConstraints(); - self::assertSame(['my_group'], $cConstraint->groups); - self::assertSame('some attached data', $cConstraint->payload); - } -} - -class SlugDummy -{ - #[Slug] - private $a; - - #[Slug(message: 'myMessage')] - private $b; - - #[Slug(groups: ['my_group'], payload: 'some attached data')] - private $c; -} diff --git a/src/Symfony/Component/Validator/Tests/Constraints/SlugValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/SlugValidatorTest.php deleted file mode 100644 index f88bff3e167ef..0000000000000 --- a/src/Symfony/Component/Validator/Tests/Constraints/SlugValidatorTest.php +++ /dev/null @@ -1,117 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Validator\Tests\Constraints; - -use Symfony\Component\String\Slugger\AsciiSlugger; -use Symfony\Component\Validator\Constraints\Slug; -use Symfony\Component\Validator\Constraints\SlugValidator; -use Symfony\Component\Validator\Exception\UnexpectedValueException; -use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; - -class SlugValidatorTest extends ConstraintValidatorTestCase -{ - protected function createValidator(): SlugValidator - { - return new SlugValidator(); - } - - public function testNullIsValid() - { - $this->validator->validate(null, new Slug()); - - $this->assertNoViolation(); - } - - public function testEmptyStringIsValid() - { - $this->validator->validate('', new Slug()); - - $this->assertNoViolation(); - } - - public function testExpectsStringCompatibleType() - { - $this->expectException(UnexpectedValueException::class); - $this->validator->validate(new \stdClass(), new Slug()); - } - - /** - * @testWith ["test-slug"] - * ["slug-123-test"] - * ["slug"] - * ["TestSlug"] - */ - public function testValidSlugs($slug) - { - $this->validator->validate($slug, new Slug()); - - $this->assertNoViolation(); - } - - /** - * @testWith ["Not a slug"] - * ["not-á-slug"] - * ["not-@-slug"] - */ - public function testInvalidSlugs($slug) - { - $constraint = new Slug(message: 'myMessage'); - - $this->validator->validate($slug, $constraint); - - $this->buildViolation('myMessage') - ->setParameter('{{ value }}', '"'.$slug.'"') - ->setCode(Slug::NOT_SLUG_ERROR) - ->assertRaised(); - } - - /** - * @testWith ["test-slug", true] - * ["slug-123-test", true] - */ - public function testCustomRegexInvalidSlugs($slug) - { - $constraint = new Slug(regex: '/^[a-z0-9]+$/i'); - - $this->validator->validate($slug, $constraint); - - $this->buildViolation($constraint->message) - ->setParameter('{{ value }}', '"'.$slug.'"') - ->setCode(Slug::NOT_SLUG_ERROR) - ->assertRaised(); - } - - /** - * @testWith ["slug"] - * ["test1234"] - */ - public function testCustomRegexValidSlugs($slug) - { - $constraint = new Slug(regex: '/^[a-z0-9]+$/i'); - - $this->validator->validate($slug, $constraint); - - $this->assertNoViolation(); - } - - /** - * @testWith ["PHP"] - * ["Symfony is cool"] - * ["Lorem ipsum dolor sit amet"] - */ - public function testAcceptAsciiSluggerResults(string $text) - { - $this->validator->validate((new AsciiSlugger())->slug($text), new Slug()); - - $this->assertNoViolation(); - } -} From 357e5f82f90885411015a9d00c5a3d7e98c54b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Mon, 19 May 2025 11:05:46 +0200 Subject: [PATCH 30/57] [Validator] Review "twig template" translation --- .../Validator/Resources/translations/validators.fr.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf index fe92eb2e76aef..6c45f32237b52 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - Cette valeur n'est pas un modèle Twig valide. + Cette valeur n'est pas un modèle Twig valide. From 4817c589724bdfde15ad4d97442dee8bd97b6d54 Mon Sep 17 00:00:00 2001 From: HypeMC Date: Mon, 19 May 2025 13:11:22 +0200 Subject: [PATCH 31/57] [Validator] Review Croatian translation --- .../Validator/Resources/translations/validators.hr.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf index 17a4c88f105b0..5b891d79f3ddd 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf @@ -472,7 +472,7 @@ This value is not a valid Twig template. - Ova vrijednost nije valjani Twig predložak. + Ova vrijednost nije valjani Twig predložak. From c29f02688f77b7908e2e2835e4dbe5d3bf711a77 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 19 May 2025 08:45:42 +0200 Subject: [PATCH 32/57] add missing $extensions and $extensionsMessage to the Image constraint --- .../Component/Validator/Constraints/Image.php | 14 +++- .../Tests/Constraints/ImageValidatorTest.php | 73 +++++++++++++++++++ 2 files changed, 84 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/Image.php b/src/Symfony/Component/Validator/Constraints/Image.php index 43590f4f2425c..8fafa5044f201 100644 --- a/src/Symfony/Component/Validator/Constraints/Image.php +++ b/src/Symfony/Component/Validator/Constraints/Image.php @@ -64,7 +64,7 @@ class Image extends File */ protected static $errorNames = self::ERROR_NAMES; - public $mimeTypes = 'image/*'; + public $mimeTypes; public $minWidth; public $maxWidth; public $maxHeight; @@ -140,7 +140,9 @@ public function __construct( ?string $allowPortraitMessage = null, ?string $corruptedMessage = null, ?array $groups = null, - mixed $payload = null + mixed $payload = null, + array|string|null $extensions = null, + ?string $extensionsMessage = null, ) { parent::__construct( $options, @@ -163,7 +165,9 @@ public function __construct( $uploadExtensionErrorMessage, $uploadErrorMessage, $groups, - $payload + $payload, + $extensions, + $extensionsMessage, ); $this->minWidth = $minWidth ?? $this->minWidth; @@ -192,6 +196,10 @@ public function __construct( $this->allowPortraitMessage = $allowPortraitMessage ?? $this->allowPortraitMessage; $this->corruptedMessage = $corruptedMessage ?? $this->corruptedMessage; + if (null === $this->mimeTypes && [] === $this->extensions) { + $this->mimeTypes = 'image/*'; + } + if (!\in_array('image/*', (array) $this->mimeTypes, true) && !\array_key_exists('mimeTypesMessage', $options ?? []) && null === $mimeTypesMessage) { $this->mimeTypesMessage = 'The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}.'; } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php index 3e646cfa39572..c8341e95f0176 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/ImageValidatorTest.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Validator\Tests\Constraints; +use Symfony\Component\HttpFoundation\File\File; +use Symfony\Component\Mime\MimeTypes; use Symfony\Component\Validator\Constraints\Image; use Symfony\Component\Validator\Constraints\ImageValidator; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; @@ -579,4 +581,75 @@ public static function provideInvalidMimeTypeWithNarrowedSet() ]), ]; } + + /** + * @dataProvider providerValidExtension + */ + public function testExtensionValid(string $name) + { + if (!class_exists(MimeTypes::class)) { + $this->markTestSkipped('Guessing the mime type is not possible'); + } + + $constraint = new Image(mimeTypes: [], extensions: ['gif'], extensionsMessage: 'myMessage'); + + $this->validator->validate(new File(__DIR__.'/Fixtures/'.$name), $constraint); + + $this->assertNoViolation(); + } + + public static function providerValidExtension(): iterable + { + yield ['test.gif']; + yield ['test.png.gif']; + } + + /** + * @dataProvider provideInvalidExtension + */ + public function testExtensionInvalid(string $name, string $extension) + { + $path = __DIR__.'/Fixtures/'.$name; + $constraint = new Image(extensions: ['png', 'svg'], extensionsMessage: 'myMessage'); + + $this->validator->validate(new File($path), $constraint); + + $this->buildViolation('myMessage') + ->setParameters([ + '{{ file }}' => '"'.$path.'"', + '{{ extension }}' => '"'.$extension.'"', + '{{ extensions }}' => '"png", "svg"', + '{{ name }}' => '"'.$name.'"', + ]) + ->setCode(Image::INVALID_EXTENSION_ERROR) + ->assertRaised(); + } + + public static function provideInvalidExtension(): iterable + { + yield ['test.gif', 'gif']; + yield ['test.png.gif', 'gif']; + } + + public function testExtensionAutodetectMimeTypesInvalid() + { + if (!class_exists(MimeTypes::class)) { + $this->markTestSkipped('Guessing the mime type is not possible'); + } + + $path = __DIR__.'/Fixtures/invalid-content.gif'; + $constraint = new Image(mimeTypesMessage: 'myMessage', extensions: ['gif']); + + $this->validator->validate(new File($path), $constraint); + + $this->buildViolation('myMessage') + ->setParameters([ + '{{ file }}' => '"'.$path.'"', + '{{ name }}' => '"invalid-content.gif"', + '{{ type }}' => '"text/plain"', + '{{ types }}' => '"image/gif"', + ]) + ->setCode(Image::INVALID_MIME_TYPE_ERROR) + ->assertRaised(); + } } From 42eb1c0b2fc37b643a86a8a3417cdbec26620ae6 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 20 May 2025 08:06:46 +0200 Subject: [PATCH 33/57] Remove translations for slug validation error --- .../Validator/Resources/translations/validators.af.xlf | 4 ---- .../Validator/Resources/translations/validators.ar.xlf | 4 ---- .../Validator/Resources/translations/validators.az.xlf | 4 ---- .../Validator/Resources/translations/validators.be.xlf | 4 ---- .../Validator/Resources/translations/validators.bg.xlf | 4 ---- .../Validator/Resources/translations/validators.bs.xlf | 4 ---- .../Validator/Resources/translations/validators.ca.xlf | 4 ---- .../Validator/Resources/translations/validators.cs.xlf | 4 ---- .../Validator/Resources/translations/validators.cy.xlf | 4 ---- .../Validator/Resources/translations/validators.da.xlf | 4 ---- .../Validator/Resources/translations/validators.de.xlf | 4 ---- .../Validator/Resources/translations/validators.el.xlf | 4 ---- .../Validator/Resources/translations/validators.en.xlf | 4 ---- .../Validator/Resources/translations/validators.es.xlf | 4 ---- .../Validator/Resources/translations/validators.et.xlf | 4 ---- .../Validator/Resources/translations/validators.eu.xlf | 4 ---- .../Validator/Resources/translations/validators.fa.xlf | 4 ---- .../Validator/Resources/translations/validators.fi.xlf | 4 ---- .../Validator/Resources/translations/validators.fr.xlf | 4 ---- .../Validator/Resources/translations/validators.gl.xlf | 4 ---- .../Validator/Resources/translations/validators.he.xlf | 4 ---- .../Validator/Resources/translations/validators.hr.xlf | 4 ---- .../Validator/Resources/translations/validators.hu.xlf | 4 ---- .../Validator/Resources/translations/validators.hy.xlf | 4 ---- .../Validator/Resources/translations/validators.id.xlf | 4 ---- .../Validator/Resources/translations/validators.it.xlf | 4 ---- .../Validator/Resources/translations/validators.ja.xlf | 4 ---- .../Validator/Resources/translations/validators.lb.xlf | 4 ---- .../Validator/Resources/translations/validators.lt.xlf | 4 ---- .../Validator/Resources/translations/validators.lv.xlf | 4 ---- .../Validator/Resources/translations/validators.mk.xlf | 4 ---- .../Validator/Resources/translations/validators.mn.xlf | 4 ---- .../Validator/Resources/translations/validators.my.xlf | 4 ---- .../Validator/Resources/translations/validators.nb.xlf | 4 ---- .../Validator/Resources/translations/validators.nl.xlf | 4 ---- .../Validator/Resources/translations/validators.nn.xlf | 4 ---- .../Validator/Resources/translations/validators.no.xlf | 4 ---- .../Validator/Resources/translations/validators.pl.xlf | 4 ---- .../Validator/Resources/translations/validators.pt.xlf | 4 ---- .../Validator/Resources/translations/validators.pt_BR.xlf | 4 ---- .../Validator/Resources/translations/validators.ro.xlf | 4 ---- .../Validator/Resources/translations/validators.ru.xlf | 4 ---- .../Validator/Resources/translations/validators.sk.xlf | 4 ---- .../Validator/Resources/translations/validators.sl.xlf | 4 ---- .../Validator/Resources/translations/validators.sq.xlf | 4 ---- .../Validator/Resources/translations/validators.sr_Cyrl.xlf | 4 ---- .../Validator/Resources/translations/validators.sr_Latn.xlf | 4 ---- .../Validator/Resources/translations/validators.sv.xlf | 4 ---- .../Validator/Resources/translations/validators.th.xlf | 4 ---- .../Validator/Resources/translations/validators.tl.xlf | 4 ---- .../Validator/Resources/translations/validators.tr.xlf | 4 ---- .../Validator/Resources/translations/validators.uk.xlf | 4 ---- .../Validator/Resources/translations/validators.ur.xlf | 4 ---- .../Validator/Resources/translations/validators.uz.xlf | 4 ---- .../Validator/Resources/translations/validators.vi.xlf | 4 ---- .../Validator/Resources/translations/validators.zh_CN.xlf | 4 ---- .../Validator/Resources/translations/validators.zh_TW.xlf | 4 ---- 57 files changed, 228 deletions(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf index 270f85355e82f..9f53b1afe35c3 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Hierdie waarde mag nie na week "{{ max }}" kom nie. - - This value is not a valid slug. - Hierdie waarde is nie 'n geldige slug nie. - This value is not a valid Twig template. Hierdie waarde is nie 'n geldige Twig-sjabloon nie. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf index 8e068ef17429d..827eed1bcc86e 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". يجب ألا تكون هذه القيمة بعد الأسبوع "{{ max }}". - - This value is not a valid slug. - هذه القيمة ليست رمزا صالحا. - This value is not a valid Twig template. هذه القيمة ليست نموذج Twig صالح. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf index 8721507fbe97b..9332c9ec2fd93 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Bu dəyər "{{ max }}" həftəsindən sonra olmamalıdır. - - This value is not a valid slug. - Bu dəyər etibarlı slug deyil. - This value is not a valid Twig template. Bu dəyər etibarlı Twig şablonu deyil. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf index aa0e67bd8c2fc..7308820465dfa 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Гэта значэнне не павінна быць пасля тыдня "{{ max }}". - - This value is not a valid slug. - Гэта значэнне не з'яўляецца сапраўдным слугам. - This value is not a valid Twig template. Гэта значэнне не з'яўляецца сапраўдным шаблонам Twig. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf index 4717830d50925..afd7590f51cb9 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Тази стойност не трябва да бъде след седмица "{{ max }}". - - This value is not a valid slug. - Тази стойност не е валиден слаг. - This value is not a valid Twig template. Тази стойност не е валиден Twig шаблон. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.bs.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.bs.xlf index 46a6aa049e04a..d6b7de5768ee5 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.bs.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.bs.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Ova vrijednost ne bi trebala biti nakon sedmice "{{ max }}". - - This value is not a valid slug. - Ova vrijednost nije važeći slug. - This value is not a valid Twig template. Ova vrijednost nije važeći Twig šablon. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf index 15d047c31a9fc..d656ef540f825 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Aquest valor no ha de ser posterior a la setmana "{{ max }}". - - This value is not a valid slug. - Aquest valor no és un slug vàlid. - This value is not a valid Twig template. Aquest valor no és una plantilla Twig vàlida. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf index c4fd950203c21..2a2e559b95238 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Tato hodnota by neměla být týden za "{{ max }}". - - This value is not a valid slug. - Tato hodnota není platný slug. - This value is not a valid Twig template. Tato hodnota není platná šablona Twig. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf index 0fc87d313fbe2..08a76667d5f4a 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Ni ddylai'r gwerth hwn fod ar ôl yr wythnos "{{ max }}". - - This value is not a valid slug. - Nid yw'r gwerth hwn yn slug dilys. - This value is not a valid Twig template. Nid yw'r gwerth hwn yn dempled Twig dilys. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.da.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.da.xlf index eabf4450f34f5..bb05bba2e641c 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.da.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.da.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Denne værdi bør ikke være efter uge "{{ max }}". - - This value is not a valid slug. - Denne værdi er ikke en gyldig slug. - This value is not a valid Twig template. Denne værdi er ikke en gyldig Twig-skabelon. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf index 7320d3de53dfe..f02c56c6c5ca9 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Dieser Wert darf nicht nach der Woche "{{ max }}" sein. - - This value is not a valid slug. - Dieser Wert ist kein gültiger Slug. - This value is not a valid Twig template. Dieser Wert ist kein valides Twig-Template. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf index d8298f530b58d..9aec12ff82ce7 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Αυτή η τιμή δεν πρέπει να είναι μετά την εβδομάδα "{{ max }}". - - This value is not a valid slug. - Αυτή η τιμή δεν είναι έγκυρο slug. - This value is not a valid Twig template. Αυτή η τιμή δεν είναι έγκυρο πρότυπο Twig. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf index cad8466103fa8..f8c664f18c423 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". This value should not be after week "{{ max }}". - - This value is not a valid slug. - This value is not a valid slug. - This value is not a valid Twig template. This value is not a valid Twig template. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf index b428fd8c19463..a9ad8a76b11e9 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Este valor no debe ser posterior a la semana "{{ max }}". - - This value is not a valid slug. - Este valor no es un slug válido. - This value is not a valid Twig template. Este valor no es una plantilla Twig válida. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf index bbc0b5692b043..2375aa4ade30c 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.et.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". See väärtus ei tohiks olla pärast nädalat "{{ max }}". - - This value is not a valid slug. - See väärtus ei ole kehtiv slug. - This value is not a valid Twig template. See väärtus ei ole kehtiv Twig'i mall. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.eu.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.eu.xlf index d5be082cd4043..830f8673dff94 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.eu.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.eu.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Balio hau ez luke astearen "{{ max }}" ondoren egon behar. - - This value is not a valid slug. - Balio hau ez da slug balioduna. - This value is not a valid Twig template. Balio hau ez da Twig txantiloi baliozko bat. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf index cc8b3d8f0a135..f47633fd4a624 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". این مقدار نباید بعد از هفته "{{ max }}" باشد. - - This value is not a valid slug. - این مقدار یک slug معتبر نیست. - This value is not a valid Twig template. این مقدار یک قالب معتبر Twig نیست. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf index 714a7a08b81e8..c046963f7ec66 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Tämän arvon ei pitäisi olla viikon "{{ max }}" jälkeen. - - This value is not a valid slug. - Tämä arvo ei ole kelvollinen slug. - This value is not a valid Twig template. Tämä arvo ei ole kelvollinen Twig-malli. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf index 6c45f32237b52..13033c01973c8 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Cette valeur ne doit pas être postérieure à la semaine "{{ max }}". - - This value is not a valid slug. - Cette valeur n'est pas un slug valide. - This value is not a valid Twig template. Cette valeur n'est pas un modèle Twig valide. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf index 1b2303774119f..391d741e96564 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Este valor non debe estar despois da semana "{{ max }}". - - This value is not a valid slug. - Este valor non é un slug válido. - This value is not a valid Twig template. Este valor non é un modelo Twig válido. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.he.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.he.xlf index ec792b699bdf5..671a98881536e 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.he.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.he.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". ערך זה לא אמור להיות לאחר שבוע "{{ max }}". - - This value is not a valid slug. - ערך זה אינו slug חוקי. - This value is not a valid Twig template. ערך זה אינו תבנית Twig חוקית. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf index 5b891d79f3ddd..0951d41926514 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Ova vrijednost ne bi trebala biti nakon tjedna "{{ max }}". - - This value is not a valid slug. - Ova vrijednost nije valjani slug. - This value is not a valid Twig template. Ova vrijednost nije valjani Twig predložak. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf index 39e3acac818bc..dffab0ccbf700 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Ez az érték nem lehet a "{{ max }}". hétnél későbbi. - - This value is not a valid slug. - Ez az érték nem érvényes slug. - This value is not a valid Twig template. Ez az érték nem érvényes Twig sablon. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hy.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hy.xlf index a1dbb93b419a3..856babbd5fe4e 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hy.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hy.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Այս արժեքը չպետք է լինի «{{ max }}» շաբաթից հետո։ - - This value is not a valid slug. - Այս արժեքը վավեր slug չէ: - This value is not a valid Twig template. Այս արժեքը վավեր Twig ձևանմուշ չէ: diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf index 669a2afa5efd2..b9796f888f924 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Nilai ini tidak boleh setelah minggu "{{ max }}". - - This value is not a valid slug. - Nilai ini bukan slug yang valid. - This value is not a valid Twig template. Nilai ini bukan templat Twig yang valid. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf index 102cbc9beb7cd..34ef61ed5f8a7 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Questo valore non dovrebbe essere dopo la settimana "{{ max }}". - - This value is not a valid slug. - Questo valore non è uno slug valido. - This value is not a valid Twig template. Questo valore non è un template Twig valido. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf index fe928e89604a0..e83aced818553 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". この値は週 "{{ max }}" 以降であってはいけません。 - - This value is not a valid slug. - この値は有効なスラグではありません。 - This value is not a valid Twig template. この値は有効な Twig テンプレートではありません。 diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf index 81bd7de6f717e..d1b5cef57bd0e 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Dëse Wäert sollt net no Woch "{{ max }}" sinn. - - This value is not a valid slug. - Dëse Wäert ass kee gültege Slug. - This value is not a valid Twig template. Dëse Wäert ass kee valabelen Twig-Template. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf index f9e9f9e220d21..46abd95036044 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Ši reikšmė neturėtų būti po savaitės "{{ max }}". - - This value is not a valid slug. - Ši reikšmė nėra tinkamas slug. - This value is not a valid Twig template. Ši reikšmė nėra tinkamas „Twig“ šablonas. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf index d16d43bf8a7e6..3e2d51a30dec1 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Šai vērtībai nevajadzētu būt pēc "{{ max }}" nedēļas. - - This value is not a valid slug. - Šī vērtība nav derīgs URL slug. - This value is not a valid Twig template. Šī vērtība nav derīgs Twig šablons. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.mk.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.mk.xlf index 6c39949aa1e09..99b1a191b6c0d 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.mk.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.mk.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Ова вредност не треба да биде по недела "{{ max }}". - - This value is not a valid slug. - Оваа вредност не е валиден slug. - This value is not a valid Twig template. Оваа вредност не е валиден Twig шаблон. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.mn.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.mn.xlf index b3ee44b43b417..3344675d9ae6a 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.mn.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.mn.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Энэ утга нь долоо хоног "{{ max }}" -аас хойш байх ёсгүй. - - This value is not a valid slug. - Энэ утга хүчинтэй slug биш байна. - This value is not a valid Twig template. Энэ утга нь Twig-ийн хүчинтэй загвар биш юм. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.my.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.my.xlf index e82ab3b19c8e1..04c955f754509 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.my.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.my.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". ဤတန်ဖိုးသည် သီတင်းပတ် "{{ max }}" ပြီးနောက် ဖြစ်သင့်သည်မဟုတ်ပါ။ - - This value is not a valid slug. - ဒီတန်ဖိုးသည်မှန်ကန်သော slug မဟုတ်ပါ။ - This value is not a valid Twig template. ဤတန်ဖိုးသည် မှန်ကန်သော Twig တင်းပလိတ်မဟုတ်ပါ။ diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf index b0281532b4c61..58696f671ca4a 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Denne verdien bør ikke være etter uke "{{ max }}". - - This value is not a valid slug. - Denne verdien er ikke en gyldig slug. - This value is not a valid Twig template. Denne verdien er ikke en gyldig Twig-mal. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf index 10086869427df..0e0de772720c4 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Deze waarde mag niet na week "{{ max }}" liggen. - - This value is not a valid slug. - Deze waarde is geen geldige slug. - This value is not a valid Twig template. Deze waarde is geen geldige Twig-template. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nn.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nn.xlf index 6cb8812b596f1..74d332c06efb2 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nn.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nn.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Denne verdien bør ikkje vere etter veke "{{ max }}". - - This value is not a valid slug. - Denne verdien er ikkje ein gyldig slug. - This value is not a valid Twig template. Denne verdien er ikkje ein gyldig Twig-mal. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf index b0281532b4c61..58696f671ca4a 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Denne verdien bør ikke være etter uke "{{ max }}". - - This value is not a valid slug. - Denne verdien er ikke en gyldig slug. - This value is not a valid Twig template. Denne verdien er ikke en gyldig Twig-mal. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf index 40a3212bc073c..7c243a6b0ca02 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Ta wartość nie powinna być po tygodniu "{{ max }}". - - This value is not a valid slug. - Ta wartość nie jest prawidłowym slugiem. - This value is not a valid Twig template. Ta wartość nie jest prawidłowym szablonem Twig. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf index 5732702d7bcde..b6562dbfe712f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Este valor não deve estar após a semana "{{ max }}". - - This value is not a valid slug. - Este valor não é um slug válido. - This value is not a valid Twig template. Este valor não é um modelo Twig válido. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf index a755b2363a314..a6be16580c6bd 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Este valor não deve estar após a semana "{{ max }}". - - This value is not a valid slug. - Este valor não é um slug válido. - This value is not a valid Twig template. Este valor não é um modelo Twig válido. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf index 56d20634736e7..d6c3b4fb82984 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Această valoare nu trebuie să fie după săptămâna "{{ max }}". - - This value is not a valid slug. - Această valoare nu este un slug valid. - This value is not a valid Twig template. Această valoare nu este un șablon Twig valid. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf index dff7ecbbb84c6..e4179779d6c27 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Это значение не должно быть после недели "{{ max }}". - - This value is not a valid slug. - Это значение не является допустимым slug. - This value is not a valid Twig template. Это значение не является допустимым шаблоном Twig. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf index c8d9d912a1750..bba3c291a7fed 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Táto hodnota by nemala byť po týždni "{{ max }}". - - This value is not a valid slug. - Táto hodnota nie je platný slug. - This value is not a valid Twig template. Táto hodnota nie je platná šablóna Twig. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf index b4cc222ad74d3..28c370e096887 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Ta vrednost ne sme biti po tednu "{{ max }}". - - This value is not a valid slug. - Ta vrednost ni veljaven URL slug. - This value is not a valid Twig template. Ta vrednost ni veljavna predloga Twig. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf index 7ae80b937a37c..ba7178f672ef7 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf @@ -475,10 +475,6 @@ This value should not be after week "{{ max }}". Kjo vlerë nuk duhet të jetë pas javës "{{ max }}". - - This value is not a valid slug. - Kjo vlerë nuk është një slug i vlefshëm. - This value is not a valid Twig template. Kjo vlerë nuk është një shabllon Twig i vlefshëm. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf index fa355e47664bc..61040270ac884 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Ова вредност не треба да буде после недеље "{{ max }}". - - This value is not a valid slug. - Ова вредност није валидан слуг. - This value is not a valid Twig template. Ова вредност није важећи Twig шаблон. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf index 61704f6eaaf12..be7ede71376d7 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Ova vrednost ne treba da bude posle nedelje "{{ max }}". - - This value is not a valid slug. - Ova vrednost nije validan slug. - This value is not a valid Twig template. Ova vrednost nije važeći Twig šablon. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf index c88ffc5823278..692ac7f52d243 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Det här värdet bör inte vara efter vecka "{{ max }}". - - This value is not a valid slug. - Detta värde är inte en giltig slug. - This value is not a valid Twig template. Det här värdet är inte en giltig Twig-mall. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.th.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.th.xlf index 26371cd6a8bf7..75398a0b84206 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.th.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.th.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". ค่านี้ไม่ควรจะอยู่หลังสัปดาห์ "{{ max }}" - - This value is not a valid slug. - ค่านี้ไม่ใช่ slug ที่ถูกต้อง - This value is not a valid Twig template. ค่านี้ไม่ใช่เทมเพลต Twig ที่ถูกต้อง diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.tl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.tl.xlf index ef1e2ad845caf..729ebc9da9185 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.tl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.tl.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Ang halagang ito ay hindi dapat pagkatapos ng linggo "{{ max }}". - - This value is not a valid slug. - Ang halagang ito ay hindi isang wastong slug. - This value is not a valid Twig template. Ang halagang ito ay hindi isang balidong Twig template. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf index 2cf33ab33c7af..43289337af4cc 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Bu değer “{{ max }}” haftasından sonra olmamalıdır - - This value is not a valid slug. - Bu değer geçerli bir “slug” değildir. - This value is not a valid Twig template. Bu değer geçerli bir Twig şablonu değil. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf index eb4a0db9ec6d0..5f132bc77a6ec 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Це значення не повинно бути після тижня "{{ max }}". - - This value is not a valid slug. - Це значення не є дійсним slug. - This value is not a valid Twig template. Це значення не є дійсним шаблоном Twig. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ur.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ur.xlf index 6a28566ca062e..f13aafb43264b 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ur.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ur.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". یہ قدر ہفتہ "{{ max }}" کے بعد نہیں ہونا چاہیے۔ - - This value is not a valid slug. - یہ قدر درست سلاگ نہیں ہے۔ - This value is not a valid Twig template. یہ قدر ایک درست Twig سانچہ نہیں ہے۔ diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf index b54fee24a3cdf..fe0b49f715b12 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Bu qiymat "{{ max }}" haftadan keyin bo'lmasligi kerak. - - This value is not a valid slug. - Bu qiymat yaroqli slug emas. - This value is not a valid Twig template. Bu qiymat yaroqli Twig shabloni emas. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf index 8bc1e4c3e078d..9daa4fe8a29d5 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". Giá trị này không nên sau tuần "{{ max }}". - - This value is not a valid slug. - Giá trị này không phải là một slug hợp lệ. - This value is not a valid Twig template. Giá trị này không phải là một mẫu Twig hợp lệ. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf index ff41473e1555e..c570d936ff17c 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.zh_CN.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". 该值不应位于 "{{ max }}"周之后。 - - This value is not a valid slug. - 此值不是有效的 slug。 - This value is not a valid Twig template. 此值不是有效的 Twig 模板。 diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf index 7c44889bf8724..d64ea192b7eb2 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf @@ -466,10 +466,6 @@ This value should not be after week "{{ max }}". 這個數值不應晚於第「{{ max }}」週。 - - This value is not a valid slug. - 這個數值不是有效的 slug。 - This value is not a valid Twig template. 此值不是有效的 Twig 模板。 From ea204b92f829f6dc2b1e41da0ec706653a6b0ee2 Mon Sep 17 00:00:00 2001 From: HypeMC Date: Tue, 20 May 2025 03:09:57 +0200 Subject: [PATCH 34/57] [PhpUnitBridge] Clean up mocked features only when group is present --- .../Bridge/PhpUnit/SymfonyExtension.php | 54 ++++++++++++---- .../SymfonyExtensionWithManualRegister.php | 64 +++++++++++++++++++ .../PhpUnit/Tests/symfonyextension.phpt | 13 ++++ 3 files changed, 119 insertions(+), 12 deletions(-) create mode 100644 src/Symfony/Bridge/PhpUnit/Tests/SymfonyExtensionWithManualRegister.php diff --git a/src/Symfony/Bridge/PhpUnit/SymfonyExtension.php b/src/Symfony/Bridge/PhpUnit/SymfonyExtension.php index 3a429c1493780..c6a5a58e871a0 100644 --- a/src/Symfony/Bridge/PhpUnit/SymfonyExtension.php +++ b/src/Symfony/Bridge/PhpUnit/SymfonyExtension.php @@ -11,6 +11,8 @@ namespace Symfony\Bridge\PhpUnit; +use PHPUnit\Event\Code\Test; +use PHPUnit\Event\Code\TestMethod; use PHPUnit\Event\Test\BeforeTestMethodErrored; use PHPUnit\Event\Test\BeforeTestMethodErroredSubscriber; use PHPUnit\Event\Test\Errored; @@ -19,6 +21,7 @@ use PHPUnit\Event\Test\FinishedSubscriber; use PHPUnit\Event\Test\Skipped; use PHPUnit\Event\Test\SkippedSubscriber; +use PHPUnit\Metadata\Group; use PHPUnit\Runner\Extension\Extension; use PHPUnit\Runner\Extension\Facade; use PHPUnit\Runner\Extension\ParameterCollection; @@ -47,22 +50,22 @@ public function bootstrap(Configuration $configuration, Facade $facade, Paramete $facade->registerSubscriber(new class implements ErroredSubscriber { public function notify(Errored $event): void { - SymfonyExtension::disableClockMock(); - SymfonyExtension::disableDnsMock(); + SymfonyExtension::disableClockMock($event->test()); + SymfonyExtension::disableDnsMock($event->test()); } }); $facade->registerSubscriber(new class implements FinishedSubscriber { public function notify(Finished $event): void { - SymfonyExtension::disableClockMock(); - SymfonyExtension::disableDnsMock(); + SymfonyExtension::disableClockMock($event->test()); + SymfonyExtension::disableDnsMock($event->test()); } }); $facade->registerSubscriber(new class implements SkippedSubscriber { public function notify(Skipped $event): void { - SymfonyExtension::disableClockMock(); - SymfonyExtension::disableDnsMock(); + SymfonyExtension::disableClockMock($event->test()); + SymfonyExtension::disableDnsMock($event->test()); } }); @@ -70,8 +73,13 @@ public function notify(Skipped $event): void $facade->registerSubscriber(new class implements BeforeTestMethodErroredSubscriber { public function notify(BeforeTestMethodErrored $event): void { - SymfonyExtension::disableClockMock(); - SymfonyExtension::disableDnsMock(); + if (method_exists($event, 'test')) { + SymfonyExtension::disableClockMock($event->test()); + SymfonyExtension::disableDnsMock($event->test()); + } else { + ClockMock::withClockMock(false); + DnsMock::withMockedHosts([]); + } } }); } @@ -88,16 +96,38 @@ public function notify(BeforeTestMethodErrored $event): void /** * @internal */ - public static function disableClockMock(): void + public static function disableClockMock(Test $test): void { - ClockMock::withClockMock(false); + if (self::hasGroup($test, 'time-sensitive')) { + ClockMock::withClockMock(false); + } } /** * @internal */ - public static function disableDnsMock(): void + public static function disableDnsMock(Test $test): void { - DnsMock::withMockedHosts([]); + if (self::hasGroup($test, 'dns-sensitive')) { + DnsMock::withMockedHosts([]); + } + } + + /** + * @internal + */ + public static function hasGroup(Test $test, string $groupName): bool + { + if (!$test instanceof TestMethod) { + return false; + } + + foreach ($test->metadata() as $metadata) { + if ($metadata instanceof Group && $groupName === $metadata->groupName()) { + return true; + } + } + + return false; } } diff --git a/src/Symfony/Bridge/PhpUnit/Tests/SymfonyExtensionWithManualRegister.php b/src/Symfony/Bridge/PhpUnit/Tests/SymfonyExtensionWithManualRegister.php new file mode 100644 index 0000000000000..c02d6f1cf64ce --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/Tests/SymfonyExtensionWithManualRegister.php @@ -0,0 +1,64 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit\Tests; + +use PHPUnit\Framework\TestCase; +use Symfony\Bridge\PhpUnit\ClockMock; +use Symfony\Bridge\PhpUnit\DnsMock; + +class SymfonyExtensionWithManualRegister extends TestCase +{ + public static function setUpBeforeClass(): void + { + ClockMock::register(self::class); + ClockMock::withClockMock(strtotime('2024-05-20 15:30:00')); + + DnsMock::register(self::class); + DnsMock::withMockedHosts([ + 'example.com' => [ + ['type' => 'A', 'ip' => '1.2.3.4'], + ], + ]); + } + + public static function tearDownAfterClass(): void + { + ClockMock::withClockMock(false); + DnsMock::withMockedHosts([]); + } + + public function testDate() + { + self::assertSame('2024-05-20 15:30:00', date('Y-m-d H:i:s')); + } + + public function testGetHostByName() + { + self::assertSame('1.2.3.4', gethostbyname('example.com')); + } + + public function testTime() + { + self::assertSame(1716219000, time()); + } + + public function testDnsGetRecord() + { + self::assertSame([[ + 'host' => 'example.com', + 'class' => 'IN', + 'ttl' => 1, + 'type' => 'A', + 'ip' => '1.2.3.4', + ]], dns_get_record('example.com')); + } +} diff --git a/src/Symfony/Bridge/PhpUnit/Tests/symfonyextension.phpt b/src/Symfony/Bridge/PhpUnit/Tests/symfonyextension.phpt index 2c808c2f5930e..02b0a510e6301 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/symfonyextension.phpt +++ b/src/Symfony/Bridge/PhpUnit/Tests/symfonyextension.phpt @@ -5,6 +5,8 @@ if (!getenv('SYMFONY_PHPUNIT_VERSION') || version_compare(getenv('SYMFONY_PHPUNI --FILE-- Date: Tue, 20 May 2025 10:28:02 +0200 Subject: [PATCH 35/57] Update Turkish translation for Twig template validation message --- .../Validator/Resources/translations/validators.tr.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf index 43289337af4cc..42c4bbd91ebab 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf @@ -468,7 +468,7 @@ This value is not a valid Twig template. - Bu değer geçerli bir Twig şablonu değil. + Bu değer geçerli bir Twig şablonu olarak kabul edilmiyor. From 03a02acdcf85ab35a8e6279125fb68e2de76b2e5 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 20 May 2025 11:40:57 +0200 Subject: [PATCH 36/57] set path to the PHPUnit autoload file --- src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php index 0472e8c1d81b3..590a886350c79 100644 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php @@ -386,6 +386,10 @@ class_exists(\SymfonyExcludeListSimplePhpunit::class, false) && PHPUnit\Util\Bla $cmd .= '%2$s'; } +if (version_compare($PHPUNIT_VERSION, '11.0', '>=')) { + $GLOBALS['_composer_autoload_path'] = "$PHPUNIT_DIR/$PHPUNIT_VERSION_DIR/vendor/autoload.php"; +} + if ($components) { $skippedTests = $_SERVER['SYMFONY_PHPUNIT_SKIPPED_TESTS'] ?? false; $runningProcs = []; From 307d743084462b29a1bd9816f5ad3befd22cdfcb Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 20 May 2025 10:48:43 +0200 Subject: [PATCH 37/57] [FrameworkBundle] Fix activation strategy of traceable decorators --- src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php | 9 +++++++++ .../FrameworkBundle/Resources/config/profiling.php | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 7c5ba6e39e121..300fe22fb37a9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -11,6 +11,7 @@ namespace Symfony\Bundle\FrameworkBundle; +use Symfony\Bundle\FrameworkBundle\Console\Application; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddDebugLogProcessorPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AssetsContextPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ContainerBuilderDebugDumpPass; @@ -202,6 +203,14 @@ public function build(ContainerBuilder $container): void } } + /** + * @internal + */ + public static function considerProfilerEnabled(): bool + { + return !($GLOBALS['app'] ?? null) instanceof Application || empty($_GET) && \in_array('--profile', $_SERVER['argv'] ?? [], true); + } + private function addCompilerPassIfExists(ContainerBuilder $container, string $class, string $type = PassConfig::TYPE_BEFORE_OPTIMIZATION, int $priority = 0): void { $container->addResource(new ClassExistenceResource($class)); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/profiling.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/profiling.php index 68fb295bb8768..a81c53a633461 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/profiling.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/profiling.php @@ -12,6 +12,7 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; use Symfony\Bundle\FrameworkBundle\EventListener\ConsoleProfilerListener; +use Symfony\Bundle\FrameworkBundle\FrameworkBundle; use Symfony\Component\HttpKernel\Debug\VirtualRequestStack; use Symfony\Component\HttpKernel\EventListener\ProfilerListener; use Symfony\Component\HttpKernel\Profiler\FileProfilerStorage; @@ -61,7 +62,7 @@ ->set('profiler.state_checker', ProfilerStateChecker::class) ->args([ service_locator(['profiler' => service('profiler')->ignoreOnUninitialized()]), - param('kernel.runtime_mode.web'), + inline_service('bool')->factory([FrameworkBundle::class, 'considerProfilerEnabled']), ]) ->set('profiler.is_disabled_state_checker', 'Closure') From 5b2634ff8c7da371c04338953172847fc81cfb2c Mon Sep 17 00:00:00 2001 From: maciekpaprocki Date: Tue, 20 May 2025 11:29:20 +0100 Subject: [PATCH 38/57] added earlier skip to allow if=false when using source mapping --- src/Symfony/Component/ObjectMapper/ObjectMapper.php | 6 +++--- .../Tests/Fixtures/HydrateObject/SourceOnly.php | 6 ++++-- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/ObjectMapper/ObjectMapper.php b/src/Symfony/Component/ObjectMapper/ObjectMapper.php index 7624a05f7bfe0..d78bc3ce8d216 100644 --- a/src/Symfony/Component/ObjectMapper/ObjectMapper.php +++ b/src/Symfony/Component/ObjectMapper/ObjectMapper.php @@ -122,12 +122,12 @@ public function map(object $source, object|string|null $target = null): object $sourcePropertyName = $mapping->source; } - $value = $this->getRawValue($source, $sourcePropertyName); - if (($if = $mapping->if) && ($fn = $this->getCallable($if, $this->conditionCallableLocator)) && !$this->call($fn, $value, $source, $mappedTarget)) { + if (false === $if = $mapping->if) { continue; } - if (false === $if) { + $value = $this->getRawValue($source, $sourcePropertyName); + if ($if && ($fn = $this->getCallable($if, $this->conditionCallableLocator)) && !$this->call($fn, $value, $source, $mappedTarget)) { continue; } diff --git a/src/Symfony/Component/ObjectMapper/Tests/Fixtures/HydrateObject/SourceOnly.php b/src/Symfony/Component/ObjectMapper/Tests/Fixtures/HydrateObject/SourceOnly.php index 9e3127b80d965..c062427c6e8d0 100644 --- a/src/Symfony/Component/ObjectMapper/Tests/Fixtures/HydrateObject/SourceOnly.php +++ b/src/Symfony/Component/ObjectMapper/Tests/Fixtures/HydrateObject/SourceOnly.php @@ -15,7 +15,9 @@ class SourceOnly { - public function __construct(#[Map(source: 'name')] public string $mappedName) - { + public function __construct( + #[Map(source: 'name')] public string $mappedName, + #[Map(if: false)] public ?string $mappedDescription = null + ) { } } From 82d7ecdec3f8ea2f71be19026ba26707fc50e48a Mon Sep 17 00:00:00 2001 From: soyuka Date: Tue, 20 May 2025 13:53:54 +0200 Subject: [PATCH 39/57] [FrameworkBundle] object mapper service definition without form --- .../DependencyInjection/FrameworkExtension.php | 16 ++++++++-------- .../FrameworkExtensionTestCase.php | 8 ++++++++ 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 385a4caf38ded..912282f495dac 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -642,6 +642,14 @@ public function load(array $configs, ContainerBuilder $container): void $loader->load('mime_type.php'); } + if (ContainerBuilder::willBeAvailable('symfony/object-mapper', ObjectMapperInterface::class, ['symfony/framework-bundle'])) { + $loader->load('object_mapper.php'); + $container->registerForAutoconfiguration(TransformCallableInterface::class) + ->addTag('object_mapper.transform_callable'); + $container->registerForAutoconfiguration(ConditionCallableInterface::class) + ->addTag('object_mapper.condition_callable'); + } + $container->registerForAutoconfiguration(PackageInterface::class) ->addTag('assets.package'); $container->registerForAutoconfiguration(AssetCompilerInterface::class) @@ -880,14 +888,6 @@ private function registerFormConfiguration(array $config, ContainerBuilder $cont if (!ContainerBuilder::willBeAvailable('symfony/translation', Translator::class, ['symfony/framework-bundle', 'symfony/form'])) { $container->removeDefinition('form.type_extension.upload.validator'); } - - if (ContainerBuilder::willBeAvailable('symfony/object-mapper', ObjectMapperInterface::class, ['symfony/framework-bundle'])) { - $loader->load('object_mapper.php'); - $container->registerForAutoconfiguration(TransformCallableInterface::class) - ->addTag('object_mapper.transform_callable'); - $container->registerForAutoconfiguration(ConditionCallableInterface::class) - ->addTag('object_mapper.condition_callable'); - } } private function registerHttpCacheConfiguration(array $config, ContainerBuilder $container, bool $httpMethodOverride): void diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php index 990e1e8c252d4..8b452d4c8baf4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php @@ -2600,6 +2600,14 @@ public function testJsonStreamerEnabled() $this->assertTrue($container->has('json_streamer.stream_writer')); } + public function testObjectMapperEnabled() + { + $container = $this->createContainerFromClosure(function (ContainerBuilder $container) { + $container->loadFromExtension('framework', []); + }); + $this->assertTrue($container->has('object_mapper')); + } + protected function createContainer(array $data = []) { return new ContainerBuilder(new EnvPlaceholderParameterBag(array_merge([ From 6468ac18ef5d38069a64f39d207cc66e8e328d5e Mon Sep 17 00:00:00 2001 From: es Date: Tue, 20 May 2025 17:15:13 +0300 Subject: [PATCH 40/57] review translation messages(be) --- .../Resources/translations/security.be.xlf | 2 +- .../Resources/translations/validators.be.xlf | 30 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.be.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.be.xlf index 194392935fcc1..6478e2a15caf7 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.be.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.be.xlf @@ -76,7 +76,7 @@ Too many failed login attempts, please try again in %minutes% minutes. - Занадта шмат няўдалых спробаў уваходу, калі ласка, паспрабуйце зноў праз %minutes% хвіліну.|Занадта шмат няўдалых спробаў уваходу, калі ласка, паспрабуйце зноў праз %minutes% хвіліны.|Занадта шмат няўдалых спробаў уваходу, калі ласка, паспрабуйце зноў праз %minutes% хвілін. + Занадта вялікая колькасць няўдалых спробаў уваходу. Калі ласка, паспрабуйце зноў праз %minutes% хвіліну.|Занадта вялікая колькасць няўдалых спробаў уваходу. Калі ласка, паспрабуйце зноў праз %minutes% хвіліны.|Занадта вялікая колькасць няўдалых спробаў уваходу. Калі ласка, паспрабуйце зноў праз %minutes% хвілін. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf index 7308820465dfa..7b24df5e5c189 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf @@ -136,7 +136,7 @@ This value is not a valid IP address. - Гэта значэнне не з'яўляецца сапраўдным IP-адрасам. + Гэта значэнне не з'яўляецца сапраўдным IP-адрасам. This value is not a valid language. @@ -224,7 +224,7 @@ This value is not a valid International Bank Account Number (IBAN). - Гэта значэнне не з'яўляецца сапраўдным міжнародным нумарам банкаўскага рахунку (IBAN). + Гэта значэнне не з'яўляецца сапраўдным міжнародным нумарам банкаўскага рахунку (IBAN). This value is not a valid ISBN-10. @@ -312,7 +312,7 @@ This value is not a valid Business Identifier Code (BIC). - Гэта значэнне не з'яўляецца сапраўдным кодам ідэнтыфікацыі бізнесу (BIC). + Гэта значэнне не з'яўляецца сапраўдным кодам ідэнтыфікацыі банка (BIC). Error @@ -320,7 +320,7 @@ This value is not a valid UUID. - Гэта значэнне не з'яўляецца сапраўдным UUID. + Гэта значэнне не з'яўляецца сапраўдным UUID. This value should be a multiple of {{ compared_value }}. @@ -428,47 +428,47 @@ The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. - Пашырэнне файла няслушнае ({{ extension }}). Дазволеныя пашырэнні: {{ extensions }}. + Пашырэнне файла недапушчальнае ({{ extension }}). Дазволеныя пашырэнні: {{ extensions }}. The detected character encoding is invalid ({{ detected }}). Allowed encodings are {{ encodings }}. - Выяўленая кадыроўка знакаў няслушная ({{ detected }}). Дазволеныя кадыроўкі: {{ encodings }}. + Выяўленая кадзіроўка недапушчальная ({{ detected }}). Дазволеныя кадзіроўкі: {{ encodings }}. This value is not a valid MAC address. - Гэта значэнне не з'яўляецца сапраўдным MAC-адрасам. + Гэта значэнне не з'яўляецца сапраўдным MAC-адрасам. This URL is missing a top-level domain. - Гэтаму URL бракуе дамен верхняга ўзроўню. + Гэтаму URL бракуе дамен верхняга ўзроўню. This value is too short. It should contain at least one word.|This value is too short. It should contain at least {{ min }} words. - Гэта значэнне занадта кароткае. Яно павінна ўтрымліваць хаця б адно слова.|Гэта значэнне занадта кароткае. Яно павінна ўтрымліваць хаця б {{ min }} словы. + Гэта значэнне занадта кароткае. Яно павінна ўтрымліваць хаця б адно слова.|Гэта значэнне занадта кароткае. Яно павінна ўтрымліваць хаця б {{ min }} слоў. This value is too long. It should contain one word.|This value is too long. It should contain {{ max }} words or less. - Гэта значэнне занадта доўгае. Яно павінна ўтрымліваць адно слова.|Гэта значэнне занадта доўгае. Яно павінна ўтрымліваць {{ max }} словы або менш. + Гэта значэнне занадта доўгае. Яно павінна ўтрымліваць адно слова.|Гэта значэнне занадта доўгае. Яно павінна ўтрымліваць {{ max }} слоў або менш. This value does not represent a valid week in the ISO 8601 format. - Гэта значэнне не адпавядае правільнаму тыдні ў фармаце ISO 8601. + Гэта значэнне не адпавядае сапраўднаму тыдню ў фармаце ISO 8601. This value is not a valid week. - Гэта значэнне не з'яўляецца сапраўдным тыднем. + Гэта значэнне не з'яўляецца сапраўдным тыднем. This value should not be before week "{{ min }}". - Гэта значэнне не павінна быць раней за тыдзень "{{ min }}". + Гэта значэнне не павінна быць раней за тыдзень "{{ min }}". This value should not be after week "{{ max }}". - Гэта значэнне не павінна быць пасля тыдня "{{ max }}". + Гэта значэнне не павінна быць пасля тыдня "{{ max }}". This value is not a valid Twig template. - Гэта значэнне не з'яўляецца сапраўдным шаблонам Twig. + Гэта значэнне не з'яўляецца сапраўдным шаблонам Twig. From 6efc2045a16a1668aadcc1e179c7ec58bc1b2632 Mon Sep 17 00:00:00 2001 From: Link1515 Date: Tue, 20 May 2025 18:08:09 +0800 Subject: [PATCH 41/57] Review translations for Chinese (zh_TW) --- .../Validator/Resources/translations/validators.zh_TW.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf index d64ea192b7eb2..a60283b280898 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf @@ -468,7 +468,7 @@ This value is not a valid Twig template. - 此值不是有效的 Twig 模板。 + 這個數值不是有效的 Twig 模板。 From 4cdbbe51b79415df76018acce2b8e114ba5aaff5 Mon Sep 17 00:00:00 2001 From: Ignacio Alveal Date: Tue, 20 May 2025 12:54:44 -0400 Subject: [PATCH 42/57] fix: Add argument as integer Co-authored-by: Guillermo Fuentes --- .../Component/Messenger/Bridge/Amqp/Transport/Connection.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php index 0ae1bff21d7c8..061bbcb47d124 100644 --- a/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php @@ -31,6 +31,7 @@ class Connection 'x-max-length-bytes', 'x-max-priority', 'x-message-ttl', + 'x-delivery-limit', ]; /** From 5ec5f407e575cebd18edd96f5fe3d089bdb55ec2 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 21 May 2025 09:40:19 +0200 Subject: [PATCH 43/57] fix merge --- src/Symfony/Component/Validator/Constraints/Image.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/Image.php b/src/Symfony/Component/Validator/Constraints/Image.php index 0dd09bf1f165f..5812b9a4989a4 100644 --- a/src/Symfony/Component/Validator/Constraints/Image.php +++ b/src/Symfony/Component/Validator/Constraints/Image.php @@ -58,7 +58,7 @@ class Image extends File self::CORRUPTED_IMAGE_ERROR => 'CORRUPTED_IMAGE_ERROR', ]; - public array|string $mimeTypes = 'image/*'; + public array|string $mimeTypes = []; public ?int $minWidth = null; public ?int $maxWidth = null; public ?int $maxHeight = null; @@ -220,7 +220,7 @@ public function __construct( $this->allowPortraitMessage = $allowPortraitMessage ?? $this->allowPortraitMessage; $this->corruptedMessage = $corruptedMessage ?? $this->corruptedMessage; - if (null === $this->mimeTypes && [] === $this->extensions) { + if ([] === $this->mimeTypes && [] === $this->extensions) { $this->mimeTypes = 'image/*'; } From 7e09dc03208d75b8879ee031568e9731073fbbb8 Mon Sep 17 00:00:00 2001 From: PatrickRedStar Date: Wed, 21 May 2025 14:12:29 +0300 Subject: [PATCH 44/57] validate translate src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf:471 --- .../Validator/Resources/translations/validators.ru.xlf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf index e4179779d6c27..727ae0aefdf86 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf @@ -468,7 +468,7 @@ This value is not a valid Twig template. - Это значение не является допустимым шаблоном Twig. + Это значение не является корректным шаблоном Twig. From 7d63c76de82c906e398c104e9848063b5fa5e10f Mon Sep 17 00:00:00 2001 From: HypeMC Date: Wed, 21 May 2025 14:18:26 +0200 Subject: [PATCH 45/57] [PropertyInfo] Improve deprecation message --- .../FrameworkBundle/DependencyInjection/Configuration.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 0e9b20b0ca015..f4e137f04b980 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -1290,7 +1290,7 @@ private function addPropertyInfoSection(ArrayNodeDefinition $rootNode, callable ->then(function ($v) { $v['property_info']['with_constructor_extractor'] = false; - trigger_deprecation('symfony/framework-bundle', '7.3', 'Not setting the "with_constructor_extractor" option explicitly is deprecated because its default value will change in version 8.0.'); + trigger_deprecation('symfony/framework-bundle', '7.3', 'Not setting the "property_info.with_constructor_extractor" option explicitly is deprecated because its default value will change in version 8.0.'); return $v; }) From c6ceb0cc94b07fcac091cc7f1c8d6068bdd029b9 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 22 May 2025 13:56:34 +0200 Subject: [PATCH 46/57] meaningfully error in DeduplicateStamp if the Lock component is missing --- src/Symfony/Component/Messenger/Stamp/DeduplicateStamp.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Symfony/Component/Messenger/Stamp/DeduplicateStamp.php b/src/Symfony/Component/Messenger/Stamp/DeduplicateStamp.php index 4e08d5369f261..1b9ff480b4f49 100644 --- a/src/Symfony/Component/Messenger/Stamp/DeduplicateStamp.php +++ b/src/Symfony/Component/Messenger/Stamp/DeduplicateStamp.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Messenger\Stamp; use Symfony\Component\Lock\Key; +use Symfony\Component\Messenger\Exception\LogicException; final class DeduplicateStamp implements StampInterface { @@ -22,6 +23,10 @@ public function __construct( private ?float $ttl = 300.0, private bool $onlyDeduplicateInQueue = false, ) { + if (!class_exists(Key::class)) { + throw new LogicException(\sprintf('You cannot use the "%s" as the Lock component is not installed. Try running "composer require symfony/lock".', self::class)); + } + $this->key = new Key($key); } From 62da782fd3941e75bf150a52eebb6935623ad814 Mon Sep 17 00:00:00 2001 From: HypeMC Date: Wed, 21 May 2025 14:00:46 +0200 Subject: [PATCH 47/57] [PhpUnitBridge] Fix cleaning up mocked features with attributes --- .github/workflows/phpunit-bridge.yml | 2 +- .../Bridge/PhpUnit/SymfonyExtension.php | 54 ++++++++++++------- 2 files changed, 37 insertions(+), 19 deletions(-) diff --git a/.github/workflows/phpunit-bridge.yml b/.github/workflows/phpunit-bridge.yml index 56360c4c3d80a..5de320ee91c0e 100644 --- a/.github/workflows/phpunit-bridge.yml +++ b/.github/workflows/phpunit-bridge.yml @@ -35,4 +35,4 @@ jobs: php-version: "7.2" - name: Lint - run: find ./src/Symfony/Bridge/PhpUnit -name '*.php' | grep -v -e /Tests/ -e /Attribute/ -e /Extension/ -e /Metadata/ -e ForV7 -e ForV8 -e ForV9 -e ConstraintLogicTrait | parallel -j 4 php -l {} + run: find ./src/Symfony/Bridge/PhpUnit -name '*.php' | grep -v -e /Tests/ -e /Attribute/ -e /Extension/ -e /Metadata/ -e ForV7 -e ForV8 -e ForV9 -e ConstraintLogicTrait -e SymfonyExtension | parallel -j 4 php -l {} diff --git a/src/Symfony/Bridge/PhpUnit/SymfonyExtension.php b/src/Symfony/Bridge/PhpUnit/SymfonyExtension.php index f290a2c228865..05ff99aa8aedc 100644 --- a/src/Symfony/Bridge/PhpUnit/SymfonyExtension.php +++ b/src/Symfony/Bridge/PhpUnit/SymfonyExtension.php @@ -26,6 +26,8 @@ use PHPUnit\Runner\Extension\Facade; use PHPUnit\Runner\Extension\ParameterCollection; use PHPUnit\TextUI\Configuration\Configuration; +use Symfony\Bridge\PhpUnit\Attribute\DnsSensitive; +use Symfony\Bridge\PhpUnit\Attribute\TimeSensitive; use Symfony\Bridge\PhpUnit\Extension\EnableClockMockSubscriber; use Symfony\Bridge\PhpUnit\Extension\RegisterClockMockSubscriber; use Symfony\Bridge\PhpUnit\Extension\RegisterDnsMockSubscriber; @@ -50,35 +52,51 @@ public function bootstrap(Configuration $configuration, Facade $facade, Paramete $facade->registerSubscriber(new RegisterClockMockSubscriber($reader)); $facade->registerSubscriber(new EnableClockMockSubscriber($reader)); - $facade->registerSubscriber(new class implements ErroredSubscriber { + $facade->registerSubscriber(new class($reader) implements ErroredSubscriber { + public function __construct(private AttributeReader $reader) + { + } + public function notify(Errored $event): void { - SymfonyExtension::disableClockMock($event->test()); - SymfonyExtension::disableDnsMock($event->test()); + SymfonyExtension::disableClockMock($event->test(), $this->reader); + SymfonyExtension::disableDnsMock($event->test(), $this->reader); } }); - $facade->registerSubscriber(new class implements FinishedSubscriber { + $facade->registerSubscriber(new class($reader) implements FinishedSubscriber { + public function __construct(private AttributeReader $reader) + { + } + public function notify(Finished $event): void { - SymfonyExtension::disableClockMock($event->test()); - SymfonyExtension::disableDnsMock($event->test()); + SymfonyExtension::disableClockMock($event->test(), $this->reader); + SymfonyExtension::disableDnsMock($event->test(), $this->reader); } }); - $facade->registerSubscriber(new class implements SkippedSubscriber { + $facade->registerSubscriber(new class($reader) implements SkippedSubscriber { + public function __construct(private AttributeReader $reader) + { + } + public function notify(Skipped $event): void { - SymfonyExtension::disableClockMock($event->test()); - SymfonyExtension::disableDnsMock($event->test()); + SymfonyExtension::disableClockMock($event->test(), $this->reader); + SymfonyExtension::disableDnsMock($event->test(), $this->reader); } }); if (interface_exists(BeforeTestMethodErroredSubscriber::class)) { - $facade->registerSubscriber(new class implements BeforeTestMethodErroredSubscriber { + $facade->registerSubscriber(new class($reader) implements BeforeTestMethodErroredSubscriber { + public function __construct(private AttributeReader $reader) + { + } + public function notify(BeforeTestMethodErrored $event): void { if (method_exists($event, 'test')) { - SymfonyExtension::disableClockMock($event->test()); - SymfonyExtension::disableDnsMock($event->test()); + SymfonyExtension::disableClockMock($event->test(), $this->reader); + SymfonyExtension::disableDnsMock($event->test(), $this->reader); } else { ClockMock::withClockMock(false); DnsMock::withMockedHosts([]); @@ -99,9 +117,9 @@ public function notify(BeforeTestMethodErrored $event): void /** * @internal */ - public static function disableClockMock(Test $test): void + public static function disableClockMock(Test $test, AttributeReader $reader): void { - if (self::hasGroup($test, 'time-sensitive')) { + if (self::hasGroup($test, 'time-sensitive', $reader, TimeSensitive::class)) { ClockMock::withClockMock(false); } } @@ -109,9 +127,9 @@ public static function disableClockMock(Test $test): void /** * @internal */ - public static function disableDnsMock(Test $test): void + public static function disableDnsMock(Test $test, AttributeReader $reader): void { - if (self::hasGroup($test, 'dns-sensitive')) { + if (self::hasGroup($test, 'dns-sensitive', $reader, DnsSensitive::class)) { DnsMock::withMockedHosts([]); } } @@ -119,7 +137,7 @@ public static function disableDnsMock(Test $test): void /** * @internal */ - public static function hasGroup(Test $test, string $groupName): bool + public static function hasGroup(Test $test, string $groupName, AttributeReader $reader, string $attribute): bool { if (!$test instanceof TestMethod) { return false; @@ -131,6 +149,6 @@ public static function hasGroup(Test $test, string $groupName): bool } } - return false; + return [] !== $reader->forClassAndMethod($test->className(), $test->methodName(), $attribute); } } From 0d6cda354b3f4358cdadc4d81800ee94a5241760 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 23 May 2025 10:51:09 +0200 Subject: [PATCH 48/57] also reject \DateTime subclasses --- .../Read/DateTimeTypePropertyMetadataLoader.php | 2 +- .../DateTimeTypePropertyMetadataLoaderTest.php | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/JsonStreamer/Mapping/Read/DateTimeTypePropertyMetadataLoader.php b/src/Symfony/Component/JsonStreamer/Mapping/Read/DateTimeTypePropertyMetadataLoader.php index 11ce2b4f93962..26bc022cae2e3 100644 --- a/src/Symfony/Component/JsonStreamer/Mapping/Read/DateTimeTypePropertyMetadataLoader.php +++ b/src/Symfony/Component/JsonStreamer/Mapping/Read/DateTimeTypePropertyMetadataLoader.php @@ -38,7 +38,7 @@ public function load(string $className, array $options = [], array $context = [] $type = $metadata->getType(); if ($type instanceof ObjectType && is_a($type->getClassName(), \DateTimeInterface::class, true)) { - if (\DateTime::class === $type->getClassName()) { + if (is_a($type->getClassName(), \DateTime::class, true)) { throw new InvalidArgumentException('The "DateTime" class is not supported. Use "DateTimeImmutable" instead.'); } diff --git a/src/Symfony/Component/JsonStreamer/Tests/Mapping/Read/DateTimeTypePropertyMetadataLoaderTest.php b/src/Symfony/Component/JsonStreamer/Tests/Mapping/Read/DateTimeTypePropertyMetadataLoaderTest.php index c71189815be29..779499adf21c2 100644 --- a/src/Symfony/Component/JsonStreamer/Tests/Mapping/Read/DateTimeTypePropertyMetadataLoaderTest.php +++ b/src/Symfony/Component/JsonStreamer/Tests/Mapping/Read/DateTimeTypePropertyMetadataLoaderTest.php @@ -47,6 +47,18 @@ public function testThrowWhenDateTimeType() $loader->load(self::class); } + public function testThrowWhenDateTimeSubclassType() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('The "DateTime" class is not supported. Use "DateTimeImmutable" instead.'); + + $loader = new DateTimeTypePropertyMetadataLoader(self::propertyMetadataLoader([ + 'mutable' => new PropertyMetadata('mutable', Type::object(DateTimeChild::class)), + ])); + + $loader->load(self::class); + } + /** * @param array $propertiesMetadata */ @@ -64,3 +76,7 @@ public function load(string $className, array $options = [], array $context = [] }; } } + +class DateTimeChild extends \DateTime +{ +} From 734e60aa338244975d15fbce2cf0214253f5e2ea Mon Sep 17 00:00:00 2001 From: Fabien Salathe Date: Sat, 24 May 2025 01:18:01 +0900 Subject: [PATCH 49/57] [Notifier] Fix Clicksend transport --- .../Notifier/Bridge/ClickSend/ClickSendTransport.php | 2 +- .../Bridge/ClickSend/Tests/ClickSendTransportTest.php | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Notifier/Bridge/ClickSend/ClickSendTransport.php b/src/Symfony/Component/Notifier/Bridge/ClickSend/ClickSendTransport.php index 0e5bd147d3f61..f60e4e23ee3f9 100644 --- a/src/Symfony/Component/Notifier/Bridge/ClickSend/ClickSendTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/ClickSend/ClickSendTransport.php @@ -87,7 +87,7 @@ protected function doSend(MessageInterface $message): SentMessage $response = $this->client->request('POST', $endpoint, [ 'auth_basic' => [$this->apiUsername, $this->apiKey], - 'json' => array_filter($options), + 'json' => ['messages' => [array_filter($options)]], ]); try { diff --git a/src/Symfony/Component/Notifier/Bridge/ClickSend/Tests/ClickSendTransportTest.php b/src/Symfony/Component/Notifier/Bridge/ClickSend/Tests/ClickSendTransportTest.php index 166bb10d8a8dc..ba7923a7fa231 100644 --- a/src/Symfony/Component/Notifier/Bridge/ClickSend/Tests/ClickSendTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/ClickSend/Tests/ClickSendTransportTest.php @@ -63,10 +63,14 @@ public function testNoInvalidArgumentExceptionIsThrownIfFromIsValid(string $from $response = $this->createMock(ResponseInterface::class); $response->expects(self::exactly(2))->method('getStatusCode')->willReturn(200); $response->expects(self::once())->method('getContent')->willReturn(''); - $client = new MockHttpClient(function (string $method, string $url) use ($response): ResponseInterface { + $client = new MockHttpClient(function (string $method, string $url, array $options) use ($response): ResponseInterface { self::assertSame('POST', $method); self::assertSame('https://rest.clicksend.com/v3/sms/send', $url); + $body = json_decode($options['body'], true); + self::assertIsArray($body); + self::assertArrayHasKey('messages', $body); + return $response; }); $transport = $this->createTransport($client, $from); From c9d7c63cbe5ef82a34a5ced5720f97a8cc43feb1 Mon Sep 17 00:00:00 2001 From: Kevin Bond Date: Sat, 17 May 2025 19:37:35 -0400 Subject: [PATCH 50/57] [Console] Improve `#[Argument]`/`#[Option]` exception messages --- .../Component/Console/Attribute/Argument.php | 11 ++++++++-- .../Component/Console/Attribute/Option.php | 21 ++++++++++++------ .../Tests/Command/InvokableCommandTest.php | 22 +++++-------------- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/src/Symfony/Component/Console/Attribute/Argument.php b/src/Symfony/Component/Console/Attribute/Argument.php index 22bfbf48b762d..e6a94d2f10e4c 100644 --- a/src/Symfony/Component/Console/Attribute/Argument.php +++ b/src/Symfony/Component/Console/Attribute/Argument.php @@ -26,6 +26,7 @@ class Argument private string|bool|int|float|array|null $default = null; private array|\Closure $suggestedValues; private ?int $mode = null; + private string $function = ''; /** * Represents a console command definition. @@ -52,17 +53,23 @@ public static function tryFrom(\ReflectionParameter $parameter): ?self return null; } + if (($function = $parameter->getDeclaringFunction()) instanceof \ReflectionMethod) { + $self->function = $function->class.'::'.$function->name; + } else { + $self->function = $function->name; + } + $type = $parameter->getType(); $name = $parameter->getName(); if (!$type instanceof \ReflectionNamedType) { - throw new LogicException(\sprintf('The parameter "$%s" must have a named type. Untyped, Union or Intersection types are not supported for command arguments.', $name)); + throw new LogicException(\sprintf('The parameter "$%s" of "%s()" must have a named type. Untyped, Union or Intersection types are not supported for command arguments.', $name, $self->function)); } $parameterTypeName = $type->getName(); if (!\in_array($parameterTypeName, self::ALLOWED_TYPES, true)) { - throw new LogicException(\sprintf('The type "%s" of parameter "$%s" is not supported as a command argument. Only "%s" types are allowed.', $parameterTypeName, $name, implode('", "', self::ALLOWED_TYPES))); + throw new LogicException(\sprintf('The type "%s" on parameter "$%s" of "%s()" is not supported as a command argument. Only "%s" types are allowed.', $parameterTypeName, $name, $self->function, implode('", "', self::ALLOWED_TYPES))); } if (!$self->name) { diff --git a/src/Symfony/Component/Console/Attribute/Option.php b/src/Symfony/Component/Console/Attribute/Option.php index 19c82317033c4..2f0256b177658 100644 --- a/src/Symfony/Component/Console/Attribute/Option.php +++ b/src/Symfony/Component/Console/Attribute/Option.php @@ -29,6 +29,7 @@ class Option private ?int $mode = null; private string $typeName = ''; private bool $allowNull = false; + private string $function = ''; /** * Represents a console command --option definition. @@ -57,11 +58,17 @@ public static function tryFrom(\ReflectionParameter $parameter): ?self return null; } + if (($function = $parameter->getDeclaringFunction()) instanceof \ReflectionMethod) { + $self->function = $function->class.'::'.$function->name; + } else { + $self->function = $function->name; + } + $name = $parameter->getName(); $type = $parameter->getType(); if (!$parameter->isDefaultValueAvailable()) { - throw new LogicException(\sprintf('The option parameter "$%s" must declare a default value.', $name)); + throw new LogicException(\sprintf('The option parameter "$%s" of "%s()" must declare a default value.', $name, $self->function)); } if (!$self->name) { @@ -76,21 +83,21 @@ public static function tryFrom(\ReflectionParameter $parameter): ?self } if (!$type instanceof \ReflectionNamedType) { - throw new LogicException(\sprintf('The parameter "$%s" must have a named type. Untyped or Intersection types are not supported for command options.', $name)); + throw new LogicException(\sprintf('The parameter "$%s" of "%s()" must have a named type. Untyped or Intersection types are not supported for command options.', $name, $self->function)); } $self->typeName = $type->getName(); if (!\in_array($self->typeName, self::ALLOWED_TYPES, true)) { - throw new LogicException(\sprintf('The type "%s" of parameter "$%s" is not supported as a command option. Only "%s" types are allowed.', $self->typeName, $name, implode('", "', self::ALLOWED_TYPES))); + throw new LogicException(\sprintf('The type "%s" on parameter "$%s" of "%s()" is not supported as a command option. Only "%s" types are allowed.', $self->typeName, $name, $self->function, implode('", "', self::ALLOWED_TYPES))); } if ('bool' === $self->typeName && $self->allowNull && \in_array($self->default, [true, false], true)) { - throw new LogicException(\sprintf('The option parameter "$%s" must not be nullable when it has a default boolean value.', $name)); + throw new LogicException(\sprintf('The option parameter "$%s" of "%s()" must not be nullable when it has a default boolean value.', $name, $self->function)); } if ($self->allowNull && null !== $self->default) { - throw new LogicException(\sprintf('The option parameter "$%s" must either be not-nullable or have a default of null.', $name)); + throw new LogicException(\sprintf('The option parameter "$%s" of "%s()" must either be not-nullable or have a default of null.', $name, $self->function)); } if ('bool' === $self->typeName) { @@ -160,11 +167,11 @@ private function handleUnion(\ReflectionUnionType $type): self $this->typeName = implode('|', array_filter($types)); if (!\in_array($this->typeName, self::ALLOWED_UNION_TYPES, true)) { - throw new LogicException(\sprintf('The union type for parameter "$%s" is not supported as a command option. Only "%s" types are allowed.', $this->name, implode('", "', self::ALLOWED_UNION_TYPES))); + throw new LogicException(\sprintf('The union type for parameter "$%s" of "%s()" is not supported as a command option. Only "%s" types are allowed.', $this->name, $this->function, implode('", "', self::ALLOWED_UNION_TYPES))); } if (false !== $this->default) { - throw new LogicException(\sprintf('The option parameter "$%s" must have a default value of false.', $this->name)); + throw new LogicException(\sprintf('The option parameter "$%s" of "%s()" must have a default value of false.', $this->name, $this->function)); } $this->mode = InputOption::VALUE_OPTIONAL; diff --git a/src/Symfony/Component/Console/Tests/Command/InvokableCommandTest.php b/src/Symfony/Component/Console/Tests/Command/InvokableCommandTest.php index 917e2f88f1655..5ab7951e7f575 100644 --- a/src/Symfony/Component/Console/Tests/Command/InvokableCommandTest.php +++ b/src/Symfony/Component/Console/Tests/Command/InvokableCommandTest.php @@ -138,7 +138,6 @@ public function testInvalidArgumentType() $command->setCode(function (#[Argument] object $any) {}); $this->expectException(LogicException::class); - $this->expectExceptionMessage('The type "object" of parameter "$any" is not supported as a command argument. Only "string", "bool", "int", "float", "array" types are allowed.'); $command->getDefinition(); } @@ -149,7 +148,6 @@ public function testInvalidOptionType() $command->setCode(function (#[Option] ?object $any = null) {}); $this->expectException(LogicException::class); - $this->expectExceptionMessage('The type "object" of parameter "$any" is not supported as a command option. Only "string", "bool", "int", "float", "array" types are allowed.'); $command->getDefinition(); } @@ -322,13 +320,12 @@ public static function provideNonBinaryInputOptions(): \Generator /** * @dataProvider provideInvalidOptionDefinitions */ - public function testInvalidOptionDefinition(callable $code, string $expectedMessage) + public function testInvalidOptionDefinition(callable $code) { $command = new Command('foo'); $command->setCode($code); $this->expectException(LogicException::class); - $this->expectExceptionMessage($expectedMessage); $command->getDefinition(); } @@ -336,40 +333,31 @@ public function testInvalidOptionDefinition(callable $code, string $expectedMess public static function provideInvalidOptionDefinitions(): \Generator { yield 'no-default' => [ - function (#[Option] string $a) {}, - 'The option parameter "$a" must declare a default value.', + function (#[Option] string $a) {} ]; yield 'nullable-bool-default-true' => [ - function (#[Option] ?bool $a = true) {}, - 'The option parameter "$a" must not be nullable when it has a default boolean value.', + function (#[Option] ?bool $a = true) {} ]; yield 'nullable-bool-default-false' => [ - function (#[Option] ?bool $a = false) {}, - 'The option parameter "$a" must not be nullable when it has a default boolean value.', + function (#[Option] ?bool $a = false) {} ]; yield 'invalid-union-type' => [ - function (#[Option] array|bool $a = false) {}, - 'The union type for parameter "$a" is not supported as a command option. Only "bool|string", "bool|int", "bool|float" types are allowed.', + function (#[Option] array|bool $a = false) {} ]; yield 'union-type-cannot-allow-null' => [ function (#[Option] string|bool|null $a = null) {}, - 'The union type for parameter "$a" is not supported as a command option. Only "bool|string", "bool|int", "bool|float" types are allowed.', ]; yield 'union-type-default-true' => [ function (#[Option] string|bool $a = true) {}, - 'The option parameter "$a" must have a default value of false.', ]; yield 'union-type-default-string' => [ function (#[Option] string|bool $a = 'foo') {}, - 'The option parameter "$a" must have a default value of false.', ]; yield 'nullable-string-not-null-default' => [ function (#[Option] ?string $a = 'foo') {}, - 'The option parameter "$a" must either be not-nullable or have a default of null.', ]; yield 'nullable-array-not-null-default' => [ function (#[Option] ?array $a = []) {}, - 'The option parameter "$a" must either be not-nullable or have a default of null.', ]; } From 73ebb399a55861ef3b069191fc4c4d7aecc74da9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20Andr=C3=A9?= Date: Sat, 24 May 2025 16:05:12 +0200 Subject: [PATCH 51/57] [AssetMapper] Fix SequenceParser possible infinite loop --- .../Parser/JavascriptSequenceParser.php | 41 +++++++++---------- .../Parser/JavascriptSequenceParserTest.php | 5 +++ 2 files changed, 25 insertions(+), 21 deletions(-) diff --git a/src/Symfony/Component/AssetMapper/Compiler/Parser/JavascriptSequenceParser.php b/src/Symfony/Component/AssetMapper/Compiler/Parser/JavascriptSequenceParser.php index 943c0eea14f51..7531221a8e5ee 100644 --- a/src/Symfony/Component/AssetMapper/Compiler/Parser/JavascriptSequenceParser.php +++ b/src/Symfony/Component/AssetMapper/Compiler/Parser/JavascriptSequenceParser.php @@ -133,36 +133,35 @@ public function parseUntil(int $position): void continue; } - // Single-line string - if ('"' === $matchChar || "'" === $matchChar) { - if (false === $endPos = strpos($this->content, $matchChar, $matchPos + 1)) { - $this->endsWithSequence(self::STATE_STRING, $position); - - return; - } - while (false !== $endPos && '\\' == $this->content[$endPos - 1]) { - $endPos = strpos($this->content, $matchChar, $endPos + 1); + if ('"' === $matchChar || "'" === $matchChar || '`' === $matchChar) { + $endPos = $matchPos + 1; + while (false !== $endPos = strpos($this->content, $matchChar, $endPos)) { + $backslashes = 0; + $i = $endPos - 1; + while ($i >= 0 && $this->content[$i] === '\\') { + $backslashes++; + $i--; + } + + if (0 === $backslashes % 2) { + break; + } + + $endPos++; } - $this->cursor = min($endPos + 1, $position); - $this->setSequence(self::STATE_STRING, $endPos + 1); - continue; - } - - // Multi-line string - if ('`' === $matchChar) { - if (false === $endPos = strpos($this->content, $matchChar, $matchPos + 1)) { + if (false === $endPos) { $this->endsWithSequence(self::STATE_STRING, $position); - return; } - while (false !== $endPos && '\\' == $this->content[$endPos - 1]) { - $endPos = strpos($this->content, $matchChar, $endPos + 1); - } $this->cursor = min($endPos + 1, $position); $this->setSequence(self::STATE_STRING, $endPos + 1); + continue; } + + // Fallback + $this->cursor = $matchPos + 1; } } diff --git a/src/Symfony/Component/AssetMapper/Tests/Compiler/Parser/JavascriptSequenceParserTest.php b/src/Symfony/Component/AssetMapper/Tests/Compiler/Parser/JavascriptSequenceParserTest.php index cd9c88ff72593..794b7bbf61d94 100644 --- a/src/Symfony/Component/AssetMapper/Tests/Compiler/Parser/JavascriptSequenceParserTest.php +++ b/src/Symfony/Component/AssetMapper/Tests/Compiler/Parser/JavascriptSequenceParserTest.php @@ -230,5 +230,10 @@ public static function provideStringCases(): iterable 3, false, ]; + yield 'after unclosed string' => [ + '"hello', + 6, + true, + ]; } } From 9fbc6a4914bfef64b02ae157f6310f643fe00faa Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 24 May 2025 16:28:13 +0200 Subject: [PATCH 52/57] [Uid] Remove InvalidU*idException in favor of InvalidArgumentException --- .../Uid/Exception/InvalidUlidException.php | 20 ----------------- .../Uid/Exception/InvalidUuidException.php | 22 ------------------- src/Symfony/Component/Uid/Tests/UlidTest.php | 3 +-- src/Symfony/Component/Uid/Ulid.php | 3 +-- src/Symfony/Component/Uid/Uuid.php | 6 ++--- 5 files changed, 5 insertions(+), 49 deletions(-) delete mode 100644 src/Symfony/Component/Uid/Exception/InvalidUlidException.php delete mode 100644 src/Symfony/Component/Uid/Exception/InvalidUuidException.php diff --git a/src/Symfony/Component/Uid/Exception/InvalidUlidException.php b/src/Symfony/Component/Uid/Exception/InvalidUlidException.php deleted file mode 100644 index cfb42ac5867a7..0000000000000 --- a/src/Symfony/Component/Uid/Exception/InvalidUlidException.php +++ /dev/null @@ -1,20 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Uid\Exception; - -class InvalidUlidException extends InvalidArgumentException -{ - public function __construct(string $value) - { - parent::__construct(\sprintf('Invalid ULID: "%s".', $value)); - } -} diff --git a/src/Symfony/Component/Uid/Exception/InvalidUuidException.php b/src/Symfony/Component/Uid/Exception/InvalidUuidException.php deleted file mode 100644 index 97009412b9c63..0000000000000 --- a/src/Symfony/Component/Uid/Exception/InvalidUuidException.php +++ /dev/null @@ -1,22 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Uid\Exception; - -class InvalidUuidException extends InvalidArgumentException -{ - public function __construct( - public readonly int $type, - string $value, - ) { - parent::__construct(\sprintf('Invalid UUID%s: "%s".', $type ? 'v'.$type : '', $value)); - } -} diff --git a/src/Symfony/Component/Uid/Tests/UlidTest.php b/src/Symfony/Component/Uid/Tests/UlidTest.php index fe1e15b4cedde..f34660fbfd393 100644 --- a/src/Symfony/Component/Uid/Tests/UlidTest.php +++ b/src/Symfony/Component/Uid/Tests/UlidTest.php @@ -13,7 +13,6 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Uid\Exception\InvalidArgumentException; -use Symfony\Component\Uid\Exception\InvalidUlidException; use Symfony\Component\Uid\MaxUlid; use Symfony\Component\Uid\NilUlid; use Symfony\Component\Uid\Tests\Fixtures\CustomUlid; @@ -43,7 +42,7 @@ public function testGenerate() public function testWithInvalidUlid() { - $this->expectException(InvalidUlidException::class); + $this->expectException(InvalidArgumentException::class); $this->expectExceptionMessage('Invalid ULID: "this is not a ulid".'); new Ulid('this is not a ulid'); diff --git a/src/Symfony/Component/Uid/Ulid.php b/src/Symfony/Component/Uid/Ulid.php index 9170d429b0eb7..5ea3b84051880 100644 --- a/src/Symfony/Component/Uid/Ulid.php +++ b/src/Symfony/Component/Uid/Ulid.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Uid; use Symfony\Component\Uid\Exception\InvalidArgumentException; -use Symfony\Component\Uid\Exception\InvalidUlidException; /** * A ULID is lexicographically sortable and contains a 48-bit timestamp and 80-bit of crypto-random entropy. @@ -39,7 +38,7 @@ public function __construct(?string $ulid = null) $this->uid = $ulid; } else { if (!self::isValid($ulid)) { - throw new InvalidUlidException($ulid); + throw new InvalidArgumentException(\sprintf('Invalid ULID: "%s".', $ulid)); } $this->uid = strtoupper($ulid); diff --git a/src/Symfony/Component/Uid/Uuid.php b/src/Symfony/Component/Uid/Uuid.php index 66717f2ca1d2e..e1c9735ee85fe 100644 --- a/src/Symfony/Component/Uid/Uuid.php +++ b/src/Symfony/Component/Uid/Uuid.php @@ -11,7 +11,7 @@ namespace Symfony\Component\Uid; -use Symfony\Component\Uid\Exception\InvalidUuidException; +use Symfony\Component\Uid\Exception\InvalidArgumentException; /** * @author Grégoire Pineau @@ -41,13 +41,13 @@ public function __construct(string $uuid, bool $checkVariant = false) $type = preg_match('{^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$}Di', $uuid) ? (int) $uuid[14] : false; if (false === $type || (static::TYPE ?: $type) !== $type) { - throw new InvalidUuidException(static::TYPE, $uuid); + throw new InvalidArgumentException(\sprintf('Invalid UUID%s: "%s".', static::TYPE ? 'v'.static::TYPE : '', $uuid)); } $this->uid = strtolower($uuid); if ($checkVariant && !\in_array($this->uid[19], ['8', '9', 'a', 'b'], true)) { - throw new InvalidUuidException(static::TYPE, $uuid); + throw new InvalidArgumentException(\sprintf('Invalid UUID%s: "%s".', static::TYPE ? 'v'.static::TYPE : '', $uuid)); } } From d775dde53475c95f17645436dadcb6df0b0d91cd Mon Sep 17 00:00:00 2001 From: HypeMC Date: Sat, 24 May 2025 22:22:45 +0200 Subject: [PATCH 53/57] [Routing] Fix inline default `null` --- src/Symfony/Component/Routing/Route.php | 2 +- .../Component/Routing/Tests/RouteTest.php | 71 +++++++++++-------- 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/src/Symfony/Component/Routing/Route.php b/src/Symfony/Component/Routing/Route.php index 1ed484f71237b..621a4239fcf7a 100644 --- a/src/Symfony/Component/Routing/Route.php +++ b/src/Symfony/Component/Routing/Route.php @@ -420,7 +420,7 @@ private function extractInlineDefaultsAndRequirements(string $pattern): string $pattern = preg_replace_callback('#\{(!?)([\w\x80-\xFF]++)(:([\w\x80-\xFF]++)(\.[\w\x80-\xFF]++)?)?(<.*?>)?(\?[^\}]*+)?\}#', function ($m) use (&$mapping) { if (isset($m[7][0])) { - $this->setDefault($m[2], '?' !== $m[6] ? substr($m[7], 1) : null); + $this->setDefault($m[2], '?' !== $m[7] ? substr($m[7], 1) : null); } if (isset($m[6][0])) { $this->setRequirement($m[2], substr($m[6], 1, -1)); diff --git a/src/Symfony/Component/Routing/Tests/RouteTest.php b/src/Symfony/Component/Routing/Tests/RouteTest.php index b58358a3ef31b..3472804249f57 100644 --- a/src/Symfony/Component/Routing/Tests/RouteTest.php +++ b/src/Symfony/Component/Routing/Tests/RouteTest.php @@ -226,37 +226,48 @@ public function testSerialize() $this->assertNotSame($route, $unserialized); } - public function testInlineDefaultAndRequirement() + /** + * @dataProvider provideInlineDefaultAndRequirementCases + */ + public function testInlineDefaultAndRequirement(Route $route, string $expectedPath, string $expectedHost, array $expectedDefaults, array $expectedRequirements) + { + self::assertSame($expectedPath, $route->getPath()); + self::assertSame($expectedHost, $route->getHost()); + self::assertSame($expectedDefaults, $route->getDefaults()); + self::assertSame($expectedRequirements, $route->getRequirements()); + } + + public static function provideInlineDefaultAndRequirementCases(): iterable { - $this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', null), new Route('/foo/{bar?}')); - $this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', 'baz'), new Route('/foo/{bar?baz}')); - $this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', 'baz'), new Route('/foo/{bar?baz}')); - $this->assertEquals((new Route('/foo/{!bar}'))->setDefault('bar', 'baz'), new Route('/foo/{!bar?baz}')); - $this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', 'baz'), new Route('/foo/{bar?}', ['bar' => 'baz'])); - - $this->assertEquals((new Route('/foo/{bar}'))->setRequirement('bar', '.*'), new Route('/foo/{bar<.*>}')); - $this->assertEquals((new Route('/foo/{bar}'))->setRequirement('bar', '>'), new Route('/foo/{bar<>>}')); - $this->assertEquals((new Route('/foo/{bar}'))->setRequirement('bar', '\d+'), new Route('/foo/{bar<.*>}', [], ['bar' => '\d+'])); - $this->assertEquals((new Route('/foo/{bar}'))->setRequirement('bar', '[a-z]{2}'), new Route('/foo/{bar<[a-z]{2}>}')); - $this->assertEquals((new Route('/foo/{!bar}'))->setRequirement('bar', '\d+'), new Route('/foo/{!bar<\d+>}')); - - $this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', null)->setRequirement('bar', '.*'), new Route('/foo/{bar<.*>?}')); - $this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', '<>')->setRequirement('bar', '>'), new Route('/foo/{bar<>>?<>}')); - - $this->assertEquals((new Route('/{foo}/{!bar}'))->setDefaults(['bar' => '<>', 'foo' => '\\'])->setRequirements(['bar' => '\\', 'foo' => '.']), new Route('/{foo<.>?\}/{!bar<\>?<>}')); - - $this->assertEquals((new Route('/'))->setHost('{bar}')->setDefault('bar', null), (new Route('/'))->setHost('{bar?}')); - $this->assertEquals((new Route('/'))->setHost('{bar}')->setDefault('bar', 'baz'), (new Route('/'))->setHost('{bar?baz}')); - $this->assertEquals((new Route('/'))->setHost('{bar}')->setDefault('bar', 'baz'), (new Route('/'))->setHost('{bar?baz}')); - $this->assertEquals((new Route('/'))->setHost('{bar}')->setDefault('bar', null), (new Route('/', ['bar' => 'baz']))->setHost('{bar?}')); - - $this->assertEquals((new Route('/'))->setHost('{bar}')->setRequirement('bar', '.*'), (new Route('/'))->setHost('{bar<.*>}')); - $this->assertEquals((new Route('/'))->setHost('{bar}')->setRequirement('bar', '>'), (new Route('/'))->setHost('{bar<>>}')); - $this->assertEquals((new Route('/'))->setHost('{bar}')->setRequirement('bar', '.*'), (new Route('/', [], ['bar' => '\d+']))->setHost('{bar<.*>}')); - $this->assertEquals((new Route('/'))->setHost('{bar}')->setRequirement('bar', '[a-z]{2}'), (new Route('/'))->setHost('{bar<[a-z]{2}>}')); - - $this->assertEquals((new Route('/'))->setHost('{bar}')->setDefault('bar', null)->setRequirement('bar', '.*'), (new Route('/'))->setHost('{bar<.*>?}')); - $this->assertEquals((new Route('/'))->setHost('{bar}')->setDefault('bar', '<>')->setRequirement('bar', '>'), (new Route('/'))->setHost('{bar<>>?<>}')); + yield [new Route('/foo/{bar?}'), '/foo/{bar}', '', ['bar' => null], []]; + yield [new Route('/foo/{bar?baz}'), '/foo/{bar}', '', ['bar' => 'baz'], []]; + yield [new Route('/foo/{bar?baz}'), '/foo/{bar}', '', ['bar' => 'baz'], []]; + yield [new Route('/foo/{!bar?baz}'), '/foo/{!bar}', '', ['bar' => 'baz'], []]; + yield [new Route('/foo/{bar?}', ['bar' => 'baz']), '/foo/{bar}', '', ['bar' => 'baz'], []]; + + yield [new Route('/foo/{bar<.*>}'), '/foo/{bar}', '', [], ['bar' => '.*']]; + yield [new Route('/foo/{bar<>>}'), '/foo/{bar}', '', [], ['bar' => '>']]; + yield [new Route('/foo/{bar<.*>}', [], ['bar' => '\d+']), '/foo/{bar}', '', [], ['bar' => '\d+']]; + yield [new Route('/foo/{bar<[a-z]{2}>}'), '/foo/{bar}', '', [], ['bar' => '[a-z]{2}']]; + yield [new Route('/foo/{!bar<\d+>}'), '/foo/{!bar}', '', [], ['bar' => '\d+']]; + + yield [new Route('/foo/{bar<.*>?}'), '/foo/{bar}', '', ['bar' => null], ['bar' => '.*']]; + yield [new Route('/foo/{bar<>>?<>}'), '/foo/{bar}', '', ['bar' => '<>'], ['bar' => '>']]; + + yield [new Route('/{foo<.>?\}/{!bar<\>?<>}'), '/{foo}/{!bar}', '', ['foo' => '\\', 'bar' => '<>'], ['foo' => '.', 'bar' => '\\']]; + + yield [new Route('/', host: '{bar?}'), '/', '{bar}', ['bar' => null], []]; + yield [new Route('/', host: '{bar?baz}'), '/', '{bar}', ['bar' => 'baz'], []]; + yield [new Route('/', host: '{bar?baz}'), '/', '{bar}', ['bar' => 'baz'], []]; + yield [new Route('/', ['bar' => 'baz'], host: '{bar?}'), '/', '{bar}', ['bar' => null], []]; + + yield [new Route('/', host: '{bar<.*>}'), '/', '{bar}', [], ['bar' => '.*']]; + yield [new Route('/', host: '{bar<>>}'), '/', '{bar}', [], ['bar' => '>']]; + yield [new Route('/', [], ['bar' => '\d+'], host: '{bar<.*>}'), '/', '{bar}', [], ['bar' => '.*']]; + yield [new Route('/', host: '{bar<[a-z]{2}>}'), '/', '{bar}', [], ['bar' => '[a-z]{2}']]; + + yield [new Route('/', host: '{bar<.*>?}'), '/', '{bar}', ['bar' => null], ['bar' => '.*']]; + yield [new Route('/', host: '{bar<>>?<>}'), '/', '{bar}', ['bar' => '<>'], ['bar' => '>']]; } /** From 71528ca67f15bb43456fef36118cb161063c9839 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 24 May 2025 23:27:21 +0200 Subject: [PATCH 54/57] conflict with 7.4 releases of experimental components --- src/Symfony/Bundle/FrameworkBundle/composer.json | 1 + src/Symfony/Component/JsonPath/composer.json | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 316c595ffa2bb..15a9496d11067 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -94,6 +94,7 @@ "symfony/mailer": "<6.4", "symfony/messenger": "<6.4", "symfony/mime": "<6.4", + "symfony/object-mapper": ">=7.4", "symfony/property-info": "<6.4", "symfony/property-access": "<6.4", "symfony/runtime": "<6.4.13|>=7.0,<7.1.6", diff --git a/src/Symfony/Component/JsonPath/composer.json b/src/Symfony/Component/JsonPath/composer.json index 95b02675e7459..fe8ddf84dd82d 100644 --- a/src/Symfony/Component/JsonPath/composer.json +++ b/src/Symfony/Component/JsonPath/composer.json @@ -20,7 +20,10 @@ "symfony/polyfill-mbstring": "~1.0" }, "require-dev": { - "symfony/json-streamer": "^7.3" + "symfony/json-streamer": "7.3.*" + }, + "conflict": { + "symfony/json-streamer": ">=7.4" }, "autoload": { "psr-4": { "Symfony\\Component\\JsonPath\\": "" }, From 5972d989e2942e43faad54a3608a54ff146a3d5a Mon Sep 17 00:00:00 2001 From: HypeMC Date: Sun, 25 May 2025 03:39:50 +0200 Subject: [PATCH 55/57] [DoctrineBridge] Fix resetting the manager when using native lazy objects --- .../Bridge/Doctrine/ManagerRegistry.php | 42 ++++++++----- .../Doctrine/Tests/Fixtures/DummyManager.php | 13 ++++ .../Doctrine/Tests/ManagerRegistryTest.php | 62 +++++++++++++++++-- 3 files changed, 99 insertions(+), 18 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/ManagerRegistry.php b/src/Symfony/Bridge/Doctrine/ManagerRegistry.php index a533b3bb8d12c..fa4d88b99455d 100644 --- a/src/Symfony/Bridge/Doctrine/ManagerRegistry.php +++ b/src/Symfony/Bridge/Doctrine/ManagerRegistry.php @@ -80,21 +80,35 @@ function (&$wrappedInstance, LazyLoadingInterface $manager) use ($name) { return; } - try { - $r->resetAsLazyProxy($manager, \Closure::bind( - function () use ($name) { - $name = $this->aliases[$name] ?? $name; + $asProxy = $r->initializeLazyObject($manager) !== $manager; + $initializer = \Closure::bind( + function ($manager) use ($name, $asProxy) { + $name = $this->aliases[$name] ?? $name; + if ($asProxy) { + $manager = false; + } + + $manager = match (true) { + isset($this->fileMap[$name]) => $this->load($this->fileMap[$name], $manager), + !$method = $this->methodMap[$name] ?? null => throw new \LogicException(\sprintf('The "%s" service is synthetic and cannot be reset.', $name)), + (new \ReflectionMethod($this, $method))->isStatic() => $this->{$method}($this, $manager), + default => $this->{$method}($manager), + }; + + if ($asProxy) { + return $manager; + } + }, + $this->container, + Container::class + ); - return match (true) { - isset($this->fileMap[$name]) => $this->load($this->fileMap[$name], false), - !$method = $this->methodMap[$name] ?? null => throw new \LogicException(\sprintf('The "%s" service is synthetic and cannot be reset.', $name)), - (new \ReflectionMethod($this, $method))->isStatic() => $this->{$method}($this, false), - default => $this->{$method}(false), - }; - }, - $this->container, - Container::class - )); + try { + if ($asProxy) { + $r->resetAsLazyProxy($manager, $initializer); + } else { + $r->resetAsLazyGhost($manager, $initializer); + } } catch (\Error $e) { if (__FILE__ !== $e->getFile()) { throw $e; diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/DummyManager.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/DummyManager.php index 04e5a2acdd334..806ef032d8d5c 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/DummyManager.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/DummyManager.php @@ -1,5 +1,14 @@ + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + namespace Symfony\Bridge\Doctrine\Tests\Fixtures; use Doctrine\Persistence\Mapping\ClassMetadata; @@ -11,6 +20,10 @@ class DummyManager implements ObjectManager { public $bar; + public function __construct() + { + } + public function find($className, $id): ?object { } diff --git a/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php b/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php index fa44ba0a00bbb..4803e6acaf0af 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php @@ -22,7 +22,7 @@ class ManagerRegistryTest extends TestCase { - public static function setUpBeforeClass(): void + public function testResetService() { $container = new ContainerBuilder(); @@ -32,10 +32,7 @@ public static function setUpBeforeClass(): void $dumper = new PhpDumper($container); eval('?>'.$dumper->dump(['class' => 'LazyServiceDoctrineBridgeContainer'])); - } - public function testResetService() - { $container = new \LazyServiceDoctrineBridgeContainer(); $registry = new TestManagerRegistry('name', [], ['defaultManager' => 'foo'], 'defaultConnection', 'defaultManager', 'proxyInterfaceName'); @@ -52,6 +49,63 @@ public function testResetService() $this->assertFalse(isset($foo->bar)); } + /** + * @requires PHP 8.4 + * + * @dataProvider provideResetServiceWithNativeLazyObjectsCases + */ + public function testResetServiceWithNativeLazyObjects(string $class) + { + $container = new $class(); + + $registry = new TestManagerRegistry( + 'irrelevant', + [], + ['defaultManager' => 'foo'], + 'irrelevant', + 'defaultManager', + 'irrelevant', + ); + $registry->setTestContainer($container); + + $foo = $container->get('foo'); + self::assertSame(DummyManager::class, $foo::class); + + $foo->bar = 123; + self::assertTrue(isset($foo->bar)); + + $registry->resetManager(); + + self::assertSame($foo, $container->get('foo')); + self::assertSame(DummyManager::class, $foo::class); + self::assertFalse(isset($foo->bar)); + } + + public static function provideResetServiceWithNativeLazyObjectsCases(): iterable + { + $container = new ContainerBuilder(); + + $container->register('foo', DummyManager::class)->setPublic(true); + $container->getDefinition('foo')->setLazy(true); + $container->compile(); + + $dumper = new PhpDumper($container); + + eval('?>'.$dumper->dump(['class' => 'NativeLazyServiceDoctrineBridgeContainer'])); + + yield ['NativeLazyServiceDoctrineBridgeContainer']; + + $dumps = $dumper->dump(['class' => 'NativeLazyServiceDoctrineBridgeContainerAsFiles', 'as_files' => true]); + + $lastDump = array_pop($dumps); + foreach (array_reverse($dumps) as $dump) { + eval('?>'.$dump); + } + eval('?>'.$lastDump); + + yield ['NativeLazyServiceDoctrineBridgeContainerAsFiles']; + } + /** * When performing an entity manager lazy service reset, the reset operations may re-use the container * to create a "fresh" service: when doing so, it can happen that the "fresh" service is itself a proxy. From a3d3dff6229fd37fce8fedbd9189c6dcd77d3d2f Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 25 May 2025 22:29:28 +0200 Subject: [PATCH 56/57] Update CHANGELOG for 7.3.0-RC1 --- CHANGELOG-7.3.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/CHANGELOG-7.3.md b/CHANGELOG-7.3.md index b88c6a58f068c..91adc8732cd35 100644 --- a/CHANGELOG-7.3.md +++ b/CHANGELOG-7.3.md @@ -7,6 +7,36 @@ in 7.3 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v7.3.0...v7.3.1 +* 7.3.0-RC1 (2025-05-25) + + * bug #60529 [AssetMapper] Fix SequenceParser possible infinite loop (smnandre) + * bug #60532 [Routing] Fix inline default `null` (HypeMC) + * bug #60535 [DoctrineBridge] Fix resetting the manager when using native lazy objects (HypeMC) + * bug #60500 [PhpUnitBridge] Fix cleaning up mocked features with attributes (HypeMC) + * bug #60330 [FrameworkBundle] skip messenger deduplication middleware registration when no "default" lock is configured (lyrixx) + * bug #60494 [Messenger] fix: Add argument as integer (overexpOG) + * bug #60524 [Notifier] Fix Clicksend transport (BafS) + * bug #60479 [FrameworkBundle] object mapper service definition without form (soyuka) + * bug #60478 [Validator] add missing `$extensions` and `$extensionsMessage` to the `Image` constraint (xabbuh) + * bug #60491 [ObjectMapper] added earlier skip to allow if=false when using source mapping (maciekpaprocki) + * bug #60484 [PhpUnitBridge] Clean up mocked features only when ``@group`` is present (HypeMC) + * bug #60490 [PhpUnitBridge] set path to the PHPUnit autoload file (xabbuh) + * bug #60489 [FrameworkBundle] Fix activation strategy of traceable decorators (nicolas-grekas) + * feature #60475 [Validator] Revert Slug constraint (wouterj) + * feature #60105 [JsonPath] Add `JsonPathAssertionsTrait` and related constraints (alexandre-daubois) + * bug #60423 [DependencyInjection] Make `DefinitionErrorExceptionPass` consider `IGNORE_ON_UNINITIALIZED_REFERENCE` and `RUNTIME_EXCEPTION_ON_INVALID_REFERENCE` the same (MatTheCat) + * bug #60439 [FrameworkBundle] Fix declaring field-attr tags in xml config files (nicolas-grekas) + * bug #60428 [DependencyInjection] Fix missing binding for ServiceCollectionInterface when declaring a service subscriber (nicolas-grekas) + * bug #60426 [Validator] let the `SlugValidator` accept `AsciiSlugger` results (xabbuh) + * bug #60421 [VarExporter] Fixed lazy-loading ghost objects generation with property hooks (cheack) + * bug #60419 [SecurityBundle] normalize string values to a single ExposeSecurityLevel instance (xabbuh) + * bug #60266 [Security] Exclude remember_me from default login authenticators (santysisi) + * bug #60407 [Console] Invokable command `#[Option]` adjustments (kbond) + * bug #60400 [Config] Fix generated comment for multiline "info" (GromNaN) + * bug #60260 [Serializer] Prevent `Cannot traverse an already closed generator` error by materializing Traversable input (santysisi) + * bug #60292 [HttpFoundation] Encode path in `X-Accel-Redirect` header (Athorcis) + * bug #60401 Passing more than one Security attribute is not supported (santysisi) + * 7.3.0-BETA2 (2025-05-10) * bug #58643 [SecurityBundle] Use Composer `InstalledVersions` to check if flex is installed (andyexeter) From f3605bbc8887af1221798b1dc7173c49d5d980aa Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 25 May 2025 22:29:38 +0200 Subject: [PATCH 57/57] Update VERSION for 7.3.0-RC1 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index b5a41236d1899..566e721bf3bb3 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -73,12 +73,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static array $freshCache = []; - public const VERSION = '7.3.0-DEV'; + public const VERSION = '7.3.0-RC1'; public const VERSION_ID = 70300; public const MAJOR_VERSION = 7; public const MINOR_VERSION = 3; public const RELEASE_VERSION = 0; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = 'RC1'; public const END_OF_MAINTENANCE = '05/2025'; public const END_OF_LIFE = '01/2026';