From 88a1303d491e1907d8180a5a571b50d4ec7b352b Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 27 Nov 2024 13:42:55 +0100 Subject: [PATCH 01/37] Update CHANGELOG for 5.4.48 --- CHANGELOG-5.4.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/CHANGELOG-5.4.md b/CHANGELOG-5.4.md index 8bf2d08b4db72..23768a799ed86 100644 --- a/CHANGELOG-5.4.md +++ b/CHANGELOG-5.4.md @@ -7,6 +7,31 @@ in 5.4 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/v5.4.0...v5.4.1 +* 5.4.48 (2024-11-27) + + * bug #59013 [HttpClient] Fix checking for private IPs before connecting (nicolas-grekas) + * bug #58562 [HttpClient] Close gracefull when the server closes the connection abruptly (discordier) + * bug #59007 [Dotenv] read runtime config from composer.json in debug dotenv command (xabbuh) + * bug #58963 [PropertyInfo] Fix write visibility for Asymmetric Visibility and Virtual Properties (xabbuh, pan93412) + * bug #58983 [Translation] [Bridge][Lokalise] Fix empty keys array in PUT, DELETE requests causing Lokalise API error (DominicLuidold) + * bug #58959 [PropertyInfo] consider write property visibility to decide whether a property is writable (xabbuh) + * bug #58964 [TwigBridge] do not add child nodes to EmptyNode instances (xabbuh) + * bug #58822 [DependencyInjection] Fix checking for interfaces in ContainerBuilder::getReflectionClass() (donquixote) + * bug #58865 Dynamically fix compatibility with doctrine/data-fixtures v2 (greg0ire) + * bug #58921 [HttpKernel] Ensure `HttpCache::getTraceKey()` does not throw exception (lyrixx) + * bug #58908 [DoctrineBridge] don't call `EntityManager::initializeObject()` with scalar values (xabbuh) + * bug #58924 [HttpClient] Fix empty hosts in option "resolve" (nicolas-grekas) + * bug #58915 [HttpClient] Fix option "resolve" with IPv6 addresses (nicolas-grekas) + * bug #58919 [WebProfilerBundle] Twig deprecations (mazodude) + * bug #58914 [HttpClient] Fix option "bindto" with IPv6 addresses (nicolas-grekas) + * bug #58875 [HttpClient] Removed body size limit (Carl Julian Sauter) + * bug #58860 [HttpClient] Fix catching some invalid Location headers (nicolas-grekas) + * bug #58836 Work around `parse_url()` bug (bis) (nicolas-grekas) + * bug #58818 [Messenger] silence PHP warnings issued by `Redis::connect()` (xabbuh) + * bug #58828 [PhpUnitBridge] fix dumping tests to skip with data providers (xabbuh) + * bug #58842 [Routing] Fix: lost priority when defining hosts in configuration (BeBlood) + * bug #58850 [HttpClient] fix PHP 7.2 compatibility (xabbuh) + * 5.4.47 (2024-11-13) * security #cve-2024-50342 [HttpClient] Resolve hostnames in NoPrivateNetworkHttpClient (nicolas-grekas) From 2562dc24b92e855326f2e60bfa0479f68e94e175 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 27 Nov 2024 13:43:03 +0100 Subject: [PATCH 02/37] Update CONTRIBUTORS for 5.4.48 --- CONTRIBUTORS.md | 47 +++++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index bcc33dc4892f2..c83c2ca56b1d4 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -19,8 +19,8 @@ The Symfony Connect username in parenthesis allows to get more information - Jordi Boggiano (seldaek) - Maxime Steinhausser (ogizanagi) - Kévin Dunglas (dunglas) - - Victor Berchet (victor) - Javier Eguiluz (javier.eguiluz) + - Victor Berchet (victor) - Ryan Weaver (weaverryan) - Jérémy DERUSSÉ (jderusse) - Jules Pietri (heah) @@ -51,15 +51,15 @@ The Symfony Connect username in parenthesis allows to get more information - Igor Wiedler - Jan Schädlich (jschaedl) - Mathieu Lechat (mat_the_cat) + - Simon André (simonandre) - Matthias Pigulla (mpdude) - Gabriel Ostrolucký (gadelat) - - Simon André (simonandre) - Jonathan Wage (jwage) + - Mathias Arlaud (mtarld) - Vincent Langlet (deviling) - Valentin Udaltsov (vudaltsov) - - Mathias Arlaud (mtarld) - - Alexandre Salomé (alexandresalome) - Grégoire Paris (greg0ire) + - Alexandre Salomé (alexandresalome) - William DURAND - ornicar - Dany Maillard (maidmaid) @@ -83,11 +83,11 @@ The Symfony Connect username in parenthesis allows to get more information - Alexander Schranz (alexander-schranz) - Mathieu Piot (mpiot) - Vasilij Duško (staff) + - Dariusz Ruminski - Sarah Khalil (saro0h) - Laurent VOULLEMIER (lvo) - Konstantin Kudryashov (everzet) - Guilhem N (guilhemn) - - Dariusz Ruminski - Bilal Amarni (bamarni) - Eriksen Costa - Florin Patan (florinpatan) @@ -110,12 +110,12 @@ The Symfony Connect username in parenthesis allows to get more information - Baldini - Alex Pott - Fran Moreno (franmomu) + - Hubert Lenoir (hubert_lenoir) - Charles Sarrazin (csarrazi) - Henrik Westphal (snc) - Dariusz Górecki (canni) - - Hubert Lenoir (hubert_lenoir) - - Ener-Getick - Antoine Makdessi (amakdessi) + - Ener-Getick - Graham Campbell (graham) - Tugdual Saunier (tucksaun) - Lee McDermott @@ -148,6 +148,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jérôme Vasseur (jvasseur) - Peter Kokot (peterkokot) - Brice BERNARD (brikou) + - Valtteri R (valtzu) - Martin Auswöger - Michal Piotrowski - marc.weistroff @@ -156,7 +157,6 @@ The Symfony Connect username in parenthesis allows to get more information - Vladimir Tsykun (vtsykun) - Jacob Dreesen (jdreesen) - Włodzimierz Gajda (gajdaw) - - Valtteri R (valtzu) - Nicolas Philippe (nikophil) - Javier Spagnoletti (phansys) - Adrien Brault (adrienbrault) @@ -170,6 +170,7 @@ The Symfony Connect username in parenthesis allows to get more information - Baptiste Clavié (talus) - Alexander Schwenn (xelaris) - Fabien Pennequin (fabienpennequin) + - Dāvis Zālītis (k0d3r1s) - Gordon Franke (gimler) - Malte Schlüter (maltemaltesich) - jeremyFreeAgent (jeremyfreeagent) @@ -178,7 +179,6 @@ The Symfony Connect username in parenthesis allows to get more information - Vasilij Dusko - Daniel Wehner (dawehner) - Maxime Helias (maxhelias) - - Dāvis Zālītis (k0d3r1s) - Robert Schönthal (digitalkaoz) - Smaine Milianni (ismail1432) - François-Xavier de Guillebon (de-gui_f) @@ -193,6 +193,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jhonny Lidfors (jhonne) - Juti Noppornpitak (shiroyuki) - Gregor Harlan (gharlan) + - Alexis Lefebvre - Hugo Alliaume (kocal) - Anthony MARTIN - Sebastian Hörl (blogsh) @@ -206,7 +207,6 @@ The Symfony Connect username in parenthesis allows to get more information - Guilherme Blanco (guilhermeblanco) - Saif Eddin Gmati (azjezz) - Farhad Safarov (safarov) - - Alexis Lefebvre - SpacePossum - Richard van Laak (rvanlaak) - Andreas Braun @@ -351,6 +351,7 @@ The Symfony Connect username in parenthesis allows to get more information - fd6130 (fdtvui) - Priyadi Iman Nurcahyo (priyadi) - Alan Poulain (alanpoulain) + - Oleg Andreyev (oleg.andreyev) - Maciej Malarz (malarzm) - Marcin Sikoń (marphi) - Michele Orselli (orso) @@ -390,13 +391,13 @@ The Symfony Connect username in parenthesis allows to get more information - Alexander Kotynia (olden) - Elnur Abdurrakhimov (elnur) - Manuel Reinhard (sprain) + - Zan Baldwin (zanbaldwin) - Antonio J. García Lagar (ajgarlag) - BoShurik - Quentin Devos - Adam Prager (padam87) - Benoît Burnichon (bburnichon) - maxime.steinhausser - - Oleg Andreyev (oleg.andreyev) - Roman Ring (inori) - Xavier Montaña Carreras (xmontana) - Arjen van der Meijden @@ -460,7 +461,6 @@ The Symfony Connect username in parenthesis allows to get more information - Magnus Nordlander (magnusnordlander) - Tim Goudriaan (codedmonkey) - Robert Kiss (kepten) - - Zan Baldwin (zanbaldwin) - Alexandre Quercia (alquerci) - Marcos Sánchez - Emanuele Panzeri (thepanz) @@ -484,6 +484,7 @@ The Symfony Connect username in parenthesis allows to get more information - Bohan Yang (brentybh) - Vilius Grigaliūnas - David Badura (davidbadura) + - Jordane VASPARD (elementaire) - Chris Smith (cs278) - Thomas Bisignani (toma) - Florian Klein (docteurklein) @@ -582,7 +583,6 @@ The Symfony Connect username in parenthesis allows to get more information - Alexander Menshchikov - Clément Gautier (clementgautier) - roman joly (eltharin) - - Jordane VASPARD (elementaire) - James Gilliland (neclimdul) - Sanpi (sanpi) - Eduardo Gulias (egulias) @@ -683,6 +683,7 @@ The Symfony Connect username in parenthesis allows to get more information - Neil Peyssard (nepey) - Niklas Fiekas - Mark Challoner (markchalloner) + - Andreas Hennings - Markus Bachmann (baachi) - Gunnstein Lye (glye) - Erkhembayar Gantulga (erheme318) @@ -797,6 +798,7 @@ The Symfony Connect username in parenthesis allows to get more information - Kev - Kevin McBride - Sergio Santoro + - Jonas Elfering - Philipp Rieber (bicpi) - Dmitriy Derepko - Manuel de Ruiter (manuel) @@ -949,7 +951,6 @@ The Symfony Connect username in parenthesis allows to get more information - Franck RANAIVO-HARISOA (franckranaivo) - Yi-Jyun Pan - Egor Taranov - - Andreas Hennings - Arnaud Frézet - Philippe Segatori - Jon Gotlin (jongotlin) @@ -1295,6 +1296,7 @@ The Symfony Connect username in parenthesis allows to get more information - _sir_kane (waly) - Olivier Maisonneuve - Gálik Pál + - Bálint Szekeres - Andrei C. (moldman) - Mike Meier (mykon) - Pedro Miguel Maymone de Resende (pedroresende) @@ -1306,6 +1308,7 @@ The Symfony Connect username in parenthesis allows to get more information - Kagan Balga (kagan-balga) - Nikita Nefedov (nikita2206) - Alex Bacart + - StefanoTarditi - cgonzalez - hugovms - Ben @@ -1418,6 +1421,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jason Woods - mwsaz - bogdan + - wanxiangchwng - Geert De Deckere - grizlik - Derek ROTH @@ -1447,7 +1451,6 @@ The Symfony Connect username in parenthesis allows to get more information - Morten Wulff (wulff) - Kieran - Don Pinkster - - Jonas Elfering - Maksim Muruev - Emil Einarsson - 243083df @@ -1624,6 +1627,7 @@ The Symfony Connect username in parenthesis allows to get more information - Luciano Mammino (loige) - LHommet Nicolas (nicolaslh) - fabios + - eRIZ - Sander Coolen (scoolen) - Vic D'Elfant (vicdelfant) - Amirreza Shafaat (amirrezashafaat) @@ -2034,6 +2038,7 @@ The Symfony Connect username in parenthesis allows to get more information - Vladimir Mantulo (mantulo) - Boullé William (williamboulle) - Jesper Noordsij + - Bart Baaten - Frederic Godfrin - Paul Matthews - aim8604 @@ -2068,6 +2073,7 @@ The Symfony Connect username in parenthesis allows to get more information - Dalibor Karlović - Cesar Scur (cesarscur) - Cyril Vermandé (cyve) + - Daniele Orru' (danydev) - Raul Garcia Canet (juagarc4) - Sagrario Meneses - Dmitri Petmanson @@ -2161,6 +2167,7 @@ The Symfony Connect username in parenthesis allows to get more information - Maxime THIRY - Norman Soetbeer - Ludek Stepan + - Benjamin BOUDIER - Frederik Schwan - Mark van den Berg - Aaron Stephens (astephens) @@ -2276,6 +2283,7 @@ The Symfony Connect username in parenthesis allows to get more information - Frank Neff (fneff) - Volodymyr Kupriienko (greeflas) - Ilya Biryukov (ibiryukov) + - Mathieu Ledru (matyo91) - Roma (memphys) - Florian Caron (shalalalala) - Serhiy Lunak (slunak) @@ -2381,7 +2389,6 @@ The Symfony Connect username in parenthesis allows to get more information - Nicolas Eeckeloo (neeckeloo) - Andriy Prokopenko (sleepyboy) - Dariusz Ruminski - - Bálint Szekeres - Starfox64 - Ivo Valchev - Thomas Hanke @@ -2472,6 +2479,7 @@ The Symfony Connect username in parenthesis allows to get more information - karstennilsen - kaywalker - Sebastian Ionescu + - Kurt Thiemann - Robert Kopera - Pablo Ogando Ferreira - Thomas Ploch @@ -2481,6 +2489,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jeremiah VALERIE - Alexandre Beaujour - Franck Ranaivo-Harisoa + - Grégoire Rabasse - Cas van Dongen - Patrik Patie Gmitter - George Yiannoulopoulos @@ -2560,6 +2569,7 @@ The Symfony Connect username in parenthesis allows to get more information - Tobias Genberg (lorceroth) - Michael Simonson (mikes) - Nicolas Badey (nico-b) + - Florent Blaison (orkin) - Olivier Scherler (oscherler) - Flo Gleixner (redflo) - Romain Jacquart (romainjacquart) @@ -3158,6 +3168,7 @@ The Symfony Connect username in parenthesis allows to get more information - Vlad Dumitrache - wetternest - Erik van Wingerden + - matlec - Valouleloup - Pathpat - Jaymin G @@ -3302,6 +3313,7 @@ The Symfony Connect username in parenthesis allows to get more information - dasmfm - Claas Augner - Mathias Geat + - neodevcode - Angel Fernando Quiroz Campos (angelfqc) - Arnaud Buathier (arnapou) - Curtis (ccorliss) @@ -3362,6 +3374,7 @@ The Symfony Connect username in parenthesis allows to get more information - Steffen Keuper - Kai Eichinger - Antonio Angelino + - Jan Nedbal - Jens Schulze - Tema Yud - Matt Fields @@ -3393,6 +3406,7 @@ The Symfony Connect username in parenthesis allows to get more information - Menno Holtkamp - Ser5 - Michael Hudson-Doyle + - Matthew Burns - Daniel Bannert - Karim Miladi - Michael Genereux @@ -3771,6 +3785,7 @@ The Symfony Connect username in parenthesis allows to get more information - damaya - Kevin Weber - Alexandru Năstase + - Carl Julian Sauter - Dionysis Arvanitis - Sergey Fedotov - Konstantin Scheumann From 1622f3f08df465d5aa53645728398e449ce87d17 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 27 Nov 2024 13:43:17 +0100 Subject: [PATCH 03/37] Update VERSION for 5.4.48 --- 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 04f9b627ceefd..8bb0ab184b9f8 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -78,12 +78,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static $freshCache = []; - public const VERSION = '5.4.48-DEV'; + public const VERSION = '5.4.48'; public const VERSION_ID = 50448; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 4; public const RELEASE_VERSION = 48; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2024'; public const END_OF_LIFE = '02/2029'; From 92da41d52f30d483325d4ac97d8ddfb6a5578d2c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 27 Nov 2024 13:48:42 +0100 Subject: [PATCH 04/37] Bump Symfony version to 5.4.49 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 8bb0ab184b9f8..a6a70bfb3cb4d 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -78,12 +78,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static $freshCache = []; - public const VERSION = '5.4.48'; - public const VERSION_ID = 50448; + public const VERSION = '5.4.49-DEV'; + public const VERSION_ID = 50449; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 4; - public const RELEASE_VERSION = 48; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 49; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '11/2024'; public const END_OF_LIFE = '02/2029'; From 2982bb7ffc7adb1a3e5ab290c2b5f303d8e585d1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 27 Nov 2024 13:54:17 +0100 Subject: [PATCH 05/37] Bump Symfony version to 6.4.17 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index e4d06fad61928..185c9686aa097 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -76,12 +76,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static array $freshCache = []; - public const VERSION = '6.4.16'; - public const VERSION_ID = 60416; + public const VERSION = '6.4.17-DEV'; + public const VERSION_ID = 60417; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 4; - public const RELEASE_VERSION = 16; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 17; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '11/2026'; public const END_OF_LIFE = '11/2027'; From 1defdbac9596610162b36b4054740ed9248fc459 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 28 Nov 2024 08:55:08 +0100 Subject: [PATCH 06/37] [HttpClient] Fix streaming and redirecting with NoPrivateNetworkHttpClient --- .../HttpClient/NoPrivateNetworkHttpClient.php | 35 ++++------ .../HttpClientDataCollectorTest.php | 5 -- .../HttpClient/Tests/HttpClientTestCase.php | 67 +++++++++++++++++++ .../HttpClient/Tests/HttplugClientTest.php | 5 -- .../HttpClient/Tests/Psr18ClientTest.php | 5 -- .../Tests/RetryableHttpClientTest.php | 5 -- .../Tests/TraceableHttpClientTest.php | 5 -- .../HttpClient/Test/HttpClientTestCase.php | 1 - 8 files changed, 81 insertions(+), 47 deletions(-) diff --git a/src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.php b/src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.php index 8ea8d917e307d..ad973671c08d9 100644 --- a/src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.php +++ b/src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.php @@ -20,7 +20,6 @@ use Symfony\Contracts\HttpClient\ChunkInterface; use Symfony\Contracts\HttpClient\HttpClientInterface; use Symfony\Contracts\HttpClient\ResponseInterface; -use Symfony\Contracts\HttpClient\ResponseStreamInterface; use Symfony\Contracts\Service\ResetInterface; /** @@ -103,24 +102,13 @@ public function request(string $method, string $url, array $options = []): Respo $ip = self::dnsResolve($dnsCache, $host, $this->ipFlags, $options); self::ipCheck($ip, $this->subnets, $this->ipFlags, $host, $url); - if (0 < $maxRedirects = $options['max_redirects']) { - $options['max_redirects'] = 0; - $redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = $options['headers']; - - if (isset($options['normalized_headers']['host']) || isset($options['normalized_headers']['authorization']) || isset($options['normalized_headers']['cookie'])) { - $redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], static function ($h) { - return 0 !== stripos($h, 'Host:') && 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:'); - }); - } - } - $onProgress = $options['on_progress'] ?? null; $subnets = $this->subnets; $ipFlags = $this->ipFlags; $lastPrimaryIp = ''; $options['on_progress'] = static function (int $dlNow, int $dlSize, array $info) use ($onProgress, $subnets, $ipFlags, &$lastPrimaryIp): void { - if (($info['primary_ip'] ?? '') !== $lastPrimaryIp) { + if (!\in_array($info['primary_ip'] ?? '', ['', $lastPrimaryIp], true)) { self::ipCheck($info['primary_ip'], $subnets, $ipFlags, null, $info['url']); $lastPrimaryIp = $info['primary_ip']; } @@ -128,6 +116,19 @@ public function request(string $method, string $url, array $options = []): Respo null !== $onProgress && $onProgress($dlNow, $dlSize, $info); }; + if (0 >= $maxRedirects = $options['max_redirects']) { + return new AsyncResponse($this->client, $method, $url, $options); + } + + $options['max_redirects'] = 0; + $redirectHeaders['with_auth'] = $redirectHeaders['no_auth'] = $options['headers']; + + if (isset($options['normalized_headers']['host']) || isset($options['normalized_headers']['authorization']) || isset($options['normalized_headers']['cookie'])) { + $redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], static function ($h) { + return 0 !== stripos($h, 'Host:') && 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:'); + }); + } + return new AsyncResponse($this->client, $method, $url, $options, static function (ChunkInterface $chunk, AsyncContext $context) use (&$method, &$options, $maxRedirects, &$redirectHeaders, $subnets, $ipFlags, $dnsCache): \Generator { if (null !== $chunk->getError() || $chunk->isTimeout() || !$chunk->isFirst()) { yield $chunk; @@ -178,14 +179,6 @@ public function request(string $method, string $url, array $options = []): Respo }); } - /** - * {@inheritdoc} - */ - public function stream($responses, ?float $timeout = null): ResponseStreamInterface - { - return $this->client->stream($responses, $timeout); - } - /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php b/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php index 54e160b5c5240..15a3136da6b73 100644 --- a/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php +++ b/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php @@ -24,11 +24,6 @@ public static function setUpBeforeClass(): void TestHttpServer::start(); } - public static function tearDownAfterClass(): void - { - TestHttpServer::stop(); - } - public function testItCollectsRequestCount() { $httpClient1 = $this->httpClientThatHasTracedRequests([ diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php index 6bed6d6f787c0..d18cc46431135 100644 --- a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php +++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php @@ -523,6 +523,73 @@ public function testNoPrivateNetworkWithResolveAndRedirect() $client->request('GET', 'http://localhost:8057/302?location=https://symfony.com/'); } + public function testNoPrivateNetwork304() + { + $client = $this->getHttpClient(__FUNCTION__); + $client = new NoPrivateNetworkHttpClient($client, '104.26.14.6/32'); + $response = $client->request('GET', 'http://localhost:8057/304', [ + 'headers' => ['If-Match' => '"abc"'], + 'buffer' => false, + ]); + + $this->assertSame(304, $response->getStatusCode()); + $this->assertSame('', $response->getContent(false)); + } + + public function testNoPrivateNetwork302() + { + $client = $this->getHttpClient(__FUNCTION__); + $client = new NoPrivateNetworkHttpClient($client, '104.26.14.6/32'); + $response = $client->request('GET', 'http://localhost:8057/302/relative'); + + $body = $response->toArray(); + + $this->assertSame('/', $body['REQUEST_URI']); + $this->assertNull($response->getInfo('redirect_url')); + + $response = $client->request('GET', 'http://localhost:8057/302/relative', [ + 'max_redirects' => 0, + ]); + + $this->assertSame(302, $response->getStatusCode()); + $this->assertSame('http://localhost:8057/', $response->getInfo('redirect_url')); + } + + public function testNoPrivateNetworkStream() + { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('GET', 'http://localhost:8057'); + $client = new NoPrivateNetworkHttpClient($client, '104.26.14.6/32'); + + $response = $client->request('GET', 'http://localhost:8057'); + $chunks = $client->stream($response); + $result = []; + + foreach ($chunks as $r => $chunk) { + if ($chunk->isTimeout()) { + $result[] = 't'; + } elseif ($chunk->isLast()) { + $result[] = 'l'; + } elseif ($chunk->isFirst()) { + $result[] = 'f'; + } + } + + $this->assertSame($response, $r); + $this->assertSame(['f', 'l'], $result); + + $chunk = null; + $i = 0; + + foreach ($client->stream($response) as $chunk) { + ++$i; + } + + $this->assertSame(1, $i); + $this->assertTrue($chunk->isLast()); + } + public function testNoRedirectWithInvalidLocation() { $client = $this->getHttpClient(__FUNCTION__); diff --git a/src/Symfony/Component/HttpClient/Tests/HttplugClientTest.php b/src/Symfony/Component/HttpClient/Tests/HttplugClientTest.php index 41ed55eda7822..51b469cb35b4e 100644 --- a/src/Symfony/Component/HttpClient/Tests/HttplugClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/HttplugClientTest.php @@ -32,11 +32,6 @@ public static function setUpBeforeClass(): void TestHttpServer::start(); } - public static function tearDownAfterClass(): void - { - TestHttpServer::stop(); - } - /** * @requires function ob_gzhandler */ diff --git a/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php b/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php index 65b7f5b3f6794..bf49535ae3e66 100644 --- a/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php @@ -28,11 +28,6 @@ public static function setUpBeforeClass(): void TestHttpServer::start(); } - public static function tearDownAfterClass(): void - { - TestHttpServer::stop(); - } - /** * @requires function ob_gzhandler */ diff --git a/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php index c15b0d2a4e0ad..9edf41318555e 100644 --- a/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php @@ -27,11 +27,6 @@ class RetryableHttpClientTest extends TestCase { - public static function tearDownAfterClass(): void - { - TestHttpServer::stop(); - } - public function testRetryOnError() { $client = new RetryableHttpClient( diff --git a/src/Symfony/Component/HttpClient/Tests/TraceableHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/TraceableHttpClientTest.php index 052400bb3cf96..5f20e1989dfa1 100644 --- a/src/Symfony/Component/HttpClient/Tests/TraceableHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/TraceableHttpClientTest.php @@ -29,11 +29,6 @@ public static function setUpBeforeClass(): void TestHttpServer::start(); } - public static function tearDownAfterClass(): void - { - TestHttpServer::stop(); - } - public function testItTracesRequest() { $httpClient = $this->createMock(HttpClientInterface::class); diff --git a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php index 2a70ea66a16ca..08825f7a0ed46 100644 --- a/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php +++ b/src/Symfony/Contracts/HttpClient/Test/HttpClientTestCase.php @@ -36,7 +36,6 @@ public static function tearDownAfterClass(): void { TestHttpServer::stop(8067); TestHttpServer::stop(8077); - TestHttpServer::stop(8087); } abstract protected function getHttpClient(string $testCase): HttpClientInterface; From dcda2c44ab7cc5c9ecccb5b333dabb9faef5a4b9 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 29 Nov 2024 09:36:44 +0100 Subject: [PATCH 07/37] Update CHANGELOG for 5.4.49 --- CHANGELOG-5.4.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG-5.4.md b/CHANGELOG-5.4.md index 23768a799ed86..8929969db1276 100644 --- a/CHANGELOG-5.4.md +++ b/CHANGELOG-5.4.md @@ -7,6 +7,10 @@ in 5.4 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/v5.4.0...v5.4.1 +* 5.4.49 (2024-11-29) + + * bug #59023 [HttpClient] Fix streaming and redirecting with NoPrivateNetworkHttpClient (nicolas-grekas) + * 5.4.48 (2024-11-27) * bug #59013 [HttpClient] Fix checking for private IPs before connecting (nicolas-grekas) From 23f75d33d284dd755d502b4f5cfbfe9f1398ceb4 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 29 Nov 2024 09:36:48 +0100 Subject: [PATCH 08/37] Update VERSION for 5.4.49 --- 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 a6a70bfb3cb4d..10a65d1393f36 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -78,12 +78,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static $freshCache = []; - public const VERSION = '5.4.49-DEV'; + public const VERSION = '5.4.49'; public const VERSION_ID = 50449; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 4; public const RELEASE_VERSION = 49; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2024'; public const END_OF_LIFE = '02/2029'; From ac4ca4616bf0dd18eb35d1b79b3a11a947d694e6 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 2 Dec 2024 07:48:00 +0100 Subject: [PATCH 09/37] fix Twig 3.17 compatibility --- .../Node/SearchAndRenderBlockNodeTest.php | 88 +++++++++++-------- 1 file changed, 49 insertions(+), 39 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Tests/Node/SearchAndRenderBlockNodeTest.php b/src/Symfony/Bridge/Twig/Tests/Node/SearchAndRenderBlockNodeTest.php index 5c2bacf19d5f8..47ec58acb36cb 100644 --- a/src/Symfony/Bridge/Twig/Tests/Node/SearchAndRenderBlockNodeTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Node/SearchAndRenderBlockNodeTest.php @@ -22,6 +22,7 @@ use Twig\Node\Expression\ConditionalExpression; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\NameExpression; +use Twig\Node\Expression\Ternary\ConditionalTernary; use Twig\Node\Expression\Variable\ContextVariable; use Twig\Node\Node; use Twig\Node\Nodes; @@ -308,32 +309,32 @@ public function testCompileLabelWithLabelAndAttributes() public function testCompileLabelWithLabelThatEvaluatesToNull() { + if (class_exists(ConditionalTernary::class)) { + $conditional = new ConditionalTernary( + // if + new ConstantExpression(true, 0), + // then + new ConstantExpression(null, 0), + // else + new ConstantExpression(null, 0), + 0 + ); + } else { + $conditional = new ConditionalExpression( + // if + new ConstantExpression(true, 0), + // then + new ConstantExpression(null, 0), + // else + new ConstantExpression(null, 0), + 0 + ); + } + if (class_exists(Nodes::class)) { - $arguments = new Nodes([ - new ContextVariable('form', 0), - new ConditionalExpression( - // if - new ConstantExpression(true, 0), - // then - new ConstantExpression(null, 0), - // else - new ConstantExpression(null, 0), - 0 - ), - ]); + $arguments = new Nodes([new ContextVariable('form', 0), $conditional]); } else { - $arguments = new Node([ - new NameExpression('form', 0), - new ConditionalExpression( - // if - new ConstantExpression(true, 0), - // then - new ConstantExpression(null, 0), - // else - new ConstantExpression(null, 0), - 0 - ), - ]); + $arguments = new Node([new NameExpression('form', 0), $conditional]); } if (class_exists(FirstClassTwigCallableReady::class)) { @@ -359,18 +360,32 @@ public function testCompileLabelWithLabelThatEvaluatesToNull() public function testCompileLabelWithLabelThatEvaluatesToNullAndAttributes() { + if (class_exists(ConditionalTernary::class)) { + $conditional = new ConditionalTernary( + // if + new ConstantExpression(true, 0), + // then + new ConstantExpression(null, 0), + // else + new ConstantExpression(null, 0), + 0 + ); + } else { + $conditional = new ConditionalExpression( + // if + new ConstantExpression(true, 0), + // then + new ConstantExpression(null, 0), + // else + new ConstantExpression(null, 0), + 0 + ); + } + if (class_exists(Nodes::class)) { $arguments = new Nodes([ new ContextVariable('form', 0), - new ConditionalExpression( - // if - new ConstantExpression(true, 0), - // then - new ConstantExpression(null, 0), - // else - new ConstantExpression(null, 0), - 0 - ), + $conditional, new ArrayExpression([ new ConstantExpression('foo', 0), new ConstantExpression('bar', 0), @@ -381,12 +396,7 @@ public function testCompileLabelWithLabelThatEvaluatesToNullAndAttributes() } else { $arguments = new Node([ new NameExpression('form', 0), - new ConditionalExpression( - new ConstantExpression(true, 0), - new ConstantExpression(null, 0), - new ConstantExpression(null, 0), - 0 - ), + $conditional, new ArrayExpression([ new ConstantExpression('foo', 0), new ConstantExpression('bar', 0), From 886d4eddfebcfdb067132c117bd5a08b00d38486 Mon Sep 17 00:00:00 2001 From: Maxime Pinot Date: Mon, 2 Dec 2024 12:09:41 +0100 Subject: [PATCH 10/37] [Mime] Fix wrong PHPDoc in `FormDataPart` constructor --- src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php b/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php index 904c86d6b3cfd..0db5dfa0abe44 100644 --- a/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php +++ b/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php @@ -26,7 +26,7 @@ final class FormDataPart extends AbstractMultipartPart private array $fields = []; /** - * @param array $fields + * @param array $fields */ public function __construct(array $fields = []) { From 55a46e75a4fb55b768bc291ff1aa00e47664e7c0 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 2 Dec 2024 15:13:07 +0100 Subject: [PATCH 11/37] evaluate access flags for properties with asymmetric visibility --- .../Extractor/ReflectionExtractor.php | 8 +++- .../Extractor/ReflectionExtractorTest.php | 45 +++++++++++++++++++ 2 files changed, 51 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index 8e00e6473a4e8..89239a53f3505 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -581,8 +581,12 @@ private function isAllowedProperty(string $class, string $property, bool $writeA return false; } - if (\PHP_VERSION_ID >= 80400 && ($reflectionProperty->isProtectedSet() || $reflectionProperty->isPrivateSet())) { - return false; + if (\PHP_VERSION_ID >= 80400 && $reflectionProperty->isProtectedSet()) { + return (bool) ($this->propertyReflectionFlags & \ReflectionProperty::IS_PROTECTED); + } + + if (\PHP_VERSION_ID >= 80400 && $reflectionProperty->isPrivateSet()) { + return (bool) ($this->propertyReflectionFlags & \ReflectionProperty::IS_PRIVATE); } if (\PHP_VERSION_ID >= 80400 &&$reflectionProperty->isVirtual() && !$reflectionProperty->hasHook(\PropertyHookType::Set)) { diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php index a6315103a2266..45565096d9963 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php @@ -672,6 +672,51 @@ public function testAsymmetricVisibility() $this->assertFalse($this->extractor->isWritable(AsymmetricVisibility::class, 'protectedPrivate')); } + /** + * @requires PHP 8.4 + */ + public function testAsymmetricVisibilityAllowPublicOnly() + { + $extractor = new ReflectionExtractor(null, null, null, true, ReflectionExtractor::ALLOW_PUBLIC); + + $this->assertTrue($extractor->isReadable(AsymmetricVisibility::class, 'publicPrivate')); + $this->assertTrue($extractor->isReadable(AsymmetricVisibility::class, 'publicProtected')); + $this->assertFalse($extractor->isReadable(AsymmetricVisibility::class, 'protectedPrivate')); + $this->assertFalse($extractor->isWritable(AsymmetricVisibility::class, 'publicPrivate')); + $this->assertFalse($extractor->isWritable(AsymmetricVisibility::class, 'publicProtected')); + $this->assertFalse($extractor->isWritable(AsymmetricVisibility::class, 'protectedPrivate')); + } + + /** + * @requires PHP 8.4 + */ + public function testAsymmetricVisibilityAllowProtectedOnly() + { + $extractor = new ReflectionExtractor(null, null, null, true, ReflectionExtractor::ALLOW_PROTECTED); + + $this->assertFalse($extractor->isReadable(AsymmetricVisibility::class, 'publicPrivate')); + $this->assertFalse($extractor->isReadable(AsymmetricVisibility::class, 'publicProtected')); + $this->assertTrue($extractor->isReadable(AsymmetricVisibility::class, 'protectedPrivate')); + $this->assertFalse($extractor->isWritable(AsymmetricVisibility::class, 'publicPrivate')); + $this->assertTrue($extractor->isWritable(AsymmetricVisibility::class, 'publicProtected')); + $this->assertFalse($extractor->isWritable(AsymmetricVisibility::class, 'protectedPrivate')); + } + + /** + * @requires PHP 8.4 + */ + public function testAsymmetricVisibilityAllowPrivateOnly() + { + $extractor = new ReflectionExtractor(null, null, null, true, ReflectionExtractor::ALLOW_PRIVATE); + + $this->assertFalse($extractor->isReadable(AsymmetricVisibility::class, 'publicPrivate')); + $this->assertFalse($extractor->isReadable(AsymmetricVisibility::class, 'publicProtected')); + $this->assertFalse($extractor->isReadable(AsymmetricVisibility::class, 'protectedPrivate')); + $this->assertTrue($extractor->isWritable(AsymmetricVisibility::class, 'publicPrivate')); + $this->assertFalse($extractor->isWritable(AsymmetricVisibility::class, 'publicProtected')); + $this->assertTrue($extractor->isWritable(AsymmetricVisibility::class, 'protectedPrivate')); + } + /** * @requires PHP 8.4 */ From bfdf5d92312f42db46ac8ceb21b129ea25e53045 Mon Sep 17 00:00:00 2001 From: Kurt Thiemann Date: Mon, 2 Dec 2024 12:18:11 +0100 Subject: [PATCH 12/37] [HttpClient] Always set CURLOPT_CUSTOMREQUEST to the correct HTTP method in CurlHttpClient --- .../Component/HttpClient/CurlHttpClient.php | 3 +-- .../HttpClient/Tests/HttpClientTestCase.php | 22 +++++++++++++++++++ .../Component/HttpClient/composer.json | 2 +- .../HttpClient/Test/Fixtures/web/index.php | 1 + 4 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php index 7d996200527eb..3e15bef74cc9e 100644 --- a/src/Symfony/Component/HttpClient/CurlHttpClient.php +++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php @@ -197,13 +197,12 @@ public function request(string $method, string $url, array $options = []): Respo $curlopts[\CURLOPT_RESOLVE] = $resolve; } + $curlopts[\CURLOPT_CUSTOMREQUEST] = $method; if ('POST' === $method) { // Use CURLOPT_POST to have browser-like POST-to-GET redirects for 301, 302 and 303 $curlopts[\CURLOPT_POST] = true; } elseif ('HEAD' === $method) { $curlopts[\CURLOPT_NOBODY] = true; - } else { - $curlopts[\CURLOPT_CUSTOMREQUEST] = $method; } if ('\\' !== \DIRECTORY_SEPARATOR && $options['timeout'] < 1) { diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php index a0e57bf2c5ff4..f572908c1535d 100644 --- a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php +++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php @@ -651,4 +651,26 @@ public function testDefaultContentType() $this->assertSame(['abc' => 'def', 'content-type' => 'application/json', 'REQUEST_METHOD' => 'POST'], $response->toArray()); } + + public function testHeadRequestWithClosureBody() + { + $p = TestHttpServer::start(8067); + + try { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('HEAD', 'http://localhost:8057/head', [ + 'body' => fn () => '', + ]); + $headers = $response->getHeaders(); + } finally { + $p->stop(); + } + + $this->assertArrayHasKey('x-request-vars', $headers); + + $vars = json_decode($headers['x-request-vars'][0], true); + $this->assertIsArray($vars); + $this->assertSame('HEAD', $vars['REQUEST_METHOD']); + } } diff --git a/src/Symfony/Component/HttpClient/composer.json b/src/Symfony/Component/HttpClient/composer.json index 23437d5363f28..9c9ee14a4a3ff 100644 --- a/src/Symfony/Component/HttpClient/composer.json +++ b/src/Symfony/Component/HttpClient/composer.json @@ -25,7 +25,7 @@ "php": ">=8.1", "psr/log": "^1|^2|^3", "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-client-contracts": "~3.4.3|^3.5.1", + "symfony/http-client-contracts": "~3.4.4|^3.5.2", "symfony/service-contracts": "^2.5|^3" }, "require-dev": { diff --git a/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php b/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php index a75001785ae2d..59033d55a0350 100644 --- a/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php +++ b/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php @@ -42,6 +42,7 @@ exit; case '/head': + header('X-Request-Vars: '.json_encode($vars, \JSON_UNESCAPED_SLASHES | \JSON_UNESCAPED_UNICODE)); header('Content-Length: '.strlen($json), true); break; From 15d56bb070669d73f165f7c39c176e368126f529 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Wed, 4 Dec 2024 15:37:29 +0100 Subject: [PATCH 13/37] Add an experimental CI job for PHP 8.5 --- .github/workflows/unit-tests.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index e5defe2a989f9..8849fd3a94c58 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -33,6 +33,7 @@ jobs: mode: low-deps - php: '8.3' - php: '8.4' + - php: '8.5' #mode: experimental fail-fast: false From 91cd48227ba61bb36d92f9933e69170342f75567 Mon Sep 17 00:00:00 2001 From: Alexandre Daubois Date: Wed, 4 Dec 2024 16:33:28 +0100 Subject: [PATCH 14/37] [ErrorHandler] Fix error message with PHP 8.5 --- .../ErrorHandler/Tests/phpt/fatal_with_nested_handlers.phpt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/ErrorHandler/Tests/phpt/fatal_with_nested_handlers.phpt b/src/Symfony/Component/ErrorHandler/Tests/phpt/fatal_with_nested_handlers.phpt index cfb10d03dafdd..81becafd8e350 100644 --- a/src/Symfony/Component/ErrorHandler/Tests/phpt/fatal_with_nested_handlers.phpt +++ b/src/Symfony/Component/ErrorHandler/Tests/phpt/fatal_with_nested_handlers.phpt @@ -24,7 +24,7 @@ var_dump([ $eHandler[0]->setExceptionHandler('print_r'); if (true) { - class Broken implements \JsonSerializable + class Broken implements \Iterator { } } @@ -37,14 +37,14 @@ array(1) { } object(Symfony\Component\ErrorHandler\Error\FatalError)#%d (%d) { ["message":protected]=> - string(186) "Error: Class Symfony\Component\ErrorHandler\Broken contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (JsonSerializable::jsonSerialize)" + string(209) "Error: Class Symfony\Component\ErrorHandler\Broken contains 5 abstract methods and must therefore be declared abstract or implement the remaining methods (Iterator::current, Iterator::next, Iterator::key, ...)" %a ["error":"Symfony\Component\ErrorHandler\Error\FatalError":private]=> array(4) { ["type"]=> int(1) ["message"]=> - string(179) "Class Symfony\Component\ErrorHandler\Broken contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (JsonSerializable::jsonSerialize)" + string(202) "Class Symfony\Component\ErrorHandler\Broken contains 5 abstract methods and must therefore be declared abstract or implement the remaining methods (Iterator::current, Iterator::next, Iterator::key, ...)" ["file"]=> string(%d) "%s" ["line"]=> From ee400b0b88372e1f496355bfb4708b6ba9ec46a9 Mon Sep 17 00:00:00 2001 From: Sven Nolting Date: Mon, 2 Dec 2024 14:51:36 +0100 Subject: [PATCH 15/37] [Console] Fix division by 0 error --- src/Symfony/Component/Console/Helper/ProgressBar.php | 2 +- .../Component/Console/Tests/Helper/ProgressBarTest.php | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Helper/ProgressBar.php b/src/Symfony/Component/Console/Helper/ProgressBar.php index b406292b44b3a..23157e3c7b2db 100644 --- a/src/Symfony/Component/Console/Helper/ProgressBar.php +++ b/src/Symfony/Component/Console/Helper/ProgressBar.php @@ -229,7 +229,7 @@ public function getEstimated(): float public function getRemaining(): float { - if (!$this->step) { + if (0 === $this->step || $this->step === $this->startingStep) { return 0; } diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php index a5a0eca245080..c32307720fce8 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php @@ -110,6 +110,14 @@ public function testRegularTimeEstimation() ); } + public function testRegularTimeRemainingWithDifferentStartAtAndCustomDisplay() + { + ProgressBar::setFormatDefinition('custom', ' %current%/%max% [%bar%] %percent:3s%% %remaining% %estimated%'); + $bar = new ProgressBar($output = $this->getOutputStream(), 1_200, 0); + $bar->setFormat('custom'); + $bar->start(1_200, 600); + } + public function testResumedTimeEstimation() { $bar = new ProgressBar($output = $this->getOutputStream(), 1_200, 0); From 6262a6271d43fd3bb9fda15c7a956d95821105ca Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Sat, 7 Dec 2024 10:09:39 +0100 Subject: [PATCH 16/37] Add tests covering `trans_default_domain` with dynamic expressions --- .../Extension/TranslationExtensionTest.php | 62 +++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php index 96f707cdfdf2c..f6dd5f623baee 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php @@ -206,6 +206,68 @@ public function testDefaultTranslationDomainWithNamedArguments() $this->assertEquals('foo (custom)foo (foo)foo (custom)foo (custom)foo (fr)foo (custom)foo (fr)', trim($template->render([]))); } + public function testDefaultTranslationDomainWithExpression() + { + $templates = [ + 'index' => ' + {%- extends "base" %} + + {%- trans_default_domain custom_domain %} + + {%- block content %} + {{- "foo"|trans }} + {%- endblock %} + ', + + 'base' => ' + {%- block content "" %} + ', + ]; + + $translator = new Translator('en'); + $translator->addLoader('array', new ArrayLoader()); + $translator->addResource('array', ['foo' => 'foo (messages)'], 'en'); + $translator->addResource('array', ['foo' => 'foo (custom)'], 'en', 'custom'); + $translator->addResource('array', ['foo' => 'foo (foo)'], 'en', 'foo'); + + $template = $this->getTemplate($templates, $translator); + + $this->assertEquals('foo (foo)', trim($template->render(['custom_domain' => 'foo']))); + } + + public function testDefaultTranslationDomainWithExpressionAndInheritance() + { + $templates = [ + 'index' => ' + {%- extends "base" %} + + {%- trans_default_domain foo_domain %} + + {%- block content %} + {{- "foo"|trans }} + {%- endblock %} + ', + + 'base' => ' + {%- trans_default_domain custom_domain %} + + {{- "foo"|trans }} + {%- block content "" %} + {{- "foo"|trans }} + ', + ]; + + $translator = new Translator('en'); + $translator->addLoader('array', new ArrayLoader()); + $translator->addResource('array', ['foo' => 'foo (messages)'], 'en'); + $translator->addResource('array', ['foo' => 'foo (custom)'], 'en', 'custom'); + $translator->addResource('array', ['foo' => 'foo (foo)'], 'en', 'foo'); + + $template = $this->getTemplate($templates, $translator); + + $this->assertEquals('foo (custom)foo (foo)foo (custom)', trim($template->render(['foo_domain' => 'foo', 'custom_domain' => 'custom']))); + } + private function getTemplate($template, ?TranslatorInterface $translator = null): TemplateWrapper { $translator ??= new Translator('en'); From 97d6e68b2ae92c5dc4131e97425c36f9c3764a8d Mon Sep 17 00:00:00 2001 From: raphael-geffroy Date: Sat, 7 Dec 2024 12:28:46 +0100 Subject: [PATCH 17/37] fix: notifier push channel bus abstract arg --- .../DependencyInjection/FrameworkExtension.php | 2 +- .../Bundle/FrameworkBundle/Resources/config/notifier.php | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 83518061fed36..36984e7398528 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -2765,7 +2765,7 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $ $container->removeDefinition('notifier.channel.email'); } - foreach (['texter', 'chatter', 'notifier.channel.chat', 'notifier.channel.email', 'notifier.channel.sms'] as $serviceId) { + foreach (['texter', 'chatter', 'notifier.channel.chat', 'notifier.channel.email', 'notifier.channel.sms', 'notifier.channel.push'] as $serviceId) { if (!$container->hasDefinition($serviceId)) { continue; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier.php index 6ce674148a878..bcc1248208c61 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/notifier.php @@ -73,7 +73,10 @@ ->tag('notifier.channel', ['channel' => 'email']) ->set('notifier.channel.push', PushChannel::class) - ->args([service('texter.transports'), service('messenger.default_bus')->ignoreOnInvalid()]) + ->args([ + service('texter.transports'), + abstract_arg('message bus'), + ]) ->tag('notifier.channel', ['channel' => 'push']) ->set('notifier.monolog_handler', NotifierHandler::class) From 4cca70ba1dbf996ece9fb2c9622bcf7f2be58f84 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 7 Dec 2024 13:07:30 +0100 Subject: [PATCH 18/37] fix risky test that doesn't perform any assertions --- .../Component/Console/Tests/Helper/ProgressBarTest.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php index c32307720fce8..a1db94583db49 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php @@ -112,8 +112,10 @@ public function testRegularTimeEstimation() public function testRegularTimeRemainingWithDifferentStartAtAndCustomDisplay() { + $this->expectNotToPerformAssertions(); + ProgressBar::setFormatDefinition('custom', ' %current%/%max% [%bar%] %percent:3s%% %remaining% %estimated%'); - $bar = new ProgressBar($output = $this->getOutputStream(), 1_200, 0); + $bar = new ProgressBar($this->getOutputStream(), 1_200, 0); $bar->setFormat('custom'); $bar->start(1_200, 600); } From ac08b9a5c41c9ccff2892d085bed4de660d582c6 Mon Sep 17 00:00:00 2001 From: Christopher Hertel Date: Mon, 9 Dec 2024 00:00:41 +0100 Subject: [PATCH 19/37] fix: preserve and nowrap in profiler code highlighting --- .../WebProfilerBundle/Resources/views/Profiler/open.css.twig | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/open.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/open.css.twig index af9f0a4ceaba3..55589c2945d88 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/open.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/open.css.twig @@ -40,6 +40,7 @@ #source .source-content ol li { margin: 0 0 2px 0; padding-left: 5px; + white-space: preserve nowrap; } #source .source-content ol li::marker { color: var(--color-muted); From e0957a0b33bf44814914810aa412180554ea4c64 Mon Sep 17 00:00:00 2001 From: Ionut Enache Date: Sat, 7 Dec 2024 22:19:39 +0200 Subject: [PATCH 20/37] [HttpKernel] Denormalize request data using the csv format when using "#[MapQueryString]" or "#[MapRequestPayload]" (except for content data) --- .../RequestPayloadValueResolver.php | 6 +- .../RequestPayloadValueResolverTest.php | 65 +++++++++++++++++++ 2 files changed, 67 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php index 444be1b3fe7d2..542297c035e3b 100644 --- a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php +++ b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver/RequestPayloadValueResolver.php @@ -40,11 +40,9 @@ class RequestPayloadValueResolver implements ValueResolverInterface, EventSubscriberInterface { /** - * @see \Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer::DISABLE_TYPE_ENFORCEMENT * @see DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS */ private const CONTEXT_DENORMALIZE = [ - 'disable_type_enforcement' => true, 'collect_denormalization_errors' => true, ]; @@ -161,7 +159,7 @@ private function mapQueryString(Request $request, string $type, MapQueryString $ return null; } - return $this->serializer->denormalize($data, $type, null, $attribute->serializationContext + self::CONTEXT_DENORMALIZE); + return $this->serializer->denormalize($data, $type, 'csv', $attribute->serializationContext + self::CONTEXT_DENORMALIZE); } private function mapRequestPayload(Request $request, string $type, MapRequestPayload $attribute): ?object @@ -175,7 +173,7 @@ private function mapRequestPayload(Request $request, string $type, MapRequestPay } if ($data = $request->request->all()) { - return $this->serializer->denormalize($data, $type, null, $attribute->serializationContext + self::CONTEXT_DENORMALIZE); + return $this->serializer->denormalize($data, $type, 'csv', $attribute->serializationContext + self::CONTEXT_DENORMALIZE); } if ('' === $data = $request->getContent()) { diff --git a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/RequestPayloadValueResolverTest.php b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/RequestPayloadValueResolverTest.php index 331c2a529d8c0..7c5c946560737 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/RequestPayloadValueResolverTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Controller/ArgumentResolver/RequestPayloadValueResolverTest.php @@ -22,6 +22,7 @@ use Symfony\Component\HttpKernel\Exception\HttpException; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\PropertyAccess\Exception\InvalidTypeException; +use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor; use Symfony\Component\Serializer\Encoder\JsonEncoder; use Symfony\Component\Serializer\Encoder\XmlEncoder; use Symfony\Component\Serializer\Exception\PartialDenormalizationException; @@ -363,6 +364,38 @@ public function testQueryStringValidationPassed() $this->assertEquals([$payload], $event->getArguments()); } + public function testQueryStringParameterTypeMismatch() + { + $query = ['price' => 'not a float']; + + $normalizer = new ObjectNormalizer(null, null, null, new ReflectionExtractor()); + $serializer = new Serializer([$normalizer], ['json' => new JsonEncoder()]); + + $validator = $this->createMock(ValidatorInterface::class); + $validator->expects($this->never())->method('validate'); + + $resolver = new RequestPayloadValueResolver($serializer, $validator); + + $argument = new ArgumentMetadata('invalid', RequestPayload::class, false, false, null, false, [ + MapQueryString::class => new MapQueryString(), + ]); + + $request = Request::create('/', 'GET', $query); + + $kernel = $this->createMock(HttpKernelInterface::class); + $arguments = $resolver->resolve($request, $argument); + $event = new ControllerArgumentsEvent($kernel, function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST); + + try { + $resolver->onKernelControllerArguments($event); + $this->fail(sprintf('Expected "%s" to be thrown.', HttpException::class)); + } catch (HttpException $e) { + $validationFailedException = $e->getPrevious(); + $this->assertInstanceOf(ValidationFailedException::class, $validationFailedException); + $this->assertSame('This value should be of type float.', $validationFailedException->getViolations()[0]->getMessage()); + } + } + public function testRequestInputValidationPassed() { $input = ['price' => '50']; @@ -391,6 +424,38 @@ public function testRequestInputValidationPassed() $this->assertEquals([$payload], $event->getArguments()); } + public function testRequestInputTypeMismatch() + { + $input = ['price' => 'not a float']; + + $normalizer = new ObjectNormalizer(null, null, null, new ReflectionExtractor()); + $serializer = new Serializer([$normalizer], ['json' => new JsonEncoder()]); + + $validator = $this->createMock(ValidatorInterface::class); + $validator->expects($this->never())->method('validate'); + + $resolver = new RequestPayloadValueResolver($serializer, $validator); + + $argument = new ArgumentMetadata('invalid', RequestPayload::class, false, false, null, false, [ + MapRequestPayload::class => new MapRequestPayload(), + ]); + + $request = Request::create('/', 'POST', $input); + + $kernel = $this->createMock(HttpKernelInterface::class); + $arguments = $resolver->resolve($request, $argument); + $event = new ControllerArgumentsEvent($kernel, function () {}, $arguments, $request, HttpKernelInterface::MAIN_REQUEST); + + try { + $resolver->onKernelControllerArguments($event); + $this->fail(sprintf('Expected "%s" to be thrown.', HttpException::class)); + } catch (HttpException $e) { + $validationFailedException = $e->getPrevious(); + $this->assertInstanceOf(ValidationFailedException::class, $validationFailedException); + $this->assertSame('This value should be of type float.', $validationFailedException->getViolations()[0]->getMessage()); + } + } + public function testItThrowsOnVariadicArgument() { $serializer = new Serializer(); From a96cfa400f5395435930e9225d66e2e37e86927c Mon Sep 17 00:00:00 2001 From: Kurt Thiemann Date: Thu, 5 Dec 2024 14:35:19 +0100 Subject: [PATCH 21/37] [HttpClient] Test POST to GET redirects --- .../HttpClient/Tests/HttpClientTestCase.php | 22 +++++++++++++++++++ .../HttpClient/Test/Fixtures/web/index.php | 10 +++++++++ 2 files changed, 32 insertions(+) diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php index f572908c1535d..79763bc1019f3 100644 --- a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php +++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php @@ -673,4 +673,26 @@ public function testHeadRequestWithClosureBody() $this->assertIsArray($vars); $this->assertSame('HEAD', $vars['REQUEST_METHOD']); } + + /** + * @testWith [301] + * [302] + * [303] + */ + public function testPostToGetRedirect(int $status) + { + $p = TestHttpServer::start(8067); + + try { + $client = $this->getHttpClient(__FUNCTION__); + + $response = $client->request('POST', 'http://localhost:8057/custom?status=' . $status . '&headers[]=Location%3A%20%2F'); + $body = $response->toArray(); + } finally { + $p->stop(); + } + + $this->assertSame('GET', $body['REQUEST_METHOD']); + $this->assertSame('/', $body['REQUEST_URI']); + } } diff --git a/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php b/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php index 59033d55a0350..399f8bdde17b6 100644 --- a/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php +++ b/src/Symfony/Contracts/HttpClient/Test/Fixtures/web/index.php @@ -199,6 +199,16 @@ ]); exit; + + case '/custom': + if (isset($_GET['status'])) { + http_response_code((int) $_GET['status']); + } + if (isset($_GET['headers']) && is_array($_GET['headers'])) { + foreach ($_GET['headers'] as $header) { + header($header); + } + } } header('Content-Type: application/json', true); From 88e7a7226c0bb0ee211799a4a1fa4eb5e9f0e9af Mon Sep 17 00:00:00 2001 From: Jan Nedbal Date: Wed, 27 Nov 2024 11:52:54 +0100 Subject: [PATCH 22/37] [PropertyInfo] Fix interface handling in `PhpStanTypeHelper` --- .../Tests/Extractor/PhpStanExtractorTest.php | 86 ++++++++++++++++++- .../Tests/Fixtures/DummyGeneric.php | 41 +++++++++ .../PropertyInfo/Util/PhpStanTypeHelper.php | 2 +- 3 files changed, 127 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyGeneric.php diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php index b97032574ab86..b7987668b4f8f 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php @@ -14,10 +14,13 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; use Symfony\Component\PropertyInfo\Extractor\PhpStanExtractor; +use Symfony\Component\PropertyInfo\Tests\Fixtures\Clazz; use Symfony\Component\PropertyInfo\Tests\Fixtures\ConstructorDummyWithoutDocBlock; use Symfony\Component\PropertyInfo\Tests\Fixtures\DefaultValue; use Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\DummyCollection; +use Symfony\Component\PropertyInfo\Tests\Fixtures\DummyGeneric; +use Symfony\Component\PropertyInfo\Tests\Fixtures\IFace; use Symfony\Component\PropertyInfo\Tests\Fixtures\ParentDummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\Php80Dummy; use Symfony\Component\PropertyInfo\Tests\Fixtures\Php80PromotedDummy; @@ -482,7 +485,88 @@ public static function php80TypesProvider() public function testGenericInterface() { - $this->assertNull($this->extractor->getTypes(Dummy::class, 'genericInterface')); + $this->assertEquals( + [ + new Type( + builtinType: Type::BUILTIN_TYPE_OBJECT, + class: \BackedEnum::class, + collectionValueType: new Type( + builtinType: Type::BUILTIN_TYPE_STRING, + ) + ), + ], + $this->extractor->getTypes(Dummy::class, 'genericInterface') + ); + } + + /** + * @param list $expectedTypes + * @dataProvider genericsProvider + */ + public function testGenericsLegacy(string $property, array $expectedTypes) + { + $this->assertEquals($expectedTypes, $this->extractor->getTypes(DummyGeneric::class, $property)); + } + + /** + * @return iterable}> + */ + public static function genericsProvider(): iterable + { + yield [ + 'basicClass', + [ + new Type( + builtinType: Type::BUILTIN_TYPE_OBJECT, + class: Clazz::class, + collectionValueType: new Type( + builtinType: Type::BUILTIN_TYPE_OBJECT, + class: Dummy::class, + ) + ), + ], + ]; + yield [ + 'nullableClass', + [ + new Type( + builtinType: Type::BUILTIN_TYPE_OBJECT, + class: Clazz::class, + nullable: true, + collectionValueType: new Type( + builtinType: Type::BUILTIN_TYPE_OBJECT, + class: Dummy::class, + ) + ), + ], + ]; + yield [ + 'basicInterface', + [ + new Type( + builtinType: Type::BUILTIN_TYPE_OBJECT, + class: IFace::class, + collectionValueType: new Type( + builtinType: Type::BUILTIN_TYPE_OBJECT, + class: Dummy::class, + ) + ), + ], + ]; + yield [ + 'nullableInterface', + [ + new Type( + builtinType: Type::BUILTIN_TYPE_OBJECT, + class: IFace::class, + nullable: true, + collectionValueType: new Type( + builtinType: Type::BUILTIN_TYPE_OBJECT, + class: Dummy::class, + ) + ), + ], + ]; } } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyGeneric.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyGeneric.php new file mode 100644 index 0000000000000..5863fbfc95450 --- /dev/null +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyGeneric.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyInfo\Tests\Fixtures; + +interface IFace {} + +class Clazz {} + +class DummyGeneric +{ + + /** + * @var Clazz + */ + public $basicClass; + + /** + * @var ?Clazz + */ + public $nullableClass; + + /** + * @var IFace + */ + public $basicInterface; + + /** + * @var ?IFace + */ + public $nullableInterface; + +} diff --git a/src/Symfony/Component/PropertyInfo/Util/PhpStanTypeHelper.php b/src/Symfony/Component/PropertyInfo/Util/PhpStanTypeHelper.php index 7d439f55660dd..56a6b509172c7 100644 --- a/src/Symfony/Component/PropertyInfo/Util/PhpStanTypeHelper.php +++ b/src/Symfony/Component/PropertyInfo/Util/PhpStanTypeHelper.php @@ -128,7 +128,7 @@ private function extractTypes(TypeNode $node, NameScope $nameScope): array $collection = $mainType->isCollection() || \is_a($mainType->getClassName(), \Traversable::class, true) || \is_a($mainType->getClassName(), \ArrayAccess::class, true); // it's safer to fall back to other extractors if the generic type is too abstract - if (!$collection && !class_exists($mainType->getClassName())) { + if (!$collection && !class_exists($mainType->getClassName()) && !interface_exists($mainType->getClassName(), false)) { return []; } From 99aae50d516ad4d14b3d5c6e551c5e8ad1dae80f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Igor=20Planta=C5=A1?= Date: Tue, 10 Dec 2024 15:49:24 +0100 Subject: [PATCH 23/37] [BeanstalkMessenger] Round delay to an integer to avoid deprecation warning --- .../Tests/Transport/ConnectionTest.php | 21 +++++++++++++++++++ .../Beanstalkd/Transport/Connection.php | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/Bridge/Beanstalkd/Tests/Transport/ConnectionTest.php b/src/Symfony/Component/Messenger/Bridge/Beanstalkd/Tests/Transport/ConnectionTest.php index f4cc745846584..bf54ac1272483 100644 --- a/src/Symfony/Component/Messenger/Bridge/Beanstalkd/Tests/Transport/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Beanstalkd/Tests/Transport/ConnectionTest.php @@ -330,4 +330,25 @@ public function testSendWhenABeanstalkdExceptionOccurs() $connection->send($body, $headers, $delay); } + + public function testSendWithRoundedDelay() + { + $tube = 'xyz'; + $body = 'foo'; + $headers = ['test' => 'bar']; + $delay = 920; + $expectedDelay = 0; + + $client = $this->createMock(PheanstalkInterface::class); + $client->expects($this->once())->method('useTube')->with($tube)->willReturn($client); + $client->expects($this->once())->method('put')->with( + $this->anything(), + $this->anything(), + $expectedDelay, + $this->anything(), + ); + + $connection = new Connection(['tube_name' => $tube], $client); + $connection->send($body, $headers, $delay); + } } diff --git a/src/Symfony/Component/Messenger/Bridge/Beanstalkd/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Beanstalkd/Transport/Connection.php index 98ab37c875d18..ff520ddb3071f 100644 --- a/src/Symfony/Component/Messenger/Bridge/Beanstalkd/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/Beanstalkd/Transport/Connection.php @@ -123,7 +123,7 @@ public function send(string $body, array $headers, int $delay = 0): string $job = $this->client->useTube($this->tube)->put( $message, PheanstalkInterface::DEFAULT_PRIORITY, - $delay / 1000, + (int) ($delay / 1000), $this->ttr ); } catch (Exception $exception) { From d8fa076a63d4cb4db7e58c7f15ac2e6b2bb1ebbc Mon Sep 17 00:00:00 2001 From: Tim Goudriaan Date: Sat, 7 Dec 2024 12:26:50 +0100 Subject: [PATCH 24/37] [Scheduler] Fix optional count variable in testGetNextRunDates --- .../Scheduler/Tests/Trigger/PeriodicalTriggerTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Scheduler/Tests/Trigger/PeriodicalTriggerTest.php b/src/Symfony/Component/Scheduler/Tests/Trigger/PeriodicalTriggerTest.php index 22162e792fa24..8f1ce90fee72a 100644 --- a/src/Symfony/Component/Scheduler/Tests/Trigger/PeriodicalTriggerTest.php +++ b/src/Symfony/Component/Scheduler/Tests/Trigger/PeriodicalTriggerTest.php @@ -108,9 +108,9 @@ public static function provideForToString() /** * @dataProvider providerGetNextRunDates */ - public function testGetNextRunDates(\DateTimeImmutable $from, TriggerInterface $trigger, array $expected, int $count = 0) + public function testGetNextRunDates(\DateTimeImmutable $from, TriggerInterface $trigger, array $expected, int $count) { - $this->assertEquals($expected, $this->getNextRunDates($from, $trigger, $count ?? \count($expected))); + $this->assertEquals($expected, $this->getNextRunDates($from, $trigger, $count)); } public static function providerGetNextRunDates(): iterable From 0332f5ea46ded09fd8530bfb483fe4252e7a1028 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sat, 14 Dec 2024 16:09:22 +0100 Subject: [PATCH 25/37] Remove 5.4 branch from PR template --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 90e51d60536d6..3d21822287b6b 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,6 @@ | Q | A | ------------- | --- -| Branch? | 7.3 for features / 5.4, 6.4, 7.1, and 7.2 for bug fixes +| Branch? | 7.3 for features / 6.4, 7.1, and 7.2 for bug fixes | Bug fix? | yes/no | New feature? | yes/no | Deprecations? | yes/no From cf64a866f7323c2a2643f3bea5eeffd7994356db Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 15 Dec 2024 11:26:42 +0100 Subject: [PATCH 26/37] don't require fake notifier transports to be installed as non-dev dependencies --- .../FrameworkExtension.php | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 36984e7398528..aed6bdefa2c6f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -122,6 +122,8 @@ use Symfony\Component\Mime\MimeTypeGuesserInterface; use Symfony\Component\Mime\MimeTypes; use Symfony\Component\Notifier\Bridge as NotifierBridge; +use Symfony\Component\Notifier\Bridge\FakeChat\FakeChatTransportFactory; +use Symfony\Component\Notifier\Bridge\FakeSms\FakeSmsTransportFactory; use Symfony\Component\Notifier\ChatterInterface; use Symfony\Component\Notifier\Notifier; use Symfony\Component\Notifier\Recipient\Recipient; @@ -2812,8 +2814,6 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $ NotifierBridge\Engagespot\EngagespotTransportFactory::class => 'notifier.transport_factory.engagespot', NotifierBridge\Esendex\EsendexTransportFactory::class => 'notifier.transport_factory.esendex', NotifierBridge\Expo\ExpoTransportFactory::class => 'notifier.transport_factory.expo', - NotifierBridge\FakeChat\FakeChatTransportFactory::class => 'notifier.transport_factory.fake-chat', - NotifierBridge\FakeSms\FakeSmsTransportFactory::class => 'notifier.transport_factory.fake-sms', NotifierBridge\Firebase\FirebaseTransportFactory::class => 'notifier.transport_factory.firebase', NotifierBridge\FortySixElks\FortySixElksTransportFactory::class => 'notifier.transport_factory.forty-six-elks', NotifierBridge\FreeMobile\FreeMobileTransportFactory::class => 'notifier.transport_factory.free-mobile', @@ -2891,20 +2891,26 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $ $container->removeDefinition($classToServices[NotifierBridge\Mercure\MercureTransportFactory::class]); } - if (ContainerBuilder::willBeAvailable('symfony/fake-chat-notifier', NotifierBridge\FakeChat\FakeChatTransportFactory::class, ['symfony/framework-bundle', 'symfony/notifier', 'symfony/mailer'])) { - $container->getDefinition($classToServices[NotifierBridge\FakeChat\FakeChatTransportFactory::class]) - ->replaceArgument(0, new Reference('mailer')) - ->replaceArgument(1, new Reference('logger')) + // don't use ContainerBuilder::willBeAvailable() as these are not needed in production + if (class_exists(FakeChatTransportFactory::class)) { + $container->getDefinition('notifier.transport_factory.fake-chat') + ->replaceArgument(0, new Reference('mailer', ContainerBuilder::NULL_ON_INVALID_REFERENCE)) + ->replaceArgument(1, new Reference('logger', ContainerBuilder::NULL_ON_INVALID_REFERENCE)) ->addArgument(new Reference('event_dispatcher', ContainerBuilder::NULL_ON_INVALID_REFERENCE)) ->addArgument(new Reference('http_client', ContainerBuilder::NULL_ON_INVALID_REFERENCE)); + } else { + $container->removeDefinition('notifier.transport_factory.fake-chat'); } - if (ContainerBuilder::willBeAvailable('symfony/fake-sms-notifier', NotifierBridge\FakeSms\FakeSmsTransportFactory::class, ['symfony/framework-bundle', 'symfony/notifier', 'symfony/mailer'])) { - $container->getDefinition($classToServices[NotifierBridge\FakeSms\FakeSmsTransportFactory::class]) - ->replaceArgument(0, new Reference('mailer')) - ->replaceArgument(1, new Reference('logger')) + // don't use ContainerBuilder::willBeAvailable() as these are not needed in production + if (class_exists(FakeSmsTransportFactory::class)) { + $container->getDefinition('notifier.transport_factory.fake-sms') + ->replaceArgument(0, new Reference('mailer', ContainerBuilder::NULL_ON_INVALID_REFERENCE)) + ->replaceArgument(1, new Reference('logger', ContainerBuilder::NULL_ON_INVALID_REFERENCE)) ->addArgument(new Reference('event_dispatcher', ContainerBuilder::NULL_ON_INVALID_REFERENCE)) ->addArgument(new Reference('http_client', ContainerBuilder::NULL_ON_INVALID_REFERENCE)); + } else { + $container->removeDefinition('notifier.transport_factory.fake-sms'); } if (isset($config['admin_recipients'])) { From 8448227905e52e35fcdb6a777445abedb53c2e32 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 16 Dec 2024 16:09:00 +0100 Subject: [PATCH 27/37] require the writer to implement getFormats() in the translation:extract --- .../Command/TranslationUpdateCommand.php | 4 +++ .../Compiler/TranslationUpdateCommandPass.php | 31 +++++++++++++++++++ .../FrameworkBundle/FrameworkBundle.php | 2 ++ 3 files changed, 37 insertions(+) create mode 100644 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TranslationUpdateCommandPass.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php index 91e7e33491d97..0ffe6a949d472 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php @@ -64,6 +64,10 @@ public function __construct(TranslationWriterInterface $writer, TranslationReade { parent::__construct(); + if (!method_exists($writer, 'getFormats')) { + throw new \InvalidArgumentException(sprintf('The writer class "%s" does not implement the "getFormats()" method.', $writer::class)); + } + $this->writer = $writer; $this->reader = $reader; $this->extractor = $extractor; diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TranslationUpdateCommandPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TranslationUpdateCommandPass.php new file mode 100644 index 0000000000000..7542191d0e83e --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/TranslationUpdateCommandPass.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +class TranslationUpdateCommandPass implements CompilerPassInterface +{ + public function process(ContainerBuilder $container): void + { + if (!$container->hasDefinition('console.command.translation_extract')) { + return; + } + + $translationWriterClass = $container->getParameterBag()->resolveValue($container->findDefinition('translation.writer')->getClass()); + + if (!method_exists($translationWriterClass, 'getFormats')) { + $container->removeDefinition('console.command.translation_extract'); + } + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 0da10da9d77f8..c371d10dbc684 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -20,6 +20,7 @@ use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RemoveUnusedSessionMarshallingHandlerPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TestServiceContainerRealRefPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TestServiceContainerWeakRefPass; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\TranslationUpdateCommandPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\UnusedTagsPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\VirtualRequestStackPass; use Symfony\Component\Cache\Adapter\ApcuAdapter; @@ -193,6 +194,7 @@ public function build(ContainerBuilder $container) // must be registered after MonologBundle's LoggerChannelPass $container->addCompilerPass(new ErrorLoggerCompilerPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -32); $container->addCompilerPass(new VirtualRequestStackPass()); + $container->addCompilerPass(new TranslationUpdateCommandPass(), PassConfig::TYPE_BEFORE_REMOVING); if ($container->getParameter('kernel.debug')) { $container->addCompilerPass(new AddDebugLogProcessorPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 2); From f38d4b07fafcf9b198597ef07ec971512dcf7eaa Mon Sep 17 00:00:00 2001 From: Nicolas PHILIPPE Date: Thu, 5 Dec 2024 18:36:22 +0100 Subject: [PATCH 28/37] [Messenger] ensure exception on rollback does not hide previous exception --- .../DoctrineTransactionMiddleware.php | 12 ++++++-- .../DoctrineTransactionMiddlewareTest.php | 30 +++++++++++++++---- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Messenger/DoctrineTransactionMiddleware.php b/src/Symfony/Bridge/Doctrine/Messenger/DoctrineTransactionMiddleware.php index e4831557f01db..8e10891b0ba74 100644 --- a/src/Symfony/Bridge/Doctrine/Messenger/DoctrineTransactionMiddleware.php +++ b/src/Symfony/Bridge/Doctrine/Messenger/DoctrineTransactionMiddleware.php @@ -27,15 +27,17 @@ class DoctrineTransactionMiddleware extends AbstractDoctrineMiddleware protected function handleForManager(EntityManagerInterface $entityManager, Envelope $envelope, StackInterface $stack): Envelope { $entityManager->getConnection()->beginTransaction(); + + $success = false; try { $envelope = $stack->next()->handle($envelope, $stack); $entityManager->flush(); $entityManager->getConnection()->commit(); + $success = true; + return $envelope; } catch (\Throwable $exception) { - $entityManager->getConnection()->rollBack(); - if ($exception instanceof HandlerFailedException) { // Remove all HandledStamp from the envelope so the retry will execute all handlers again. // When a handler fails, the queries of allegedly successful previous handlers just got rolled back. @@ -43,6 +45,12 @@ protected function handleForManager(EntityManagerInterface $entityManager, Envel } throw $exception; + } finally { + $connection = $entityManager->getConnection(); + + if (!$success && $connection->isTransactionActive()) { + $connection->rollBack(); + } } } } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrineTransactionMiddlewareTest.php b/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrineTransactionMiddlewareTest.php index 977f32e30fa61..05e5dae1b34ac 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrineTransactionMiddlewareTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrineTransactionMiddlewareTest.php @@ -56,12 +56,9 @@ public function testMiddlewareWrapsInTransactionAndFlushes() public function testTransactionIsRolledBackOnException() { - $this->connection->expects($this->once()) - ->method('beginTransaction') - ; - $this->connection->expects($this->once()) - ->method('rollBack') - ; + $this->connection->expects($this->once())->method('beginTransaction'); + $this->connection->expects($this->once())->method('isTransactionActive')->willReturn(true); + $this->connection->expects($this->once())->method('rollBack'); $this->expectException(\RuntimeException::class); $this->expectExceptionMessage('Thrown from next middleware.'); @@ -69,6 +66,27 @@ public function testTransactionIsRolledBackOnException() $this->middleware->handle(new Envelope(new \stdClass()), $this->getThrowingStackMock()); } + public function testExceptionInRollBackDoesNotHidePreviousException() + { + $this->connection->expects($this->once())->method('beginTransaction'); + $this->connection->expects($this->once())->method('isTransactionActive')->willReturn(true); + $this->connection->expects($this->once())->method('rollBack')->willThrowException(new \RuntimeException('Thrown from rollBack.')); + + try { + $this->middleware->handle(new Envelope(new \stdClass()), $this->getThrowingStackMock()); + } catch (\Throwable $exception) { + } + + self::assertNotNull($exception); + self::assertInstanceOf(\RuntimeException::class, $exception); + self::assertSame('Thrown from rollBack.', $exception->getMessage()); + + $previous = $exception->getPrevious(); + self::assertNotNull($previous); + self::assertInstanceOf(\RuntimeException::class, $previous); + self::assertSame('Thrown from next middleware.', $previous->getMessage()); + } + public function testInvalidEntityManagerThrowsException() { $managerRegistry = $this->createMock(ManagerRegistry::class); From e6ec2126c8c74b7690883a16ea7fe410eb671b6a Mon Sep 17 00:00:00 2001 From: Jontsa Date: Wed, 18 Dec 2024 14:18:31 +0200 Subject: [PATCH 29/37] [HttpClient] Fix a typo in NoPrivateNetworkHttpClient --- .../HttpClient/NoPrivateNetworkHttpClient.php | 2 +- .../Tests/NoPrivateNetworkHttpClientTest.php | 21 +++++++++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.php b/src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.php index 1a81155e76811..4094f98806323 100644 --- a/src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.php +++ b/src/Symfony/Component/HttpClient/NoPrivateNetworkHttpClient.php @@ -138,7 +138,7 @@ public function request(string $method, string $url, array $options = []): Respo $filterContentHeaders = static function ($h) { return 0 !== stripos($h, 'Content-Length:') && 0 !== stripos($h, 'Content-Type:') && 0 !== stripos($h, 'Transfer-Encoding:'); }; - $options['header'] = array_filter($options['header'], $filterContentHeaders); + $options['headers'] = array_filter($options['headers'], $filterContentHeaders); $redirectHeaders['no_auth'] = array_filter($redirectHeaders['no_auth'], $filterContentHeaders); $redirectHeaders['with_auth'] = array_filter($redirectHeaders['with_auth'], $filterContentHeaders); } diff --git a/src/Symfony/Component/HttpClient/Tests/NoPrivateNetworkHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/NoPrivateNetworkHttpClientTest.php index fb940790b0b3f..06ffc128187cf 100644 --- a/src/Symfony/Component/HttpClient/Tests/NoPrivateNetworkHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/NoPrivateNetworkHttpClientTest.php @@ -173,6 +173,27 @@ public function testNonCallableOnProgressCallback() $client->request('GET', $url, ['on_progress' => $customCallback]); } + public function testHeadersArePassedOnRedirect() + { + $ipAddr = '104.26.14.6'; + $url = sprintf('http://%s/', $ipAddr); + $content = 'foo'; + + $callback = function ($method, $url, $options) use ($content): MockResponse { + $this->assertArrayHasKey('headers', $options); + $this->assertNotContains('content-type: application/json', $options['headers']); + $this->assertContains('foo: bar', $options['headers']); + return new MockResponse($content); + }; + $responses = [ + new MockResponse('', ['http_code' => 302, 'redirect_url' => 'http://104.26.14.7']), + $callback, + ]; + $client = new NoPrivateNetworkHttpClient(new MockHttpClient($responses)); + $response = $client->request('POST', $url, ['headers' => ['foo' => 'bar', 'content-type' => 'application/json']]); + $this->assertEquals($content, $response->getContent()); + } + private function getMockHttpClient(string $ipAddr, string $content) { return new MockHttpClient(new MockResponse($content, ['primary_ip' => $ipAddr])); From 85a5d13d6bbb74a796b0432f9baab0c3028070e4 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 19 Dec 2024 14:05:52 +0100 Subject: [PATCH 30/37] relax assertions on generated hashes --- .../Twig/Tests/Extension/HttpKernelExtensionTest.php | 2 +- .../FrameworkBundle/Tests/Functional/FragmentTest.php | 2 +- .../HttpKernel/Tests/Fragment/EsiFragmentRendererTest.php | 8 ++++---- .../Tests/Fragment/HIncludeFragmentRendererTest.php | 2 +- .../HttpKernel/Tests/Fragment/SsiFragmentRendererTest.php | 8 ++++---- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php index 9b7eb0b1165c8..a7057fda57d88 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/HttpKernelExtensionTest.php @@ -81,7 +81,7 @@ public function testGenerateFragmentUri() ]); $twig->addRuntimeLoader($loader); - $this->assertSame('/_fragment?_hash=XCg0hX8QzSwik8Xuu9aMXhoCeI4oJOob7lUVacyOtyY%3D&_path=template%3Dfoo.html.twig%26_format%3Dhtml%26_locale%3Den%26_controller%3DSymfony%255CBundle%255CFrameworkBundle%255CController%255CTemplateController%253A%253AtemplateAction', $twig->render('index')); + $this->assertMatchesRegularExpression('#/_fragment\?_hash=.+&_path=template%3Dfoo.html.twig%26_format%3Dhtml%26_locale%3Den%26_controller%3DSymfony%255CBundle%255CFrameworkBundle%255CController%255CTemplateController%253A%253AtemplateAction$#', $twig->render('index')); } protected function getFragmentHandler($returnOrException): FragmentHandler diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/FragmentTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/FragmentTest.php index 6d8966a171ba2..48d5c327a3986 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/FragmentTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/FragmentTest.php @@ -50,6 +50,6 @@ public function testGenerateFragmentUri() $client = self::createClient(['test_case' => 'Fragment', 'root_config' => 'config.yml', 'debug' => true]); $client->request('GET', '/fragment_uri'); - $this->assertSame('/_fragment?_hash=CCRGN2D%2FoAJbeGz%2F%2FdoH3bNSPwLCrmwC1zAYCGIKJ0E%3D&_path=_format%3Dhtml%26_locale%3Den%26_controller%3DSymfony%255CBundle%255CFrameworkBundle%255CTests%255CFunctional%255CBundle%255CTestBundle%255CController%255CFragmentController%253A%253AindexAction', $client->getResponse()->getContent()); + $this->assertMatchesRegularExpression('#/_fragment\?_hash=.+&_path=_format%3Dhtml%26_locale%3Den%26_controller%3DSymfony%255CBundle%255CFrameworkBundle%255CTests%255CFunctional%255CBundle%255CTestBundle%255CController%255CFragmentController%253A%253AindexAction$#', $client->getResponse()->getContent()); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/EsiFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/EsiFragmentRendererTest.php index fa9885d2753cd..43c740ee12b98 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/EsiFragmentRendererTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/EsiFragmentRendererTest.php @@ -60,8 +60,8 @@ public function testRenderControllerReference() $reference = new ControllerReference('main_controller', [], []); $altReference = new ControllerReference('alt_controller', [], []); - $this->assertEquals( - '', + $this->assertMatchesRegularExpression( + '#^$#', $strategy->render($reference, $request, ['alt' => $altReference])->getContent() ); } @@ -78,8 +78,8 @@ public function testRenderControllerReferenceWithAbsoluteUri() $reference = new ControllerReference('main_controller', [], []); $altReference = new ControllerReference('alt_controller', [], []); - $this->assertSame( - '', + $this->assertMatchesRegularExpression( + '#^$#', $strategy->render($reference, $request, ['alt' => $altReference, 'absolute_uri' => true])->getContent() ); } diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php index f74887ade36f4..8e4b59e5feeb9 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php @@ -32,7 +32,7 @@ public function testRenderWithControllerAndSigner() { $strategy = new HIncludeFragmentRenderer(null, new UriSigner('foo')); - $this->assertEquals('', $strategy->render(new ControllerReference('main_controller', [], []), Request::create('/'))->getContent()); + $this->assertMatchesRegularExpression('#^$#', $strategy->render(new ControllerReference('main_controller', [], []), Request::create('/'))->getContent()); } public function testRenderWithUri() diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/SsiFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/SsiFragmentRendererTest.php index 4af00f9f75137..7fd04c5a5b0b7 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/SsiFragmentRendererTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/SsiFragmentRendererTest.php @@ -51,8 +51,8 @@ public function testRenderControllerReference() $reference = new ControllerReference('main_controller', [], []); $altReference = new ControllerReference('alt_controller', [], []); - $this->assertEquals( - '', + $this->assertMatchesRegularExpression( + '{^$}', $strategy->render($reference, $request, ['alt' => $altReference])->getContent() ); } @@ -69,8 +69,8 @@ public function testRenderControllerReferenceWithAbsoluteUri() $reference = new ControllerReference('main_controller', [], []); $altReference = new ControllerReference('alt_controller', [], []); - $this->assertSame( - '', + $this->assertMatchesRegularExpression( + '{^$}', $strategy->render($reference, $request, ['alt' => $altReference, 'absolute_uri' => true])->getContent() ); } From 7f251dafdc9e29fa8f4f70d9a20296cb4f01c026 Mon Sep 17 00:00:00 2001 From: Dario Guarracino Date: Thu, 26 Dec 2024 20:01:29 +0100 Subject: [PATCH 31/37] [PropertyInfo] Remove `@internal` directives to allow extensions with no static-analysis errors --- src/Symfony/Component/PropertyInfo/PropertyReadInfo.php | 2 -- src/Symfony/Component/PropertyInfo/PropertyWriteInfo.php | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/Symfony/Component/PropertyInfo/PropertyReadInfo.php b/src/Symfony/Component/PropertyInfo/PropertyReadInfo.php index 8de070dc046c9..d006e32483896 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyReadInfo.php +++ b/src/Symfony/Component/PropertyInfo/PropertyReadInfo.php @@ -15,8 +15,6 @@ * The property read info tells how a property can be read. * * @author Joel Wurtz - * - * @internal */ final class PropertyReadInfo { diff --git a/src/Symfony/Component/PropertyInfo/PropertyWriteInfo.php b/src/Symfony/Component/PropertyInfo/PropertyWriteInfo.php index 6bc7abcdf849e..81ce7eda6d5b0 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyWriteInfo.php +++ b/src/Symfony/Component/PropertyInfo/PropertyWriteInfo.php @@ -15,8 +15,6 @@ * The write mutator defines how a property can be written. * * @author Joel Wurtz - * - * @internal */ final class PropertyWriteInfo { From 399524f1de662d536b18c8f374f9c831a1bf86d7 Mon Sep 17 00:00:00 2001 From: BahmanMD Date: Mon, 23 Dec 2024 00:32:24 +0330 Subject: [PATCH 32/37] Update validators.fa.xlf --- .../Resources/translations/validators.fa.xlf | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf index 3977f37433060..485d69add1ee8 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf @@ -444,27 +444,27 @@ This value is too short. It should contain at least one word.|This value is too short. It should contain at least {{ min }} words. - 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 }} کلمه داشته باشد. This value is too long. It should contain one word.|This value is too long. It should contain {{ max }} words or less. - This value is too long. It should contain one word.|This value is too long. It should contain {{ max }} words or less. + این مقدار بیش از حد طولانی است. باید فقط یک کلمه باشد.|این مقدار بیش از حد طولانی است. باید حداکثر {{ max }} کلمه داشته باشد. This value does not represent a valid week in the ISO 8601 format. - This value does not represent a valid week in the ISO 8601 format. + این مقدار یک هفته معتبر در قالب ISO 8601 را نشان نمی‌دهد. This value is not a valid week. - This value is not a valid week. + این مقدار یک هفته معتبر نیست. This value should not be before week "{{ min }}". - This value should not be before week "{{ min }}". + این مقدار نباید قبل از هفته "{{ min }}" باشد. This value should not be after week "{{ max }}". - This value should not be after week "{{ max }}". + این مقدار نباید بعد از هفته "{{ max }}" باشد. From a247d5851922578c182d46886f976725e961cf47 Mon Sep 17 00:00:00 2001 From: matlec Date: Sun, 29 Dec 2024 14:51:37 +0100 Subject: [PATCH 33/37] [Finder] Fix using `==` as default operator in `DateComparator` --- src/Symfony/Component/Finder/Comparator/DateComparator.php | 2 +- .../Component/Finder/Tests/Comparator/DateComparatorTest.php | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Finder/Comparator/DateComparator.php b/src/Symfony/Component/Finder/Comparator/DateComparator.php index e0c523d05523b..f7c27de677fb1 100644 --- a/src/Symfony/Component/Finder/Comparator/DateComparator.php +++ b/src/Symfony/Component/Finder/Comparator/DateComparator.php @@ -36,7 +36,7 @@ public function __construct(string $test) throw new \InvalidArgumentException(sprintf('"%s" is not a valid date.', $matches[2])); } - $operator = $matches[1] ?? '=='; + $operator = $matches[1] ?: '=='; if ('since' === $operator || 'after' === $operator) { $operator = '>'; } diff --git a/src/Symfony/Component/Finder/Tests/Comparator/DateComparatorTest.php b/src/Symfony/Component/Finder/Tests/Comparator/DateComparatorTest.php index 47bcc4838bd26..e50b713062638 100644 --- a/src/Symfony/Component/Finder/Tests/Comparator/DateComparatorTest.php +++ b/src/Symfony/Component/Finder/Tests/Comparator/DateComparatorTest.php @@ -59,6 +59,7 @@ public static function getTestData() ['after 2005-10-10', [strtotime('2005-10-15')], [strtotime('2005-10-09')]], ['since 2005-10-10', [strtotime('2005-10-15')], [strtotime('2005-10-09')]], ['!= 2005-10-10', [strtotime('2005-10-11')], [strtotime('2005-10-10')]], + ['2005-10-10', [strtotime('2005-10-10')], [strtotime('2005-10-11')]], ]; } } From a90f6e72e90ef1bb1f4c9041a14d877f0487842a Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 29 Dec 2024 21:27:14 +0100 Subject: [PATCH 34/37] reject URLs containing whitespaces --- .../Tests/TextSanitizer/UrlSanitizerTest.php | 28 +++++++++---------- .../TextSanitizer/UrlSanitizer.php | 8 +++++- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/Symfony/Component/HtmlSanitizer/Tests/TextSanitizer/UrlSanitizerTest.php b/src/Symfony/Component/HtmlSanitizer/Tests/TextSanitizer/UrlSanitizerTest.php index fe0e0d39cd9d9..c00b8f7dfbfe5 100644 --- a/src/Symfony/Component/HtmlSanitizer/Tests/TextSanitizer/UrlSanitizerTest.php +++ b/src/Symfony/Component/HtmlSanitizer/Tests/TextSanitizer/UrlSanitizerTest.php @@ -358,10 +358,10 @@ public static function provideParse(): iterable 'non-special://:@untrusted.com/x' => ['scheme' => 'non-special', 'host' => 'untrusted.com'], 'http:foo.com' => ['scheme' => 'http', 'host' => null], " :foo.com \n" => null, - ' foo.com ' => ['scheme' => null, 'host' => null], + ' foo.com ' => null, 'a: foo.com' => null, - 'http://f:21/ b ? d # e ' => ['scheme' => 'http', 'host' => 'f'], - 'lolscheme:x x#x x' => ['scheme' => 'lolscheme', 'host' => null], + 'http://f:21/ b ? d # e ' => null, + 'lolscheme:x x#x x' => null, 'http://f:/c' => ['scheme' => 'http', 'host' => 'f'], 'http://f:0/c' => ['scheme' => 'http', 'host' => 'f'], 'http://f:00000000000000/c' => ['scheme' => 'http', 'host' => 'f'], @@ -434,7 +434,7 @@ public static function provideParse(): iterable 'javascript:example.com/' => ['scheme' => 'javascript', 'host' => null], 'mailto:example.com/' => ['scheme' => 'mailto', 'host' => null], '/a/b/c' => ['scheme' => null, 'host' => null], - '/a/ /c' => ['scheme' => null, 'host' => null], + '/a/ /c' => null, '/a%2fc' => ['scheme' => null, 'host' => null], '/a/%2f/c' => ['scheme' => null, 'host' => null], '#β' => ['scheme' => null, 'host' => null], @@ -495,10 +495,10 @@ public static function provideParse(): iterable 'http://example.com/你好你好' => ['scheme' => 'http', 'host' => 'example.com'], 'http://example.com/‥/foo' => ['scheme' => 'http', 'host' => 'example.com'], "http://example.com/\u{feff}/foo" => ['scheme' => 'http', 'host' => 'example.com'], - "http://example.com\u{002f}\u{202e}\u{002f}\u{0066}\u{006f}\u{006f}\u{002f}\u{202d}\u{002f}\u{0062}\u{0061}\u{0072}\u{0027}\u{0020}" => ['scheme' => 'http', 'host' => 'example.com'], + "http://example.com\u{002f}\u{202e}\u{002f}\u{0066}\u{006f}\u{006f}\u{002f}\u{202d}\u{002f}\u{0062}\u{0061}\u{0072}\u{0027}\u{0020}" => null, 'http://www.google.com/foo?bar=baz#' => ['scheme' => 'http', 'host' => 'www.google.com'], - 'http://www.google.com/foo?bar=baz# »' => ['scheme' => 'http', 'host' => 'www.google.com'], - 'data:test# »' => ['scheme' => 'data', 'host' => null], + 'http://www.google.com/foo?bar=baz# »' => null, + 'data:test# »' => null, 'http://www.google.com' => ['scheme' => 'http', 'host' => 'www.google.com'], 'http://192.0x00A80001' => ['scheme' => 'http', 'host' => '192.0x00A80001'], 'http://www/foo%2Ehtml' => ['scheme' => 'http', 'host' => 'www'], @@ -706,11 +706,11 @@ public static function provideParse(): iterable 'test-a-colon-slash-slash-b.html' => ['scheme' => null, 'host' => null], 'http://example.org/test?a#bc' => ['scheme' => 'http', 'host' => 'example.org'], 'http:\\/\\/f:b\\/c' => ['scheme' => 'http', 'host' => null], - 'http:\\/\\/f: \\/c' => ['scheme' => 'http', 'host' => null], + 'http:\\/\\/f: \\/c' => null, 'http:\\/\\/f:fifty-two\\/c' => ['scheme' => 'http', 'host' => null], 'http:\\/\\/f:999999\\/c' => ['scheme' => 'http', 'host' => null], 'non-special:\\/\\/f:999999\\/c' => ['scheme' => 'non-special', 'host' => null], - 'http:\\/\\/f: 21 \\/ b ? d # e ' => ['scheme' => 'http', 'host' => null], + 'http:\\/\\/f: 21 \\/ b ? d # e ' => null, 'http:\\/\\/[1::2]:3:4' => ['scheme' => 'http', 'host' => null], 'http:\\/\\/2001::1' => ['scheme' => 'http', 'host' => null], 'http:\\/\\/2001::1]' => ['scheme' => 'http', 'host' => null], @@ -734,8 +734,8 @@ public static function provideParse(): iterable 'http:@:www.example.com' => ['scheme' => 'http', 'host' => null], 'http:\\/@:www.example.com' => ['scheme' => 'http', 'host' => null], 'http:\\/\\/@:www.example.com' => ['scheme' => 'http', 'host' => null], - 'http:\\/\\/example example.com' => ['scheme' => 'http', 'host' => null], - 'http:\\/\\/Goo%20 goo%7C|.com' => ['scheme' => 'http', 'host' => null], + 'http:\\/\\/example example.com' => null, + 'http:\\/\\/Goo%20 goo%7C|.com' => null, 'http:\\/\\/[]' => ['scheme' => 'http', 'host' => null], 'http:\\/\\/[:]' => ['scheme' => 'http', 'host' => null], 'http:\\/\\/GOO\\u00a0\\u3000goo.com' => ['scheme' => 'http', 'host' => null], @@ -752,8 +752,8 @@ public static function provideParse(): iterable 'http:\\/\\/hello%00' => ['scheme' => 'http', 'host' => null], 'http:\\/\\/192.168.0.257' => ['scheme' => 'http', 'host' => null], 'http:\\/\\/%3g%78%63%30%2e%30%32%35%30%2E.01' => ['scheme' => 'http', 'host' => null], - 'http:\\/\\/192.168.0.1 hello' => ['scheme' => 'http', 'host' => null], - 'https:\\/\\/x x:12' => ['scheme' => 'https', 'host' => null], + 'http:\\/\\/192.168.0.1 hello' => null, + 'https:\\/\\/x x:12' => null, 'http:\\/\\/[www.google.com]\\/' => ['scheme' => 'http', 'host' => null], 'http:\\/\\/[google.com]' => ['scheme' => 'http', 'host' => null], 'http:\\/\\/[::1.2.3.4x]' => ['scheme' => 'http', 'host' => null], @@ -763,7 +763,7 @@ public static function provideParse(): iterable '..\\/i' => ['scheme' => null, 'host' => null], '\\/i' => ['scheme' => null, 'host' => null], 'sc:\\/\\/\\u0000\\/' => ['scheme' => 'sc', 'host' => null], - 'sc:\\/\\/ \\/' => ['scheme' => 'sc', 'host' => null], + 'sc:\\/\\/ \\/' => null, 'sc:\\/\\/@\\/' => ['scheme' => 'sc', 'host' => null], 'sc:\\/\\/te@s:t@\\/' => ['scheme' => 'sc', 'host' => null], 'sc:\\/\\/:\\/' => ['scheme' => 'sc', 'host' => null], diff --git a/src/Symfony/Component/HtmlSanitizer/TextSanitizer/UrlSanitizer.php b/src/Symfony/Component/HtmlSanitizer/TextSanitizer/UrlSanitizer.php index a806981de770f..05d86ba15da8e 100644 --- a/src/Symfony/Component/HtmlSanitizer/TextSanitizer/UrlSanitizer.php +++ b/src/Symfony/Component/HtmlSanitizer/TextSanitizer/UrlSanitizer.php @@ -94,7 +94,13 @@ public static function parse(string $url): ?array } try { - return UriString::parse($url); + $parsedUrl = UriString::parse($url); + + if (preg_match('/\s/', $url)) { + return null; + } + + return $parsedUrl; } catch (SyntaxError) { return null; } From 8119da35bc240914a0bfef404b1b8a5ebc2269ed Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 31 Dec 2024 15:49:15 +0100 Subject: [PATCH 35/37] Update CHANGELOG for 6.4.17 --- CHANGELOG-6.4.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG-6.4.md b/CHANGELOG-6.4.md index 94111d16ed62b..56df1b333f50b 100644 --- a/CHANGELOG-6.4.md +++ b/CHANGELOG-6.4.md @@ -7,6 +7,25 @@ in 6.4 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/v6.4.0...v6.4.1 +* 6.4.17 (2024-12-31) + + * bug #59304 [PropertyInfo] Remove ``@internal`` from `PropertyReadInfo` and `PropertyWriteInfo` (Dario Guarracino) + * bug #59318 [Finder] Fix using `==` as default operator in `DateComparator` (MatTheCat) + * bug #59321 [HtmlSanitizer] reject URLs containing whitespaces (xabbuh) + * bug #59250 [HttpClient] Fix a typo in NoPrivateNetworkHttpClient (Jontsa) + * bug #59103 [Messenger] ensure exception on rollback does not hide previous exception (nikophil) + * bug #59226 [FrameworkBundle] require the writer to implement getFormats() in the translation:extract (xabbuh) + * bug #59213 [FrameworkBundle] don't require fake notifier transports to be installed as non-dev dependencies (xabbuh) + * bug #59160 [BeanstalkMessenger] Round delay to an integer to avoid deprecation warning (plantas) + * bug #59012 [PropertyInfo] Fix interface handling in `PhpStanTypeHelper` (janedbal) + * bug #59134 [HttpKernel] Denormalize request data using the csv format when using "#[MapQueryString]" or "#[MapRequestPayload]" (except for content data) (ovidiuenache) + * bug #59140 [WebProfilerBundle] fix: white-space in highlighted code (chr-hertel) + * bug #59124 [FrameworkBundle] fix: notifier push channel bus abstract arg (raphael-geffroy) + * bug #59069 [Console] Fix division by 0 error (Rindula) + * bug #59070 [PropertyInfo] evaluate access flags for properties with asymmetric visibility (xabbuh) + * bug #59062 [HttpClient] Always set CURLOPT_CUSTOMREQUEST to the correct HTTP method in CurlHttpClient (KurtThiemann) + * bug #59023 [HttpClient] Fix streaming and redirecting with NoPrivateNetworkHttpClient (nicolas-grekas) + * 6.4.16 (2024-11-27) * bug #59013 [HttpClient] Fix checking for private IPs before connecting (nicolas-grekas) From 059e588ac52a8f3d330500cc14d092272e04bb83 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 31 Dec 2024 15:49:21 +0100 Subject: [PATCH 36/37] Update CONTRIBUTORS for 6.4.17 --- CONTRIBUTORS.md | 56 +++++++++++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 23 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index c83c2ca56b1d4..d0472fa4bd167 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -34,8 +34,8 @@ The Symfony Connect username in parenthesis allows to get more information - Tobias Nyholm (tobias) - HypeMC (hypemc) - Jérôme Tamarelle (gromnan) - - Samuel ROZE (sroze) - Antoine Lamirault (alamirault) + - Samuel ROZE (sroze) - Pascal Borreli (pborreli) - Romain Neutron - Joseph Bielawski (stloyd) @@ -51,11 +51,11 @@ The Symfony Connect username in parenthesis allows to get more information - Igor Wiedler - Jan Schädlich (jschaedl) - Mathieu Lechat (mat_the_cat) + - Mathias Arlaud (mtarld) - Simon André (simonandre) - Matthias Pigulla (mpdude) - Gabriel Ostrolucký (gadelat) - Jonathan Wage (jwage) - - Mathias Arlaud (mtarld) - Vincent Langlet (deviling) - Valentin Udaltsov (vudaltsov) - Grégoire Paris (greg0ire) @@ -73,17 +73,17 @@ The Symfony Connect username in parenthesis allows to get more information - Pierre du Plessis (pierredup) - David Maicher (dmaicher) - Tomasz Kowalczyk (thunderer) + - Mathieu Santostefano (welcomattic) - Bulat Shakirzyanov (avalanche123) - Iltar van der Berg - Miha Vrhovnik (mvrhov) - Gary PEGEOT (gary-p) - - Mathieu Santostefano (welcomattic) - Saša Stamenković (umpirsky) - Allison Guilhem (a_guilhem) - Alexander Schranz (alexander-schranz) + - Dariusz Ruminski - Mathieu Piot (mpiot) - Vasilij Duško (staff) - - Dariusz Ruminski - Sarah Khalil (saro0h) - Laurent VOULLEMIER (lvo) - Konstantin Kudryashov (everzet) @@ -144,20 +144,20 @@ The Symfony Connect username in parenthesis allows to get more information - Tac Tacelosky (tacman1123) - gnito-org - Tim Nagel (merk) + - Valtteri R (valtzu) - Chris Wilkinson (thewilkybarkid) - Jérôme Vasseur (jvasseur) - Peter Kokot (peterkokot) - Brice BERNARD (brikou) - - Valtteri R (valtzu) + - Jacob Dreesen (jdreesen) + - Nicolas Philippe (nikophil) - Martin Auswöger - Michal Piotrowski - marc.weistroff - Lars Strojny (lstrojny) - lenar - Vladimir Tsykun (vtsykun) - - Jacob Dreesen (jdreesen) - Włodzimierz Gajda (gajdaw) - - Nicolas Philippe (nikophil) - Javier Spagnoletti (phansys) - Adrien Brault (adrienbrault) - Florian Voutzinos (florianv) @@ -181,11 +181,13 @@ The Symfony Connect username in parenthesis allows to get more information - Maxime Helias (maxhelias) - Robert Schönthal (digitalkaoz) - Smaine Milianni (ismail1432) + - Hugo Alliaume (kocal) - François-Xavier de Guillebon (de-gui_f) - Andreas Schempp (aschempp) - noniagriconomie - Eric GELOEN (gelo) - Gabriel Caruso + - Christopher Hertel (chertel) - Stefano Sala (stefano.sala) - Ion Bazan (ionbazan) - Niels Keurentjes (curry684) @@ -194,15 +196,14 @@ The Symfony Connect username in parenthesis allows to get more information - Juti Noppornpitak (shiroyuki) - Gregor Harlan (gharlan) - Alexis Lefebvre - - Hugo Alliaume (kocal) - Anthony MARTIN - Sebastian Hörl (blogsh) - Tigran Azatyan (tigranazatyan) - Florent Mata (fmata) - - Christopher Hertel (chertel) - Jonathan Scheiber (jmsche) - Daniel Gomes (danielcsgomes) - Hidenori Goto (hidenorigoto) + - Thomas Landauer (thomas-landauer) - Arnaud Kleinpeter (nanocom) - Guilherme Blanco (guilhermeblanco) - Saif Eddin Gmati (azjezz) @@ -214,7 +215,6 @@ The Symfony Connect username in parenthesis allows to get more information - Alessandro Chitolina (alekitto) - Rafael Dohms (rdohms) - Roman Martinuk (a2a4) - - Thomas Landauer (thomas-landauer) - jwdeitch - David Prévot (taffit) - Jérôme Parmentier (lctrs) @@ -223,6 +223,7 @@ The Symfony Connect username in parenthesis allows to get more information - soyuka - Jérémy Derussé - Matthieu Napoli (mnapoli) + - Bob van de Vijver (bobvandevijver) - Tomas Votruba (tomas_votruba) - Arman Hosseini (arman) - Sokolov Evgeniy (ewgraf) @@ -242,7 +243,6 @@ The Symfony Connect username in parenthesis allows to get more information - Fabien Bourigault (fbourigault) - Olivier Dolbeau (odolbeau) - Rouven Weßling (realityking) - - Bob van de Vijver (bobvandevijver) - Daniel Burger - Ben Davies (bendavies) - YaFou @@ -270,6 +270,7 @@ The Symfony Connect username in parenthesis allows to get more information - Samuel NELA (snela) - Baptiste Leduc (korbeil) - Vincent AUBERT (vincent) + - Nate Wiebe (natewiebe13) - Michael Voříšek - zairig imad (zairigimad) - Colin O'Dell (colinodell) @@ -336,7 +337,6 @@ The Symfony Connect username in parenthesis allows to get more information - Julien Pauli - Michael Lee (zerustech) - Florian Lonqueu-Brochard (florianlb) - - Nate Wiebe (natewiebe13) - Joe Bennett (kralos) - Leszek Prabucki (l3l0) - Wojciech Kania @@ -392,6 +392,7 @@ The Symfony Connect username in parenthesis allows to get more information - Elnur Abdurrakhimov (elnur) - Manuel Reinhard (sprain) - Zan Baldwin (zanbaldwin) + - Tim Goudriaan (codedmonkey) - Antonio J. García Lagar (ajgarlag) - BoShurik - Quentin Devos @@ -416,6 +417,7 @@ The Symfony Connect username in parenthesis allows to get more information - Pierre-Yves Lebecq (pylebecq) - Benjamin Leveque (benji07) - Jordan Samouh (jordansamouh) + - David Badura (davidbadura) - Sullivan SENECHAL (soullivaneuh) - Uwe Jäger (uwej711) - javaDeveloperKid @@ -459,7 +461,6 @@ The Symfony Connect username in parenthesis allows to get more information - Wodor Wodorski - Beau Simensen (simensen) - Magnus Nordlander (magnusnordlander) - - Tim Goudriaan (codedmonkey) - Robert Kiss (kepten) - Alexandre Quercia (alquerci) - Marcos Sánchez @@ -483,11 +484,11 @@ The Symfony Connect username in parenthesis allows to get more information - Marco Petersen (ocrampete16) - Bohan Yang (brentybh) - Vilius Grigaliūnas - - David Badura (davidbadura) - Jordane VASPARD (elementaire) - Chris Smith (cs278) - Thomas Bisignani (toma) - Florian Klein (docteurklein) + - Raphaël Geffroy (raphael-geffroy) - Damien Alexandre (damienalexandre) - Manuel Kießling (manuelkiessling) - Alexey Kopytko (sanmai) @@ -687,6 +688,7 @@ The Symfony Connect username in parenthesis allows to get more information - Markus Bachmann (baachi) - Gunnstein Lye (glye) - Erkhembayar Gantulga (erheme318) + - Yi-Jyun Pan - Sergey Melesh (sergex) - Greg Anderson - lancergr @@ -762,6 +764,7 @@ The Symfony Connect username in parenthesis allows to get more information - Soufian EZ ZANTAR (soezz) - Marek Zajac - Adam Harvey + - Klaus Silveira (klaussilveira) - ilyes kooli (skafandri) - Anton Bakai - battye @@ -788,6 +791,7 @@ The Symfony Connect username in parenthesis allows to get more information - Joshua Nye - Martin Kirilov (wucdbm) - Koen Reiniers (koenre) + - Kurt Thiemann - Nathan Dench (ndenc2) - Gijs van Lammeren - Sebastian Bergmann @@ -901,6 +905,7 @@ The Symfony Connect username in parenthesis allows to get more information - Daniel Tiringer - Lenar Lõhmus - Ilija Tovilo (ilijatovilo) + - Maxime Pinot (maximepinot) - Sander Toonen (xatoo) - Zach Badgett (zachbadgett) - Loïc Faugeron @@ -967,6 +972,7 @@ The Symfony Connect username in parenthesis allows to get more information - Ricky Su (ricky) - scyzoryck - Kyle Evans (kevans91) + - Ioan Ovidiu Enache (ionutenache) - Max Rath (drak3) - Cristoforo Cervino (cristoforocervino) - marie @@ -976,7 +982,6 @@ The Symfony Connect username in parenthesis allows to get more information - Noémi Salaün (noemi-salaun) - Sinan Eldem (sineld) - Gennady Telegin - - Yi-Jyun Pan - ampaze - Alexandre Dupuy (satchette) - Michel Hunziker @@ -999,6 +1004,7 @@ The Symfony Connect username in parenthesis allows to get more information - Åsmund Garfors - Maxime Douailin - Jean Pasdeloup + - Maxime COLIN (maximecolin) - Lorenzo Millucci (lmillucci) - Javier López (loalf) - Reinier Kip @@ -1065,6 +1071,7 @@ The Symfony Connect username in parenthesis allows to get more information - Quentin de Longraye (quentinus95) - Chris Heng (gigablah) - Mickaël Buliard (mbuliard) + - Jan Nedbal - Cornel Cruceru (amne) - Richard Bradley - Jan Walther (janwalther) @@ -1157,7 +1164,6 @@ The Symfony Connect username in parenthesis allows to get more information - Aleksandr Volochnev (exelenz) - Robin van der Vleuten (robinvdvleuten) - Grinbergs Reinis (shima5) - - Klaus Silveira (klaussilveira) - Michael Piecko (michael.piecko) - Toni Peric (tperic) - yclian @@ -1242,7 +1248,6 @@ The Symfony Connect username in parenthesis allows to get more information - Thorry84 - Romanavr - michaelwilliams - - Raphaël Geffroy (raphael-geffroy) - Alexandre Parent - 1emming - Nykopol (nykopol) @@ -1345,6 +1350,7 @@ The Symfony Connect username in parenthesis allows to get more information - Francisco Alvarez (sormes) - Martin Parsiegla (spea) - Maxim Tugaev (tugmaks) + - ywisax - Manuel Alejandro Paz Cetina - Denis Charrier (brucewouaigne) - Youssef Benhssaien (moghreb) @@ -1436,7 +1442,6 @@ The Symfony Connect username in parenthesis allows to get more information - Dmytro Boiko (eagle) - Shin Ohno (ganchiku) - Matthieu Mota (matthieumota) - - Maxime Pinot (maximepinot) - Jean-Baptiste GOMOND (mjbgo) - Jakub Podhorsky (podhy) - abdul malik ikhsan (samsonasik) @@ -1603,7 +1608,6 @@ The Symfony Connect username in parenthesis allows to get more information - Grégoire Hébert (gregoirehebert) - Franz Wilding (killerpoke) - Ferenczi Krisztian (fchris82) - - Ioan Ovidiu Enache (ionutenache) - Artyum Petrov - Oleg Golovakhin (doc_tr) - Guillaume Smolders (guillaumesmo) @@ -1783,6 +1787,7 @@ The Symfony Connect username in parenthesis allows to get more information - Evgeny Anisiforov - otsch - TristanPouliquen + - Dominic Luidold - Piotr Antosik (antek88) - Nacho Martin (nacmartin) - Thibaut Chieux @@ -1828,6 +1833,7 @@ The Symfony Connect username in parenthesis allows to get more information - Claus Due (namelesscoder) - Christian - Alexandru Patranescu + - Sébastien Lévêque (legenyes) - ju1ius - Denis Golubovskiy (bukashk0zzz) - Arkadiusz Rzadkowolski (flies) @@ -2198,6 +2204,7 @@ The Symfony Connect username in parenthesis allows to get more information - Harald Tollefsen - PabloKowalczyk - Matthieu + - ZiYao54 - Arend-Jan Tetteroo - Albin Kerouaton - Sébastien HOUZÉ @@ -2257,6 +2264,7 @@ The Symfony Connect username in parenthesis allows to get more information - George Giannoulopoulos - Alexander Pasichnik (alex_brizzz) - Florian Merle (florian-merle) + - Felix Eymonot (hyanda) - Luis Ramirez (luisdeimos) - Ilia Sergunin (maranqz) - Daniel Richter (richtermeister) @@ -2382,6 +2390,7 @@ The Symfony Connect username in parenthesis allows to get more information - Ivan Tse - René Kerner - Nathaniel Catchpole + - Igor Plantaš - upchuk - Adrien Samson (adriensamson) - Samuel Gordalina (gordalina) @@ -2401,9 +2410,11 @@ The Symfony Connect username in parenthesis allows to get more information - Wojciech Gorczyca - Neagu Cristian-Doru (cristian-neagu) - Mathieu Morlon (glutamatt) + - NIRAV MUKUNDBHAI PATEL (niravpatel919) - Owen Gray (otis) - Rafał Muszyński (rafmus90) - Sébastien Decrême (sebdec) + - Wu (wu-agriconomie) - Timothy Anido (xanido) - Robert-Jan de Dreu - Mara Blaga @@ -2479,7 +2490,6 @@ The Symfony Connect username in parenthesis allows to get more information - karstennilsen - kaywalker - Sebastian Ionescu - - Kurt Thiemann - Robert Kopera - Pablo Ogando Ferreira - Thomas Ploch @@ -2609,7 +2619,6 @@ The Symfony Connect username in parenthesis allows to get more information - tpetry - JustDylan23 - Juraj Surman - - ywisax - Martin Eckhardt - natechicago - Victor @@ -2756,6 +2765,7 @@ The Symfony Connect username in parenthesis allows to get more information - botbotbot - tatankat - Cláudio Cesar + - Sven Nolting - Timon van der Vorm - nuncanada - Thierry Marianne @@ -3359,6 +3369,7 @@ The Symfony Connect username in parenthesis allows to get more information - jersoe - Brian Debuire - Eric Grimois + - Christian Schiffler - Piers Warmers - Sylvain Lorinet - klyk50 @@ -3374,7 +3385,6 @@ The Symfony Connect username in parenthesis allows to get more information - Steffen Keuper - Kai Eichinger - Antonio Angelino - - Jan Nedbal - Jens Schulze - Tema Yud - Matt Fields @@ -3452,6 +3462,7 @@ The Symfony Connect username in parenthesis allows to get more information - Kaipi Yann - wiseguy1394 - adam-mospan + - AUDUL - Steve Hyde - AbdelatifAitBara - nerdgod @@ -3816,7 +3827,6 @@ The Symfony Connect username in parenthesis allows to get more information - Courcier Marvin (helyakin) - Henne Van Och (hennevo) - Jeroen De Dauw (jeroendedauw) - - Maxime COLIN (maximecolin) - Muharrem Demirci (mdemirci) - Evgeny Z (meze) - Aleksandar Dimitrov (netbull) From 3bf11cbf2c027959b1d11e314b3194eee7cca549 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 31 Dec 2024 15:49:31 +0100 Subject: [PATCH 37/37] Update VERSION for 6.4.17 --- 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 185c9686aa097..eb98942076da3 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -76,12 +76,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static array $freshCache = []; - public const VERSION = '6.4.17-DEV'; + public const VERSION = '6.4.17'; public const VERSION_ID = 60417; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 4; public const RELEASE_VERSION = 17; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2026'; public const END_OF_LIFE = '11/2027';