diff --git a/composer.json b/composer.json
index 7a8b32cf29e39..d64d859d766f2 100644
--- a/composer.json
+++ b/composer.json
@@ -124,13 +124,12 @@
"async-aws/sqs": "^1.0",
"async-aws/sns": "^1.0",
"cache/integration-tests": "dev-master",
- "composer/package-versions-deprecated": "^1.8",
"doctrine/annotations": "^1.13.1",
"doctrine/cache": "^1.11|^2.0",
"doctrine/collections": "~1.0",
"doctrine/data-fixtures": "^1.1",
"doctrine/dbal": "^2.13.1|^3.0",
- "doctrine/orm": "^2.7.3",
+ "doctrine/orm": "^2.7.4",
"guzzlehttp/promises": "^1.4",
"masterminds/html5": "^2.6",
"monolog/monolog": "^1.25.1|^2",
@@ -164,6 +163,12 @@
"ocramius/proxy-manager": "<2.1",
"phpunit/phpunit": "<5.4.3"
},
+ "config": {
+ "allow-plugins": {
+ "composer/package-versions-deprecated": true,
+ "symfony/runtime": true
+ }
+ },
"autoload": {
"psr-4": {
"Symfony\\Bridge\\Doctrine\\": "src/Symfony/Bridge/Doctrine/",
diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json
index f2e0d9520c4b4..7a4f5f0a18b7c 100644
--- a/src/Symfony/Bridge/Doctrine/composer.json
+++ b/src/Symfony/Bridge/Doctrine/composer.json
@@ -26,7 +26,6 @@
"symfony/service-contracts": "^1.1|^2|^3"
},
"require-dev": {
- "composer/package-versions-deprecated": "^1.8",
"symfony/stopwatch": "^4.4|^5.0|^6.0",
"symfony/cache": "^5.4|^6.0",
"symfony/config": "^4.4|^5.0|^6.0",
@@ -48,13 +47,13 @@
"doctrine/collections": "~1.0",
"doctrine/data-fixtures": "^1.1",
"doctrine/dbal": "^2.13.1|^3.0",
- "doctrine/orm": "^2.7.3",
+ "doctrine/orm": "^2.7.4"
"psr/log": "^1|^2|^3"
},
"conflict": {
"doctrine/dbal": "<2.13.1",
"doctrine/lexer": "<1.1",
- "doctrine/orm": "<2.7.3",
+ "doctrine/orm": "<2.7.4",
"phpunit/phpunit": "<5.4.3",
"symfony/cache": "<5.4",
"symfony/dependency-injection": "<4.4",
diff --git a/src/Symfony/Bridge/ProxyManager/composer.json b/src/Symfony/Bridge/ProxyManager/composer.json
index 68ec28540704d..58feb308356e4 100644
--- a/src/Symfony/Bridge/ProxyManager/composer.json
+++ b/src/Symfony/Bridge/ProxyManager/composer.json
@@ -17,7 +17,6 @@
],
"require": {
"php": ">=7.2.5",
- "composer/package-versions-deprecated": "^1.8",
"friendsofphp/proxy-manager-lts": "^1.0.2",
"symfony/dependency-injection": "^5.0|^6.0",
"symfony/polyfill-php80": "^1.16"
diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php
index 658854626b461..2821e10df8465 100644
--- a/src/Symfony/Component/HttpClient/CurlHttpClient.php
+++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php
@@ -439,8 +439,6 @@ private function validateExtraCurlOptions(array $options): void
\CURLOPT_INFILESIZE => 'body',
\CURLOPT_POSTFIELDS => 'body',
\CURLOPT_UPLOAD => 'body',
- \CURLOPT_PINNEDPUBLICKEY => 'peer_fingerprint',
- \CURLOPT_UNIX_SOCKET_PATH => 'bindto',
\CURLOPT_INTERFACE => 'bindto',
\CURLOPT_TIMEOUT_MS => 'max_duration',
\CURLOPT_TIMEOUT => 'max_duration',
@@ -463,6 +461,14 @@ private function validateExtraCurlOptions(array $options): void
\CURLOPT_PROGRESSFUNCTION => 'on_progress',
];
+ if (\defined('CURLOPT_UNIX_SOCKET_PATH')) {
+ $curloptsToConfig[\CURLOPT_UNIX_SOCKET_PATH] = 'bindto';
+ }
+
+ if (\defined('CURLOPT_PINNEDPUBLICKEY')) {
+ $curloptsToConfig[\CURLOPT_PINNEDPUBLICKEY] = 'peer_fingerprint';
+ }
+
$curloptsToCheck = [
\CURLOPT_PRIVATE,
\CURLOPT_HEADERFUNCTION,
diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php
index 59e4dc1da7cc8..a1d8c0b9fc186 100644
--- a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php
+++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php
@@ -32,6 +32,9 @@ abstract class HttpClientTestCase extends BaseHttpClientTestCase
{
private static $vulcainStarted = false;
+ /**
+ * @group transient-on-macos
+ */
public function testTimeoutOnDestruct()
{
if (!method_exists(parent::class, 'testTimeoutOnDestruct')) {
diff --git a/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php b/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php
index ef0aa721d3904..7f69ed79ccc76 100644
--- a/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php
+++ b/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php
@@ -93,7 +93,7 @@ public function onKernelRequest(RequestEvent $event)
public function onKernelResponse(ResponseEvent $event)
{
- if (!$event->isMainRequest()) {
+ if (!$event->isMainRequest() || (!$this->container->has('initialized_session') && !$event->getRequest()->hasSession())) {
return;
}
diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/SessionListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/SessionListenerTest.php
index 3d70b82a3928a..28d488796d14a 100644
--- a/src/Symfony/Component/HttpKernel/Tests/EventListener/SessionListenerTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/SessionListenerTest.php
@@ -283,6 +283,24 @@ public function testUninitializedSession()
$this->assertFalse($response->headers->has(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER));
}
+ public function testUninitializedSessionWithoutInitializedSession()
+ {
+ $kernel = $this->createMock(HttpKernelInterface::class);
+ $response = new Response();
+ $response->setSharedMaxAge(60);
+ $response->headers->set(AbstractSessionListener::NO_AUTO_CACHE_CONTROL_HEADER, 'true');
+
+ $container = new ServiceLocator([]);
+
+ $listener = new SessionListener($container);
+ $listener->onKernelResponse(new ResponseEvent($kernel, new Request(), HttpKernelInterface::MASTER_REQUEST, $response));
+ $this->assertFalse($response->headers->has('Expires'));
+ $this->assertTrue($response->headers->hasCacheControlDirective('public'));
+ $this->assertFalse($response->headers->hasCacheControlDirective('private'));
+ $this->assertFalse($response->headers->hasCacheControlDirective('must-revalidate'));
+ $this->assertSame('60', $response->headers->getCacheControlDirective('s-maxage'));
+ }
+
public function testSurrogateMainRequestIsPublic()
{
$session = $this->createMock(Session::class);
diff --git a/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php b/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php
index 78c4df8533c9c..c010bc7d33dc3 100644
--- a/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php
+++ b/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php
@@ -283,14 +283,14 @@ public function testToArray()
public function testInReplyToAcceptsNonIdentifierValues()
{
$headers = new Headers();
- $headers->addHeader('In-Reply-To', 'foobar');
+ $headers->addTextHeader('In-Reply-To', 'foobar');
$this->assertEquals('foobar', $headers->get('In-Reply-To')->getBody());
}
public function testReferencesAcceptsNonIdentifierValues()
{
$headers = new Headers();
- $headers->addHeader('References' , 'foobar');
+ $headers->addTextHeader('References' , 'foobar');
$this->assertEquals('foobar', $headers->get('References')->getBody());
}
diff --git a/src/Symfony/Component/Notifier/Transport.php b/src/Symfony/Component/Notifier/Transport.php
index 9944573630e68..dea527d51eb25 100644
--- a/src/Symfony/Component/Notifier/Transport.php
+++ b/src/Symfony/Component/Notifier/Transport.php
@@ -28,7 +28,7 @@
use Symfony\Component\Notifier\Bridge\Mattermost\MattermostTransportFactory;
use Symfony\Component\Notifier\Bridge\MessageBird\MessageBirdTransportFactory;
use Symfony\Component\Notifier\Bridge\MessageMedia\MessageMediaTransportFactory;
-use Symfony\Component\Notifier\Bridge\MicrosoftTeams\MicrosoftTeamsTransport;
+use Symfony\Component\Notifier\Bridge\MicrosoftTeams\MicrosoftTeamsTransportFactory;
use Symfony\Component\Notifier\Bridge\Mobyt\MobytTransportFactory;
use Symfony\Component\Notifier\Bridge\Nexmo\NexmoTransportFactory;
use Symfony\Component\Notifier\Bridge\Octopush\OctopushTransportFactory;
@@ -84,7 +84,7 @@ class Transport
MattermostTransportFactory::class,
MessageBirdTransportFactory::class,
MessageMediaTransportFactory::class,
- MicrosoftTeamsTransport::class,
+ MicrosoftTeamsTransportFactory::class,
MobytTransportFactory::class,
NexmoTransportFactory::class,
OctopushTransportFactory::class,
diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.lb.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.lb.xlf
index 5f707535fa723..36987bc99f37f 100644
--- a/src/Symfony/Component/Security/Core/Resources/translations/security.lb.xlf
+++ b/src/Symfony/Component/Security/Core/Resources/translations/security.lb.xlf
@@ -1,6 +1,6 @@
-
+
An authentication exception occurred.
diff --git a/src/Symfony/Component/Security/Http/EventListener/CookieClearingLogoutListener.php b/src/Symfony/Component/Security/Http/EventListener/CookieClearingLogoutListener.php
index ecff5fd03078f..d178b926c3ade 100644
--- a/src/Symfony/Component/Security/Http/EventListener/CookieClearingLogoutListener.php
+++ b/src/Symfony/Component/Security/Http/EventListener/CookieClearingLogoutListener.php
@@ -40,7 +40,7 @@ public function onLogout(LogoutEvent $event): void
}
foreach ($this->cookies as $cookieName => $cookieData) {
- $response->headers->clearCookie($cookieName, $cookieData['path'], $cookieData['domain']);
+ $response->headers->clearCookie($cookieName, $cookieData['path'], $cookieData['domain'], $cookieData['secure'] ?? false, true, $cookieData['samesite'] ?? null);
}
}
diff --git a/src/Symfony/Component/Security/Http/Tests/EventListener/CookieClearingLogoutListenerTest.php b/src/Symfony/Component/Security/Http/Tests/EventListener/CookieClearingLogoutListenerTest.php
new file mode 100644
index 0000000000000..f4c0e3d89b611
--- /dev/null
+++ b/src/Symfony/Component/Security/Http/Tests/EventListener/CookieClearingLogoutListenerTest.php
@@ -0,0 +1,56 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Security\Http\Tests\EventListener;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\HttpFoundation\Cookie;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpFoundation\ResponseHeaderBag;
+use Symfony\Component\Security\Http\Event\LogoutEvent;
+use Symfony\Component\Security\Http\EventListener\CookieClearingLogoutListener;
+
+class CookieClearingLogoutListenerTest extends TestCase
+{
+ public function testLogout()
+ {
+ $response = new Response();
+ $event = new LogoutEvent(new Request(), null);
+ $event->setResponse($response);
+
+ $listener = new CookieClearingLogoutListener(['foo' => ['path' => '/foo', 'domain' => 'foo.foo', 'secure' => true, 'samesite' => Cookie::SAMESITE_STRICT], 'foo2' => ['path' => null, 'domain' => null]]);
+
+ $cookies = $response->headers->getCookies();
+ $this->assertCount(0, $cookies);
+
+ $listener->onLogout($event);
+
+ $cookies = $response->headers->getCookies(ResponseHeaderBag::COOKIES_ARRAY);
+ $this->assertCount(2, $cookies);
+
+ $cookie = $cookies['foo.foo']['/foo']['foo'];
+ $this->assertEquals('foo', $cookie->getName());
+ $this->assertEquals('/foo', $cookie->getPath());
+ $this->assertEquals('foo.foo', $cookie->getDomain());
+ $this->assertEquals(Cookie::SAMESITE_STRICT, $cookie->getSameSite());
+ $this->assertTrue($cookie->isSecure());
+ $this->assertTrue($cookie->isCleared());
+
+ $cookie = $cookies['']['/']['foo2'];
+ $this->assertStringStartsWith('foo2', $cookie->getName());
+ $this->assertEquals('/', $cookie->getPath());
+ $this->assertNull($cookie->getDomain());
+ $this->assertNull($cookie->getSameSite());
+ $this->assertFalse($cookie->isSecure());
+ $this->assertTrue($cookie->isCleared());
+ }
+}
diff --git a/src/Symfony/Component/Translation/Bridge/Loco/Tests/LocoProviderTest.php b/src/Symfony/Component/Translation/Bridge/Loco/Tests/LocoProviderTest.php
index 2a2183abf110f..5b224de8aa1be 100644
--- a/src/Symfony/Component/Translation/Bridge/Loco/Tests/LocoProviderTest.php
+++ b/src/Symfony/Component/Translation/Bridge/Loco/Tests/LocoProviderTest.php
@@ -426,12 +426,16 @@ public function getResponsesForManyLocalesAndManyDomains(): \Generator
$expectedTranslatorBag = new TranslatorBag();
$expectedTranslatorBag->addCatalogue($arrayLoader->load([
'index.hello' => 'Hello',
- 'index.greetings' => 'Welcome, {firstname}!',
], 'en'));
+ $expectedTranslatorBag->addCatalogue($arrayLoader->load([
+ 'index.greetings' => 'Welcome, {firstname}!',
+ ], 'en', 'messages+intl-icu'));
$expectedTranslatorBag->addCatalogue($arrayLoader->load([
'index.hello' => 'Bonjour',
- 'index.greetings' => 'Bienvenue, {firstname} !',
], 'fr'));
+ $expectedTranslatorBag->addCatalogue($arrayLoader->load([
+ 'index.greetings' => 'Bienvenue, {firstname} !',
+ ], 'fr', 'messages+intl-icu'));
$expectedTranslatorBag->addCatalogue($arrayLoader->load([
'firstname.error' => 'Firstname must contains only letters.',
'lastname.error' => 'Lastname must contains only letters.',
@@ -443,7 +447,7 @@ public function getResponsesForManyLocalesAndManyDomains(): \Generator
yield [
['en', 'fr'],
- ['messages', 'validators'],
+ ['messages', 'messages+intl-icu', 'validators'],
[
'en' => [
'messages' => <<<'XLIFF'
@@ -458,6 +462,19 @@ public function getResponsesForManyLocalesAndManyDomains(): \Generator
index.hello
Hello
+
+
+
+XLIFF
+ ,
+ 'messages+intl-icu' => <<<'XLIFF'
+
+
+
+
+
index.greetings
Welcome, {firstname}!
@@ -502,6 +519,19 @@ public function getResponsesForManyLocalesAndManyDomains(): \Generator
index.hello
Bonjour
+
+
+
+XLIFF
+ ,
+ 'messages+intl-icu' => <<<'XLIFF'
+
+
+
+
+
index.greetings
Bienvenue, {firstname} !
diff --git a/src/Symfony/Component/Translation/Catalogue/AbstractOperation.php b/src/Symfony/Component/Translation/Catalogue/AbstractOperation.php
index 9869fbb8bb34e..98d42e5b6e46c 100644
--- a/src/Symfony/Component/Translation/Catalogue/AbstractOperation.php
+++ b/src/Symfony/Component/Translation/Catalogue/AbstractOperation.php
@@ -83,7 +83,18 @@ public function __construct(MessageCatalogueInterface $source, MessageCatalogueI
public function getDomains()
{
if (null === $this->domains) {
- $this->domains = array_values(array_unique(array_merge($this->source->getDomains(), $this->target->getDomains())));
+ $domains = [];
+ foreach ([$this->source, $this->target] as $catalogue) {
+ foreach ($catalogue->getDomains() as $domain) {
+ $domains[$domain] = $domain;
+
+ if ($catalogue->all($domainIcu = $domain.MessageCatalogueInterface::INTL_DOMAIN_SUFFIX)) {
+ $domains[$domainIcu] = $domainIcu;
+ }
+ }
+ }
+
+ $this->domains = array_values($domains);
}
return $this->domains;
diff --git a/src/Symfony/Component/Translation/Tests/Catalogue/MergeOperationTest.php b/src/Symfony/Component/Translation/Tests/Catalogue/MergeOperationTest.php
index 240c492800acc..3f21abac9dd52 100644
--- a/src/Symfony/Component/Translation/Tests/Catalogue/MergeOperationTest.php
+++ b/src/Symfony/Component/Translation/Tests/Catalogue/MergeOperationTest.php
@@ -58,7 +58,7 @@ public function testGetResultFromIntlDomain()
$this->assertEquals(
new MessageCatalogue('en', [
'messages' => ['a' => 'old_a', 'b' => 'old_b'],
- 'messages+intl-icu' => ['d' => 'old_d', 'c' => 'new_c'],
+ 'messages+intl-icu' => ['d' => 'old_d', 'c' => 'new_c', 'a' => 'new_a'],
]),
$this->createOperation(
new MessageCatalogue('en', ['messages' => ['a' => 'old_a', 'b' => 'old_b'], 'messages+intl-icu' => ['d' => 'old_d']]),
diff --git a/src/Symfony/Component/Translation/Tests/Catalogue/TargetOperationTest.php b/src/Symfony/Component/Translation/Tests/Catalogue/TargetOperationTest.php
index d5441f3bee4ef..2b63cd4166464 100644
--- a/src/Symfony/Component/Translation/Tests/Catalogue/TargetOperationTest.php
+++ b/src/Symfony/Component/Translation/Tests/Catalogue/TargetOperationTest.php
@@ -72,6 +72,7 @@ public function testGetResultWithMixedDomains()
$this->assertEquals(
new MessageCatalogue('en', [
'messages' => ['a' => 'old_a'],
+ 'messages+intl-icu' => ['a' => 'new_a'],
]),
$this->createOperation(
new MessageCatalogue('en', ['messages' => ['a' => 'old_a']]),
@@ -103,7 +104,7 @@ public function testGetResultWithMixedDomains()
$this->assertEquals(
new MessageCatalogue('en', [
'messages' => ['a' => 'old_a'],
- 'messages+intl-icu' => ['b' => 'new_b'],
+ 'messages+intl-icu' => ['b' => 'new_b', 'a' => 'new_a'],
]),
$this->createOperation(
new MessageCatalogue('en', ['messages' => ['a' => 'old_a']]),
diff --git a/src/Symfony/Component/Translation/Tests/Command/TranslationPullCommandTest.php b/src/Symfony/Component/Translation/Tests/Command/TranslationPullCommandTest.php
index e5726f266c77d..c002fc7532b1f 100644
--- a/src/Symfony/Component/Translation/Tests/Command/TranslationPullCommandTest.php
+++ b/src/Symfony/Component/Translation/Tests/Command/TranslationPullCommandTest.php
@@ -47,19 +47,27 @@ public function testPullNewXlf12Messages()
{
$arrayLoader = new ArrayLoader();
$filenameEn = $this->createFile();
+ $filenameEnIcu = $this->createFile(['say_hello' => 'Welcome, {firstname}!'], 'en', 'messages+intl-icu.%locale%.xlf');
$filenameFr = $this->createFile(['note' => 'NOTE'], 'fr');
+ $filenameFrIcu = $this->createFile(['say_hello' => 'Bonjour, {firstname}!'], 'fr', 'messages+intl-icu.%locale%.xlf');
$locales = ['en', 'fr'];
- $domains = ['messages'];
+ $domains = ['messages', 'messages+intl-icu'];
$providerReadTranslatorBag = new TranslatorBag();
$providerReadTranslatorBag->addCatalogue($arrayLoader->load([
'note' => 'NOTE',
'new.foo' => 'newFoo',
], 'en'));
+ $providerReadTranslatorBag->addCatalogue($arrayLoader->load([
+ 'say_hello' => 'Welcome, {firstname}!',
+ ], 'en', 'messages+intl-icu'));
$providerReadTranslatorBag->addCatalogue($arrayLoader->load([
'note' => 'NOTE',
'new.foo' => 'nouveauFoo',
], 'fr'));
+ $providerReadTranslatorBag->addCatalogue($arrayLoader->load([
+ 'say_hello' => 'Bonjour, {firstname}!',
+ ], 'fr', 'messages+intl-icu'));
$provider = $this->createMock(ProviderInterface::class);
$provider->expects($this->once())
@@ -72,9 +80,9 @@ public function testPullNewXlf12Messages()
->willReturn('null://default');
$tester = $this->createCommandTester($provider, $locales, $domains);
- $tester->execute(['--locales' => ['en', 'fr'], '--domains' => ['messages']]);
+ $tester->execute(['--locales' => ['en', 'fr'], '--domains' => ['messages', 'messages+intl-icu']]);
- $this->assertStringContainsString('[OK] New translations from "null" has been written locally (for "en, fr" locale(s), and "messages" domain(s)).', trim($tester->getDisplay()));
+ $this->assertStringContainsString('[OK] New translations from "null" has been written locally (for "en, fr" locale(s), and "messages, messages+intl-icu"', trim($tester->getDisplay()));
$this->assertXmlStringEqualsXmlString(<<
@@ -98,6 +106,23 @@ public function testPullNewXlf12Messages()
, file_get_contents($filenameEn));
$this->assertXmlStringEqualsXmlString(<<
+
+
+
+
+
+ say_hello
+ Welcome, {firstname}!
+
+
+
+
+XLIFF
+ , file_get_contents($filenameEnIcu));
+ $this->assertXmlStringEqualsXmlString(<<
@@ -117,6 +142,23 @@ public function testPullNewXlf12Messages()
XLIFF
, file_get_contents($filenameFr));
+ $this->assertXmlStringEqualsXmlString(<<
+
+
+
+
+
+ say_hello
+ Bonjour, {firstname}!
+
+
+
+
+XLIFF
+ , file_get_contents($filenameFrIcu));
}
public function testPullNewXlf20Messages()