From cf0b56f18463e236bfa503178cbcebdf13aa414d Mon Sep 17 00:00:00 2001 From: Jordi Boggiano Date: Fri, 26 Aug 2022 15:50:20 +0200 Subject: [PATCH 01/57] Make bash completion run in non interactive mode --- src/Symfony/Component/Console/Resources/completion.bash | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Console/Resources/completion.bash b/src/Symfony/Component/Console/Resources/completion.bash index fba46070cdebe..bf3edf511b2cb 100644 --- a/src/Symfony/Component/Console/Resources/completion.bash +++ b/src/Symfony/Component/Console/Resources/completion.bash @@ -24,7 +24,7 @@ _sf_{{ COMMAND_NAME }}() { local cur prev words cword _get_comp_words_by_ref -n := cur prev words cword - local completecmd=("$sf_cmd" "_complete" "-sbash" "-c$cword" "-S{{ VERSION }}") + local completecmd=("$sf_cmd" "_complete" "--no-interaction" "-sbash" "-c$cword" "-S{{ VERSION }}") for w in ${words[@]}; do w=$(printf -- '%b' "$w") # remove quotes from typed values From 1b904ec781ecc60ba81cae5e588dbf1f3248b592 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 26 Aug 2022 16:34:43 +0200 Subject: [PATCH 02/57] Update CHANGELOG for 4.4.45 --- CHANGELOG-4.4.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/CHANGELOG-4.4.md b/CHANGELOG-4.4.md index 9e6451685ab5c..b3498d37227df 100644 --- a/CHANGELOG-4.4.md +++ b/CHANGELOG-4.4.md @@ -7,6 +7,24 @@ in 4.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/v4.4.0...v4.4.1 +* 4.4.45 (2022-08-26) + + * bug #47358 Fix broken request stack state if throwable is thrown. (Warxcell) + * bug #47304 [Serializer] Fix caching context-aware encoders/decoders in ChainEncoder/ChainDecoder (Guite) + * bug #47329 Email image parts: regex for single closing quote (rr-it) + * bug #47200 [Form] ignore missing keys when mapping DateTime objects to uninitialized arrays (xabbuh) + * bug #47189 [Validator] Add additional hint when `egulias/email-validator` needs to be installed (mpdude) + * bug #47195 [FrameworkBundle] fix writes to static $kernel property (xabbuh) + * bug #47175 [DowCrawler] Fix locale-sensitivity of whitespace normalization (nicolas-grekas) + * bug #47171 [TwigBridge] suggest to install the Twig bundle when the required component is already installed (xabbuh) + * bug #47161 [Mailer] Fix logic (fabpot) + * bug #47157 [Messenger] Fix Doctrine transport on MySQL (nicolas-grekas) + * bug #46190 [Translation] Fix translator overlapse (Xavier RENAUDIN) + * bug #47142 [Mailer] Fix error message in case of an STMP error (fabpot) + * bug #47145 [HttpClient] Fix shared connections not being freed on PHP < 8 (nicolas-grekas) + * bug #47143 [HttpClient] Fix memory leak when using StreamWrapper (nicolas-grekas) + * bug #47130 [HttpFoundation] Fix invalid ID not regenerated with native PHP file sessions (BrokenSourceCode) + * 4.4.44 (2022-07-29) * bug #47069 [Security] Allow redirect after login to absolute URLs (Tim Ward) From ce345c5469972594dcc7e7dc73710a3344c40101 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 26 Aug 2022 16:34:47 +0200 Subject: [PATCH 03/57] Update CONTRIBUTORS for 4.4.45 --- CONTRIBUTORS.md | 68 +++++++++++++++++++++++++++++-------------------- 1 file changed, 41 insertions(+), 27 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 99d8c121d9fce..167d559dc9e9f 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -24,8 +24,8 @@ The Symfony Connect username in parenthesis allows to get more information - Yonel Ceruto (yonelceruto) - Tobias Nyholm (tobias) - Oskar Stark (oskarstark) - - Ryan Weaver (weaverryan) - Javier Eguiluz (javier.eguiluz) + - Ryan Weaver (weaverryan) - Johannes S (johannes) - Jakub Zalas (jakubzalas) - Kris Wallsmith (kriswallsmith) @@ -43,9 +43,9 @@ The Symfony Connect username in parenthesis allows to get more information - Martin Hasoň (hason) - Jérôme Tamarelle (gromnan) - Jeremy Mikola (jmikola) + - Kevin Bond (kbond) - Jean-François Simon (jfsimon) - Benjamin Eberlei (beberlei) - - Kevin Bond (kbond) - Igor Wiedler - Valentin Udaltsov (vudaltsov) - Vasilij Duško (staff) @@ -84,8 +84,8 @@ The Symfony Connect username in parenthesis allows to get more information - Sarah Khalil (saro0h) - Konstantin Kudryashov (everzet) - Vincent Langlet (deviling) - - Bilal Amarni (bamarni) - Tomas Norkūnas (norkunas) + - Bilal Amarni (bamarni) - Eriksen Costa - Florin Patan (florinpatan) - Peter Rehm (rpet) @@ -95,14 +95,14 @@ The Symfony Connect username in parenthesis allows to get more information - Julien Falque (julienfalque) - Massimiliano Arione (garak) - Douglas Greenshields (shieldo) - - Christian Raue - David Buchmann (dbu) + - Christian Raue + - Jáchym Toušek (enumag) - Graham Campbell (graham) - Michel Weimerskirch (mweimerskirch) - Eric Clemmons (ericclemmons) - Issei Murasawa (issei_m) - Fran Moreno (franmomu) - - Jáchym Toušek (enumag) - Malte Schlüter (maltemaltesich) - Mathias Arlaud (mtarld) - Vasilij Dusko @@ -114,8 +114,8 @@ The Symfony Connect username in parenthesis allows to get more information - Dariusz Górecki (canni) - Maxime Helias (maxhelias) - Ener-Getick - - Sebastiaan Stok (sstok) - Ruud Kamphuis (ruudk) + - Sebastiaan Stok (sstok) - Jérôme Vasseur (jvasseur) - Ion Bazan (ionbazan) - Lee McDermott @@ -134,6 +134,7 @@ The Symfony Connect username in parenthesis allows to get more information - Konstantin.Myakshin - Rokas Mikalkėnas (rokasm) - Arman Hosseini (arman) + - Antoine Lamirault - Arnaud Le Blanc (arnaud-lb) - Maxime STEINHAUSSER - Peter Kokot (maastermedia) @@ -146,10 +147,10 @@ The Symfony Connect username in parenthesis allows to get more information - YaFou - Gary PEGEOT (gary-p) - Chris Wilkinson (thewilkybarkid) + - Mathieu Lechat (mat_the_cat) - Brice BERNARD (brikou) - Roman Martinuk (a2a4) - Gregor Harlan (gharlan) - - Antoine Lamirault - Baptiste Clavié (talus) - Adrien Brault (adrienbrault) - Michal Piotrowski @@ -161,7 +162,6 @@ The Symfony Connect username in parenthesis allows to get more information - Włodzimierz Gajda (gajdaw) - Christian Scheb - Guillaume (guill) - - Mathieu Lechat (mat_the_cat) - Tugdual Saunier (tucksaun) - Jacob Dreesen (jdreesen) - Joel Wurtz (brouznouf) @@ -173,6 +173,7 @@ The Symfony Connect username in parenthesis allows to get more information - Javier Spagnoletti (phansys) - excelwebzone - Jérôme Parmentier (lctrs) + - Jeroen Spee (jeroens) - HeahDude - Richard van Laak (rvanlaak) - Paráda József (paradajozsef) @@ -180,7 +181,6 @@ The Symfony Connect username in parenthesis allows to get more information - Alexander Schwenn (xelaris) - Fabien Pennequin (fabienpennequin) - Gordon Franke (gimler) - - Jeroen Spee (jeroens) - Christopher Hertel (chertel) - Gabriel Caruso - Anthony GRASSIOT (antograssiot) @@ -207,6 +207,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jhonny Lidfors (jhonne) - Martin Hujer (martinhujer) - Wouter J + - Guilliam Xavier - Timo Bakx (timobakx) - Juti Noppornpitak (shiroyuki) - Joe Bennett (kralos) @@ -215,6 +216,7 @@ The Symfony Connect username in parenthesis allows to get more information - Colin O'Dell (colinodell) - Sebastian Hörl (blogsh) - Ben Davies (bendavies) + - Andreas Schempp (aschempp) - François-Xavier de Guillebon (de-gui_f) - Daniel Gomes (danielcsgomes) - Michael Käfer (michael_kaefer) @@ -223,11 +225,10 @@ The Symfony Connect username in parenthesis allows to get more information - Arnaud Kleinpeter (nanocom) - Guilherme Blanco (guilhermeblanco) - Chi-teck - - Guilliam Xavier + - Antonio Pauletich (x-coder264) - Nate Wiebe (natewiebe13) - Michael Voříšek - SpacePossum - - Andreas Schempp (aschempp) - Pablo Godel (pgodel) - Romaric Drigon (romaricdrigon) - Andréia Bohner (andreia) @@ -239,7 +240,6 @@ The Symfony Connect username in parenthesis allows to get more information - jwdeitch - Jurica Vlahoviček (vjurica) - David Prévot - - Antonio Pauletich (x-coder264) - Vincent Touzet (vincenttouzet) - Fabien Bourigault (fbourigault) - Farhad Safarov (safarov) @@ -373,9 +373,11 @@ The Symfony Connect username in parenthesis allows to get more information - Emanuele Panzeri (thepanz) - Matthew Smeets - François Zaninotto (fzaninotto) + - Alexis Lefebvre - Dustin Whittle (dustinwhittle) - jeff - John Kary (johnkary) + - Bob van de Vijver (bobvandevijver) - smoench - Michele Orselli (orso) - Sven Paulus (subsven) @@ -397,8 +399,10 @@ The Symfony Connect username in parenthesis allows to get more information - Fabien S (bafs) - Victor Bocharsky (bocharsky_bw) - Sébastien Alfaiate (seb33300) + - Jan Sorgalla (jsor) - henrikbjorn - Alex Bowers + - Simon Podlipsky (simpod) - Marcel Beerta (mazen) - Phil Taylor (prazgod) - flack (flack) @@ -426,7 +430,6 @@ The Symfony Connect username in parenthesis allows to get more information - Iker Ibarguren (ikerib) - Manuel Reinhard (sprain) - Johann Pardanaud - - Alexis Lefebvre - Indra Gunawan (indragunawan) - Tim Goudriaan (codedmonkey) - Harm van Tilborg (hvt) @@ -444,7 +447,6 @@ The Symfony Connect username in parenthesis allows to get more information - Xavier Montaña Carreras (xmontana) - Tarmo Leppänen (tarlepp) - AnneKir - - Bob van de Vijver (bobvandevijver) - Tobias Weichart - Miro Michalicka - M. Vondano @@ -473,12 +475,10 @@ The Symfony Connect username in parenthesis allows to get more information - Félix Labrecque (woodspire) - GordonsLondon - Roman Anasal - - Jan Sorgalla (jsor) - Piotr Kugla (piku235) - Quynh Xuan Nguyen (seriquynh) - Ray - Philipp Cordes (corphi) - - Simon Podlipsky (simpod) - Chekote - bhavin (bhavin4u) - Pavel Popov (metaer) @@ -495,12 +495,14 @@ The Symfony Connect username in parenthesis allows to get more information - Thomas Schulz (king2500) - Benjamin Morel - Bernd Stellwag + - Romain Monteil (ker0x) - Frank de Jonge - Chris Tanaskoski - julien57 - Loïc Frémont (loic425) - Ben Ramsey (ramsey) - Matthieu Auger (matthieuauger) + - Kévin THERAGE (kevin_therage) - Josip Kruslin (jkruslin) - Giorgio Premi - renanbr @@ -526,6 +528,7 @@ The Symfony Connect username in parenthesis allows to get more information - Michael Holm (hollo) - Giso Stallenberg (gisostallenberg) - Blanchon Vincent (blanchonvincent) + - William Arslett (warslett) - Christian Schmidt - Gonzalo Vilaseca (gonzalovilaseca) - Vadim Borodavko (javer) @@ -575,7 +578,6 @@ The Symfony Connect username in parenthesis allows to get more information - Marko Kaznovac (kaznovac) - Emanuele Gaspari (inmarelibero) - Dariusz Rumiński - - Romain Monteil (ker0x) - Terje Bråten - Gennadi Janzen - James Hemery @@ -599,7 +601,6 @@ The Symfony Connect username in parenthesis allows to get more information - Fractal Zombie - Gunnstein Lye (glye) - Thomas Talbot (ioni) - - Kévin THERAGE (kevin_therage) - Noémi Salaün (noemi-salaun) - Michel Hunziker - Krystian Marcisz (simivar) @@ -623,6 +624,7 @@ The Symfony Connect username in parenthesis allows to get more information - Thomas Royer (cydonia7) - Gildas Quéméner (gquemener) - Nicolas LEFEVRE (nicoweb) + - Asmir Mustafic (goetas) - Martins Sipenko - Guilherme Augusto Henschel - Mardari Dorel (dorumd) @@ -662,7 +664,6 @@ The Symfony Connect username in parenthesis allows to get more information - “Filip - Simon Watiau (simonwatiau) - Ruben Jacobs (rubenj) - - William Arslett - Arkadius Stefanski (arkadius) - Jérémy M (th3mouk) - Terje Bråten @@ -700,6 +701,7 @@ The Symfony Connect username in parenthesis allows to get more information - Philipp Kräutli (pkraeutli) - Carl Casbolt (carlcasbolt) - battye + - BrokenSourceCode - Grzegorz (Greg) Zdanowski (kiler129) - Kirill chEbba Chebunin - kylekatarnls (kylekatarnls) @@ -850,7 +852,6 @@ The Symfony Connect username in parenthesis allows to get more information - Arturs Vonda - Xavier Briand (xavierbriand) - Daniel Badura - - Asmir Mustafic (goetas) - vagrant - Asier Illarramendi (doup) - AKeeman (akeeman) @@ -861,6 +862,7 @@ The Symfony Connect username in parenthesis allows to get more information - Chris Sedlmayr (catchamonkey) - Kamil Kokot (pamil) - Seb Koelen + - FORT Pierre-Louis (plfort) - Christoph Mewes (xrstf) - Vitaliy Tverdokhlib (vitaliytv) - Ariel Ferrandini (aferrandini) @@ -900,7 +902,6 @@ The Symfony Connect username in parenthesis allows to get more information - Pablo Díez (pablodip) - Damien Fa - Kevin McBride - - BrokenSourceCode - Sergio Santoro - Philipp Rieber (bicpi) - Dennis Væversted (srnzitcom) @@ -988,6 +989,7 @@ The Symfony Connect username in parenthesis allows to get more information - Ziumin - Matthias Schmidt - Lenar Lõhmus + - Samaël Villette (samadu61) - Zach Badgett (zachbadgett) - Loïc Faugeron - Aurélien Fredouelle @@ -1049,6 +1051,7 @@ The Symfony Connect username in parenthesis allows to get more information - Simon DELICATA - Thibault Buathier (gwemox) - vitaliytv + - Andreas Hennings - Arnaud Frézet - Nicolas Martin (cocorambo) - luffy1727 @@ -1136,6 +1139,7 @@ The Symfony Connect username in parenthesis allows to get more information - David Fuhr - Evgeny Anisiforov - TristanPouliquen + - Gwendolen Lynch - mwos - Aurimas Niekis (gcds) - Volker Killesreiter (ol0lll) @@ -1189,7 +1193,6 @@ The Symfony Connect username in parenthesis allows to get more information - Chris Heng (gigablah) - Oleksii Svitiashchuk - Tristan Bessoussa (sf_tristanb) - - FORT Pierre-Louis (plfort) - Richard Bradley - Nathanaël Martel (nathanaelmartel) - Nicolas Jourdan (nicolasjc) @@ -1259,6 +1262,7 @@ The Symfony Connect username in parenthesis allows to get more information - Aleksandr Dankovtsev - Maciej Zgadzaj - David Legatt (dlegatt) + - Maarten de Boer (mdeboer) - Cameron Porter - Hossein Bukhamsin - Oliver Hoff @@ -1463,6 +1467,7 @@ The Symfony Connect username in parenthesis allows to get more information - bill moll - PaoRuby - Bizley + - Edvin Hultberg - Dominik Piekarski (dompie) - Rares Sebastian Moldovan (raresmldvn) - Felds Liscia (felds) @@ -1773,7 +1778,6 @@ The Symfony Connect username in parenthesis allows to get more information - Pierre-Olivier Vares (povares) - Ronny López (ronnylt) - Julius (sakalys) - - Samaël Villette (samadu61) - abdul malik ikhsan (samsonasik) - Dmitry (staratel) - Tito Miguel Costa (titomiguelcosta) @@ -1956,6 +1960,7 @@ The Symfony Connect username in parenthesis allows to get more information - Daniel Alejandro Castro Arellano (lexcast) - Aleksandar Dimitrov (netbull) - Gary Houbre (thegarious) + - Florent Morselli - Thomas Jarrand - Baptiste Leduc (bleduc) - Antoine Bluchet (soyuka) @@ -2053,6 +2058,7 @@ The Symfony Connect username in parenthesis allows to get more information - Pablo Borowicz - Máximo Cuadros (mcuadros) - Lukas Mencl + - EXT - THERAGE Kevin - tamirvs - gauss - julien.galenski @@ -2067,6 +2073,7 @@ The Symfony Connect username in parenthesis allows to get more information - Goran Juric - Laurent G. (laurentg) - Nicolas Macherey + - Asil Barkin Elik (asilelik) - Bhujagendra Ishaya - Guido Donnari - Mert Simsek (mrtsmsk0) @@ -2097,6 +2104,7 @@ The Symfony Connect username in parenthesis allows to get more information - Dan Finnie - Ken Marfilla (marfillaster) - Max Grigorian (maxakawizard) + - allison guilhem - benatespina (benatespina) - Denis Kop - Jean-Guilhem Rouel (jean-gui) @@ -2130,6 +2138,7 @@ The Symfony Connect username in parenthesis allows to get more information - Tadas Gliaubicas (tadcka) - Thanos Polymeneas (thanos) - Benoit Garret + - HellFirePvP - Maximilian Ruta (deltachaos) - Jakub Sacha - Olaf Klischat @@ -2194,6 +2203,7 @@ The Symfony Connect username in parenthesis allows to get more information - Philipp Kretzschmar - Ilya Vertakov - Brooks Boyd + - Axel Venet - Roger Webb - Dmitriy Simushev - Pawel Smolinski @@ -2201,7 +2211,6 @@ The Symfony Connect username in parenthesis allows to get more information - Oxan van Leeuwen - pkowalczyk - Soner Sayakci - - Andreas Hennings - Max Voloshin (maxvoloshin) - Nicolas Fabre (nfabre) - Raul Rodriguez (raul782) @@ -2238,6 +2247,7 @@ The Symfony Connect username in parenthesis allows to get more information - Dmitri Petmanson - heccjj - Alexandre Melard + - AlbinoDrought - Jay Klehr - Sergey Yuferev - Tobias Stöckler @@ -2247,6 +2257,7 @@ The Symfony Connect username in parenthesis allows to get more information - cilefen (cilefen) - Mo Di (modi) - Pablo Schläpfer + - Xavier RENAUDIN - Christian Wahler (christian) - Jelte Steijaert (jelte) - David Négrier (moufmouf) @@ -2268,6 +2279,7 @@ The Symfony Connect username in parenthesis allows to get more information - Malaney J. Hill - Patryk Kozłowski - Alexandre Pavy + - Tim Ward - Christian Flach (cmfcmf) - Lars Ambrosius Wallenborn (larsborn) - Oriol Mangas Abellan (oriolman) @@ -2282,6 +2294,7 @@ The Symfony Connect username in parenthesis allows to get more information - Mihai Nica (redecs) - Andrei Igna - azine + - Wojciech Zimoń - Pierre Tachoire - Dawid Sajdak - Ludek Stepan @@ -2363,6 +2376,7 @@ The Symfony Connect username in parenthesis allows to get more information - Daniel Kay (danielkay-cp) - Matt Daum (daum) - Alberto Pirovano (geezmo) + - Pascal Woerde (pascalwoerde) - Pete Mitchell (peterjmit) - Tom Corrigan (tomcorrigan) - Luis Galeas @@ -2479,6 +2493,7 @@ The Symfony Connect username in parenthesis allows to get more information - Keith Maika - Mephistofeles - Hoffmann András + - Cédric Anne - LubenZA - Flavian Sierk - Michael Bessolov @@ -2508,7 +2523,6 @@ The Symfony Connect username in parenthesis allows to get more information - Alex Teterin (errogaht) - Gunnar Lium (gunnarlium) - Malte Wunsch (maltewunsch) - - Maarten de Boer (mdeboer) - Tiago Garcia (tiagojsag) - Artiom - Jakub Simon @@ -2635,6 +2649,7 @@ The Symfony Connect username in parenthesis allows to get more information - Andy Stanberry - Felix Marezki - Normunds + - Walter Doekes - Thomas Rothe - Troy Crawford - nietonfir @@ -2952,7 +2967,6 @@ The Symfony Connect username in parenthesis allows to get more information - temperatur - Paul Andrieux - Cas - - Gwendolen Lynch - ghazy ben ahmed - Karolis - Myke79 @@ -3051,6 +3065,7 @@ The Symfony Connect username in parenthesis allows to get more information - Shude - Ondřej Führer - Sema + - Ayke Halder - Thorsten Hallwas - Brian Freytag - Alex Nostadt @@ -3062,7 +3077,6 @@ The Symfony Connect username in parenthesis allows to get more information - Yuriy Potemkin - Emilie Lorenzo - enomotodev - - Edvin Hultberg - Vincent - Benjamin Long - Ben Miller From 6ba69e892ff98236fd3c7cfc0e08cb02958b414a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 26 Aug 2022 16:34:48 +0200 Subject: [PATCH 04/57] Update VERSION for 4.4.45 --- 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 3a699112e1a5d..adb9a94727c5e 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 $freshCache = []; - public const VERSION = '4.4.45-DEV'; + public const VERSION = '4.4.45'; public const VERSION_ID = 40445; public const MAJOR_VERSION = 4; public const MINOR_VERSION = 4; public const RELEASE_VERSION = 45; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2022'; public const END_OF_LIFE = '11/2023'; From d82f7dfe83718d244067cd91268a6b529a508451 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 26 Aug 2022 16:40:14 +0200 Subject: [PATCH 05/57] Bump Symfony version to 4.4.46 --- 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 adb9a94727c5e..09c0f681629f6 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 $freshCache = []; - public const VERSION = '4.4.45'; - public const VERSION_ID = 40445; + public const VERSION = '4.4.46-DEV'; + public const VERSION_ID = 40446; public const MAJOR_VERSION = 4; public const MINOR_VERSION = 4; - public const RELEASE_VERSION = 45; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 46; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '11/2022'; public const END_OF_LIFE = '11/2023'; From 81a2a6c5711c4450be4866b7055e2680ee8773fb Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 26 Aug 2022 16:44:24 +0200 Subject: [PATCH 06/57] Bump Symfony version to 5.4.13 --- 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 efedd884ad5e1..7a7e678a4f75c 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.12'; - public const VERSION_ID = 50412; + public const VERSION = '5.4.13-DEV'; + public const VERSION_ID = 50413; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 4; - public const RELEASE_VERSION = 12; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 13; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '11/2024'; public const END_OF_LIFE = '11/2025'; From 15d66ef1b710030419cea714a2ee0219337d3ea4 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 27 Aug 2022 07:42:54 +0200 Subject: [PATCH 07/57] [Mailer] Fix edge cases in STMP transports --- .../Transport/Smtp/SmtpTransportTest.php | 30 +++++++++++++++++++ .../Mailer/Transport/Smtp/EsmtpTransport.php | 6 +++- .../Mailer/Transport/Smtp/SmtpTransport.php | 3 +- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Mailer/Tests/Transport/Smtp/SmtpTransportTest.php b/src/Symfony/Component/Mailer/Tests/Transport/Smtp/SmtpTransportTest.php index 5f8d3ba0d8180..c54b050b92963 100644 --- a/src/Symfony/Component/Mailer/Tests/Transport/Smtp/SmtpTransportTest.php +++ b/src/Symfony/Component/Mailer/Tests/Transport/Smtp/SmtpTransportTest.php @@ -13,6 +13,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Mailer\Envelope; +use Symfony\Component\Mailer\Exception\LogicException; use Symfony\Component\Mailer\Exception\TransportException; use Symfony\Component\Mailer\Transport\Smtp\SmtpTransport; use Symfony\Component\Mailer\Transport\Smtp\Stream\AbstractStream; @@ -133,6 +134,35 @@ public function testWriteEncodedRecipientAndSenderAddresses() $this->assertContains("RCPT TO:\r\n", $stream->getCommands()); $this->assertContains("RCPT TO:\r\n", $stream->getCommands()); } + + public function testAssertResponseCodeNoCodes() + { + $this->expectException(LogicException::class); + $this->invokeAssertResponseCode('response', []); + } + + public function testAssertResponseCodeWithEmptyResponse() + { + $this->expectException(TransportException::class); + $this->expectExceptionMessage('Expected response code "220" but got empty code.'); + $this->invokeAssertResponseCode('', [220]); + } + + public function testAssertResponseCodeWithNotValidCode() + { + $this->expectException(TransportException::class); + $this->expectExceptionMessage('Expected response code "220" but got code "550", with message "550 Access Denied".'); + $this->expectExceptionCode(550); + $this->invokeAssertResponseCode('550 Access Denied', [220]); + } + + private function invokeAssertResponseCode(string $response, array $codes): void + { + $transport = new SmtpTransport($this->getMockForAbstractClass(AbstractStream::class)); + $m = new \ReflectionMethod($transport, 'assertResponseCode'); + $m->setAccessible(true); + $m->invoke($transport, $response, $codes); + } } class DummyStream extends AbstractStream diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php b/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php index 25006fbb7d326..da2498aa0dc02 100644 --- a/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php +++ b/src/Symfony/Component/Mailer/Transport/Smtp/EsmtpTransport.php @@ -94,7 +94,9 @@ public function addAuthenticator(AuthenticatorInterface $authenticator): void protected function doHeloCommand(): void { - $capabilities = $this->callHeloCommand(); + if (!$capabilities = $this->callHeloCommand()) { + return; + } /** @var SocketStream $stream */ $stream = $this->getStream(); @@ -123,6 +125,8 @@ private function callHeloCommand(): array } catch (TransportExceptionInterface $e) { try { parent::doHeloCommand(); + + return []; } catch (TransportExceptionInterface $ex) { if (!$ex->getCode()) { throw $e; diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php index 3c05e94e376d1..517aa0c31906a 100644 --- a/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php +++ b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php @@ -301,7 +301,8 @@ private function assertResponseCode(string $response, array $codes): void if (!$valid || !$response) { $codeStr = $code ? sprintf('code "%s"', $code) : 'empty code'; $responseStr = $response ? sprintf(', with message "%s"', trim($response)) : ''; - throw new TransportException(sprintf('Expected response code "%s" but got ', implode('/', $codes), $codeStr).$codeStr.$responseStr.'.', $code); + + throw new TransportException(sprintf('Expected response code "%s" but got ', implode('/', $codes)).$codeStr.$responseStr.'.', $code ?: 0); } } From c09e7a6b8e6cd48e108a1737ce0db280d6082af9 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Mon, 29 Aug 2022 01:24:00 +0200 Subject: [PATCH 08/57] [WebProfilerBundle] Fix profile search bar link query params --- .../WebProfilerBundle/Resources/views/Profiler/layout.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig index 379653cf93f3c..00c64cadf6aa0 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig @@ -108,7 +108,7 @@ {{ include('@WebProfiler/Icon/search.svg') }} Search - {{ render(controller('web_profiler.controller.profiler::searchBarAction', request.query.all)) }} + {{ render(controller('web_profiler.controller.profiler::searchBarAction', query=request.query.all)) }} From 39cd15b506d9c7cc93d1a8501e7d098b2509d922 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 30 Aug 2022 12:21:51 +0200 Subject: [PATCH 09/57] Fix checking result of DateTime::getLastErrors --- .../Core/DataTransformer/DateTimeToStringTransformer.php | 2 +- .../Component/Validator/Constraints/DateTimeValidator.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php index 51d42494d1def..bae85a86fbec5 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToStringTransformer.php @@ -121,7 +121,7 @@ public function reverseTransform($value) $outputTz = new \DateTimeZone($this->outputTimezone); $dateTime = \DateTime::createFromFormat($this->parseFormat, $value, $outputTz); - $lastErrors = \DateTime::getLastErrors(); + $lastErrors = \DateTime::getLastErrors() ?: ['error_count' => 0, 'warning_count' => 0]; if (0 < $lastErrors['warning_count'] || 0 < $lastErrors['error_count']) { throw new TransformationFailedException(implode(', ', array_merge(array_values($lastErrors['warnings']), array_values($lastErrors['errors'])))); diff --git a/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php b/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php index 1a3ae3784b422..5f2c7a8ef140e 100644 --- a/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php +++ b/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php @@ -48,7 +48,7 @@ public function validate($value, Constraint $constraint) \DateTime::createFromFormat($constraint->format, $value); - $errors = \DateTime::getLastErrors(); + $errors = \DateTime::getLastErrors() ?: ['error_count' => 0, 'warnings' => []]; if (0 < $errors['error_count']) { $this->context->buildViolation($constraint->message) From c0efe1a0880fcb2201b1f5966b775129c700e73b Mon Sep 17 00:00:00 2001 From: MatTheCat Date: Sun, 21 Aug 2022 11:55:11 +0200 Subject: [PATCH 10/57] [FrameworkBundle] Do not throw when describing a factory definition --- .../Console/Descriptor/JsonDescriptor.php | 2 +- .../Console/Descriptor/MarkdownDescriptor.php | 2 +- .../Console/Descriptor/TextDescriptor.php | 2 +- .../Console/Descriptor/XmlDescriptor.php | 2 +- .../Console/Descriptor/ObjectsProvider.php | 4 ++++ .../Descriptor/builder_1_services.json | 14 ++++++++++++++ .../Fixtures/Descriptor/builder_1_services.md | 14 ++++++++++++++ .../Fixtures/Descriptor/builder_1_services.txt | 1 + .../Fixtures/Descriptor/builder_1_services.xml | 3 +++ .../Fixtures/Descriptor/definition_3.json | 14 ++++++++++++++ .../Tests/Fixtures/Descriptor/definition_3.md | 11 +++++++++++ .../Tests/Fixtures/Descriptor/definition_3.txt | 18 ++++++++++++++++++ .../Tests/Fixtures/Descriptor/definition_3.xml | 4 ++++ .../Descriptor/definition_arguments_3.json | 15 +++++++++++++++ .../Descriptor/definition_arguments_3.md | 12 ++++++++++++ .../Descriptor/definition_arguments_3.txt | 18 ++++++++++++++++++ .../Descriptor/definition_arguments_3.xml | 4 ++++ 17 files changed, 136 insertions(+), 4 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.json create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.md create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.txt create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.xml create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.json create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.md create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.txt create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.xml diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php index 64841b1a25d4e..f22e6f48b71fb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php @@ -219,7 +219,7 @@ private function getContainerDefinitionData(Definition $definition, bool $omitTa if ($factory[0] instanceof Reference) { $data['factory_service'] = (string) $factory[0]; } elseif ($factory[0] instanceof Definition) { - throw new \InvalidArgumentException('Factory is not describable.'); + $data['factory_class'] = $factory[0]->getClass() ?? 'not configured'; } else { $data['factory_class'] = $factory[0]; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php index a2360a094ee9a..bd3f8c78d67e5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php @@ -196,7 +196,7 @@ protected function describeContainerDefinition(Definition $definition, array $op if ($factory[0] instanceof Reference) { $output .= "\n".'- Factory Service: `'.$factory[0].'`'; } elseif ($factory[0] instanceof Definition) { - throw new \InvalidArgumentException('Factory is not describable.'); + $output .= "\n".'- Factory Class: `'.($factory[0]->getClass() ?? 'not configured').'`'; } else { $output .= "\n".'- Factory Class: `'.$factory[0].'`'; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index 67669e5a3c3cc..e5bb80010ca7b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -309,7 +309,7 @@ protected function describeContainerDefinition(Definition $definition, array $op if ($factory[0] instanceof Reference) { $tableRows[] = ['Factory Service', $factory[0]]; } elseif ($factory[0] instanceof Definition) { - throw new \InvalidArgumentException('Factory is not describable.'); + $tableRows[] = ['Factory Class', $factory[0]->getClass() ?? 'not configured']; } else { $tableRows[] = ['Factory Class', $factory[0]]; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php index 65e3dbc17b077..7d13cc35df0ae 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php @@ -294,7 +294,7 @@ private function getContainerDefinitionDocument(Definition $definition, string $ if ($factory[0] instanceof Reference) { $factoryXML->setAttribute('service', (string) $factory[0]); } elseif ($factory[0] instanceof Definition) { - throw new \InvalidArgumentException('Factory is not describable.'); + $factoryXML->setAttribute('class', $factory[0]->getClass() ?? 'not configured'); } else { $factoryXML->setAttribute('class', $factory[0]); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php index a097e058be7dd..4d96e90f0ef27 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php @@ -123,6 +123,7 @@ public static function getContainerDefinitions() { $definition1 = new Definition('Full\\Qualified\\Class1'); $definition2 = new Definition('Full\\Qualified\\Class2'); + $definition3 = new Definition('Full\\Qualified\\Class3'); return [ 'definition_1' => $definition1 @@ -154,6 +155,9 @@ public static function getContainerDefinitions() ->addTag('tag2') ->addMethodCall('setMailer', [new Reference('mailer')]) ->setFactory([new Reference('factory.service'), 'get']), + '.definition_3' => $definition3 + ->setFile('/path/to/file') + ->setFactory([new Definition('Full\\Qualified\\FactoryClass'), 'get']), 'definition_without_class' => new Definition(), ]; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json index 0eda1932f7a15..31987c13f6c0c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json @@ -34,6 +34,20 @@ "parameters": [] } ] + }, + ".definition_3": { + "class": "Full\\Qualified\\Class3", + "public": false, + "synthetic": false, + "lazy": false, + "shared": true, + "abstract": false, + "autowire": false, + "autoconfigure": false, + "file": "\/path\/to\/file", + "factory_class": "Full\\Qualified\\FactoryClass", + "factory_method": "get", + "tags": [] } }, "aliases": { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md index 2d0edfd01952e..2bc9cfac9582d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md @@ -25,6 +25,20 @@ Definitions - Attr3: val3 - Tag: `tag2` +### .definition_3 + +- Class: `Full\Qualified\Class3` +- Public: no +- Synthetic: no +- Lazy: no +- Shared: yes +- Abstract: no +- Autowired: no +- Autoconfigured: no +- File: `/path/to/file` +- Factory Class: `Full\Qualified\FactoryClass` +- Factory Method: `get` + Aliases ------- diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.txt index 82b4909242d84..daf47ddc39187 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.txt +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.txt @@ -7,5 +7,6 @@ --------------- ------------------------ .alias_2 alias for ".service_2" .definition_2 Full\Qualified\Class2 + .definition_3 Full\Qualified\Class3 --------------- ------------------------ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.xml index a311a2e2bb991..fd450279000b2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.xml @@ -17,4 +17,7 @@ + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.json new file mode 100644 index 0000000000000..1c9f6abbf1b0c --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.json @@ -0,0 +1,14 @@ +{ + "class": "Full\\Qualified\\Class3", + "public": false, + "synthetic": false, + "lazy": false, + "shared": true, + "abstract": false, + "autowire": false, + "autoconfigure": false, + "file": "\/path\/to\/file", + "factory_class": "Full\\Qualified\\FactoryClass", + "factory_method": "get", + "tags": [] +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.md new file mode 100644 index 0000000000000..7db01b0b02045 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.md @@ -0,0 +1,11 @@ +- Class: `Full\Qualified\Class3` +- Public: no +- Synthetic: no +- Lazy: no +- Shared: yes +- Abstract: no +- Autowired: no +- Autoconfigured: no +- File: `/path/to/file` +- Factory Class: `Full\Qualified\FactoryClass` +- Factory Method: `get` diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.txt new file mode 100644 index 0000000000000..9a1de59a7e9a4 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.txt @@ -0,0 +1,18 @@ + ---------------- ----------------------------- +  Option   Value  + ---------------- ----------------------------- + Service ID - + Class Full\Qualified\Class3 + Tags - + Public no + Synthetic no + Lazy no + Shared yes + Abstract no + Autowired no + Autoconfigured no + Required File /path/to/file + Factory Class Full\Qualified\FactoryClass + Factory Method get + ---------------- ----------------------------- + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.xml new file mode 100644 index 0000000000000..4969b699e5763 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.xml @@ -0,0 +1,4 @@ + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.json new file mode 100644 index 0000000000000..9971492075ca9 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.json @@ -0,0 +1,15 @@ +{ + "class": "Full\\Qualified\\Class3", + "public": false, + "synthetic": false, + "lazy": false, + "shared": true, + "abstract": false, + "autowire": false, + "autoconfigure": false, + "arguments": [], + "file": "\/path\/to\/file", + "factory_class": "Full\\Qualified\\FactoryClass", + "factory_method": "get", + "tags": [] +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.md new file mode 100644 index 0000000000000..40051de909ef4 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.md @@ -0,0 +1,12 @@ +- Class: `Full\Qualified\Class3` +- Public: no +- Synthetic: no +- Lazy: no +- Shared: yes +- Abstract: no +- Autowired: no +- Autoconfigured: no +- Arguments: no +- File: `/path/to/file` +- Factory Class: `Full\Qualified\FactoryClass` +- Factory Method: `get` diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.txt new file mode 100644 index 0000000000000..b3c6fd80560f2 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.txt @@ -0,0 +1,18 @@ + ---------------- ----------------------------- +  Option   Value  + ---------------- ----------------------------- + Service ID - + Class Full\Qualified\Class3 + Tags - + Public no + Synthetic no + Lazy no + Shared yes + Abstract no + Autowired no + Autoconfigured no + Required File /path/to/file + Factory Class Full\Qualified\FactoryClass + Factory Method get + ---------------- ----------------------------- + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.xml new file mode 100644 index 0000000000000..4969b699e5763 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.xml @@ -0,0 +1,4 @@ + + + + From 118acea77a24c20dc8fd13f6ddefba0f85c77ca8 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 30 Aug 2022 18:14:54 +0200 Subject: [PATCH 11/57] [HttpFoundation] move flushing outside of Response::closeOutputBuffers --- src/Symfony/Component/HttpFoundation/Response.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php index c14a7bbfdfcb5..75f64fa9eb907 100644 --- a/src/Symfony/Component/HttpFoundation/Response.php +++ b/src/Symfony/Component/HttpFoundation/Response.php @@ -384,6 +384,7 @@ public function send() fastcgi_finish_request(); } elseif (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true)) { static::closeOutputBuffers(0, true); + flush(); } return $this; @@ -1236,7 +1237,6 @@ public static function closeOutputBuffers(int $targetLevel, bool $flush): void while ($level-- > $targetLevel && ($s = $status[$level]) && (!isset($s['del']) ? !isset($s['flags']) || ($s['flags'] & $flags) === $flags : $s['del'])) { if ($flush) { ob_end_flush(); - flush(); } else { ob_end_clean(); } From d2370e525c6a34c4a5760d76d1dbec439cb44b22 Mon Sep 17 00:00:00 2001 From: Martin Komischke Date: Tue, 30 Aug 2022 17:05:50 +0200 Subject: [PATCH 12/57] fix typo --- src/Symfony/Component/DependencyInjection/Attribute/When.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Attribute/When.php b/src/Symfony/Component/DependencyInjection/Attribute/When.php index 60b7af04b6e21..302b7b0507737 100644 --- a/src/Symfony/Component/DependencyInjection/Attribute/When.php +++ b/src/Symfony/Component/DependencyInjection/Attribute/When.php @@ -12,7 +12,7 @@ namespace Symfony\Component\DependencyInjection\Attribute; /** - * An attribute to tell under which environement this class should be registered as a service. + * An attribute to tell under which environment this class should be registered as a service. * * @author Nicolas Grekas */ From be97af45d411daf532da9ade42fda76b02616063 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 30 Aug 2022 20:56:59 +0200 Subject: [PATCH 13/57] [Mime] Fix email rendering when having inlined parts that are not related to the content --- src/Symfony/Component/Mime/Email.php | 32 ++++++++++--------- .../Component/Mime/Tests/EmailTest.php | 29 +++++++++++++++++ 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/src/Symfony/Component/Mime/Email.php b/src/Symfony/Component/Mime/Email.php index 9cdde13e533c6..70ea745788e8a 100644 --- a/src/Symfony/Component/Mime/Email.php +++ b/src/Symfony/Component/Mime/Email.php @@ -463,7 +463,7 @@ private function generateBody(): AbstractPart $this->ensureValidity(); - [$htmlPart, $attachmentParts, $inlineParts] = $this->prepareParts(); + [$htmlPart, $otherParts, $relatedParts] = $this->prepareParts(); $part = null === $this->text ? null : new TextPart($this->text, $this->textCharset); if (null !== $htmlPart) { @@ -474,15 +474,15 @@ private function generateBody(): AbstractPart } } - if ($inlineParts) { - $part = new RelatedPart($part, ...$inlineParts); + if ($relatedParts) { + $part = new RelatedPart($part, ...$relatedParts); } - if ($attachmentParts) { + if ($otherParts) { if ($part) { - $part = new MixedPart($part, ...$attachmentParts); + $part = new MixedPart($part, ...$otherParts); } else { - $part = new MixedPart(...$attachmentParts); + $part = new MixedPart(...$otherParts); } } @@ -508,42 +508,44 @@ private function prepareParts(): ?array } // usage of reflection is a temporary workaround for missing getters that will be added in 6.2 - $dispositionRef = new \ReflectionProperty(TextPart::class, 'disposition'); - $dispositionRef->setAccessible(true); $nameRef = new \ReflectionProperty(TextPart::class, 'name'); $nameRef->setAccessible(true); - $attachmentParts = $inlineParts = []; + $otherParts = $relatedParts = []; foreach ($this->attachments as $attachment) { $part = $this->createDataPart($attachment); if (isset($attachment['part'])) { $attachment['name'] = $nameRef->getValue($part); } + $related = false; foreach ($names as $name) { if ($name !== $attachment['name']) { continue; } - if (isset($inlineParts[$name])) { + if (isset($relatedParts[$name])) { continue 2; } $part->setDisposition('inline'); - $html = str_replace('cid:'.$name, 'cid:'.$part->getContentId(), $html); + $html = str_replace('cid:'.$name, 'cid:'.$part->getContentId(), $html, $count); + if ($count) { + $related = true; + } $part->setName($part->getContentId()); break; } - if ('inline' === $dispositionRef->getValue($part)) { - $inlineParts[$attachment['name']] = $part; + if ($related) { + $relatedParts[$attachment['name']] = $part; } else { - $attachmentParts[] = $part; + $otherParts[] = $part; } } if (null !== $htmlPart) { $htmlPart = new TextPart($html, $this->htmlCharset, 'html'); } - return [$htmlPart, $attachmentParts, array_values($inlineParts)]; + return [$htmlPart, $otherParts, array_values($relatedParts)]; } private function createDataPart(array $attachment): DataPart diff --git a/src/Symfony/Component/Mime/Tests/EmailTest.php b/src/Symfony/Component/Mime/Tests/EmailTest.php index a79a785576361..2d03a8a9aeedd 100644 --- a/src/Symfony/Component/Mime/Tests/EmailTest.php +++ b/src/Symfony/Component/Mime/Tests/EmailTest.php @@ -302,6 +302,17 @@ public function testGenerateBodyWithHtmlContentAndAttachedFile() $this->assertEquals(new MixedPart($html, $filePart), $e->getBody()); } + public function testGenerateBodyWithHtmlContentAndInlineImageNotreferenced() + { + [$text, $html, $filePart, $file, $imagePart, $image] = $this->generateSomeParts(); + $imagePart = new DataPart($image = fopen(__DIR__.'/Fixtures/mimetypes/test.gif', 'r')); + $imagePart->asInline(); + $e = (new Email())->from('me@example.com')->to('you@example.com'); + $e->embed($image); + $e->html('html content'); + $this->assertEquals(new MixedPart($html, $imagePart), $e->getBody()); + } + public function testGenerateBodyWithAttachedFileOnly() { [$text, $html, $filePart, $file, $imagePart, $image] = $this->generateSomeParts(); @@ -310,6 +321,24 @@ public function testGenerateBodyWithAttachedFileOnly() $this->assertEquals(new MixedPart($filePart), $e->getBody()); } + public function testGenerateBodyWithInlineImageOnly() + { + $imagePart = new DataPart($image = fopen(__DIR__.'/Fixtures/mimetypes/test.gif', 'r')); + $imagePart->asInline(); + $e = (new Email())->from('me@example.com')->to('you@example.com'); + $e->embed($image); + $this->assertEquals(new MixedPart($imagePart), $e->getBody()); + } + + public function testGenerateBodyWithEmbeddedImageOnly() + { + $imagePart = new DataPart($image = fopen(__DIR__.'/Fixtures/mimetypes/test.gif', 'r')); + $e = (new Email())->from('me@example.com')->to('you@example.com'); + $e->embed($image); + $imagePart->asInline(); + $this->assertEquals(new MixedPart($imagePart), $e->getBody()); + } + public function testGenerateBodyWithTextAndHtmlContentAndAttachedFile() { [$text, $html, $filePart, $file, $imagePart, $image] = $this->generateSomeParts(); From d873a206c726858632202fca2cbeb7fd2401dc6a Mon Sep 17 00:00:00 2001 From: Guilherme Ferreira Date: Wed, 31 Aug 2022 00:05:24 +0200 Subject: [PATCH 14/57] Using identical comparison for path validation --- .../Component/Asset/VersionStrategy/StaticVersionStrategy.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php b/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php index e7ce0ec218976..d752cd4c2f13d 100644 --- a/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php +++ b/src/Symfony/Component/Asset/VersionStrategy/StaticVersionStrategy.php @@ -46,7 +46,7 @@ public function applyVersion($path) { $versionized = sprintf($this->format, ltrim($path, '/'), $this->getVersion($path)); - if ($path && '/' == $path[0]) { + if ($path && '/' === $path[0]) { return '/'.$versionized; } From e65c54c18efc6f3ce4d3ed5d271c2a73c3a66828 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 30 Aug 2022 18:39:01 +0200 Subject: [PATCH 15/57] [HttpKernel] lock when writting profiles --- .../Profiler/FileProfilerStorage.php | 56 +++++++++---------- 1 file changed, 28 insertions(+), 28 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php b/src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php index d729994c1f0cc..aa494691d1fc1 100644 --- a/src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php +++ b/src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php @@ -115,19 +115,7 @@ public function purge() */ public function read($token): ?Profile { - if (!$token || !file_exists($file = $this->getFilename($token))) { - return null; - } - - if (\function_exists('gzcompress')) { - $file = 'compress.zlib://'.$file; - } - - if (!$data = unserialize(file_get_contents($file))) { - return null; - } - - return $this->createProfileFromData($token, $data); + return $this->doRead($token); } /** @@ -169,14 +157,13 @@ public function write(Profile $profile): bool 'status_code' => $profile->getStatusCode(), ]; - $context = stream_context_create(); + $data = serialize($data); - if (\function_exists('gzcompress')) { - $file = 'compress.zlib://'.$file; - stream_context_set_option($context, 'zlib', 'level', 3); + if (\function_exists('gzencode')) { + $data = gzencode($data, 3); } - if (false === file_put_contents($file, serialize($data), 0, $context)) { + if (false === file_put_contents($file, $data, \LOCK_EX)) { return false; } @@ -293,21 +280,34 @@ protected function createProfileFromData($token, $data, $parent = null) } foreach ($data['children'] as $token) { - if (!$token || !file_exists($file = $this->getFilename($token))) { - continue; + if (null !== $childProfile = $this->doRead($token, $profile)) { + $profile->addChild($childProfile); } + } - if (\function_exists('gzcompress')) { - $file = 'compress.zlib://'.$file; - } + return $profile; + } - if (!$childData = unserialize(file_get_contents($file))) { - continue; - } + private function doRead($token, Profile $profile = null): ?Profile + { + if (!$token || !file_exists($file = $this->getFilename($token))) { + return null; + } + + $h = fopen($file, 'r'); + flock($h, \LOCK_SH); + $data = stream_get_contents($h); + flock($h, \LOCK_UN); + fclose($h); - $profile->addChild($this->createProfileFromData($token, $childData, $profile)); + if (\function_exists('gzdecode')) { + $data = @gzdecode($data) ?: $data; } - return $profile; + if (!$data = unserialize($data)) { + return null; + } + + return $this->createProfileFromData($token, $data, $profile); } } From 1864eaa38ca692a4d80a2c2132260cfd6068c25b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 31 Aug 2022 10:40:26 +0200 Subject: [PATCH 16/57] [FrameworkBundle] fix test --- .../FrameworkBundle/Tests/Kernel/MicroKernelTraitTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Kernel/MicroKernelTraitTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Kernel/MicroKernelTraitTest.php index d47ca5a822139..1aa15d48daa69 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Kernel/MicroKernelTraitTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Kernel/MicroKernelTraitTest.php @@ -101,7 +101,7 @@ public function testSecretLoadedFromExtension() public function testAnonymousMicroKernel() { - $kernel = new class('anonymous_kernel') extends MinimalKernel { + $kernel = $this->kernel = new class('anonymous_kernel') extends MinimalKernel { public function helloAction(): Response { return new Response('Hello World!'); From c3cae1f38c1b72c8d2d2dd4638d4d024fef968f7 Mon Sep 17 00:00:00 2001 From: Mathieu Piot Date: Mon, 29 Aug 2022 12:21:59 +0200 Subject: [PATCH 17/57] [String] CamelCase/SnakeCase on uppercase word --- src/Symfony/Component/String/AbstractUnicodeString.php | 2 +- src/Symfony/Component/String/ByteString.php | 5 ++++- src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php | 4 ++++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/String/AbstractUnicodeString.php b/src/Symfony/Component/String/AbstractUnicodeString.php index 6fd418e65afe9..1bc6f88fdac22 100644 --- a/src/Symfony/Component/String/AbstractUnicodeString.php +++ b/src/Symfony/Component/String/AbstractUnicodeString.php @@ -162,7 +162,7 @@ public function ascii(array $rules = []): self public function camel(): parent { $str = clone $this; - $str->string = str_replace(' ', '', preg_replace_callback('/\b./u', static function ($m) use (&$i) { + $str->string = str_replace(' ', '', preg_replace_callback('/\b.(?![A-Z]{2,})/u', static function ($m) use (&$i) { return 1 === ++$i ? ('İ' === $m[0] ? 'i̇' : mb_strtolower($m[0], 'UTF-8')) : mb_convert_case($m[0], \MB_CASE_TITLE, 'UTF-8'); }, preg_replace('/[^\pL0-9]++/u', ' ', $this->string))); diff --git a/src/Symfony/Component/String/ByteString.php b/src/Symfony/Component/String/ByteString.php index d9ee3edb52cb2..626d8c1bb31fe 100644 --- a/src/Symfony/Component/String/ByteString.php +++ b/src/Symfony/Component/String/ByteString.php @@ -103,7 +103,10 @@ public function append(string ...$suffix): parent public function camel(): parent { $str = clone $this; - $str->string = lcfirst(str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $this->string)))); + + $parts = explode(' ', trim(ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $this->string)))); + $parts[0] = 1 !== \strlen($parts[0]) && ctype_upper($parts[0]) ? $parts[0] : lcfirst($parts[0]); + $str->string = implode('', $parts); return $str; } diff --git a/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php b/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php index b3c3d9086e1e6..a0cf2068f9476 100644 --- a/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php +++ b/src/Symfony/Component/String/Tests/AbstractAsciiTestCase.php @@ -1042,11 +1042,13 @@ public static function provideCamel() return [ ['', ''], ['xY', 'x_y'], + ['xuYo', 'xu_yo'], ['symfonyIsGreat', 'symfony_is_great'], ['symfony5IsGreat', 'symfony_5_is_great'], ['symfonyIsGreat', 'Symfony is great'], ['symfonyIsAGreatFramework', 'Symfony is a great framework'], ['symfonyIsGREAT', '*Symfony* is GREAT!!'], + ['SYMFONY', 'SYMFONY'], ]; } @@ -1066,6 +1068,7 @@ public static function provideSnake() ['', ''], ['x_y', 'x_y'], ['x_y', 'X_Y'], + ['xu_yo', 'xu_yo'], ['symfony_is_great', 'symfonyIsGreat'], ['symfony5_is_great', 'symfony5IsGreat'], ['symfony5is_great', 'symfony5isGreat'], @@ -1073,6 +1076,7 @@ public static function provideSnake() ['symfony_is_a_great_framework', 'symfonyIsAGreatFramework'], ['symfony_is_great', 'symfonyIsGREAT'], ['symfony_is_really_great', 'symfonyIsREALLYGreat'], + ['symfony', 'SYMFONY'], ]; } From a1a1609b34110e5eb0bfc00891a16c31139be516 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 1 Sep 2022 20:18:29 +0200 Subject: [PATCH 18/57] [Mime] Fix TextPart broken after being serialized --- src/Symfony/Component/Mime/Part/TextPart.php | 1 + src/Symfony/Component/Mime/Tests/Part/TextPartTest.php | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Mime/Part/TextPart.php b/src/Symfony/Component/Mime/Part/TextPart.php index 4afb6560aec0a..bfe41c0aab235 100644 --- a/src/Symfony/Component/Mime/Part/TextPart.php +++ b/src/Symfony/Component/Mime/Part/TextPart.php @@ -197,6 +197,7 @@ public function __sleep() // convert resources to strings for serialization if (null !== $this->seekable) { $this->body = $this->getBody(); + $this->seekable = null; } $this->_headers = $this->getHeaders(); diff --git a/src/Symfony/Component/Mime/Tests/Part/TextPartTest.php b/src/Symfony/Component/Mime/Tests/Part/TextPartTest.php index c3818b883d465..ea14fe29f88af 100644 --- a/src/Symfony/Component/Mime/Tests/Part/TextPartTest.php +++ b/src/Symfony/Component/Mime/Tests/Part/TextPartTest.php @@ -87,6 +87,8 @@ public function testSerialize() $p = new TextPart($r); $p->getHeaders()->addTextHeader('foo', 'bar'); $expected = clone $p; - $this->assertEquals($expected->toString(), unserialize(serialize($p))->toString()); + $n = unserialize(serialize($p)); + $this->assertEquals($expected->toString(), $p->toString()); + $this->assertEquals($expected->toString(), $n->toString()); } } From fcfcba11b67df38f57cd7463625419cb75b60157 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 2 Sep 2022 14:13:40 +0200 Subject: [PATCH 19/57] skip a transient test on Windows --- .../Component/VarDumper/Tests/Server/ConnectionTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/VarDumper/Tests/Server/ConnectionTest.php b/src/Symfony/Component/VarDumper/Tests/Server/ConnectionTest.php index 15e7b0760d3b6..e15b8d6acffb2 100644 --- a/src/Symfony/Component/VarDumper/Tests/Server/ConnectionTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Server/ConnectionTest.php @@ -24,6 +24,10 @@ class ConnectionTest extends TestCase public function testDump() { + if ('True' === getenv('APPVEYOR')) { + $this->markTestSkipped('Skip transient test on AppVeyor'); + } + $cloner = new VarCloner(); $data = $cloner->cloneVar('foo'); $connection = new Connection(self::VAR_DUMPER_SERVER, [ From 5f0a5b44bf14986a515c207fe5974bb9bd8554f1 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 2 Sep 2022 15:07:33 +0200 Subject: [PATCH 20/57] tweak the factory class description for inlined factory services --- .../Console/Descriptor/JsonDescriptor.php | 2 +- .../Console/Descriptor/MarkdownDescriptor.php | 2 +- .../Console/Descriptor/TextDescriptor.php | 2 +- .../Console/Descriptor/XmlDescriptor.php | 2 +- .../Descriptor/builder_1_services.json | 2 +- .../Fixtures/Descriptor/builder_1_services.md | 2 +- .../Descriptor/builder_1_services.xml | 2 +- .../Fixtures/Descriptor/definition_3.json | 2 +- .../Tests/Fixtures/Descriptor/definition_3.md | 2 +- .../Fixtures/Descriptor/definition_3.txt | 34 +++++++++---------- .../Fixtures/Descriptor/definition_3.xml | 2 +- .../Descriptor/definition_arguments_3.json | 2 +- .../Descriptor/definition_arguments_3.md | 2 +- .../Descriptor/definition_arguments_3.txt | 34 +++++++++---------- .../Descriptor/definition_arguments_3.xml | 2 +- 15 files changed, 47 insertions(+), 47 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php index f22e6f48b71fb..3af3ec03f437a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php @@ -219,7 +219,7 @@ private function getContainerDefinitionData(Definition $definition, bool $omitTa if ($factory[0] instanceof Reference) { $data['factory_service'] = (string) $factory[0]; } elseif ($factory[0] instanceof Definition) { - $data['factory_class'] = $factory[0]->getClass() ?? 'not configured'; + $data['factory_service'] = sprintf('inline factory service (%s)', $factory[0]->getClass() ?? 'class not configured'); } else { $data['factory_class'] = $factory[0]; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php index bd3f8c78d67e5..4d48620236f79 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php @@ -196,7 +196,7 @@ protected function describeContainerDefinition(Definition $definition, array $op if ($factory[0] instanceof Reference) { $output .= "\n".'- Factory Service: `'.$factory[0].'`'; } elseif ($factory[0] instanceof Definition) { - $output .= "\n".'- Factory Class: `'.($factory[0]->getClass() ?? 'not configured').'`'; + $output .= "\n".sprintf('- Factory Service: inline factory service (%s)', $factory[0]->getClass() ? sprintf('`%s`', $factory[0]->getClass()) : 'not configured'); } else { $output .= "\n".'- Factory Class: `'.$factory[0].'`'; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index e5bb80010ca7b..5163a8730795b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -309,7 +309,7 @@ protected function describeContainerDefinition(Definition $definition, array $op if ($factory[0] instanceof Reference) { $tableRows[] = ['Factory Service', $factory[0]]; } elseif ($factory[0] instanceof Definition) { - $tableRows[] = ['Factory Class', $factory[0]->getClass() ?? 'not configured']; + $tableRows[] = ['Factory Service', sprintf('inline factory service (%s)', $factory[0]->getClass() ?? 'class not configured')]; } else { $tableRows[] = ['Factory Class', $factory[0]]; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php index 7d13cc35df0ae..28044126f9a7f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php @@ -294,7 +294,7 @@ private function getContainerDefinitionDocument(Definition $definition, string $ if ($factory[0] instanceof Reference) { $factoryXML->setAttribute('service', (string) $factory[0]); } elseif ($factory[0] instanceof Definition) { - $factoryXML->setAttribute('class', $factory[0]->getClass() ?? 'not configured'); + $factoryXML->setAttribute('service', sprintf('inline factory service (%s)', $factory[0]->getClass() ?? 'not configured')); } else { $factoryXML->setAttribute('class', $factory[0]); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json index 31987c13f6c0c..401c588c03d42 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json @@ -45,7 +45,7 @@ "autowire": false, "autoconfigure": false, "file": "\/path\/to\/file", - "factory_class": "Full\\Qualified\\FactoryClass", + "factory_service": "inline factory service (Full\\Qualified\\FactoryClass)", "factory_method": "get", "tags": [] } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md index 2bc9cfac9582d..f8667daa86793 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md @@ -36,7 +36,7 @@ Definitions - Autowired: no - Autoconfigured: no - File: `/path/to/file` -- Factory Class: `Full\Qualified\FactoryClass` +- Factory Service: inline factory service (`Full\Qualified\FactoryClass`) - Factory Method: `get` diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.xml index fd450279000b2..b9416fd069d05 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.xml @@ -18,6 +18,6 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.json index 1c9f6abbf1b0c..4bf56746493f8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.json +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.json @@ -8,7 +8,7 @@ "autowire": false, "autoconfigure": false, "file": "\/path\/to\/file", - "factory_class": "Full\\Qualified\\FactoryClass", + "factory_service": "inline factory service (Full\\Qualified\\FactoryClass)", "factory_method": "get", "tags": [] } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.md index 7db01b0b02045..68f51634db99f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.md +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.md @@ -7,5 +7,5 @@ - Autowired: no - Autoconfigured: no - File: `/path/to/file` -- Factory Class: `Full\Qualified\FactoryClass` +- Factory Service: inline factory service (`Full\Qualified\FactoryClass`) - Factory Method: `get` diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.txt index 9a1de59a7e9a4..35ddaf3e452a8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.txt +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.txt @@ -1,18 +1,18 @@ - ---------------- ----------------------------- -  Option   Value  - ---------------- ----------------------------- - Service ID - - Class Full\Qualified\Class3 - Tags - - Public no - Synthetic no - Lazy no - Shared yes - Abstract no - Autowired no - Autoconfigured no - Required File /path/to/file - Factory Class Full\Qualified\FactoryClass - Factory Method get - ---------------- ----------------------------- + ----------------- ------------------------------------------------------ +  Option   Value  + ----------------- ------------------------------------------------------ + Service ID - + Class Full\Qualified\Class3 + Tags - + Public no + Synthetic no + Lazy no + Shared yes + Abstract no + Autowired no + Autoconfigured no + Required File /path/to/file + Factory Service inline factory service (Full\Qualified\FactoryClass) + Factory Method get + ----------------- ------------------------------------------------------ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.xml index 4969b699e5763..e81c77014253f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_3.xml @@ -1,4 +1,4 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.json index 9971492075ca9..94c2fda5402fc 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.json +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.json @@ -9,7 +9,7 @@ "autoconfigure": false, "arguments": [], "file": "\/path\/to\/file", - "factory_class": "Full\\Qualified\\FactoryClass", + "factory_service": "inline factory service (Full\\Qualified\\FactoryClass)", "factory_method": "get", "tags": [] } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.md index 40051de909ef4..2ce1f264dfc6c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.md +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.md @@ -8,5 +8,5 @@ - Autoconfigured: no - Arguments: no - File: `/path/to/file` -- Factory Class: `Full\Qualified\FactoryClass` +- Factory Service: inline factory service (`Full\Qualified\FactoryClass`) - Factory Method: `get` diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.txt b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.txt index b3c6fd80560f2..6e400de44e8ff 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.txt +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.txt @@ -1,18 +1,18 @@ - ---------------- ----------------------------- -  Option   Value  - ---------------- ----------------------------- - Service ID - - Class Full\Qualified\Class3 - Tags - - Public no - Synthetic no - Lazy no - Shared yes - Abstract no - Autowired no - Autoconfigured no - Required File /path/to/file - Factory Class Full\Qualified\FactoryClass - Factory Method get - ---------------- ----------------------------- + ----------------- ------------------------------------------------------ +  Option   Value  + ----------------- ------------------------------------------------------ + Service ID - + Class Full\Qualified\Class3 + Tags - + Public no + Synthetic no + Lazy no + Shared yes + Abstract no + Autowired no + Autoconfigured no + Required File /path/to/file + Factory Service inline factory service (Full\Qualified\FactoryClass) + Factory Method get + ----------------- ------------------------------------------------------ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.xml index 4969b699e5763..e81c77014253f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_arguments_3.xml @@ -1,4 +1,4 @@ - + From d5e624c339dd2e0d47cb1d23261ade11fe91eacd Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sun, 4 Sep 2022 00:51:21 +0200 Subject: [PATCH 21/57] skip a transient test on AppVeyor --- .../Component/VarDumper/Tests/Dumper/ServerDumperTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/VarDumper/Tests/Dumper/ServerDumperTest.php b/src/Symfony/Component/VarDumper/Tests/Dumper/ServerDumperTest.php index 921cfda456acf..44036295efb68 100644 --- a/src/Symfony/Component/VarDumper/Tests/Dumper/ServerDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Dumper/ServerDumperTest.php @@ -39,6 +39,10 @@ public function testDumpForwardsToWrappedDumperWhenServerIsUnavailable() public function testDump() { + if ('True' === getenv('APPVEYOR')) { + $this->markTestSkipped('Skip transient test on AppVeyor'); + } + $wrappedDumper = $this->createMock(DataDumperInterface::class); $wrappedDumper->expects($this->never())->method('dump'); // test wrapped dumper is not used From f6f8748b110bc8e3b4a31ff710bd0fc6c9b3e599 Mon Sep 17 00:00:00 2001 From: nuryagdym Date: Mon, 29 Aug 2022 01:14:07 +0300 Subject: [PATCH 22/57] Psr18Client ignore invalid HTTP headers --- .../Component/HttpClient/Psr18Client.php | 6 +++++- .../HttpClient/Tests/Psr18ClientTest.php | 20 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/Psr18Client.php b/src/Symfony/Component/HttpClient/Psr18Client.php index 67c2fdb8f07bc..7f79af16426a1 100644 --- a/src/Symfony/Component/HttpClient/Psr18Client.php +++ b/src/Symfony/Component/HttpClient/Psr18Client.php @@ -100,7 +100,11 @@ public function sendRequest(RequestInterface $request): ResponseInterface foreach ($response->getHeaders(false) as $name => $values) { foreach ($values as $value) { - $psrResponse = $psrResponse->withAddedHeader($name, $value); + try { + $psrResponse = $psrResponse->withAddedHeader($name, $value); + } catch (\InvalidArgumentException $e) { + // ignore invalid header + } } } diff --git a/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php b/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php index 1ef36fc5bd09e..366d555ae03f9 100644 --- a/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php @@ -13,10 +13,12 @@ use Nyholm\Psr7\Factory\Psr17Factory; use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpClient\MockHttpClient; use Symfony\Component\HttpClient\NativeHttpClient; use Symfony\Component\HttpClient\Psr18Client; use Symfony\Component\HttpClient\Psr18NetworkException; use Symfony\Component\HttpClient\Psr18RequestException; +use Symfony\Component\HttpClient\Response\MockResponse; use Symfony\Contracts\HttpClient\Test\TestHttpServer; class Psr18ClientTest extends TestCase @@ -81,4 +83,22 @@ public function test404() $response = $client->sendRequest($factory->createRequest('GET', 'http://localhost:8057/404')); $this->assertSame(404, $response->getStatusCode()); } + + public function testInvalidHeaderResponse() + { + $responseHeaders = [ + // space in header name not allowed in RFC 7230 + ' X-XSS-Protection' => '0', + 'Cache-Control' => 'no-cache', + ]; + $response = new MockResponse('body', ['response_headers' => $responseHeaders]); + $this->assertArrayHasKey(' x-xss-protection', $response->getHeaders()); + + $client = new Psr18Client(new MockHttpClient($response)); + $request = $client->createRequest('POST', 'http://localhost:8057/post') + ->withBody($client->createStream('foo=0123456789')); + + $resultResponse = $client->sendRequest($request); + $this->assertCount(1, $resultResponse->getHeaders()); + } } From 89e13985f352b36bb3318797b96c2d2736e30600 Mon Sep 17 00:00:00 2001 From: Andreas Schempp Date: Mon, 5 Sep 2022 16:21:17 +0200 Subject: [PATCH 23/57] Prevent exception if request stack is empty --- .../HttpKernel/DataCollector/RequestDataCollector.php | 2 +- .../Tests/DataCollector/RequestDataCollectorTest.php | 9 +++++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php index 523f5c957f188..951860a225668 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php @@ -110,7 +110,7 @@ public function collect(Request $request, Response $response, \Throwable $except 'session_metadata' => $sessionMetadata, 'session_attributes' => $sessionAttributes, 'session_usages' => array_values($this->sessionUsages), - 'stateless_check' => $this->requestStack && $this->requestStack->getMainRequest()->attributes->get('_stateless', false), + 'stateless_check' => $this->requestStack && ($mainRequest = $this->requestStack->getMainRequest()) && $mainRequest->attributes->get('_stateless', false), 'flashes' => $flashes, 'path_info' => $request->getPathInfo(), 'controller' => 'n/a', diff --git a/src/Symfony/Component/HttpKernel/Tests/DataCollector/RequestDataCollectorTest.php b/src/Symfony/Component/HttpKernel/Tests/DataCollector/RequestDataCollectorTest.php index 0c576e00ed4dd..d7c8b302b628a 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DataCollector/RequestDataCollectorTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DataCollector/RequestDataCollectorTest.php @@ -312,6 +312,15 @@ public function testStatelessCheck() $collector->lateCollect(); $this->assertTrue($collector->getStatelessCheck()); + + $requestStack = new RequestStack(); + $request = $this->createRequest(); + + $collector = new RequestDataCollector($requestStack); + $collector->collect($request, $response = $this->createResponse()); + $collector->lateCollect(); + + $this->assertFalse($collector->getStatelessCheck()); } public function testItHidesPassword() From 62ceded47ca4a581eefbe00c85387c6915a1f8e2 Mon Sep 17 00:00:00 2001 From: Ivan Kurnosov Date: Tue, 6 Sep 2022 09:23:46 +1200 Subject: [PATCH 24/57] Bug #42343 [Security] Fix valid remember-me token exposure to the second consequent request Close https://github.com/symfony/symfony/issues/42343 Fix https://github.com/symfony/symfony/pull/46760 --- .../Http/RememberMe/PersistentRememberMeHandler.php | 5 ++--- .../RememberMe/PersistentRememberMeHandlerTest.php | 13 +------------ 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php b/src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php index 8a5db07e5e8ab..8d9360355282a 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php +++ b/src/Symfony/Component/Security/Http/RememberMe/PersistentRememberMeHandler.php @@ -75,7 +75,6 @@ public function processRememberMe(RememberMeDetails $rememberMeDetails, UserInte if ($this->tokenVerifier) { $isTokenValid = $this->tokenVerifier->verifyToken($persistentToken, $tokenValue); - $tokenValue = $persistentToken->getTokenValue(); } else { $isTokenValid = hash_equals($persistentToken->getTokenValue(), $tokenValue); } @@ -96,9 +95,9 @@ public function processRememberMe(RememberMeDetails $rememberMeDetails, UserInte $this->tokenVerifier->updateExistingToken($persistentToken, $tokenValue, $tokenLastUsed); } $this->tokenProvider->updateToken($series, $tokenValue, $tokenLastUsed); - } - $this->createCookie($rememberMeDetails->withValue($series.':'.$tokenValue)); + $this->createCookie($rememberMeDetails->withValue($series.':'.$tokenValue)); + } } /** diff --git a/src/Symfony/Component/Security/Http/Tests/RememberMe/PersistentRememberMeHandlerTest.php b/src/Symfony/Component/Security/Http/Tests/RememberMe/PersistentRememberMeHandlerTest.php index 770a1c634abe6..4e2c0980ba0aa 100644 --- a/src/Symfony/Component/Security/Http/Tests/RememberMe/PersistentRememberMeHandlerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/RememberMe/PersistentRememberMeHandlerTest.php @@ -125,18 +125,7 @@ public function testConsumeRememberMeCookieValidByValidatorWithoutUpdate() $rememberMeDetails = new RememberMeDetails(InMemoryUser::class, 'wouter', 360, 'series1:oldTokenValue'); $handler->consumeRememberMeCookie($rememberMeDetails); - // assert that the cookie has been updated with a new base64 encoded token value - $this->assertTrue($this->request->attributes->has(ResponseListener::COOKIE_ATTR_NAME)); - - /** @var Cookie $cookie */ - $cookie = $this->request->attributes->get(ResponseListener::COOKIE_ATTR_NAME); - - $cookieParts = explode(':', base64_decode($cookie->getValue()), 4); - - $this->assertSame(InMemoryUser::class, $cookieParts[0]); // class - $this->assertSame(base64_encode('wouter'), $cookieParts[1]); // identifier - $this->assertSame('360', $cookieParts[2]); // expire - $this->assertSame('series1:tokenvalue', $cookieParts[3]); // value + $this->assertFalse($this->request->attributes->has(ResponseListener::COOKIE_ATTR_NAME)); } public function testConsumeRememberMeCookieInvalidToken() From 17e5a5335d7f4809dc955c26aa87b9bf13f239e3 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 6 Sep 2022 09:26:22 +0200 Subject: [PATCH 25/57] [Cache] update readme --- src/Symfony/Component/Cache/README.md | 12 ++++++------ src/Symfony/Component/Cache/composer.json | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Cache/README.md b/src/Symfony/Component/Cache/README.md index 74052052c8c33..c466d57883c2f 100644 --- a/src/Symfony/Component/Cache/README.md +++ b/src/Symfony/Component/Cache/README.md @@ -1,13 +1,13 @@ Symfony PSR-6 implementation for caching ======================================== -The Cache component provides an extended -[PSR-6](http://www.php-fig.org/psr/psr-6/) implementation for adding cache to +The Cache component provides extended +[PSR-6](https://www.php-fig.org/psr/psr-6/) implementations for adding cache to your applications. It is designed to have a low overhead so that caching is -fastest. It ships with a few caching adapters for the most widespread and -suited to caching backends. It also provides a `doctrine/cache` proxy adapter -to cover more advanced caching needs and a proxy adapter for greater -interoperability between PSR-6 implementations. +fastest. It ships with adapters for the most widespread caching backends. +It also provides a [PSR-16](https://www.php-fig.org/psr/psr-16/) adapter, +and implementations for [symfony/cache-contracts](https://github.com/symfony/cache-contracts)' +`CacheInterface` and `TagAwareCacheInterface`. Resources --------- diff --git a/src/Symfony/Component/Cache/composer.json b/src/Symfony/Component/Cache/composer.json index 6ef5eac991d20..7a9e8df5a40e4 100644 --- a/src/Symfony/Component/Cache/composer.json +++ b/src/Symfony/Component/Cache/composer.json @@ -1,7 +1,7 @@ { "name": "symfony/cache", "type": "library", - "description": "Provides an extended PSR-6, PSR-16 (and tags) implementation", + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", "keywords": ["caching", "psr6"], "homepage": "https://symfony.com", "license": "MIT", From cdb6c15618a0907a38445d56806d30041eca3bee Mon Sep 17 00:00:00 2001 From: andrey-tech Date: Tue, 6 Sep 2022 14:08:20 +0300 Subject: [PATCH 26/57] [Bridge] Fix mkdir() race condition in ProxyCacheWarmer --- src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php b/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php index 24cf25be59f3d..08f9fef880e51 100644 --- a/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php +++ b/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php @@ -49,7 +49,7 @@ public function warmUp($cacheDir) foreach ($this->registry->getManagers() as $em) { // we need the directory no matter the proxy cache generation strategy if (!is_dir($proxyCacheDir = $em->getConfiguration()->getProxyDir())) { - if (false === @mkdir($proxyCacheDir, 0777, true)) { + if (false === @mkdir($proxyCacheDir, 0777, true) && !is_dir($proxyCacheDir)) { throw new \RuntimeException(sprintf('Unable to create the Doctrine Proxy directory "%s".', $proxyCacheDir)); } } elseif (!is_writable($proxyCacheDir)) { From fdd73c7f99343242b9d921529a7ca62991e73f61 Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Tue, 6 Sep 2022 14:53:09 +0200 Subject: [PATCH 27/57] [Validator][UID] Stop to first ULID format violation --- src/Symfony/Component/Validator/Constraints/UlidValidator.php | 4 ++++ .../Validator/Tests/Constraints/UlidValidatorTest.php | 1 + 2 files changed, 5 insertions(+) diff --git a/src/Symfony/Component/Validator/Constraints/UlidValidator.php b/src/Symfony/Component/Validator/Constraints/UlidValidator.php index dedaabcfc5998..ad741244132c8 100644 --- a/src/Symfony/Component/Validator/Constraints/UlidValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UlidValidator.php @@ -48,6 +48,8 @@ public function validate($value, Constraint $constraint) ->setParameter('{{ value }}', $this->formatValue($value)) ->setCode(26 > \strlen($value) ? Ulid::TOO_SHORT_ERROR : Ulid::TOO_LONG_ERROR) ->addViolation(); + + return; } if (\strlen($value) !== strspn($value, '0123456789ABCDEFGHJKMNPQRSTVWXYZabcdefghjkmnpqrstvwxyz')) { @@ -55,6 +57,8 @@ public function validate($value, Constraint $constraint) ->setParameter('{{ value }}', $this->formatValue($value)) ->setCode(Ulid::INVALID_CHARACTERS_ERROR) ->addViolation(); + + return; } // Largest valid ULID is '7ZZZZZZZZZZZZZZZZZZZZZZZZZ' diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UlidValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UlidValidatorTest.php index 2c97c97604e6e..8948cbabd8d9f 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UlidValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UlidValidatorTest.php @@ -78,6 +78,7 @@ public function getInvalidUlids() ['01ARZ3NDEKTSV4RRFFQ69G5FAVA', Ulid::TOO_LONG_ERROR], ['01ARZ3NDEKTSV4RRFFQ69G5FAO', Ulid::INVALID_CHARACTERS_ERROR], ['Z1ARZ3NDEKTSV4RRFFQ69G5FAV', Ulid::TOO_LARGE_ERROR], + ['not-even-ulid-like', Ulid::TOO_SHORT_ERROR], ]; } From d822e41538d55c4f78092160f1e8c51fc8858f42 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 8 Sep 2022 10:19:33 +0200 Subject: [PATCH 28/57] [Uid] Fix validating UUID variant bits --- src/Symfony/Component/Uid/Tests/UuidTest.php | 26 ++++++++++++++++++++ src/Symfony/Component/Uid/Ulid.php | 4 +-- src/Symfony/Component/Uid/Uuid.php | 22 +++++++++++------ src/Symfony/Component/Uid/UuidV1.php | 2 +- src/Symfony/Component/Uid/UuidV3.php | 5 ++++ src/Symfony/Component/Uid/UuidV4.php | 2 +- src/Symfony/Component/Uid/UuidV5.php | 5 ++++ src/Symfony/Component/Uid/UuidV6.php | 2 +- 8 files changed, 55 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Component/Uid/Tests/UuidTest.php b/src/Symfony/Component/Uid/Tests/UuidTest.php index dad559f5a31ce..3e3c36c02ab03 100644 --- a/src/Symfony/Component/Uid/Tests/UuidTest.php +++ b/src/Symfony/Component/Uid/Tests/UuidTest.php @@ -44,6 +44,32 @@ public function provideInvalidUuids(): iterable yield ['these are just thirty-six characters']; } + /** + * @dataProvider provideInvalidVariant + */ + public function testInvalidVariant(string $uuid) + { + $uuid = new Uuid($uuid); + $this->assertFalse(Uuid::isValid($uuid)); + + $uuid = (string) $uuid; + $class = Uuid::class.'V'.$uuid[14]; + + $this->expectException(\InvalidArgumentException::class); + $this->expectExceptionMessage('Invalid UUIDv'.$uuid[14].': "'.$uuid.'".'); + + new $class($uuid); + } + + public function provideInvalidVariant(): iterable + { + yield ['8dac64d3-937a-1e7c-fa1d-d5d6c06a61f5']; + yield ['8dac64d3-937a-3e7c-fa1d-d5d6c06a61f5']; + yield ['8dac64d3-937a-4e7c-fa1d-d5d6c06a61f5']; + yield ['8dac64d3-937a-5e7c-fa1d-d5d6c06a61f5']; + yield ['8dac64d3-937a-6e7c-fa1d-d5d6c06a61f5']; + } + public function testConstructorWithValidUuid() { $uuid = new UuidV4(self::A_UUID_V4); diff --git a/src/Symfony/Component/Uid/Ulid.php b/src/Symfony/Component/Uid/Ulid.php index 0ed0673ee3183..a23481612745e 100644 --- a/src/Symfony/Component/Uid/Ulid.php +++ b/src/Symfony/Component/Uid/Ulid.php @@ -64,8 +64,8 @@ public static function isValid(string $ulid): bool */ public static function fromString(string $ulid): parent { - if (36 === \strlen($ulid) && Uuid::isValid($ulid)) { - $ulid = (new Uuid($ulid))->toBinary(); + if (36 === \strlen($ulid) && preg_match('{^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$}Di', $ulid)) { + $ulid = uuid_parse($ulid); } elseif (22 === \strlen($ulid) && 22 === strspn($ulid, BinaryUtil::BASE58[''])) { $ulid = str_pad(BinaryUtil::fromBase($ulid, BinaryUtil::BASE58), 16, "\0", \STR_PAD_LEFT); } diff --git a/src/Symfony/Component/Uid/Uuid.php b/src/Symfony/Component/Uid/Uuid.php index 58c2871c49665..a68c5092f09de 100644 --- a/src/Symfony/Component/Uid/Uuid.php +++ b/src/Symfony/Component/Uid/Uuid.php @@ -26,7 +26,7 @@ class Uuid extends AbstractUid protected const TYPE = 0; protected const NIL = '00000000-0000-0000-0000-000000000000'; - public function __construct(string $uuid) + public function __construct(string $uuid, bool $checkVariant = false) { $type = preg_match('{^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$}Di', $uuid) ? (int) $uuid[14] : false; @@ -35,6 +35,10 @@ public function __construct(string $uuid) } $this->uid = strtolower($uuid); + + if ($checkVariant && !\in_array($this->uid[19], ['8', '9', 'a', 'b'], true)) { + throw new \InvalidArgumentException(sprintf('Invalid UUID%s: "%s".', static::TYPE ? 'v'.static::TYPE : '', $uuid)); + } } /** @@ -67,12 +71,14 @@ public static function fromString(string $uuid): parent return new NilUuid(); } - switch ($uuid[14]) { - case UuidV1::TYPE: return new UuidV1($uuid); - case UuidV3::TYPE: return new UuidV3($uuid); - case UuidV4::TYPE: return new UuidV4($uuid); - case UuidV5::TYPE: return new UuidV5($uuid); - case UuidV6::TYPE: return new UuidV6($uuid); + if (\in_array($uuid[19], ['8', '9', 'a', 'b', 'A', 'B'], true)) { + switch ($uuid[14]) { + case UuidV1::TYPE: return new UuidV1($uuid); + case UuidV3::TYPE: return new UuidV3($uuid); + case UuidV4::TYPE: return new UuidV4($uuid); + case UuidV5::TYPE: return new UuidV5($uuid); + case UuidV6::TYPE: return new UuidV6($uuid); + } } return new self($uuid); @@ -111,7 +117,7 @@ final public static function v6(): UuidV6 public static function isValid(string $uuid): bool { - if (!preg_match('{^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$}Di', $uuid)) { + if (!preg_match('{^[0-9a-f]{8}(?:-[0-9a-f]{4}){2}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$}Di', $uuid)) { return false; } diff --git a/src/Symfony/Component/Uid/UuidV1.php b/src/Symfony/Component/Uid/UuidV1.php index 7c1fceb9065e8..3b8cd5e3fc87a 100644 --- a/src/Symfony/Component/Uid/UuidV1.php +++ b/src/Symfony/Component/Uid/UuidV1.php @@ -27,7 +27,7 @@ public function __construct(string $uuid = null) if (null === $uuid) { $this->uid = uuid_create(static::TYPE); } else { - parent::__construct($uuid); + parent::__construct($uuid, true); } } diff --git a/src/Symfony/Component/Uid/UuidV3.php b/src/Symfony/Component/Uid/UuidV3.php index f89f2d7bb313b..cc9f016b47192 100644 --- a/src/Symfony/Component/Uid/UuidV3.php +++ b/src/Symfony/Component/Uid/UuidV3.php @@ -21,4 +21,9 @@ class UuidV3 extends Uuid { protected const TYPE = 3; + + public function __construct(string $uuid) + { + parent::__construct($uuid, true); + } } diff --git a/src/Symfony/Component/Uid/UuidV4.php b/src/Symfony/Component/Uid/UuidV4.php index 897e1ba627213..9724b67de2c59 100644 --- a/src/Symfony/Component/Uid/UuidV4.php +++ b/src/Symfony/Component/Uid/UuidV4.php @@ -30,7 +30,7 @@ public function __construct(string $uuid = null) $this->uid = substr($uuid, 0, 8).'-'.substr($uuid, 8, 4).'-'.substr($uuid, 12, 4).'-'.substr($uuid, 16, 4).'-'.substr($uuid, 20, 12); } else { - parent::__construct($uuid); + parent::__construct($uuid, true); } } } diff --git a/src/Symfony/Component/Uid/UuidV5.php b/src/Symfony/Component/Uid/UuidV5.php index f671f41250373..74ab133a296c8 100644 --- a/src/Symfony/Component/Uid/UuidV5.php +++ b/src/Symfony/Component/Uid/UuidV5.php @@ -21,4 +21,9 @@ class UuidV5 extends Uuid { protected const TYPE = 5; + + public function __construct(string $uuid) + { + parent::__construct($uuid, true); + } } diff --git a/src/Symfony/Component/Uid/UuidV6.php b/src/Symfony/Component/Uid/UuidV6.php index 5ba260e82a521..bf307ef41916a 100644 --- a/src/Symfony/Component/Uid/UuidV6.php +++ b/src/Symfony/Component/Uid/UuidV6.php @@ -29,7 +29,7 @@ public function __construct(string $uuid = null) if (null === $uuid) { $this->uid = static::generate(); } else { - parent::__construct($uuid); + parent::__construct($uuid, true); } } From 87738ba11894d740d76a157e723d34143f1c95ed Mon Sep 17 00:00:00 2001 From: martkop26 <112486711+martkop26@users.noreply.github.com> Date: Tue, 30 Aug 2022 15:50:25 +0200 Subject: [PATCH 29/57] [HttpClient] Fix computing retry delay when using RetryableHttpClient --- .../HttpClient/RetryableHttpClient.php | 2 +- .../Tests/RetryableHttpClientTest.php | 38 +++++++++++++++++++ 2 files changed, 39 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/RetryableHttpClient.php b/src/Symfony/Component/HttpClient/RetryableHttpClient.php index 4df466f4ceb31..9a5b503fa25fa 100644 --- a/src/Symfony/Component/HttpClient/RetryableHttpClient.php +++ b/src/Symfony/Component/HttpClient/RetryableHttpClient.php @@ -138,7 +138,7 @@ private function getDelayFromHeader(array $headers): ?int { if (null !== $after = $headers['retry-after'][0] ?? null) { if (is_numeric($after)) { - return (int) $after * 1000; + return (int) ($after * 1000); } if (false !== $time = strtotime($after)) { diff --git a/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php index 6bd9a1f15e788..21e63badb9caa 100644 --- a/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php @@ -187,4 +187,42 @@ public function testCancelOnTimeout() $response->cancel(); } } + + public function testRetryWithDelay() + { + $retryAfter = '0.46'; + + $client = new RetryableHttpClient( + new MockHttpClient([ + new MockResponse('', [ + 'http_code' => 503, + 'response_headers' => [ + 'retry-after' => $retryAfter, + ], + ]), + new MockResponse('', [ + 'http_code' => 200, + ]), + ]), + new GenericRetryStrategy(), + 1, + $logger = new class() extends TestLogger { + public array $context = []; + + public function log($level, $message, array $context = []): void + { + $this->context = $context; + parent::log($level, $message, $context); + } + }, + ); + + $client->request('GET', 'http://example.com/foo-bar')->getContent(); + + $delay = $logger->context['delay'] ?? null; + + $this->assertArrayHasKey('delay', $logger->context); + $this->assertNotNull($delay); + $this->assertSame((int) ($retryAfter * 1000), $delay); + } } From 1f4cfc799a7c50105ac0f99fe2d76e753e135a7b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 8 Sep 2022 11:37:16 +0200 Subject: [PATCH 30/57] [HttpClient] fix merge --- .../Component/HttpClient/Tests/RetryableHttpClientTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php index 21e63badb9caa..5c6e17ea31832 100644 --- a/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php @@ -207,7 +207,7 @@ public function testRetryWithDelay() new GenericRetryStrategy(), 1, $logger = new class() extends TestLogger { - public array $context = []; + public $context = []; public function log($level, $message, array $context = []): void { From 6e8fc95fe22cac87698684ca5c6812b99f58978a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 8 Sep 2022 20:41:21 +0200 Subject: [PATCH 31/57] [HttpClient] fix merge --- .../Component/HttpClient/Tests/RetryableHttpClientTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php index 5c6e17ea31832..85a03fd225183 100644 --- a/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php @@ -214,7 +214,7 @@ public function log($level, $message, array $context = []): void $this->context = $context; parent::log($level, $message, $context); } - }, + } ); $client->request('GET', 'http://example.com/foo-bar')->getContent(); From 1cf5d37d5913b22589ca53a623a68f8f0130eb3f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 8 Sep 2022 18:30:24 +0200 Subject: [PATCH 32/57] [Uid] Ensure ULIDs are monotonic even when the time goes backward --- src/Symfony/Component/Uid/Tests/UlidTest.php | 5 +++ src/Symfony/Component/Uid/Ulid.php | 33 ++++++++------------ 2 files changed, 18 insertions(+), 20 deletions(-) diff --git a/src/Symfony/Component/Uid/Tests/UlidTest.php b/src/Symfony/Component/Uid/Tests/UlidTest.php index 9a8ee9a78abe0..50801a840c326 100644 --- a/src/Symfony/Component/Uid/Tests/UlidTest.php +++ b/src/Symfony/Component/Uid/Tests/UlidTest.php @@ -26,11 +26,16 @@ public function testGenerate() { $a = new Ulid(); $b = new Ulid(); + usleep(-10000); + $c = new Ulid(); $this->assertSame(0, strncmp($a, $b, 20)); + $this->assertSame(0, strncmp($a, $c, 20)); $a = base_convert(strtr(substr($a, -6), 'ABCDEFGHJKMNPQRSTVWXYZ', 'abcdefghijklmnopqrstuv'), 32, 10); $b = base_convert(strtr(substr($b, -6), 'ABCDEFGHJKMNPQRSTVWXYZ', 'abcdefghijklmnopqrstuv'), 32, 10); + $c = base_convert(strtr(substr($c, -6), 'ABCDEFGHJKMNPQRSTVWXYZ', 'abcdefghijklmnopqrstuv'), 32, 10); $this->assertSame(1, $b - $a); + $this->assertSame(1, $c - $b); } public function testWithInvalidUlid() diff --git a/src/Symfony/Component/Uid/Ulid.php b/src/Symfony/Component/Uid/Ulid.php index a23481612745e..bda82ef6856c9 100644 --- a/src/Symfony/Component/Uid/Ulid.php +++ b/src/Symfony/Component/Uid/Ulid.php @@ -137,7 +137,7 @@ public function getDateTime(): \DateTimeImmutable } if (4 > \strlen($time)) { - $time = str_pad($time, 4, '0', \STR_PAD_LEFT); + $time = '000'.$time; } return \DateTimeImmutable::createFromFormat('U.u', substr_replace($time, '.', -3, 0)); @@ -145,25 +145,15 @@ public function getDateTime(): \DateTimeImmutable public static function generate(\DateTimeInterface $time = null): string { - if (null === $time) { - return self::doGenerate(); - } - - if (0 > $time = substr($time->format('Uu'), 0, -3)) { - throw new \InvalidArgumentException('The timestamp must be positive.'); - } - - return self::doGenerate($time); - } - - private static function doGenerate(string $mtime = null): string - { - if (null === $time = $mtime) { + if (null === $mtime = $time) { $time = microtime(false); $time = substr($time, 11).substr($time, 2, 3); + } elseif (0 > $time = $time->format('Uv')) { + throw new \InvalidArgumentException('The timestamp must be positive.'); } - if ($time !== self::$time) { + if ($time > self::$time || (null !== $mtime && $time !== self::$time)) { + randomize: $r = unpack('nr1/nr2/nr3/nr4/nr', random_bytes(10)); $r['r1'] |= ($r['r'] <<= 4) & 0xF0000; $r['r2'] |= ($r['r'] <<= 4) & 0xF0000; @@ -173,19 +163,22 @@ private static function doGenerate(string $mtime = null): string self::$rand = array_values($r); self::$time = $time; } elseif ([0xFFFFF, 0xFFFFF, 0xFFFFF, 0xFFFFF] === self::$rand) { - if (null === $mtime) { - usleep(100); + if (\PHP_INT_SIZE >= 8 || 10 > \strlen($time = self::$time)) { + $time = (string) (1 + $time); + } elseif ('999999999' === $mtime = substr($time, -9)) { + $time = (1 + substr($time, 0, -9)).'000000000'; } else { - self::$rand = [0, 0, 0, 0]; + $time = substr_replace($time, str_pad(++$mtime, 9, '0', \STR_PAD_LEFT), -9); } - return self::doGenerate($mtime); + goto randomize; } else { for ($i = 3; $i >= 0 && 0xFFFFF === self::$rand[$i]; --$i) { self::$rand[$i] = 0; } ++self::$rand[$i]; + $time = self::$time; } if (\PHP_INT_SIZE >= 8) { From 4760265edd7a3f3127c508e80eedd70c261df693 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 9 Sep 2022 11:14:45 +0200 Subject: [PATCH 33/57] [Form] fix UUID tranformer --- .../UuidToStringTransformer.php | 8 +++-- .../UuidToStringTransformerTest.php | 30 +++++-------------- 2 files changed, 12 insertions(+), 26 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/UuidToStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/UuidToStringTransformer.php index 1ccf04b223c09..c4775bb12bca5 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/UuidToStringTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/UuidToStringTransformer.php @@ -64,12 +64,14 @@ public function reverseTransform($value) throw new TransformationFailedException('Expected a string.'); } + if (!Uuid::isValid($value)) { + throw new TransformationFailedException(sprintf('The value "%s" is not a valid UUID.', $value)); + } + try { - $uuid = new Uuid($value); + return Uuid::fromString($value); } catch (\InvalidArgumentException $e) { throw new TransformationFailedException(sprintf('The value "%s" is not a valid UUID.', $value), $e->getCode(), $e); } - - return $uuid; } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/UuidToStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/UuidToStringTransformerTest.php index f7a93beca8fb9..cb4374535ed70 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/UuidToStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/UuidToStringTransformerTest.php @@ -15,26 +15,15 @@ use Symfony\Component\Form\Exception\TransformationFailedException; use Symfony\Component\Form\Extension\Core\DataTransformer\UuidToStringTransformer; use Symfony\Component\Uid\Uuid; +use Symfony\Component\Uid\UuidV1; class UuidToStringTransformerTest extends TestCase { - public function provideValidUuid() - { - return [ - ['123e4567-e89b-12d3-a456-426655440000', new Uuid('123e4567-e89b-12d3-a456-426655440000')], - ]; - } - - /** - * @dataProvider provideValidUuid - */ - public function testTransform($output, $input) + public function testTransform() { $transformer = new UuidToStringTransformer(); - $input = new Uuid($input); - - $this->assertEquals($output, $transformer->transform($input)); + $this->assertEquals('123e4567-e89b-12d3-a456-426655440000', $transformer->transform(new UuidV1('123e4567-e89b-12d3-a456-426655440000'))); } public function testTransformEmpty() @@ -53,16 +42,11 @@ public function testTransformExpectsUuid() $transformer->transform('1234'); } - /** - * @dataProvider provideValidUuid - */ - public function testReverseTransform($input, $output) + public function testReverseTransform() { - $reverseTransformer = new UuidToStringTransformer(); - - $output = new Uuid($output); + $transformer = new UuidToStringTransformer(); - $this->assertEquals($output, $reverseTransformer->reverseTransform($input)); + $this->assertEquals(new UuidV1('123e4567-e89b-12d3-a456-426655440000'), $transformer->reverseTransform('123e4567-e89b-12d3-a456-426655440000')); } public function testReverseTransformEmpty() @@ -78,7 +62,7 @@ public function testReverseTransformExpectsString() $this->expectException(TransformationFailedException::class); - $reverseTransformer->reverseTransform(1234); + $reverseTransformer->reverseTransform(Uuid::fromString('123e4567-e89b-12d3-a456-426655440000')->toBase32()); } public function testReverseTransformExpectsValidUuidString() From 821d17673480d155a36078d1d3f1c0263f94ea9b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 9 Sep 2022 17:04:33 +0200 Subject: [PATCH 34/57] [Security/Http] cs fixes --- .../Security/Core/Signature/SignatureHasher.php | 12 ++++++------ .../Security/Http/LoginLink/LoginLinkHandler.php | 10 +++++----- .../Http/RememberMe/AbstractRememberMeHandler.php | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Symfony/Component/Security/Core/Signature/SignatureHasher.php b/src/Symfony/Component/Security/Core/Signature/SignatureHasher.php index b578d77c9b638..e2b5dcb31f655 100644 --- a/src/Symfony/Component/Security/Core/Signature/SignatureHasher.php +++ b/src/Symfony/Component/Security/Core/Signature/SignatureHasher.php @@ -31,9 +31,9 @@ class SignatureHasher private $maxUses; /** - * @param array $signatureProperties properties of the User; the hash is invalidated if these properties change - * @param ExpiredSignatureStorage|null $expiredSignaturesStorage if provided, secures a sequence of hashes that are expired - * @param int|null $maxUses used together with $expiredSignatureStorage to allow a maximum usage of a hash + * @param array $signatureProperties Properties of the User; the hash is invalidated if these properties change + * @param ExpiredSignatureStorage|null $expiredSignaturesStorage If provided, secures a sequence of hashes that are expired + * @param int|null $maxUses Used together with $expiredSignatureStorage to allow a maximum usage of a hash */ public function __construct(PropertyAccessorInterface $propertyAccessor, array $signatureProperties, string $secret, ExpiredSignatureStorage $expiredSignaturesStorage = null, int $maxUses = null) { @@ -47,8 +47,8 @@ public function __construct(PropertyAccessorInterface $propertyAccessor, array $ /** * Verifies the hash using the provided user and expire time. * - * @param int $expires the expiry time as a unix timestamp - * @param string $hash the plaintext hash provided by the request + * @param int $expires The expiry time as a unix timestamp + * @param string $hash The plaintext hash provided by the request * * @throws InvalidSignatureException If the signature does not match the provided parameters * @throws ExpiredSignatureException If the signature is no longer valid @@ -75,7 +75,7 @@ public function verifySignatureHash(UserInterface $user, int $expires, string $h /** * Computes the secure hash for the provided user and expire time. * - * @param int $expires the expiry time as a unix timestamp + * @param int $expires The expiry time as a unix timestamp */ public function computeSignatureHash(UserInterface $user, int $expires): string { diff --git a/src/Symfony/Component/Security/Http/LoginLink/LoginLinkHandler.php b/src/Symfony/Component/Security/Http/LoginLink/LoginLinkHandler.php index b55e8aa6becf9..e245ad5f8bd3c 100644 --- a/src/Symfony/Component/Security/Http/LoginLink/LoginLinkHandler.php +++ b/src/Symfony/Component/Security/Http/LoginLink/LoginLinkHandler.php @@ -31,13 +31,13 @@ final class LoginLinkHandler implements LoginLinkHandlerInterface private $urlGenerator; private $userProvider; private $options; - private $signatureHashUtil; + private $signatureHasher; - public function __construct(UrlGeneratorInterface $urlGenerator, UserProviderInterface $userProvider, SignatureHasher $signatureHashUtil, array $options) + public function __construct(UrlGeneratorInterface $urlGenerator, UserProviderInterface $userProvider, SignatureHasher $signatureHasher, array $options) { $this->urlGenerator = $urlGenerator; $this->userProvider = $userProvider; - $this->signatureHashUtil = $signatureHashUtil; + $this->signatureHasher = $signatureHasher; $this->options = array_merge([ 'route_name' => null, 'lifetime' => 600, @@ -53,7 +53,7 @@ public function createLoginLink(UserInterface $user, Request $request = null): L // @deprecated since Symfony 5.3, change to $user->getUserIdentifier() in 6.0 'user' => method_exists($user, 'getUserIdentifier') ? $user->getUserIdentifier() : $user->getUsername(), 'expires' => $expires, - 'hash' => $this->signatureHashUtil->computeSignatureHash($user, $expires), + 'hash' => $this->signatureHasher->computeSignatureHash($user, $expires), ]; if ($request) { @@ -101,7 +101,7 @@ public function consumeLoginLink(Request $request): UserInterface $expires = $request->get('expires'); try { - $this->signatureHashUtil->verifySignatureHash($user, $expires, $hash); + $this->signatureHasher->verifySignatureHash($user, $expires, $hash); } catch (ExpiredSignatureException $e) { throw new ExpiredLoginLinkException(ucfirst(str_ireplace('signature', 'login link', $e->getMessage())), 0, $e); } catch (InvalidSignatureException $e) { diff --git a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeHandler.php b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeHandler.php index 97918c86cb8b4..d9c9d8327a197 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeHandler.php +++ b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeHandler.php @@ -53,7 +53,7 @@ public function __construct(UserProviderInterface $userProvider, RequestStack $r * - Create a new remember-me cookie to be sent with the response (using {@see createCookie()}); * - If you store the token somewhere else (e.g. in a database), invalidate the stored token. * - * @throws AuthenticationException throw this exception if the remember me details are not accepted + * @throws AuthenticationException If the remember-me details are not accepted */ abstract protected function processRememberMe(RememberMeDetails $rememberMeDetails, UserInterface $user): void; From 7ae7d7bb3c60872e801bc35a7571dfbb8a8895c7 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 9 Sep 2022 18:38:54 +0300 Subject: [PATCH 35/57] decode URL-encoded characters in DSN's usernames/passwords --- .../Component/Messenger/Transport/AmqpExt/Connection.php | 4 ++-- .../Component/Messenger/Transport/RedisExt/Connection.php | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php index 2dba7d9f1045b..6f36a39250b36 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php @@ -126,11 +126,11 @@ public static function fromDsn(string $dsn, array $options = [], AmqpFactory $am ], $options, $parsedQuery); if (isset($parsedUrl['user'])) { - $amqpOptions['login'] = $parsedUrl['user']; + $amqpOptions['login'] = urldecode($parsedUrl['user']); } if (isset($parsedUrl['pass'])) { - $amqpOptions['password'] = $parsedUrl['pass']; + $amqpOptions['password'] = urldecode($parsedUrl['pass']); } if (!isset($amqpOptions['queues'])) { diff --git a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php index 29eb6cb12e0d9..7f9f876dc54f4 100644 --- a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php @@ -93,8 +93,8 @@ public static function fromDsn(string $dsn, array $redisOptions = [], \Redis $re $stream = $pathParts[1] ?? $redisOptions['stream'] ?? null; $group = $pathParts[2] ?? $redisOptions['group'] ?? null; $consumer = $pathParts[3] ?? $redisOptions['consumer'] ?? null; - $pass = '' !== ($parsedUrl['pass'] ?? '') ? $parsedUrl['pass'] : null; - $user = '' !== ($parsedUrl['user'] ?? '') ? $parsedUrl['user'] : null; + $pass = '' !== ($parsedUrl['pass'] ?? '') ? urldecode($parsedUrl['pass']) : null; + $user = '' !== ($parsedUrl['user'] ?? '') ? urldecode($parsedUrl['user']) : null; $connectionCredentials = [ 'host' => $parsedUrl['host'] ?? '127.0.0.1', From abddada74bb1edf2edca4ed3c14a9e03e9353e6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Auswo=CC=88ger?= Date: Fri, 9 Sep 2022 13:48:55 +0200 Subject: [PATCH 36/57] [HttpFoundation] Always return strings from accept headers --- src/Symfony/Component/HttpFoundation/Request.php | 9 +++++---- .../Component/HttpFoundation/Tests/RequestTest.php | 14 ++++++++++++++ 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 4b2c4d96752c4..32e07b532e379 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1646,7 +1646,8 @@ public function getLanguages() $languages = AcceptHeader::fromString($this->headers->get('Accept-Language'))->all(); $this->languages = []; - foreach ($languages as $lang => $acceptHeaderItem) { + foreach ($languages as $acceptHeaderItem) { + $lang = $acceptHeaderItem->getValue(); if (str_contains($lang, '-')) { $codes = explode('-', $lang); if ('i' === $codes[0]) { @@ -1684,7 +1685,7 @@ public function getCharsets() return $this->charsets; } - return $this->charsets = array_keys(AcceptHeader::fromString($this->headers->get('Accept-Charset'))->all()); + return $this->charsets = array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept-Charset'))->all())); } /** @@ -1698,7 +1699,7 @@ public function getEncodings() return $this->encodings; } - return $this->encodings = array_keys(AcceptHeader::fromString($this->headers->get('Accept-Encoding'))->all()); + return $this->encodings = array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept-Encoding'))->all())); } /** @@ -1712,7 +1713,7 @@ public function getAcceptableContentTypes() return $this->acceptableContentTypes; } - return $this->acceptableContentTypes = array_keys(AcceptHeader::fromString($this->headers->get('Accept'))->all()); + return $this->acceptableContentTypes = array_map('strval', array_keys(AcceptHeader::fromString($this->headers->get('Accept'))->all())); } /** diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index 6035dd5d32da9..060de405e58ae 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -1582,6 +1582,20 @@ public function testGetLanguages() $this->assertEquals(['zh', 'cherokee'], $request->getLanguages()); } + public function testGetAcceptHeadersReturnString() + { + $request = new Request(); + $request->headers->set('Accept', '123'); + $request->headers->set('Accept-Charset', '123'); + $request->headers->set('Accept-Encoding', '123'); + $request->headers->set('Accept-Language', '123'); + + $this->assertSame(['123'], $request->getAcceptableContentTypes()); + $this->assertSame(['123'], $request->getCharsets()); + $this->assertSame(['123'], $request->getEncodings()); + $this->assertSame(['123'], $request->getLanguages()); + } + public function testGetRequestFormat() { $request = new Request(); From e6275ea4c183d93285483105eab7dda6eba14302 Mon Sep 17 00:00:00 2001 From: naitsirch Date: Wed, 7 Sep 2022 21:28:33 +0200 Subject: [PATCH 37/57] [HttpFoundation] Prevent BinaryFileResponse::prepare from adding content type if no content is sent --- .../HttpFoundation/BinaryFileResponse.php | 71 +++++++++++-------- .../Tests/BinaryFileResponseTest.php | 15 ++++ 2 files changed, 55 insertions(+), 31 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php index f44eb6daf44e9..2cd105c3bb0f3 100644 --- a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php +++ b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php @@ -201,15 +201,17 @@ public function setContentDisposition($disposition, $filename = '', $filenameFal */ public function prepare(Request $request) { - if (!$this->headers->has('Content-Type')) { - $this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream'); - } + parent::prepare($request); - if ('HTTP/1.0' !== $request->server->get('SERVER_PROTOCOL')) { - $this->setProtocolVersion('1.1'); + if ($this->isInformational() || $this->isEmpty()) { + $this->maxlen = 0; + + return $this; } - $this->ensureIEOverSSLCompatibility($request); + if (!$this->headers->has('Content-Type')) { + $this->headers->set('Content-Type', $this->file->getMimeType() ?: 'application/octet-stream'); + } $this->offset = 0; $this->maxlen = -1; @@ -217,6 +219,7 @@ public function prepare(Request $request) if (false === $fileSize = $this->file->getSize()) { return $this; } + $this->headers->remove('Transfer-Encoding'); $this->headers->set('Content-Length', $fileSize); if (!$this->headers->has('Accept-Ranges')) { @@ -286,6 +289,10 @@ public function prepare(Request $request) } } + if ($request->isMethod('HEAD')) { + $this->maxlen = 0; + } + return $this; } @@ -309,40 +316,42 @@ private function hasValidIfRangeHeader(?string $header): bool */ public function sendContent() { - if (!$this->isSuccessful()) { - return parent::sendContent(); - } + try { + if (!$this->isSuccessful()) { + return parent::sendContent(); + } - if (0 === $this->maxlen) { - return $this; - } + if (0 === $this->maxlen) { + return $this; + } - $out = fopen('php://output', 'w'); - $file = fopen($this->file->getPathname(), 'r'); + $out = fopen('php://output', 'w'); + $file = fopen($this->file->getPathname(), 'r'); - ignore_user_abort(true); + ignore_user_abort(true); - if (0 !== $this->offset) { - fseek($file, $this->offset); - } + if (0 !== $this->offset) { + fseek($file, $this->offset); + } - $length = $this->maxlen; - while ($length && !feof($file)) { - $read = ($length > $this->chunkSize) ? $this->chunkSize : $length; - $length -= $read; + $length = $this->maxlen; + while ($length && !feof($file)) { + $read = ($length > $this->chunkSize) ? $this->chunkSize : $length; + $length -= $read; - stream_copy_to_stream($file, $out, $read); + stream_copy_to_stream($file, $out, $read); - if (connection_aborted()) { - break; + if (connection_aborted()) { + break; + } } - } - fclose($out); - fclose($file); - - if ($this->deleteFileAfterSend && file_exists($this->file->getPathname())) { - unlink($this->file->getPathname()); + fclose($out); + fclose($file); + } finally { + if ($this->deleteFileAfterSend && file_exists($this->file->getPathname())) { + unlink($this->file->getPathname()); + } } return $this; diff --git a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php index f88c8a48df1aa..4e4ddbf4446ef 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php @@ -373,6 +373,21 @@ public function testStream() $this->assertNull($response->headers->get('Content-Length')); } + public function testPrepareNotAddingContentTypeHeaderIfNoContentResponse() + { + $request = Request::create('/'); + $request->headers->set('If-Modified-Since', date('D, d M Y H:i:s').' GMT'); + + $response = new BinaryFileResponse(__DIR__.'/File/Fixtures/test.gif', 200, ['Content-Type' => 'application/octet-stream']); + $response->setLastModified(new \DateTimeImmutable('-1 day')); + $response->isNotModified($request); + + $response->prepare($request); + + $this->assertSame(BinaryFileResponse::HTTP_NOT_MODIFIED, $response->getStatusCode()); + $this->assertFalse($response->headers->has('Content-Type')); + } + protected function provideResponse() { return new BinaryFileResponse(__DIR__.'/../README.md', 200, ['Content-Type' => 'application/octet-stream']); From 0bb3d84d55809806de00ce54ddb3fc032ba7d3c8 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 12 Sep 2022 13:45:18 +0300 Subject: [PATCH 38/57] add tests covering union types in MessengerPass --- .../DependencyInjection/MessengerPass.php | 5 +++ .../DependencyInjection/MessengerPassTest.php | 40 +++++++++++++++++++ .../UnionBuiltinTypeArgumentHandler.php | 19 +++++++++ .../Fixtures/UnionTypeArgumentHandler.php | 19 +++++++++ 4 files changed, 83 insertions(+) create mode 100644 src/Symfony/Component/Messenger/Tests/Fixtures/UnionBuiltinTypeArgumentHandler.php create mode 100644 src/Symfony/Component/Messenger/Tests/Fixtures/UnionTypeArgumentHandler.php diff --git a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php index ab7771b9aedfc..5c27ed9415818 100644 --- a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php +++ b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php @@ -230,15 +230,20 @@ private function guessHandledClasses(\ReflectionClass $handlerClass, string $ser if ($type instanceof \ReflectionUnionType) { $types = []; + $invalidTypes = []; foreach ($type->getTypes() as $type) { if (!$type->isBuiltin()) { $types[] = (string) $type; + } else { + $invalidTypes[] = (string) $type; } } if ($types) { return $types; } + + throw new RuntimeException(sprintf('Invalid handler service "%s": type-hint of argument "$%s" in method "%s::__invoke()" must be a class , "%s" given.', $serviceId, $parameters[0]->getName(), $handlerClass->getName(), implode('|', $invalidTypes))); } if ($type->isBuiltin()) { diff --git a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php index 940c32b374742..82fe774f2469d 100644 --- a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php +++ b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php @@ -31,6 +31,7 @@ use Symfony\Component\Messenger\Middleware\HandleMessageMiddleware; use Symfony\Component\Messenger\Middleware\MiddlewareInterface; use Symfony\Component\Messenger\Middleware\StackInterface; +use Symfony\Component\Messenger\Tests\Fixtures\ChildDummyMessage; use Symfony\Component\Messenger\Tests\Fixtures\DummyCommand; use Symfony\Component\Messenger\Tests\Fixtures\DummyCommandHandler; use Symfony\Component\Messenger\Tests\Fixtures\DummyMessage; @@ -39,6 +40,8 @@ use Symfony\Component\Messenger\Tests\Fixtures\MultipleBusesMessage; use Symfony\Component\Messenger\Tests\Fixtures\MultipleBusesMessageHandler; use Symfony\Component\Messenger\Tests\Fixtures\SecondMessage; +use Symfony\Component\Messenger\Tests\Fixtures\UnionBuiltinTypeArgumentHandler; +use Symfony\Component\Messenger\Tests\Fixtures\UnionTypeArgumentHandler; use Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceiver; use Symfony\Component\Messenger\Transport\Receiver\ReceiverInterface; @@ -474,6 +477,43 @@ public function testBuiltinArgumentTypeHandler() (new MessengerPass())->process($container); } + /** + * @requires PHP 8 + */ + public function testUnionTypeArgumentsTypeHandler() + { + $container = $this->getContainerBuilder($busId = 'message_bus'); + $container + ->register(UnionTypeArgumentHandler::class, UnionTypeArgumentHandler::class) + ->addTag('messenger.message_handler') + ; + + (new MessengerPass())->process($container); + + $handlersMapping = $container->getDefinition($busId.'.messenger.handlers_locator')->getArgument(0); + + $this->assertArrayHasKey(ChildDummyMessage::class, $handlersMapping); + $this->assertArrayHasKey(DummyMessage::class, $handlersMapping); + $this->assertHandlerDescriptor($container, $handlersMapping, ChildDummyMessage::class, [UnionTypeArgumentHandler::class]); + $this->assertHandlerDescriptor($container, $handlersMapping, DummyMessage::class, [UnionTypeArgumentHandler::class]); + } + + /** + * @requires PHP 8 + */ + public function testUnionBuiltinArgumentTypeHandler() + { + $this->expectException(RuntimeException::class); + $this->expectExceptionMessage(sprintf('Invalid handler service "%s": type-hint of argument "$message" in method "%s::__invoke()" must be a class , "string|int" given.', UnionBuiltinTypeArgumentHandler::class, UnionBuiltinTypeArgumentHandler::class)); + $container = $this->getContainerBuilder(); + $container + ->register(UnionBuiltinTypeArgumentHandler::class, UnionBuiltinTypeArgumentHandler::class) + ->addTag('messenger.message_handler') + ; + + (new MessengerPass())->process($container); + } + public function testNeedsToHandleAtLeastOneMessage() { $this->expectException(RuntimeException::class); diff --git a/src/Symfony/Component/Messenger/Tests/Fixtures/UnionBuiltinTypeArgumentHandler.php b/src/Symfony/Component/Messenger/Tests/Fixtures/UnionBuiltinTypeArgumentHandler.php new file mode 100644 index 0000000000000..6061651de187b --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Fixtures/UnionBuiltinTypeArgumentHandler.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Fixtures; + +class UnionBuiltinTypeArgumentHandler +{ + public function __invoke(string|int $message): void + { + } +} diff --git a/src/Symfony/Component/Messenger/Tests/Fixtures/UnionTypeArgumentHandler.php b/src/Symfony/Component/Messenger/Tests/Fixtures/UnionTypeArgumentHandler.php new file mode 100644 index 0000000000000..85be3662ac974 --- /dev/null +++ b/src/Symfony/Component/Messenger/Tests/Fixtures/UnionTypeArgumentHandler.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Messenger\Tests\Fixtures; + +class UnionTypeArgumentHandler +{ + public function __invoke(ChildDummyMessage|DummyMessage $message): void + { + } +} From c31b9e07af55a6f61d2d905cb4ccce27f1a4a62c Mon Sep 17 00:00:00 2001 From: Jairo Pastor Date: Thu, 15 Sep 2022 14:03:28 +0200 Subject: [PATCH 39/57] [Validator] [Security] Add Norwegian translations --- .../Core/Resources/translations/security.nb.xlf | 8 ++++++++ .../Core/Resources/translations/security.no.xlf | 8 ++++++++ .../Resources/translations/validators.nb.xlf | 16 ++++++++++++++++ .../Resources/translations/validators.no.xlf | 16 ++++++++++++++++ 4 files changed, 48 insertions(+) diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.nb.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.nb.xlf index 2d3a87c793ddf..7e75773798bf3 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.nb.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.nb.xlf @@ -70,6 +70,14 @@ Invalid or expired login link. Ugyldig eller utløpt påloggingskobling. + + Too many failed login attempts, please try again in %minutes% minute. + For mange mislykkede påloggingsforsøk, prøv igjen om %minutes% minutt. + + + Too many failed login attempts, please try again in %minutes% minutes. + For mange mislykkede påloggingsforsøk, prøv igjen om %minutes% minutter. + diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.no.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.no.xlf index 2d3a87c793ddf..7e75773798bf3 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.no.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.no.xlf @@ -70,6 +70,14 @@ Invalid or expired login link. Ugyldig eller utløpt påloggingskobling. + + Too many failed login attempts, please try again in %minutes% minute. + For mange mislykkede påloggingsforsøk, prøv igjen om %minutes% minutt. + + + Too many failed login attempts, please try again in %minutes% minutes. + For mange mislykkede påloggingsforsøk, prøv igjen om %minutes% minutter. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf index 93132ec57cdfc..5e1ebc189c350 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf @@ -386,6 +386,22 @@ This value is not a valid International Securities Identification Number (ISIN). Denne verdien er ikke et gyldig International Securities Identification Number (ISIN). + + This value should be a valid expression. + Denne verdien skal være et gyldig uttrykk. + + + This value is not a valid CSS color. + Denne verdien er ikke en gyldig CSS-farge. + + + This value is not a valid CIDR notation. + Denne verdien er ikke en gyldig CIDR-notasjon. + + + The value of the netmask should be between {{ min }} and {{ max }}. + Verdien på nettmasken skal være mellom {{ min }} og {{ max }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf index 93132ec57cdfc..5e1ebc189c350 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf @@ -386,6 +386,22 @@ This value is not a valid International Securities Identification Number (ISIN). Denne verdien er ikke et gyldig International Securities Identification Number (ISIN). + + This value should be a valid expression. + Denne verdien skal være et gyldig uttrykk. + + + This value is not a valid CSS color. + Denne verdien er ikke en gyldig CSS-farge. + + + This value is not a valid CIDR notation. + Denne verdien er ikke en gyldig CIDR-notasjon. + + + The value of the netmask should be between {{ min }} and {{ max }}. + Verdien på nettmasken skal være mellom {{ min }} og {{ max }}. + From 519f3a3449a2992cd9aa7af064fb91037a1ae870 Mon Sep 17 00:00:00 2001 From: Jules Pietri Date: Sun, 18 Sep 2022 11:39:21 +0200 Subject: [PATCH 40/57] [FrameworkBundle] Fix a phpdoc in mailer assertions --- .../Bundle/FrameworkBundle/Test/MailerAssertionsTrait.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/MailerAssertionsTrait.php b/src/Symfony/Bundle/FrameworkBundle/Test/MailerAssertionsTrait.php index d0ca84e25ae7a..fe20731a78a7b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Test/MailerAssertionsTrait.php +++ b/src/Symfony/Bundle/FrameworkBundle/Test/MailerAssertionsTrait.php @@ -91,7 +91,7 @@ public static function assertEmailAddressContains(RawMessage $email, string $hea } /** - * @return MessageEvents[] + * @return MessageEvent[] */ public static function getMailerEvents(string $transport = null): array { From b53b44845bdfee329799054b4f6d53c461ea418b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Mon, 19 Sep 2022 08:14:42 +0200 Subject: [PATCH 41/57] Run composer with --ignore-platform-req=php+ --- .github/workflows/unit-tests.yml | 7 +------ src/Symfony/Component/Lock/composer.json | 4 ++-- src/Symfony/Component/Messenger/composer.json | 3 ++- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index c9bd72085e803..42d2f02fbd24f 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -44,11 +44,6 @@ jobs: with: fetch-depth: 2 - - name: Configure for PHP >= 8.2 - if: "matrix.php >= '8.2'" - run: | - composer config platform.php 8.1.99 - - name: Setup PHP uses: shivammathur/setup-php@v2 with: @@ -70,7 +65,7 @@ jobs: echo COLUMNS=120 >> $GITHUB_ENV echo PHPUNIT="$(pwd)/phpunit --exclude-group tty,benchmark,intl-data,integration" >> $GITHUB_ENV - echo COMPOSER_UP='composer update --no-progress --ansi' >> $GITHUB_ENV + echo COMPOSER_UP='composer update --no-progress --ansi'$([[ "${{ matrix.php }}" = "8.2" ]] && echo ' --ignore-platform-req=php+') >> $GITHUB_ENV SYMFONY_VERSIONS=$(git ls-remote -q --heads | cut -f2 | grep -o '/[1-9][0-9]*\.[0-9].*' | sort -V) SYMFONY_VERSION=$(grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | cut -d "'" -f2 | cut -d '.' -f 1-2) diff --git a/src/Symfony/Component/Lock/composer.json b/src/Symfony/Component/Lock/composer.json index f7f8f84cc16db..1cd15c22a9e10 100644 --- a/src/Symfony/Component/Lock/composer.json +++ b/src/Symfony/Component/Lock/composer.json @@ -21,11 +21,11 @@ "symfony/polyfill-php80": "^1.16" }, "require-dev": { - "doctrine/dbal": "^2.6|^3.0", + "doctrine/dbal": "^2.7|^3.0", "predis/predis": "~1.0" }, "conflict": { - "doctrine/dbal": "<2.6" + "doctrine/dbal": "<2.7" }, "autoload": { "psr-4": { "Symfony\\Component\\Lock\\": "" }, diff --git a/src/Symfony/Component/Messenger/composer.json b/src/Symfony/Component/Messenger/composer.json index fd8aabb747cb9..1859442a96dab 100644 --- a/src/Symfony/Component/Messenger/composer.json +++ b/src/Symfony/Component/Messenger/composer.json @@ -21,7 +21,7 @@ "symfony/polyfill-php80": "^1.16" }, "require-dev": { - "doctrine/dbal": "^2.6|^3.0", + "doctrine/dbal": "^2.7|^3.0", "doctrine/persistence": "^1.3|^2|^3", "psr/cache": "^1.0|^2.0|^3.0", "symfony/console": "^3.4|^4.0|^5.0", @@ -36,6 +36,7 @@ "symfony/validator": "^3.4|^4.0|^5.0" }, "conflict": { + "doctrine/dbal": "<2.7", "doctrine/persistence": "<1.3", "symfony/event-dispatcher": "<4.3", "symfony/framework-bundle": "<4.4", From b6ac197fa4668c34e8107be4dc427bc4a60a5d33 Mon Sep 17 00:00:00 2001 From: Mathieu Date: Wed, 21 Sep 2022 09:27:00 +0200 Subject: [PATCH 42/57] Fix LocaleListenerTest Accept-Language headers --- .../Tests/EventListener/LocaleListenerTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php index 4c1c624de2524..824d906340460 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php @@ -120,7 +120,7 @@ public function testRequestLocaleIsNotOverridden() public function testRequestPreferredLocaleFromAcceptLanguageHeader() { $request = Request::create('/'); - $request->headers->set('Accept-Language', ['Accept-Language: fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5']); + $request->headers->set('Accept-Language', 'fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5'); $listener = new LocaleListener($this->requestStack, 'de', null, true, ['de', 'fr']); $event = $this->getEvent($request); @@ -133,7 +133,7 @@ public function testRequestPreferredLocaleFromAcceptLanguageHeader() public function testRequestSecondPreferredLocaleFromAcceptLanguageHeader() { $request = Request::create('/'); - $request->headers->set('Accept-Language', ['Accept-Language: fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5']); + $request->headers->set('Accept-Language', 'fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5'); $listener = new LocaleListener($this->requestStack, 'de', null, true, ['de', 'en']); $event = $this->getEvent($request); @@ -146,7 +146,7 @@ public function testRequestSecondPreferredLocaleFromAcceptLanguageHeader() public function testDontUseAcceptLanguageHeaderIfNotEnabled() { $request = Request::create('/'); - $request->headers->set('Accept-Language', ['Accept-Language: fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5']); + $request->headers->set('Accept-Language', 'fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5'); $listener = new LocaleListener($this->requestStack, 'de', null, false, ['de', 'en']); $event = $this->getEvent($request); @@ -159,7 +159,7 @@ public function testDontUseAcceptLanguageHeaderIfNotEnabled() public function testRequestUnavailablePreferredLocaleFromAcceptLanguageHeader() { $request = Request::create('/'); - $request->headers->set('Accept-Language', ['Accept-Language: fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5']); + $request->headers->set('Accept-Language', 'fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5'); $listener = new LocaleListener($this->requestStack, 'de', null, true, ['de', 'it']); $event = $this->getEvent($request); @@ -172,7 +172,7 @@ public function testRequestUnavailablePreferredLocaleFromAcceptLanguageHeader() public function testRequestNoLocaleFromAcceptLanguageHeader() { $request = Request::create('/'); - $request->headers->set('Accept-Language', ['Accept-Language: fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5']); + $request->headers->set('Accept-Language', 'fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5'); $listener = new LocaleListener($this->requestStack, 'de', null, true); $event = $this->getEvent($request); @@ -186,7 +186,7 @@ public function testRequestAttributeLocaleNotOverridenFromAcceptLanguageHeader() { $request = Request::create('/'); $request->attributes->set('_locale', 'it'); - $request->headers->set('Accept-Language', ['Accept-Language: fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5']); + $request->headers->set('Accept-Language', 'fr-FR,fr;q=0.9,en-GB;q=0.8,en;q=0.7,en-US;q=0.6,es;q=0.5'); $listener = new LocaleListener($this->requestStack, 'de', null, true, ['fr', 'en']); $event = $this->getEvent($request); From a02fc6d7d381fd3dff86fb3760392a653bc82309 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Wed, 21 Sep 2022 21:53:16 +0200 Subject: [PATCH 43/57] Remove non-empty-string PHPDoc annotations --- src/Symfony/Component/Filesystem/Path.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Filesystem/Path.php b/src/Symfony/Component/Filesystem/Path.php index 6d3755e0a6ac3..9aa37355a8555 100644 --- a/src/Symfony/Component/Filesystem/Path.php +++ b/src/Symfony/Component/Filesystem/Path.php @@ -721,7 +721,7 @@ public static function isBasePath(string $basePath, string $ofPath): bool } /** - * @return non-empty-string[] + * @return string[] */ private static function findCanonicalParts(string $root, string $pathWithoutRoot): array { From 3882065ef67b21ca33136f65da0abbf759af1075 Mon Sep 17 00:00:00 2001 From: AndrolGenhald Date: Wed, 14 Sep 2022 11:41:31 -0500 Subject: [PATCH 44/57] Fix AbstractFormLoginAuthenticator return types (fixes #47571). Children of AbstractFormLoginAuthenticator should be allowed to return a `Response` instead of being required to return a `RedirectResponse`. This change matches the return types in the newer AbstractLoginFormAuthenticator. --- .../Guard/Authenticator/AbstractFormLoginAuthenticator.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Security/Guard/Authenticator/AbstractFormLoginAuthenticator.php b/src/Symfony/Component/Security/Guard/Authenticator/AbstractFormLoginAuthenticator.php index f91478bfc91b2..212ac310bc91a 100644 --- a/src/Symfony/Component/Security/Guard/Authenticator/AbstractFormLoginAuthenticator.php +++ b/src/Symfony/Component/Security/Guard/Authenticator/AbstractFormLoginAuthenticator.php @@ -13,6 +13,7 @@ use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Security; use Symfony\Component\Security\Guard\AbstractGuardAuthenticator; @@ -34,7 +35,7 @@ abstract protected function getLoginUrl(); /** * Override to change what happens after a bad username/password is submitted. * - * @return RedirectResponse + * @return Response */ public function onAuthenticationFailure(Request $request, AuthenticationException $exception) { @@ -56,7 +57,7 @@ public function supportsRememberMe() * Override to control what happens when the user hits a secure page * but isn't logged in yet. * - * @return RedirectResponse + * @return Response */ public function start(Request $request, AuthenticationException $authException = null) { From b02e25151f53685e6c81cc0bd71efd51ec1f6d23 Mon Sep 17 00:00:00 2001 From: Peter Gribanov Date: Tue, 27 Sep 2022 15:17:00 +0300 Subject: [PATCH 45/57] Correct compare float data --- src/Symfony/Component/Stopwatch/Tests/StopwatchPeriodTest.php | 2 +- src/Symfony/Component/Stopwatch/composer.json | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Stopwatch/Tests/StopwatchPeriodTest.php b/src/Symfony/Component/Stopwatch/Tests/StopwatchPeriodTest.php index e01849d474869..81010a79413fd 100644 --- a/src/Symfony/Component/Stopwatch/Tests/StopwatchPeriodTest.php +++ b/src/Symfony/Component/Stopwatch/Tests/StopwatchPeriodTest.php @@ -40,7 +40,7 @@ public function testGetEndTime($end, $useMorePrecision, $expected) public function testGetDuration($start, $end, $useMorePrecision, $duration) { $period = new StopwatchPeriod($start, $end, $useMorePrecision); - $this->assertSame($duration, $period->getDuration()); + $this->assertEqualsWithDelta($duration, $period->getDuration(), \PHP_FLOAT_EPSILON); } public function provideTimeValues() diff --git a/src/Symfony/Component/Stopwatch/composer.json b/src/Symfony/Component/Stopwatch/composer.json index 1babf15aed09f..a11dc7960f185 100644 --- a/src/Symfony/Component/Stopwatch/composer.json +++ b/src/Symfony/Component/Stopwatch/composer.json @@ -19,6 +19,9 @@ "php": ">=7.1.3", "symfony/service-contracts": "^1.0|^2" }, + "require-dev": { + "symfony/polyfill-php72": "~1.5" + }, "autoload": { "psr-4": { "Symfony\\Component\\Stopwatch\\": "" }, "exclude-from-classmap": [ From 8f4f2b1e58a02b7ab229cc912d0a0d1a0f9d319f Mon Sep 17 00:00:00 2001 From: tatankat Date: Mon, 12 Sep 2022 00:45:21 +0200 Subject: [PATCH 46/57] [Ldap] Do not run ldap_set_option on failed connection --- .../Component/Ldap/Adapter/ExtLdap/Connection.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php index defed4e35a787..9bd9cef35ce35 100644 --- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php +++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php @@ -159,7 +159,11 @@ private function connect() } } - $this->connection = ldap_connect($this->config['connection_string']); + if (false === $connection = ldap_connect($this->config['connection_string'])) { + throw new LdapException('Invalid connection string: '.$this->config['connection_string']); + } else { + $this->connection = $connection; + } foreach ($this->config['options'] as $name => $value) { if (!\in_array(ConnectionOptions::getOption($name), self::PRECONNECT_OPTIONS, true)) { @@ -167,10 +171,6 @@ private function connect() } } - if (false === $this->connection) { - throw new LdapException('Could not connect to Ldap server: '.ldap_error($this->connection)); - } - if ('tls' === $this->config['encryption'] && false === @ldap_start_tls($this->connection)) { throw new LdapException('Could not initiate TLS connection: '.ldap_error($this->connection)); } From a76016aba701720ea3fba9b6fdc455f7bc1ae282 Mon Sep 17 00:00:00 2001 From: siganushka Date: Fri, 25 Feb 2022 14:21:46 +0800 Subject: [PATCH 47/57] [Serializer] Fixed framework.serializer.default_context is not working for JsonEncoder --- .../Component/Serializer/Encoder/JsonEncoder.php | 6 +++--- .../Serializer/Tests/Encoder/JsonEncoderTest.php | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Serializer/Encoder/JsonEncoder.php b/src/Symfony/Component/Serializer/Encoder/JsonEncoder.php index cf4a89ca1ab5f..27f749b637bf0 100644 --- a/src/Symfony/Component/Serializer/Encoder/JsonEncoder.php +++ b/src/Symfony/Component/Serializer/Encoder/JsonEncoder.php @@ -23,10 +23,10 @@ class JsonEncoder implements EncoderInterface, DecoderInterface protected $encodingImpl; protected $decodingImpl; - public function __construct(JsonEncode $encodingImpl = null, JsonDecode $decodingImpl = null) + public function __construct(JsonEncode $encodingImpl = null, JsonDecode $decodingImpl = null, array $defaultContext = []) { - $this->encodingImpl = $encodingImpl ?? new JsonEncode(); - $this->decodingImpl = $decodingImpl ?? new JsonDecode([JsonDecode::ASSOCIATIVE => true]); + $this->encodingImpl = $encodingImpl ?? new JsonEncode($defaultContext); + $this->decodingImpl = $decodingImpl ?? new JsonDecode(array_merge([JsonDecode::ASSOCIATIVE => true], $defaultContext)); } /** diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/JsonEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/JsonEncoderTest.php index c1d7d496cce71..6cd1f82b1ab6c 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/JsonEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/JsonEncoderTest.php @@ -66,6 +66,22 @@ public function testOptions() $this->assertEquals($expected, $this->serializer->serialize($arr, 'json'), 'Context should not be persistent'); } + public function testWithDefaultContext() + { + $defaultContext = [ + 'json_encode_options' => \JSON_UNESCAPED_UNICODE, + 'json_decode_associative' => false, + ]; + + $encoder = new JsonEncoder(null, null, $defaultContext); + + $data = new \stdClass(); + $data->msg = '你好'; + + $this->assertEquals('{"msg":"你好"}', $json = $encoder->encode($data, 'json')); + $this->assertEquals($data, $encoder->decode($json, 'json')); + } + public function testEncodeNotUtf8WithoutPartialOnError() { $this->expectException(UnexpectedValueException::class); From 7caf8384ebd8447df3b4ab77a028f627b3608c22 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 28 Sep 2022 17:33:58 +0200 Subject: [PATCH 48/57] [Form] fix tests --- .../PercentToLocalizedStringTransformerTest.php | 2 +- .../Form/Tests/Extension/Core/Type/PercentTypeTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php index 708a0acf71db4..c9d89e8e27a2e 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/PercentToLocalizedStringTransformerTest.php @@ -82,7 +82,7 @@ public function testReverseTransformWithScaleAndRoundingDisabled() $transformer = new PercentToLocalizedStringTransformer(2, PercentToLocalizedStringTransformer::FRACTIONAL); - $this->assertEquals(0.0123456, $transformer->reverseTransform('1.23456')); + $this->assertEqualsWithDelta(0.0123456, $transformer->reverseTransform('1.23456'), \PHP_FLOAT_EPSILON); } public function testReverseTransform() diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/PercentTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/PercentTypeTest.php index 875ac905f7689..9641d529f3e3b 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/PercentTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/PercentTypeTest.php @@ -96,7 +96,7 @@ public function testSubmitWithoutRoundingMode() $form->submit('1.23456'); - $this->assertEquals(0.0123456, $form->getData()); + $this->assertEqualsWithDelta(0.0123456, $form->getData(), \PHP_FLOAT_EPSILON); } /** @@ -113,6 +113,6 @@ public function testSubmitWithNullRoundingMode() $form->submit('1.23456'); - $this->assertEquals(0.0123456, $form->getData()); + $this->assertEqualsWithDelta(0.0123456, $form->getData(), \PHP_FLOAT_EPSILON); } } From 459ac042a900a01533f5f8f72e1a04614518cdac Mon Sep 17 00:00:00 2001 From: Nate Wiebe Date: Wed, 28 Sep 2022 11:01:35 -0400 Subject: [PATCH 49/57] [FrameworkBundle] Filter out trans paths that are covered by a parent folder path --- .../Command/TranslationUpdateCommand.php | 22 ++++++++++ .../Command/TranslationUpdateCommandTest.php | 40 +++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php index de9332615eb97..f0e1dc8870aa6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php @@ -407,6 +407,7 @@ private function extractMessages(string $locale, array $transPaths, string $pref { $extractedCatalogue = new MessageCatalogue($locale); $this->extractor->setPrefix($prefix); + $transPaths = $this->filterDuplicateTransPaths($transPaths); foreach ($transPaths as $path) { if (is_dir($path) || is_file($path)) { $this->extractor->extract($path, $extractedCatalogue); @@ -416,6 +417,27 @@ private function extractMessages(string $locale, array $transPaths, string $pref return $extractedCatalogue; } + private function filterDuplicateTransPaths(array $transPaths): array + { + $transPaths = array_filter(array_map('realpath', $transPaths)); + + sort($transPaths); + + $filteredPaths = []; + + foreach ($transPaths as $path) { + foreach ($filteredPaths as $filteredPath) { + if (str_starts_with($path, $filteredPath.\DIRECTORY_SEPARATOR)) { + continue 2; + } + } + + $filteredPaths[] = $path; + } + + return $filteredPaths; + } + private function loadCurrentMessages(string $locale, array $transPaths): MessageCatalogue { $currentCatalogue = new MessageCatalogue($locale); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php index 5c6fa8ec35ea2..83f891080639e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php @@ -140,6 +140,46 @@ public function testWriteMessagesForSpecificDomain() $this->assertMatchesRegularExpression('/Translation files were successfully updated./', $tester->getDisplay()); } + public function testFilterDuplicateTransPaths() + { + $transPaths = [ + $this->translationDir.'/a/test/folder/with/a/subfolder', + $this->translationDir.'/a/test/folder/', + $this->translationDir.'/a/test/folder/with/a/subfolder/and/a/file.txt', + $this->translationDir.'/a/different/test/folder', + ]; + + $expectedPaths = [ + $this->translationDir.'/a/different/test/folder', + $this->translationDir.'/a/test/folder', + ]; + + foreach ($transPaths as $transPath) { + if (realpath($transPath)) { + continue; + } + + if (preg_match('/\.[a-z]+$/', $transPath)) { + if (!realpath(\dirname($transPath))) { + mkdir(\dirname($transPath), 0777, true); + } + + touch($transPath); + } else { + mkdir($transPath, 0777, true); + } + } + + $command = $this->createMock(TranslationUpdateCommand::class); + + $method = new \ReflectionMethod(TranslationUpdateCommand::class, 'filterDuplicateTransPaths'); + $method->setAccessible(true); + + $filteredTransPaths = $method->invoke($command, $transPaths); + + $this->assertEquals($expectedPaths, $filteredTransPaths); + } + protected function setUp(): void { $this->fs = new Filesystem(); From 3d0fb221bb12d70db7d634d80458ad79bddf0c1d Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 28 Sep 2022 17:49:31 +0200 Subject: [PATCH 50/57] [FrameworkBundle] fix merge --- .../Bundle/FrameworkBundle/Resources/config/serializer.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php index 6a4508d0d7620..9c044e11a9fd4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php @@ -176,6 +176,7 @@ ->tag('serializer.encoder') ->set('serializer.encoder.json', JsonEncoder::class) + ->args([null, null]) ->tag('serializer.encoder') ->set('serializer.encoder.yaml', YamlEncoder::class) From fd813578929b3e1cf9bb31688929098cb1d60256 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 28 Sep 2022 18:17:29 +0200 Subject: [PATCH 51/57] [FrameworkBundle] Fix tests --- .../Tests/Command/TranslationUpdateCommandTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php index 83f891080639e..f883fac0c57ce 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php @@ -149,11 +149,6 @@ public function testFilterDuplicateTransPaths() $this->translationDir.'/a/different/test/folder', ]; - $expectedPaths = [ - $this->translationDir.'/a/different/test/folder', - $this->translationDir.'/a/test/folder', - ]; - foreach ($transPaths as $transPath) { if (realpath($transPath)) { continue; @@ -177,6 +172,11 @@ public function testFilterDuplicateTransPaths() $filteredTransPaths = $method->invoke($command, $transPaths); + $expectedPaths = [ + realpath($this->translationDir.'/a/different/test/folder'), + realpath($this->translationDir.'/a/test/folder'), + ]; + $this->assertEquals($expectedPaths, $filteredTransPaths); } From d8636923820ce0675659e97a9c3cc5f6850c19ea Mon Sep 17 00:00:00 2001 From: wuchen90 Date: Wed, 21 Sep 2022 08:47:03 +0200 Subject: [PATCH 52/57] [FrameworkBundle] Fix passing `serializer.default_context` option to normalizers --- .../Resources/config/serializer.php | 5 +-- .../Tests/Functional/SerializerTest.php | 35 +++++++++++++++ .../Functional/app/Serializer/config.yml | 45 +++++++++++++++++++ 3 files changed, 82 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php index 9c044e11a9fd4..ca0cf9b53612e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php @@ -78,7 +78,8 @@ // Normalizer ->set('serializer.normalizer.constraint_violation_list', ConstraintViolationListNormalizer::class) - ->args([[], service('serializer.name_converter.metadata_aware')]) + ->args([1 => service('serializer.name_converter.metadata_aware')]) + ->autowire(true) ->tag('serializer.normalizer', ['priority' => -915]) ->set('serializer.normalizer.mime_message', MimeMessageNormalizer::class) @@ -124,7 +125,6 @@ service('property_info')->ignoreOnInvalid(), service('serializer.mapping.class_discriminator_resolver')->ignoreOnInvalid(), null, - [], ]) ->tag('serializer.normalizer', ['priority' => -1000]) @@ -137,7 +137,6 @@ service('property_info')->ignoreOnInvalid(), service('serializer.mapping.class_discriminator_resolver')->ignoreOnInvalid(), null, - [], ]) ->alias(PropertyNormalizer::class, 'serializer.normalizer.property') diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SerializerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SerializerTest.php index 019aa418901d8..aaf6ad49ccca1 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SerializerTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SerializerTest.php @@ -32,6 +32,41 @@ public function testDeserializeArrayOfObject() $this->assertEquals($expected, $result); } + + /** + * @dataProvider provideNormalizersAndEncodersWithDefaultContextOption + */ + public function testNormalizersAndEncodersUseDefaultContextConfigOption(string $normalizerId) + { + static::bootKernel(['test_case' => 'Serializer']); + + $normalizer = static::getContainer()->get($normalizerId); + + $reflectionObject = new \ReflectionObject($normalizer); + $property = $reflectionObject->getProperty('defaultContext'); + $property->setAccessible(true); + + $defaultContext = $property->getValue($normalizer); + + self::assertArrayHasKey('fake_context_option', $defaultContext); + self::assertEquals('foo', $defaultContext['fake_context_option']); + } + + public function provideNormalizersAndEncodersWithDefaultContextOption(): array + { + return [ + ['serializer.normalizer.constraint_violation_list.alias'], + ['serializer.normalizer.dateinterval.alias'], + ['serializer.normalizer.datetime.alias'], + ['serializer.normalizer.json_serializable.alias'], + ['serializer.normalizer.problem.alias'], + ['serializer.normalizer.uid.alias'], + ['serializer.normalizer.object.alias'], + ['serializer.encoder.xml.alias'], + ['serializer.encoder.yaml.alias'], + ['serializer.encoder.csv.alias'], + ]; + } } class Foo diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml index 3721de1cac584..e9620ede4d920 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml @@ -6,9 +6,54 @@ framework: enabled: true default_context: enable_max_depth: true + fake_context_option: foo property_info: { enabled: true } services: serializer.alias: alias: serializer public: true + + serializer.normalizer.constraint_violation_list.alias: + alias: serializer.normalizer.constraint_violation_list + public: true + + serializer.normalizer.dateinterval.alias: + alias: serializer.normalizer.dateinterval + public: true + + serializer.normalizer.datetime.alias: + alias: serializer.normalizer.datetime + public: true + + serializer.normalizer.json_serializable.alias: + alias: serializer.normalizer.json_serializable + public: true + + serializer.normalizer.problem.alias: + alias: serializer.normalizer.problem + public: true + + serializer.normalizer.uid.alias: + alias: serializer.normalizer.uid + public: true + + serializer.normalizer.property.alias: + alias: serializer.normalizer.property + public: true + + serializer.normalizer.object.alias: + alias: serializer.normalizer.object + public: true + + serializer.encoder.xml.alias: + alias: serializer.encoder.xml + public: true + + serializer.encoder.yaml.alias: + alias: serializer.encoder.yaml + public: true + + serializer.encoder.csv.alias: + alias: serializer.encoder.csv + public: true From 1c24b3ad78248b8b1b7e0e18c078f82e35c822ca Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 29 Sep 2022 10:53:10 +0200 Subject: [PATCH 53/57] [Notifier] Use local copy of stella-maris/clock when testing --- .github/workflows/package-tests.yml | 2 +- .github/workflows/unit-tests.yml | 2 +- composer.json | 9 ++++++++ .../stella-maris-clock/ClockInterface.php | 23 +++++++++++++++++++ .../Tests/stella-maris-clock/composer.json | 17 ++++++++++++++ .../Notifier/Bridge/Mercure/composer.json | 11 +++++++++ 6 files changed, 62 insertions(+), 2 deletions(-) create mode 100644 src/Symfony/Component/Notifier/Bridge/Mercure/Tests/stella-maris-clock/ClockInterface.php create mode 100644 src/Symfony/Component/Notifier/Bridge/Mercure/Tests/stella-maris-clock/composer.json diff --git a/.github/workflows/package-tests.yml b/.github/workflows/package-tests.yml index b6015edf4e00c..40c0e66c573ea 100644 --- a/.github/workflows/package-tests.yml +++ b/.github/workflows/package-tests.yml @@ -21,7 +21,7 @@ jobs: - name: Find packages id: find-packages - run: echo "::set-output name=packages::$(php .github/get-modified-packages.php $(find src/Symfony -mindepth 2 -type f -name composer.json -printf '%h\n' | jq -R -s -c 'split("\n")[:-1]') $(git diff --name-only origin/${{ github.base_ref }} HEAD | grep src/ | jq -R -s -c 'split("\n")[:-1]'))" + run: echo "::set-output name=packages::$(php .github/get-modified-packages.php $(find src/Symfony -mindepth 2 -maxdepth 6 -type f -name composer.json -printf '%h\n' | jq -R -s -c 'split("\n")[:-1]') $(git diff --name-only origin/${{ github.base_ref }} HEAD | grep src/ | jq -R -s -c 'split("\n")[:-1]'))" - name: Verify meta files are correct run: | diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 35ed9ae555ebc..6d49e81916ac6 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -94,7 +94,7 @@ jobs: echo SYMFONY_DEPRECATIONS_HELPER=weak >> $GITHUB_ENV cp composer.json composer.json.orig echo -e '{\n"require":{'"$(grep phpunit-bridge composer.json)"'"php":"*"},"minimum-stability":"dev"}' > composer.json - php .github/build-packages.php HEAD^ $SYMFONY_VERSION $(find src/Symfony -mindepth 2 -type f -name composer.json -printf '%h\n') + php .github/build-packages.php HEAD^ $SYMFONY_VERSION $(find src/Symfony -mindepth 2 -maxdepth 6 -type f -name composer.json -printf '%h\n') mv composer.json composer.json.phpunit mv composer.json.orig composer.json fi diff --git a/composer.json b/composer.json index 8ba28df968853..ffe1e31ef4341 100644 --- a/composer.json +++ b/composer.json @@ -204,6 +204,15 @@ { "type": "path", "url": "src/Symfony/Component/Runtime" + }, + { + "type": "path", + "url": "src/Symfony/Component/Notifier/Bridge/Mercure/Tests/stella-maris-clock", + "options": { + "versions": { + "stella-maris/clock": "0.1.x-dev" + } + } } ], "minimum-stability": "dev" diff --git a/src/Symfony/Component/Notifier/Bridge/Mercure/Tests/stella-maris-clock/ClockInterface.php b/src/Symfony/Component/Notifier/Bridge/Mercure/Tests/stella-maris-clock/ClockInterface.php new file mode 100644 index 0000000000000..d8b2e86692260 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Mercure/Tests/stella-maris-clock/ClockInterface.php @@ -0,0 +1,23 @@ + and ClockInterfaceContributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + */ + +namespace StellaMaris\Clock; + +use DateTimeImmutable; + +interface ClockInterface +{ + /** + * Return the current point in time as a DateTimeImmutable object + */ + public function now() : DateTimeImmutable; +} diff --git a/src/Symfony/Component/Notifier/Bridge/Mercure/Tests/stella-maris-clock/composer.json b/src/Symfony/Component/Notifier/Bridge/Mercure/Tests/stella-maris-clock/composer.json new file mode 100644 index 0000000000000..fb838caed6e88 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Mercure/Tests/stella-maris-clock/composer.json @@ -0,0 +1,17 @@ +{ + "name": "stella-maris/clock", + "description": "A local fork to workaround gitlab failing to serve the package reliably", + "homepage": "https://gitlab.com/stella-maris/clock", + "license": "MIT", + "authors": [ + { + "name": "Andreas Heigl", + "role": "Maintainer" + } + ], + "autoload": { + "psr-4": { + "StellaMaris\\Clock\\": "" + } + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/Mercure/composer.json b/src/Symfony/Component/Notifier/Bridge/Mercure/composer.json index ed13323a28166..eb7532353c4c3 100644 --- a/src/Symfony/Component/Notifier/Bridge/Mercure/composer.json +++ b/src/Symfony/Component/Notifier/Bridge/Mercure/composer.json @@ -28,5 +28,16 @@ "/Tests/" ] }, + "repositories": [ + { + "type": "path", + "url": "Tests/stella-maris-clock", + "options": { + "versions": { + "stella-maris/clock": "0.1.x-dev" + } + } + } + ], "minimum-stability": "dev" } From c693778940f379edf42272018cf8984e217befeb Mon Sep 17 00:00:00 2001 From: David Buchmann Date: Wed, 10 Aug 2022 17:09:47 +0200 Subject: [PATCH 54/57] [Serializer] forward the context from the JsonEncoder to JsonEncode and JsonDecode --- .../Component/Serializer/Encoder/JsonEncoder.php | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Serializer/Encoder/JsonEncoder.php b/src/Symfony/Component/Serializer/Encoder/JsonEncoder.php index 27f749b637bf0..d460331a3dd51 100644 --- a/src/Symfony/Component/Serializer/Encoder/JsonEncoder.php +++ b/src/Symfony/Component/Serializer/Encoder/JsonEncoder.php @@ -23,10 +23,15 @@ class JsonEncoder implements EncoderInterface, DecoderInterface protected $encodingImpl; protected $decodingImpl; + private $defaultContext = [ + JsonDecode::ASSOCIATIVE => true, + ]; + public function __construct(JsonEncode $encodingImpl = null, JsonDecode $decodingImpl = null, array $defaultContext = []) { - $this->encodingImpl = $encodingImpl ?? new JsonEncode($defaultContext); - $this->decodingImpl = $decodingImpl ?? new JsonDecode(array_merge([JsonDecode::ASSOCIATIVE => true], $defaultContext)); + $this->defaultContext = array_merge($this->defaultContext, $defaultContext); + $this->encodingImpl = $encodingImpl ?? new JsonEncode($this->defaultContext); + $this->decodingImpl = $decodingImpl ?? new JsonDecode($this->defaultContext); } /** @@ -34,6 +39,8 @@ public function __construct(JsonEncode $encodingImpl = null, JsonDecode $decodin */ public function encode($data, string $format, array $context = []) { + $context = array_merge($this->defaultContext, $context); + return $this->encodingImpl->encode($data, self::FORMAT, $context); } @@ -42,6 +49,8 @@ public function encode($data, string $format, array $context = []) */ public function decode(string $data, string $format, array $context = []) { + $context = array_merge($this->defaultContext, $context); + return $this->decodingImpl->decode($data, self::FORMAT, $context); } From ff340e2128c9c2ce54873689dba780104ec28cf8 Mon Sep 17 00:00:00 2001 From: Stefan Gehrig Date: Thu, 18 Aug 2022 13:15:07 +0200 Subject: [PATCH 55/57] [Security] Fix login url matching when app is not run with url rewriting or from a sub folder --- .../AbstractLoginFormAuthenticator.php | 2 +- .../AbstractLoginFormAuthenticatorTest.php | 121 ++++++++++++++++++ 2 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/Security/Http/Tests/Authenticator/AbstractLoginFormAuthenticatorTest.php diff --git a/src/Symfony/Component/Security/Http/Authenticator/AbstractLoginFormAuthenticator.php b/src/Symfony/Component/Security/Http/Authenticator/AbstractLoginFormAuthenticator.php index 25413b73cbc0f..c234cb4df4868 100644 --- a/src/Symfony/Component/Security/Http/Authenticator/AbstractLoginFormAuthenticator.php +++ b/src/Symfony/Component/Security/Http/Authenticator/AbstractLoginFormAuthenticator.php @@ -41,7 +41,7 @@ abstract protected function getLoginUrl(Request $request): string; */ public function supports(Request $request): bool { - return $request->isMethod('POST') && $this->getLoginUrl($request) === $request->getPathInfo(); + return $request->isMethod('POST') && $this->getLoginUrl($request) === $request->getBaseUrl().$request->getPathInfo(); } /** diff --git a/src/Symfony/Component/Security/Http/Tests/Authenticator/AbstractLoginFormAuthenticatorTest.php b/src/Symfony/Component/Security/Http/Tests/Authenticator/AbstractLoginFormAuthenticatorTest.php new file mode 100644 index 0000000000000..3a50c131cd522 --- /dev/null +++ b/src/Symfony/Component/Security/Http/Tests/Authenticator/AbstractLoginFormAuthenticatorTest.php @@ -0,0 +1,121 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Http\Tests\Authenticator; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; +use Symfony\Component\Security\Http\Authenticator\AbstractLoginFormAuthenticator; +use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; +use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport; + +class AbstractLoginFormAuthenticatorTest extends TestCase +{ + /** + * @dataProvider provideSupportsData + */ + public function testSupports(string $loginUrl, Request $request, bool $expected) + { + $authenticator = new ConcreteFormAuthenticator($loginUrl); + $this->assertSame($expected, $authenticator->supports($request)); + } + + public function provideSupportsData(): iterable + { + yield [ + '/login', + Request::create('http://localhost/login', Request::METHOD_POST, [], [], [], [ + 'DOCUMENT_ROOT' => '/var/www/app/public', + 'PHP_SELF' => '/index.php', + 'SCRIPT_FILENAME' => '/var/www/app/public/index.php', + 'SCRIPT_NAME' => '/index.php', + ]), + true, + ]; + yield [ + '/login', + Request::create('http://localhost/somepath', Request::METHOD_POST, [], [], [], [ + 'DOCUMENT_ROOT' => '/var/www/app/public', + 'PHP_SELF' => '/index.php', + 'SCRIPT_FILENAME' => '/var/www/app/public/index.php', + 'SCRIPT_NAME' => '/index.php', + ]), + false, + ]; + yield [ + '/folder/login', + Request::create('http://localhost/folder/login', Request::METHOD_POST, [], [], [], [ + 'DOCUMENT_ROOT' => '/var/www/app/public', + 'PHP_SELF' => '/folder/index.php', + 'SCRIPT_FILENAME' => '/var/www/app/public/index.php', + 'SCRIPT_NAME' => '/folder/index.php', + ]), + true, + ]; + yield [ + '/folder/login', + Request::create('http://localhost/folder/somepath', Request::METHOD_POST, [], [], [], [ + 'DOCUMENT_ROOT' => '/var/www/app/public', + 'PHP_SELF' => '/folder/index.php', + 'SCRIPT_FILENAME' => '/var/www/app/public/index.php', + 'SCRIPT_NAME' => '/folder/index.php', + ]), + false, + ]; + yield [ + '/index.php/login', + Request::create('http://localhost/index.php/login', Request::METHOD_POST, [], [], [], [ + 'DOCUMENT_ROOT' => '/var/www/app/public', + 'PHP_SELF' => '/index.php', + 'SCRIPT_FILENAME' => '/var/www/app/public/index.php', + 'SCRIPT_NAME' => '/index.php', + ]), + true, + ]; + yield [ + '/index.php/login', + Request::create('http://localhost/index.php/somepath', Request::METHOD_POST, [], [], [], [ + 'DOCUMENT_ROOT' => '/var/www/app/public', + 'PHP_SELF' => '/index.php', + 'SCRIPT_FILENAME' => '/var/www/app/public/index.php', + 'SCRIPT_NAME' => '/index.php', + ]), + false, + ]; + } +} + +class ConcreteFormAuthenticator extends AbstractLoginFormAuthenticator +{ + private $loginUrl; + + public function __construct(string $loginUrl) + { + $this->loginUrl = $loginUrl; + } + + protected function getLoginUrl(Request $request): string + { + return $this->loginUrl; + } + + public function authenticate(Request $request) + { + return new SelfValidatingPassport(new UserBadge('dummy')); + } + + public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response + { + return null; + } +} From 707cb06b88044c582b815e7533b870f953bb59bd Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 30 Sep 2022 09:40:18 +0200 Subject: [PATCH 56/57] Update CHANGELOG for 5.4.13 --- CHANGELOG-5.4.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/CHANGELOG-5.4.md b/CHANGELOG-5.4.md index 184bbd447c979..f4ed8a2960638 100644 --- a/CHANGELOG-5.4.md +++ b/CHANGELOG-5.4.md @@ -7,6 +7,37 @@ 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.13 (2022-09-30) + + * bug #47317 [Security] Fix login url matching when app is not run with url rewriting or from a sub folder (sgehrig) + * bug #47637 [FrameworkBundle] Fix passing `serializer.default_context` option to normalizers (wuchen90) + * bug #47695 [FrameworkBundle] Filter out trans paths that are covered by a parent folder path (natewiebe13) + * bug #45554 [Serializer] Fixed framework.serializer.default_context is not working for JsonEncoder (siganushka) + * bug #47547 [Ldap] Do not run ldap_set_option on failed connection (tatankat) + * bug #47578 [Security] Fix AbstractFormLoginAuthenticator return types (AndrolGenhald) + * bug #47614 [FrameworkBundle] Fix a phpdoc in mailer assertions (HeahDude) + * bug #47516 [HttpFoundation] Prevent BinaryFileResponse::prepare from adding content type if no content is sent (naitsirch) + * bug #47533 [Messenger] decode URL-encoded characters in DSN's usernames/passwords (xabbuh) + * bug #47530 [HttpFoundation] Always return strings from accept headers (ausi) + * bug #47523 [Uid] Ensure ULIDs are monotonic even when the time goes backward (nicolas-grekas) + * bug #47528 [Form] fix UUID tranformer (nicolas-grekas) + * bug #47488 [Security] Fix valid remember-me token exposure to the second consequent request (Ivan Kurnosov) + * bug #47518 [Uid] Fix validating UUID variant bits (nicolas-grekas) + * bug #47441 [HttpClient] [HttpClientBundle] Bugfix for delayed retryableHttpClient (martkop26) + * bug #47499 [Uid][Validator] Stop to first ULID format violation (ogizanagi) + * bug #47491 [HttpKernel] Prevent exception in RequestDataCollector if request stack is empty (aschempp) + * bug #47497 [Bridge] Fix mkdir() race condition in ProxyCacheWarmer (andrey-tech) + * bug #47415 [HttpClient] Psr18Client ignore invalid HTTP headers (nuryagdym) + * bug #47394 [Console] [Completion] Make bash completion run in non interactive mode (Seldaek) + * bug #47455 [Mime] Fix TextPart broken after being serialized (fabpot) + * bug #47423 [String] CamelCase/SnakeCase on uppercase word (mpiot) + * bug #47435 [HttpKernel] lock when writting profiles (nicolas-grekas) + * bug #47417 [WebProfilerBundle] Fix profile search bar link query params (HeahDude) + * bug #47437 [Mime] Fix email rendering when having inlined parts that are not related to the content (fabpot) + * bug #47434 [HttpFoundation] move flushing outside of Response::closeOutputBuffers (nicolas-grekas) + * bug #47351 [FrameworkBundle] Do not throw when describing a factory definition (MatTheCat) + * bug #47403 [Mailer] Fix edge cases in STMP transports (fabpot) + * 5.4.12 (2022-08-26) * bug #47391 [LokaliseBridge] Fix push command --delete-missing options when there are no missing messages (rwionczek) From ed62ced72bce3f7e1160950f5d5077d0ce681f13 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 30 Sep 2022 09:40:28 +0200 Subject: [PATCH 57/57] Update VERSION for 5.4.13 --- 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 7a7e678a4f75c..93068eda13b69 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.13-DEV'; + public const VERSION = '5.4.13'; public const VERSION_ID = 50413; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 4; public const RELEASE_VERSION = 13; - public const EXTRA_VERSION = 'DEV'; + public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2024'; public const END_OF_LIFE = '11/2025';