diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index 5f2d77a453eaf..d4dafb2aa0029 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,6 +1,6 @@
| Q | A
| ------------- | ---
-| Branch? | 7.3 for features / 6.4, and 7.2 for bug fixes
+| Branch? | 7.4 for features / 6.4, 7.2, or 7.3 for bug fixes
| Bug fix? | yes/no
| New feature? | yes/no
| Deprecations? | yes/no
diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
index a82202d055cc9..1033e761a2d0b 100644
--- a/.github/workflows/scorecards.yml
+++ b/.github/workflows/scorecards.yml
@@ -6,7 +6,7 @@ on:
schedule:
- cron: '34 4 * * 6'
push:
- branches: [ "7.3" ]
+ branches: [ "7.4" ]
# Declare default permissions as read only.
permissions: read-all
diff --git a/CHANGELOG-7.3.md b/CHANGELOG-7.3.md
index 91adc8732cd35..bee0295a98485 100644
--- a/CHANGELOG-7.3.md
+++ b/CHANGELOG-7.3.md
@@ -7,6 +7,12 @@ 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 (2025-05-29)
+
+ * bug #60549 [Translation] Add intl-icu fallback for MessageCatalogue metadata (pontus-mp)
+ * bug #60571 [ErrorHandler] Do not transform file to link if it does not exist (lyrixx)
+ * bug #60542 [Webhook] Fix controller service name (HypeMC)
+
* 7.3.0-RC1 (2025-05-25)
* bug #60529 [AssetMapper] Fix SequenceParser possible infinite loop (smnandre)
diff --git a/UPGRADE-7.3.md b/UPGRADE-7.3.md
index 77a3f14c3445b..5c279372b7626 100644
--- a/UPGRADE-7.3.md
+++ b/UPGRADE-7.3.md
@@ -179,9 +179,7 @@ Security
```php
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token, ?Vote $vote = null): bool
{
- $vote ??= new Vote();
-
- $vote->reasons[] = 'A brief explanation of why access is granted or denied, as appropriate.';
+ $vote?->addReason('A brief explanation of why access is granted or denied, as appropriate.');
}
```
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing/webhook.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing/webhook.php
index ea80311599fa0..177606b26214e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing/webhook.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/routing/webhook.php
@@ -24,7 +24,7 @@
}
$routes->add('_webhook_controller', '/{type}')
- ->controller('webhook_controller::handle')
+ ->controller('webhook.controller::handle')
->requirements(['type' => '.+'])
;
};
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_multiple_buses_without_deduplicate_middleware.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_multiple_buses_without_deduplicate_middleware.php
index b8e7530bb3e01..fd4a008341cb4 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_multiple_buses_without_deduplicate_middleware.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/messenger_multiple_buses_without_deduplicate_middleware.php
@@ -5,6 +5,7 @@
'http_method_override' => false,
'handle_all_throwables' => true,
'php_errors' => ['log' => true],
+ 'lock' => false,
'messenger' => [
'default_bus' => 'messenger.bus.commands',
'buses' => [
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_multiple_buses_without_deduplicate_middleware.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_multiple_buses_without_deduplicate_middleware.xml
index dcf402e1a36ec..3f0d96249959e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_multiple_buses_without_deduplicate_middleware.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/messenger_multiple_buses_without_deduplicate_middleware.xml
@@ -8,6 +8,7 @@
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_multiple_buses_without_deduplicate_middleware.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_multiple_buses_without_deduplicate_middleware.yml
index f06d534a55ec2..38fca57379fcb 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_multiple_buses_without_deduplicate_middleware.yml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/messenger_multiple_buses_without_deduplicate_middleware.yml
@@ -4,6 +4,7 @@ framework:
handle_all_throwables: true
php_errors:
log: true
+ lock: false
messenger:
default_bus: messenger.bus.commands
buses:
diff --git a/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php b/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php
index d0d1246a1ddbd..7bd9a083e53a4 100644
--- a/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php
+++ b/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php
@@ -233,6 +233,10 @@ private function formatFile(string $file, int $line, ?string $text = null): stri
$text .= ' at line '.$line;
}
+ if (!file_exists($file)) {
+ return $text;
+ }
+
$link = $this->fileLinkFormat->format($file, $line);
return \sprintf('%s ', $this->escape($link), $text);
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index 566e721bf3bb3..bfef40fac58ad 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-RC1';
+ public const VERSION = '7.3.0';
public const VERSION_ID = 70300;
public const MAJOR_VERSION = 7;
public const MINOR_VERSION = 3;
public const RELEASE_VERSION = 0;
- public const EXTRA_VERSION = 'RC1';
+ public const EXTRA_VERSION = '';
public const END_OF_MAINTENANCE = '05/2025';
public const END_OF_LIFE = '01/2026';
diff --git a/src/Symfony/Component/ObjectMapper/composer.json b/src/Symfony/Component/ObjectMapper/composer.json
index eb89582d8aad6..6d1b445d92781 100644
--- a/src/Symfony/Component/ObjectMapper/composer.json
+++ b/src/Symfony/Component/ObjectMapper/composer.json
@@ -32,5 +32,6 @@
},
"conflict": {
"symfony/property-access": "<7.2"
- }
+ },
+ "minimum-stability": "dev"
}
diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/AuthenticatedVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/AuthenticatedVoter.php
index 1403aaaaf0b15..3ab6b92c1d956 100644
--- a/src/Symfony/Component/Security/Core/Authorization/Voter/AuthenticatedVoter.php
+++ b/src/Symfony/Component/Security/Core/Authorization/Voter/AuthenticatedVoter.php
@@ -45,11 +45,10 @@ public function __construct(
*/
public function vote(TokenInterface $token, mixed $subject, array $attributes/* , ?Vote $vote = null */): int
{
- $vote = 3 < \func_num_args() ? func_get_arg(3) : new Vote();
- $vote ??= new Vote();
+ $vote = 3 < \func_num_args() ? func_get_arg(3) : null;
if ($attributes === [self::PUBLIC_ACCESS]) {
- $vote->reasons[] = 'Access is public.';
+ $vote?->addReason('Access is public.');
return VoterInterface::ACCESS_GRANTED;
}
@@ -73,7 +72,7 @@ public function vote(TokenInterface $token, mixed $subject, array $attributes/*
if ((self::IS_AUTHENTICATED_FULLY === $attribute || self::IS_AUTHENTICATED_REMEMBERED === $attribute)
&& $this->authenticationTrustResolver->isFullFledged($token)
) {
- $vote->reasons[] = 'The user is fully authenticated.';
+ $vote?->addReason('The user is fully authenticated.');
return VoterInterface::ACCESS_GRANTED;
}
@@ -81,32 +80,32 @@ public function vote(TokenInterface $token, mixed $subject, array $attributes/*
if (self::IS_AUTHENTICATED_REMEMBERED === $attribute
&& $this->authenticationTrustResolver->isRememberMe($token)
) {
- $vote->reasons[] = 'The user is remembered.';
+ $vote?->addReason('The user is remembered.');
return VoterInterface::ACCESS_GRANTED;
}
if (self::IS_AUTHENTICATED === $attribute && $this->authenticationTrustResolver->isAuthenticated($token)) {
- $vote->reasons[] = 'The user is authenticated.';
+ $vote?->addReason('The user is authenticated.');
return VoterInterface::ACCESS_GRANTED;
}
if (self::IS_REMEMBERED === $attribute && $this->authenticationTrustResolver->isRememberMe($token)) {
- $vote->reasons[] = 'The user is remembered.';
+ $vote?->addReason('The user is remembered.');
return VoterInterface::ACCESS_GRANTED;
}
if (self::IS_IMPERSONATOR === $attribute && $token instanceof SwitchUserToken) {
- $vote->reasons[] = 'The user is impersonating another user.';
+ $vote?->addReason('The user is impersonating another user.');
return VoterInterface::ACCESS_GRANTED;
}
}
if (VoterInterface::ACCESS_DENIED === $result) {
- $vote->reasons[] = 'The user is not appropriately authenticated.';
+ $vote?->addReason('The user is not appropriately authenticated.');
}
return $result;
diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/ClosureVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/ClosureVoter.php
index 03a9f7571a571..4fb5502fd91c5 100644
--- a/src/Symfony/Component/Security/Core/Authorization/Voter/ClosureVoter.php
+++ b/src/Symfony/Component/Security/Core/Authorization/Voter/ClosureVoter.php
@@ -42,7 +42,6 @@ public function supportsType(string $subjectType): bool
public function vote(TokenInterface $token, mixed $subject, array $attributes, ?Vote $vote = null): int
{
- $vote ??= new Vote();
$context = new IsGrantedContext($token, $token->getUser(), $this->authorizationChecker);
$failingClosures = [];
$result = VoterInterface::ACCESS_ABSTAIN;
@@ -54,7 +53,7 @@ public function vote(TokenInterface $token, mixed $subject, array $attributes, ?
$name = (new \ReflectionFunction($attribute))->name;
$result = VoterInterface::ACCESS_DENIED;
if ($attribute($context, $subject)) {
- $vote->reasons[] = \sprintf('Closure %s returned true.', $name);
+ $vote?->addReason(\sprintf('Closure %s returned true.', $name));
return VoterInterface::ACCESS_GRANTED;
}
@@ -63,7 +62,7 @@ public function vote(TokenInterface $token, mixed $subject, array $attributes, ?
}
if ($failingClosures) {
- $vote->reasons[] = \sprintf('Closure%s %s returned false.', 1 < \count($failingClosures) ? 's' : '', implode(', ', $failingClosures));
+ $vote?->addReason(\sprintf('Closure%s %s returned false.', 1 < \count($failingClosures) ? 's' : '', implode(', ', $failingClosures)));
}
return $result;
diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php
index 35d727a8eb15e..719aae7d46872 100644
--- a/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php
+++ b/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php
@@ -49,8 +49,7 @@ public function supportsType(string $subjectType): bool
*/
public function vote(TokenInterface $token, mixed $subject, array $attributes/* , ?Vote $vote = null */): int
{
- $vote = 3 < \func_num_args() ? func_get_arg(3) : new Vote();
- $vote ??= new Vote();
+ $vote = 3 < \func_num_args() ? func_get_arg(3) : null;
$result = VoterInterface::ACCESS_ABSTAIN;
$variables = null;
$failingExpressions = [];
@@ -64,7 +63,7 @@ public function vote(TokenInterface $token, mixed $subject, array $attributes/*
$result = VoterInterface::ACCESS_DENIED;
if ($this->expressionLanguage->evaluate($attribute, $variables)) {
- $vote->reasons[] = \sprintf('Expression (%s) is true.', $attribute);
+ $vote?->addReason(\sprintf('Expression (%s) is true.', $attribute));
return VoterInterface::ACCESS_GRANTED;
}
@@ -73,7 +72,7 @@ public function vote(TokenInterface $token, mixed $subject, array $attributes/*
}
if ($failingExpressions) {
- $vote->reasons[] = \sprintf('Expression (%s) is false.', implode(') || (', $failingExpressions));
+ $vote?->addReason(\sprintf('Expression (%s) is false.', implode(') || (', $failingExpressions)));
}
return $result;
diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/RoleVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/RoleVoter.php
index 46c08d15b48ed..2225e8d4d4c41 100644
--- a/src/Symfony/Component/Security/Core/Authorization/Voter/RoleVoter.php
+++ b/src/Symfony/Component/Security/Core/Authorization/Voter/RoleVoter.php
@@ -30,8 +30,7 @@ public function __construct(
*/
public function vote(TokenInterface $token, mixed $subject, array $attributes/* , ?Vote $vote = null */): int
{
- $vote = 3 < \func_num_args() ? func_get_arg(3) : new Vote();
- $vote ??= new Vote();
+ $vote = 3 < \func_num_args() ? func_get_arg(3) : null;
$result = VoterInterface::ACCESS_ABSTAIN;
$roles = $this->extractRoles($token);
$missingRoles = [];
@@ -44,7 +43,7 @@ public function vote(TokenInterface $token, mixed $subject, array $attributes/*
$result = VoterInterface::ACCESS_DENIED;
if (\in_array($attribute, $roles, true)) {
- $vote->reasons[] = \sprintf('The user has %s.', $attribute);
+ $vote?->addReason(\sprintf('The user has %s.', $attribute));
return VoterInterface::ACCESS_GRANTED;
}
@@ -53,7 +52,7 @@ public function vote(TokenInterface $token, mixed $subject, array $attributes/*
}
if (VoterInterface::ACCESS_DENIED === $result) {
- $vote->reasons[] = \sprintf('The user doesn\'t have%s %s.', 1 < \count($missingRoles) ? ' any of' : '', implode(', ', $missingRoles));
+ $vote?->addReason(\sprintf('The user doesn\'t have%s %s.', 1 < \count($missingRoles) ? ' any of' : '', implode(', ', $missingRoles)));
}
return $result;
diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/TraceableVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/TraceableVoter.php
index 47572797ee906..ec92606359859 100644
--- a/src/Symfony/Component/Security/Core/Authorization/Voter/TraceableVoter.php
+++ b/src/Symfony/Component/Security/Core/Authorization/Voter/TraceableVoter.php
@@ -32,9 +32,9 @@ public function __construct(
public function vote(TokenInterface $token, mixed $subject, array $attributes, ?Vote $vote = null): int
{
- $result = $this->voter->vote($token, $subject, $attributes, $vote ??= new Vote());
+ $result = $this->voter->vote($token, $subject, $attributes, $vote);
- $this->eventDispatcher->dispatch(new VoteEvent($this->voter, $subject, $attributes, $result, $vote->reasons), 'debug.security.authorization.vote');
+ $this->eventDispatcher->dispatch(new VoteEvent($this->voter, $subject, $attributes, $result, $vote->reasons ?? []), 'debug.security.authorization.vote');
return $result;
}
diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php
index 3d7fd9e2d7a1f..55930def8fda9 100644
--- a/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php
+++ b/src/Symfony/Component/Security/Core/Authorization/Voter/Voter.php
@@ -29,10 +29,9 @@ abstract class Voter implements VoterInterface, CacheableVoterInterface
*/
public function vote(TokenInterface $token, mixed $subject, array $attributes/* , ?Vote $vote = null */): int
{
- $vote = 3 < \func_num_args() ? func_get_arg(3) : new Vote();
- $vote ??= new Vote();
+ $vote = 3 < \func_num_args() ? func_get_arg(3) : null;
// abstain vote by default in case none of the attributes are supported
- $vote->result = self::ACCESS_ABSTAIN;
+ $voteResult = self::ACCESS_ABSTAIN;
foreach ($attributes as $attribute) {
try {
@@ -48,15 +47,27 @@ public function vote(TokenInterface $token, mixed $subject, array $attributes/*
}
// as soon as at least one attribute is supported, default is to deny access
- $vote->result = self::ACCESS_DENIED;
+ $voteResult = self::ACCESS_DENIED;
+
+ if (null !== $vote) {
+ $vote->result = $voteResult;
+ }
if ($this->voteOnAttribute($attribute, $subject, $token, $vote)) {
// grant access as soon as at least one attribute returns a positive response
- return $vote->result = self::ACCESS_GRANTED;
+ if (null !== $vote) {
+ $vote->result = self::ACCESS_GRANTED;
+ }
+
+ return self::ACCESS_GRANTED;
}
}
- return $vote->result;
+ if (null !== $vote) {
+ $vote->result = $voteResult;
+ }
+
+ return $voteResult;
}
/**
diff --git a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/VoterTest.php b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/VoterTest.php
index a8f87e09da7e6..eaada3061dbfe 100644
--- a/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/VoterTest.php
+++ b/src/Symfony/Component/Security/Core/Tests/Authorization/Voter/VoterTest.php
@@ -33,35 +33,51 @@ public static function getTests(): array
return [
[$voter, ['EDIT'], VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if attribute and class are supported and attribute grants access'],
+ [$voter, ['EDIT'], VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if attribute and class are supported and attribute grants access', new Vote()],
[$voter, ['CREATE'], VoterInterface::ACCESS_DENIED, new \stdClass(), 'ACCESS_DENIED if attribute and class are supported and attribute does not grant access'],
+ [$voter, ['CREATE'], VoterInterface::ACCESS_DENIED, new \stdClass(), 'ACCESS_DENIED if attribute and class are supported and attribute does not grant access', new Vote()],
[$voter, ['DELETE', 'EDIT'], VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if one attribute is supported and grants access'],
+ [$voter, ['DELETE', 'EDIT'], VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if one attribute is supported and grants access', new Vote()],
[$voter, ['DELETE', 'CREATE'], VoterInterface::ACCESS_DENIED, new \stdClass(), 'ACCESS_DENIED if one attribute is supported and denies access'],
+ [$voter, ['DELETE', 'CREATE'], VoterInterface::ACCESS_DENIED, new \stdClass(), 'ACCESS_DENIED if one attribute is supported and denies access', new Vote()],
[$voter, ['CREATE', 'EDIT'], VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if one attribute grants access'],
+ [$voter, ['CREATE', 'EDIT'], VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if one attribute grants access', new Vote()],
[$voter, ['DELETE'], VoterInterface::ACCESS_ABSTAIN, new \stdClass(), 'ACCESS_ABSTAIN if no attribute is supported'],
+ [$voter, ['DELETE'], VoterInterface::ACCESS_ABSTAIN, new \stdClass(), 'ACCESS_ABSTAIN if no attribute is supported', new Vote()],
[$voter, ['EDIT'], VoterInterface::ACCESS_ABSTAIN, new class {}, 'ACCESS_ABSTAIN if class is not supported'],
+ [$voter, ['EDIT'], VoterInterface::ACCESS_ABSTAIN, new class {}, 'ACCESS_ABSTAIN if class is not supported', new Vote()],
[$voter, ['EDIT'], VoterInterface::ACCESS_ABSTAIN, null, 'ACCESS_ABSTAIN if object is null'],
+ [$voter, ['EDIT'], VoterInterface::ACCESS_ABSTAIN, null, 'ACCESS_ABSTAIN if object is null', new Vote()],
[$voter, [], VoterInterface::ACCESS_ABSTAIN, new \stdClass(), 'ACCESS_ABSTAIN if no attributes were provided'],
+ [$voter, [], VoterInterface::ACCESS_ABSTAIN, new \stdClass(), 'ACCESS_ABSTAIN if no attributes were provided', new Vote()],
[$voter, [new StringableAttribute()], VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if attribute and class are supported and attribute grants access'],
+ [$voter, [new StringableAttribute()], VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if attribute and class are supported and attribute grants access', new Vote()],
[$voter, [new \stdClass()], VoterInterface::ACCESS_ABSTAIN, new \stdClass(), 'ACCESS_ABSTAIN if attributes were not strings'],
+ [$voter, [new \stdClass()], VoterInterface::ACCESS_ABSTAIN, new \stdClass(), 'ACCESS_ABSTAIN if attributes were not strings', new Vote()],
[$integerVoter, [42], VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if attribute is an integer'],
+ [$integerVoter, [42], VoterInterface::ACCESS_GRANTED, new \stdClass(), 'ACCESS_GRANTED if attribute is an integer', new Vote()],
];
}
/**
* @dataProvider getTests
*/
- public function testVote(VoterInterface $voter, array $attributes, $expectedVote, $object, $message)
+ public function testVote(VoterInterface $voter, array $attributes, $expectedVote, $object, $message, ?Vote $vote = null)
{
- $this->assertEquals($expectedVote, $voter->vote($this->token, $object, $attributes), $message);
+ $this->assertSame($expectedVote, $voter->vote($this->token, $object, $attributes, $vote), $message);
+
+ if (null !== $vote) {
+ self::assertSame($expectedVote, $vote->result);
+ }
}
public function testVoteWithTypeError()
diff --git a/src/Symfony/Component/Security/Http/Tests/EventListener/IsGrantedAttributeListenerTest.php b/src/Symfony/Component/Security/Http/Tests/EventListener/IsGrantedAttributeListenerTest.php
index 73494f405468c..d34b31f2bdeb8 100644
--- a/src/Symfony/Component/Security/Http/Tests/EventListener/IsGrantedAttributeListenerTest.php
+++ b/src/Symfony/Component/Security/Http/Tests/EventListener/IsGrantedAttributeListenerTest.php
@@ -232,7 +232,7 @@ protected function supports(string $attribute, mixed $subject): bool
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token, ?Vote $vote = null): bool
{
- $vote->reasons[] = 'Because I can 😈.';
+ $vote?->addReason('Because I can 😈.');
return false;
}
diff --git a/src/Symfony/Component/Translation/MessageCatalogue.php b/src/Symfony/Component/Translation/MessageCatalogue.php
index 2d229f2dd1839..eac50bb1f9b9e 100644
--- a/src/Symfony/Component/Translation/MessageCatalogue.php
+++ b/src/Symfony/Component/Translation/MessageCatalogue.php
@@ -217,6 +217,16 @@ public function getMetadata(string $key = '', string $domain = 'messages'): mixe
return $this->metadata;
}
+ if (isset($this->metadata[$domain.self::INTL_DOMAIN_SUFFIX])) {
+ if ('' === $key) {
+ return $this->metadata[$domain.self::INTL_DOMAIN_SUFFIX];
+ }
+
+ if (isset($this->metadata[$domain.self::INTL_DOMAIN_SUFFIX][$key])) {
+ return $this->metadata[$domain.self::INTL_DOMAIN_SUFFIX][$key];
+ }
+ }
+
if (isset($this->metadata[$domain])) {
if ('' == $key) {
return $this->metadata[$domain];
diff --git a/src/Symfony/Component/Translation/Tests/Catalogue/MessageCatalogueTest.php b/src/Symfony/Component/Translation/Tests/Catalogue/MessageCatalogueTest.php
new file mode 100644
index 0000000000000..1ac61673999b2
--- /dev/null
+++ b/src/Symfony/Component/Translation/Tests/Catalogue/MessageCatalogueTest.php
@@ -0,0 +1,27 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Translation\Tests\Catalogue;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\Translation\MessageCatalogue;
+
+class MessageCatalogueTest extends TestCase
+{
+ public function testIcuMetadataKept()
+ {
+ $mc = new MessageCatalogue('en', ['messages' => ['a' => 'new_a']]);
+ $metadata = ['metadata' => 'value'];
+ $mc->setMetadata('a', $metadata, 'messages+intl-icu');
+ $this->assertEquals($metadata, $mc->getMetadata('a', 'messages'));
+ $this->assertEquals($metadata, $mc->getMetadata('a', 'messages+intl-icu'));
+ }
+}
diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf
index 0e0de772720c4..1781b1f29ec64 100644
--- a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf
+++ b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf
@@ -468,7 +468,7 @@
This value is not a valid Twig template.
- Deze waarde is geen geldige Twig-template.
+ Deze waarde is geen geldige Twig-template.
Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies:
Alternative Proxy
pFad Proxy
pFad v3 Proxy
pFad v4 Proxy