From 676b692516486fa1d06ba0a4d38be398467c4329 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 30 Sep 2023 08:30:30 +0200 Subject: [PATCH 01/79] Update CHANGELOG for 5.4.29 --- CHANGELOG-5.4.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG-5.4.md b/CHANGELOG-5.4.md index 73623f61863cb..15e18cb53360c 100644 --- a/CHANGELOG-5.4.md +++ b/CHANGELOG-5.4.md @@ -7,6 +7,23 @@ 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.29 (2023-09-30) + + * bug #51701 [Serializer] Fix parsing XML root node attributes (mtarld) + * bug #51588 [FrameworkBundle] Always use buildDir as `ConfigBuilderGenerator` outputDir (HypeMC) + * bug #51675 [Messenger] Fix cloned TraceableStack not unstacking the stack independently (krciga22) + * bug #51198 [DependencyInjection] Fix autocasting `null` env values to empty string with `container.env_var_processors_locator` (fancyweb) + * bug #51683 [Cache] Fix support for Redis Sentinel using php-redis 6.0.0 (Qonstrukt) + * bug #51686 [SecurityBundle][PasswordHasher] Fix password migration with custom hasher service with security bundle config (ogizanagi) + * bug #51671 [FrameworkBundle] Fix support for `translator.default_path` in XML (HeahDude) + * bug #51659 [HttpClient] Fix TraceableResponse if response has no destruct method (maxhelias) + * bug #51598 [Cache] fix using multiple Redis Sentinel hosts when the first one is not resolvable (digilist) + * bug #51497 [FrameworkBundle] no serializer mapping cache in debug mode without enable_annotations (soyuka) + * bug #51645 [String] Update wcswidth data with Unicode 15.1 (fancyweb) + * bug #51586 [ErrorHandler] Handle PHP 8.3 `highlight_file` function output changes (PhilETaylor) + * bug #47221 [Serializer] Fallback looking for DiscriminatorMap on interfaces (Caligone) + * bug #51511 [PasswordHasher] Avoid passing `null` to `hash_pbkdf2()` (sdespont) + * 5.4.28 (2023-08-26) * bug #51474 [Serializer] Fix wrong InvalidArgumentException thrown (mtarld) From 55a06b63292b3a904c3244cd94a15e32a940392c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 30 Sep 2023 08:31:11 +0200 Subject: [PATCH 02/79] Update CONTRIBUTORS for 5.4.29 --- CONTRIBUTORS.md | 76 +++++++++++++++++++++++++++++++------------------ 1 file changed, 48 insertions(+), 28 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 2346e07cbd6ad..d75f3a9e8cdd7 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -19,37 +19,37 @@ The Symfony Connect username in parenthesis allows to get more information - Christophe Coevoet (stof) - Kévin Dunglas (dunglas) - Jordi Boggiano (seldaek) + - Oskar Stark (oskarstark) - Roland Franssen (ro0) - Victor Berchet (victor) - - Oskar Stark (oskarstark) - Javier Eguiluz (javier.eguiluz) - - Yonel Ceruto (yonelceruto) - Ryan Weaver (weaverryan) + - Yonel Ceruto (yonelceruto) - Tobias Nyholm (tobias) + - Alexandre Daubois (alexandre-daubois) - Johannes S (johannes) - Jakub Zalas (jakubzalas) - Kris Wallsmith (kriswallsmith) - - Alexandre Daubois (alexandre-daubois) - Jules Pietri (heah) - Hugo Hamon (hhamon) + - Jérôme Tamarelle (gromnan) - Hamza Amrouche (simperfit) - Samuel ROZE (sroze) - - Jérôme Tamarelle (gromnan) + - Kevin Bond (kbond) - Pascal Borreli (pborreli) - Romain Neutron - - Kevin Bond (kbond) - Joseph Bielawski (stloyd) - Drak (drak) - Abdellatif Ait boudad (aitboudad) + - HypeMC (hypemc) - Jan Schädlich (jschaedl) - Lukas Kahwe Smith (lsmith) - - HypeMC (hypemc) + - Antoine Lamirault (alamirault) - Martin Hasoň (hason) - Jeremy Mikola (jmikola) - Jean-François Simon (jfsimon) - Benjamin Eberlei (beberlei) - Igor Wiedler - - Antoine Lamirault (alamirault) - Valentin Udaltsov (vudaltsov) - Vasilij Duško (staff) - Matthias Pigulla (mpdude) @@ -60,12 +60,13 @@ The Symfony Connect username in parenthesis allows to get more information - Pierre du Plessis (pierredup) - Grégoire Paris (greg0ire) - Jonathan Wage (jwage) + - Alexander Schranz (alexander-schranz) - David Maicher (dmaicher) - Titouan Galopin (tgalopin) + - Gary PEGEOT (gary-p) + - Mathieu Santostefano (welcomattic) - Vincent Langlet (deviling) - - Alexander Schranz (alexander-schranz) - Gábor Egyed (1ed) - - Mathieu Santostefano (welcomattic) - Alexandre Salomé (alexandresalome) - William DURAND - ornicar @@ -75,6 +76,7 @@ The Symfony Connect username in parenthesis allows to get more information - stealth35 ‏ (stealth35) - Alexander Mols (asm89) - Francis Besset (francisbesset) + - Allison Guilhem (a_guilhem) - Vasilij Dusko | CREATION - Bulat Shakirzyanov (avalanche123) - Iltar van der Berg @@ -82,7 +84,6 @@ The Symfony Connect username in parenthesis allows to get more information - Mathieu Piot (mpiot) - Saša Stamenković (umpirsky) - Alex Pott - - Gary PEGEOT (gary-p) - Guilhem N (guilhemn) - Vladimir Reznichenko (kalessil) - Sarah Khalil (saro0h) @@ -91,14 +92,14 @@ The Symfony Connect username in parenthesis allows to get more information - Konstantin Kudryashov (everzet) - Bilal Amarni (bamarni) - Eriksen Costa + - Frank A. Fiebig (fafiebig) + - Mathias Arlaud (mtarld) - Florin Patan (florinpatan) - Konstantin Myakshin (koc) - Peter Rehm (rpet) - Henrik Bjørnskov (henrikbjorn) - David Buchmann (dbu) - - Allison Guilhem (a_guilhem) - Massimiliano Arione (garak) - - Mathias Arlaud (mtarld) - Andrej Hudec (pulzarraider) - Julien Falque (julienfalque) - Fran Moreno (franmomu) @@ -112,12 +113,12 @@ The Symfony Connect username in parenthesis allows to get more information - Malte Schlüter (maltemaltesich) - Denis (yethee) - Vasilij Dusko + - Maxime Helias (maxhelias) - Arnout Boks (aboks) - Charles Sarrazin (csarrazi) - Przemysław Bogusz (przemyslaw-bogusz) - Henrik Westphal (snc) - Dariusz Górecki (canni) - - Maxime Helias (maxhelias) - Ener-Getick - Tugdual Saunier (tucksaun) - Yanick Witschi (toflar) @@ -137,18 +138,18 @@ The Symfony Connect username in parenthesis allows to get more information - Dariusz Ruminski - Lars Strojny (lstrojny) - Joel Wurtz (brouznouf) + - Hubert Lenoir (hubert_lenoir) - Antoine Hérault (herzult) - Konstantin.Myakshin - Arman Hosseini (arman) - - Frank A. Fiebig (fafiebig) - gnito-org - Saif Eddin Gmati (azjezz) - Simon Berger - Arnaud Le Blanc (arnaud-lb) - - Hubert Lenoir (hubert_lenoir) - Maxime STEINHAUSSER - Peter Kokot (maastermedia) - jeremyFreeAgent (jeremyfreeagent) + - Jeroen Spee (jeroens) - Ahmed TAILOULOUTE (ahmedtai) - Tim Nagel (merk) - Andreas Braun @@ -167,7 +168,6 @@ The Symfony Connect username in parenthesis allows to get more information - lenar - Jesse Rushlow (geeshoe) - Théo FIDRY - - Jeroen Spee (jeroens) - Michael Babker (mbabker) - Włodzimierz Gajda (gajdaw) - Hugo Alliaume (kocal) @@ -187,6 +187,7 @@ The Symfony Connect username in parenthesis allows to get more information - Paráda József (paradajozsef) - Alessandro Lai (jean85) - Alexander Schwenn (xelaris) + - Jonathan Scheiber (jmsche) - Fabien Pennequin (fabienpennequin) - Gordon Franke (gimler) - François-Xavier de Guillebon (de-gui_f) @@ -233,15 +234,17 @@ The Symfony Connect username in parenthesis allows to get more information - Anthony MARTIN - Colin O'Dell (colinodell) - Sebastian Hörl (blogsh) + - Markus Fasselt (digilist) - Daniel Burger - Daniel Gomes (danielcsgomes) - Michael Käfer (michael_kaefer) - Hidenori Goto (hidenorigoto) - - Jonathan Scheiber (jmsche) - Albert Casademont (acasademont) - Arnaud Kleinpeter (nanocom) - Guilherme Blanco (guilhermeblanco) + - soyuka - SpacePossum + - Sébastien Alfaiate (seb33300) - Pablo Godel (pgodel) - Denis Brumann (dbrumann) - Romaric Drigon (romaricdrigon) @@ -257,10 +260,8 @@ The Symfony Connect username in parenthesis allows to get more information - Jurica Vlahoviček (vjurica) - Vincent Touzet (vincenttouzet) - Fabien Bourigault (fbourigault) - - soyuka - Jérémy Derussé - Maximilian Beckers (maxbeckers) - - Sébastien Alfaiate (seb33300) - Florent Mata (fmata) - mcfedr (mcfedr) - Maciej Malarz (malarzm) @@ -357,6 +358,7 @@ The Symfony Connect username in parenthesis allows to get more information - Andreas Hucks (meandmymonkey) - Noel Guilbert (noel) - Hamza Makraz (makraz) + - Vladimir Tsykun (vtsykun) - Loick Piera (pyrech) - Vitalii Ekert (comrade42) - Clara van Miert @@ -396,7 +398,6 @@ The Symfony Connect username in parenthesis allows to get more information - Michele Orselli (orso) - Sven Paulus (subsven) - Daniel STANCU - - Markus Fasselt (digilist) - Maxime Veber (nek-) - Oleksiy (alexndlm) - Sullivan SENECHAL (soullivaneuh) @@ -407,6 +408,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jérémie Augustin (jaugustin) - Pascal Montoya - Julien Brochet + - Phil E. Taylor (philetaylor) - Michaël Perrin (michael.perrin) - Tristan Darricau (tristandsensio) - Fabien S (bafs) @@ -466,7 +468,6 @@ The Symfony Connect username in parenthesis allows to get more information - M. Vondano - Xavier Perez - Arjen Brouwer (arjenjb) - - Vladimir Tsykun (vtsykun) - Tavo Nieves J (tavoniievez) - Arjen van der Meijden - Patrick McDougle (patrick-mcdougle) @@ -512,6 +513,7 @@ The Symfony Connect username in parenthesis allows to get more information - Johan Vlaar (johjohan) - Thomas Schulz (king2500) - Anderson Müller + - Marko Kaznovac (kaznovac) - Benjamin Morel - Bernd Stellwag - Philippe SEGATORI (tigitz) @@ -555,6 +557,7 @@ The Symfony Connect username in parenthesis allows to get more information - Vadim Borodavko (javer) - Haralan Dobrev (hkdobrev) - Soufian EZ ZANTAR (soezz) + - Arnaud POINTET (oipnet) - Jan van Thoor (janvt) - Martin Kirilov (wucdbm) - Axel Guckelsberger (guite) @@ -562,7 +565,6 @@ The Symfony Connect username in parenthesis allows to get more information - Florian Klein (docteurklein) - James Gilliland (neclimdul) - Bilge - - Phil E. Taylor (philetaylor) - Cătălin Dan (dancatalin) - Rhodri Pugh (rodnaph) - Manuel Kiessling (manuelkiessling) @@ -576,6 +578,7 @@ The Symfony Connect username in parenthesis allows to get more information - Andrew Moore (finewolf) - Bertrand Zuchuat (garfield-fr) - Marc Morera (mmoreram) + - Zbigniew Malcherczyk (ferror) - Gabor Toth (tgabi333) - realmfoo - Dmitriy Derepko @@ -604,7 +607,6 @@ The Symfony Connect username in parenthesis allows to get more information - Francesc Rosàs (frosas) - Bongiraud Dominique - janschoenherr - - Marko Kaznovac (kaznovac) - Emanuele Gaspari (inmarelibero) - Dariusz Rumiński - Terje Bråten @@ -716,6 +718,7 @@ The Symfony Connect username in parenthesis allows to get more information - Clément Gautier (clementgautier) - Jelle Raaijmakers (gmta) - Roberto Nygaard + - Valtteri R (valtzu) - Joshua Nye - Jordane VASPARD (elementaire) - Dalibor Karlović @@ -864,6 +867,7 @@ The Symfony Connect username in parenthesis allows to get more information - Daniel González (daniel.gonzalez) - Webnet team (webnet) - Berny Cantos (xphere81) + - Baldini - Mátyás Somfai (smatyas) - Simon Leblanc (leblanc_simon) - Jan Schumann @@ -877,9 +881,11 @@ The Symfony Connect username in parenthesis allows to get more information - Alex Hofbauer (alexhofbauer) - Andrii Popov (andrii-popov) - lancergr + - Maxime PINEAU - Ivan Nikolaev (destillat) - Xavier Leune (xleune) - Matthieu Calie (matth--) + - Simon André (simonandre) - Benjamin Georgeault (wedgesama) - Joost van Driel (j92) - ampaze @@ -1212,6 +1218,7 @@ The Symfony Connect username in parenthesis allows to get more information - Claus Due (namelesscoder) - aaa2000 (aaa2000) - Alexandru Patranescu + - Andrew Neil Forster (krciga22) - Arkadiusz Rzadkowolski (flies) - Oksana Kozlova (oksanakozlova) - Quentin Moreau (sheitak) @@ -1225,7 +1232,6 @@ The Symfony Connect username in parenthesis allows to get more information - Timothée BARRAY - Nilmar Sanchez Muguercia - Ivo Bathke (ivoba) - - Arnaud POINTET (oipnet) - Lukas Mencl - Strate - Anton A. Sumin @@ -1583,6 +1589,7 @@ The Symfony Connect username in parenthesis allows to get more information - Masterklavi - Franco Traversaro (belinde) - Francis Turmel (fturmel) + - Kagan Balga (kagan-balga) - Nikita Nefedov (nikita2206) - Bernat Llibre - cgonzalez @@ -1711,7 +1718,6 @@ The Symfony Connect username in parenthesis allows to get more information - Neil Ferreira - Julie Hourcade (juliehde) - Dmitry Parnas (parnas) - - Valtteri R (valtzu) - Christian Weiske - Maria Grazia Patteri - Sébastien COURJEAN @@ -1866,7 +1872,6 @@ The Symfony Connect username in parenthesis allows to get more information - Balazs Csaba - Bill Hance (billhance) - Douglas Reith (douglas_reith) - - Zbigniew Malcherczyk (ferror) - Harry Walter (haswalt) - Jeffrey Moelands (jeffreymoelands) - Jacques MOATI (jmoati) @@ -1906,6 +1911,7 @@ The Symfony Connect username in parenthesis allows to get more information - Clemens Krack - Bruno Baguette - Alexis Lefebvre + - sarah-eit - Michal Forbak - Alexey Berezuev - Pierrick Charron @@ -2025,6 +2031,7 @@ The Symfony Connect username in parenthesis allows to get more information - Mickael Perraud (mikaelkael) - Anton Dyshkant - Ramunas Pabreza + - Zoran Makrevski (zmakrevski) - Kirill Nesmeyanov (serafim) - Reece Fowell (reecefowell) - Muhammad Aakash @@ -2036,6 +2043,7 @@ The Symfony Connect username in parenthesis allows to get more information - Renan Taranto (renan-taranto) - Mateusz Żyła (plotkabytes) - Rikijs Murgs + - WoutervanderLoop.nl - Uladzimir Tsykun - Amaury Leroux de Lens (amo__) - Christian Jul Jensen @@ -2063,9 +2071,9 @@ The Symfony Connect username in parenthesis allows to get more information - Sander Marechal - Franz Wilding (killerpoke) - Ferenczi Krisztian (fchris82) - - Simon André (simonandre) - Artyum Petrov - Oleg Golovakhin (doc_tr) + - Guillaume Smolders (guillaumesmo) - Icode4Food (icode4food) - Radosław Benkel - Bert ter Heide (bertterheide) @@ -2134,6 +2142,7 @@ The Symfony Connect username in parenthesis allows to get more information - gauss - julien.galenski - Florian Guimier + - Igor Kokhlov (verdet) - Christian Neff (secondtruth) - Chris Tiearney - Oliver Hoff @@ -2269,7 +2278,6 @@ The Symfony Connect username in parenthesis allows to get more information - Viacheslav Sychov - Nicolas Sauveur (baishu) - Helmut Hummel (helhum) - - Andrew Neil Forster (krciga22) - Matt Brunt - Carlos Ortega Huetos - Péter Buri (burci) @@ -2288,6 +2296,7 @@ The Symfony Connect username in parenthesis allows to get more information - Matthias Neid - Yannick - Kuzia + - Bram Leeda - Vladimir Luchaninov (luchaninov) - spdionis - rchoquet @@ -2379,6 +2388,7 @@ The Symfony Connect username in parenthesis allows to get more information - Victor Truhanovich (victor_truhanovich) - Pablo Schläpfer - Nikos Charalampidis + - Caligone - Xavier RENAUDIN - Christian Wahler (christian) - Jelte Steijaert (jelte) @@ -2448,6 +2458,7 @@ The Symfony Connect username in parenthesis allows to get more information - Matthieu - Albin Kerouaton - Sébastien HOUZÉ + - wivaku - Jingyu Wang - steveYeah - Samy D (dinduks) @@ -2472,6 +2483,7 @@ The Symfony Connect username in parenthesis allows to get more information - Constantine Shtompel - Jules Lamur - Renato Mendes Figueiredo + - xdavidwu - Raphaël Droz - Asis Pattisahusiwa - Eric Stern @@ -2513,6 +2525,7 @@ The Symfony Connect username in parenthesis allows to get more information - Daniel Kay (danielkay-cp) - Matt Daum (daum) - Alberto Pirovano (geezmo) + - inwebo veritas (inwebo) - Pascal Woerde (pascalwoerde) - Pete Mitchell (peterjmit) - Tom Corrigan (tomcorrigan) @@ -2547,6 +2560,7 @@ The Symfony Connect username in parenthesis allows to get more information - Carsten Nielsen (phreaknerd) - lepeule (vlepeule) - Jay Severson + - Stefan Moonen - René Kerner - Nathaniel Catchpole - upchuk @@ -2688,6 +2702,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jakub Simon - Brandon Antonio Lorenzo - Bouke Haarsma + - Boris Medvedev - mlievertz - Enrico Schultz - tpetry @@ -2769,6 +2784,7 @@ The Symfony Connect username in parenthesis allows to get more information - Houziaux mike - Phobetor - Yoann MOROCUTTI + - d.huethorst - Markus - Zayan Goripov - Janusz Mocek @@ -2881,6 +2897,7 @@ The Symfony Connect username in parenthesis allows to get more information - Gijs Kunze - Artyom Protaskin - Nathanael d. Noblet + - PEHAUT-PIETRI Valmont - Yurun - helmer - ged15 @@ -2890,6 +2907,7 @@ The Symfony Connect username in parenthesis allows to get more information - amcastror - Bram Van der Sype (brammm) - Guile (guile) + - Yuriy Vilks (igrizzli) - Julien Moulin (lizjulien) - Raito Akehanareru (raito) - Mauro Foti (skler) @@ -3217,6 +3235,7 @@ The Symfony Connect username in parenthesis allows to get more information - Paweł Tomulik - Eric J. Duran - Blackfelix + - Pavel Witassek - Alexandru Bucur - cmfcmf - Drew Butler @@ -3354,6 +3373,7 @@ The Symfony Connect username in parenthesis allows to get more information - Daniel Basten (axhm3a) - Albert Bakker (babbert) - Bernd Matzner (bmatzner) + - Sébastien Despont (bouillou) - Bram Tweedegolf (bram_tweedegolf) - Brandon Kelly (brandonkelly) - Choong Wei Tjeng (choonge) From 03c0330919421f40427916d41951c345051eb98f Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 30 Sep 2023 08:31:17 +0200 Subject: [PATCH 03/79] Update VERSION for 5.4.29 --- 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 42e6ed4b1e80f..8e40682cea873 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.29-DEV'; + public const VERSION = '5.4.29'; public const VERSION_ID = 50429; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 4; public const RELEASE_VERSION = 29; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2024'; public const END_OF_LIFE = '11/2025'; From b8eb61daf4a9443298178893f858b953d4e5fd2d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 30 Sep 2023 08:36:22 +0200 Subject: [PATCH 04/79] Bump Symfony version to 5.4.30 --- 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 8e40682cea873..e7e3282d49db7 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.29'; - public const VERSION_ID = 50429; + public const VERSION = '5.4.30-DEV'; + public const VERSION_ID = 50430; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 4; - public const RELEASE_VERSION = 29; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 30; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '11/2024'; public const END_OF_LIFE = '11/2025'; From 1b5ddd09b70594d56d8d4cbe204737ccf5a5bef0 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 30 Sep 2023 08:41:26 +0200 Subject: [PATCH 05/79] Bump Symfony version to 6.3.6 --- 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 be4c9e15bc651..8e9efabd133d2 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.3.5'; - public const VERSION_ID = 60305; + public const VERSION = '6.3.6-DEV'; + public const VERSION_ID = 60306; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 3; - public const RELEASE_VERSION = 5; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 6; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '01/2024'; public const END_OF_LIFE = '01/2024'; From 2f00352ea139c9ac942be5d0fb27638cdf04bd9e Mon Sep 17 00:00:00 2001 From: HypeMC Date: Sun, 1 Oct 2023 00:08:06 +0200 Subject: [PATCH 06/79] [Messenger] Check if PCNTL is installed --- .../Component/Messenger/Command/ConsumeMessagesCommand.php | 2 +- .../Component/Messenger/Command/FailedMessagesRetryCommand.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php index 03dac4b23fe7d..5302d560f8d94 100644 --- a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php +++ b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php @@ -258,7 +258,7 @@ public function complete(CompletionInput $input, CompletionSuggestions $suggesti public function getSubscribedSignals(): array { - return $this->signals ?? [\SIGTERM, \SIGINT]; + return $this->signals ?? (\defined('SIGTERM') ? [\SIGTERM, \SIGINT] : []); } public function handleSignal(int $signal, int|false $previousExitCode = 0): int|false diff --git a/src/Symfony/Component/Messenger/Command/FailedMessagesRetryCommand.php b/src/Symfony/Component/Messenger/Command/FailedMessagesRetryCommand.php index 46929f5493c20..c85f2094127e6 100644 --- a/src/Symfony/Component/Messenger/Command/FailedMessagesRetryCommand.php +++ b/src/Symfony/Component/Messenger/Command/FailedMessagesRetryCommand.php @@ -129,7 +129,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int public function getSubscribedSignals(): array { - return $this->signals ?? [\SIGTERM, \SIGINT]; + return $this->signals ?? (\defined('SIGTERM') ? [\SIGTERM, \SIGINT] : []); } public function handleSignal(int $signal, int|false $previousExitCode = 0): int|false From 5d9d6b79e49178dd9328d29a0959ed1278f350b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Lesueurs?= Date: Fri, 19 Aug 2022 19:39:55 +0200 Subject: [PATCH 07/79] Change incorrect message, when the sender in the global envelope or the from header of asEmailMessage() is not defined. --- src/Symfony/Component/Notifier/Channel/EmailChannel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Notifier/Channel/EmailChannel.php b/src/Symfony/Component/Notifier/Channel/EmailChannel.php index a258783464d6a..c5eec591755c8 100644 --- a/src/Symfony/Component/Notifier/Channel/EmailChannel.php +++ b/src/Symfony/Component/Notifier/Channel/EmailChannel.php @@ -57,7 +57,7 @@ public function notify(Notification $notification, RecipientInterface $recipient if ($email instanceof Email) { if (!$email->getFrom()) { if (null === $this->from) { - throw new LogicException(sprintf('To send the "%s" notification by email, you should either configure a global "from" header, set a sender in the global "envelope" of the mailer configuration or set a "from" header in the "asEmailMessage()" method.', get_debug_type($notification))); + throw new LogicException(sprintf('To send the "%s" notification by email, you must configure the global "from" header. For this you can set a sender in the global "envelope" of the mailer configuration or set a "from" header in the "asEmailMessage()" method.', get_debug_type($notification))); } $email->from($this->from); From 28ba7d98e804cda552188b7c6e053e77176cf122 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 1 Oct 2023 09:27:32 +0200 Subject: [PATCH 08/79] [Notifier] Tweak an error message --- src/Symfony/Component/Notifier/Channel/EmailChannel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Notifier/Channel/EmailChannel.php b/src/Symfony/Component/Notifier/Channel/EmailChannel.php index c5eec591755c8..69caaad1ae480 100644 --- a/src/Symfony/Component/Notifier/Channel/EmailChannel.php +++ b/src/Symfony/Component/Notifier/Channel/EmailChannel.php @@ -57,7 +57,7 @@ public function notify(Notification $notification, RecipientInterface $recipient if ($email instanceof Email) { if (!$email->getFrom()) { if (null === $this->from) { - throw new LogicException(sprintf('To send the "%s" notification by email, you must configure the global "from" header. For this you can set a sender in the global "envelope" of the mailer configuration or set a "from" header in the "asEmailMessage()" method.', get_debug_type($notification))); + throw new LogicException(sprintf('To send the "%s" notification by email, you must configure a "from" header by either setting a sender in the global "envelope" of the mailer configuration or by setting a "from" header in the "asEmailMessage()" method.', get_debug_type($notification))); } $email->from($this->from); From ef35ec1432709d5a08cae91f62e94d2a210635c4 Mon Sep 17 00:00:00 2001 From: Antoine Lamirault Date: Mon, 2 Oct 2023 18:43:31 +0200 Subject: [PATCH 09/79] Fix duplicate component in UPGRADE-6.3.md --- UPGRADE-6.3.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/UPGRADE-6.3.md b/UPGRADE-6.3.md index cf66a462ed78d..b3dcb9eeb1801 100644 --- a/UPGRADE-6.3.md +++ b/UPGRADE-6.3.md @@ -119,10 +119,6 @@ HttpFoundation -------------- * `Response::sendHeaders()` now takes an optional `$statusCode` parameter - -HttpFoundation --------------- - * Deprecate conversion of invalid values in `ParameterBag::getInt()` and `ParameterBag::getBoolean()` * Deprecate ignoring invalid values when using `ParameterBag::filter()`, unless flag `FILTER_NULL_ON_FAILURE` is set From 67f49d4c940bf42ea99d882a577e7f59f6639130 Mon Sep 17 00:00:00 2001 From: Jeroen de Graaf Date: Tue, 3 Oct 2023 10:05:29 +0200 Subject: [PATCH 10/79] Fix order array sum normalizedData and nestedData Previously, when `array_merge` was changed array+array in 6.3.5, the combined array result is changed as well. array_merge behaves differently than array+array. e.g.: ``` $a = ['key' => 'value-a']; $b = ['key' => 'value-b']; var_dump(array_merge($a, $b)); // Results in: // array(1) { // ["key"]=> // string(7) "value-b" // } var_dump($a + $b); // Results in: // array(1) { // ["key"]=> // string(7) "value-a" // } ``` By switching left with right, the result will be the same again. --- .../Normalizer/AbstractObjectNormalizer.php | 2 +- .../AbstractObjectNormalizerTest.php | 22 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index 069d2e3935f62..e6efb49833d0f 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -339,7 +339,7 @@ public function denormalize(mixed $data, string $type, string $format = null, ar $normalizedData = $this->removeNestedValue($serializedPath->getElements(), $normalizedData); } - $normalizedData = $normalizedData + $nestedData; + $normalizedData = $nestedData + $normalizedData; $object = $this->instantiateObject($normalizedData, $mappedClass, $context, new \ReflectionClass($mappedClass), $allowedAttributes, $format); $resolvedClass = ($this->objectClassResolver)($object); diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php index 8eb77718c4ac9..97f96635167a7 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php @@ -813,6 +813,28 @@ public function testDenormalizeWithNumberAsSerializedNameAndNoArrayReindex() $this->assertSame('foo', $test->foo); $this->assertSame('baz', $test->baz); } + + public function testDenormalizeWithCorrectOrderOfAttributeAndProperty() + { + $normalizer = new AbstractObjectNormalizerWithMetadata(); + + $data = [ + 'id' => 'root-level-id', + 'data' => [ + 'id' => 'nested-id', + ], + ]; + + $obj = new class() { + /** + * @SerializedPath("[data][id]") + */ + public $id; + }; + + $test = $normalizer->denormalize($data, $obj::class); + $this->assertSame('nested-id', $test->id); + } } class AbstractObjectNormalizerDummy extends AbstractObjectNormalizer From cff99dc3fdc7d863290dfe12c96c6d412ab81d8b Mon Sep 17 00:00:00 2001 From: "g.petraroli" Date: Wed, 4 Oct 2023 14:42:59 +0200 Subject: [PATCH 11/79] [Validator] Add missing italian translations --- .../Resources/translations/validators.it.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf index c7cd43784ee63..d9d9d06611d42 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Il valore della netmask dovrebbe essere compreso tra {{ min }} e {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Il nome del file è troppo lungo. Dovrebbe avere {{ filename_max_length }} carattere o meno.|Il nome del file è troppo lungo. Dovrebbe avere {{ filename_max_length }} caratteri o meno. + + + The password strength is too low. Please use a stronger password. + La password non è abbastanza sicura. Per favore, utilizza una password più robusta. + + + This value contains characters that are not allowed by the current restriction-level. + Questo valore contiene caratteri che non sono consentiti dal livello di restrizione attuale. + + + Using invisible characters is not allowed. + Utilizzare caratteri invisibili non è consentito. + + + Mixing numbers from different scripts is not allowed. + Non è consentito mescolare numeri provenienti da diversi script. + + + Using hidden overlay characters is not allowed. + Non è consentito utilizzare caratteri sovrapposti nascosti. + From 1610db245e0eddfa4e973721269107ab0ee6b8d5 Mon Sep 17 00:00:00 2001 From: Romain Monteil Date: Wed, 4 Oct 2023 16:12:03 +0200 Subject: [PATCH 12/79] [FrameworkBundle] Fix call to invalid method in NotificationAssertionsTrait --- .../Bundle/FrameworkBundle/Test/NotificationAssertionsTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/NotificationAssertionsTrait.php b/src/Symfony/Bundle/FrameworkBundle/Test/NotificationAssertionsTrait.php index 30298ef04c54f..5f2876c63c98b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Test/NotificationAssertionsTrait.php +++ b/src/Symfony/Bundle/FrameworkBundle/Test/NotificationAssertionsTrait.php @@ -29,7 +29,7 @@ public static function assertNotificationCount(int $count, string $transportName public static function assertQueuedNotificationCount(int $count, string $transportName = null, string $message = ''): void { - self::assertThat(self::getMessageMailerEvents(), new NotifierConstraint\NotificationCount($count, $transportName, true), $message); + self::assertThat(self::getNotificationEvents(), new NotifierConstraint\NotificationCount($count, $transportName, true), $message); } public static function assertNotificationIsQueued(MessageEvent $event, string $message = ''): void From 2ddf09b6645564d2b7dd4e2358e28de81c3a87e4 Mon Sep 17 00:00:00 2001 From: Philipp Date: Fri, 6 Oct 2023 12:08:56 +0200 Subject: [PATCH 13/79] [HttpClient] Fix type error with http_version 1.1 Fix a type error by removing a nested setProtocolVersions() call in AmpHttpClient::request() --- src/Symfony/Component/HttpClient/AmpHttpClient.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/AmpHttpClient.php b/src/Symfony/Component/HttpClient/AmpHttpClient.php index 26b1977314deb..341961ee7fa9e 100644 --- a/src/Symfony/Component/HttpClient/AmpHttpClient.php +++ b/src/Symfony/Component/HttpClient/AmpHttpClient.php @@ -122,7 +122,7 @@ public function request(string $method, string $url, array $options = []): Respo if ($options['http_version']) { $request->setProtocolVersions(match ((float) $options['http_version']) { 1.0 => ['1.0'], - 1.1 => $request->setProtocolVersions(['1.1', '1.0']), + 1.1 => ['1.1', '1.0'], default => ['2', '1.1', '1.0'], }); } From 98c41e07bc95db4cd478d4f408c04dbe8455fb9a Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Thu, 5 Oct 2023 15:08:48 +0200 Subject: [PATCH 14/79] [Security] Fix resetting traceable listeners --- .../SecurityBundle/Debug/TraceableFirewallListener.php | 9 ++++++++- .../DependencyInjection/SecurityExtension.php | 1 + .../SecurityBundle/Resources/config/security_debug.php | 1 + src/Symfony/Bundle/SecurityBundle/composer.json | 3 ++- .../Debug/TraceableAuthenticatorManagerListener.php | 8 +++++++- src/Symfony/Component/Security/Http/composer.json | 5 +++-- 6 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php b/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php index e82b47695bad9..9cb032adc8e93 100644 --- a/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php +++ b/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php @@ -17,13 +17,14 @@ use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\Security\Http\Authenticator\Debug\TraceableAuthenticatorManagerListener; use Symfony\Component\Security\Http\Firewall\FirewallListenerInterface; +use Symfony\Contracts\Service\ResetInterface; /** * Firewall collecting called security listeners and authenticators. * * @author Robin Chalas */ -final class TraceableFirewallListener extends FirewallListener +final class TraceableFirewallListener extends FirewallListener implements ResetInterface { private $wrappedListeners = []; private $authenticatorsInfo = []; @@ -38,6 +39,12 @@ public function getAuthenticatorsInfo(): array return $this->authenticatorsInfo; } + public function reset(): void + { + $this->wrappedListeners = []; + $this->authenticatorsInfo = []; + } + protected function callListeners(RequestEvent $event, iterable $listeners) { $wrappedListeners = []; diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index c165024b68d0d..c19cae041bd10 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -544,6 +544,7 @@ private function createFirewall(ContainerBuilder $container, string $id, array $ ->register('debug.security.firewall.authenticator.'.$id, TraceableAuthenticatorManagerListener::class) ->setDecoratedService('security.firewall.authenticator.'.$id) ->setArguments([new Reference('debug.security.firewall.authenticator.'.$id.'.inner')]) + ->addTag('kernel.reset', ['method' => 'reset']) ; } diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_debug.php b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_debug.php index dc668b15e9ded..c98e3a6984672 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_debug.php +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_debug.php @@ -36,6 +36,7 @@ service('security.logout_url_generator'), ]) ->tag('kernel.event_subscriber') + ->tag('kernel.reset', ['method' => 'reset']) ->alias('security.firewall', 'debug.security.firewall') ; }; diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index dc3c62aeee0e6..097031baffb6d 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -29,7 +29,8 @@ "symfony/security-core": "^5.4|^6.0", "symfony/security-csrf": "^4.4|^5.0|^6.0", "symfony/security-guard": "^5.3", - "symfony/security-http": "^5.4.20|~6.0.20|~6.1.12|^6.2.6" + "symfony/security-http": "^5.4.30|^6.3.6", + "symfony/service-contracts": "^1.10|^2|^3" }, "require-dev": { "doctrine/annotations": "^1.10.4|^2", diff --git a/src/Symfony/Component/Security/Http/Authenticator/Debug/TraceableAuthenticatorManagerListener.php b/src/Symfony/Component/Security/Http/Authenticator/Debug/TraceableAuthenticatorManagerListener.php index 3286ce265dd81..e67e332286014 100644 --- a/src/Symfony/Component/Security/Http/Authenticator/Debug/TraceableAuthenticatorManagerListener.php +++ b/src/Symfony/Component/Security/Http/Authenticator/Debug/TraceableAuthenticatorManagerListener.php @@ -16,13 +16,14 @@ use Symfony\Component\Security\Http\Firewall\AbstractListener; use Symfony\Component\Security\Http\Firewall\AuthenticatorManagerListener; use Symfony\Component\VarDumper\Caster\ClassStub; +use Symfony\Contracts\Service\ResetInterface; /** * Decorates the AuthenticatorManagerListener to collect information about security authenticators. * * @author Robin Chalas */ -final class TraceableAuthenticatorManagerListener extends AbstractListener +final class TraceableAuthenticatorManagerListener extends AbstractListener implements ResetInterface { private $authenticationManagerListener; private $authenticatorsInfo = []; @@ -78,4 +79,9 @@ public function getAuthenticatorsInfo(): array { return $this->authenticatorsInfo; } + + public function reset(): void + { + $this->authenticatorsInfo = []; + } } diff --git a/src/Symfony/Component/Security/Http/composer.json b/src/Symfony/Component/Security/Http/composer.json index a5378b3ce5812..deb09da87c162 100644 --- a/src/Symfony/Component/Security/Http/composer.json +++ b/src/Symfony/Component/Security/Http/composer.json @@ -18,12 +18,13 @@ "require": { "php": ">=7.2.5", "symfony/deprecation-contracts": "^2.1|^3", - "symfony/security-core": "^5.4.19|~6.0.19|~6.1.11|^6.2.5", "symfony/http-foundation": "^5.3|^6.0", "symfony/http-kernel": "^5.3|^6.0", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php80": "^1.16", - "symfony/property-access": "^4.4|^5.0|^6.0" + "symfony/property-access": "^4.4|^5.0|^6.0", + "symfony/security-core": "^5.4.19|~6.0.19|~6.1.11|^6.2.5", + "symfony/service-contracts": "^1.10|^2|^3" }, "require-dev": { "symfony/cache": "^4.4|^5.0|^6.0", From af18ce4709c66987dc8d85670b1547d945deeee9 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Fri, 6 Oct 2023 21:16:43 +0200 Subject: [PATCH 15/79] Make FormPerformanceTestCase compatible with PHPUnit 10 --- .../Form/Test/FormPerformanceTestCase.php | 10 ++++-- .../Form/Test/Traits/RunTestTrait.php | 36 +++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Component/Form/Test/Traits/RunTestTrait.php diff --git a/src/Symfony/Component/Form/Test/FormPerformanceTestCase.php b/src/Symfony/Component/Form/Test/FormPerformanceTestCase.php index 732f9ec3dd02b..8c0284ebf5985 100644 --- a/src/Symfony/Component/Form/Test/FormPerformanceTestCase.php +++ b/src/Symfony/Component/Form/Test/FormPerformanceTestCase.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Form\Test; +use Symfony\Component\Form\Test\Traits\RunTestTrait; use Symfony\Component\Form\Tests\VersionAwareTest; /** @@ -23,6 +24,7 @@ */ abstract class FormPerformanceTestCase extends FormIntegrationTestCase { + use RunTestTrait; use VersionAwareTest; /** @@ -31,17 +33,19 @@ abstract class FormPerformanceTestCase extends FormIntegrationTestCase protected $maxRunningTime = 0; /** - * {@inheritdoc} + * @return mixed */ - protected function runTest() + private function doRunTest() { $s = microtime(true); - parent::runTest(); + $result = parent::runTest(); $time = microtime(true) - $s; if (0 != $this->maxRunningTime && $time > $this->maxRunningTime) { $this->fail(sprintf('expected running time: <= %s but was: %s', $this->maxRunningTime, $time)); } + + return $result; } /** diff --git a/src/Symfony/Component/Form/Test/Traits/RunTestTrait.php b/src/Symfony/Component/Form/Test/Traits/RunTestTrait.php new file mode 100644 index 0000000000000..17204b96703f2 --- /dev/null +++ b/src/Symfony/Component/Form/Test/Traits/RunTestTrait.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Test\Traits; + +use PHPUnit\Framework\TestCase; + +if ((new \ReflectionMethod(TestCase::class, 'runTest'))->hasReturnType()) { + // PHPUnit 10 + /** @internal */ + trait RunTestTrait + { + protected function runTest(): mixed + { + return $this->doRunTest(); + } + } +} else { + // PHPUnit 9 + /** @internal */ + trait RunTestTrait + { + protected function runTest() + { + return $this->doRunTest(); + } + } +} From 06347181ebf877a13d80b8a5a32431bd502552b2 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 8 Oct 2023 19:43:22 +0200 Subject: [PATCH 16/79] synchronize the Relay fixture --- src/Symfony/Component/Cache/Traits/RelayProxy.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Symfony/Component/Cache/Traits/RelayProxy.php b/src/Symfony/Component/Cache/Traits/RelayProxy.php index 0971aa186ffd9..2f0e2c8460007 100644 --- a/src/Symfony/Component/Cache/Traits/RelayProxy.php +++ b/src/Symfony/Component/Cache/Traits/RelayProxy.php @@ -542,6 +542,11 @@ public function publish($channel, $message): \Relay\Relay|false|int return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->publish(...\func_get_args()); } + public function pubsub($operation, ...$args): mixed + { + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->pubsub(...\func_get_args()); + } + public function spublish($channel, $message): \Relay\Relay|false|int { return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->spublish(...\func_get_args()); From 7c8b6ed5de8fd672f9e00820ba956306f73c9d7e Mon Sep 17 00:00:00 2001 From: Mykola Zyk Date: Wed, 22 Dec 2021 20:01:14 +0200 Subject: [PATCH 17/79] [RateLimiter] TokenBucket policy fix for adding tokens with a predefined frequency --- .../Component/RateLimiter/Policy/Rate.php | 12 +++++++++ .../RateLimiter/Policy/TokenBucket.php | 7 ++++- .../RateLimiter/Policy/TokenBucketLimiter.php | 2 -- .../Tests/Policy/TokenBucketLimiterTest.php | 26 +++++++++++++++++++ 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/RateLimiter/Policy/Rate.php b/src/Symfony/Component/RateLimiter/Policy/Rate.php index 0c91ef78e76c2..3775f53ae8b3c 100644 --- a/src/Symfony/Component/RateLimiter/Policy/Rate.php +++ b/src/Symfony/Component/RateLimiter/Policy/Rate.php @@ -95,6 +95,18 @@ public function calculateNewTokensDuringInterval(float $duration): int return $cycles * $this->refillAmount; } + /** + * Calculates total amount in seconds of refill intervals during $duration (for maintain strict refill frequency). + * + * @param float $duration interval in seconds + */ + public function calculateRefillInterval(float $duration): int + { + $cycleTime = TimeUtil::dateIntervalToSeconds($this->refillTime); + + return floor($duration / $cycleTime) * $cycleTime; + } + public function __toString(): string { return $this->refillTime->format('P%dDT%HH%iM%sS').'-'.$this->refillAmount; diff --git a/src/Symfony/Component/RateLimiter/Policy/TokenBucket.php b/src/Symfony/Component/RateLimiter/Policy/TokenBucket.php index e4eb32a744a71..2d43286e15e23 100644 --- a/src/Symfony/Component/RateLimiter/Policy/TokenBucket.php +++ b/src/Symfony/Component/RateLimiter/Policy/TokenBucket.php @@ -83,8 +83,13 @@ public function setTokens(int $tokens): void public function getAvailableTokens(float $now): int { $elapsed = max(0, $now - $this->timer); + $newTokens = $this->rate->calculateNewTokensDuringInterval($elapsed); - return min($this->burstSize, $this->tokens + $this->rate->calculateNewTokensDuringInterval($elapsed)); + if ($newTokens > 0) { + $this->timer += $this->rate->calculateRefillInterval($elapsed); + } + + return min($this->burstSize, $this->tokens + $newTokens); } public function getExpirationTime(): int diff --git a/src/Symfony/Component/RateLimiter/Policy/TokenBucketLimiter.php b/src/Symfony/Component/RateLimiter/Policy/TokenBucketLimiter.php index 09c4e36cdf861..5724eba2b2abb 100644 --- a/src/Symfony/Component/RateLimiter/Policy/TokenBucketLimiter.php +++ b/src/Symfony/Component/RateLimiter/Policy/TokenBucketLimiter.php @@ -72,7 +72,6 @@ public function reserve(int $tokens = 1, float $maxTime = null): Reservation if ($availableTokens >= $tokens) { // tokens are now available, update bucket $bucket->setTokens($availableTokens - $tokens); - $bucket->setTimer($now); $reservation = new Reservation($now, new RateLimit($bucket->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now)), true, $this->maxBurst)); } else { @@ -89,7 +88,6 @@ public function reserve(int $tokens = 1, float $maxTime = null): Reservation // at $now + $waitDuration all tokens will be reserved for this process, // so no tokens are left for other processes. $bucket->setTokens($availableTokens - $tokens); - $bucket->setTimer($now); $reservation = new Reservation($now + $waitDuration, new RateLimit(0, \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false, $this->maxBurst)); } diff --git a/src/Symfony/Component/RateLimiter/Tests/Policy/TokenBucketLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/Policy/TokenBucketLimiterTest.php index 84136ed7f5d7d..3b7b579c0cf77 100644 --- a/src/Symfony/Component/RateLimiter/Tests/Policy/TokenBucketLimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/Policy/TokenBucketLimiterTest.php @@ -128,6 +128,32 @@ public function testBucketResilientToTimeShifting() $this->assertSame(100, $bucket->getAvailableTokens($serverOneClock)); } + public function testBucketRefilledWithStrictFrequency() + { + $limiter = $this->createLimiter(1000, new Rate(\DateInterval::createFromDateString('15 seconds'), 100)); + $rateLimit = $limiter->consume(300); + + $this->assertTrue($rateLimit->isAccepted()); + $this->assertEquals(700, $rateLimit->getRemainingTokens()); + + $expected = 699; + + for ($i = 1; $i <= 20; ++$i) { + $rateLimit = $limiter->consume(); + $this->assertTrue($rateLimit->isAccepted()); + $this->assertEquals($expected, $rateLimit->getRemainingTokens()); + + sleep(4); + --$expected; + + if (\in_array($i, [4, 8, 12], true)) { + $expected += 100; + } elseif (\in_array($i, [15, 19], true)) { + $expected = 999; + } + } + } + private function createLimiter($initialTokens = 10, Rate $rate = null) { return new TokenBucketLimiter('test', $initialTokens, $rate ?? Rate::perSecond(10), $this->storage); From 49f7f5e71911b3d6540f744cf4475f571cf012a6 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Tue, 10 Oct 2023 08:19:19 +0200 Subject: [PATCH 18/79] Add keyword `dev` to leverage composer hint --- src/Symfony/Bridge/PhpUnit/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/composer.json b/src/Symfony/Bridge/PhpUnit/composer.json index 9627d2b40c12c..4cddb15dac3a2 100644 --- a/src/Symfony/Bridge/PhpUnit/composer.json +++ b/src/Symfony/Bridge/PhpUnit/composer.json @@ -2,7 +2,7 @@ "name": "symfony/phpunit-bridge", "type": "symfony-bridge", "description": "Provides utilities for PHPUnit, especially user deprecation notices management", - "keywords": [], + "keywords": ['dev'], "homepage": "https://symfony.com", "license": "MIT", "authors": [ From e86d26abd07187d5ec5b2d780cfd1d872d57fe2a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 10 Oct 2023 09:31:48 +0200 Subject: [PATCH 19/79] [PhpUnitBridge] Fix typo --- src/Symfony/Bridge/PhpUnit/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/composer.json b/src/Symfony/Bridge/PhpUnit/composer.json index 4cddb15dac3a2..167ed8767b35b 100644 --- a/src/Symfony/Bridge/PhpUnit/composer.json +++ b/src/Symfony/Bridge/PhpUnit/composer.json @@ -2,7 +2,7 @@ "name": "symfony/phpunit-bridge", "type": "symfony-bridge", "description": "Provides utilities for PHPUnit, especially user deprecation notices management", - "keywords": ['dev'], + "keywords": ["dev"], "homepage": "https://symfony.com", "license": "MIT", "authors": [ From 5168f2d8515e1a76c097b0432ffbad4dd5034488 Mon Sep 17 00:00:00 2001 From: adhamiamirhossein Date: Tue, 10 Oct 2023 13:52:57 +0330 Subject: [PATCH 20/79] [Validator] Add missing Persian(fa) translations --- .../Resources/translations/validators.fa.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf index b72bc6e03e93c..50bb61aac420f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. مقدار ماسک شبکه (NetMask) باید بین {{ min }} و {{ max }} باشد. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + نام فایل طولانی است. نام فایل باید {{ filename_max_length }} کاراکتر یا کمتر باشد.|نام فایل طولانی است. نام فایل باید {{ filename_max_length }} کاراکتر یا کمتر باشد. + + + The password strength is too low. Please use a stronger password. + رمز عبور ضعیف است. لطفا از رمز عبور قوی‌تری استفاده کنید. + + + This value contains characters that are not allowed by the current restriction-level. + این مقدار حاوی کاراکترهایی است که در سطح محدودیت فعلی مجاز نیستند. + + + Using invisible characters is not allowed. + استفاده از کاراکترهای نامرئی مجاز نمی‌باشد. + + + Mixing numbers from different scripts is not allowed. + مخلوط کردن اعداد از اسکریپت های مختلف مجاز نیست. + + + Using hidden overlay characters is not allowed. + استفاده از کاراکترهای همپوشانی پنهان (hidden overlay characters) مجاز نیست. + From 21e4d935e7e5a44dd0489986b94ef35652f08daa Mon Sep 17 00:00:00 2001 From: Victor Bocharsky Date: Tue, 10 Oct 2023 15:57:34 +0200 Subject: [PATCH 21/79] Fix the link to the docs --- src/Symfony/Component/AssetMapper/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/AssetMapper/README.md b/src/Symfony/Component/AssetMapper/README.md index dad6763a644b8..f57179ff6fd2d 100644 --- a/src/Symfony/Component/AssetMapper/README.md +++ b/src/Symfony/Component/AssetMapper/README.md @@ -14,7 +14,7 @@ are not covered by Symfony's Resources --------- - * [Documentation](https://symfony.com/doc/current/components/asset_mapper/introduction.html) + * [Documentation](https://symfony.com/doc/current/frontend/asset_mapper.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) From f10c2ccd33a0ac17f5a45f930e3a878452eb830f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 10 Oct 2023 12:05:35 +0200 Subject: [PATCH 22/79] [FrameworkBundle] Fix calling Kernel::warmUp() when running cache:warmup --- .../Bundle/FrameworkBundle/Command/CacheWarmupCommand.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CacheWarmupCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CacheWarmupCommand.php index ddaf9eb63e06d..48e882e6f68b3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/CacheWarmupCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/CacheWarmupCommand.php @@ -18,6 +18,7 @@ use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\DependencyInjection\Dumper\Preloader; use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerAggregate; +use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface; /** * Warmup the cache. @@ -73,8 +74,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int if (!$input->getOption('no-optional-warmers')) { $this->cacheWarmer->enableOptionalWarmers(); } + $cacheDir = $kernel->getContainer()->getParameter('kernel.cache_dir'); - $preload = $this->cacheWarmer->warmUp($cacheDir = $kernel->getContainer()->getParameter('kernel.cache_dir')); + if ($kernel instanceof WarmableInterface) { + $kernel->warmUp($cacheDir); + } + + $preload = $this->cacheWarmer->warmUp($cacheDir); if ($preload && file_exists($preloadFile = $cacheDir.'/'.$kernel->getContainer()->getParameter('kernel.container_class').'.preload.php')) { Preloader::append($preloadFile, $preload); From b32735b19f17901b3aed9e5ac38a71ffdc31a69c Mon Sep 17 00:00:00 2001 From: Pedro Silva <9375141+pedrox-hs@users.noreply.github.com> Date: Tue, 10 Oct 2023 14:12:05 -0300 Subject: [PATCH 23/79] [Translation][Validator] Add missing translations for pt_BR (104-109) --- .../translations/validators.pt_BR.xlf | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf index e88b81f9eaf8b..7e930a3c6a0bf 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf @@ -402,6 +402,31 @@ The value of the netmask should be between {{ min }} and {{ max }}. O valor da máscara de rede deve estar entre {{ min }} e {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + O nome do arquivo é muito longo. Deve ter {{ filename_max_length }} caractere ou menos.|O nome do arquivo é muito longo. Deve ter {{ filename_max_length }} caracteres ou menos. + + + The password strength is too low. Please use a stronger password. + A força da senha é muito baixa. Por favor, use uma senha mais forte. + + + This value contains characters that are not allowed by the current restriction-level. + Este valor contém caracteres que não são permitidos pelo nível de restrição atual. + + + Using invisible characters is not allowed. + O uso de caracteres invisíveis não é permitido. + + + Mixing numbers from different scripts is not allowed. + Misturar números de scripts diferentes não é permitido. + + + Using hidden overlay characters is not allowed. + O uso de caracteres de sobreposição ocultos não é permitido. + + From 887b1307bfea90fff734e2cbaaef4242099dc8be Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Tue, 10 Oct 2023 21:28:02 +0200 Subject: [PATCH 24/79] [Translation] remove blank line --- .../Validator/Resources/translations/validators.pt_BR.xlf | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf index 7e930a3c6a0bf..2430ad6b58285 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf @@ -426,7 +426,6 @@ Using hidden overlay characters is not allowed. O uso de caracteres de sobreposição ocultos não é permitido. - From 970f9ae38e99b23182862e95e8303b91c7ba765e Mon Sep 17 00:00:00 2001 From: Natsuki Ikeguchi Date: Wed, 11 Oct 2023 01:50:15 +0900 Subject: [PATCH 25/79] [Translation][Validator] Add missing translations for Japanese (104 - 109) --- .../Resources/translations/validators.ja.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf index 9feed48d04cb0..7e4cac5434a17 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. ネットマスクの値は、{{ min }}から{{ max }}の間にある必要があります。 + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + ファイル名が長すぎます。ファイル名の長さは{{ filename_max_length }}文字以下でなければなりません。 + + + The password strength is too low. Please use a stronger password. + パスワードの強度が弱すぎます。より強いパスワードを使用してください。 + + + This value contains characters that are not allowed by the current restriction-level. + この値は現在の制限レベルで許可されていない文字を含んでいます。 + + + Using invisible characters is not allowed. + 不可視文字は使用できません。 + + + Mixing numbers from different scripts is not allowed. + 異なる種類の数字を使うことはできません。 + + + Using hidden overlay characters is not allowed. + 隠れたオーバレイ文字は使用できません。 + From d398c8bacf05d0035a3f36699f0001981c23ac45 Mon Sep 17 00:00:00 2001 From: Sergey Panteleev Date: Wed, 11 Oct 2023 10:53:45 +0300 Subject: [PATCH 26/79] [Translation][Validator] Add missing translations for Russian (104 - 109) --- .../Resources/translations/validators.ru.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf index 8705cbb55d0e6..2b66b1eafd954 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Значение маски подсети должно быть от {{ min }} до {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Имя файла слишком длинное. Оно должно содержать {{ filename_max_length }} символ или меньше.|Имя файла слишком длинное. Оно должно содержать {{ filename_max_length }} символа или меньше.|Имя файла слишком длинное. Оно должно содержать {{ filename_max_length }} символов или меньше. + + + The password strength is too low. Please use a stronger password. + Слишком низкая надёжность пароля. Пожалуйста, используйте более надёжный пароль. + + + This value contains characters that are not allowed by the current restriction-level. + Значение содержит символы, запрещённые на текущем уровне ограничений. + + + Using invisible characters is not allowed. + Использование невидимых символов запрещено. + + + Mixing numbers from different scripts is not allowed. + Смешивание номеров из разных сценариев запрещено. + + + Using hidden overlay characters is not allowed. + Использование невидимых символов наложения запрещено. + From c0648fff946731e2d6ad82baf81b01a48522b608 Mon Sep 17 00:00:00 2001 From: Mathieu Lechat Date: Wed, 11 Oct 2023 10:22:16 +0200 Subject: [PATCH 27/79] [WebProfilerBundle] Fix markup to make link to profiler appear on errored WDT --- .../Resources/views/Profiler/base_js.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig index af36bc03313de..be979cd6ad231 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig @@ -618,7 +618,7 @@ if (typeof Sfjs === 'undefined' || typeof Sfjs.loadToolbar === 'undefined') { sfwdt.innerHTML = '\
\
\ - An error occurred while loading the web debug toolbar. Open the web profiler.\ + An error occurred while loading the web debug toolbar. Open the web profiler.\
\ '; sfwdt.setAttribute('class', 'sf-toolbar sf-error-toolbar'); From ccacdf885bfd2cb4ddd02a4acd5da80ec09b7611 Mon Sep 17 00:00:00 2001 From: Yanick Witschi Date: Wed, 11 Oct 2023 10:40:37 +0200 Subject: [PATCH 28/79] Do not match request twice in HttpUtils --- .../Component/Security/Http/HttpUtils.php | 5 +++++ .../Security/Http/Tests/HttpUtilsTest.php | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Symfony/Component/Security/Http/HttpUtils.php b/src/Symfony/Component/Security/Http/HttpUtils.php index a4e0371321516..ee15ce965e38e 100644 --- a/src/Symfony/Component/Security/Http/HttpUtils.php +++ b/src/Symfony/Component/Security/Http/HttpUtils.php @@ -118,6 +118,11 @@ public function createRequest(Request $request, string $path) public function checkRequestPath(Request $request, string $path) { if ('/' !== $path[0]) { + // Shortcut if request has already been matched before + if ($request->attributes->has('_route')) { + return $path === $request->attributes->get('_route'); + } + try { // matching a request is more powerful than matching a URL path + context, so try that first if ($this->urlMatcher instanceof RequestMatcherInterface) { diff --git a/src/Symfony/Component/Security/Http/Tests/HttpUtilsTest.php b/src/Symfony/Component/Security/Http/Tests/HttpUtilsTest.php index 7686a296d775b..a63c40f5b9758 100644 --- a/src/Symfony/Component/Security/Http/Tests/HttpUtilsTest.php +++ b/src/Symfony/Component/Security/Http/Tests/HttpUtilsTest.php @@ -318,6 +318,22 @@ public function testCheckRequestPathWithUrlMatcherLoadingException() $utils->checkRequestPath($this->getRequest(), 'foobar'); } + public function testCheckRequestPathWithRequestAlreadyMatchedBefore() + { + $urlMatcher = $this->createMock(RequestMatcherInterface::class); + $urlMatcher + ->expects($this->never()) + ->method('matchRequest') + ; + + $request = $this->getRequest(); + $request->attributes->set('_route', 'route_name'); + + $utils = new HttpUtils(null, $urlMatcher); + $this->assertTrue($utils->checkRequestPath($request, 'route_name')); + $this->assertFalse($utils->checkRequestPath($request, 'foobar')); + } + public function testCheckPathWithoutRouteParam() { $urlMatcher = $this->createMock(UrlMatcherInterface::class); From 79d75ffba9975873b898b511fda59b2d40e44fa7 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Tue, 10 Oct 2023 09:59:31 +0200 Subject: [PATCH 29/79] Run high-deps tests with ORM 3 and DBAL 4 --- .../PropertyInfo/DoctrineExtractor.php | 19 +++-- .../Doctrine/Test/TestRepositoryFactory.php | 35 +++++++-- .../Tests/Fixtures/LegacyQueryMock.php | 36 +++++++++ .../ChoiceList/ORMQueryBuilderLoaderTest.php | 78 +++++++------------ .../Tests/Form/DoctrineOrmTypeGuesserTest.php | 46 +++++++---- .../PropertyInfo/DoctrineExtractorTest.php | 24 ++---- .../Security/User/EntityUserProviderTest.php | 5 +- .../Constraints/UniqueEntityValidatorTest.php | 5 +- .../Tests/Validator/DoctrineLoaderTest.php | 43 ++++++---- .../Doctrine/Validator/DoctrineLoader.php | 4 +- src/Symfony/Bridge/Doctrine/composer.json | 4 +- .../Cache/Tests/Fixtures/DriverWrapper.php | 5 +- src/Symfony/Component/Cache/composer.json | 2 +- .../Tests/Store/DoctrineDbalStoreTest.php | 15 +++- src/Symfony/Component/Lock/composer.json | 2 +- .../Tests/Transport/ConnectionTest.php | 48 ++++++++---- .../DoctrineTransportFactoryTest.php | 12 ++- .../Bridge/Doctrine/Transport/Connection.php | 7 +- .../Messenger/Bridge/Doctrine/composer.json | 2 +- 19 files changed, 247 insertions(+), 145 deletions(-) create mode 100644 src/Symfony/Bridge/Doctrine/Tests/Fixtures/LegacyQueryMock.php diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index db9c151f0268e..ccd53c1ebe7c6 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -14,9 +14,8 @@ use Doctrine\Common\Collections\Collection; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Mapping\AssociationMapping; use Doctrine\ORM\Mapping\ClassMetadata; -use Doctrine\ORM\Mapping\ClassMetadataInfo; -use Doctrine\ORM\Mapping\Embedded; use Doctrine\ORM\Mapping\MappingException as OrmMappingException; use Doctrine\Persistence\Mapping\MappingException; use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface; @@ -49,7 +48,7 @@ public function getProperties(string $class, array $context = []) $properties = array_merge($metadata->getFieldNames(), $metadata->getAssociationNames()); - if ($metadata instanceof ClassMetadataInfo && class_exists(Embedded::class) && $metadata->embeddedClasses) { + if ($metadata instanceof ClassMetadata && $metadata->embeddedClasses) { $properties = array_filter($properties, function ($property) { return !str_contains($property, '.'); }); @@ -73,7 +72,7 @@ public function getTypes(string $class, string $property, array $context = []) $class = $metadata->getAssociationTargetClass($property); if ($metadata->isSingleValuedAssociation($property)) { - if ($metadata instanceof ClassMetadataInfo) { + if ($metadata instanceof ClassMetadata) { $associationMapping = $metadata->getAssociationMapping($property); $nullable = $this->isAssociationNullable($associationMapping); @@ -86,11 +85,10 @@ public function getTypes(string $class, string $property, array $context = []) $collectionKeyType = Type::BUILTIN_TYPE_INT; - if ($metadata instanceof ClassMetadataInfo) { + if ($metadata instanceof ClassMetadata) { $associationMapping = $metadata->getAssociationMapping($property); if (isset($associationMapping['indexBy'])) { - /** @var ClassMetadataInfo $subMetadata */ $subMetadata = $this->entityManager->getClassMetadata($associationMapping['targetEntity']); // Check if indexBy value is a property @@ -102,7 +100,6 @@ public function getTypes(string $class, string $property, array $context = []) // Maybe the column name is the association join column? $associationMapping = $subMetadata->getAssociationMapping($fieldName); - /** @var ClassMetadataInfo $subMetadata */ $indexProperty = $subMetadata->getSingleAssociationReferencedJoinColumnName($fieldName); $subMetadata = $this->entityManager->getClassMetadata($associationMapping['targetEntity']); @@ -130,7 +127,7 @@ public function getTypes(string $class, string $property, array $context = []) )]; } - if ($metadata instanceof ClassMetadataInfo && class_exists(Embedded::class) && isset($metadata->embeddedClasses[$property])) { + if ($metadata instanceof ClassMetadata && isset($metadata->embeddedClasses[$property])) { return [new Type(Type::BUILTIN_TYPE_OBJECT, false, $metadata->embeddedClasses[$property]['class'])]; } @@ -141,7 +138,7 @@ public function getTypes(string $class, string $property, array $context = []) return null; } - $nullable = $metadata instanceof ClassMetadataInfo && $metadata->isNullable($property); + $nullable = $metadata instanceof ClassMetadata && $metadata->isNullable($property); $enumType = null; if (null !== $enumClass = $metadata->getFieldMapping($property)['enumType'] ?? null) { $enumType = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $enumClass); @@ -233,9 +230,11 @@ private function getMetadata(string $class): ?ClassMetadata /** * Determines whether an association is nullable. * + * @param array|AssociationMapping $associationMapping + * * @see https://github.com/doctrine/doctrine2/blob/v2.5.4/lib/Doctrine/ORM/Tools/EntityGenerator.php#L1221-L1246 */ - private function isAssociationNullable(array $associationMapping): bool + private function isAssociationNullable($associationMapping): bool { if (isset($associationMapping['id']) && $associationMapping['id']) { return false; diff --git a/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php b/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php index 80964663c340c..f08e2154d06e9 100644 --- a/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php +++ b/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php @@ -12,10 +12,36 @@ namespace Symfony\Bridge\Doctrine\Test; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Repository\RepositoryFactory; use Doctrine\Persistence\ObjectRepository; +if ((new \ReflectionMethod(RepositoryFactory::class, 'getRepository'))->hasReturnType()) { + /** @internal */ + trait GetRepositoryTrait + { + public function getRepository(EntityManagerInterface $entityManager, string $entityName): EntityRepository + { + return $this->doGetRepository($entityManager, $entityName); + } + } +} else { + /** @internal */ + trait GetRepositoryTrait + { + /** + * {@inheritdoc} + * + * @return ObjectRepository + */ + public function getRepository(EntityManagerInterface $entityManager, $entityName) + { + return $this->doGetRepository($entityManager, $entityName); + } + } +} + /** * @author Andreas Braun * @@ -23,17 +49,14 @@ */ class TestRepositoryFactory implements RepositoryFactory { + use GetRepositoryTrait; + /** * @var ObjectRepository[] */ private $repositoryList = []; - /** - * {@inheritdoc} - * - * @return ObjectRepository - */ - public function getRepository(EntityManagerInterface $entityManager, $entityName) + private function doGetRepository(EntityManagerInterface $entityManager, string $entityName): ObjectRepository { if (__CLASS__ === static::class) { trigger_deprecation('symfony/doctrine-bridge', '5.3', '"%s" is deprecated and will be removed in 6.0.', __CLASS__); diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/LegacyQueryMock.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/LegacyQueryMock.php new file mode 100644 index 0000000000000..5ec46f606a8d9 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/LegacyQueryMock.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Tests\Fixtures; + +use Doctrine\DBAL\Result; +use Doctrine\ORM\AbstractQuery; + +class LegacyQueryMock extends AbstractQuery +{ + public function __construct() + { + } + + /** + * @return array|string + */ + public function getSQL() + { + } + + /** + * @return Result|int + */ + protected function _doExecute() + { + } +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/ORMQueryBuilderLoaderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/ORMQueryBuilderLoaderTest.php index b9a9d6558a49d..67f600f5d145e 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/ORMQueryBuilderLoaderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/ORMQueryBuilderLoaderTest.php @@ -13,14 +13,19 @@ use Doctrine\DBAL\ArrayParameterType; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\Result; use Doctrine\DBAL\Types\GuidType; use Doctrine\DBAL\Types\Type; use Doctrine\ORM\AbstractQuery; -use Doctrine\ORM\Version; +use Doctrine\ORM\Query; +use Doctrine\ORM\QueryBuilder; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader; use Symfony\Bridge\Doctrine\Tests\DoctrineTestHelper; +use Symfony\Bridge\Doctrine\Tests\Fixtures\EmbeddedIdentifierEntity; +use Symfony\Bridge\Doctrine\Tests\Fixtures\LegacyQueryMock; +use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity; +use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringIdEntity; use Symfony\Bridge\Doctrine\Types\UlidType; use Symfony\Bridge\Doctrine\Types\UuidType; use Symfony\Component\Form\Exception\TransformationFailedException; @@ -37,21 +42,19 @@ protected function tearDown(): void public function testIdentifierTypeIsStringArray() { - $this->checkIdentifierType('Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringIdEntity', class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY); + $this->checkIdentifierType(SingleStringIdEntity::class, class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY); } public function testIdentifierTypeIsIntegerArray() { - $this->checkIdentifierType('Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity', class_exists(ArrayParameterType::class) ? ArrayParameterType::INTEGER : Connection::PARAM_INT_ARRAY); + $this->checkIdentifierType(SingleIntIdEntity::class, class_exists(ArrayParameterType::class) ? ArrayParameterType::INTEGER : Connection::PARAM_INT_ARRAY); } - protected function checkIdentifierType($classname, $expectedType) + protected function checkIdentifierType(string $classname, $expectedType) { $em = DoctrineTestHelper::createTestEntityManager(); - $query = $this->getMockBuilder(QueryMock::class) - ->onlyMethods(['setParameter', 'getResult', 'getSql', '_doExecute']) - ->getMock(); + $query = $this->getQueryMock(); $query ->method('getResult') @@ -62,7 +65,7 @@ protected function checkIdentifierType($classname, $expectedType) ->with('ORMQueryBuilderLoader_getEntitiesByIds_id', [1, 2], $expectedType) ->willReturn($query); - $qb = $this->getMockBuilder(\Doctrine\ORM\QueryBuilder::class) + $qb = $this->getMockBuilder(QueryBuilder::class) ->setConstructorArgs([$em]) ->onlyMethods(['getQuery']) ->getMock(); @@ -82,9 +85,7 @@ public function testFilterNonIntegerValues() { $em = DoctrineTestHelper::createTestEntityManager(); - $query = $this->getMockBuilder(QueryMock::class) - ->onlyMethods(['setParameter', 'getResult', 'getSql', '_doExecute']) - ->getMock(); + $query = $this->getQueryMock(); $query ->method('getResult') @@ -95,7 +96,7 @@ public function testFilterNonIntegerValues() ->with('ORMQueryBuilderLoader_getEntitiesByIds_id', [1, 2, 3, '9223372036854775808'], class_exists(ArrayParameterType::class) ? ArrayParameterType::INTEGER : Connection::PARAM_INT_ARRAY) ->willReturn($query); - $qb = $this->getMockBuilder(\Doctrine\ORM\QueryBuilder::class) + $qb = $this->getMockBuilder(QueryBuilder::class) ->setConstructorArgs([$em]) ->onlyMethods(['getQuery']) ->getMock(); @@ -118,9 +119,7 @@ public function testFilterEmptyUuids($entityClass) { $em = DoctrineTestHelper::createTestEntityManager(); - $query = $this->getMockBuilder(QueryMock::class) - ->onlyMethods(['setParameter', 'getResult', 'getSql', '_doExecute']) - ->getMock(); + $query = $this->getQueryMock(); $query ->method('getResult') @@ -131,7 +130,7 @@ public function testFilterEmptyUuids($entityClass) ->with('ORMQueryBuilderLoader_getEntitiesByIds_id', ['71c5fd46-3f16-4abb-bad7-90ac1e654a2d', 'b98e8e11-2897-44df-ad24-d2627eb7f499'], class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY) ->willReturn($query); - $qb = $this->getMockBuilder(\Doctrine\ORM\QueryBuilder::class) + $qb = $this->getMockBuilder(QueryBuilder::class) ->setConstructorArgs([$em]) ->onlyMethods(['getQuery']) ->getMock(); @@ -163,9 +162,7 @@ public function testFilterUid($entityClass) $em = DoctrineTestHelper::createTestEntityManager(); - $query = $this->getMockBuilder(QueryMock::class) - ->onlyMethods(['setParameter', 'getResult', 'getSql', '_doExecute']) - ->getMock(); + $query = $this->getQueryMock(); $query ->method('getResult') @@ -176,7 +173,7 @@ public function testFilterUid($entityClass) ->with('ORMQueryBuilderLoader_getEntitiesByIds_id', [Uuid::fromString('71c5fd46-3f16-4abb-bad7-90ac1e654a2d')->toBinary(), Uuid::fromString('b98e8e11-2897-44df-ad24-d2627eb7f499')->toBinary()], class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY) ->willReturn($query); - $qb = $this->getMockBuilder(\Doctrine\ORM\QueryBuilder::class) + $qb = $this->getMockBuilder(QueryBuilder::class) ->setConstructorArgs([$em]) ->onlyMethods(['getQuery']) ->getMock(); @@ -208,7 +205,7 @@ public function testUidThrowProperException($entityClass) $em = DoctrineTestHelper::createTestEntityManager(); - $qb = $this->getMockBuilder(\Doctrine\ORM\QueryBuilder::class) + $qb = $this->getMockBuilder(QueryBuilder::class) ->setConstructorArgs([$em]) ->onlyMethods(['getQuery']) ->getMock(); @@ -229,17 +226,9 @@ public function testUidThrowProperException($entityClass) public function testEmbeddedIdentifierName() { - if (Version::compare('2.5.0') > 0) { - $this->markTestSkipped('Applicable only for Doctrine >= 2.5.0'); - - return; - } - $em = DoctrineTestHelper::createTestEntityManager(); - $query = $this->getMockBuilder(QueryMock::class) - ->onlyMethods(['setParameter', 'getResult', 'getSql', '_doExecute']) - ->getMock(); + $query = $this->getQueryMock(); $query ->method('getResult') @@ -250,7 +239,7 @@ public function testEmbeddedIdentifierName() ->with('ORMQueryBuilderLoader_getEntitiesByIds_id_value', [1, 2, 3], class_exists(ArrayParameterType::class) ? ArrayParameterType::INTEGER : Connection::PARAM_INT_ARRAY) ->willReturn($query); - $qb = $this->getMockBuilder(\Doctrine\ORM\QueryBuilder::class) + $qb = $this->getMockBuilder(QueryBuilder::class) ->setConstructorArgs([$em]) ->onlyMethods(['getQuery']) ->getMock(); @@ -259,13 +248,13 @@ public function testEmbeddedIdentifierName() ->willReturn($query); $qb->select('e') - ->from('Symfony\Bridge\Doctrine\Tests\Fixtures\EmbeddedIdentifierEntity', 'e'); + ->from(EmbeddedIdentifierEntity::class, 'e'); $loader = new ORMQueryBuilderLoader($qb); $loader->getEntitiesByIds('id.value', [1, '', 2, 3, 'foo']); } - public static function provideGuidEntityClasses() + public static function provideGuidEntityClasses(): array { return [ ['Symfony\Bridge\Doctrine\Tests\Fixtures\GuidIdEntity'], @@ -273,32 +262,21 @@ public static function provideGuidEntityClasses() ]; } - public static function provideUidEntityClasses() + public static function provideUidEntityClasses(): array { return [ ['Symfony\Bridge\Doctrine\Tests\Fixtures\UuidIdEntity'], ['Symfony\Bridge\Doctrine\Tests\Fixtures\UlidIdEntity'], ]; } -} - -class QueryMock extends AbstractQuery -{ - public function __construct() - { - } /** - * @return array|string + * @return (LegacyQueryMock&MockObject)|(Query&MockObject) */ - public function getSQL() + private function getQueryMock(): AbstractQuery { - } + $class = ((new \ReflectionClass(Query::class))->isFinal()) ? LegacyQueryMock::class : Query::class; - /** - * @return Result|int - */ - protected function _doExecute() - { + return $this->createMock($class); } } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php index f211f291f873a..930ee9994879e 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php @@ -13,6 +13,8 @@ use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\Mapping\JoinColumnMapping; +use Doctrine\ORM\Mapping\ManyToOneAssociationMapping; use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ObjectManager; use PHPUnit\Framework\TestCase; @@ -69,33 +71,49 @@ public function testRequiredGuesserSimpleFieldNullable() public function testRequiredGuesserOneToOneNullable() { - $classMetadata = $this->createMock(ClassMetadata::class); - $classMetadata->expects($this->once())->method('isAssociationWithSingleJoinColumn')->with('field')->willReturn(true); + $classMetadata = new ClassMetadata('Acme\Entity\Foo'); - $mapping = ['joinColumns' => [[]]]; - $classMetadata->expects($this->once())->method('getAssociationMapping')->with('field')->willReturn($mapping); + if (class_exists(ManyToOneAssociationMapping::class)) { + $associationMapping = new ManyToOneAssociationMapping('field', 'Acme\Entity\Foo', 'Acme\Entity\Bar'); + $associationMapping->joinColumns[] = new JoinColumnMapping('field', 'field'); + } else { + $associationMapping = ['joinColumns' => [[]]]; + } + $classMetadata->associationMappings['field'] = $associationMapping; $this->assertEquals(new ValueGuess(false, Guess::HIGH_CONFIDENCE), $this->getGuesser($classMetadata)->guessRequired('TestEntity', 'field')); } public function testRequiredGuesserOneToOneExplicitNullable() { - $classMetadata = $this->createMock(ClassMetadata::class); - $classMetadata->expects($this->once())->method('isAssociationWithSingleJoinColumn')->with('field')->willReturn(true); - - $mapping = ['joinColumns' => [['nullable' => true]]]; - $classMetadata->expects($this->once())->method('getAssociationMapping')->with('field')->willReturn($mapping); + $classMetadata = new ClassMetadata('Acme\Entity\Foo'); + + if (class_exists(ManyToOneAssociationMapping::class)) { + $associationMapping = new ManyToOneAssociationMapping('field', 'Acme\Entity\Foo', 'Acme\Entity\Bar'); + $joinColumnMapping = new JoinColumnMapping('field', 'field'); + $joinColumnMapping->nullable = true; + $associationMapping->joinColumns[] = $joinColumnMapping; + } else { + $associationMapping = ['joinColumns' => [['nullable' => true]]]; + } + $classMetadata->associationMappings['field'] = $associationMapping; $this->assertEquals(new ValueGuess(false, Guess::HIGH_CONFIDENCE), $this->getGuesser($classMetadata)->guessRequired('TestEntity', 'field')); } public function testRequiredGuesserOneToOneNotNullable() { - $classMetadata = $this->createMock(ClassMetadata::class); - $classMetadata->expects($this->once())->method('isAssociationWithSingleJoinColumn')->with('field')->willReturn(true); - - $mapping = ['joinColumns' => [['nullable' => false]]]; - $classMetadata->expects($this->once())->method('getAssociationMapping')->with('field')->willReturn($mapping); + $classMetadata = new ClassMetadata('Acme\Entity\Foo'); + + if (class_exists(ManyToOneAssociationMapping::class)) { + $associationMapping = new ManyToOneAssociationMapping('field', 'Acme\Entity\Foo', 'Acme\Entity\Bar'); + $joinColumnMapping = new JoinColumnMapping('field', 'field'); + $joinColumnMapping->nullable = false; + $associationMapping->joinColumns[] = $joinColumnMapping; + } else { + $associationMapping = ['joinColumns' => [['nullable' => false]]]; + } + $classMetadata->associationMappings['field'] = $associationMapping; $this->assertEquals(new ValueGuess(true, Guess::HIGH_CONFIDENCE), $this->getGuesser($classMetadata)->guessRequired('TestEntity', 'field')); } diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php index 40884d2c572c6..e4e67eb663557 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php @@ -26,9 +26,11 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor; use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineDummy; +use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineEmbeddable; use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineEnum; use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineGeneratedValue; use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation; +use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineWithEmbedded; use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\EnumInt; use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\EnumString; use Symfony\Component\PropertyInfo\Type; @@ -38,7 +40,7 @@ */ class DoctrineExtractorTest extends TestCase { - private function createExtractor() + private function createExtractor(): DoctrineExtractor { $config = class_exists(ORMSetup::class) ? ORMSetup::createConfiguration(true) @@ -109,10 +111,6 @@ public function testGetProperties() public function testTestGetPropertiesWithEmbedded() { - if (!class_exists(\Doctrine\ORM\Mapping\Embedded::class)) { - $this->markTestSkipped('@Embedded is not available in Doctrine ORM lower than 2.5.'); - } - $this->assertEquals( [ 'id', @@ -125,25 +123,21 @@ public function testTestGetPropertiesWithEmbedded() /** * @dataProvider typesProvider */ - public function testExtract($property, array $type = null) + public function testExtract(string $property, array $type = null) { $this->assertEquals($type, $this->createExtractor()->getTypes(DoctrineDummy::class, $property, [])); } public function testExtractWithEmbedded() { - if (!class_exists(\Doctrine\ORM\Mapping\Embedded::class)) { - $this->markTestSkipped('@Embedded is not available in Doctrine ORM lower than 2.5.'); - } - $expectedTypes = [new Type( Type::BUILTIN_TYPE_OBJECT, false, - 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineEmbeddable' + DoctrineEmbeddable::class )]; $actualTypes = $this->createExtractor()->getTypes( - 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineWithEmbedded', + DoctrineWithEmbedded::class, 'embedded', [] ); @@ -166,9 +160,9 @@ public function testExtractEnum() $this->assertNull($this->createExtractor()->getTypes(DoctrineEnum::class, 'enumCustom', [])); } - public static function typesProvider() + public static function typesProvider(): array { - $provider = [ + return [ ['id', [new Type(Type::BUILTIN_TYPE_INT)]], ['guid', [new Type(Type::BUILTIN_TYPE_STRING)]], ['bigint', [new Type(Type::BUILTIN_TYPE_STRING)]], @@ -251,8 +245,6 @@ public static function typesProvider() )]], ['json', null], ]; - - return $provider; } public function testGetPropertiesCatchException() diff --git a/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php index eb7b00d561173..f3a78dfe9226b 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Doctrine\Tests\Security\User; use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Tools\SchemaTool; use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ObjectManager; @@ -251,12 +252,12 @@ private function createSchema($em) } } -abstract class UserLoaderRepository implements ObjectRepository, UserLoaderInterface +abstract class UserLoaderRepository extends EntityRepository implements UserLoaderInterface { abstract public function loadUserByIdentifier(string $identifier): ?UserInterface; } -abstract class PasswordUpgraderRepository implements ObjectRepository, PasswordUpgraderInterface +abstract class PasswordUpgraderRepository extends EntityRepository implements PasswordUpgraderInterface { abstract public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void; } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php index b04e51eb781e4..66849208fd44b 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php @@ -14,6 +14,7 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\DBAL\Types\Type; use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadataInfo; use Doctrine\ORM\Tools\SchemaTool; use Doctrine\Persistence\ManagerRegistry; @@ -114,7 +115,9 @@ protected function createEntityManagerMock($repositoryMock) ->willReturn($repositoryMock) ; - $classMetadata = $this->createMock(ClassMetadataInfo::class); + $classMetadata = $this->createMock( + class_exists(ClassMetadataInfo::class) ? ClassMetadataInfo::class : ClassMetadata::class + ); $classMetadata ->expects($this->any()) ->method('hasField') diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php index 731f393c48b1d..9aa8d6ef61230 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Doctrine\Tests\Validator; use Doctrine\ORM\Mapping\Column; +use Doctrine\ORM\Mapping\Driver\AnnotationDriver; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Doctrine\Tests\DoctrineTestHelper; use Symfony\Bridge\Doctrine\Tests\Fixtures\BaseUser; @@ -47,9 +48,12 @@ protected function setUp(): void public function testLoadClassMetadata() { - $validator = Validation::createValidatorBuilder() - ->enableAnnotationMapping(true) - ->addDefaultDoctrineAnnotationReader() + $validatorBuilder = Validation::createValidatorBuilder()->enableAnnotationMapping(true); + if (class_exists(AnnotationDriver::class) && method_exists($validatorBuilder, 'addDefaultDoctrineAnnotationReader')) { + $validatorBuilder->addDefaultDoctrineAnnotationReader(); + } + + $validator = $validatorBuilder ->addLoader(new DoctrineLoader(DoctrineTestHelper::createTestEntityManager(), '{^Symfony\\\\Bridge\\\\Doctrine\\\\Tests\\\\Fixtures\\\\DoctrineLoader}')) ->getValidator() ; @@ -157,10 +161,15 @@ public function testExtractEnum() $this->markTestSkipped('The "enumType" requires doctrine/orm 2.11.'); } - $validator = Validation::createValidatorBuilder() + $validatorBuilder = Validation::createValidatorBuilder() ->addMethodMapping('loadValidatorMetadata') - ->enableAnnotationMapping(true) - ->addDefaultDoctrineAnnotationReader() + ->enableAnnotationMapping(true); + + if (class_exists(AnnotationDriver::class) && method_exists($validatorBuilder, 'addDefaultDoctrineAnnotationReader')) { + $validatorBuilder->addDefaultDoctrineAnnotationReader(); + } + + $validator = $validatorBuilder ->addLoader(new DoctrineLoader(DoctrineTestHelper::createTestEntityManager(), '{^Symfony\\\\Bridge\\\\Doctrine\\\\Tests\\\\Fixtures\\\\DoctrineLoader}')) ->getValidator() ; @@ -176,9 +185,13 @@ public function testExtractEnum() public function testFieldMappingsConfiguration() { - $validator = Validation::createValidatorBuilder() - ->enableAnnotationMapping(true) - ->addDefaultDoctrineAnnotationReader() + $validatorBuilder = Validation::createValidatorBuilder()->enableAnnotationMapping(true); + + if (class_exists(AnnotationDriver::class) && method_exists($validatorBuilder, 'addDefaultDoctrineAnnotationReader')) { + $validatorBuilder->addDefaultDoctrineAnnotationReader(); + } + + $validator = $validatorBuilder ->addXmlMappings([__DIR__.'/../Resources/validator/BaseUser.xml']) ->addLoader( new DoctrineLoader( @@ -206,7 +219,7 @@ public function testClassValidator(bool $expected, string $classValidatorRegexp $this->assertSame($expected, $doctrineLoader->loadClassMetadata($classMetadata)); } - public static function regexpProvider() + public static function regexpProvider(): array { return [ [false, null], @@ -218,9 +231,13 @@ public static function regexpProvider() public function testClassNoAutoMapping() { - $validator = Validation::createValidatorBuilder() - ->enableAnnotationMapping(true) - ->addDefaultDoctrineAnnotationReader() + $validatorBuilder = Validation::createValidatorBuilder()->enableAnnotationMapping(true); + + if (class_exists(AnnotationDriver::class) && method_exists($validatorBuilder, 'addDefaultDoctrineAnnotationReader')) { + $validatorBuilder->addDefaultDoctrineAnnotationReader(); + } + + $validator = $validatorBuilder ->addLoader(new DoctrineLoader(DoctrineTestHelper::createTestEntityManager(), '{.*}')) ->getValidator(); diff --git a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php index fe199c2043ff0..9fcb0d3486ada 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php +++ b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php @@ -12,7 +12,7 @@ namespace Symfony\Bridge\Doctrine\Validator; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\ClassMetadata as OrmClassMetadata; use Doctrine\ORM\Mapping\MappingException as OrmMappingException; use Doctrine\Persistence\Mapping\MappingException; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; @@ -54,7 +54,7 @@ public function loadClassMetadata(ClassMetadata $metadata): bool return false; } - if (!$doctrineMetadata instanceof ClassMetadataInfo) { + if (!$doctrineMetadata instanceof OrmClassMetadata) { return false; } diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json index dcb046fbc38e7..61d08a0b213d2 100644 --- a/src/Symfony/Bridge/Doctrine/composer.json +++ b/src/Symfony/Bridge/Doctrine/composer.json @@ -46,8 +46,8 @@ "doctrine/annotations": "^1.10.4|^2", "doctrine/collections": "^1.0|^2.0", "doctrine/data-fixtures": "^1.1", - "doctrine/dbal": "^2.13.1|^3.0", - "doctrine/orm": "^2.7.4", + "doctrine/dbal": "^2.13.1|^3|^4", + "doctrine/orm": "^2.7.4|^3", "psr/log": "^1|^2|^3" }, "conflict": { diff --git a/src/Symfony/Component/Cache/Tests/Fixtures/DriverWrapper.php b/src/Symfony/Component/Cache/Tests/Fixtures/DriverWrapper.php index bb73d8d0cf240..f0d97724a4e3f 100644 --- a/src/Symfony/Component/Cache/Tests/Fixtures/DriverWrapper.php +++ b/src/Symfony/Component/Cache/Tests/Fixtures/DriverWrapper.php @@ -15,6 +15,7 @@ use Doctrine\DBAL\Driver; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Schema\AbstractSchemaManager; +use Doctrine\DBAL\ServerVersionProvider; class DriverWrapper implements Driver { @@ -31,9 +32,9 @@ public function connect(array $params, $username = null, $password = null, array return $this->driver->connect($params, $username, $password, $driverOptions); } - public function getDatabasePlatform(): AbstractPlatform + public function getDatabasePlatform(ServerVersionProvider $versionProvider = null): AbstractPlatform { - return $this->driver->getDatabasePlatform(); + return $this->driver->getDatabasePlatform($versionProvider); } public function getSchemaManager(Connection $conn, AbstractPlatform $platform): AbstractSchemaManager diff --git a/src/Symfony/Component/Cache/composer.json b/src/Symfony/Component/Cache/composer.json index 91296b0477ba9..e3526bb8158b4 100644 --- a/src/Symfony/Component/Cache/composer.json +++ b/src/Symfony/Component/Cache/composer.json @@ -34,7 +34,7 @@ "require-dev": { "cache/integration-tests": "dev-master", "doctrine/cache": "^1.6|^2.0", - "doctrine/dbal": "^2.13.1|^3.0", + "doctrine/dbal": "^2.13.1|^3|^4", "predis/predis": "^1.1", "psr/simple-cache": "^1.0|^2.0", "symfony/config": "^4.4|^5.0|^6.0", diff --git a/src/Symfony/Component/Lock/Tests/Store/DoctrineDbalStoreTest.php b/src/Symfony/Component/Lock/Tests/Store/DoctrineDbalStoreTest.php index f8abec2522319..9f8c2aac6be3b 100644 --- a/src/Symfony/Component/Lock/Tests/Store/DoctrineDbalStoreTest.php +++ b/src/Symfony/Component/Lock/Tests/Store/DoctrineDbalStoreTest.php @@ -150,13 +150,22 @@ public function testCreatesTableInTransaction(string $platform) $store->save($key); } - public static function providePlatforms() + public static function providePlatforms(): \Generator { yield [\Doctrine\DBAL\Platforms\PostgreSQLPlatform::class]; - yield [\Doctrine\DBAL\Platforms\PostgreSQL94Platform::class]; + + // DBAL < 4 + if (class_exists(\Doctrine\DBAL\Platforms\PostgreSQL94Platform::class)) { + yield [\Doctrine\DBAL\Platforms\PostgreSQL94Platform::class]; + } + yield [\Doctrine\DBAL\Platforms\SqlitePlatform::class]; yield [\Doctrine\DBAL\Platforms\SQLServerPlatform::class]; - yield [\Doctrine\DBAL\Platforms\SQLServer2012Platform::class]; + + // DBAL < 4 + if (class_exists(\Doctrine\DBAL\Platforms\SQLServer2012Platform::class)) { + yield [\Doctrine\DBAL\Platforms\SQLServer2012Platform::class]; + } } public function testTableCreationInTransactionNotSupported() diff --git a/src/Symfony/Component/Lock/composer.json b/src/Symfony/Component/Lock/composer.json index c2b8e3078e756..b7e2d0c0d87ea 100644 --- a/src/Symfony/Component/Lock/composer.json +++ b/src/Symfony/Component/Lock/composer.json @@ -22,7 +22,7 @@ "symfony/polyfill-php80": "^1.16" }, "require-dev": { - "doctrine/dbal": "^2.13|^3.0", + "doctrine/dbal": "^2.13|^3|^4", "predis/predis": "~1.0" }, "conflict": { diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php index 5af44c4845849..d7c9a05c8502e 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php @@ -19,8 +19,10 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\MariaDBPlatform; use Doctrine\DBAL\Platforms\MySQL57Platform; +use Doctrine\DBAL\Platforms\MySQLPlatform; use Doctrine\DBAL\Platforms\OraclePlatform; use Doctrine\DBAL\Platforms\SQLServer2012Platform; +use Doctrine\DBAL\Platforms\SQLServerPlatform; use Doctrine\DBAL\Query\QueryBuilder; use Doctrine\DBAL\Result; use Doctrine\DBAL\Schema\AbstractSchemaManager; @@ -98,7 +100,7 @@ public function testItThrowsATransportExceptionIfItCannotAcknowledgeMessage() { $this->expectException(TransportException::class); $driverConnection = $this->getDBALConnectionMock(); - $driverConnection->method('delete')->willThrowException(new DBALException()); + $driverConnection->method('delete')->willThrowException($this->createStub(DBALException::class)); $connection = new Connection([], $driverConnection); $connection->ack('dummy_id'); @@ -108,7 +110,7 @@ public function testItThrowsATransportExceptionIfItCannotRejectMessage() { $this->expectException(TransportException::class); $driverConnection = $this->getDBALConnectionMock(); - $driverConnection->method('delete')->willThrowException(new DBALException()); + $driverConnection->method('delete')->willThrowException($this->createStub(DBALException::class)); $connection = new Connection([], $driverConnection); $connection->reject('dummy_id'); @@ -391,7 +393,7 @@ public function testGeneratedSql(AbstractPlatform $platform, string $expectedSql public static function providePlatformSql(): iterable { yield 'MySQL' => [ - new MySQL57Platform(), + class_exists(MySQLPlatform::class) ? new MySQLPlatform() : new MySQL57Platform(), 'SELECT m.* FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?) ORDER BY available_at ASC LIMIT 1 FOR UPDATE', ]; @@ -403,14 +405,23 @@ public static function providePlatformSql(): iterable } yield 'SQL Server' => [ - new SQLServer2012Platform(), + class_exists(SQLServerPlatform::class) && !class_exists(SQLServer2012Platform::class) ? new SQLServerPlatform() : new SQLServer2012Platform(), 'SELECT m.* FROM messenger_messages m WITH (UPDLOCK, ROWLOCK) WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?) ORDER BY available_at ASC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY ', ]; - yield 'Oracle' => [ - new OraclePlatform(), - 'SELECT w.id AS "id", w.body AS "body", w.headers AS "headers", w.queue_name AS "queue_name", w.created_at AS "created_at", w.available_at AS "available_at", w.delivered_at AS "delivered_at" FROM messenger_messages w WHERE w.id IN (SELECT a.id FROM (SELECT m.id FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?) ORDER BY available_at ASC) a WHERE ROWNUM <= 1) FOR UPDATE', - ]; + if (!class_exists(MySQL57Platform::class)) { + // DBAL >= 4 + yield 'Oracle' => [ + new OraclePlatform(), + 'SELECT w.id AS "id", w.body AS "body", w.headers AS "headers", w.queue_name AS "queue_name", w.created_at AS "created_at", w.available_at AS "available_at", w.delivered_at AS "delivered_at" FROM messenger_messages w WHERE w.id IN (SELECT m.id FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?) ORDER BY available_at ASC FETCH NEXT 1 ROWS ONLY) FOR UPDATE', + ]; + } else { + // DBAL < 4 + yield 'Oracle' => [ + new OraclePlatform(), + 'SELECT w.id AS "id", w.body AS "body", w.headers AS "headers", w.queue_name AS "queue_name", w.created_at AS "created_at", w.available_at AS "available_at", w.delivered_at AS "delivered_at" FROM messenger_messages w WHERE w.id IN (SELECT a.id FROM (SELECT m.id FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?) ORDER BY available_at ASC) a WHERE ROWNUM <= 1) FOR UPDATE', + ]; + } } public function testConfigureSchema() @@ -483,7 +494,7 @@ public function testFindAllSqlGenerated(AbstractPlatform $platform, string $expe public function provideFindAllSqlGeneratedByPlatform(): iterable { yield 'MySQL' => [ - new MySQL57Platform(), + class_exists(MySQLPlatform::class) ? new MySQLPlatform() : new MySQL57Platform(), 'SELECT m.* FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?) LIMIT 50', ]; @@ -495,13 +506,22 @@ public function provideFindAllSqlGeneratedByPlatform(): iterable } yield 'SQL Server' => [ - new SQLServer2012Platform(), + class_exists(SQLServerPlatform::class) && !class_exists(SQLServer2012Platform::class) ? new SQLServerPlatform() : new SQLServer2012Platform(), 'SELECT m.* FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?) ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 50 ROWS ONLY', ]; - yield 'Oracle' => [ - new OraclePlatform(), - 'SELECT a.* FROM (SELECT m.id AS "id", m.body AS "body", m.headers AS "headers", m.queue_name AS "queue_name", m.created_at AS "created_at", m.available_at AS "available_at", m.delivered_at AS "delivered_at" FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?)) a WHERE ROWNUM <= 50', - ]; + if (!class_exists(MySQL57Platform::class)) { + // DBAL >= 4 + yield 'Oracle' => [ + new OraclePlatform(), + 'SELECT m.id AS "id", m.body AS "body", m.headers AS "headers", m.queue_name AS "queue_name", m.created_at AS "created_at", m.available_at AS "available_at", m.delivered_at AS "delivered_at" FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?) FETCH NEXT 50 ROWS ONLY', + ]; + } else { + // DBAL < 4 + yield 'Oracle' => [ + new OraclePlatform(), + 'SELECT a.* FROM (SELECT m.id AS "id", m.body AS "body", m.headers AS "headers", m.queue_name AS "queue_name", m.created_at AS "created_at", m.available_at AS "available_at", m.delivered_at AS "delivered_at" FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?)) a WHERE ROWNUM <= 50', + ]; + } } } diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineTransportFactoryTest.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineTransportFactoryTest.php index 54dd7ab153adf..6e108baa449be 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineTransportFactoryTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineTransportFactoryTest.php @@ -46,7 +46,11 @@ public function testCreateTransport() $schemaConfig = $this->createMock(SchemaConfig::class); $platform = $this->createMock(AbstractPlatform::class); $schemaManager->method('createSchemaConfig')->willReturn($schemaConfig); - $driverConnection->method('getSchemaManager')->willReturn($schemaManager); + $driverConnection->method( + method_exists(\Doctrine\DBAL\Connection::class, 'createSchemaManager') + ? 'createSchemaManager' + : 'getSchemaManager' + )->willReturn($schemaManager); $driverConnection->method('getDatabasePlatform')->willReturn($platform); $registry = $this->createMock(ConnectionRegistry::class); @@ -70,7 +74,11 @@ public function testCreateTransportNotifyWithPostgreSQLPlatform() $schemaConfig = $this->createMock(SchemaConfig::class); $platform = $this->createMock(PostgreSQLPlatform::class); $schemaManager->method('createSchemaConfig')->willReturn($schemaConfig); - $driverConnection->method('getSchemaManager')->willReturn($schemaManager); + $driverConnection->method( + method_exists(\Doctrine\DBAL\Connection::class, 'createSchemaManager') + ? 'createSchemaManager' + : 'getSchemaManager' + )->willReturn($schemaManager); $driverConnection->method('getDatabasePlatform')->willReturn($platform); $registry = $this->createMock(ConnectionRegistry::class); diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php index 6bb601c2eef29..fe1b7a2f4ef91 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php @@ -177,11 +177,8 @@ public function get(): ?array // Append pessimistic write lock to FROM clause if db platform supports it $sql = $query->getSQL(); - if (($fromPart = $query->getQueryPart('from')) && - ($table = $fromPart[0]['table'] ?? null) && - ($alias = $fromPart[0]['alias'] ?? null) - ) { - $fromClause = sprintf('%s %s', $table, $alias); + if (preg_match('/FROM (.+) WHERE/', (string) $sql, $matches)) { + $fromClause = $matches[1]; $sql = str_replace( sprintf('FROM %s WHERE', $fromClause), sprintf('FROM %s WHERE', $this->driverConnection->getDatabasePlatform()->appendLockHint($fromClause, LockMode::PESSIMISTIC_WRITE)), diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/composer.json b/src/Symfony/Component/Messenger/Bridge/Doctrine/composer.json index 3a9494a6a24cb..e1490a7f98e2e 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/composer.json +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/composer.json @@ -21,7 +21,7 @@ "symfony/service-contracts": "^1.1|^2|^3" }, "require-dev": { - "doctrine/dbal": "^2.13|^3.0", + "doctrine/dbal": "^2.13|^3|^4", "doctrine/persistence": "^1.3|^2|^3", "symfony/property-access": "^4.4|^5.0|^6.0", "symfony/serializer": "^4.4|^5.0|^6.0" From e05c25256eaf65f6996728c28b7f28ae067d7370 Mon Sep 17 00:00:00 2001 From: JoppeDC Date: Wed, 11 Oct 2023 13:43:35 +0200 Subject: [PATCH 30/79] Add missing dutch translations --- .../Resources/translations/validators.nl.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf index 97d1da00e9a50..45cefb3bbd59f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. De waarde van de netmask moet zich tussen {{ min }} en {{ max }} bevinden. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + De bestandsnaam is te lang. Het moet {{ filename_max_length }} karakter of minder zijn. + + + The password strength is too low. Please use a stronger password. + De wachtwoordsterkte is te laag. Gebruik alstublieft een sterker wachtwoord. + + + This value contains characters that are not allowed by the current restriction-level. + Deze waarde bevat tekens die niet zijn toegestaan volgens het huidige beperkingsniveau. + + + Using invisible characters is not allowed. + Het gebruik van onzichtbare tekens is niet toegestaan. + + + Mixing numbers from different scripts is not allowed. + Het mengen van cijfers uit verschillende schriften is niet toegestaan. + + + Using hidden overlay characters is not allowed. + Het gebruik van verborgen overlay-tekens is niet toegestaan. + From 1ed99d11f98cb0e3c2a0816622dca226c60ac181 Mon Sep 17 00:00:00 2001 From: Jessica F Martinez Date: Wed, 11 Oct 2023 13:40:17 +0200 Subject: [PATCH 31/79] [Validator] Add missing Spanish (es) translations #51956 --- .../Resources/translations/validators.es.xlf | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf index 897d0a45d74fd..55f21271f1bc9 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf @@ -40,7 +40,7 @@ This field is missing. - Este campo está desaparecido. + Este campo falta. This value is not a valid date. @@ -48,7 +48,7 @@ This value is not a valid datetime. - Este valor no es una fecha y hora válidas. + Este valor no es una fecha y hora válida. This value is not a valid email address. @@ -184,11 +184,11 @@ The file was only partially uploaded. - El archivo fue sólo subido parcialmente. + El archivo se cargó solo parcialmente. No file was uploaded. - Ningún archivo fue subido. + No se subió ningún archivo. No temporary folder was configured in php.ini. @@ -200,7 +200,7 @@ A PHP extension caused the upload to fail. - Una extensión de PHP hizo que la subida fallara. + Una extensión de PHP provocó que la carga fallara. This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. @@ -300,7 +300,7 @@ An empty file is not allowed. - No está permitido un archivo vacío. + No se permite un archivo vacío. The host could not be resolved. @@ -360,7 +360,7 @@ This password has been leaked in a data breach, it must not be used. Please use another password. - Esta contraseña no se puede utilizar porque está incluida en un listado de contraseñas públicas obtenido gracias a fallos de seguridad de otros sitios y aplicaciones. Por favor utilice otra contraseña. + Esta contraseña no se puede utilizar porque está incluida en un listado de contraseñas públicas obtenido gracias a fallos de seguridad de otros sitios y aplicaciones. Por favor, utilice otra contraseña. This value should be between {{ min }} and {{ max }}. @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. El valor de la máscara de red debería estar entre {{ min }} y {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + El nombre del archivo es demasido largo. Debe tener {{ filename_max_length }} carácter o menos.|El nombre del archivo es demasido largo. Debe tener {{ filename_max_length }} caracteres o menos. + + + The password strength is too low. Please use a stronger password. + La seguridad de la contraseña es demasiado baja. Por favor, utilice una contraseña más segura. + + + This value contains characters that are not allowed by the current restriction-level. + Este valor contiene caracteres que no están permitidos según el nivel de restricción actual. + + + Using invisible characters is not allowed. + No se permite el uso de caracteres invisibles. + + + Mixing numbers from different scripts is not allowed. + No está permitido mezclar números de diferentes scripts. + + + Using hidden overlay characters is not allowed. + No está permitido el uso de caracteres superpuestos ocultos. + From 42d70af349e92ced6aa26e165a4f077084bf95ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anamarija=20Papi=C4=87?= Date: Wed, 11 Oct 2023 21:09:11 +0200 Subject: [PATCH 32/79] Add missing Validator translations - Croatian (hr) --- .../Resources/translations/validators.hr.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf index 34384b401551f..0b57fc98ef56b 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Vrijednost mrežne maske trebala bi biti između {{ min }} i {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Naziv datoteke je predug. Treba imati {{ filename_max_length }} znak ili manje.|Naziv datoteke je predug. Treba imati {{ filename_max_length }} znaka ili manje.|Naziv datoteke je predug. Treba imati {{ filename_max_length }} znakova ili manje. + + + The password strength is too low. Please use a stronger password. + Jačina lozinke je preniska. Molim koristite jaču lozinku. + + + This value contains characters that are not allowed by the current restriction-level. + Ova vrijednost sadrži znakove koji nisu dopušteni prema trenutnoj razini ograničenja. + + + Using invisible characters is not allowed. + Korištenje nevidljivih znakova nije dopušteno. + + + Mixing numbers from different scripts is not allowed. + Miješanje brojeva iz različitih pisama nije dopušteno. + + + Using hidden overlay characters is not allowed. + Korištenje skrivenih preklapajućih znakova nije dopušteno. + From 7af728985ece80600083c9ed815f0206fd1ad3aa Mon Sep 17 00:00:00 2001 From: BiaDd <49127629+BiaDd@users.noreply.github.com> Date: Wed, 11 Oct 2023 21:25:23 -0400 Subject: [PATCH 33/79] [Validator] Add missing translations for Vietnamese (VI) Update validators.vi.xlf --- .../Resources/translations/validators.vi.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf index 00201792253ab..4de9de6fb8c81 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Giá trị của mặt nạ mạng phải nằm trong khoảng từ {{ min }} đến {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Tên tệp quá dài. Phải bằng {{ filename_max_length }} ký tự hoặc ít hơn.|Tên tệp quá dài. Phải bằng {{ filename_max_length }} ký tự hoặc ít hơn. + + + The password strength is too low. Please use a stronger password. + Sức mạnh mật khẩu quá thấp. Vui lòng sử dụng mật khẩu mạnh hơn. + + + This value contains characters that are not allowed by the current restriction-level. + Giá trị này chứa các ký tự không được phép bởi mức độ hạn chế hiện tại. + + + Using invisible characters is not allowed. + Sử dụng ký tự vô hình không được phép. + + + Mixing numbers from different scripts is not allowed. + Không được phép trộn các số từ các tập lệnh khác nhau. + + + Using hidden overlay characters is not allowed. + Sử dụng các ký tự lớp phủ ẩn không được phép. + From 7d4fb1cb06d40323a5b7c005bdff3b5f788a1b3f Mon Sep 17 00:00:00 2001 From: Asis Pattisahusiwa <79239132+asispts@users.noreply.github.com> Date: Thu, 12 Oct 2023 08:37:04 +0700 Subject: [PATCH 34/79] [Validator] Add missing translations for Indonesian (id) --- .../Resources/translations/validators.id.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf index 1687f330bc570..29960b3da34e5 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Nilai dari netmask harus berada diantara {{ min }} dan {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Nama file terlalu panjang. Harusnya {{ filename_max_length }} karakter atau kurang. + + + The password strength is too low. Please use a stronger password. + Kata sandi terlalu lemah. Harap gunakan kata sandi yang lebih kuat. + + + This value contains characters that are not allowed by the current restriction-level. + Nilai ini mengandung karakter yang tidak diizinkan oleh tingkat pembatasan saat ini. + + + Using invisible characters is not allowed. + Penggunaan karakter tak terlihat tidak diperbolehkan. + + + Mixing numbers from different scripts is not allowed. + Menggabungkan angka-angka dari skrip yang berbeda tidak diperbolehkan. + + + Using hidden overlay characters is not allowed. + Penggunaan karakter overlay yang tersembunyi tidak diperbolehkan. + From 9ec85bb68f8e705a887f4535b62b3d10b65eebdc Mon Sep 17 00:00:00 2001 From: Viktoriia Zolotova Date: Wed, 11 Oct 2023 19:05:47 -0700 Subject: [PATCH 35/79] [Validator] Add missing Ukrainian translations #51960 --- .../Resources/translations/validators.uk.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf index c11f851fb0267..d12b4db8c9459 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Значення в мережевій масці має бути між {{ min }} та {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Назва файлу занадто довга. Вона має містити {{ filename_max_length }} символів або менше.|Назва файлу занадто довга. Вона має містити {{ filename_max_length }} символів або менше. + + + The password strength is too low. Please use a stronger password. + Надійність пароля занадто низька. Будь ласка, створіть складніший пароль. + + + This value contains characters that are not allowed by the current restriction-level. + Це значення містить символи, які не дозволяються поточним рівнем обмежень. + + + Using invisible characters is not allowed. + Використання невидимих ​​символів не допускається. + + + Mixing numbers from different scripts is not allowed. + Змішувати числа з різних скриптів не допускається. + + + Using hidden overlay characters is not allowed. + Використання прихованих накладених символів не допускається. + From 315a8a462cb057287c13e69b25596477eb7e4582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Thu, 12 Oct 2023 10:12:39 +0200 Subject: [PATCH 36/79] Revert "Add keyword `dev` to leverage composer hint" This reverts commit 49f7f5e71911b3d6540f744cf4475f571cf012a6. --- src/Symfony/Bridge/PhpUnit/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/composer.json b/src/Symfony/Bridge/PhpUnit/composer.json index 167ed8767b35b..9627d2b40c12c 100644 --- a/src/Symfony/Bridge/PhpUnit/composer.json +++ b/src/Symfony/Bridge/PhpUnit/composer.json @@ -2,7 +2,7 @@ "name": "symfony/phpunit-bridge", "type": "symfony-bridge", "description": "Provides utilities for PHPUnit, especially user deprecation notices management", - "keywords": ["dev"], + "keywords": [], "homepage": "https://symfony.com", "license": "MIT", "authors": [ From 8e877cc13a51f1eb5aa27965944e6b69cfdcfd67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20Rumi=C5=84ski?= Date: Thu, 12 Oct 2023 14:37:23 +0200 Subject: [PATCH 37/79] DX: PHP CS Fixer - drop explicit no_superfluous_phpdoc_tags config, as it's part of ruleset already --- .php-cs-fixer.dist.php | 1 - 1 file changed, 1 deletion(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 7245326249db2..efb790e4eb26b 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -31,7 +31,6 @@ 'protected_to_private' => false, 'native_constant_invocation' => ['strict' => false], 'nullable_type_declaration_for_default_null_value' => ['use_nullable_type_declaration' => false], - 'no_superfluous_phpdoc_tags' => ['remove_inheritdoc' => true], 'header_comment' => ['header' => $fileHeaderComment], 'modernize_strpos' => true, 'get_class_to_class_keyword' => true, From 929390669e360a25fe176088d5477d993fdab350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20Rumi=C5=84ski?= Date: Thu, 12 Oct 2023 14:38:41 +0200 Subject: [PATCH 38/79] DX: PHP CS Fixer - drop explicit nullable_type_declaration_for_default_null_value config, as it's part of ruleset anyway --- .php-cs-fixer.dist.php | 1 - 1 file changed, 1 deletion(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 311ef1270f734..8333789ec831b 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -30,7 +30,6 @@ '@Symfony:risky' => true, 'protected_to_private' => false, 'native_constant_invocation' => ['strict' => false], - 'nullable_type_declaration_for_default_null_value' => ['use_nullable_type_declaration' => false], 'header_comment' => ['header' => $fileHeaderComment], ]) ->setRiskyAllowed(true) From b7d25e85cf4758e9daf16fd020f43e46db879463 Mon Sep 17 00:00:00 2001 From: Mathieu Lechat Date: Thu, 12 Oct 2023 10:00:56 +0200 Subject: [PATCH 39/79] [FrameworkBundle] Configure `logger` as error logger if the Monolog Bundle is not registered --- .../Compiler/ErrorLoggerCompilerPass.php | 37 +++++++++++++++++++ .../FrameworkBundle/FrameworkBundle.php | 3 ++ .../Resources/config/debug_prod.php | 4 +- .../FrameworkExtensionTestCase.php | 6 +-- 4 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php new file mode 100644 index 0000000000000..9ce67bc10cc65 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php @@ -0,0 +1,37 @@ + + * + * 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; +use Symfony\Component\DependencyInjection\Reference; + +/** + * @internal + */ +class ErrorLoggerCompilerPass implements CompilerPassInterface +{ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition('debug.debug_handlers_listener')) { + return; + } + + $definition = $container->getDefinition('debug.debug_handlers_listener'); + if ($container->hasDefinition('monolog.logger.php')) { + $definition->replaceArgument(1, new Reference('monolog.logger.php')); + } + if ($container->hasDefinition('monolog.logger.deprecation')) { + $definition->replaceArgument(6, new Reference('monolog.logger.deprecation')); + } + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 4ec54eccf555d..2197610896eb5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -17,6 +17,7 @@ use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AssetsContextPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ContainerBuilderDebugDumpPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\DataCollectorTranslatorPass; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ErrorLoggerCompilerPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\LoggingTranslatorPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ProfilerPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RemoveUnusedSessionMarshallingHandlerPass; @@ -160,6 +161,8 @@ public function build(ContainerBuilder $container) $container->addCompilerPass(new RegisterReverseContainerPass(false), PassConfig::TYPE_AFTER_REMOVING); $container->addCompilerPass(new RemoveUnusedSessionMarshallingHandlerPass()); $container->addCompilerPass(new SessionPass()); + // must be registered after MonologBundle's LoggerChannelPass + $container->addCompilerPass(new ErrorLoggerCompilerPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -32); if ($container->getParameter('kernel.debug')) { $container->addCompilerPass(new AddDebugLogProcessorPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 2); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug_prod.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug_prod.php index f381b018f0629..f3a16eb25f663 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug_prod.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug_prod.php @@ -21,12 +21,12 @@ ->set('debug.debug_handlers_listener', DebugHandlersListener::class) ->args([ null, // Exception handler - service('monolog.logger.php')->nullOnInvalid(), + service('logger')->nullOnInvalid(), null, // Log levels map for enabled error levels param('debug.error_handler.throw_at'), param('kernel.debug'), param('kernel.debug'), - service('monolog.logger.deprecation')->nullOnInvalid(), + service('logger')->nullOnInvalid(), ]) ->tag('kernel.event_subscriber') ->tag('monolog.logger', ['channel' => 'php']) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php index f5429d617b1a7..52a6ad6a4840f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php @@ -507,7 +507,7 @@ public function testEnabledPhpErrorsConfig() $container = $this->createContainerFromFile('php_errors_enabled'); $definition = $container->getDefinition('debug.debug_handlers_listener'); - $this->assertEquals(new Reference('monolog.logger.php', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1)); + $this->assertEquals(new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1)); $this->assertNull($definition->getArgument(2)); $this->assertSame(-1, $container->getParameter('debug.error_handler.throw_at')); } @@ -527,7 +527,7 @@ public function testPhpErrorsWithLogLevel() $container = $this->createContainerFromFile('php_errors_log_level'); $definition = $container->getDefinition('debug.debug_handlers_listener'); - $this->assertEquals(new Reference('monolog.logger.php', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1)); + $this->assertEquals(new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1)); $this->assertSame(8, $definition->getArgument(2)); } @@ -536,7 +536,7 @@ public function testPhpErrorsWithLogLevels() $container = $this->createContainerFromFile('php_errors_log_levels'); $definition = $container->getDefinition('debug.debug_handlers_listener'); - $this->assertEquals(new Reference('monolog.logger.php', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1)); + $this->assertEquals(new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1)); $this->assertSame([ \E_NOTICE => \Psr\Log\LogLevel::ERROR, \E_WARNING => \Psr\Log\LogLevel::ERROR, From eb394bb97871281c749ab92206d522366df80248 Mon Sep 17 00:00:00 2001 From: Romanavr Date: Thu, 12 Oct 2023 15:48:09 +0300 Subject: [PATCH 40/79] [Mailer] Capitalize sender header for Mailgun --- .../Tests/Transport/MailgunApiTransportTest.php | 6 +++--- .../Tests/Transport/MailgunHttpTransportTest.php | 12 ++---------- .../Bridge/Mailgun/Transport/MailgunApiTransport.php | 2 +- .../Mailgun/Transport/MailgunHttpTransport.php | 1 - 4 files changed, 6 insertions(+), 15 deletions(-) diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php index 808798ea88748..e60a153850711 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunApiTransportTest.php @@ -62,7 +62,7 @@ public function testCustomHeader() $email = new Email(); $envelope = new Envelope(new Address('alice@system.com'), [new Address('bob@system.com')]); - $email->getHeaders()->addTextHeader('h:sender', $envelope->getSender()->toString()); + $email->getHeaders()->addTextHeader('h:Sender', $envelope->getSender()->toString()); $email->getHeaders()->addTextHeader('h:X-Mailgun-Variables', $json); $email->getHeaders()->addTextHeader('h:foo', 'foo-value'); $email->getHeaders()->addTextHeader('t:text', 'text-value'); @@ -79,8 +79,8 @@ public function testCustomHeader() $this->assertArrayHasKey('h:X-Mailgun-Variables', $payload); $this->assertEquals($json, $payload['h:X-Mailgun-Variables']); - $this->assertArrayHasKey('h:sender', $payload); - $this->assertEquals($envelope->getSender()->toString(), $payload['h:sender']); + $this->assertArrayHasKey('h:Sender', $payload); + $this->assertEquals($envelope->getSender()->toString(), $payload['h:Sender']); $this->assertArrayHasKey('h:foo', $payload); $this->assertEquals('foo-value', $payload['h:foo']); $this->assertArrayHasKey('t:text', $payload); diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunHttpTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunHttpTransportTest.php index cc83f6f0db074..85342c23368d6 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunHttpTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Tests/Transport/MailgunHttpTransportTest.php @@ -69,8 +69,6 @@ public function testSend() $this->assertStringContainsString('Subject: Hello!', $content); $this->assertStringContainsString('To: Saif Eddin ', $content); $this->assertStringContainsString('From: Fabien ', $content); - $this->assertStringContainsString('Sender: Senior Fabien Eddin ', $content); - $this->assertStringContainsString('h:sender: "Senior Fabien Eddin" ', $content); $this->assertStringContainsString('Hello There!', $content); return new MockResponse(json_encode(['id' => 'foobar']), [ @@ -81,17 +79,11 @@ public function testSend() $transport->setPort(8984); $mail = new Email(); - $toAddress = new Address('saif.gmati@symfony.com', 'Saif Eddin'); - $fromAddress = new Address('fabpot@symfony.com', 'Fabien'); - $senderAddress = new Address('fabpot@symfony.com', 'Senior Fabien Eddin'); $mail->subject('Hello!') - ->to($toAddress) - ->from($fromAddress) - ->sender($senderAddress) + ->to(new Address('saif.gmati@symfony.com', 'Saif Eddin')) + ->from(new Address('fabpot@symfony.com', 'Fabien')) ->text('Hello There!'); - $mail->getHeaders()->addHeader('h:sender', $mail->getSender()->toString()); - $message = $transport->send($mail); $this->assertSame('foobar', $message->getMessageId()); diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php index 36fb59c8e6f67..7c927541c46d0 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunApiTransport.php @@ -87,7 +87,7 @@ protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $e private function getPayload(Email $email, Envelope $envelope): array { $headers = $email->getHeaders(); - $headers->addHeader('h:sender', $envelope->getSender()->toString()); + $headers->addHeader('h:Sender', $envelope->getSender()->toString()); $html = $email->getHtmlBody(); if (null !== $html && \is_resource($html)) { if (stream_get_meta_data($html)['seekable'] ?? false) { diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHttpTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHttpTransport.php index 1af78bfd1a39a..7dbbb8dce9dab 100644 --- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHttpTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHttpTransport.php @@ -53,7 +53,6 @@ public function __toString(): string protected function doSendHttp(SentMessage $message): ResponseInterface { $body = new FormDataPart([ - 'h:sender' => $message->getEnvelope()->getSender()->toString(), 'to' => implode(',', $this->stringifyAddresses($message->getEnvelope()->getRecipients())), 'message' => new DataPart($message->toString(), 'message.mime'), ]); From 66648c51f1a568d6e9cf596d0c8b87ce0372d5ee Mon Sep 17 00:00:00 2001 From: Jordane Vaspard Date: Tue, 10 Oct 2023 13:26:09 +0200 Subject: [PATCH 41/79] [HttpKernel] Handle nullable callback of StreamedResponse --- src/Symfony/Component/HttpFoundation/StreamedResponse.php | 6 +++++- src/Symfony/Component/HttpKernel/HttpKernel.php | 3 +-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/StreamedResponse.php b/src/Symfony/Component/HttpFoundation/StreamedResponse.php index 5c7817e3c9afd..37b6510b947d6 100644 --- a/src/Symfony/Component/HttpFoundation/StreamedResponse.php +++ b/src/Symfony/Component/HttpFoundation/StreamedResponse.php @@ -56,8 +56,12 @@ public function setCallback(callable $callback): static return $this; } - public function getCallback(): \Closure + public function getCallback(): ?\Closure { + if (!isset($this->callback)) { + return null; + } + return ($this->callback)(...); } diff --git a/src/Symfony/Component/HttpKernel/HttpKernel.php b/src/Symfony/Component/HttpKernel/HttpKernel.php index 4999870e4c55d..d2cf4eaee27ce 100644 --- a/src/Symfony/Component/HttpKernel/HttpKernel.php +++ b/src/Symfony/Component/HttpKernel/HttpKernel.php @@ -92,8 +92,7 @@ public function handle(Request $request, int $type = HttpKernelInterface::MAIN_R } finally { $this->requestStack->pop(); - if ($response instanceof StreamedResponse) { - $callback = $response->getCallback(); + if ($response instanceof StreamedResponse && $callback = $response->getCallback()) { $requestStack = $this->requestStack; $response->setCallback(static function () use ($request, $callback, $requestStack) { From 913a317706780c843a7d1d7ed78e2e81a0d4d9e1 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 12 Oct 2023 17:06:00 +0200 Subject: [PATCH 42/79] [DoctrineBridge] Fix cross-versions compat --- src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php index 3f4ba10fc2138..87a2222468db2 100644 --- a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php @@ -39,14 +39,15 @@ public function __construct( $this->query = new Query($sql); } - public function bindValue(int|string $param, mixed $value, ParameterType $type): void + public function bindValue($param, $value, $type = null): void { + $type ??= ParameterType::STRING; $this->query->setValue($param, $value, $type); parent::bindValue($param, $value, $type); } - public function execute(): ResultInterface + public function execute($params = null): ResultInterface { // clone to prevent variables by reference to change $this->debugDataHolder->addQuery($this->connectionName, $query = clone $this->query); @@ -55,7 +56,7 @@ public function execute(): ResultInterface $query->start(); try { - return parent::execute(); + return parent::execute($params); } finally { $query->stop(); $this->stopwatch?->stop('doctrine'); From e7d45da727dfb6afb604716104e6e68b11587021 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 12 Oct 2023 17:13:29 +0200 Subject: [PATCH 43/79] [FrameworkBundle] Add void return-type to ErrorLoggerCompilerPass --- .../DependencyInjection/Compiler/ErrorLoggerCompilerPass.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php index 9ce67bc10cc65..15ff70aa650e7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php @@ -20,7 +20,7 @@ */ class ErrorLoggerCompilerPass implements CompilerPassInterface { - public function process(ContainerBuilder $container) + public function process(ContainerBuilder $container): void { if (!$container->hasDefinition('debug.debug_handlers_listener')) { return; From 73b272aa595fe9b2a5cc8570b496497e5fdf7d8f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 12 Oct 2023 17:14:49 +0200 Subject: [PATCH 44/79] Sync .github/expected-missing-return-types.diff --- .github/expected-missing-return-types.diff | 119 ++++++++++++--------- 1 file changed, 68 insertions(+), 51 deletions(-) diff --git a/.github/expected-missing-return-types.diff b/.github/expected-missing-return-types.diff index a8d626bae0833..925a5c0dff016 100644 --- a/.github/expected-missing-return-types.diff +++ b/.github/expected-missing-return-types.diff @@ -242,6 +242,23 @@ diff --git a/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvid + public function createNewToken(PersistentTokenInterface $token): void { $sql = 'INSERT INTO rememberme_token (class, username, series, value, lastUsed) VALUES (:class, :username, :series, :value, :lastUsed)'; +diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/LegacyQueryMock.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/LegacyQueryMock.php +--- a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/LegacyQueryMock.php ++++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/LegacyQueryMock.php +@@ -24,5 +24,5 @@ class LegacyQueryMock extends AbstractQuery + * @return array|string + */ +- public function getSQL() ++ public function getSQL(): array|string + { + } +@@ -31,5 +31,5 @@ class LegacyQueryMock extends AbstractQuery + * @return Result|int + */ +- protected function _doExecute() ++ protected function _doExecute(): Result|int + { + } diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php --- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php +++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php @@ -636,7 +653,7 @@ diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExt + public function load(array $configs, ContainerBuilder $container): void { $loader = new PhpFileLoader($container, new FileLocator(\dirname(__DIR__).'/Resources/config')); -@@ -2903,5 +2903,5 @@ class FrameworkExtension extends Extension +@@ -2913,5 +2913,5 @@ class FrameworkExtension extends Extension * @return void */ - public static function registerRateLimiter(ContainerBuilder $container, string $name, array $limiterConfig) @@ -646,14 +663,14 @@ diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExt diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php -@@ -94,5 +94,5 @@ class FrameworkBundle extends Bundle +@@ -95,5 +95,5 @@ class FrameworkBundle extends Bundle * @return void */ - public function boot() + public function boot(): void { $_ENV['DOCTRINE_DEPRECATIONS'] = $_SERVER['DOCTRINE_DEPRECATIONS'] ??= 'trigger'; -@@ -119,5 +119,5 @@ class FrameworkBundle extends Bundle +@@ -120,5 +120,5 @@ class FrameworkBundle extends Bundle * @return void */ - public function build(ContainerBuilder $container) @@ -751,7 +768,7 @@ diff --git a/src/Symfony/Bundle/FrameworkBundle/Translation/Translator.php b/src diff --git a/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php b/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php --- a/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php +++ b/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php -@@ -32,5 +32,5 @@ final class TraceableFirewallListener extends FirewallListener +@@ -33,5 +33,5 @@ final class TraceableFirewallListener extends FirewallListener implements ResetI * @return array */ - public function getWrappedListeners() @@ -821,35 +838,35 @@ diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/Regi diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/AbstractFactory.php -@@ -56,5 +56,5 @@ abstract class AbstractFactory implements AuthenticatorFactoryInterface +@@ -53,5 +53,5 @@ abstract class AbstractFactory implements AuthenticatorFactoryInterface * @return void */ - public function addConfiguration(NodeDefinition $node) + public function addConfiguration(NodeDefinition $node): void { $builder = $node->children(); -@@ -79,5 +79,5 @@ abstract class AbstractFactory implements AuthenticatorFactoryInterface +@@ -76,5 +76,5 @@ abstract class AbstractFactory implements AuthenticatorFactoryInterface * @return string */ - protected function createAuthenticationSuccessHandler(ContainerBuilder $container, string $id, array $config) + protected function createAuthenticationSuccessHandler(ContainerBuilder $container, string $id, array $config): string { $successHandlerId = $this->getSuccessHandlerId($id); -@@ -101,5 +101,5 @@ abstract class AbstractFactory implements AuthenticatorFactoryInterface +@@ -98,5 +98,5 @@ abstract class AbstractFactory implements AuthenticatorFactoryInterface * @return string */ - protected function createAuthenticationFailureHandler(ContainerBuilder $container, string $id, array $config) + protected function createAuthenticationFailureHandler(ContainerBuilder $container, string $id, array $config): string { $id = $this->getFailureHandlerId($id); -@@ -121,5 +121,5 @@ abstract class AbstractFactory implements AuthenticatorFactoryInterface +@@ -118,5 +118,5 @@ abstract class AbstractFactory implements AuthenticatorFactoryInterface * @return string */ - protected function getSuccessHandlerId(string $id) + protected function getSuccessHandlerId(string $id): string { return 'security.authentication.success_handler.'.$id.'.'.str_replace('-', '_', $this->getKey()); -@@ -129,5 +129,5 @@ abstract class AbstractFactory implements AuthenticatorFactoryInterface +@@ -126,5 +126,5 @@ abstract class AbstractFactory implements AuthenticatorFactoryInterface * @return string */ - protected function getFailureHandlerId(string $id) @@ -2281,21 +2298,21 @@ diff --git a/src/Symfony/Component/Console/EventListener/ErrorListener.php b/src diff --git a/src/Symfony/Component/Console/Formatter/OutputFormatter.php b/src/Symfony/Component/Console/Formatter/OutputFormatter.php --- a/src/Symfony/Component/Console/Formatter/OutputFormatter.php +++ b/src/Symfony/Component/Console/Formatter/OutputFormatter.php -@@ -85,5 +85,5 @@ class OutputFormatter implements WrappableOutputFormatterInterface +@@ -87,5 +87,5 @@ class OutputFormatter implements WrappableOutputFormatterInterface * @return void */ - public function setDecorated(bool $decorated) + public function setDecorated(bool $decorated): void { $this->decorated = $decorated; -@@ -98,5 +98,5 @@ class OutputFormatter implements WrappableOutputFormatterInterface +@@ -100,5 +100,5 @@ class OutputFormatter implements WrappableOutputFormatterInterface * @return void */ - public function setStyle(string $name, OutputFormatterStyleInterface $style) + public function setStyle(string $name, OutputFormatterStyleInterface $style): void { $this->styles[strtolower($name)] = $style; -@@ -125,5 +125,5 @@ class OutputFormatter implements WrappableOutputFormatterInterface +@@ -127,5 +127,5 @@ class OutputFormatter implements WrappableOutputFormatterInterface * @return string */ - public function formatAndWrap(?string $message, int $width) @@ -2896,13 +2913,13 @@ diff --git a/src/Symfony/Component/Console/Output/ConsoleSectionOutput.php b/src + public function overwrite(string|iterable $message): void { $this->clear(); -@@ -167,5 +167,5 @@ class ConsoleSectionOutput extends StreamOutput +@@ -166,5 +166,5 @@ class ConsoleSectionOutput extends StreamOutput * @return void */ - protected function doWrite(string $message, bool $newline) + protected function doWrite(string $message, bool $newline): void { - if (!$this->isDecorated()) { + // Simulate newline behavior for consistent output formatting, avoiding extra logic diff --git a/src/Symfony/Component/Console/Output/NullOutput.php b/src/Symfony/Component/Console/Output/NullOutput.php --- a/src/Symfony/Component/Console/Output/NullOutput.php +++ b/src/Symfony/Component/Console/Output/NullOutput.php @@ -7096,98 +7113,98 @@ diff --git a/src/Symfony/Component/HttpFoundation/ParameterBag.php b/src/Symfony diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php -@@ -269,5 +269,5 @@ class Request +@@ -272,5 +272,5 @@ class Request * @return void */ - public function initialize(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null) + public function initialize(array $query = [], array $request = [], array $attributes = [], array $cookies = [], array $files = [], array $server = [], $content = null): void { $this->request = new InputBag($request); -@@ -429,5 +429,5 @@ class Request +@@ -432,5 +432,5 @@ class Request * @return void */ - public static function setFactory(?callable $callable) + public static function setFactory(?callable $callable): void { self::$requestFactory = $callable; -@@ -535,5 +535,5 @@ class Request +@@ -538,5 +538,5 @@ class Request * @return void */ - public function overrideGlobals() + public function overrideGlobals(): void { $this->server->set('QUERY_STRING', static::normalizeQueryString(http_build_query($this->query->all(), '', '&'))); -@@ -577,5 +577,5 @@ class Request +@@ -580,5 +580,5 @@ class Request * @return void */ - public static function setTrustedProxies(array $proxies, int $trustedHeaderSet) + public static function setTrustedProxies(array $proxies, int $trustedHeaderSet): void { self::$trustedProxies = array_reduce($proxies, function ($proxies, $proxy) { -@@ -620,5 +620,5 @@ class Request +@@ -623,5 +623,5 @@ class Request * @return void */ - public static function setTrustedHosts(array $hostPatterns) + public static function setTrustedHosts(array $hostPatterns): void { self::$trustedHostPatterns = array_map(fn ($hostPattern) => sprintf('{%s}i', $hostPattern), $hostPatterns); -@@ -668,5 +668,5 @@ class Request +@@ -671,5 +671,5 @@ class Request * @return void */ - public static function enableHttpMethodParameterOverride() + public static function enableHttpMethodParameterOverride(): void { self::$httpMethodParameterOverride = true; -@@ -755,5 +755,5 @@ class Request +@@ -758,5 +758,5 @@ class Request * @return void */ - public function setSession(SessionInterface $session) + public function setSession(SessionInterface $session): void { $this->session = $session; -@@ -1178,5 +1178,5 @@ class Request +@@ -1181,5 +1181,5 @@ class Request * @return void */ - public function setMethod(string $method) + public function setMethod(string $method): void { $this->method = null; -@@ -1301,5 +1301,5 @@ class Request +@@ -1304,5 +1304,5 @@ class Request * @return void */ - public function setFormat(?string $format, string|array $mimeTypes) + public function setFormat(?string $format, string|array $mimeTypes): void { if (null === static::$formats) { -@@ -1333,5 +1333,5 @@ class Request +@@ -1336,5 +1336,5 @@ class Request * @return void */ - public function setRequestFormat(?string $format) + public function setRequestFormat(?string $format): void { $this->format = $format; -@@ -1365,5 +1365,5 @@ class Request +@@ -1368,5 +1368,5 @@ class Request * @return void */ - public function setDefaultLocale(string $locale) + public function setDefaultLocale(string $locale): void { $this->defaultLocale = $locale; -@@ -1387,5 +1387,5 @@ class Request +@@ -1390,5 +1390,5 @@ class Request * @return void */ - public function setLocale(string $locale) + public function setLocale(string $locale): void { $this->setPhpDefaultLocale($this->locale = $locale); -@@ -1756,5 +1756,5 @@ class Request +@@ -1759,5 +1759,5 @@ class Request * @return string */ - protected function prepareRequestUri() + protected function prepareRequestUri(): string { $requestUri = ''; -@@ -1927,5 +1927,5 @@ class Request +@@ -1929,5 +1929,5 @@ class Request * @return void */ - protected static function initializeFormats() @@ -8464,7 +8481,7 @@ diff --git a/src/Symfony/Component/HttpKernel/HttpCache/SurrogateInterface.php b diff --git a/src/Symfony/Component/HttpKernel/HttpKernel.php b/src/Symfony/Component/HttpKernel/HttpKernel.php --- a/src/Symfony/Component/HttpKernel/HttpKernel.php +++ b/src/Symfony/Component/HttpKernel/HttpKernel.php -@@ -96,5 +96,5 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface +@@ -111,5 +111,5 @@ class HttpKernel implements HttpKernelInterface, TerminableInterface * @return void */ - public function terminate(Request $request, Response $response) @@ -9523,7 +9540,7 @@ diff --git a/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Transport/AmazonSq diff --git a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php --- a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php +++ b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php -@@ -128,5 +128,5 @@ EOF +@@ -132,5 +132,5 @@ EOF * @return void */ - protected function interact(InputInterface $input, OutputInterface $output) @@ -11313,56 +11330,56 @@ diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php -@@ -143,5 +143,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer +@@ -144,5 +144,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer * @return bool */ - public function supportsNormalization(mixed $data, string $format = null /* , array $context = [] */) + public function supportsNormalization(mixed $data, string $format = null /* , array $context = [] */): bool { return \is_object($data) && !$data instanceof \Traversable; -@@ -151,5 +151,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer +@@ -152,5 +152,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer * @return array|string|int|float|bool|\ArrayObject|null */ - public function normalize(mixed $object, string $format = null, array $context = []) + public function normalize(mixed $object, string $format = null, array $context = []): array|string|int|float|bool|\ArrayObject|null { if (!isset($context['cache_key'])) { -@@ -235,5 +235,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer +@@ -236,5 +236,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer * @return object */ - protected function instantiateObject(array &$data, string $class, array &$context, \ReflectionClass $reflectionClass, array|bool $allowedAttributes, string $format = null) + protected function instantiateObject(array &$data, string $class, array &$context, \ReflectionClass $reflectionClass, array|bool $allowedAttributes, string $format = null): object { if ($class !== $mappedClass = $this->getMappedClass($data, $class, $context)) { -@@ -286,5 +286,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer +@@ -287,5 +287,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer * @return string[] */ - abstract protected function extractAttributes(object $object, string $format = null, array $context = []); + abstract protected function extractAttributes(object $object, string $format = null, array $context = []): array; /** -@@ -293,5 +293,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer +@@ -294,5 +294,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer * @return mixed */ - abstract protected function getAttributeValue(object $object, string $attribute, string $format = null, array $context = []); + abstract protected function getAttributeValue(object $object, string $attribute, string $format = null, array $context = []): mixed; /** -@@ -300,5 +300,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer +@@ -301,5 +301,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer * @return bool */ - public function supportsDenormalization(mixed $data, string $type, string $format = null /* , array $context = [] */) + public function supportsDenormalization(mixed $data, string $type, string $format = null /* , array $context = [] */): bool { return class_exists($type) || (interface_exists($type, false) && null !== $this->classDiscriminatorResolver?->getMappingForClass($type)); -@@ -308,5 +308,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer +@@ -309,5 +309,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer * @return mixed */ - public function denormalize(mixed $data, string $type, string $format = null, array $context = []) + public function denormalize(mixed $data, string $type, string $format = null, array $context = []): mixed { if (!isset($context['cache_key'])) { -@@ -414,5 +414,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer +@@ -417,5 +417,5 @@ abstract class AbstractObjectNormalizer extends AbstractNormalizer * @return void */ - abstract protected function setAttributeValue(object $object, string $attribute, mixed $value, string $format = null, array $context = []); @@ -12183,7 +12200,7 @@ diff --git a/src/Symfony/Component/Translation/Writer/TranslationWriterInterface diff --git a/src/Symfony/Component/Validator/Command/DebugCommand.php b/src/Symfony/Component/Validator/Command/DebugCommand.php --- a/src/Symfony/Component/Validator/Command/DebugCommand.php +++ b/src/Symfony/Component/Validator/Command/DebugCommand.php -@@ -47,5 +47,5 @@ class DebugCommand extends Command +@@ -51,5 +51,5 @@ class DebugCommand extends Command * @return void */ - protected function configure() @@ -12193,35 +12210,35 @@ diff --git a/src/Symfony/Component/Validator/Command/DebugCommand.php b/src/Symf diff --git a/src/Symfony/Component/Validator/Constraint.php b/src/Symfony/Component/Validator/Constraint.php --- a/src/Symfony/Component/Validator/Constraint.php +++ b/src/Symfony/Component/Validator/Constraint.php -@@ -236,5 +236,5 @@ abstract class Constraint +@@ -238,5 +238,5 @@ abstract class Constraint * @return void */ - public function addImplicitGroupName(string $group) + public function addImplicitGroupName(string $group): void { if (null === $this->groups && \array_key_exists('groups', (array) $this)) { -@@ -256,5 +256,5 @@ abstract class Constraint +@@ -258,5 +258,5 @@ abstract class Constraint * @see __construct() */ - public function getDefaultOption() + public function getDefaultOption(): ?string { return null; -@@ -270,5 +270,5 @@ abstract class Constraint +@@ -272,5 +272,5 @@ abstract class Constraint * @see __construct() */ - public function getRequiredOptions() + public function getRequiredOptions(): array { return []; -@@ -284,5 +284,5 @@ abstract class Constraint +@@ -286,5 +286,5 @@ abstract class Constraint * @return string */ - public function validatedBy() + public function validatedBy(): string { return static::class.'Validator'; -@@ -298,5 +298,5 @@ abstract class Constraint +@@ -300,5 +300,5 @@ abstract class Constraint * @return string|string[] One or more constant values */ - public function getTargets() @@ -13971,49 +13988,49 @@ diff --git a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php b/src/Symfony/ + public function dumpScalar(Cursor $cursor, string $type, string|int|float|bool|null $value): void { $this->dumpKey($cursor); -@@ -195,5 +195,5 @@ class CliDumper extends AbstractDumper +@@ -196,5 +196,5 @@ class CliDumper extends AbstractDumper * @return void */ - public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut) + public function dumpString(Cursor $cursor, string $str, bool $bin, int $cut): void { $this->dumpKey($cursor); -@@ -286,5 +286,5 @@ class CliDumper extends AbstractDumper +@@ -288,5 +288,5 @@ class CliDumper extends AbstractDumper * @return void */ - public function enterHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild) + public function enterHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild): void { $this->colors ??= $this->supportsColors(); -@@ -325,5 +325,5 @@ class CliDumper extends AbstractDumper +@@ -328,5 +328,5 @@ class CliDumper extends AbstractDumper * @return void */ - public function leaveHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild, int $cut) + public function leaveHash(Cursor $cursor, int $type, string|int|null $class, bool $hasChild, int $cut): void { if (empty($cursor->attr['cut_hash'])) { -@@ -343,5 +343,5 @@ class CliDumper extends AbstractDumper +@@ -346,5 +346,5 @@ class CliDumper extends AbstractDumper * @return void */ - protected function dumpEllipsis(Cursor $cursor, bool $hasChild, int $cut) + protected function dumpEllipsis(Cursor $cursor, bool $hasChild, int $cut): void { if ($cut) { -@@ -361,5 +361,5 @@ class CliDumper extends AbstractDumper +@@ -364,5 +364,5 @@ class CliDumper extends AbstractDumper * @return void */ - protected function dumpKey(Cursor $cursor) + protected function dumpKey(Cursor $cursor): void { if (null !== $key = $cursor->hashKey) { -@@ -572,5 +572,5 @@ class CliDumper extends AbstractDumper +@@ -575,5 +575,5 @@ class CliDumper extends AbstractDumper * @return void */ - protected function dumpLine(int $depth, bool $endOfValue = false) + protected function dumpLine(int $depth, bool $endOfValue = false): void { if ($this->colors) { -@@ -583,5 +583,5 @@ class CliDumper extends AbstractDumper +@@ -586,5 +586,5 @@ class CliDumper extends AbstractDumper * @return void */ - protected function endValue(Cursor $cursor) From 03e559859c9232d9e6b956ca9b921825f140c892 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 12 Oct 2023 18:09:12 +0200 Subject: [PATCH 45/79] Fix deps=low --- .../Bundle/SecurityBundle/composer.json | 4 ++-- .../Cache/Tests/Traits/RedisProxiesTest.php | 18 ++++++------------ .../Component/HttpFoundation/composer.json | 4 ++-- .../Component/Security/Http/composer.json | 2 +- 4 files changed, 11 insertions(+), 17 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 1f6eeac2dbaa8..deedf660b975c 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -29,8 +29,8 @@ "symfony/password-hasher": "^5.4|^6.0", "symfony/security-core": "^6.2", "symfony/security-csrf": "^5.4|^6.0", - "symfony/security-http": "^6.3.4", - "symfony/service-contracts": "^1.10|^2|^3" + "symfony/security-http": "^6.3.6", + "symfony/service-contracts": "^2.5|^3" }, "require-dev": { "doctrine/annotations": "^1.10.4|^2", diff --git a/src/Symfony/Component/Cache/Tests/Traits/RedisProxiesTest.php b/src/Symfony/Component/Cache/Tests/Traits/RedisProxiesTest.php index c1c9681dfacb3..83963fcecf9bd 100644 --- a/src/Symfony/Component/Cache/Tests/Traits/RedisProxiesTest.php +++ b/src/Symfony/Component/Cache/Tests/Traits/RedisProxiesTest.php @@ -79,23 +79,17 @@ public function testRelayProxy() } /** - * @requires extension redis - * * @testWith ["Redis", "redis"] * ["RedisCluster", "redis_cluster"] */ public function testRedis6Proxy($class, $stub) { - if (version_compare(phpversion('redis'), '6.0.0', '<')) { - $stub = file_get_contents("https://raw.githubusercontent.com/phpredis/phpredis/develop/{$stub}.stub.php"); - $stub = preg_replace('/^class /m', 'return; \0', $stub); - $stub = preg_replace('/^return; class ([a-zA-Z]++)/m', 'interface \1StubInterface', $stub, 1); - $stub = preg_replace('/^ public const .*/m', '', $stub); - eval(substr($stub, 5)); - $r = new \ReflectionClass($class.'StubInterface'); - } else { - $r = new \ReflectionClass($class); - } + $stub = file_get_contents("https://raw.githubusercontent.com/phpredis/phpredis/develop/{$stub}.stub.php"); + $stub = preg_replace('/^class /m', 'return; \0', $stub); + $stub = preg_replace('/^return; class ([a-zA-Z]++)/m', 'interface \1StubInterface', $stub, 1); + $stub = preg_replace('/^ public const .*/m', '', $stub); + eval(substr($stub, 5)); + $r = new \ReflectionClass($class.'StubInterface'); $proxy = file_get_contents(\dirname(__DIR__, 2)."/Traits/{$class}6Proxy.php"); $proxy = substr($proxy, 0, 4 + strpos($proxy, '[];')); diff --git a/src/Symfony/Component/HttpFoundation/composer.json b/src/Symfony/Component/HttpFoundation/composer.json index 248bcbb163c39..6b4c4a364f489 100644 --- a/src/Symfony/Component/HttpFoundation/composer.json +++ b/src/Symfony/Component/HttpFoundation/composer.json @@ -24,7 +24,7 @@ "require-dev": { "doctrine/dbal": "^2.13.1|^3.0", "predis/predis": "^1.1|^2.0", - "symfony/cache": "^5.4|^6.0", + "symfony/cache": "^6.3", "symfony/dependency-injection": "^5.4|^6.0", "symfony/http-kernel": "^5.4.12|^6.0.12|^6.1.4", "symfony/mime": "^5.4|^6.0", @@ -32,7 +32,7 @@ "symfony/rate-limiter": "^5.2|^6.0" }, "conflict": { - "symfony/cache": "<6.2" + "symfony/cache": "<6.3" }, "autoload": { "psr-4": { "Symfony\\Component\\HttpFoundation\\": "" }, diff --git a/src/Symfony/Component/Security/Http/composer.json b/src/Symfony/Component/Security/Http/composer.json index 5102f86b400e9..1c01b9d91f6af 100644 --- a/src/Symfony/Component/Security/Http/composer.json +++ b/src/Symfony/Component/Security/Http/composer.json @@ -23,7 +23,7 @@ "symfony/polyfill-mbstring": "~1.0", "symfony/property-access": "^5.4|^6.0", "symfony/security-core": "^6.3", - "symfony/service-contracts": "^1.10|^2|^3" + "symfony/service-contracts": "^2.5|^3" }, "require-dev": { "symfony/cache": "^5.4|^6.0", From 0d418deea5cf7a7fe1808e0d90bdf414b0b099e1 Mon Sep 17 00:00:00 2001 From: "Phil E. Taylor" Date: Thu, 12 Oct 2023 18:41:20 +0100 Subject: [PATCH 46/79] Fix merge error with ErrorLoggerCompilerPass --- .../DependencyInjection/Compiler/ErrorLoggerCompilerPass.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php index 9a68cd032851b..09f2dba82f6bb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php @@ -22,11 +22,11 @@ class ErrorLoggerCompilerPass implements CompilerPassInterface { public function process(ContainerBuilder $container): void { - if (!$container->hasDefinition('debug.debug_handlers_listener')) { + if (!$container->hasDefinition('debug.error_handler_configurator')) { return; } - $definition = $container->getDefinition('debug.debug_handlers_listener'); + $definition = $container->getDefinition('debug.error_handler_configurator'); if ($container->hasDefinition('monolog.logger.php')) { $definition->replaceArgument(0, new Reference('monolog.logger.php')); } From 81c40bef833c9f95d924bdd4fb1ac2354aaefa9a Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Thu, 12 Oct 2023 19:29:50 +0200 Subject: [PATCH 47/79] Run tests with ORM 3 and DBAL 4 This reverts commit 913a317706780c843a7d1d7ed78e2e81a0d4d9e1. --- .github/patch-types.php | 2 ++ composer.json | 2 +- .../Doctrine/Middleware/Debug/Statement.php | 7 ++--- .../Component/HttpFoundation/composer.json | 2 +- .../Tests/Caster/DoctrineCasterTest.php | 30 ++++++++++++++----- 5 files changed, 29 insertions(+), 14 deletions(-) diff --git a/.github/patch-types.php b/.github/patch-types.php index 2517e1dab835d..7a1e6ffd83b23 100644 --- a/.github/patch-types.php +++ b/.github/patch-types.php @@ -23,6 +23,8 @@ } // no break; case false !== strpos($file, '/vendor/'): + case false !== strpos($file, '/src/Symfony/Bridge/Doctrine/Logger/DbalLogger.php'): + case false !== strpos($file, '/src/Symfony/Bridge/Doctrine/Middleware/Debug/'): case false !== strpos($file, '/src/Symfony/Bridge/PhpUnit/'): case false !== strpos($file, '/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Validation/Article.php'): case false !== strpos($file, '/src/Symfony/Component/Cache/Tests/Fixtures/DriverWrapper.php'): diff --git a/composer.json b/composer.json index 9a972bfdddc58..3a8174ca43aef 100644 --- a/composer.json +++ b/composer.json @@ -132,7 +132,7 @@ "doctrine/collections": "^1.0|^2.0", "doctrine/data-fixtures": "^1.1", "doctrine/dbal": "^2.13.1|^3.0", - "doctrine/orm": "^2.12", + "doctrine/orm": "^2.12|^3", "dragonmantank/cron-expression": "^3.1", "egulias/email-validator": "^2.1.10|^3.1|^4", "guzzlehttp/promises": "^1.4", diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php index 87a2222468db2..3f4ba10fc2138 100644 --- a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php @@ -39,15 +39,14 @@ public function __construct( $this->query = new Query($sql); } - public function bindValue($param, $value, $type = null): void + public function bindValue(int|string $param, mixed $value, ParameterType $type): void { - $type ??= ParameterType::STRING; $this->query->setValue($param, $value, $type); parent::bindValue($param, $value, $type); } - public function execute($params = null): ResultInterface + public function execute(): ResultInterface { // clone to prevent variables by reference to change $this->debugDataHolder->addQuery($this->connectionName, $query = clone $this->query); @@ -56,7 +55,7 @@ public function execute($params = null): ResultInterface $query->start(); try { - return parent::execute($params); + return parent::execute(); } finally { $query->stop(); $this->stopwatch?->stop('doctrine'); diff --git a/src/Symfony/Component/HttpFoundation/composer.json b/src/Symfony/Component/HttpFoundation/composer.json index 6b4c4a364f489..2128f56fcef95 100644 --- a/src/Symfony/Component/HttpFoundation/composer.json +++ b/src/Symfony/Component/HttpFoundation/composer.json @@ -22,7 +22,7 @@ "symfony/polyfill-php83": "^1.27" }, "require-dev": { - "doctrine/dbal": "^2.13.1|^3.0", + "doctrine/dbal": "^2.13.1|^3|^4", "predis/predis": "^1.1|^2.0", "symfony/cache": "^6.3", "symfony/dependency-injection": "^5.4|^6.0", diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/DoctrineCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/DoctrineCasterTest.php index 85f6293b13514..992c6c546dbbd 100644 --- a/src/Symfony/Component/VarDumper/Tests/Caster/DoctrineCasterTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Caster/DoctrineCasterTest.php @@ -31,14 +31,28 @@ public function testCastPersistentCollection() $collection = new PersistentCollection($this->createMock(EntityManagerInterface::class), $classMetadata, new ArrayCollection(['test'])); - $expected = <<= 2 + $expected = <<assertDumpMatchesFormat($expected, $collection); } From 5937e425667079883d15b8e82f21d2092881187b Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Thu, 12 Oct 2023 21:32:10 +0200 Subject: [PATCH 48/79] [Validator] Update Slovenian translations (sl) --- .../Resources/translations/validators.sl.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf index b956911e5a0dc..462a7752febe5 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Vrednost omrežne maske mora biti med {{ min }} in {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Ime datoteke je predolgo. Imeti mora {{ filename_max_length }} znak ali manj.|Ime datoteke je predolgo. Imeti mora {{ filename_max_length }} znaka ali manj.|Ime datoteke je predolgo. Imeti mora {{ filename_max_length }} znake ali manj.|Ime datoteke je predolgo. Imeti mora {{ filename_max_length }} znakov ali manj. + + + The password strength is too low. Please use a stronger password. + Moč gesla je prenizka. Uporabite močnejše geslo. + + + This value contains characters that are not allowed by the current restriction-level. + Ta vrednost vsebuje znake, ki jih trenutna raven omejitve ne dovoljuje. + + + Using invisible characters is not allowed. + Uporaba nevidnih znakov ni dovoljena. + + + Mixing numbers from different scripts is not allowed. + Mešanje številk iz različnih skript ni dovoljeno. + + + Using hidden overlay characters is not allowed. + Uporaba skritih prekrivnih znakov ni dovoljena. + From c66a2f7aebdd5a6ebdb967c44f37018e61991d8c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 13 Oct 2023 11:16:49 +0200 Subject: [PATCH 49/79] [Cache][VarExporter] Fix proxy generation to deal with edgy behaviors of internal classes --- src/Symfony/Component/Cache/Traits/Redis6Proxy.php | 8 ++++---- .../Component/Cache/Traits/RedisCluster6Proxy.php | 8 ++++---- src/Symfony/Component/Cache/Traits/RelayProxy.php | 8 ++++---- src/Symfony/Component/Cache/composer.json | 2 +- src/Symfony/Component/VarExporter/ProxyHelper.php | 12 ++++++++---- 5 files changed, 21 insertions(+), 17 deletions(-) diff --git a/src/Symfony/Component/Cache/Traits/Redis6Proxy.php b/src/Symfony/Component/Cache/Traits/Redis6Proxy.php index 24edb20bc37b3..0680404fc1eee 100644 --- a/src/Symfony/Component/Cache/Traits/Redis6Proxy.php +++ b/src/Symfony/Component/Cache/Traits/Redis6Proxy.php @@ -538,7 +538,7 @@ public function hVals($key): \Redis|array|false public function hscan($key, &$iterator, $pattern = null, $count = 0): \Redis|array|bool { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hscan($key, $iterator, $pattern, $count, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hscan($key, $iterator, ...\array_slice(\func_get_args(), 2)); } public function incr($key, $by = 1): \Redis|false|int @@ -888,7 +888,7 @@ public function save(): \Redis|bool public function scan(&$iterator, $pattern = null, $count = 0, $type = null): array|false { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scan($iterator, $pattern, $count, $type, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scan($iterator, ...\array_slice(\func_get_args(), 1)); } public function scard($key): \Redis|false|int @@ -998,7 +998,7 @@ public function srem($key, $value, ...$other_values): \Redis|false|int public function sscan($key, &$iterator, $pattern = null, $count = 0): array|false { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sscan($key, $iterator, $pattern, $count, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sscan($key, $iterator, ...\array_slice(\func_get_args(), 2)); } public function ssubscribe($channels, $cb): bool @@ -1278,7 +1278,7 @@ public function zinterstore($dst, $keys, $weights = null, $aggregate = null): \R public function zscan($key, &$iterator, $pattern = null, $count = 0): \Redis|array|false { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscan($key, $iterator, $pattern, $count, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscan($key, $iterator, ...\array_slice(\func_get_args(), 2)); } public function zunion($keys, $weights = null, $options = null): \Redis|array|false diff --git a/src/Symfony/Component/Cache/Traits/RedisCluster6Proxy.php b/src/Symfony/Component/Cache/Traits/RedisCluster6Proxy.php index 9b52a314e06ab..fafc4acf2df06 100644 --- a/src/Symfony/Component/Cache/Traits/RedisCluster6Proxy.php +++ b/src/Symfony/Component/Cache/Traits/RedisCluster6Proxy.php @@ -463,7 +463,7 @@ public function hmset($key, $key_values): \RedisCluster|bool public function hscan($key, &$iterator, $pattern = null, $count = 0): array|bool { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hscan($key, $iterator, $pattern, $count, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hscan($key, $iterator, ...\array_slice(\func_get_args(), 2)); } public function hrandfield($key, $options = null): \RedisCluster|array|string @@ -738,7 +738,7 @@ public function save($key_or_address): \RedisCluster|bool public function scan(&$iterator, $key_or_address, $pattern = null, $count = 0): array|bool { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scan($iterator, $key_or_address, $pattern, $count, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scan($iterator, ...\array_slice(\func_get_args(), 1)); } public function scard($key): \RedisCluster|false|int @@ -858,7 +858,7 @@ public function srem($key, $value, ...$other_values): \RedisCluster|false|int public function sscan($key, &$iterator, $pattern = null, $count = 0): array|false { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sscan($key, $iterator, $pattern, $count, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sscan($key, $iterator, ...\array_slice(\func_get_args(), 2)); } public function strlen($key): \RedisCluster|false|int @@ -1103,7 +1103,7 @@ public function zrevrank($key, $member): \RedisCluster|false|int public function zscan($key, &$iterator, $pattern = null, $count = 0): \RedisCluster|array|bool { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscan($key, $iterator, $pattern, $count, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscan($key, $iterator, ...\array_slice(\func_get_args(), 2)); } public function zscore($key, $member): \RedisCluster|false|float diff --git a/src/Symfony/Component/Cache/Traits/RelayProxy.php b/src/Symfony/Component/Cache/Traits/RelayProxy.php index 2f0e2c8460007..a9ad9c8403b65 100644 --- a/src/Symfony/Component/Cache/Traits/RelayProxy.php +++ b/src/Symfony/Component/Cache/Traits/RelayProxy.php @@ -984,22 +984,22 @@ public function clearBytes(): void public function scan(&$iterator, $match = null, $count = 0, $type = null): array|false { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scan($iterator, $match, $count, $type, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scan($iterator, ...\array_slice(\func_get_args(), 1)); } public function hscan($key, &$iterator, $match = null, $count = 0): array|false { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hscan($key, $iterator, $match, $count, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hscan($key, $iterator, ...\array_slice(\func_get_args(), 2)); } public function sscan($key, &$iterator, $match = null, $count = 0): array|false { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sscan($key, $iterator, $match, $count, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sscan($key, $iterator, ...\array_slice(\func_get_args(), 2)); } public function zscan($key, &$iterator, $match = null, $count = 0): array|false { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscan($key, $iterator, $match, $count, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscan($key, $iterator, ...\array_slice(\func_get_args(), 2)); } public function keys($pattern): \Relay\Relay|array|false diff --git a/src/Symfony/Component/Cache/composer.json b/src/Symfony/Component/Cache/composer.json index efec372c5ef50..82e2f49ce4b81 100644 --- a/src/Symfony/Component/Cache/composer.json +++ b/src/Symfony/Component/Cache/composer.json @@ -26,7 +26,7 @@ "psr/log": "^1.1|^2|^3", "symfony/cache-contracts": "^2.5|^3", "symfony/service-contracts": "^2.5|^3", - "symfony/var-exporter": "^6.2.10" + "symfony/var-exporter": "^6.3.6" }, "require-dev": { "cache/integration-tests": "dev-master", diff --git a/src/Symfony/Component/VarExporter/ProxyHelper.php b/src/Symfony/Component/VarExporter/ProxyHelper.php index 2e150cb5cedd9..155715de662c9 100644 --- a/src/Symfony/Component/VarExporter/ProxyHelper.php +++ b/src/Symfony/Component/VarExporter/ProxyHelper.php @@ -215,7 +215,7 @@ class_exists(\Symfony\Component\VarExporter\Internal\LazyObjectState::class); public static function exportSignature(\ReflectionFunctionAbstract $function, bool $withParameterTypes = true, string &$args = null): string { - $hasByRef = false; + $byRefIndex = 0; $args = ''; $param = null; $parameters = []; @@ -225,16 +225,20 @@ public static function exportSignature(\ReflectionFunctionAbstract $function, bo .($param->isPassedByReference() ? '&' : '') .($param->isVariadic() ? '...' : '').'$'.$param->name .($param->isOptional() && !$param->isVariadic() ? ' = '.self::exportDefault($param) : ''); - $hasByRef = $hasByRef || $param->isPassedByReference(); + if ($param->isPassedByReference()) { + $byRefIndex = 1 + $param->getPosition(); + } $args .= ($param->isVariadic() ? '...$' : '$').$param->name.', '; } - if (!$param || !$hasByRef) { + if (!$param || !$byRefIndex) { $args = '...\func_get_args()'; } elseif ($param->isVariadic()) { $args = substr($args, 0, -2); } else { - $args .= sprintf('...\array_slice(\func_get_args(), %d)', \count($parameters)); + $args = explode(', ', $args, 1 + $byRefIndex); + $args[$byRefIndex] = sprintf('...\array_slice(\func_get_args(), %d)', $byRefIndex); + $args = implode(', ', $args); } $signature = 'function '.($function->returnsReference() ? '&' : '') From d52c3159b3c5da46c75982f801537ca2a37166b3 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Fri, 13 Oct 2023 11:51:05 +0200 Subject: [PATCH 50/79] [Cache] Fix ArrayAdapter::freeze() return type --- .../Component/Cache/Adapter/ArrayAdapter.php | 2 +- .../Cache/Tests/Adapter/ArrayAdapterTest.php | 11 +++++++++++ .../Component/Cache/Tests/Fixtures/TestEnum.php | 17 +++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/Cache/Tests/Fixtures/TestEnum.php diff --git a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php index 319dc0487b3e9..1100c7734caae 100644 --- a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php @@ -298,7 +298,7 @@ private function generateItems(array $keys, float $now, \Closure $f): \Generator } } - private function freeze($value, string $key): string|int|float|bool|array|null + private function freeze($value, string $key): string|int|float|bool|array|\UnitEnum|null { if (null === $value) { return 'N;'; diff --git a/src/Symfony/Component/Cache/Tests/Adapter/ArrayAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/ArrayAdapterTest.php index 9a55e95cc7ef5..c49cc3198b32e 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/ArrayAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/ArrayAdapterTest.php @@ -13,6 +13,7 @@ use Psr\Cache\CacheItemPoolInterface; use Symfony\Component\Cache\Adapter\ArrayAdapter; +use Symfony\Component\Cache\Tests\Fixtures\TestEnum; /** * @group time-sensitive @@ -91,4 +92,14 @@ public function testMaxItems() $this->assertTrue($cache->hasItem('buz')); $this->assertTrue($cache->hasItem('foo')); } + + public function testEnum() + { + $cache = new ArrayAdapter(); + $item = $cache->getItem('foo'); + $item->set(TestEnum::Foo); + $cache->save($item); + + $this->assertSame(TestEnum::Foo, $cache->getItem('foo')->get()); + } } diff --git a/src/Symfony/Component/Cache/Tests/Fixtures/TestEnum.php b/src/Symfony/Component/Cache/Tests/Fixtures/TestEnum.php new file mode 100644 index 0000000000000..cf4c3b271f48f --- /dev/null +++ b/src/Symfony/Component/Cache/Tests/Fixtures/TestEnum.php @@ -0,0 +1,17 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Tests\Fixtures; + +enum TestEnum +{ + case Foo; +} From 50c0fbc79b4e86d1a500b27d4d519f0ec3b33cae Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Fri, 13 Oct 2023 10:59:07 +0200 Subject: [PATCH 51/79] Fix DBAL 4 compatibility --- .../Doctrine/Form/DoctrineOrmTypeGuesser.php | 2 +- .../DoctrinePingConnectionMiddleware.php | 16 +- .../Doctrine/Middleware/Debug/Connection.php | 135 ++++---------- .../Middleware/Debug/DBAL3/Connection.php | 174 ++++++++++++++++++ .../Middleware/Debug/DBAL3/Statement.php | 86 +++++++++ .../Doctrine/Middleware/Debug/Driver.php | 16 +- .../Doctrine/Middleware/Debug/Query.php | 16 +- .../Doctrine/Middleware/Debug/Statement.php | 51 ++--- .../PropertyInfo/DoctrineExtractor.php | 10 +- ...octrineDataCollectorWithDebugStackTest.php | 7 + .../Tests/Fixtures/SingleIntIdEntity.php | 5 +- .../Tests/Fixtures/Type/StringWrapperType.php | 8 +- .../Doctrine/Tests/Logger/DbalLoggerTest.php | 8 + .../DoctrinePingConnectionMiddlewareTest.php | 40 ++-- .../Tests/Middleware/Debug/MiddlewareTest.php | 10 +- .../PropertyInfo/Fixtures/DoctrineFooType.php | 8 +- ...rTransportDoctrineSchemaSubscriberTest.php | 8 + .../Doctrine/Tests/Types/UlidTypeTest.php | 23 ++- .../Bridge/Doctrine/Types/AbstractUidType.php | 40 +++- 19 files changed, 466 insertions(+), 197 deletions(-) create mode 100644 src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Connection.php create mode 100644 src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Statement.php diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php index 231b50640f040..6386318ef97d9 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php @@ -52,7 +52,7 @@ public function guessType(string $class, string $property) } switch ($metadata->getTypeOfField($property)) { - case Types::ARRAY: + case 'array': // DBAL < 4 case Types::SIMPLE_ARRAY: return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CollectionType', [], Guess::MEDIUM_CONFIDENCE); case Types::BOOLEAN: diff --git a/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php b/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php index de925284d09dc..5f8d9496348c8 100644 --- a/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php +++ b/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Doctrine\Messenger; +use Doctrine\DBAL\Connection; use Doctrine\DBAL\Exception as DBALException; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Messenger\Envelope; @@ -33,19 +34,28 @@ protected function handleForManager(EntityManagerInterface $entityManager, Envel return $stack->next()->handle($envelope, $stack); } - private function pingConnection(EntityManagerInterface $entityManager) + private function pingConnection(EntityManagerInterface $entityManager): void { $connection = $entityManager->getConnection(); try { - $connection->executeQuery($connection->getDatabasePlatform()->getDummySelectSQL()); + $this->executeDummySql($connection); } catch (DBALException $e) { $connection->close(); - $connection->connect(); + // Attempt to reestablish the lazy connection by sending another query. + $this->executeDummySql($connection); } if (!$entityManager->isOpen()) { $this->managerRegistry->resetManager($this->entityManagerName); } } + + /** + * @throws DBALException + */ + private function executeDummySql(Connection $connection): void + { + $connection->executeQuery($connection->getDatabasePlatform()->getDummySelectSQL()); + } } diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Connection.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Connection.php index e768407bdd137..a0d642dd7d250 100644 --- a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Connection.php +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Connection.php @@ -14,31 +14,26 @@ use Doctrine\DBAL\Driver\Connection as ConnectionInterface; use Doctrine\DBAL\Driver\Middleware\AbstractConnectionMiddleware; use Doctrine\DBAL\Driver\Result; -use Doctrine\DBAL\Driver\Statement as DriverStatement; use Symfony\Component\Stopwatch\Stopwatch; /** * @author Laurent VOULLEMIER + * @author Alexander M. Turek * * @internal */ final class Connection extends AbstractConnectionMiddleware { - private $nestingLevel = 0; - private $debugDataHolder; - private $stopwatch; - private $connectionName; - - public function __construct(ConnectionInterface $connection, DebugDataHolder $debugDataHolder, ?Stopwatch $stopwatch, string $connectionName) - { + public function __construct( + ConnectionInterface $connection, + private DebugDataHolder $debugDataHolder, + private ?Stopwatch $stopwatch, + private string $connectionName, + ) { parent::__construct($connection); - - $this->debugDataHolder = $debugDataHolder; - $this->stopwatch = $stopwatch; - $this->connectionName = $connectionName; } - public function prepare(string $sql): DriverStatement + public function prepare(string $sql): Statement { return new Statement( parent::prepare($sql), @@ -53,135 +48,79 @@ public function query(string $sql): Result { $this->debugDataHolder->addQuery($this->connectionName, $query = new Query($sql)); - if (null !== $this->stopwatch) { - $this->stopwatch->start('doctrine', 'doctrine'); - } - + $this->stopwatch?->start('doctrine', 'doctrine'); $query->start(); try { - $result = parent::query($sql); + return parent::query($sql); } finally { $query->stop(); - - if (null !== $this->stopwatch) { - $this->stopwatch->stop('doctrine'); - } + $this->stopwatch?->stop('doctrine'); } - - return $result; } public function exec(string $sql): int { $this->debugDataHolder->addQuery($this->connectionName, $query = new Query($sql)); - if (null !== $this->stopwatch) { - $this->stopwatch->start('doctrine', 'doctrine'); - } - + $this->stopwatch?->start('doctrine', 'doctrine'); $query->start(); try { $affectedRows = parent::exec($sql); } finally { $query->stop(); - - if (null !== $this->stopwatch) { - $this->stopwatch->stop('doctrine'); - } + $this->stopwatch?->stop('doctrine'); } return $affectedRows; } - public function beginTransaction(): bool + public function beginTransaction(): void { - $query = null; - if (1 === ++$this->nestingLevel) { - $this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"START TRANSACTION"')); - } - - if (null !== $this->stopwatch) { - $this->stopwatch->start('doctrine', 'doctrine'); - } + $query = new Query('"START TRANSACTION"'); + $this->debugDataHolder->addQuery($this->connectionName, $query); - if (null !== $query) { - $query->start(); - } + $this->stopwatch?->start('doctrine', 'doctrine'); + $query->start(); try { - $ret = parent::beginTransaction(); + parent::beginTransaction(); } finally { - if (null !== $query) { - $query->stop(); - } - - if (null !== $this->stopwatch) { - $this->stopwatch->stop('doctrine'); - } + $query->stop(); + $this->stopwatch?->stop('doctrine'); } - - return $ret; } - public function commit(): bool + public function commit(): void { - $query = null; - if (1 === $this->nestingLevel--) { - $this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"COMMIT"')); - } + $query = new Query('"COMMIT"'); + $this->debugDataHolder->addQuery($this->connectionName, $query); - if (null !== $this->stopwatch) { - $this->stopwatch->start('doctrine', 'doctrine'); - } - - if (null !== $query) { - $query->start(); - } + $this->stopwatch?->start('doctrine', 'doctrine'); + $query->start(); try { - $ret = parent::commit(); + parent::commit(); } finally { - if (null !== $query) { - $query->stop(); - } - - if (null !== $this->stopwatch) { - $this->stopwatch->stop('doctrine'); - } + $query->stop(); + $this->stopwatch?->stop('doctrine'); } - - return $ret; } - public function rollBack(): bool + public function rollBack(): void { - $query = null; - if (1 === $this->nestingLevel--) { - $this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"ROLLBACK"')); - } - - if (null !== $this->stopwatch) { - $this->stopwatch->start('doctrine', 'doctrine'); - } + $query = new Query('"ROLLBACK"'); + $this->debugDataHolder->addQuery($this->connectionName, $query); - if (null !== $query) { - $query->start(); - } + $this->stopwatch?->start('doctrine', 'doctrine'); + $query->start(); try { - $ret = parent::rollBack(); + parent::rollBack(); } finally { - if (null !== $query) { - $query->stop(); - } - - if (null !== $this->stopwatch) { - $this->stopwatch->stop('doctrine'); - } + $query->stop(); + $this->stopwatch?->stop('doctrine'); } - - return $ret; } } diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Connection.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Connection.php new file mode 100644 index 0000000000000..1bcb6c22e0c3d --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Connection.php @@ -0,0 +1,174 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Middleware\Debug\DBAL3; + +use Doctrine\DBAL\Driver\Connection as ConnectionInterface; +use Doctrine\DBAL\Driver\Middleware\AbstractConnectionMiddleware; +use Doctrine\DBAL\Driver\Result; +use Doctrine\DBAL\Driver\Statement as StatementInterface; +use Symfony\Bridge\Doctrine\Middleware\Debug\DebugDataHolder; +use Symfony\Bridge\Doctrine\Middleware\Debug\Query; +use Symfony\Component\Stopwatch\Stopwatch; + +/** + * @author Laurent VOULLEMIER + * + * @internal + */ +final class Connection extends AbstractConnectionMiddleware +{ + /** @var int */ + private $nestingLevel = 0; + private $debugDataHolder; + private $stopwatch; + private $connectionName; + + public function __construct( + ConnectionInterface $connection, + DebugDataHolder $debugDataHolder, + ?Stopwatch $stopwatch, + string $connectionName + ) { + $this->connectionName = $connectionName; + $this->stopwatch = $stopwatch; + $this->debugDataHolder = $debugDataHolder; + + parent::__construct($connection); + } + + public function prepare(string $sql): StatementInterface + { + return new Statement( + parent::prepare($sql), + $this->debugDataHolder, + $this->connectionName, + $sql, + $this->stopwatch, + ); + } + + public function query(string $sql): Result + { + $this->debugDataHolder->addQuery($this->connectionName, $query = new Query($sql)); + + if ($this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + $query->start(); + + try { + return parent::query($sql); + } finally { + $query->stop(); + if ($this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + } + + public function exec(string $sql): int + { + $this->debugDataHolder->addQuery($this->connectionName, $query = new Query($sql)); + + if ($this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + $query->start(); + + try { + return parent::exec($sql); + } finally { + $query->stop(); + if ($this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + } + + public function beginTransaction(): bool + { + $query = null; + if (1 === ++$this->nestingLevel) { + $this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"START TRANSACTION"')); + } + + if ($this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + if ($query) { + $query->start(); + } + + try { + return parent::beginTransaction(); + } finally { + if ($query) { + $query->stop(); + } + if ($this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + } + + public function commit(): bool + { + $query = null; + if (1 === $this->nestingLevel--) { + $this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"COMMIT"')); + } + + if ($this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + if ($query) { + $query->start(); + } + + try { + return parent::commit(); + } finally { + if ($query) { + $query->stop(); + } + if ($this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + } + + public function rollBack(): bool + { + $query = null; + if (1 === $this->nestingLevel--) { + $this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"ROLLBACK"')); + } + + if ($this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + if ($query) { + $query->start(); + } + + try { + return parent::rollBack(); + } finally { + if ($query) { + $query->stop(); + } + if ($this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + } +} diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Statement.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Statement.php new file mode 100644 index 0000000000000..16217c2f46a51 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Statement.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Middleware\Debug\DBAL3; + +use Doctrine\DBAL\Driver\Middleware\AbstractStatementMiddleware; +use Doctrine\DBAL\Driver\Result as ResultInterface; +use Doctrine\DBAL\Driver\Statement as StatementInterface; +use Doctrine\DBAL\ParameterType; +use Symfony\Bridge\Doctrine\Middleware\Debug\DebugDataHolder; +use Symfony\Bridge\Doctrine\Middleware\Debug\Query; +use Symfony\Component\Stopwatch\Stopwatch; + +/** + * @author Laurent VOULLEMIER + * + * @internal + */ +final class Statement extends AbstractStatementMiddleware +{ + private $query; + private $debugDataHolder; + private $connectionName; + private $stopwatch; + + public function __construct( + StatementInterface $statement, + DebugDataHolder $debugDataHolder, + string $connectionName, + string $sql, + Stopwatch $stopwatch = null + ) { + $this->stopwatch = $stopwatch; + $this->connectionName = $connectionName; + $this->debugDataHolder = $debugDataHolder; + $this->query = new Query($sql); + + parent::__construct($statement); + } + + public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null): bool + { + $this->query->setParam($param, $variable, $type); + + return parent::bindParam($param, $variable, $type, ...\array_slice(\func_get_args(), 3)); + } + + public function bindValue($param, $value, $type = ParameterType::STRING): bool + { + $this->query->setValue($param, $value, $type); + + return parent::bindValue($param, $value, $type); + } + + public function execute($params = null): ResultInterface + { + if (null !== $params) { + $this->query->setValues($params); + } + + // clone to prevent variables by reference to change + $this->debugDataHolder->addQuery($this->connectionName, $query = clone $this->query); + + if ($this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + $query->start(); + + try { + return parent::execute($params); + } finally { + $query->stop(); + if ($this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + } +} diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Driver.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Driver.php index 7f7fdd3bf0d8d..090b1643f6ad6 100644 --- a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Driver.php +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Driver.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Doctrine\Middleware\Debug; use Doctrine\DBAL\Driver as DriverInterface; +use Doctrine\DBAL\Driver\Connection as ConnectionInterface; use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware; use Symfony\Component\Stopwatch\Stopwatch; @@ -35,10 +36,21 @@ public function __construct(DriverInterface $driver, DebugDataHolder $debugDataH $this->connectionName = $connectionName; } - public function connect(array $params): Connection + public function connect(array $params): ConnectionInterface { + $connection = parent::connect($params); + + if ('void' !== (string) (new \ReflectionMethod(DriverInterface\Connection::class, 'commit'))->getReturnType()) { + return new DBAL3\Connection( + $connection, + $this->debugDataHolder, + $this->stopwatch, + $this->connectionName + ); + } + return new Connection( - parent::connect($params), + $connection, $this->debugDataHolder, $this->stopwatch, $this->connectionName diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Query.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Query.php index eb835caa41b25..6ab402e1b7779 100644 --- a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Query.php +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Query.php @@ -46,10 +46,11 @@ public function stop(): void } /** - * @param string|int $param - * @param mixed $variable + * @param string|int $param + * @param mixed $variable + * @param int|ParameterType $type */ - public function setParam($param, &$variable, int $type): void + public function setParam($param, &$variable, $type): void { // Numeric indexes start at 0 in profiler $idx = \is_int($param) ? $param - 1 : $param; @@ -59,10 +60,11 @@ public function setParam($param, &$variable, int $type): void } /** - * @param string|int $param - * @param mixed $value + * @param string|int $param + * @param mixed $value + * @param int|ParameterType $type */ - public function setValue($param, $value, int $type): void + public function setValue($param, $value, $type): void { // Numeric indexes start at 0 in profiler $idx = \is_int($param) ? $param - 1 : $param; @@ -95,7 +97,7 @@ public function getParams(): array } /** - * @return array + * @return array */ public function getTypes(): array { diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php index a40cdaa9695ba..3f4ba10fc2138 100644 --- a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php @@ -19,65 +19,46 @@ /** * @author Laurent VOULLEMIER + * @author Alexander M. Turek * * @internal */ final class Statement extends AbstractStatementMiddleware { - private $debugDataHolder; - private $connectionName; - private $query; - private $stopwatch; - - public function __construct(StatementInterface $statement, DebugDataHolder $debugDataHolder, string $connectionName, string $sql, Stopwatch $stopwatch = null) - { + private Query $query; + + public function __construct( + StatementInterface $statement, + private DebugDataHolder $debugDataHolder, + private string $connectionName, + string $sql, + private ?Stopwatch $stopwatch = null, + ) { parent::__construct($statement); - $this->debugDataHolder = $debugDataHolder; - $this->connectionName = $connectionName; $this->query = new Query($sql); - $this->stopwatch = $stopwatch; - } - - public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null): bool - { - $this->query->setParam($param, $variable, $type); - - return parent::bindParam($param, $variable, $type, ...\array_slice(\func_get_args(), 3)); } - public function bindValue($param, $value, $type = ParameterType::STRING): bool + public function bindValue(int|string $param, mixed $value, ParameterType $type): void { $this->query->setValue($param, $value, $type); - return parent::bindValue($param, $value, $type); + parent::bindValue($param, $value, $type); } - public function execute($params = null): ResultInterface + public function execute(): ResultInterface { - if (null !== $params) { - $this->query->setValues($params); - } - // clone to prevent variables by reference to change $this->debugDataHolder->addQuery($this->connectionName, $query = clone $this->query); - if ($this->stopwatch) { - $this->stopwatch->start('doctrine', 'doctrine'); - } - + $this->stopwatch?->start('doctrine', 'doctrine'); $query->start(); try { - $result = parent::execute($params); + return parent::execute(); } finally { $query->stop(); - - if ($this->stopwatch) { - $this->stopwatch->stop('doctrine'); - } + $this->stopwatch?->stop('doctrine'); } - - return $result; } } diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index ccd53c1ebe7c6..f33a62cb6257c 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -167,8 +167,8 @@ public function getTypes(string $class, string $property, array $context = []) break; case Type::BUILTIN_TYPE_ARRAY: switch ($typeOfField) { - case Types::ARRAY: - case 'json_array': + case 'array': // DBAL < 4 + case 'json_array': // DBAL < 3 // return null if $enumType is set, because we can't determine if collectionKeyType is string or int if ($enumType) { return null; @@ -281,7 +281,7 @@ private function getPhpType(string $doctrineType): ?string case Types::BINARY: return Type::BUILTIN_TYPE_RESOURCE; - case Types::OBJECT: + case 'object': // DBAL < 4 case Types::DATE_MUTABLE: case Types::DATETIME_MUTABLE: case Types::DATETIMETZ_MUTABLE: @@ -294,9 +294,9 @@ private function getPhpType(string $doctrineType): ?string case Types::DATEINTERVAL: return Type::BUILTIN_TYPE_OBJECT; - case Types::ARRAY: + case 'array': // DBAL < 4 case Types::SIMPLE_ARRAY: - case 'json_array': + case 'json_array': // DBAL < 3 return Type::BUILTIN_TYPE_ARRAY; } diff --git a/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorWithDebugStackTest.php b/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorWithDebugStackTest.php index 64bee1203b781..690c5aa6f9b8d 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorWithDebugStackTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorWithDebugStackTest.php @@ -32,6 +32,13 @@ class DoctrineDataCollectorWithDebugStackTest extends TestCase { use DoctrineDataCollectorTestTrait; + public static function setUpBeforeClass(): void + { + if (!class_exists(DebugStack::class)) { + self::markTestSkipped('This test requires DBAL < 4.'); + } + } + public function testReset() { $queries = [ diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleIntIdEntity.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleIntIdEntity.php index 94b47da855a37..85c1c0cc20ea6 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleIntIdEntity.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleIntIdEntity.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Doctrine\Tests\Fixtures; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\Entity; use Doctrine\ORM\Mapping\Id; @@ -27,8 +28,8 @@ class SingleIntIdEntity #[Column(type: 'string', nullable: true)] public $name; - /** @Column(type="array", nullable=true) */ - #[Column(type: 'array', nullable: true)] + /** @Column(type="json", nullable=true) */ + #[Column(type: Types::JSON, nullable: true)] public $phoneNumbers = []; public function __construct($id, $name) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Type/StringWrapperType.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Type/StringWrapperType.php index d01148f3b018c..33481663b6152 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Type/StringWrapperType.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Type/StringWrapperType.php @@ -18,20 +18,16 @@ class StringWrapperType extends StringType { /** * {@inheritdoc} - * - * @return mixed */ - public function convertToDatabaseValue($value, AbstractPlatform $platform) + public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string { return $value instanceof StringWrapper ? $value->getString() : null; } /** * {@inheritdoc} - * - * @return mixed */ - public function convertToPHPValue($value, AbstractPlatform $platform) + public function convertToPHPValue($value, AbstractPlatform $platform): StringWrapper { return new StringWrapper($value); } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php b/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php index 2e9ed80e3115a..b43bb93d7dd52 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Doctrine\Tests\Logger; +use Doctrine\DBAL\Logging\SQLLogger; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Symfony\Bridge\Doctrine\Logger\DbalLogger; @@ -20,6 +21,13 @@ */ class DbalLoggerTest extends TestCase { + public static function setUpBeforeClass(): void + { + if (!class_exists(SQLLogger::class)) { + self::markTestSkipped('This test requires DBAL < 4.'); + } + } + /** * @dataProvider getLogFixtures */ diff --git a/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php b/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php index 6c7bf67bc08af..a478f72266ffb 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php @@ -13,8 +13,11 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Exception as DBALException; +use Doctrine\DBAL\Platforms\AbstractPlatform; +use Doctrine\DBAL\Result; use Doctrine\ORM\EntityManagerInterface; use Doctrine\Persistence\ManagerRegistry; +use PHPUnit\Framework\MockObject\MockObject; use Symfony\Bridge\Doctrine\Messenger\DoctrinePingConnectionMiddleware; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; @@ -47,16 +50,24 @@ protected function setUp(): void public function testMiddlewarePingOk() { - $this->connection->expects($this->once()) - ->method('getDatabasePlatform') - ->will($this->throwException(new DBALException())); + $this->connection->method('getDatabasePlatform') + ->willReturn($this->mockPlatform()); + + $this->connection->expects($this->exactly(2)) + ->method('executeQuery') + ->willReturnCallback(function () { + static $counter = 0; + + if (1 === ++$counter) { + throw $this->createMock(DBALException::class); + } + + return $this->createMock(Result::class); + }); $this->connection->expects($this->once()) ->method('close') ; - $this->connection->expects($this->once()) - ->method('connect') - ; $envelope = new Envelope(new \stdClass(), [ new ConsumedByWorkerStamp(), @@ -66,9 +77,8 @@ public function testMiddlewarePingOk() public function testMiddlewarePingResetEntityManager() { - $this->connection->expects($this->once()) - ->method('getDatabasePlatform') - ->will($this->throwException(new DBALException())); + $this->connection->method('getDatabasePlatform') + ->willReturn($this->mockPlatform()); $this->entityManager->expects($this->once()) ->method('isOpen') @@ -112,11 +122,17 @@ public function testMiddlewareNoPingInNonWorkerContext() $this->connection->expects($this->never()) ->method('close') ; - $this->connection->expects($this->never()) - ->method('connect') - ; $envelope = new Envelope(new \stdClass()); $this->middleware->handle($envelope, $this->getStackMock()); } + + /** @return AbstractPlatform&MockObject */ + private function mockPlatform(): AbstractPlatform + { + $platform = $this->createMock(AbstractPlatform::class); + $platform->method('getDummySelectSQL')->willReturn('SELECT 1'); + + return $platform; + } } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php b/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php index 4e546b20890c6..e59428783e4dd 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php @@ -178,13 +178,13 @@ public static function provideEndTransactionMethod(): array { return [ 'commit' => [ - static function (Connection $conn): bool { + static function (Connection $conn): ?bool { return $conn->commit(); }, '"COMMIT"', ], 'rollback' => [ - static function (Connection $conn): bool { + static function (Connection $conn): ?bool { return $conn->rollBack(); }, '"ROLLBACK"', @@ -236,7 +236,7 @@ public static function provideExecuteAndEndTransactionMethods(): array static function (Connection $conn, string $sql) { return $conn->executeStatement($sql); }, - static function (Connection $conn): bool { + static function (Connection $conn): ?bool { return $conn->commit(); }, ], @@ -244,7 +244,7 @@ static function (Connection $conn): bool { static function (Connection $conn, string $sql): Result { return $conn->executeQuery($sql); }, - static function (Connection $conn): bool { + static function (Connection $conn): ?bool { return $conn->rollBack(); }, ], @@ -252,7 +252,7 @@ static function (Connection $conn): bool { static function (Connection $conn, string $sql): Result { return $conn->prepare($sql)->executeQuery(); }, - static function (Connection $conn): bool { + static function (Connection $conn): ?bool { return $conn->commit(); }, ], diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineFooType.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineFooType.php index 7c09108fde562..cc2e8154a7c41 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineFooType.php +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineFooType.php @@ -43,10 +43,8 @@ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $pla /** * {@inheritdoc} - * - * @return mixed */ - public function convertToDatabaseValue($value, AbstractPlatform $platform) + public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string { if (null === $value) { return null; @@ -60,10 +58,8 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform) /** * {@inheritdoc} - * - * @return mixed */ - public function convertToPHPValue($value, AbstractPlatform $platform) + public function convertToPHPValue($value, AbstractPlatform $platform): ?Foo { if (null === $value) { return null; diff --git a/src/Symfony/Bridge/Doctrine/Tests/SchemaListener/MessengerTransportDoctrineSchemaSubscriberTest.php b/src/Symfony/Bridge/Doctrine/Tests/SchemaListener/MessengerTransportDoctrineSchemaSubscriberTest.php index ff4ab2c27a19c..f846a4f38225a 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/SchemaListener/MessengerTransportDoctrineSchemaSubscriberTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/SchemaListener/MessengerTransportDoctrineSchemaSubscriberTest.php @@ -49,6 +49,10 @@ public function testPostGenerateSchema() public function testOnSchemaCreateTable() { + if (!class_exists(SchemaCreateTableEventArgs::class)) { + self::markTestSkipped('This test requires DBAL < 4.'); + } + $platform = $this->createMock(AbstractPlatform::class); $table = new Table('queue_table'); $event = new SchemaCreateTableEventArgs($table, [], [], $platform); @@ -80,6 +84,10 @@ public function testOnSchemaCreateTable() public function testOnSchemaCreateTableNoExtraSql() { + if (!class_exists(SchemaCreateTableEventArgs::class)) { + self::markTestSkipped('This test requires DBAL < 4.'); + } + $platform = $this->createMock(AbstractPlatform::class); $table = new Table('queue_table'); $event = new SchemaCreateTableEventArgs($table, [], [], $platform); diff --git a/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php index c1db2bbe70124..6f78bf3ecce92 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php @@ -15,7 +15,7 @@ use Doctrine\DBAL\Platforms\MariaDBPlatform; use Doctrine\DBAL\Platforms\MySQLPlatform; use Doctrine\DBAL\Platforms\PostgreSQLPlatform; -use Doctrine\DBAL\Platforms\SqlitePlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; use Doctrine\DBAL\Types\ConversionException; use Doctrine\DBAL\Types\Type; use PHPUnit\Framework\TestCase; @@ -26,6 +26,9 @@ // DBAL 2 compatibility class_exists('Doctrine\DBAL\Platforms\PostgreSqlPlatform'); +// DBAL 3 compatibility +class_exists('Doctrine\DBAL\Platforms\SqlitePlatform'); + final class UlidTypeTest extends TestCase { private const DUMMY_ULID = '01EEDQEK6ZAZE93J8KG5B4MBJC'; @@ -85,25 +88,25 @@ public function testNotSupportedTypeConversionForDatabaseValue() { $this->expectException(ConversionException::class); - $this->type->convertToDatabaseValue(new \stdClass(), new SqlitePlatform()); + $this->type->convertToDatabaseValue(new \stdClass(), new SQLitePlatform()); } public function testNullConversionForDatabaseValue() { - $this->assertNull($this->type->convertToDatabaseValue(null, new SqlitePlatform())); + $this->assertNull($this->type->convertToDatabaseValue(null, new SQLitePlatform())); } public function testUlidInterfaceConvertsToPHPValue() { $ulid = $this->createMock(AbstractUid::class); - $actual = $this->type->convertToPHPValue($ulid, new SqlitePlatform()); + $actual = $this->type->convertToPHPValue($ulid, new SQLitePlatform()); $this->assertSame($ulid, $actual); } public function testUlidConvertsToPHPValue() { - $ulid = $this->type->convertToPHPValue(self::DUMMY_ULID, new SqlitePlatform()); + $ulid = $this->type->convertToPHPValue(self::DUMMY_ULID, new SQLitePlatform()); $this->assertInstanceOf(Ulid::class, $ulid); $this->assertEquals(self::DUMMY_ULID, $ulid->__toString()); @@ -113,19 +116,19 @@ public function testInvalidUlidConversionForPHPValue() { $this->expectException(ConversionException::class); - $this->type->convertToPHPValue('abcdefg', new SqlitePlatform()); + $this->type->convertToPHPValue('abcdefg', new SQLitePlatform()); } public function testNullConversionForPHPValue() { - $this->assertNull($this->type->convertToPHPValue(null, new SqlitePlatform())); + $this->assertNull($this->type->convertToPHPValue(null, new SQLitePlatform())); } public function testReturnValueIfUlidForPHPValue() { $ulid = new Ulid(); - $this->assertSame($ulid, $this->type->convertToPHPValue($ulid, new SqlitePlatform())); + $this->assertSame($ulid, $this->type->convertToPHPValue($ulid, new SQLitePlatform())); } public function testGetName() @@ -144,7 +147,7 @@ public function testGetGuidTypeDeclarationSQL(AbstractPlatform $platform, string public static function provideSqlDeclarations(): \Generator { yield [new PostgreSQLPlatform(), 'UUID']; - yield [new SqlitePlatform(), 'BLOB']; + yield [new SQLitePlatform(), 'BLOB']; yield [new MySQLPlatform(), 'BINARY(16)']; if (class_exists(MariaDBPlatform::class)) { @@ -154,6 +157,6 @@ public static function provideSqlDeclarations(): \Generator public function testRequiresSQLCommentHint() { - $this->assertTrue($this->type->requiresSQLCommentHint(new SqlitePlatform())); + $this->assertTrue($this->type->requiresSQLCommentHint(new SQLitePlatform())); } } diff --git a/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php b/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php index 003093aec8845..fa1a72fa4eb33 100644 --- a/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php +++ b/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php @@ -13,6 +13,8 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\ConversionException; +use Doctrine\DBAL\Types\Exception\InvalidType; +use Doctrine\DBAL\Types\Exception\ValueNotConvertible; use Doctrine\DBAL\Types\Type; use Symfony\Component\Uid\AbstractUid; @@ -33,7 +35,7 @@ public function getSQLDeclaration(array $column, AbstractPlatform $platform): st } return $platform->getBinaryTypeDeclarationSQL([ - 'length' => '16', + 'length' => 16, 'fixed' => true, ]); } @@ -50,13 +52,13 @@ public function convertToPHPValue($value, AbstractPlatform $platform): ?Abstract } if (!\is_string($value)) { - throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'string', AbstractUid::class]); + $this->throwInvalidType($value); } try { return $this->getUidClass()::fromString($value); } catch (\InvalidArgumentException $e) { - throw ConversionException::conversionFailed($value, $this->getName(), $e); + $this->throwValueNotConvertible($value, $e); } } @@ -78,13 +80,13 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform): ?str } if (!\is_string($value)) { - throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'string', AbstractUid::class]); + $this->throwInvalidType($value); } try { return $this->getUidClass()::fromString($value)->$toString(); } catch (\InvalidArgumentException $e) { - throw ConversionException::conversionFailed($value, $this->getName()); + $this->throwValueNotConvertible($value, $e); } } @@ -105,4 +107,32 @@ private function hasNativeGuidType(AbstractPlatform $platform): bool return $platform->getGuidTypeDeclarationSQL([]) !== $platform->$method(['fixed' => true, 'length' => 36]); } + + /** + * @param mixed $value + * + * @return never + */ + private function throwInvalidType($value): void + { + if (!class_exists(InvalidType::class)) { + throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'string', AbstractUid::class]); + } + + throw InvalidType::new($value, $this->getName(), ['null', 'string', AbstractUid::class]); + } + + /** + * @param mixed $value + * + * @return never + */ + private function throwValueNotConvertible($value, \Throwable $previous): void + { + if (!class_exists(ValueNotConvertible::class)) { + throw ConversionException::conversionFailed($value, $this->getName(), $previous); + } + + throw ValueNotConvertible::new($value, $this->getName(), null, $previous); + } } From a004c1285234443929d5824924db7e2faebc1c1c Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 13 Oct 2023 14:03:48 +0200 Subject: [PATCH 52/79] [Cache] Add missing `@requires extension openssl` --- src/Symfony/Component/Cache/Tests/Traits/RedisProxiesTest.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Symfony/Component/Cache/Tests/Traits/RedisProxiesTest.php b/src/Symfony/Component/Cache/Tests/Traits/RedisProxiesTest.php index 83963fcecf9bd..71f843e23d598 100644 --- a/src/Symfony/Component/Cache/Tests/Traits/RedisProxiesTest.php +++ b/src/Symfony/Component/Cache/Tests/Traits/RedisProxiesTest.php @@ -79,6 +79,8 @@ public function testRelayProxy() } /** + * @requires extension openssl + * * @testWith ["Redis", "redis"] * ["RedisCluster", "redis_cluster"] */ From b28e3cfd52431bfd151ebc365d74e6eff2e30cb0 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 13 Oct 2023 15:38:18 +0200 Subject: [PATCH 53/79] [Cache] Fix leftovers in generated Redis proxies --- src/Symfony/Component/Cache/Traits/Redis5Proxy.php | 8 ++++---- src/Symfony/Component/Cache/Traits/RedisCluster5Proxy.php | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/Cache/Traits/Redis5Proxy.php b/src/Symfony/Component/Cache/Traits/Redis5Proxy.php index b835e553a216d..06130cc33b9cc 100644 --- a/src/Symfony/Component/Cache/Traits/Redis5Proxy.php +++ b/src/Symfony/Component/Cache/Traits/Redis5Proxy.php @@ -428,7 +428,7 @@ public function hVals($key) public function hscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hscan($str_key, $i_iterator, $str_pattern, $i_count, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hscan($str_key, $i_iterator, ...\array_slice(\func_get_args(), 2)); } public function incr($key) @@ -748,7 +748,7 @@ public function save() public function scan(&$i_iterator, $str_pattern = null, $i_count = null) { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scan($i_iterator, $str_pattern, $i_count, ...\array_slice(\func_get_args(), 3)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scan($i_iterator, ...\array_slice(\func_get_args(), 1)); } public function scard($key) @@ -843,7 +843,7 @@ public function srem($key, $member, ...$other_members) public function sscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sscan($str_key, $i_iterator, $str_pattern, $i_count, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sscan($str_key, $i_iterator, ...\array_slice(\func_get_args(), 2)); } public function strlen($key) @@ -1073,7 +1073,7 @@ public function zinterstore($key, $keys, $weights = null, $aggregate = null) public function zscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscan($str_key, $i_iterator, $str_pattern, $i_count, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscan($str_key, $i_iterator, ...\array_slice(\func_get_args(), 2)); } public function zunionstore($key, $keys, $weights = null, $aggregate = null) diff --git a/src/Symfony/Component/Cache/Traits/RedisCluster5Proxy.php b/src/Symfony/Component/Cache/Traits/RedisCluster5Proxy.php index 6e3f172e75b1d..da23e0f881e1b 100644 --- a/src/Symfony/Component/Cache/Traits/RedisCluster5Proxy.php +++ b/src/Symfony/Component/Cache/Traits/RedisCluster5Proxy.php @@ -373,7 +373,7 @@ public function hmset($key, $pairs) public function hscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hscan($str_key, $i_iterator, $str_pattern, $i_count, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->hscan($str_key, $i_iterator, ...\array_slice(\func_get_args(), 2)); } public function hset($key, $member, $value) @@ -638,7 +638,7 @@ public function save($key_or_address) public function scan(&$i_iterator, $str_node, $str_pattern = null, $i_count = null) { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scan($i_iterator, $str_node, $str_pattern, $i_count, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->scan($i_iterator, ...\array_slice(\func_get_args(), 1)); } public function scard($key) @@ -743,7 +743,7 @@ public function srem($key, $value) public function sscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sscan($str_key, $i_iterator, $str_pattern, $i_count, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->sscan($str_key, $i_iterator, ...\array_slice(\func_get_args(), 2)); } public function strlen($key) @@ -968,7 +968,7 @@ public function zrevrank($key, $member) public function zscan($str_key, &$i_iterator, $str_pattern = null, $i_count = null) { - return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscan($str_key, $i_iterator, $str_pattern, $i_count, ...\array_slice(\func_get_args(), 4)); + return ($this->lazyObjectState->realInstance ??= ($this->lazyObjectState->initializer)())->zscan($str_key, $i_iterator, ...\array_slice(\func_get_args(), 2)); } public function zscore($key, $member) From f601638291a06030bb8a5895638c99ae55b78546 Mon Sep 17 00:00:00 2001 From: Oleksii Bulba Date: Fri, 13 Oct 2023 15:54:26 +0300 Subject: [PATCH 54/79] #51928 Missing translations for Belarusian (be) - Added missing translations for Belarusian (be); --- .../Resources/translations/validators.be.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf index 648955684baa0..d9fcd93b808f9 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Значэнне сеткавай маскі павінна быць ад {{min}} да {{max}}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Назва файла занадта доўгая. Ён павінен мець {{ filename_max_length }} сімвал або менш.|Назва файла занадта доўгая. Ён павінен мець {{ filename_max_length }} сімвалы або менш.|Назва файла занадта доўгая. Ён павінен мець {{ filename_max_length }} сімвалаў або менш. + + + The password strength is too low. Please use a stronger password. + Надзейнасць пароля занадта нізкая. Выкарыстоўвайце больш надзейны пароль. + + + This value contains characters that are not allowed by the current restriction-level. + Гэта значэнне змяшчае сімвалы, якія не дазволены цяперашнім узроўнем абмежаванняў. + + + Using invisible characters is not allowed. + Выкарыстанне нябачных сімвалаў не дазваляецца. + + + Mixing numbers from different scripts is not allowed. + Змешванне лікаў з розных алфавітаў не дапускаецца. + + + Using hidden overlay characters is not allowed. + Выкарыстанне схаваных накладзеных сімвалаў не дазваляецца. + From 5b0cf25ba98fe07a581618bbc97f1441dbd705e5 Mon Sep 17 00:00:00 2001 From: Javier Ledezma Date: Wed, 11 Oct 2023 21:21:37 -0600 Subject: [PATCH 55/79] [Translation] Prevent creating empty keys when key ends with a period [Translation] create getKeyParts() to keep periods at start or end of the key [Translation] Simplify test cases by removing blank spaces --- .../Tests/Util/ArrayConverterTest.php | 28 ++++++++++++ .../Translation/Util/ArrayConverter.php | 44 ++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Translation/Tests/Util/ArrayConverterTest.php b/src/Symfony/Component/Translation/Tests/Util/ArrayConverterTest.php index 8936ef1ae6926..446130cc477a5 100644 --- a/src/Symfony/Component/Translation/Tests/Util/ArrayConverterTest.php +++ b/src/Symfony/Component/Translation/Tests/Util/ArrayConverterTest.php @@ -69,6 +69,34 @@ public static function messagesData() ], ], ], + [ + // input + [ + 'foo.' => 'foo.', + '.bar' => '.bar', + 'abc.abc' => 'value', + 'bcd.bcd.' => 'value', + '.cde.cde.' => 'value', + '.def.def' => 'value', + ], + // expected output + [ + 'foo.' => 'foo.', + '.bar' => '.bar', + 'abc' => [ + 'abc' => 'value', + ], + 'bcd' => [ + 'bcd.' => 'value', + ], + '.cde' => [ + 'cde.' => 'value', + ], + '.def' => [ + 'def' => 'value', + ], + ], + ], ]; } } diff --git a/src/Symfony/Component/Translation/Util/ArrayConverter.php b/src/Symfony/Component/Translation/Util/ArrayConverter.php index f69c2e3c6481d..e132e3decfcdd 100644 --- a/src/Symfony/Component/Translation/Util/ArrayConverter.php +++ b/src/Symfony/Component/Translation/Util/ArrayConverter.php @@ -38,7 +38,7 @@ public static function expandToTree(array $messages) $tree = []; foreach ($messages as $id => $value) { - $referenceToElement = &self::getElementByPath($tree, explode('.', $id)); + $referenceToElement = &self::getElementByPath($tree, self::getKeyParts($id)); $referenceToElement = $value; @@ -65,6 +65,7 @@ private static function &getElementByPath(array &$tree, array $parts) $elem = &$elem[implode('.', \array_slice($parts, $i))]; break; } + $parentOfElem = &$elem; $elem = &$elem[$part]; } @@ -96,4 +97,45 @@ private static function cancelExpand(array &$tree, string $prefix, array $node) } } } + + private static function getKeyParts(string $key) + { + $parts = explode('.', $key); + $partsCount = \count($parts); + + $result = []; + $buffer = ''; + + foreach ($parts as $index => $part) { + if (0 === $index && '' === $part) { + $buffer = '.'; + + continue; + } + + if ($index === $partsCount - 1 && '' === $part) { + $buffer .= '.'; + $result[] = $buffer; + + continue; + } + + if (isset($parts[$index + 1]) && '' === $parts[$index + 1]) { + $buffer .= $part; + + continue; + } + + if ($buffer) { + $result[] = $buffer.$part; + $buffer = ''; + + continue; + } + + $result[] = $part; + } + + return $result; + } } From 6b5a36248bf5a7f56427eb6778d83b7a7092e0f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ramon=20Cu=C3=B1at?= Date: Sat, 14 Oct 2023 11:09:35 +0200 Subject: [PATCH 56/79] [Validator] add missing catalan translations Solves #51932 --- .../Resources/translations/validators.ca.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf index 04f3e9abf211e..d6d925ecc5814 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. El valor de la màscara de xarxa hauria d'estar entre {{ min }} i {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + El nom del fitxer és massa llarg. Ha de tenir {{ filename_max_length }} caràcter o menys.|El nom del fitxer és massa llarg. Ha de tenir {{ filename_max_length }} caràcters o menys. + + + The password strength is too low. Please use a stronger password. + La contrasenya és massa feble. Si us plau, feu servir una contrasenya més segura. + + + This value contains characters that are not allowed by the current restriction-level. + Aquest valor conté caràcters que no estan permisos segons el nivell de restricció actual. + + + Using invisible characters is not allowed. + No es permet l'ús de caràcters invisibles. + + + Mixing numbers from different scripts is not allowed. + No es permet barrejar números de diferents scripts. + + + Using hidden overlay characters is not allowed. + No es permet l'ús de caràcters superposats ocults. + From 2aacd2249c0d7cf6f6c5068d7f71a5426dfb42ea Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Sat, 14 Oct 2023 18:25:31 +0200 Subject: [PATCH 57/79] [Translation] Add missing return type --- src/Symfony/Component/Translation/Util/ArrayConverter.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Translation/Util/ArrayConverter.php b/src/Symfony/Component/Translation/Util/ArrayConverter.php index e132e3decfcdd..cbab0c5909b19 100644 --- a/src/Symfony/Component/Translation/Util/ArrayConverter.php +++ b/src/Symfony/Component/Translation/Util/ArrayConverter.php @@ -98,7 +98,10 @@ private static function cancelExpand(array &$tree, string $prefix, array $node) } } - private static function getKeyParts(string $key) + /** + * @return string[] + */ + private static function getKeyParts(string $key): array { $parts = explode('.', $key); $partsCount = \count($parts); From fa661b53d8b8ed9a6bb0e065b02d1f159b9bc99d Mon Sep 17 00:00:00 2001 From: "Roland Franssen :)" Date: Mon, 16 Oct 2023 15:31:00 +0200 Subject: [PATCH 58/79] [Messenger] Fix DoctrineOpenTransactionLoggerMiddleware --- .../DoctrineOpenTransactionLoggerMiddleware.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Symfony/Bridge/Doctrine/Messenger/DoctrineOpenTransactionLoggerMiddleware.php b/src/Symfony/Bridge/Doctrine/Messenger/DoctrineOpenTransactionLoggerMiddleware.php index 246f0090e58ef..40adcbabae59f 100644 --- a/src/Symfony/Bridge/Doctrine/Messenger/DoctrineOpenTransactionLoggerMiddleware.php +++ b/src/Symfony/Bridge/Doctrine/Messenger/DoctrineOpenTransactionLoggerMiddleware.php @@ -26,6 +26,8 @@ class DoctrineOpenTransactionLoggerMiddleware extends AbstractDoctrineMiddleware { private $logger; + /** @var bool */ + private $isHandling = false; public function __construct(ManagerRegistry $managerRegistry, string $entityManagerName = null, LoggerInterface $logger = null) { @@ -36,6 +38,12 @@ public function __construct(ManagerRegistry $managerRegistry, string $entityMana protected function handleForManager(EntityManagerInterface $entityManager, Envelope $envelope, StackInterface $stack): Envelope { + if ($this->isHandling) { + return $stack->next()->handle($envelope, $stack); + } + + $this->isHandling = true; + try { return $stack->next()->handle($envelope, $stack); } finally { @@ -44,6 +52,7 @@ protected function handleForManager(EntityManagerInterface $entityManager, Envel 'message' => $envelope->getMessage(), ]); } + $this->isHandling = false; } } } From b270382f1f599efa0f833ab01693a29c60551bd8 Mon Sep 17 00:00:00 2001 From: HypeMC Date: Mon, 16 Oct 2023 19:35:29 +0200 Subject: [PATCH 59/79] [Messenger] Fix graceful exit --- .../Command/ConsumeMessagesCommand.php | 2 +- .../Command/FailedMessagesRetryCommand.php | 22 ++++++++++++++++--- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php index 5302d560f8d94..f430a28b4bfe2 100644 --- a/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php +++ b/src/Symfony/Component/Messenger/Command/ConsumeMessagesCommand.php @@ -271,7 +271,7 @@ public function handleSignal(int $signal, int|false $previousExitCode = 0): int| $this->worker->stop(); - return 0; + return false; } private function convertToBytes(string $memoryLimit): int diff --git a/src/Symfony/Component/Messenger/Command/FailedMessagesRetryCommand.php b/src/Symfony/Component/Messenger/Command/FailedMessagesRetryCommand.php index c85f2094127e6..adea535a7e6ae 100644 --- a/src/Symfony/Component/Messenger/Command/FailedMessagesRetryCommand.php +++ b/src/Symfony/Component/Messenger/Command/FailedMessagesRetryCommand.php @@ -43,6 +43,8 @@ class FailedMessagesRetryCommand extends AbstractFailedMessagesCommand implement private MessageBusInterface $messageBus; private ?LoggerInterface $logger; private ?array $signals; + private bool $shouldStop = false; + private bool $forceExit = false; private ?Worker $worker = null; public function __construct(?string $globalReceiverName, ServiceProviderInterface $failureTransports, MessageBusInterface $messageBus, EventDispatcherInterface $eventDispatcher, LoggerInterface $logger = null, PhpSerializer $phpSerializer = null, array $signals = null) @@ -141,8 +143,9 @@ public function handleSignal(int $signal, int|false $previousExitCode = 0): int| $this->logger?->info('Received signal {signal}.', ['signal' => $signal, 'transport_names' => $this->worker->getMetadata()->getTransportNames()]); $this->worker->stop(); + $this->shouldStop = true; - return 0; + return $this->forceExit ? 0 : false; } private function runInteractive(string $failureTransportName, SymfonyStyle $io, bool $shouldForce): void @@ -156,6 +159,10 @@ private function runInteractive(string $failureTransportName, SymfonyStyle $io, // to be temporarily "acked", even if the user aborts // handling the message while (true) { + if ($this->shouldStop) { + break; + } + $envelopes = []; $this->phpSerializer?->acceptPhpIncompleteClass(); try { @@ -180,7 +187,7 @@ private function runInteractive(string $failureTransportName, SymfonyStyle $io, } // avoid success message if nothing was processed - if (1 <= $count) { + if (1 <= $count && !$this->shouldStop) { $io->success('All failed messages have been handled or removed!'); } } @@ -198,7 +205,12 @@ private function runWorker(string $failureTransportName, ReceiverInterface $rece throw new \RuntimeException(sprintf('The message with id "%s" could not decoded, it can only be shown or removed.', $this->getMessageId($envelope) ?? '?')); } - $shouldHandle = $shouldForce || 'retry' === $io->choice('Please select an action', ['retry', 'delete'], 'retry'); + $this->forceExit = true; + try { + $shouldHandle = $shouldForce || 'retry' === $io->choice('Please select an action', ['retry', 'delete'], 'retry'); + } finally { + $this->forceExit = false; + } if ($shouldHandle) { return; @@ -257,6 +269,10 @@ private function retrySpecificEnvelopes(array $envelopes, string $failureTranspo foreach ($envelopes as $envelope) { $singleReceiver = new SingleMessageReceiver($receiver, $envelope); $this->runWorker($failureTransportName, $singleReceiver, $io, $shouldForce); + + if ($this->shouldStop) { + break; + } } } } From 49a452d0de11553ebf5874e25e78906d523e6eb8 Mon Sep 17 00:00:00 2001 From: HypeMC Date: Tue, 17 Oct 2023 01:28:54 +0200 Subject: [PATCH 60/79] [Messenger] Simplify code --- .../Messenger/Command/FailedMessagesRetryCommand.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/Symfony/Component/Messenger/Command/FailedMessagesRetryCommand.php b/src/Symfony/Component/Messenger/Command/FailedMessagesRetryCommand.php index adea535a7e6ae..3bf4f81c03f7c 100644 --- a/src/Symfony/Component/Messenger/Command/FailedMessagesRetryCommand.php +++ b/src/Symfony/Component/Messenger/Command/FailedMessagesRetryCommand.php @@ -158,11 +158,7 @@ private function runInteractive(string $failureTransportName, SymfonyStyle $io, // transports (like Doctrine), will cause the message // to be temporarily "acked", even if the user aborts // handling the message - while (true) { - if ($this->shouldStop) { - break; - } - + while (!$this->shouldStop) { $envelopes = []; $this->phpSerializer?->acceptPhpIncompleteClass(); try { From 0f398cebb02e550a8f6e4493c7dde9a11f5d23ad Mon Sep 17 00:00:00 2001 From: HypeMC Date: Sat, 7 Oct 2023 17:47:31 +0200 Subject: [PATCH 61/79] [Serializer] Fix collecting only first missing constructor argument --- .../Normalizer/AbstractNormalizer.php | 31 +++---- .../Php80WithPromotedTypedConstructor.php | 7 +- .../Tests/Fixtures/WithTypedConstructor.php | 35 ++++++++ .../ConstructorArgumentsTestTrait.php | 27 ++++++- .../Serializer/Tests/SerializerTest.php | 80 +++++++++++++++++++ 5 files changed, 161 insertions(+), 19 deletions(-) create mode 100644 src/Symfony/Component/Serializer/Tests/Fixtures/WithTypedConstructor.php diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index 4fcae7d99cfcc..5c88e4455e09c 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -348,7 +348,7 @@ protected function instantiateObject(array &$data, string $class, array &$contex } $constructorParameters = $constructor->getParameters(); - + $missingConstructorArguments = []; $params = []; foreach ($constructorParameters as $constructorParameter) { $paramName = $constructorParameter->name; @@ -401,7 +401,8 @@ protected function instantiateObject(array &$data, string $class, array &$contex $params[] = null; } else { if (!isset($context['not_normalizable_value_exceptions'])) { - throw new MissingConstructorArgumentsException(sprintf('Cannot create an instance of "%s" from serialized data because its constructor requires parameter "%s" to be present.', $class, $constructorParameter->name), 0, null, [$constructorParameter->name]); + $missingConstructorArguments[] = $constructorParameter->name; + continue; } $exception = NotNormalizableValueException::createForUnexpectedDataType( @@ -412,24 +413,26 @@ protected function instantiateObject(array &$data, string $class, array &$contex true ); $context['not_normalizable_value_exceptions'][] = $exception; - - return $reflectionClass->newInstanceWithoutConstructor(); } } - if ($constructor->isConstructor()) { - try { - return $reflectionClass->newInstanceArgs($params); - } catch (\TypeError $th) { - if (!isset($context['not_normalizable_value_exceptions'])) { - throw $th; - } + if ($missingConstructorArguments) { + throw new MissingConstructorArgumentsException(sprintf('Cannot create an instance of "%s" from serialized data because its constructor requires the following parameters to be present : "$%s".', $class, implode('", "$', $missingConstructorArguments)), 0, null, $missingConstructorArguments); + } - return $reflectionClass->newInstanceWithoutConstructor(); - } - } else { + if (!$constructor->isConstructor()) { return $constructor->invokeArgs(null, $params); } + + try { + return $reflectionClass->newInstanceArgs($params); + } catch (\TypeError $e) { + if (!isset($context['not_normalizable_value_exceptions'])) { + throw $e; + } + + return $reflectionClass->newInstanceWithoutConstructor(); + } } unset($context['has_constructor']); diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/Php80WithPromotedTypedConstructor.php b/src/Symfony/Component/Serializer/Tests/Fixtures/Php80WithPromotedTypedConstructor.php index be3247450ba79..a7b79aa47dcae 100644 --- a/src/Symfony/Component/Serializer/Tests/Fixtures/Php80WithPromotedTypedConstructor.php +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/Php80WithPromotedTypedConstructor.php @@ -13,7 +13,10 @@ final class Php80WithPromotedTypedConstructor { - public function __construct(public bool $bool) - { + public function __construct( + public bool $bool, + public string $string, + public int $int, + ) { } } diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/WithTypedConstructor.php b/src/Symfony/Component/Serializer/Tests/Fixtures/WithTypedConstructor.php new file mode 100644 index 0000000000000..734d1c83b24d9 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/WithTypedConstructor.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +final class WithTypedConstructor +{ + /** + * @var string + */ + public $string; + /** + * @var bool + */ + public $bool; + /** + * @var int + */ + public $int; + + public function __construct(string $string, bool $bool, int $int) + { + $this->string = $string; + $this->bool = $bool; + $this->int = $int; + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/Features/ConstructorArgumentsTestTrait.php b/src/Symfony/Component/Serializer/Tests/Normalizer/Features/ConstructorArgumentsTestTrait.php index 306c571f9c59d..f7e18241c7210 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/Features/ConstructorArgumentsTestTrait.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/Features/ConstructorArgumentsTestTrait.php @@ -62,9 +62,30 @@ public function testConstructorWithMissingData() ]; $normalizer = $this->getDenormalizerForConstructArguments(); + try { + $normalizer->denormalize($data, ConstructorArgumentsObject::class); + self::fail(sprintf('Failed asserting that exception of type "%s" is thrown.', MissingConstructorArgumentsException::class)); + } catch (MissingConstructorArgumentsException $e) { + self::assertSame(sprintf('Cannot create an instance of "%s" from serialized data because its constructor requires the following parameters to be present : "$bar", "$baz".', ConstructorArgumentsObject::class), $e->getMessage()); + self::assertSame(['bar', 'baz'], $e->getMissingConstructorArguments()); + } + } + + public function testExceptionsAreCollectedForConstructorWithMissingData() + { + $data = [ + 'foo' => 10, + ]; + + $exceptions = []; + + $normalizer = $this->getDenormalizerForConstructArguments(); + $normalizer->denormalize($data, ConstructorArgumentsObject::class, null, [ + 'not_normalizable_value_exceptions' => &$exceptions, + ]); - $this->expectException(MissingConstructorArgumentsException::class); - $this->expectExceptionMessage('Cannot create an instance of "'.ConstructorArgumentsObject::class.'" from serialized data because its constructor requires parameter "bar" to be present.'); - $normalizer->denormalize($data, ConstructorArgumentsObject::class); + self::assertCount(2, $exceptions); + self::assertSame('Failed to create object because the class misses the "bar" property.', $exceptions[0]->getMessage()); + self::assertSame('Failed to create object because the class misses the "baz" property.', $exceptions[1]->getMessage()); } } diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index 2141c0cf6d334..fdd98d0be5b5a 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -67,6 +67,7 @@ use Symfony\Component\Serializer\Tests\Fixtures\Php74Full; use Symfony\Component\Serializer\Tests\Fixtures\Php80WithPromotedTypedConstructor; use Symfony\Component\Serializer\Tests\Fixtures\TraversableDummy; +use Symfony\Component\Serializer\Tests\Fixtures\WithTypedConstructor; use Symfony\Component\Serializer\Tests\Normalizer\TestDenormalizer; use Symfony\Component\Serializer\Tests\Normalizer\TestNormalizer; @@ -1196,6 +1197,85 @@ public function testCollectDenormalizationErrorsWithConstructor(?ClassMetadataFa 'useMessageForUser' => false, 'message' => 'The type of the "bool" attribute for class "Symfony\\Component\\Serializer\\Tests\\Fixtures\\Php80WithPromotedTypedConstructor" must be one of "bool" ("string" given).', ], + [ + 'currentType' => 'array', + 'expectedTypes' => [ + 'unknown', + ], + 'path' => null, + 'useMessageForUser' => true, + 'message' => 'Failed to create object because the class misses the "string" property.', + ], + [ + 'currentType' => 'array', + 'expectedTypes' => [ + 'unknown', + ], + 'path' => null, + 'useMessageForUser' => true, + 'message' => 'Failed to create object because the class misses the "int" property.', + ], + ]; + + $this->assertSame($expected, $exceptionsAsArray); + } + + public function testCollectDenormalizationErrorsWithInvalidConstructorTypes() + { + $json = '{"string": "some string", "bool": "bool", "int": true}'; + + $extractor = new PropertyInfoExtractor([], [new ReflectionExtractor()]); + + $serializer = new Serializer( + [new ObjectNormalizer(null, null, null, $extractor)], + ['json' => new JsonEncoder()] + ); + + try { + $serializer->deserialize($json, WithTypedConstructor::class, 'json', [ + DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true, + ]); + + $this->fail(); + } catch (\Throwable $th) { + $this->assertInstanceOf(PartialDenormalizationException::class, $th); + } + + $this->assertInstanceOf(WithTypedConstructor::class, $object = $th->getData()); + + $this->assertSame('some string', $object->string); + $this->assertTrue($object->bool); + $this->assertSame(1, $object->int); + + $exceptionsAsArray = array_map(function (NotNormalizableValueException $e): array { + return [ + 'currentType' => $e->getCurrentType(), + 'expectedTypes' => $e->getExpectedTypes(), + 'path' => $e->getPath(), + 'useMessageForUser' => $e->canUseMessageForUser(), + 'message' => $e->getMessage(), + ]; + }, $th->getErrors()); + + $expected = [ + [ + 'currentType' => 'string', + 'expectedTypes' => [ + 0 => 'bool', + ], + 'path' => 'bool', + 'useMessageForUser' => false, + 'message' => 'The type of the "bool" attribute for class "Symfony\Component\Serializer\Tests\Fixtures\WithTypedConstructor" must be one of "bool" ("string" given).', + ], + [ + 'currentType' => 'bool', + 'expectedTypes' => [ + 0 => 'int', + ], + 'path' => 'int', + 'useMessageForUser' => false, + 'message' => 'The type of the "int" attribute for class "Symfony\Component\Serializer\Tests\Fixtures\WithTypedConstructor" must be one of "int" ("bool" given).', + ], ]; $this->assertSame($expected, $exceptionsAsArray); From 8ae89938713d54f3fe8a627c0907d693107d5c70 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Tue, 17 Oct 2023 10:37:39 +0200 Subject: [PATCH 62/79] Handle Sendinblue error responses without a message key --- .../Bridge/Sendinblue/Transport/SendinblueApiTransport.php | 2 +- .../Notifier/Bridge/Sendinblue/SendinblueTransport.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Mailer/Bridge/Sendinblue/Transport/SendinblueApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Sendinblue/Transport/SendinblueApiTransport.php index 0a43deb97f65d..110ad48f1a077 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendinblue/Transport/SendinblueApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendinblue/Transport/SendinblueApiTransport.php @@ -65,7 +65,7 @@ protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $e } if (201 !== $statusCode) { - throw new HttpTransportException('Unable to send an email: '.$result['message'].sprintf(' (code %d).', $statusCode), $response); + throw new HttpTransportException('Unable to send an email: '.($result['message'] ?? $response->getContent(false)).sprintf(' (code %d).', $statusCode), $response); } $sentMessage->setMessageId($result['messageId']); diff --git a/src/Symfony/Component/Notifier/Bridge/Sendinblue/SendinblueTransport.php b/src/Symfony/Component/Notifier/Bridge/Sendinblue/SendinblueTransport.php index b554cfef9f67b..d8709f7d1e960 100644 --- a/src/Symfony/Component/Notifier/Bridge/Sendinblue/SendinblueTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Sendinblue/SendinblueTransport.php @@ -75,7 +75,7 @@ protected function doSend(MessageInterface $message): SentMessage if (201 !== $statusCode) { $error = $response->toArray(false); - throw new TransportException('Unable to send the SMS: '.$error['message'], $response); + throw new TransportException('Unable to send the SMS: '.($error['message'] ?? $response->getContent(false)), $response); } $success = $response->toArray(false); From 77ca01ca7a48d8f19bbb405cb76e0884bb032355 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 2 Oct 2023 23:04:54 +0200 Subject: [PATCH 63/79] [HttpFoundation] Do not swallow trailing `=` in cookie value --- .../Component/HttpFoundation/HeaderUtils.php | 63 ++++++++++--------- .../HttpFoundation/Tests/CookieTest.php | 3 + .../HttpFoundation/Tests/HeaderUtilsTest.php | 6 +- 3 files changed, 39 insertions(+), 33 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/HeaderUtils.php b/src/Symfony/Component/HttpFoundation/HeaderUtils.php index 46b1e6aed60fb..f91c7e1d97d86 100644 --- a/src/Symfony/Component/HttpFoundation/HeaderUtils.php +++ b/src/Symfony/Component/HttpFoundation/HeaderUtils.php @@ -33,17 +33,21 @@ private function __construct() * * Example: * - * HeaderUtils::split("da, en-gb;q=0.8", ",;") + * HeaderUtils::split('da, en-gb;q=0.8', ',;') * // => ['da'], ['en-gb', 'q=0.8']] * * @param string $separators List of characters to split on, ordered by - * precedence, e.g. ",", ";=", or ",;=" + * precedence, e.g. ',', ';=', or ',;=' * * @return array Nested array with as many levels as there are characters in * $separators */ public static function split(string $header, string $separators): array { + if ('' === $separators) { + throw new \InvalidArgumentException('At least one separator must be specified.'); + } + $quotedSeparators = preg_quote($separators, '/'); preg_match_all(' @@ -77,8 +81,8 @@ public static function split(string $header, string $separators): array * * Example: * - * HeaderUtils::combine([["foo", "abc"], ["bar"]]) - * // => ["foo" => "abc", "bar" => true] + * HeaderUtils::combine([['foo', 'abc'], ['bar']]) + * // => ['foo' => 'abc', 'bar' => true] */ public static function combine(array $parts): array { @@ -95,13 +99,13 @@ public static function combine(array $parts): array /** * Joins an associative array into a string for use in an HTTP header. * - * The key and value of each entry are joined with "=", and all entries + * The key and value of each entry are joined with '=', and all entries * are joined with the specified separator and an additional space (for * readability). Values are quoted if necessary. * * Example: * - * HeaderUtils::toString(["foo" => "abc", "bar" => true, "baz" => "a b c"], ",") + * HeaderUtils::toString(['foo' => 'abc', 'bar' => true, 'baz' => 'a b c'], ',') * // => 'foo=abc, bar, baz="a b c"' */ public static function toString(array $assoc, string $separator): string @@ -252,40 +256,37 @@ public static function parseQuery(string $query, bool $ignoreBrackets = false, s private static function groupParts(array $matches, string $separators, bool $first = true): array { $separator = $separators[0]; - $partSeparators = substr($separators, 1); - + $separators = substr($separators, 1); $i = 0; + + if ('' === $separators && !$first) { + $parts = ['']; + + foreach ($matches as $match) { + if (!$i && isset($match['separator'])) { + $i = 1; + $parts[1] = ''; + } else { + $parts[$i] .= self::unquote($match[0]); + } + } + + return $parts; + } + + $parts = []; $partMatches = []; - $previousMatchWasSeparator = false; + foreach ($matches as $match) { - if (!$first && $previousMatchWasSeparator && isset($match['separator']) && $match['separator'] === $separator) { - $previousMatchWasSeparator = true; - $partMatches[$i][] = $match; - } elseif (isset($match['separator']) && $match['separator'] === $separator) { - $previousMatchWasSeparator = true; + if (($match['separator'] ?? null) === $separator) { ++$i; } else { - $previousMatchWasSeparator = false; $partMatches[$i][] = $match; } } - $parts = []; - if ($partSeparators) { - foreach ($partMatches as $matches) { - $parts[] = self::groupParts($matches, $partSeparators, false); - } - } else { - foreach ($partMatches as $matches) { - $parts[] = self::unquote($matches[0][0]); - } - - if (!$first && 2 < \count($parts)) { - $parts = [ - $parts[0], - implode($separator, \array_slice($parts, 1)), - ]; - } + foreach ($partMatches as $matches) { + $parts[] = '' === $separators ? self::unquote($matches[0][0]) : self::groupParts($matches, $separators, false); } return $parts; diff --git a/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php b/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php index ec5a4e28f406a..9cc0d9fb8cb1d 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php @@ -324,6 +324,9 @@ public function testFromString() $cookie = Cookie::fromString('foo=bar', true); $this->assertEquals(Cookie::create('foo', 'bar', 0, '/', null, false, false, false, null), $cookie); + $cookie = Cookie::fromString('foo=bar=', true); + $this->assertEquals(Cookie::create('foo', 'bar=', 0, '/', null, false, false, false, null), $cookie); + $cookie = Cookie::fromString('foo', true); $this->assertEquals(Cookie::create('foo', null, 0, '/', null, false, false, false, null), $cookie); diff --git a/src/Symfony/Component/HttpFoundation/Tests/HeaderUtilsTest.php b/src/Symfony/Component/HttpFoundation/Tests/HeaderUtilsTest.php index 73d3f150c7a8e..befa4aea035a5 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/HeaderUtilsTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/HeaderUtilsTest.php @@ -34,7 +34,7 @@ public static function provideHeaderToSplit(): array [['foo', '123, bar'], 'foo=123, bar', '='], [['foo', '123, bar'], ' foo = 123, bar ', '='], [[['foo', '123'], ['bar']], 'foo=123, bar', ',='], - [[[['foo', '123']], [['bar'], ['foo', '456']]], 'foo=123, bar; foo=456', ',;='], + [[[['foo', '123']], [['bar'], ['foo', '456']]], 'foo=123, bar;; foo=456', ',;='], [[[['foo', 'a,b;c=d']]], 'foo="a,b;c=d"', ',;='], [['foo', 'bar'], 'foo,,,, bar', ','], @@ -46,13 +46,15 @@ public static function provideHeaderToSplit(): array [[['foo_cookie', 'foo=1&bar=2&baz=3'], ['expires', 'Tue, 22-Sep-2020 06:27:09 GMT'], ['path', '/']], 'foo_cookie=foo=1&bar=2&baz=3; expires=Tue, 22-Sep-2020 06:27:09 GMT; path=/', ';='], [[['foo_cookie', 'foo=='], ['expires', 'Tue, 22-Sep-2020 06:27:09 GMT'], ['path', '/']], 'foo_cookie=foo==; expires=Tue, 22-Sep-2020 06:27:09 GMT; path=/', ';='], + [[['foo_cookie', 'foo='], ['expires', 'Tue, 22-Sep-2020 06:27:09 GMT'], ['path', '/']], 'foo_cookie=foo=; expires=Tue, 22-Sep-2020 06:27:09 GMT; path=/', ';='], [[['foo_cookie', 'foo=a=b'], ['expires', 'Tue, 22-Sep-2020 06:27:09 GMT'], ['path', '/']], 'foo_cookie=foo="a=b"; expires=Tue, 22-Sep-2020 06:27:09 GMT; path=/', ';='], // These are not a valid header values. We test that they parse anyway, // and that both the valid and invalid parts are returned. [[], '', ','], [[], ',,,', ','], - [['foo', 'bar', 'baz'], 'foo, "bar", "baz', ','], + [[['', 'foo'], ['bar', '']], '=foo,bar=', ',='], + [['foo', 'foobar', 'baz'], 'foo, foo"bar", "baz', ','], [['foo', 'bar, baz'], 'foo, "bar, baz', ','], [['foo', 'bar, baz\\'], 'foo, "bar, baz\\', ','], [['foo', 'bar, baz\\'], 'foo, "bar, baz\\\\', ','], From 4da09bc891d0c11a8724f1c5ffc559525272634a Mon Sep 17 00:00:00 2001 From: Priyadi Iman Nurcahyo Date: Thu, 12 Oct 2023 23:56:38 +0700 Subject: [PATCH 64/79] [Form] Fix merging params & files when "multiple" is enabled If a form field is configured with the "multiple" option, the request handler merges param values with uploaded files. However, it does not merge correctly if "multiple" is enabled. Example: With the example, the file field will incorrectly replace the first hidden field, when they should be merged. This commit fixes the problem. --- .../HttpFoundationRequestHandler.php | 3 +- .../Component/Form/NativeRequestHandler.php | 3 +- .../Tests/AbstractRequestHandlerTestCase.php | 36 +++++++++++++++++++ src/Symfony/Component/Form/Util/FormUtil.php | 25 +++++++++++++ 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php index 05503ff52977f..90723fd8b48a9 100644 --- a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php +++ b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php @@ -15,6 +15,7 @@ use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\RequestHandlerInterface; +use Symfony\Component\Form\Util\FormUtil; use Symfony\Component\Form\Util\ServerParams; use Symfony\Component\HttpFoundation\File\File; use Symfony\Component\HttpFoundation\File\UploadedFile; @@ -95,7 +96,7 @@ public function handleRequest(FormInterface $form, $request = null) } if (\is_array($params) && \is_array($files)) { - $data = array_replace_recursive($params, $files); + $data = FormUtil::mergeParamsAndFiles($params, $files); } else { $data = $params ?: $files; } diff --git a/src/Symfony/Component/Form/NativeRequestHandler.php b/src/Symfony/Component/Form/NativeRequestHandler.php index 7b39ad3a17c65..1afa6a6ba734f 100644 --- a/src/Symfony/Component/Form/NativeRequestHandler.php +++ b/src/Symfony/Component/Form/NativeRequestHandler.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Form; use Symfony\Component\Form\Exception\UnexpectedTypeException; +use Symfony\Component\Form\Util\FormUtil; use Symfony\Component\Form\Util\ServerParams; /** @@ -106,7 +107,7 @@ public function handleRequest(FormInterface $form, $request = null) } if (\is_array($params) && \is_array($files)) { - $data = array_replace_recursive($params, $files); + $data = FormUtil::mergeParamsAndFiles($params, $files); } else { $data = $params ?: $files; } diff --git a/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTestCase.php b/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTestCase.php index becf3504c3183..c61447a1ddc68 100644 --- a/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTestCase.php +++ b/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTestCase.php @@ -236,6 +236,42 @@ public function testMergeParamsAndFiles($method) $this->assertSame($file, $form->get('field2')->getData()); } + /** + * @dataProvider methodExceptGetProvider + */ + public function testMergeParamsAndFilesMultiple($method) + { + $form = $this->createForm('param1', $method, true); + $form->add($this->createBuilder('field1', false, ['allow_file_upload' => true, 'multiple' => true])->getForm()); + $file1 = $this->getUploadedFile(); + $file2 = $this->getUploadedFile(); + + $this->setRequestData($method, [ + 'param1' => [ + 'field1' => [ + 'foo', + 'bar', + 'baz', + ], + ], + ], [ + 'param1' => [ + 'field1' => [ + $file1, + $file2, + ], + ], + ]); + + $this->requestHandler->handleRequest($form, $this->request); + $data = $form->get('field1')->getData(); + + $this->assertTrue($form->isSubmitted()); + $this->assertIsArray($data); + $this->assertCount(5, $data); + $this->assertSame(['foo', 'bar', 'baz', $file1, $file2], $data); + } + /** * @dataProvider methodExceptGetProvider */ diff --git a/src/Symfony/Component/Form/Util/FormUtil.php b/src/Symfony/Component/Form/Util/FormUtil.php index fed96de4fa9b3..6c7873de70cb6 100644 --- a/src/Symfony/Component/Form/Util/FormUtil.php +++ b/src/Symfony/Component/Form/Util/FormUtil.php @@ -41,4 +41,29 @@ public static function isEmpty($data) // not considered to be empty, ever. return null === $data || '' === $data; } + + /** + * Recursively replaces or appends elements of the first array with elements + * of second array. If the key is an integer, the values will be appended to + * the new array; otherwise, the value from the second array will replace + * the one from the first array. + */ + public static function mergeParamsAndFiles(array $params, array $files): array + { + $result = []; + + foreach ($params as $key => $value) { + if (\is_array($value) && \is_array($files[$key] ?? null)) { + $value = self::mergeParamsAndFiles($value, $files[$key]); + unset($files[$key]); + } + if (\is_int($key)) { + $result[] = $value; + } else { + $result[$key] = $value; + } + } + + return array_merge($result, $files); + } } From 942c80f8c720123e4aec936482747d7e20881f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A1rbara=20Luz?= Date: Mon, 16 Oct 2023 07:43:06 -0300 Subject: [PATCH 65/79] Adds translations for Portuguese (pt) --- .../Resources/translations/validators.pt.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf index 090add6bd3413..9c3b00e01521f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. O valor da máscara de rede deve estar entre {{ min }} e {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + O nome do arquivo é muito grande. Deveria ter {{ filename_max_length }} caractere ou menos.|O nome do arquivo é muito grande. Deveria ter {{ filename_max_length }} caracteres ou menos. + + + The password strength is too low. Please use a stronger password. + A força da senha é muito baixa. Por favor utilize uma senha mais forte. + + + This value contains characters that are not allowed by the current restriction-level. + Este valor contém caracteres que não são permitidos pelo nível de restrição atual. + + + Using invisible characters is not allowed. + Não é permitido usar caracteres invisíveis. + + + Mixing numbers from different scripts is not allowed. + Não é permitido misturar números de scripts diferentes. + + + Using hidden overlay characters is not allowed. + Não é permitido usar caracteres de sobreposição ocultos. + From af15423674deba32628828e473cbc8b7b4f3d083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Tue, 17 Oct 2023 13:54:47 +0200 Subject: [PATCH 66/79] [Cache] Remove temporary cache item file on `rename()` failure --- .../Component/Cache/Traits/FilesystemCommonTrait.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php b/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php index c06cc309a6b3f..16e768990b942 100644 --- a/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php +++ b/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php @@ -90,6 +90,7 @@ protected function doUnlink(string $file) private function write(string $file, string $data, int $expiresAt = null) { + $unlink = false; set_error_handler(__CLASS__.'::throwError'); try { if (null === $this->tmp) { @@ -107,14 +108,22 @@ private function write(string $file, string $data, int $expiresAt = null) } fwrite($h, $data); fclose($h); + $unlink = true; if (null !== $expiresAt) { touch($this->tmp, $expiresAt ?: time() + 31556952); // 1 year in seconds } - return rename($this->tmp, $file); + $success = rename($this->tmp, $file); + $unlink = !$success; + + return $success; } finally { restore_error_handler(); + + if ($unlink) { + @unlink($this->tmp); + } } } From 0d1af2070066ea958b61285b1922788b22b40b96 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 17 Oct 2023 18:08:14 +0200 Subject: [PATCH 67/79] fix tests with Doctrine DBAL 3.8 --- .../Doctrine/Tests/Middleware/Debug/MiddlewareTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php b/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php index e59428783e4dd..1d723dedb6064 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php @@ -16,6 +16,7 @@ use Doctrine\DBAL\Driver\Middleware as MiddlewareInterface; use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\ParameterType; +use Doctrine\DBAL\Query\QueryBuilder; use Doctrine\DBAL\Result; use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory; use Doctrine\DBAL\Types\Types; @@ -213,11 +214,11 @@ public function testTransaction(callable $endTransactionMethod, string $expected $this->assertCount(9, $debug); $this->assertSame('"START TRANSACTION"', $debug[1]['sql']); $this->assertGreaterThan(0, $debug[1]['executionMS']); - $this->assertSame('SAVEPOINT DOCTRINE2_SAVEPOINT_2', $debug[2]['sql']); + $this->assertSame(method_exists(QueryBuilder::class, 'resetOrderBy') ? 'SAVEPOINT DOCTRINE_2' : 'SAVEPOINT DOCTRINE2_SAVEPOINT_2', $debug[2]['sql']); $this->assertGreaterThan(0, $debug[2]['executionMS']); $this->assertSame('INSERT INTO products(name, price, stock) VALUES ("product1", 12.5, 5)', $debug[3]['sql']); $this->assertGreaterThan(0, $debug[3]['executionMS']); - $this->assertSame(('"ROLLBACK"' === $expectedEndTransactionDebug ? 'ROLLBACK TO' : 'RELEASE').' SAVEPOINT DOCTRINE2_SAVEPOINT_2', $debug[4]['sql']); + $this->assertSame(('"ROLLBACK"' === $expectedEndTransactionDebug ? 'ROLLBACK TO' : 'RELEASE').' '.(method_exists(QueryBuilder::class, 'resetOrderBy') ? 'SAVEPOINT DOCTRINE_2' : 'SAVEPOINT DOCTRINE2_SAVEPOINT_2'), $debug[4]['sql']); $this->assertGreaterThan(0, $debug[4]['executionMS']); $this->assertSame($expectedEndTransactionDebug, $debug[5]['sql']); $this->assertGreaterThan(0, $debug[5]['executionMS']); From 3896d010802ac573998073b0a04386a4671c8c08 Mon Sep 17 00:00:00 2001 From: Minna N <44906587+minna-xD@users.noreply.github.com> Date: Wed, 18 Oct 2023 22:02:45 +0300 Subject: [PATCH 68/79] [Validator] Add missing Finnish translations --- .../Resources/translations/validators.fi.xlf | 116 +++++++++++------- 1 file changed, 70 insertions(+), 46 deletions(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf index 9a6bfe4b6a6f0..0a796a2dbaeb0 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf @@ -24,11 +24,11 @@ You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. - Sinun tulee valita vähintään {{ limit }} vaihtoehtoa. + Sinun tulee valita vähintään yksi vaihtoehto.|Sinun tulee valita vähintään {{ limit }} vaihtoehtoa. You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. - Sinun tulee valitan enintään {{ limit }} vaihtoehtoa. + Sinun tulee valita enintään yksi vaihtoehto.|Sinun tulee valita enintään {{ limit }} vaihtoehtoa. One or more of the given values is invalid. @@ -36,7 +36,7 @@ This field was not expected. - Tässä kentässä ei odotettu. + Tätä kenttää ei odotettu. This field is missing. @@ -60,7 +60,7 @@ The file is not readable. - Tiedostoa ei voida lukea. + Tiedostoa ei voi lukea. The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}. @@ -76,7 +76,7 @@ This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. - Liian pitkä syöte. Syöte saa olla enintään {{ limit }} merkkiä. + Liian pitkä syöte. Syöte saa olla enintään yhden merkin.|Liian pitkä syöte. Syöte saa olla enintään {{ limit }} merkkiä. This value should be {{ limit }} or more. @@ -84,7 +84,7 @@ This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. - Liian lyhyt syöte. Syötteen tulee olla vähintään {{ limit }} merkkiä. + Liian lyhyt syöte. Syötteen tulee olla vähintään yhden merkin.|Liian lyhyt syöte. Syötteen tulee olla vähintään {{ limit }} merkkiä. This value should not be blank. @@ -92,11 +92,11 @@ This value should not be null. - Syöte ei voi olla null. + Annettu arvo ei voi olla null. This value should be null. - Syötteen tulee olla null. + Annetun arvon tulee olla null. This value is not valid. @@ -128,11 +128,11 @@ This value should be a valid number. - Tämän arvon tulee olla numero. + Arvon tulee olla numero. This file is not a valid image. - Tämä tiedosto ei ole kelvollinen kuva. + Tiedosto ei ole kelvollinen kuva. This is not a valid IP address. @@ -140,47 +140,47 @@ This value is not a valid language. - Tämä arvo ei ole kelvollinen kieli. + Arvo ei ole kelvollinen kieli. This value is not a valid locale. - Tämä arvo ei ole kelvollinen kieli- ja alueasetus (locale). + Arvo ei ole kelvollinen kieli- ja alueasetus (locale). This value is not a valid country. - Tämä arvo ei ole kelvollinen maa. + Arvo ei ole kelvollinen maa. This value is already used. - Tämä arvo on jo käytetty. + Arvo on jo käytetty. The size of the image could not be detected. - Kuvan kokoa ei voitu tunnistaa. + Kuvan kokoa ei tunnistettu. The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px. - Kuva on liian leveä ({{ width }}px). Sallittu maksimileveys on {{ max_width }}px. + Kuva on liian leveä ({{ width }} px). Leveyden tulee olla enintään {{ max_width }} px. The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px. - Kuva on liian kapea ({{ width }}px). Leveyden tulisi olla vähintään {{ min_width }}px. + Kuva on liian kapea ({{ width }} px). Leveyden tulee olla vähintään {{ min_width }} px. The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px. - Kuva on liian korkea ({{ width }}px). Sallittu maksimikorkeus on {{ max_width }}px. + Kuva on liian korkea ({{ width }} px). Korkeuden tulee olla enintään {{ max_width }} px. The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px. - Kuva on liian matala ({{ height }}px). Korkeuden tulisi olla vähintään {{ min_height }}px. + Kuva on liian matala ({{ height }} px). Korkeuden tulee olla vähintään {{ min_height }} px. This value should be the user's current password. - Tämän arvon tulisi olla käyttäjän tämänhetkinen salasana. + Arvon tulee olla käyttäjän tämänhetkinen salasana. This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. - Tämän arvon tulisi olla tasan yhden merkin pituinen.|Tämän arvon tulisi olla tasan {{ limit }} merkkiä pitkä. + Arvon tulee olla tasan yhden merkin pituinen.|Arvon tulee olla tasan {{ limit }} merkin pituinen. The file was only partially uploaded. @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini. - Väliaikaishakemistoa ei ole asetettu php.ini -tiedostoon. + Väliaikaishakemistoa ei ole asetettu php.ini-tiedostossa. Cannot write temporary file to disk. @@ -204,15 +204,15 @@ This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. - Tässä ryhmässä tulisi olla yksi tai useampi elementti.|Tässä ryhmässä tulisi olla vähintään {{ limit }} elementtiä. + Tässä ryhmässä tulee olla vähintään yksi elementti.|Tässä ryhmässä tulee olla vähintään {{ limit }} elementtiä. This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. - Tässä ryhmässä tulisi olla enintään yksi elementti.|Tässä ryhmässä tulisi olla enintään {{ limit }} elementtiä. + Tässä ryhmässä tulee olla enintään yksi elementti.|Tässä ryhmässä tulee olla enintään {{ limit }} elementtiä. This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. - Tässä ryhmässä tulisi olla tasan yksi elementti.|Tässä ryhmässä tulisi olla enintään {{ limit }} elementtiä. + Tässä ryhmässä tulee olla tasan yksi elementti.|Tässä ryhmässä tulee olla tasan {{ limit }} elementtiä. Invalid card number. @@ -236,7 +236,7 @@ This value is neither a valid ISBN-10 nor a valid ISBN-13. - Arvo ei ole kelvollinen ISBN-10 tai kelvollinen ISBN-13. + Arvo ei ole kelvollinen ISBN-10 eikä ISBN-13. This value is not a valid ISSN. @@ -260,7 +260,7 @@ This value should be identical to {{ compared_value_type }} {{ compared_value }}. - Tämä arvo tulee olla sama kuin {{ compared_value_type }} {{ compared_value }}. + Arvon tulee olla sama kuin {{ compared_value_type }} {{ compared_value }}. This value should be less than {{ compared_value }}. @@ -268,7 +268,7 @@ This value should be less than or equal to {{ compared_value }}. - Arvon tulee olla pienempi tai yhtä suuri {{ compared_value }}. + Arvon tulee olla pienempi tai yhtä suuri kuin {{ compared_value }}. This value should not be equal to {{ compared_value }}. @@ -276,7 +276,7 @@ This value should not be identical to {{ compared_value_type }} {{ compared_value }}. - Tämä arvo ei tule olla sama kuin {{ compared_value_type }} {{ compared_value }}. + Arvon ei tule olla sama kuin {{ compared_value_type }} {{ compared_value }}. The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. @@ -284,23 +284,23 @@ The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. - Kuvasuhde on liian pieni ({{ ratio }}). Pienin sallittu arvo on {{ min_ratio }}. + Kuvasuhde on liian pieni ({{ ratio }}). Pienin sallittu suhde on {{ min_ratio }}. The image is square ({{ width }}x{{ height }}px). Square images are not allowed. - Kuva on neliä ({{ width }}x{{ height }}px). Neliöt kuvat eivät ole sallittuja. + Kuva on neliö ({{ width }}x{{ height }} px). Neliönmuotoiset kuvat eivät ole sallittuja. The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. - Kuva on vaakasuuntainen ({{ width }}x{{ height }}px). Vaakasuuntaiset kuvat eivät ole sallittuja. + Kuva on vaakasuuntainen ({{ width }}x{{ height }} px). Vaakasuuntaiset kuvat eivät ole sallittuja. The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. - Kuva on pystysuuntainen ({{ width }}x{{ height }}px). Pystysuuntaiset kuvat eivät ole sallittuja. + Kuva on pystysuuntainen ({{ width }}x{{ height }} px). Pystysuuntaiset kuvat eivät ole sallittuja. An empty file is not allowed. - Tyhjä tiedosto ei ole sallittu. + Tiedosto ei saa olla tyhjä. The host could not be resolved. @@ -324,11 +324,11 @@ This value should be a multiple of {{ compared_value }}. - Tämän arvon tulisi olla kerrannainen {{ compared_value }}. + Tämän arvon tulee olla luvun {{ compared_value }} kerrannainen. This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. - Tämä yritystunnus (BIC) ei ole liitetty IBAN {{ iban }}. + Tätä yritystunnusta (BIC) ei ole liitetty IBAN-tilinumeroon {{ iban }}. This value should be valid JSON. @@ -336,23 +336,23 @@ This collection should contain only unique elements. - Tämän ryhmän tulisi sisältää vain yksilöllisiä arvoja. + Ryhmän tulee sisältää vain yksilöllisiä arvoja. This value should be positive. - Arvon tulisi olla positiivinen. + Arvon tulee olla positiivinen. This value should be either positive or zero. - Arvon tulisi olla joko positiivinen tai nolla. + Arvon tulee olla joko positiivinen tai nolla. This value should be negative. - Arvon tulisi olla negatiivinen. + Arvon tulee olla negatiivinen. This value should be either negative or zero. - Arvon tulisi olla joko negatiivinen tai nolla. + Arvon tulee olla joko negatiivinen tai nolla. This value is not a valid timezone. @@ -360,11 +360,11 @@ This password has been leaked in a data breach, it must not be used. Please use another password. - Tämä salasana on vuotanut tietomurrossa, sitä ei saa käyttää. Käytä toista salasanaa. + Tämä salasana on vuotanut tietomurrossa, eikä sitä saa käyttää. Käytä toista salasanaa. This value should be between {{ min }} and {{ max }}. - Arvon tulisi olla välillä {{ min }} - {{ max }}. + Arvon tulee olla {{ min }} - {{ max }}. This value is not a valid hostname. @@ -372,11 +372,11 @@ The number of elements in this collection should be a multiple of {{ compared_value }}. - Ryhmässä olevien elementtien määrän pitää olla monikerta luvulle {{ compared_value }}. + Ryhmässä olevien elementtien määrän pitää olla luvun {{ compared_value }} kerrannainen. This value should satisfy at least one of the following constraints: - Tämän arvon tulee läpäistä vähintään yksi seuraavista tarkistuksista: + Arvon tulee läpäistä vähintään yksi seuraavista tarkistuksista: Each element of this collection should satisfy its own set of constraints. @@ -400,7 +400,31 @@ The value of the netmask should be between {{ min }} and {{ max }}. - Verkkomaskille annetun arvon tulisi olla {{ min }} ja {{ max }} välillä. + Verkkomaskille annetun arvon tulee olla {{ min }} - {{ max }}. + + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Tiedostonimi on liian pitkä. Nimi saa olla enintään yhden merkin pituinen.|Tiedostonimi on liian pitkä. Nimi saa olla enintään {{ filename_max_length }} merkin pituinen. + + + The password strength is too low. Please use a stronger password. + Salasana on liian heikko. Valitse vahvempi salasana. + + + This value contains characters that are not allowed by the current restriction-level. + Arvo sisältää merkkejä, joita nykyinen rajoitustaso ei salli. + + + Using invisible characters is not allowed. + Näkymättömiä merkkejä ei saa käyttää. + + + Mixing numbers from different scripts is not allowed. + Eri kirjaimistojen numeroita ei saa sekoittaa. + + + Using hidden overlay characters is not allowed. + Piilotettuja tarkemerkkejä ei saa käyttää. From 1fc56bb4859703742efc598b963473390bfe59cc Mon Sep 17 00:00:00 2001 From: HypeMC Date: Thu, 19 Oct 2023 07:19:49 +0200 Subject: [PATCH 69/79] [Messenger] Fix graceful exit with ids --- .../Messenger/Command/FailedMessagesRetryCommand.php | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Messenger/Command/FailedMessagesRetryCommand.php b/src/Symfony/Component/Messenger/Command/FailedMessagesRetryCommand.php index 3bf4f81c03f7c..ae47d774b51c4 100644 --- a/src/Symfony/Component/Messenger/Command/FailedMessagesRetryCommand.php +++ b/src/Symfony/Component/Messenger/Command/FailedMessagesRetryCommand.php @@ -124,7 +124,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int } $this->retrySpecificIds($failureTransportName, $ids, $io, $shouldForce); - $io->success('All done!'); + + if (!$this->shouldStop) { + $io->success('All done!'); + } return 0; } @@ -255,6 +258,10 @@ private function retrySpecificIds(string $failureTransportName, array $ids, Symf $singleReceiver = new SingleMessageReceiver($receiver, $envelope); $this->runWorker($failureTransportName, $singleReceiver, $io, $shouldForce); + + if ($this->shouldStop) { + break; + } } } From 77cd7036aa7c2039acab053be76937c8dabdf301 Mon Sep 17 00:00:00 2001 From: asrorbekh Date: Thu, 19 Oct 2023 20:08:49 +0500 Subject: [PATCH 70/79] Added missing Uzbek translations. --- .../Resources/translations/validators.uz.xlf | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf index d1ecaf1b70a29..63a79a084a924 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf @@ -4,11 +4,11 @@ This value should be false. - Qiymat noto'g'ri bo'lishi kerak. + Qiymat false bo'lishi kerak. This value should be true. - Qiymat to'g'ri bo'lishi kerak. + Qiymat true bo'lishi kerak. This value should be of type {{ type }}. @@ -20,7 +20,7 @@ The value you selected is not a valid choice. - Tanlangan qiymat to'g'ri emas. + Tanlangan qiymat yaroqli emas. You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. @@ -32,7 +32,7 @@ One or more of the given values is invalid. - Belgilangan qiymatlarning bir yoki bir nechtasi noto'g'ri. + Belgilangan qiymatlarning bir yoki bir nechtasi yaroqsiz. This field was not expected. @@ -143,9 +143,9 @@ Noto'g'ri til. - This value is not a valid locale. - Ushbu qiymat mahalliy qiymat emas. - + This value is not a valid locale. + Ushbu qiymat mahalliy qiymat emas. + This value is not a valid country. Mamlakat qiymati noto'g'ri. @@ -390,7 +390,7 @@ This value should be a valid expression. Ushbu qiymat to'g'ri ifoda bo'lishi kerak. - + This value is not a valid CSS color. Bu qiymat haqiqiy CSS rangi emas. @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Tarmoq niqobining qiymati {{ min }} va {{ max }} oralig'ida bo'lishi kerak. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Fayl nomi juda uzun. U {{ filename_max_length }} belgidan iborat boʻlishi kerak.|Fayl nomi juda uzun. U {{ filename_max_length }} ta belgidan iborat boʻlishi kerak. + + + The password strength is too low. Please use a stronger password. + Parol kuchi juda past. Iltimos, kuchliroq paroldan foydalaning. + + + This value contains characters that are not allowed by the current restriction-level. + Bu qiymat joriy cheklov darajasida ruxsat etilmagan belgilarni o'z ichiga oladi. + + + Using invisible characters is not allowed. + Ko'rinmas belgilardan foydalanish taqiqlangan. + + + Mixing numbers from different scripts is not allowed. + Turli skriptlardagi raqamlarni aralashtirish taqiqlangan. + + + Using hidden overlay characters is not allowed. + Yashirin qoplamali belgilardan foydalanish taqiqlangan. + From 7cd55763df30953cbabae4b088bd2a5f55b4cd79 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Thu, 19 Oct 2023 17:32:25 +0200 Subject: [PATCH 71/79] [Messenger] Fix requiring symfony/deprecation-contracts --- src/Symfony/Component/Messenger/composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Messenger/composer.json b/src/Symfony/Component/Messenger/composer.json index fbae1a4bd7210..7bbb47c4d26bf 100644 --- a/src/Symfony/Component/Messenger/composer.json +++ b/src/Symfony/Component/Messenger/composer.json @@ -18,13 +18,13 @@ "require": { "php": ">=8.1", "psr/log": "^1|^2|^3", - "symfony/clock": "^6.3" + "symfony/clock": "^6.3", + "symfony/deprecation-contracts": "^2.5|^3" }, "require-dev": { "psr/cache": "^1.0|^2.0|^3.0", "symfony/console": "^6.3", "symfony/dependency-injection": "^5.4|^6.0", - "symfony/deprecation-contracts": "^2.5|^3", "symfony/event-dispatcher": "^5.4|^6.0", "symfony/http-kernel": "^5.4|^6.0", "symfony/process": "^5.4|^6.0", From a58c6124368d4c8d628a1aed0a7d5b08893140ca Mon Sep 17 00:00:00 2001 From: Vitalii Date: Wed, 18 Oct 2023 14:50:47 -0500 Subject: [PATCH 72/79] [Validator] Added missing translations for Romanian language for Validator component --- .../Resources/translations/validators.ro.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf index 7fba2cd1e0e73..f0ca7477c4b95 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf @@ -398,6 +398,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Valoarea netmask-ului trebuie sa fie intre {{ min }} si {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Denumirea fișierului este prea lungă. Ea trebuie să conțină {{ filename_max_length }} caractere sau mai puține.|Denumirea fișierului este prea lungă. Ea trebuie să conțină {{ filename_max_length }} caractere sau mai puține. + + + The password strength is too low. Please use a stronger password. + Complexitatea parolei este prea mică. Vă rugăm să folosiți o parolă mai puternică. + + + This value contains characters that are not allowed by the current restriction-level. + Această valoare conține caractere care nu sunt premise de nivelul de restricționare curent. + + + Using invisible characters is not allowed. + Folosirea caracterelor invizibile nu este permisă. + + + Mixing numbers from different scripts is not allowed. + Combinarea numerelor din diferite script-uri nu este permisă. + + + Using hidden overlay characters is not allowed. + Folosirea caracterelor invizibile suprapuse nu este permisă. + From 738385f127dd9a27751deca1d600b7f4647b8c93 Mon Sep 17 00:00:00 2001 From: Nadim AL ABDOU Date: Thu, 19 Oct 2023 20:45:10 +0200 Subject: [PATCH 73/79] [Validator] Add missing arabic translations --- .../Resources/translations/validators.ar.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf index 6aa0d594843f6..fce6604a533cd 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. يجب أن تكون قيمة netmask بين {{ min }} و {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + اسم الملف طويل جدا. يجب أن يحتوي على {{ filename_max_length }} حرف أو أقل.|اسم الملف طويل جدا. يجب أن يحتوي على {{ filename_max_length }} أحرف أو أقل. + + + The password strength is too low. Please use a stronger password. + قوة كلمة المرور منخفضة للغاية. يرجى استخدام كلمة مرور أقوى. + + + This value contains characters that are not allowed by the current restriction-level. + تحتوي هذه القيمة على أحرف غير مسموح بها بواسطة مستوى التقييد الحالي. + + + Using invisible characters is not allowed. + لا يسمح باستخدام أحرف غير مرئية. + + + Mixing numbers from different scripts is not allowed. + لا يسمح بخلط الأرقام من نصوص مختلفة. + + + Using hidden overlay characters is not allowed. + لا يسمح باستخدام أحرف التراكب المخفية. + From 07f9d2eeb2d9093c3ee00661a6ddf84839eecb8a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 20 Oct 2023 07:50:21 +0200 Subject: [PATCH 74/79] Replace Tickets by Issues --- .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 f56136de940d3..ff72a1cc13a5c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,7 +4,7 @@ | Bug fix? | yes/no | New feature? | yes/no | Deprecations? | yes/no -| Tickets | Fix #... +| Issues | Fix #... | License | MIT

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy