diff --git a/.appveyor.yml b/.appveyor.yml index 09fa4fbc5954b..e536bf33d2201 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -13,7 +13,7 @@ init: - SET SYMFONY_DEPRECATIONS_HELPER=strict - SET ANSICON=121x90 (121x90) - SET SYMFONY_PHPUNIT_DISABLE_RESULT_CACHE=1 - - SET SYMFONY_DEPRECATIONS_HELPER=max[indirect]=170 + - SET SYMFONY_DEPRECATIONS_HELPER=max[direct]=1 - REG ADD "HKEY_CURRENT_USER\Software\Microsoft\Command Processor" /v DelayedExpansion /t REG_DWORD /d 1 /f install: @@ -49,12 +49,10 @@ install: - IF NOT EXIST composer.phar (appveyor DownloadFile https://github.com/composer/composer/releases/download/2.0.0/composer.phar) - php composer.phar self-update --2 - copy /Y .github\composer-config.json %APPDATA%\Composer\config.json - - php composer.phar global require --no-progress --no-scripts --no-plugins symfony/flex - git config --global user.email "" - git config --global user.name "Symfony" - FOR /F "tokens=* USEBACKQ" %%F IN (`bash -c "grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | grep -o '[0-9][0-9]*\.[0-9]'"`) DO (SET SYMFONY_VERSION=%%F) - php .github/build-packages.php HEAD^ %SYMFONY_VERSION% src\Symfony\Bridge\PhpUnit - - SET "SYMFONY_REQUIRE=>=%SYMFONY_VERSION%" - SET COMPOSER_ROOT_VERSION=%SYMFONY_VERSION%.x-dev - php composer.phar update --no-progress --ansi - php phpunit install diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index 91fcd5ea0f79e..b6a13a19f76d1 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -157,6 +157,7 @@ jobs: - name: Run tests run: ./phpunit --group integration -v env: + SYMFONY_DEPRECATIONS_HELPER: max[direct]=1 # to be removed once DbalLogger is compatible with dbal 3.2+ REDIS_HOST: localhost REDIS_CLUSTER_HOSTS: 'localhost:7000 localhost:7001 localhost:7002 localhost:7003 localhost:7004 localhost:7005' REDIS_SENTINEL_HOSTS: 'localhost:26379' diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 09e0b1f25d6b0..42bc28c6622b7 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -62,6 +62,7 @@ jobs: echo COLUMNS=120 >> $GITHUB_ENV echo PHPUNIT="$(readlink -f ./phpunit) --exclude-group tty,benchmark,intl-data" >> $GITHUB_ENV echo COMPOSER_UP='composer update --no-progress --ansi' >> $GITHUB_ENV + echo SYMFONY_DEPRECATIONS_HELPER=max[direct]=1 >> $GITHUB_ENV # to be removed once DbalLogger is compatible with dbal 3.2+ 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 | grep -P -o '[0-9]+\.[0-9]+') diff --git a/CHANGELOG-6.0.md b/CHANGELOG-6.0.md index 0023f5b2f2c73..969f4134161ff 100644 --- a/CHANGELOG-6.0.md +++ b/CHANGELOG-6.0.md @@ -7,6 +7,27 @@ in 6.0 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v6.0.0...v6.0.1 +* 6.0.0-RC1 (2021-11-24) + + * security #cve-2021-41268 [SecurityBundle] Default signature_properties to the previous behavior (wouterj) + * security #cve-2021-41267 [HttpKernel] Fix missing extra trusted header in sub-request (jderusse) + * security #cve-2021-41270 [Serializer] Use single quote to escape formulas (jderusse) + * bug #44230 [Console] Add Suggestion class for more advanced completion suggestion (wouterj) + * bug #44232 [Cache] fix connecting to local Redis sockets (nicolas-grekas) + * bug #44204 [HttpClient] fix closing curl multi handle when destructing client (nicolas-grekas) + * bug #44208 [Process] exclude argv/argc from possible default env vars (nicolas-grekas) + * bug #44188 [VarExporter] fix exporting declared but unset properties when __sleep() is implemented (nicolas-grekas) + * bug #44176 [Console] Default ansi option to null (jderusse) + * bug #44179 [WebProfilerBundle] Fix JS error when toolbar is reloaded (jderusse) + * bug #44177 [SecurityBundle] Remove Guard (derrabus) + * bug #44172 [Security] Guard is incompatible with Symfony 6 (derrabus) + * bug #44119 [HttpClient][Mime] Add correct IDN flags for IDNA2008 compliance (j-bernard) + * bug #44139 [WebProfilerBundle] Prevent installation of incompatible mailer component versions (Anne-Julia Seitz) + * bug #43917 Allow autodetecting mapping type for any object (franmomu) + * bug #44130 [SecurityBundle] Remove outdated conditions based on authenticatorManagerEnabled (chalasr) + * bug #44131 [Yaml] properly parse quoted strings tagged with !!str (xabbuh) + * bug #42323 [TwigBridge] do not merge label classes into expanded choice labels (xabbuh) + * 6.0.0-BETA3 (2021-11-18) * feature #44125 Add a setter on DateTimeNormalizer to change the default context at runtime (Seldaek) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 1ac10f641e698..92b9b528b9c50 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -20,9 +20,9 @@ The Symfony Connect username in parenthesis allows to get more information - Jordi Boggiano (seldaek) - Victor Berchet (victor) - Javier Eguiluz (javier.eguiluz) + - Thomas Calvet (fancyweb) - Ryan Weaver (weaverryan) - Roland Franssen (ro0) - - Thomas Calvet (fancyweb) - Jakub Zalas (jakubzalas) - Johannes S (johannes) - Kris Wallsmith (kriswallsmith) @@ -46,20 +46,21 @@ The Symfony Connect username in parenthesis allows to get more information - Jan Schädlich (jschaedl) - Igor Wiedler (igorw) - Eriksen Costa (eriksencosta) + - Kevin Bond (kbond) - Ener-Getick (energetick) - Sarah Khalil (saro0h) - - Kevin Bond (kbond) - Pierre du Plessis (pierredup) + - Vasilij Duško (staff) - Valentin Udaltsov (vudaltsov) - Iltar van der Berg (kjarli) - Jonathan Wage (jwage) - - Vasilij Duško (staff) - Matthias Pigulla (mpdude) - Diego Saint Esteben (dosten) - Grégoire Paris (greg0ire) - Alexandre Salomé (alexandresalome) - William Durand (couac) - ornicar + - Jérôme Tamarelle (gromnan) - Konstantin Myakshin (koc) - Dany Maillard (maidmaid) - Francis Besset (francisbesset) @@ -68,13 +69,12 @@ The Symfony Connect username in parenthesis allows to get more information - Titouan Galopin (tgalopin) - Laurent VOULLEMIER (lvo) - Vasilij Dusko | CREATION - - Jérôme Tamarelle (gromnan) - Bulat Shakirzyanov (avalanche123) - David Maicher (dmaicher) + - Gábor Egyed (1ed) - gadelat (gadelat) - Saša Stamenković (umpirsky) - Peter Rehm (rpet) - - Gábor Egyed (1ed) - Henrik Bjørnskov (henrikbjorn) - Miha Vrhovnik - Diego Saint Esteben (dii3g0) @@ -82,10 +82,10 @@ The Symfony Connect username in parenthesis allows to get more information - Konstantin Kudryashov (everzet) - Vladimir Reznichenko (kalessil) - Bilal Amarni (bamarni) + - Antoine M (amakdessi) - Florin Patan (florinpatan) - Jáchym Toušek (enumag) - Alex Pott - - Antoine M (amakdessi) - Michel Weimerskirch (mweimerskirch) - Andrej Hudec (pulzarraider) - Christian Raue @@ -112,24 +112,25 @@ The Symfony Connect username in parenthesis allows to get more information - Toni Uebernickel (havvg) - Bart van den Burg (burgov) - Jordan Alliot (jalliot) + - Mathieu Santostefano (welcomattic) - John Wards (johnwards) - Tomas Norkūnas (norkunas) - Baptiste Clavié (talus) - Antoine Hérault (herzult) - Paráda József (paradajozsef) + - Alexandre Daubois (alexandre-daubois) - Vincent Langlet (deviling) + - HypeMC (hypemc) - Massimiliano Arione (garak) - Arnaud Le Blanc (arnaud-lb) - Przemysław Bogusz (przemyslaw-bogusz) + - Julien Falque (julienfalque) - Maxime STEINHAUSSER - Michal Piotrowski (eventhorizon) - Tomáš Votruba (tomas_votruba) - Mathias Arlaud (mtarld) - Tim Nagel (merk) - - Alexandre Daubois (alexandre-daubois) - - HypeMC (hypemc) - Chris Wilkinson (thewilkybarkid) - - Julien Falque (julienfalque) - Peter Kokot (maastermedia) - Lars Strojny (lstrojny) - Brice BERNARD (brikou) @@ -144,7 +145,6 @@ The Symfony Connect username in parenthesis allows to get more information - Adrien Brault (adrienbrault) - Yanick Witschi (toflar) - Jacob Dreesen (jdreesen) - - Mathieu Santostefano (welcomattic) - Malte Schlüter (maltemaltesich) - Joel Wurtz (brouznouf) - Théo FIDRY (theofidry) @@ -168,6 +168,7 @@ The Symfony Connect username in parenthesis allows to get more information - Gary PEGEOT (gary-p) - Matthieu Napoli (mnapoli) - Ruud Kamphuis (ruudk) + - Ion Bazan (ionbazan) - Jannik Zschiesche (apfelbox) - Robert Schönthal (digitalkaoz) - Florian Lonqueu-Brochard (florianlb) @@ -186,7 +187,6 @@ The Symfony Connect username in parenthesis allows to get more information - Hidenori Goto (hidenorigoto) - Jan Rosier (rosier) - Alessandro Chitolina (alekitto) - - Ion Bazan (ionbazan) - Albert Casademont (acasademont) - Arnaud Kleinpeter (nanocom) - Guilherme Blanco (guilhermeblanco) @@ -202,6 +202,8 @@ The Symfony Connect username in parenthesis allows to get more information - George Mponos (gmponos) - jwdeitch - Jeroen Spee (jeroens) + - Jérôme Parmentier (lctrs) + - Marco Pivetta (ocramius) - Fabien Bourigault (fbourigault) - Joe Bennett (kralos) - Mikael Pajunen @@ -216,16 +218,16 @@ The Symfony Connect username in parenthesis allows to get more information - Thomas Rabaix (rande) - Chi-teck - Timo Bakx (timobakx) - - Marco Pivetta (ocramius) - Vincent Touzet (vincenttouzet) - Nate Wiebe (natewiebe13) - Rouven Weßling (realityking) - - Jérôme Parmentier (lctrs) + - Michael Babker (mbabker) - Ben Davies (bendavies) - Clemens Tolboom - Helmer Aaviksoo - Christopher Hertel (chertel) - Remon van de Kamp (rpkamp) + - Rokas Mikalkėnas (rokasm) - Filippo Tessarotto (slamdunk) - Hiromi Hishida (77web) - Michael Käfer (michael_kaefer) @@ -233,6 +235,7 @@ The Symfony Connect username in parenthesis allows to get more information - Michał Pipa (michal.pipa) - Dawid Nowak - Andreas Möller (localheinz) + - Roman Martinuk (a2a4) - Amal Raghav (kertz) - Jonathan Ingram (jonathaningram) - Artur Kotyrba @@ -241,8 +244,9 @@ The Symfony Connect username in parenthesis allows to get more information - Samuel NELA (snela) - David Prévot - Hugo Monteiro (monteiro) + - Baptiste Leduc (korbeil) - Dmitrii Poddubnyi (karser) - - Michael Babker (mbabker) + - zairig imad (zairigimad) - Tien Vo (tienvx) - Timothée Barray (tyx) - James Halsall (jaitsu) @@ -270,11 +274,9 @@ The Symfony Connect username in parenthesis allows to get more information - Philippe Segatori - Thibaut Cheymol (tcheymol) - Sebastien Morel (plopix) - - Baptiste Leduc (korbeil) - mcfedr (mcfedr) - Ruben Gonzalez (rubenrua) - Benjamin Dulau (dbenjamin) - - zairig imad (zairigimad) - Baptiste Lafontaine (magnetik) - Mathieu Lemoine (lemoinem) - Denis Brumann (dbrumann) @@ -287,13 +289,11 @@ The Symfony Connect username in parenthesis allows to get more information - Stadly - Stepan Anchugov (kix) - François Pluchino (francoispluchino) - - Rokas Mikalkėnas (rokasm) - bronze1man - sun (sun) - Larry Garfield (crell) - Edi Modrić (emodric) - Gocha Ossinkine (ossinkine) - - Roman Martinuk (a2a4) - Leo Feyer (leofeyer) - Nikolay Labinskiy (e-moe) - Martin Schuhfuß (usefulthink) @@ -317,6 +317,7 @@ The Symfony Connect username in parenthesis allows to get more information - Dustin Whittle (dustinwhittle) - jeff - John Kary (johnkary) + - fd6130 (fdtvui) - Justin Hileman (bobthecow) - Blanchon Vincent (blanchonvincent) - Maciej Malarz (malarzm) @@ -330,6 +331,7 @@ The Symfony Connect username in parenthesis allows to get more information - Bastien Jaillot (bastnic) - Rui Marinho (ruimarinho) - Patrick Landolt (scube) + - Michał (bambucha15) - Eugene Wissner - Bohan Yang (brentybh) - Pascal Montoya @@ -362,7 +364,6 @@ The Symfony Connect username in parenthesis allows to get more information - Marcos Sánchez - Elnur Abdurrakhimov (elnur) - Manuel Reinhard (sprain) - - fd6130 (fdtvui) - Harm van Tilborg (hvt) - Danny Berger (dpb587) - Antonio J. García Lagar (ajgarlag) @@ -375,9 +376,9 @@ The Symfony Connect username in parenthesis allows to get more information - Xavier Perez - Arjen Brouwer (arjenjb) - Katsuhiro OGAWA + - Sylvain Fabre (sylfabre) - Patrick McDougle (patrick-mcdougle) - Marc Weistroff (futurecat) - - Michał (bambucha15) - Alif Rachmawadi - Anton Chernikov (anton_ch1989) - Kristen Gilden (kgilden) @@ -387,6 +388,7 @@ The Symfony Connect username in parenthesis allows to get more information - Sullivan SENECHAL (soullivaneuh) - Thomas Bisignani (toma) - Uwe Jäger (uwej711) + - Dāvis Zālītis (k0d3r1s) - Eugene Leonovich (rybakit) - Joseph Rouff (rouffj) - Félix Labrecque (woodspire) @@ -395,11 +397,13 @@ The Symfony Connect username in parenthesis allows to get more information - Jan Sorgalla (jsor) - Ray - Chekote + - Aleksandar Jakovljevic (ajakov) - Thomas Adam - Jhonny Lidfors (jhonne) - Diego Agulló (aeoris) - jdhoek - Thomas Landauer (thomas-landauer) + - Jurica Vlahoviček (vjurica) - Bob den Otter (bopp) - Thomas Schulz (king2500) - Frank de Jonge (frenkynet) @@ -412,6 +416,7 @@ The Symfony Connect username in parenthesis allows to get more information - Dmitriy Mamontov (mamontovdmitriy) - Ben Ramsey (ramsey) - Laurent Masforné (heisenberg) + - Sergey (upyx) - Giorgio Premi - Guillaume (guill) - renanbr @@ -434,7 +439,6 @@ The Symfony Connect username in parenthesis allows to get more information - Soner Sayakci - Peter Kruithof (pkruithof) - Michael Holm (hollo) - - Sylvain Fabre (sylfabre) - Arjen van der Meijden - Markus Fasselt (digilist) - Damien Alexandre (damienalexandre) @@ -452,7 +456,6 @@ The Symfony Connect username in parenthesis allows to get more information - Chris Smith (cs278) - Florian Klein (docteurklein) - W0rma - - Dāvis Zālītis (k0d3r1s) - Manuel Kiessling (manuelkiessling) - Dimitri Gritsajuk (ottaviano) - Alexey Kopytko (sanmai) @@ -497,6 +500,7 @@ The Symfony Connect username in parenthesis allows to get more information - Berny Cantos (xphere81) - Andrii Bodnar - Thierry Thuon (lepiaf) + - Antonio Jose Cerezo (ajcerezo) - Ricard Clau (ricardclau) - Mark Challoner (markchalloner) - Loïc Frémont (loic425) @@ -507,9 +511,9 @@ The Symfony Connect username in parenthesis allows to get more information - Tri Pham (phamuyentri) - Urinbayev Shakhobiddin (shokhaa) - Gennady Telegin (gtelegin) - - Sergey (upyx) - Krystian Marcisz (simivar) - Toni Rudolf (toooni) + - Dalibor Karlović (dkarlovi) - Erin Millard - Artur Melo (restless) - Matthew Lewinski (lewinski) @@ -526,10 +530,12 @@ The Symfony Connect username in parenthesis allows to get more information - Tobias Sjösten (tobiassjosten) - Gyula Sallai (salla) - Benjamin Cremer (bcremer) + - Hendrik Luup (hluup) - Inal DJAFAR (inalgnu) - Christian Gärtner (dagardner) - Dmytro Borysovskyi (dmytr0) - Tomasz Kowalczyk (thunderer) + - Artem Lopata - Artur Eshenbrener - Thomas Perez (scullwm) - Yoann RENARD (yrenard) @@ -585,7 +591,6 @@ The Symfony Connect username in parenthesis allows to get more information - Daniel Beyer - Manuel Alejandro Paz Cetina - Shein Alexey - - Aleksandar Jakovljevic (ajakov) - Jacek Jędrzejewski (jacek.jedrzejewski) - Romain Gautier (mykiwi) - Stefan Kruppa @@ -611,7 +616,6 @@ The Symfony Connect username in parenthesis allows to get more information - Marc Morales Valldepérez (kuert) - Jean-Baptiste GOMOND (mjbgo) - Vadim Kharitonov (virtuozzz) - - Jurica Vlahoviček (vjurica) - Oscar Cubo Medina (ocubom) - Karel Souffriau - Christophe L. (christophelau) @@ -630,7 +634,6 @@ The Symfony Connect username in parenthesis allows to get more information - Alexandru Furculita (afurculita) - Valentin Jonovs (valentins-jonovs) - Bastien DURAND (deamon) - - Antonio Jose Cerezo (ajcerezo) - Jeanmonod David (jeanmonod) - Christin Gruber (christingruber) - Andrey Sevastianov @@ -640,11 +643,11 @@ The Symfony Connect username in parenthesis allows to get more information - Noémi Salaün (noemi-salaun) - Niklas Fiekas - Philippe Segatori - - Dalibor Karlović (dkarlovi) - Markus Bachmann (baachi) - Kévin THERAGE (kevin_therage) - Michel Hunziker - Gunnstein Lye (glye) + - scyzoryck - Matthias Krauser (mkrauser) - Erkhembayar Gantulga (erheme318) - Lorenzo Millucci (lmillucci) @@ -665,14 +668,12 @@ The Symfony Connect username in parenthesis allows to get more information - Stefan Gehrig (sgehrig) - vagrant - Aurimas Niekis (gcds) - - Hendrik Luup (hluup) - EdgarPE - Florian Pfitzer (marmelatze) - Asier Illarramendi (doup) - Martijn Cuppens - Vlad Gregurco (vgregurco) - Boris Vujicic (boris.vujicic) - - Artem Lopata - Chris Sedlmayr (catchamonkey) - Indra Gunawan (indragunawan) - Mathias STRASSER (roukmoute) @@ -703,6 +704,7 @@ The Symfony Connect username in parenthesis allows to get more information - Lukáš Holeczy (holicz) - Erik Saunier (snickers) - franek (franek) + - Jerzy (jlekowski) - Raulnet - Christian Wahler - Dries Vints @@ -770,6 +772,7 @@ The Symfony Connect username in parenthesis allows to get more information - Alex Bacart - mcben - Jérôme Vieilledent (lolautruche) + - Roman Anasal - Maks Slesarenko - Filip Procházka (fprochazka) - mmoreram @@ -808,6 +811,7 @@ The Symfony Connect username in parenthesis allows to get more information - Tom Klingenberg - Gábor Fási - DUPUCH (bdupuch) + - Dadang NH (dadangnh) - Nate (frickenate) - Joachim Løvgaard (loevgaard) - Stefan Kruppa @@ -832,8 +836,10 @@ The Symfony Connect username in parenthesis allows to get more information - Samuele Lilli (doncallisto) - Gawain Lynch (gawain) - Peter Bowyer (pbowyer) + - Wojciech Kania - mmokhi - NothingWeAre + - Andrii Dembitskyi - Ryan - Lctrs - Alexander Deruwe (aderuwe) @@ -857,6 +863,7 @@ The Symfony Connect username in parenthesis allows to get more information - Johnny Robeson (johnny) - Disquedur - Michiel Boeckaert (milio) + - Benjamin Morel - Dmitriy Derepko - Geoffrey Tran (geoff) - Pablo Lozano (arkadis) @@ -992,7 +999,6 @@ The Symfony Connect username in parenthesis allows to get more information - Timothée BARRAY - Nilmar Sanchez Muguercia - Ivo Bathke (ivoba) - - scyzoryck - Ippei SUmida (ippey_s) - David Molineus - Strate @@ -1010,6 +1016,7 @@ The Symfony Connect username in parenthesis allows to get more information - rtek - Benjamin Dos Santos - Jérémy Jarrié (gagnar) + - Adrien Jourdier - Tomas Javaisis - Ivan Grigoriev - Johann Saunier (prophet777) @@ -1019,6 +1026,7 @@ The Symfony Connect username in parenthesis allows to get more information - Michael Devery (mickadoo) - Antoine Corcy - Ahmed Ashraf (ahmedash95) + - Gert Wijnalda (cinamo) - Luca Saba (lucasaba) - maxime.perrimond - Sascha Grossenbacher @@ -1090,7 +1098,6 @@ The Symfony Connect username in parenthesis allows to get more information - Junaid Farooq (junaidfarooq) - Massimiliano Braglia (massimilianobraglia) - Frankie Wittevrongel - - Jerzy (jlekowski) - Richard Quadling - Raphaëll Roussel - Anton Kroshilin @@ -1240,6 +1247,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jake (jakesoft) - Flinsch - Quentin Dreyer + - Bahman Mehrdad (bahman) - Jordan de Laune (jdelaune) - Christopher Hall (mythmakr) - none (nelexa) @@ -1251,6 +1259,7 @@ The Symfony Connect username in parenthesis allows to get more information - Martin Parsiegla (spea) - Bernhard Rusch - bhavin (bhavin4u) + - Mario Ramundo (rammar) - Ivan - Quentin Schuler - Nico Haase @@ -1259,6 +1268,7 @@ The Symfony Connect username in parenthesis allows to get more information - Sofiane HADDAG (sofhad) - frost-nzcr4 - Taylor Otwell + - Shahriar56 - Sami Mussbach - Dhananjay Goratela - Kien Nguyen @@ -1268,17 +1278,18 @@ The Symfony Connect username in parenthesis allows to get more information - Achilles Kaloeridis (achilles) - Adrien Wilmet (adrienfr) - Laurent Bassin (lbassin) + - Mouad ZIANI (mouadziani) - Tomasz Ignatiuk - andrey1s - Abhoryo - Fabian Vogler (fabian) + - Shakhobiddin - Korvin Szanto - Stéphan Kochen - Steven Dubois - Arjan Keeman - siganushka - Alaattin Kahramanlar (alaattin) - - Dadang NH (dadangnh) - Sergey Zolotov (enleur) - Maksim Kotlyar (makasim) - Neil Ferreira @@ -1287,6 +1298,7 @@ The Symfony Connect username in parenthesis allows to get more information - Paul LE CORRE - Loïc Beurlet - Sébastien COURJEAN + - Ana Raro - Daniel Gorgan - Ana Raro - Tony Malzhacker @@ -1295,9 +1307,9 @@ The Symfony Connect username in parenthesis allows to get more information - Cyril Quintin (cyqui) - Cyrille Bourgois (cyrilleb) - Gerard van Helden (drm) + - Ivan Sarastov (isarastov) - Johnny Peck (johnnypeck) - Jordi Sala Morales (jsala) - - Roman Anasal - Ivan Menshykov - David Romaní - Patrick Allaert @@ -1305,7 +1317,6 @@ The Symfony Connect username in parenthesis allows to get more information - Matt Robinson (inanimatt) - Aleksey Podskrebyshev - Calin Mihai Pristavu - - Andrii Dembitskyi - David Marín Carreño (davefx) - Fabien LUCAS (flucas2) - Ondrej Machulda (ondram) @@ -1328,6 +1339,7 @@ The Symfony Connect username in parenthesis allows to get more information - Derek ROTH - Ben Johnson - mweimerskirch + - Andrew Codispoti - Benjamin Franzke - baron (bastien) - Dmytro Boiko (eagle) @@ -1379,7 +1391,6 @@ The Symfony Connect username in parenthesis allows to get more information - Matthew Davis (mdavis1982) - Paulo Ribeiro (paulo) - Markus S. (staabm) - - Benjamin Morel - Maks - Knallcharge - Antoine LA @@ -1467,6 +1478,7 @@ The Symfony Connect username in parenthesis allows to get more information - Mahmoud Mostafa (mahmoud) - Fractal Zombie - Ahmed Abdou + - Khoo Yong Jun - shreyadenny - Daniel Iwaniec - Pieter @@ -1500,6 +1512,7 @@ The Symfony Connect username in parenthesis allows to get more information - Amirreza Shafaat (amirrezashafaat) - Adoni Pavlakis (adoni) - Nicolas Le Goff (nlegoff) + - Alex Hofbauer (alexhofbauer) - Maarten Nusteling (nusje2000) - Ahmed EBEN HASSINE (famas23) - Ben Oman @@ -1777,6 +1790,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jorge Vahldick (jvahldick) - Frederic Godfrin - Paul Matthews + - aim8604 - Jakub Kisielewski - Vacheslav Silyutin - Aleksandr Dankovtsev @@ -1831,6 +1845,7 @@ The Symfony Connect username in parenthesis allows to get more information - Rubén Calvo (rubencm) - Abdul.Mohsen B. A. A - Swen van Zanten + - Agustin Gomes - Benoît Burnichon - pthompson - Malaney J. Hill @@ -1845,6 +1860,7 @@ The Symfony Connect username in parenthesis allows to get more information - Sebastian Göttschkes (sgoettschkes) - Tatsuya Tsuruoka - Ross Tuck + - Oleksiy (alexndlm) - Kévin Gomez (kevin) - Mihai Nica (redecs) - Andrei Igna @@ -1935,7 +1951,9 @@ The Symfony Connect username in parenthesis allows to get more information - Lance McNearney - Volodymyr Kupriienko (greeflas) - Serhiy Lunak (slunak) + - Wojciech Błoszyk (wbloszyk) - Giorgio Premi + - abunch - Sergey Belyshkin - tamcy - Mikko Pesari @@ -1958,6 +1976,7 @@ The Symfony Connect username in parenthesis allows to get more information - Foxprodev - Max Summe - WedgeSama + - Dale.Nash - Felds Liscia - Chihiro Adachi (chihiro-adachi) - Raphaëll Roussel @@ -2030,6 +2049,7 @@ The Symfony Connect username in parenthesis allows to get more information - Alexander Janssen (tnajanssen) - Thomas Chmielowiec (chmielot) - Jānis Lukss + - Julien BERNARD - Michael Zangerle - rkerner - Alex Silcock @@ -2177,6 +2197,7 @@ The Symfony Connect username in parenthesis allows to get more information - Matt Farmer - catch - aetxebeste + - Juga Paazmaya - Alexandre Segura - afaricamp - Josef Cech @@ -2186,11 +2207,12 @@ The Symfony Connect username in parenthesis allows to get more information - Andrii Boiko - Harold Iedema - WaiSkats + - Morimoto Ryosuke - Ikhsan Agustian - Arnau González (arnaugm) - - Bahman Mehrdad (bahman) - Simon Bouland (bouland) - Jibé Barth (jibbarth) + - Jm Aribau (jmaribau) - Matthew Foster (mfoster) - Reyo Stallenberg (reyostallenberg) - Paul Seiffert (seiffert) @@ -2226,6 +2248,7 @@ The Symfony Connect username in parenthesis allows to get more information - Eric Schildkamp - Andreas - Markus + - agaktr - kernig - Thomas Chmielowiec - shdev @@ -2239,6 +2262,7 @@ The Symfony Connect username in parenthesis allows to get more information - Joe Springe - Mickael GOETZ - Maciej Schmidt + - botbotbot - Dennis Væversted - Timon van der Vorm - nuncanada @@ -2255,7 +2279,6 @@ The Symfony Connect username in parenthesis allows to get more information - Mathieu Dewet (mdewet) - Nicolas Tallefourtané (nicolab) - Botond Dani (picur) - - Mario Ramundo (rammar) - Rémi Faivre (rfv) - Thierry Marianne (thierrymarianne) - Nick Stemerdink @@ -2263,6 +2286,7 @@ The Symfony Connect username in parenthesis allows to get more information - jjanvier - Julius Beckmann - Ruben Jansen + - Marc Biorklund - shreypuranik - loru88 - Thibaut Salanon @@ -2291,6 +2315,7 @@ The Symfony Connect username in parenthesis allows to get more information - Yuri Karaban - Johan - Thomas Rothe + - Edwin - Martin - nietonfir - Andriy @@ -2300,21 +2325,26 @@ The Symfony Connect username in parenthesis allows to get more information - Pavel.Batanov - avi123 - Pavel Prischepa + - qzylalala - alsar - downace - Aarón Nieves Fernández - Mike Meier + - Mikolaj Czajkowski - Kirill Saksin - Shiro - Reda DAOUDI - Koalabaerchen - michalmarcinkowski - Warwick + - Jesper Skytte - Chris - Farid Jalilov - Christiaan Wiesenekker - Florent Olivaud + - Sergey Panteleev - JakeFr + - Dmitry Hordinky - Oliver Klee - Simon Sargeant - efeen @@ -2329,20 +2359,22 @@ The Symfony Connect username in parenthesis allows to get more information - kshida - Michał Dąbrowski (defrag) - Aryel Tupinamba (dfkimera) + - Florian Wolfsjaeger (flowolf) - Hans Höchtl (hhoechtl) - Simone Fumagalli (hpatoio) - Brian Graham (incognito) - Kevin Vergauwen (innocenzo) - Alessio Baglio (ioalessio) + - Jawira Portugal (jawira) - Johannes Müller (johmue) - Jordi Llonch (jordillonch) - - Mouad ZIANI (mouadziani) - Nicholas Ruunu (nicholasruunu) - Jeroen van den Nieuwenhuisen (nieuwenhuisen) - Cyril Pascal (paxal) - Cédric Dugat (ph3nol) - Philip Dahlstrøm (phidah) - Milos Colakovic (project2481) + - Raphael de Almeida (raphaeldealmeida) - Rénald Casagraude (rcasagraude) - Robin Duval (robin-duval) - Grinbergs Reinis (shima5) @@ -2446,6 +2478,7 @@ The Symfony Connect username in parenthesis allows to get more information - Darryl Hein (xmmedia) - Sadicov Vladimir (xtech) - Kevin EMO (zarcox) + - Marcel Berteler - sdkawata - Andrzej - Alexander Zogheb @@ -2473,7 +2506,6 @@ The Symfony Connect username in parenthesis allows to get more information - adenkejawen - Florent SEVESTRE (aniki-taicho) - Ari Pringle (apringle) - - Gert Wijnalda (cinamo) - Dan Ordille (dordille) - Jan Eichhorn (exeu) - Grégory Pelletier (ip512) @@ -2493,16 +2525,13 @@ The Symfony Connect username in parenthesis allows to get more information - grifx - Robert Campbell - Matt Lehner - - Shakhobiddin - Helmut Januschka - Hein Zaw Htet™ - Ruben Kruiswijk - Cosmin-Romeo TANASE - - Ana Raro - Michael J - youssef saoubou - Joseph Maarek - - Ivan Sarastov - Alexander Menk - Alex Pods - hadriengem @@ -2517,6 +2546,7 @@ The Symfony Connect username in parenthesis allows to get more information - Matthieu Prat - Grummfy - zors1 + - Peter Simoncic - Paul Le Corre - Noel Light-Hilary - Filipe Guerra @@ -2693,6 +2723,7 @@ The Symfony Connect username in parenthesis allows to get more information - temperatur - misterx - Cas + - arend - Vincent Godé - Dusan Kasan - Michael Steininger @@ -2739,7 +2770,6 @@ The Symfony Connect username in parenthesis allows to get more information - Daniel Bannert - Karim Miladi - Michael Genereux - - Wojciech Kania - patrick-mcdougle - Dariusz Czech - Bruno Baguette @@ -2811,6 +2841,7 @@ The Symfony Connect username in parenthesis allows to get more information - Adam Klvač - Bruno Nogueira Nascimento Wowk - Tomanhez + - satalaondrej - jonmldr - Yevgen Kovalienia - Lebnik @@ -2871,6 +2902,7 @@ The Symfony Connect username in parenthesis allows to get more information - Nicolas - Sergio Santoro - tirnanog06 + - Andrejs Leonovs - phc - Дмитрий Пацура - Signor Pedro @@ -3037,6 +3069,7 @@ The Symfony Connect username in parenthesis allows to get more information - ddegentesh - DSeemiller - Jan Emrich + - Anne-Julia Seitz - Mark Topper - Xavier REN - Zander Baldwin diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php index 6d03fdbae3561..367eb12e29162 100644 --- a/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php +++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php @@ -286,13 +286,15 @@ private function detectMappingType(string $directory, ContainerBuilder $containe $glob = new GlobResource($directory, '*', true); $container->addResource($glob); + $quotedMappingObjectName = preg_quote($this->getMappingObjectDefaultName(), '/'); + foreach ($glob as $file) { $content = file_get_contents($file); - if (preg_match('/^#\[.*Entity\b/m', $content)) { + if (preg_match('/^#\[.*'.$quotedMappingObjectName.'\b/m', $content)) { break; } - if (preg_match('/^ \* @.*Entity\b/m', $content)) { + if (preg_match('/^ \* @.*'.$quotedMappingObjectName.'\b/m', $content)) { $type = 'annotation'; break; } diff --git a/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/DoctrineExtensionTest.php b/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/DoctrineExtensionTest.php index e4f578bc207e7..774f1f0babf3c 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/DoctrineExtensionTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/DoctrineExtensionTest.php @@ -49,6 +49,10 @@ protected function setUp(): void ->willReturnCallback(function ($name) { return 'doctrine.orm.'.$name; }); + + $this->extension + ->method('getMappingObjectDefaultName') + ->willReturn('Entity'); } public function testFixManagersAutoMappingsWithTwoAutomappings() diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json index 86e7daa4e89ea..494e8835bb371 100644 --- a/src/Symfony/Bridge/Doctrine/composer.json +++ b/src/Symfony/Bridge/Doctrine/composer.json @@ -19,10 +19,10 @@ "php": ">=8.0.2", "doctrine/event-manager": "~1.0", "doctrine/persistence": "^2", - "symfony/deprecation-contracts": "^2.1|^3.0", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0", - "symfony/service-contracts": "^1.1|^2.0|^3.0" + "symfony/service-contracts": "^1.1|^2|^3" }, "require-dev": { "composer/package-versions-deprecated": "^1.8", diff --git a/src/Symfony/Bridge/Monolog/composer.json b/src/Symfony/Bridge/Monolog/composer.json index e73f8ca757d9d..1fd9424f683a9 100644 --- a/src/Symfony/Bridge/Monolog/composer.json +++ b/src/Symfony/Bridge/Monolog/composer.json @@ -18,7 +18,7 @@ "require": { "php": ">=8.0.2", "monolog/monolog": "^1.25.1|^2", - "symfony/service-contracts": "^1.1|^2.0|^3.0", + "symfony/service-contracts": "^1.1|^2|^3", "symfony/http-kernel": "^5.4|^6.0" }, "require-dev": { diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig index 7316abf0ddd12..34cbc76074acd 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig @@ -90,9 +90,6 @@ {%- if required -%} {%- set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' required')|trim}) -%} {%- endif -%} - {%- if parent_label_class is defined -%} - {%- set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' ' ~ parent_label_class)|trim}) -%} - {%- endif -%} {%- if label is not same as(false) and label is empty -%} {%- if label_format is not empty -%} {%- set label = label_format|replace({ diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig index fb440282861d8..0e80840541fa1 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig @@ -283,9 +283,6 @@ {%- if required -%} {%- set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' required')|trim}) -%} {%- endif -%} - {%- if parent_label_class is defined -%} - {%- set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' ' ~ parent_label_class)|replace({'checkbox-inline': '', 'radio-inline': '', 'checkbox-custom': '', 'radio-custom': ''})|trim}) -%} - {%- endif -%} {%- if label is not same as(false) and label is empty -%} {%- if label_format is not empty -%} {%- set label = label_format|replace({ diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig index b02b94210d9be..f8c51b83dd8ed 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/foundation_5_layout.html.twig @@ -253,9 +253,6 @@ {% if errors|length > 0 -%} {% set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' error')|trim}) %} {% endif %} - {% if parent_label_class is defined %} - {% set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ parent_label_class)|trim}) %} - {% endif %} {% if label is empty %} {%- if label_format is not empty -%} {% set label = label_format|replace({ diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index 0b474b61be2ae..0765818346b6d 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=8.0.2", - "symfony/translation-contracts": "^1.1|^2.0|^3.0", + "symfony/translation-contracts": "^1.1|^2|^3", "twig/twig": "^2.13|^3.0.4" }, "require-dev": { diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 866efbd4f7e89..18115870fa87e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -328,7 +328,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) $workflows = []; } - if (1 === \count($workflows) && isset($workflows['workflows']) && array_keys($workflows['workflows']) !== range(0, \count($workflows) - 1) && !empty(array_diff(array_keys($workflows['workflows']), ['audit_trail', 'type', 'marking_store', 'supports', 'support_strategy', 'initial_marking', 'places', 'transitions']))) { + if (1 === \count($workflows) && isset($workflows['workflows']) && !array_is_list($workflows['workflows']) && !empty(array_diff(array_keys($workflows['workflows']), ['audit_trail', 'type', 'marking_store', 'supports', 'support_strategy', 'initial_marking', 'places', 'transitions']))) { $workflows = $workflows['workflows']; } @@ -1251,7 +1251,7 @@ private function addLockSection(ArrayNodeDefinition $rootNode, callable $enableI ->ifString()->then(function ($v) { return ['default' => $v]; }) ->end() ->beforeNormalization() - ->ifTrue(function ($v) { return \is_array($v) && array_keys($v) === range(0, \count($v) - 1); }) + ->ifTrue(function ($v) { return \is_array($v) && array_is_list($v); }) ->then(function ($v) { $resources = []; foreach ($v as $resource) { diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 96ae42c0ac18c..6b91858fde767 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -81,11 +81,9 @@ use Symfony\Component\HttpKernel\Controller\ArgumentValueResolverInterface; use Symfony\Component\HttpKernel\DataCollector\DataCollectorInterface; use Symfony\Component\HttpKernel\DependencyInjection\Extension; -use Symfony\Component\Lock\Lock; use Symfony\Component\Lock\LockFactory; use Symfony\Component\Lock\PersistingStoreInterface; use Symfony\Component\Lock\Store\StoreFactory; -use Symfony\Component\Lock\StoreInterface; use Symfony\Component\Mailer\Bridge\Amazon\Transport\SesTransportFactory; use Symfony\Component\Mailer\Bridge\Google\Transport\GmailTransportFactory; use Symfony\Component\Mailer\Bridge\Mailchimp\Transport\MandrillTransportFactory; @@ -1439,10 +1437,6 @@ private function registerValidationConfiguration(array $config, ContainerBuilder $definition->replaceArgument(0, $config['email_validation_mode']); if (\array_key_exists('enable_annotations', $config) && $config['enable_annotations']) { - if (!$this->annotationsConfigEnabled) { - throw new \LogicException('"enable_annotations" on the validator cannot be set as the PHP version is lower than 8 and Doctrine Annotations support is disabled. Consider upgrading PHP.'); - } - $validatorBuilder->addMethodCall('enableAnnotationMapping', [true]); if ($this->annotationsConfigEnabled) { $validatorBuilder->addMethodCall('setDoctrineAnnotationReader', [new Reference('annotation_reader')]); @@ -1815,7 +1809,7 @@ private function registerLockConfiguration(array $config, ContainerBuilder $cont $storeDefinitions = []; foreach ($resourceStores as $storeDsn) { $storeDsn = $container->resolveEnvPlaceholders($storeDsn, null, $usedEnvs); - $storeDefinition = new Definition(interface_exists(StoreInterface::class) ? StoreInterface::class : PersistingStoreInterface::class); + $storeDefinition = new Definition(PersistingStoreInterface::class); $storeDefinition->setFactory([StoreFactory::class, 'createStore']); $storeDefinition->setArguments([$storeDsn]); @@ -1838,12 +1832,6 @@ private function registerLockConfiguration(array $config, ContainerBuilder $cont $factoryDefinition->replaceArgument(0, new Reference($storeDefinitionId)); $container->setDefinition('lock.'.$resourceName.'.factory', $factoryDefinition); - // Generate services for lock instances - $lockDefinition = new Definition(Lock::class); - $lockDefinition->setPublic(false); - $lockDefinition->setFactory([new Reference('lock.'.$resourceName.'.factory'), 'createLock']); - $lockDefinition->setArguments([$resourceName]); - // provide alias for default resource if ('default' === $resourceName) { $container->setAlias('lock.factory', new Alias('lock.'.$resourceName.'.factory', false)); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/BaseBundle/BaseBundle.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/BaseBundle/BaseBundle.php deleted file mode 100644 index 494a18dff0a14..0000000000000 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/BaseBundle/BaseBundle.php +++ /dev/null @@ -1,18 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures\BaseBundle; - -use Symfony\Component\HttpKernel\Bundle\Bundle; - -class BaseBundle extends Bundle -{ -} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/BaseBundle/Resources/views/base.format.engine b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/BaseBundle/Resources/views/base.format.engine deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/BaseBundle/Resources/views/controller/base.format.engine b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/BaseBundle/Resources/views/controller/base.format.engine deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/BaseBundle/Resources/views/this.is.a.template.format.engine b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/BaseBundle/Resources/views/this.is.a.template.format.engine deleted file mode 100644 index e69de29bb2d1d..0000000000000 diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 54cf9cc13307b..1d73dd97e57c0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -27,6 +27,7 @@ "symfony/http-foundation": "^5.4|^6.0", "symfony/http-kernel": "^5.4|^6.0", "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php81": "^1.22", "symfony/filesystem": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", "symfony/routing": "^5.4|^6.0" diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php index b33136891809f..b2cd3fed196ba 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php @@ -154,6 +154,7 @@ public function addConfiguration(NodeDefinition $node) ->requiresAtLeastOneElement() ->info('An array of properties on your User that are used to sign the remember-me cookie. If any of these change, all existing cookies will become invalid.') ->example(['email', 'password']) + ->defaultValue(['password']) ->end() ->arrayNode('token_provider') ->beforeNormalization() diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig b/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig index 33285fc8f565d..ba479f2fbe832 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig +++ b/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig @@ -4,8 +4,6 @@ {% block toolbar %} {% if collector.firewall %} - {% set color_code = collector.enabled and not collector.authenticatorManagerEnabled ? 'yellow' %} - {% set icon %} {{ include('@Security/Collector/icon.svg') }} {{ collector.user|default('n/a') }} @@ -85,7 +83,7 @@ {% endset %} - {{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: profiler_url, status: color_code }) }} + {{ include('@WebProfiler/Profiler/toolbar_item.html.twig', { link: profiler_url }) }} {% endif %} {% endblock %} @@ -176,12 +174,6 @@ {{ include('@WebProfiler/Icon/' ~ (collector.firewall.stateless ? 'yes' : 'no') ~ '.svg') }} Stateless - {% if collector.authenticatorManagerEnabled == false %} -
- {{ include('@WebProfiler/Icon/' ~ (collector.firewall.allows_anonymous ? 'yes' : 'no') ~ '.svg') }} - Allows anonymous -
- {% endif %} {% if collector.firewall.security_enabled %} @@ -218,17 +210,10 @@ access_denied_url {{ collector.firewall.access_denied_url ?: '(none)' }} - {% if collector.authenticatorManagerEnabled %} - - authenticators - {{ collector.firewall.authenticators is empty ? '(none)' : profiler_dump(collector.firewall.authenticators, maxDepth=1) }} - - {% else %} - - listeners - {{ collector.firewall.listeners is empty ? '(none)' : profiler_dump(collector.firewall.listeners, maxDepth=1) }} - - {% endif %} + + authenticators + {{ collector.firewall.authenticators is empty ? '(none)' : profiler_dump(collector.firewall.authenticators, maxDepth=1) }} + {% endif %} diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/RememberMeBundle/Security/UserChangingUserProvider.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/RememberMeBundle/Security/UserChangingUserProvider.php index f28bfff393693..c40a7e0a12267 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/RememberMeBundle/Security/UserChangingUserProvider.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/Bundle/RememberMeBundle/Security/UserChangingUserProvider.php @@ -21,6 +21,8 @@ class UserChangingUserProvider implements UserProviderInterface { private $inner; + public static $changePassword = false; + public function __construct(InMemoryUserProvider $inner) { $this->inner = $inner; @@ -28,26 +30,31 @@ public function __construct(InMemoryUserProvider $inner) public function loadUserByUsername($username): UserInterface { - return $this->inner->loadUserByUsername($username); + return $this->changeUser($this->inner->loadUserByUsername($username)); } public function loadUserByIdentifier(string $userIdentifier): UserInterface { - return $this->inner->loadUserByIdentifier($userIdentifier); + return $this->changeUser($this->inner->loadUserByIdentifier($userIdentifier)); } public function refreshUser(UserInterface $user): UserInterface { - $user = $this->inner->refreshUser($user); - - $alterUser = \Closure::bind(function (InMemoryUser $user) { $user->password = 'foo'; }, null, class_exists(User::class) ? User::class : InMemoryUser::class); - $alterUser($user); - - return $user; + return $this->changeUser($this->inner->refreshUser($user)); } public function supportsClass($class): bool { return $this->inner->supportsClass($class); } + + private function changeUser(UserInterface $user): UserInterface + { + if (self::$changePassword) { + $alterUser = \Closure::bind(function (InMemoryUser $user) { $user->password = 'changed!'; }, null, class_exists(User::class) ? User::class : InMemoryUser::class); + $alterUser($user); + } + + return $user; + } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/RememberMeTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/RememberMeTest.php index d9dd477b15b68..0ccc17d9c989d 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/RememberMeTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/RememberMeTest.php @@ -11,8 +11,15 @@ namespace Symfony\Bundle\SecurityBundle\Tests\Functional; +use Symfony\Bundle\SecurityBundle\Tests\Functional\Bundle\RememberMeBundle\Security\UserChangingUserProvider; + class RememberMeTest extends AbstractWebTestCase { + protected function setUp(): void + { + UserChangingUserProvider::$changePassword = false; + } + /** * @dataProvider provideConfigs */ @@ -51,11 +58,19 @@ public function testUserChangeClearsCookie() $this->assertSame(302, $client->getResponse()->getStatusCode()); $cookieJar = $client->getCookieJar(); - $this->assertNotNull($cookieJar->get('REMEMBERME')); + $this->assertNotNull($cookie = $cookieJar->get('REMEMBERME')); + UserChangingUserProvider::$changePassword = true; + + // change password (through user provider), this deauthenticates the session $client->request('GET', '/profile'); $this->assertRedirect($client->getResponse(), '/login'); $this->assertNull($cookieJar->get('REMEMBERME')); + + // restore the old remember me cookie, it should no longer be valid + $cookieJar->set($cookie); + $client->request('GET', '/profile'); + $this->assertRedirect($client->getResponse(), '/login'); } public function testSessionLessRememberMeLogout() diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index f4e7877a26e0c..9f928c2c4fb57 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -27,7 +27,6 @@ "symfony/password-hasher": "^5.4|^6.0", "symfony/security-core": "^5.4|^6.0", "symfony/security-csrf": "^5.4|^6.0", - "symfony/security-guard": "^5.4|^6.0", "symfony/security-http": "^5.4|^6.0" }, "require-dev": { diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig index 4b234d24b354c..fbe3c0794314b 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig @@ -409,6 +409,14 @@ if (typeof Sfjs === 'undefined' || typeof Sfjs.loadToolbar === 'undefined') { renderAjaxRequests: renderAjaxRequests, + getSfwdt: function(token) { + if (!this.sfwdt) { + this.sfwdt = document.getElementById('sfwdt' + token); + } + + return this.sfwdt; + }, + load: function(selector, url, onSuccess, onError, options) { var el = document.getElementById(selector); @@ -440,7 +448,7 @@ if (typeof Sfjs === 'undefined' || typeof Sfjs.loadToolbar === 'undefined') { }, showToolbar: function(token) { - var sfwdt = document.getElementById('sfwdt' + token); + var sfwdt = this.getSfwdt(token); removeClass(sfwdt, 'sf-display-none'); if (getPreference('toolbar/displayState') == 'none') { @@ -455,7 +463,7 @@ if (typeof Sfjs === 'undefined' || typeof Sfjs.loadToolbar === 'undefined') { }, hideToolbar: function(token) { - var sfwdt = document.getElementById('sfwdt' + token); + var sfwdt = this.getSfwdt(token); addClass(sfwdt, 'sf-display-none'); }, @@ -606,7 +614,7 @@ if (typeof Sfjs === 'undefined' || typeof Sfjs.loadToolbar === 'undefined') { }, function(xhr) { if (xhr.status !== 0 && !options.stop) { - var sfwdt = document.getElementById('sfwdt' + token); + var sfwdt = that.getSfwdt(token); sfwdt.innerHTML = '\
\
\ diff --git a/src/Symfony/Bundle/WebProfilerBundle/composer.json b/src/Symfony/Bundle/WebProfilerBundle/composer.json index fa5042cf3afb7..2326917ef1c90 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/composer.json +++ b/src/Symfony/Bundle/WebProfilerBundle/composer.json @@ -32,6 +32,7 @@ }, "conflict": { "symfony/form": "<5.4", + "symfony/mailer": "<5.4", "symfony/messenger": "<5.4", "symfony/dependency-injection": "<5.4" }, diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php index 7bb16573db32f..b020ddc9f43a8 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisAdapterTest.php @@ -96,6 +96,7 @@ public function provideFailedCreateConnection(): array ['redis://localhost:1234'], ['redis://foo@localhost'], ['redis://localhost/123'], + ['redis:///some/local/path'], ]; } diff --git a/src/Symfony/Component/Cache/Tests/Fixtures/PrunableCache.php b/src/Symfony/Component/Cache/Tests/Fixtures/PrunableCache.php deleted file mode 100644 index c1b3f740129d8..0000000000000 --- a/src/Symfony/Component/Cache/Tests/Fixtures/PrunableCache.php +++ /dev/null @@ -1,19 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Cache\Tests\Fixtures; - -use Psr\SimpleCache\CacheInterface; -use Symfony\Component\Cache\PruneableInterface; - -abstract class PrunableCache implements CacheInterface, PruneableInterface -{ -} diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php index 1d8d512c38640..fc833beb7f23a 100644 --- a/src/Symfony/Component/Cache/Traits/RedisTrait.php +++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php @@ -142,7 +142,7 @@ public static function createConnection(string $dsn, array $options = []): \Redi if (preg_match('#/(\d+)$#', $params['path'], $m)) { $params['dbindex'] = $m[1]; $params['path'] = substr($params['path'], 0, -\strlen($m[0])); - } else { + } elseif (isset($params['host'])) { throw new InvalidArgumentException(sprintf('Invalid Redis DSN: "%s", the "dbindex" parameter must be a number.', $dsn)); } } diff --git a/src/Symfony/Component/Cache/composer.json b/src/Symfony/Component/Cache/composer.json index 735a5fb3992c4..8969c33192055 100644 --- a/src/Symfony/Component/Cache/composer.json +++ b/src/Symfony/Component/Cache/composer.json @@ -24,8 +24,8 @@ "php": ">=8.0.2", "psr/cache": "^2.0|^3.0", "psr/log": "^1.1|^2|^3", - "symfony/cache-contracts": "^1.1.7|^2.0|^3.0", - "symfony/service-contracts": "^1.1|^2.0|^3.0", + "symfony/cache-contracts": "^1.1.7|^2|^3", + "symfony/service-contracts": "^1.1|^2|^3", "symfony/var-exporter": "^5.4|^6.0" }, "require-dev": { diff --git a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php index a157d25f96859..6381d70bb3674 100644 --- a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php +++ b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php @@ -119,14 +119,12 @@ private function computeHash(): string private function generateSignature(\ReflectionClass $class): iterable { - if (\PHP_VERSION_ID >= 80000) { - $attributes = []; - foreach ($class->getAttributes() as $a) { - $attributes[] = [$a->getName(), \PHP_VERSION_ID >= 80100 ? (string) $a : $a->getArguments()]; - } - yield print_r($attributes, true); - $attributes = []; + $attributes = []; + foreach ($class->getAttributes() as $a) { + $attributes[] = [$a->getName(), \PHP_VERSION_ID >= 80100 ? (string) $a : $a->getArguments()]; } + yield print_r($attributes, true); + $attributes = []; yield $class->getDocComment(); yield (int) $class->isFinal(); @@ -144,13 +142,11 @@ private function generateSignature(\ReflectionClass $class): iterable $defaults = $class->getDefaultProperties(); foreach ($class->getProperties(\ReflectionProperty::IS_PUBLIC | \ReflectionProperty::IS_PROTECTED) as $p) { - if (\PHP_VERSION_ID >= 80000) { - foreach ($p->getAttributes() as $a) { - $attributes[] = [$a->getName(), \PHP_VERSION_ID >= 80100 ? (string) $a : $a->getArguments()]; - } - yield print_r($attributes, true); - $attributes = []; + foreach ($p->getAttributes() as $a) { + $attributes[] = [$a->getName(), \PHP_VERSION_ID >= 80100 ? (string) $a : $a->getArguments()]; } + yield print_r($attributes, true); + $attributes = []; yield $p->getDocComment(); yield $p->isDefault() ? '' : ''; @@ -164,24 +160,20 @@ private function generateSignature(\ReflectionClass $class): iterable $defined = \Closure::bind(static function ($c) { return \defined($c); }, null, $class->name); foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $m) { - if (\PHP_VERSION_ID >= 80000) { - foreach ($m->getAttributes() as $a) { - $attributes[] = [$a->getName(), \PHP_VERSION_ID >= 80100 ? (string) $a : $a->getArguments()]; - } - yield print_r($attributes, true); - $attributes = []; + foreach ($m->getAttributes() as $a) { + $attributes[] = [$a->getName(), \PHP_VERSION_ID >= 80100 ? (string) $a : $a->getArguments()]; } + yield print_r($attributes, true); + $attributes = []; $defaults = []; $parametersWithUndefinedConstants = []; foreach ($m->getParameters() as $p) { - if (\PHP_VERSION_ID >= 80000) { - foreach ($p->getAttributes() as $a) { - $attributes[] = [$a->getName(), \PHP_VERSION_ID >= 80100 ? (string) $a : $a->getArguments()]; - } - yield print_r($attributes, true); - $attributes = []; + foreach ($p->getAttributes() as $a) { + $attributes[] = [$a->getName(), \PHP_VERSION_ID >= 80100 ? (string) $a : $a->getArguments()]; } + yield print_r($attributes, true); + $attributes = []; if (!$p->isDefaultValueAvailable()) { $defaults[$p->name] = null; diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/AddToList/Symfony/Config/AddToList/Messenger/ReceivingConfig.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/AddToList/Symfony/Config/AddToList/Messenger/ReceivingConfig.php new file mode 100644 index 0000000000000..b408fb1f32de9 --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/AddToList/Symfony/Config/AddToList/Messenger/ReceivingConfig.php @@ -0,0 +1,73 @@ +priority = $value; + + return $this; + } + + /** + * @default null + * @param ParamConfigurator|mixed $value + * @return $this + */ + public function color($value): static + { + $this->color = $value; + + return $this; + } + + public function __construct(array $value = []) + { + + if (isset($value['priority'])) { + $this->priority = $value['priority']; + unset($value['priority']); + } + + if (isset($value['color'])) { + $this->color = $value['color']; + unset($value['color']); + } + + if ([] !== $value) { + throw new InvalidConfigurationException(sprintf('The following keys are not supported by "%s": ', __CLASS__).implode(', ', array_keys($value))); + } + } + + public function toArray(): array + { + $output = []; + if (null !== $this->priority) { + $output['priority'] = $this->priority; + } + if (null !== $this->color) { + $output['color'] = $this->color; + } + + return $output; + } + +} diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/AddToList/Symfony/Config/AddToList/Messenger/RoutingConfig.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/AddToList/Symfony/Config/AddToList/Messenger/RoutingConfig.php new file mode 100644 index 0000000000000..744ffd9c40ffb --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/AddToList/Symfony/Config/AddToList/Messenger/RoutingConfig.php @@ -0,0 +1,52 @@ + $value + * + * @return $this + */ + public function senders(ParamConfigurator|array $value): static + { + $this->senders = $value; + + return $this; + } + + public function __construct(array $value = []) + { + + if (isset($value['senders'])) { + $this->senders = $value['senders']; + unset($value['senders']); + } + + if ([] !== $value) { + throw new InvalidConfigurationException(sprintf('The following keys are not supported by "%s": ', __CLASS__).implode(', ', array_keys($value))); + } + } + + public function toArray(): array + { + $output = []; + if (null !== $this->senders) { + $output['senders'] = $this->senders; + } + + return $output; + } + +} diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/AddToList/Symfony/Config/AddToList/MessengerConfig.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/AddToList/Symfony/Config/AddToList/MessengerConfig.php new file mode 100644 index 0000000000000..2189fde0f3bec --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/AddToList/Symfony/Config/AddToList/MessengerConfig.php @@ -0,0 +1,67 @@ +routing[$message_class])) { + return $this->routing[$message_class] = new \Symfony\Config\AddToList\Messenger\RoutingConfig($value); + } + if ([] === $value) { + return $this->routing[$message_class]; + } + + throw new InvalidConfigurationException('The node created by "routing()" has already been initialized. You cannot pass values the second time you call routing().'); + } + + public function receiving(array $value = []): \Symfony\Config\AddToList\Messenger\ReceivingConfig + { + return $this->receiving[] = new \Symfony\Config\AddToList\Messenger\ReceivingConfig($value); + } + + public function __construct(array $value = []) + { + + if (isset($value['routing'])) { + $this->routing = array_map(function ($v) { return new \Symfony\Config\AddToList\Messenger\RoutingConfig($v); }, $value['routing']); + unset($value['routing']); + } + + if (isset($value['receiving'])) { + $this->receiving = array_map(function ($v) { return new \Symfony\Config\AddToList\Messenger\ReceivingConfig($v); }, $value['receiving']); + unset($value['receiving']); + } + + if ([] !== $value) { + throw new InvalidConfigurationException(sprintf('The following keys are not supported by "%s": ', __CLASS__).implode(', ', array_keys($value))); + } + } + + public function toArray(): array + { + $output = []; + if (null !== $this->routing) { + $output['routing'] = array_map(function ($v) { return $v->toArray(); }, $this->routing); + } + if (null !== $this->receiving) { + $output['receiving'] = array_map(function ($v) { return $v->toArray(); }, $this->receiving); + } + + return $output; + } + +} diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/AddToList/Symfony/Config/AddToList/TranslatorConfig.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/AddToList/Symfony/Config/AddToList/TranslatorConfig.php new file mode 100644 index 0000000000000..10713b582cd49 --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/AddToList/Symfony/Config/AddToList/TranslatorConfig.php @@ -0,0 +1,71 @@ + $value + * + * @return $this + */ + public function fallbacks(ParamConfigurator|array $value): static + { + $this->fallbacks = $value; + + return $this; + } + + /** + * @return $this + */ + public function source(string $source_class, mixed $value): static + { + $this->sources[$source_class] = $value; + + return $this; + } + + public function __construct(array $value = []) + { + + if (isset($value['fallbacks'])) { + $this->fallbacks = $value['fallbacks']; + unset($value['fallbacks']); + } + + if (isset($value['sources'])) { + $this->sources = $value['sources']; + unset($value['sources']); + } + + if ([] !== $value) { + throw new InvalidConfigurationException(sprintf('The following keys are not supported by "%s": ', __CLASS__).implode(', ', array_keys($value))); + } + } + + public function toArray(): array + { + $output = []; + if (null !== $this->fallbacks) { + $output['fallbacks'] = $this->fallbacks; + } + if (null !== $this->sources) { + $output['sources'] = $this->sources; + } + + return $output; + } + +} diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/AddToList/Symfony/Config/AddToListConfig.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/AddToList/Symfony/Config/AddToListConfig.php new file mode 100644 index 0000000000000..679aa9bbc7fca --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/AddToList/Symfony/Config/AddToListConfig.php @@ -0,0 +1,77 @@ +translator) { + $this->translator = new \Symfony\Config\AddToList\TranslatorConfig($value); + } elseif ([] !== $value) { + throw new InvalidConfigurationException('The node created by "translator()" has already been initialized. You cannot pass values the second time you call translator().'); + } + + return $this->translator; + } + + public function messenger(array $value = []): \Symfony\Config\AddToList\MessengerConfig + { + if (null === $this->messenger) { + $this->messenger = new \Symfony\Config\AddToList\MessengerConfig($value); + } elseif ([] !== $value) { + throw new InvalidConfigurationException('The node created by "messenger()" has already been initialized. You cannot pass values the second time you call messenger().'); + } + + return $this->messenger; + } + + public function getExtensionAlias(): string + { + return 'add_to_list'; + } + + public function __construct(array $value = []) + { + + if (isset($value['translator'])) { + $this->translator = new \Symfony\Config\AddToList\TranslatorConfig($value['translator']); + unset($value['translator']); + } + + if (isset($value['messenger'])) { + $this->messenger = new \Symfony\Config\AddToList\MessengerConfig($value['messenger']); + unset($value['messenger']); + } + + if ([] !== $value) { + throw new InvalidConfigurationException(sprintf('The following keys are not supported by "%s": ', __CLASS__).implode(', ', array_keys($value))); + } + } + + public function toArray(): array + { + $output = []; + if (null !== $this->translator) { + $output['translator'] = $this->translator->toArray(); + } + if (null !== $this->messenger) { + $output['messenger'] = $this->messenger->toArray(); + } + + return $output; + } + +} diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/ArrayExtraKeys.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/ArrayExtraKeys.php index 453468330b26d..751fe5c2934cc 100644 --- a/src/Symfony/Component/Config/Tests/Builder/Fixtures/ArrayExtraKeys.php +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/ArrayExtraKeys.php @@ -29,6 +29,9 @@ public function getConfigTreeBuilder(): TreeBuilder ->end() ->end() ->end() + ->arrayNode('baz') + ->ignoreExtraKeys(false) + ->end() ; return $tb; diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/ArrayExtraKeys/Symfony/Config/ArrayExtraKeys/BarConfig.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/ArrayExtraKeys/Symfony/Config/ArrayExtraKeys/BarConfig.php new file mode 100644 index 0000000000000..4447d6db76984 --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/ArrayExtraKeys/Symfony/Config/ArrayExtraKeys/BarConfig.php @@ -0,0 +1,88 @@ +corge = $value; + + return $this; + } + + /** + * @default null + * @param ParamConfigurator|mixed $value + * @return $this + */ + public function grault($value): static + { + $this->grault = $value; + + return $this; + } + + public function __construct(array $value = []) + { + + if (isset($value['corge'])) { + $this->corge = $value['corge']; + unset($value['corge']); + } + + if (isset($value['grault'])) { + $this->grault = $value['grault']; + unset($value['grault']); + } + + $this->_extraKeys = $value; + + } + + public function toArray(): array + { + $output = []; + if (null !== $this->corge) { + $output['corge'] = $this->corge; + } + if (null !== $this->grault) { + $output['grault'] = $this->grault; + } + + return $output + $this->_extraKeys; + } + + /** + * @param ParamConfigurator|mixed $value + * + * @return $this + */ + public function set(string $key, mixed $value): static + { + if (null === $value) { + unset($this->_extraKeys[$key]); + } else { + $this->_extraKeys[$key] = $value; + } + + return $this; + } + +} diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/ArrayExtraKeys/Symfony/Config/ArrayExtraKeys/BazConfig.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/ArrayExtraKeys/Symfony/Config/ArrayExtraKeys/BazConfig.php new file mode 100644 index 0000000000000..6ba4de7a56a2e --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/ArrayExtraKeys/Symfony/Config/ArrayExtraKeys/BazConfig.php @@ -0,0 +1,46 @@ +_extraKeys = $value; + + } + + public function toArray(): array + { + $output = []; + + return $output + $this->_extraKeys; + } + + /** + * @param ParamConfigurator|mixed $value + * + * @return $this + */ + public function set(string $key, mixed $value): static + { + if (null === $value) { + unset($this->_extraKeys[$key]); + } else { + $this->_extraKeys[$key] = $value; + } + + return $this; + } + +} diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/ArrayExtraKeys/Symfony/Config/ArrayExtraKeys/FooConfig.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/ArrayExtraKeys/Symfony/Config/ArrayExtraKeys/FooConfig.php new file mode 100644 index 0000000000000..35cf66d3f169b --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/ArrayExtraKeys/Symfony/Config/ArrayExtraKeys/FooConfig.php @@ -0,0 +1,88 @@ +baz = $value; + + return $this; + } + + /** + * @default null + * @param ParamConfigurator|mixed $value + * @return $this + */ + public function qux($value): static + { + $this->qux = $value; + + return $this; + } + + public function __construct(array $value = []) + { + + if (isset($value['baz'])) { + $this->baz = $value['baz']; + unset($value['baz']); + } + + if (isset($value['qux'])) { + $this->qux = $value['qux']; + unset($value['qux']); + } + + $this->_extraKeys = $value; + + } + + public function toArray(): array + { + $output = []; + if (null !== $this->baz) { + $output['baz'] = $this->baz; + } + if (null !== $this->qux) { + $output['qux'] = $this->qux; + } + + return $output + $this->_extraKeys; + } + + /** + * @param ParamConfigurator|mixed $value + * + * @return $this + */ + public function set(string $key, mixed $value): static + { + if (null === $value) { + unset($this->_extraKeys[$key]); + } else { + $this->_extraKeys[$key] = $value; + } + + return $this; + } + +} diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/ArrayExtraKeys/Symfony/Config/ArrayExtraKeysConfig.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/ArrayExtraKeys/Symfony/Config/ArrayExtraKeysConfig.php new file mode 100644 index 0000000000000..20ff730475f54 --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/ArrayExtraKeys/Symfony/Config/ArrayExtraKeysConfig.php @@ -0,0 +1,92 @@ +foo) { + $this->foo = new \Symfony\Config\ArrayExtraKeys\FooConfig($value); + } elseif ([] !== $value) { + throw new InvalidConfigurationException('The node created by "foo()" has already been initialized. You cannot pass values the second time you call foo().'); + } + + return $this->foo; + } + + public function bar(array $value = []): \Symfony\Config\ArrayExtraKeys\BarConfig + { + return $this->bar[] = new \Symfony\Config\ArrayExtraKeys\BarConfig($value); + } + + public function baz(array $value = []): \Symfony\Config\ArrayExtraKeys\BazConfig + { + if (null === $this->baz) { + $this->baz = new \Symfony\Config\ArrayExtraKeys\BazConfig($value); + } elseif ([] !== $value) { + throw new InvalidConfigurationException('The node created by "baz()" has already been initialized. You cannot pass values the second time you call baz().'); + } + + return $this->baz; + } + + public function getExtensionAlias(): string + { + return 'array_extra_keys'; + } + + public function __construct(array $value = []) + { + + if (isset($value['foo'])) { + $this->foo = new \Symfony\Config\ArrayExtraKeys\FooConfig($value['foo']); + unset($value['foo']); + } + + if (isset($value['bar'])) { + $this->bar = array_map(function ($v) { return new \Symfony\Config\ArrayExtraKeys\BarConfig($v); }, $value['bar']); + unset($value['bar']); + } + + if (isset($value['baz'])) { + $this->baz = new \Symfony\Config\ArrayExtraKeys\BazConfig($value['baz']); + unset($value['baz']); + } + + if ([] !== $value) { + throw new InvalidConfigurationException(sprintf('The following keys are not supported by "%s": ', __CLASS__).implode(', ', array_keys($value))); + } + } + + public function toArray(): array + { + $output = []; + if (null !== $this->foo) { + $output['foo'] = $this->foo->toArray(); + } + if (null !== $this->bar) { + $output['bar'] = array_map(function ($v) { return $v->toArray(); }, $this->bar); + } + if (null !== $this->baz) { + $output['baz'] = $this->baz->toArray(); + } + + return $output; + } + +} diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues/Symfony/Config/NodeInitialValues/Messenger/TransportsConfig.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues/Symfony/Config/NodeInitialValues/Messenger/TransportsConfig.php new file mode 100644 index 0000000000000..e524f94e9c60b --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues/Symfony/Config/NodeInitialValues/Messenger/TransportsConfig.php @@ -0,0 +1,94 @@ +dsn = $value; + + return $this; + } + + /** + * @default null + * @param ParamConfigurator|mixed $value + * @return $this + */ + public function serializer($value): static + { + $this->serializer = $value; + + return $this; + } + + /** + * @param ParamConfigurator|list $value + * + * @return $this + */ + public function options(ParamConfigurator|array $value): static + { + $this->options = $value; + + return $this; + } + + public function __construct(array $value = []) + { + + if (isset($value['dsn'])) { + $this->dsn = $value['dsn']; + unset($value['dsn']); + } + + if (isset($value['serializer'])) { + $this->serializer = $value['serializer']; + unset($value['serializer']); + } + + if (isset($value['options'])) { + $this->options = $value['options']; + unset($value['options']); + } + + if ([] !== $value) { + throw new InvalidConfigurationException(sprintf('The following keys are not supported by "%s": ', __CLASS__).implode(', ', array_keys($value))); + } + } + + public function toArray(): array + { + $output = []; + if (null !== $this->dsn) { + $output['dsn'] = $this->dsn; + } + if (null !== $this->serializer) { + $output['serializer'] = $this->serializer; + } + if (null !== $this->options) { + $output['options'] = $this->options; + } + + return $output; + } + +} diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues/Symfony/Config/NodeInitialValues/MessengerConfig.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues/Symfony/Config/NodeInitialValues/MessengerConfig.php new file mode 100644 index 0000000000000..8e59732f2d024 --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues/Symfony/Config/NodeInitialValues/MessengerConfig.php @@ -0,0 +1,52 @@ +transports[$name])) { + return $this->transports[$name] = new \Symfony\Config\NodeInitialValues\Messenger\TransportsConfig($value); + } + if ([] === $value) { + return $this->transports[$name]; + } + + throw new InvalidConfigurationException('The node created by "transports()" has already been initialized. You cannot pass values the second time you call transports().'); + } + + public function __construct(array $value = []) + { + + if (isset($value['transports'])) { + $this->transports = array_map(function ($v) { return new \Symfony\Config\NodeInitialValues\Messenger\TransportsConfig($v); }, $value['transports']); + unset($value['transports']); + } + + if ([] !== $value) { + throw new InvalidConfigurationException(sprintf('The following keys are not supported by "%s": ', __CLASS__).implode(', ', array_keys($value))); + } + } + + public function toArray(): array + { + $output = []; + if (null !== $this->transports) { + $output['transports'] = array_map(function ($v) { return $v->toArray(); }, $this->transports); + } + + return $output; + } + +} diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues/Symfony/Config/NodeInitialValues/SomeCleverNameConfig.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues/Symfony/Config/NodeInitialValues/SomeCleverNameConfig.php new file mode 100644 index 0000000000000..25f6a01fe496a --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues/Symfony/Config/NodeInitialValues/SomeCleverNameConfig.php @@ -0,0 +1,73 @@ +first = $value; + + return $this; + } + + /** + * @default null + * @param ParamConfigurator|mixed $value + * @return $this + */ + public function second($value): static + { + $this->second = $value; + + return $this; + } + + public function __construct(array $value = []) + { + + if (isset($value['first'])) { + $this->first = $value['first']; + unset($value['first']); + } + + if (isset($value['second'])) { + $this->second = $value['second']; + unset($value['second']); + } + + if ([] !== $value) { + throw new InvalidConfigurationException(sprintf('The following keys are not supported by "%s": ', __CLASS__).implode(', ', array_keys($value))); + } + } + + public function toArray(): array + { + $output = []; + if (null !== $this->first) { + $output['first'] = $this->first; + } + if (null !== $this->second) { + $output['second'] = $this->second; + } + + return $output; + } + +} diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues/Symfony/Config/NodeInitialValuesConfig.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues/Symfony/Config/NodeInitialValuesConfig.php new file mode 100644 index 0000000000000..d2f8bc654cfde --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/NodeInitialValues/Symfony/Config/NodeInitialValuesConfig.php @@ -0,0 +1,77 @@ +someCleverName) { + $this->someCleverName = new \Symfony\Config\NodeInitialValues\SomeCleverNameConfig($value); + } elseif ([] !== $value) { + throw new InvalidConfigurationException('The node created by "someCleverName()" has already been initialized. You cannot pass values the second time you call someCleverName().'); + } + + return $this->someCleverName; + } + + public function messenger(array $value = []): \Symfony\Config\NodeInitialValues\MessengerConfig + { + if (null === $this->messenger) { + $this->messenger = new \Symfony\Config\NodeInitialValues\MessengerConfig($value); + } elseif ([] !== $value) { + throw new InvalidConfigurationException('The node created by "messenger()" has already been initialized. You cannot pass values the second time you call messenger().'); + } + + return $this->messenger; + } + + public function getExtensionAlias(): string + { + return 'node_initial_values'; + } + + public function __construct(array $value = []) + { + + if (isset($value['some_clever_name'])) { + $this->someCleverName = new \Symfony\Config\NodeInitialValues\SomeCleverNameConfig($value['some_clever_name']); + unset($value['some_clever_name']); + } + + if (isset($value['messenger'])) { + $this->messenger = new \Symfony\Config\NodeInitialValues\MessengerConfig($value['messenger']); + unset($value['messenger']); + } + + if ([] !== $value) { + throw new InvalidConfigurationException(sprintf('The following keys are not supported by "%s": ', __CLASS__).implode(', ', array_keys($value))); + } + } + + public function toArray(): array + { + $output = []; + if (null !== $this->someCleverName) { + $output['some_clever_name'] = $this->someCleverName->toArray(); + } + if (null !== $this->messenger) { + $output['messenger'] = $this->messenger->toArray(); + } + + return $output; + } + +} diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/Placeholders/Symfony/Config/PlaceholdersConfig.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/Placeholders/Symfony/Config/PlaceholdersConfig.php new file mode 100644 index 0000000000000..f05f40ce1eed6 --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/Placeholders/Symfony/Config/PlaceholdersConfig.php @@ -0,0 +1,99 @@ +enabled = $value; + + return $this; + } + + /** + * @default null + * @param ParamConfigurator|float $value + * @return $this + */ + public function favoriteFloat($value): static + { + $this->favoriteFloat = $value; + + return $this; + } + + /** + * @param ParamConfigurator|list $value + * + * @return $this + */ + public function goodIntegers(ParamConfigurator|array $value): static + { + $this->goodIntegers = $value; + + return $this; + } + + public function getExtensionAlias(): string + { + return 'placeholders'; + } + + public function __construct(array $value = []) + { + + if (isset($value['enabled'])) { + $this->enabled = $value['enabled']; + unset($value['enabled']); + } + + if (isset($value['favorite_float'])) { + $this->favoriteFloat = $value['favorite_float']; + unset($value['favorite_float']); + } + + if (isset($value['good_integers'])) { + $this->goodIntegers = $value['good_integers']; + unset($value['good_integers']); + } + + if ([] !== $value) { + throw new InvalidConfigurationException(sprintf('The following keys are not supported by "%s": ', __CLASS__).implode(', ', array_keys($value))); + } + } + + public function toArray(): array + { + $output = []; + if (null !== $this->enabled) { + $output['enabled'] = $this->enabled; + } + if (null !== $this->favoriteFloat) { + $output['favorite_float'] = $this->favoriteFloat; + } + if (null !== $this->goodIntegers) { + $output['good_integers'] = $this->goodIntegers; + } + + return $output; + } + +} diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/PrimitiveTypes/Symfony/Config/PrimitiveTypesConfig.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/PrimitiveTypes/Symfony/Config/PrimitiveTypesConfig.php new file mode 100644 index 0000000000000..313499b20cbb6 --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/PrimitiveTypes/Symfony/Config/PrimitiveTypesConfig.php @@ -0,0 +1,141 @@ +booleanNode = $value; + + return $this; + } + + /** + * @default null + * @param ParamConfigurator|'foo'|'bar'|'baz' $value + * @return $this + */ + public function enumNode($value): static + { + $this->enumNode = $value; + + return $this; + } + + /** + * @default null + * @param ParamConfigurator|float $value + * @return $this + */ + public function floatNode($value): static + { + $this->floatNode = $value; + + return $this; + } + + /** + * @default null + * @param ParamConfigurator|int $value + * @return $this + */ + public function integerNode($value): static + { + $this->integerNode = $value; + + return $this; + } + + /** + * @default null + * @param ParamConfigurator|mixed $value + * @return $this + */ + public function scalarNode($value): static + { + $this->scalarNode = $value; + + return $this; + } + + public function getExtensionAlias(): string + { + return 'primitive_types'; + } + + public function __construct(array $value = []) + { + + if (isset($value['boolean_node'])) { + $this->booleanNode = $value['boolean_node']; + unset($value['boolean_node']); + } + + if (isset($value['enum_node'])) { + $this->enumNode = $value['enum_node']; + unset($value['enum_node']); + } + + if (isset($value['float_node'])) { + $this->floatNode = $value['float_node']; + unset($value['float_node']); + } + + if (isset($value['integer_node'])) { + $this->integerNode = $value['integer_node']; + unset($value['integer_node']); + } + + if (isset($value['scalar_node'])) { + $this->scalarNode = $value['scalar_node']; + unset($value['scalar_node']); + } + + if ([] !== $value) { + throw new InvalidConfigurationException(sprintf('The following keys are not supported by "%s": ', __CLASS__).implode(', ', array_keys($value))); + } + } + + public function toArray(): array + { + $output = []; + if (null !== $this->booleanNode) { + $output['boolean_node'] = $this->booleanNode; + } + if (null !== $this->enumNode) { + $output['enum_node'] = $this->enumNode; + } + if (null !== $this->floatNode) { + $output['float_node'] = $this->floatNode; + } + if (null !== $this->integerNode) { + $output['integer_node'] = $this->integerNode; + } + if (null !== $this->scalarNode) { + $output['scalar_node'] = $this->scalarNode; + } + + return $output; + } + +} diff --git a/src/Symfony/Component/Config/Tests/Builder/Fixtures/VariableType/Symfony/Config/VariableTypeConfig.php b/src/Symfony/Component/Config/Tests/Builder/Fixtures/VariableType/Symfony/Config/VariableTypeConfig.php new file mode 100644 index 0000000000000..2ccd609255b17 --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Builder/Fixtures/VariableType/Symfony/Config/VariableTypeConfig.php @@ -0,0 +1,58 @@ +anyValue = $value; + + return $this; + } + + public function getExtensionAlias(): string + { + return 'variable_type'; + } + + public function __construct(array $value = []) + { + + if (isset($value['any_value'])) { + $this->anyValue = $value['any_value']; + unset($value['any_value']); + } + + if ([] !== $value) { + throw new InvalidConfigurationException(sprintf('The following keys are not supported by "%s": ', __CLASS__).implode(', ', array_keys($value))); + } + } + + public function toArray(): array + { + $output = []; + if (null !== $this->anyValue) { + $output['any_value'] = $this->anyValue; + } + + return $output; + } + +} diff --git a/src/Symfony/Component/Config/Tests/Builder/GeneratedConfigTest.php b/src/Symfony/Component/Config/Tests/Builder/GeneratedConfigTest.php index 4089bacc97f26..e85558cac8d96 100644 --- a/src/Symfony/Component/Config/Tests/Builder/GeneratedConfigTest.php +++ b/src/Symfony/Component/Config/Tests/Builder/GeneratedConfigTest.php @@ -11,6 +11,8 @@ use Symfony\Component\Config\Tests\Builder\Fixtures\NodeInitialValues; use Symfony\Component\DependencyInjection\Loader\Configurator\AbstractConfigurator; use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; +use Symfony\Component\Filesystem\Filesystem; +use Symfony\Component\Finder\Iterator\RecursiveDirectoryIterator; use Symfony\Config\AddToListConfig; /** @@ -20,6 +22,23 @@ */ class GeneratedConfigTest extends TestCase { + private $tempDir = []; + + protected function setup(): void + { + parent::setup(); + + $this->tempDir = []; + } + + protected function tearDown(): void + { + (new Filesystem())->remove($this->tempDir); + $this->tempDir = []; + + parent::tearDown(); + } + public function fixtureNames() { $array = [ @@ -49,11 +68,20 @@ public function fixtureNames() public function testConfig(string $name, string $alias) { $basePath = __DIR__.'/Fixtures/'; - $configBuilder = $this->generateConfigBuilder('Symfony\\Component\\Config\\Tests\\Builder\\Fixtures\\'.$name); $callback = include $basePath.$name.'.config.php'; $expectedOutput = include $basePath.$name.'.output.php'; + $expectedCode = $basePath.$name; + + // to regenerate snapshot files, uncomment these lines + // (new Filesystem())->remove($expectedCode); + // $configBuilder = $this->generateConfigBuilder('Symfony\\Component\\Config\\Tests\\Builder\\Fixtures\\'.$name, $expectedCode); + + $outputDir = sys_get_temp_dir().\DIRECTORY_SEPARATOR.uniqid('sf_config_builder', true); + $configBuilder = $this->generateConfigBuilder('Symfony\\Component\\Config\\Tests\\Builder\\Fixtures\\'.$name, $outputDir); $callback($configBuilder); + $this->assertDirectorySame($expectedCode, $outputDir); + $this->assertInstanceOf(ConfigBuilderInterface::class, $configBuilder); $this->assertSame($alias, $configBuilder->getExtensionAlias()); $output = $configBuilder->toArray(); @@ -118,8 +146,13 @@ public function testSetExtraKeyMethodIsNotGeneratedWhenAllowExtraKeysIsFalse() /** * Generate the ConfigBuilder or return an already generated instance. */ - private function generateConfigBuilder(string $configurationClass) + private function generateConfigBuilder(string $configurationClass, string $outputDir = null) { + $outputDir ?? $outputDir = sys_get_temp_dir().\DIRECTORY_SEPARATOR.uniqid('sf_config_builder', true); + if (!str_contains($outputDir, __DIR__)) { + $this->tempDir[] = $outputDir; + } + $configuration = new $configurationClass(); $rootNode = $configuration->getConfigTreeBuilder()->buildTree(); $rootClass = new ClassBuilder('Symfony\\Config', $rootNode->getName()); @@ -128,13 +161,31 @@ private function generateConfigBuilder(string $configurationClass) return new $fqcn(); } - $outputDir = sys_get_temp_dir().\DIRECTORY_SEPARATOR.uniqid('sf_config_builder', true); - - // This line is helpful for debugging - // $outputDir = __DIR__.'/.build'; - $loader = (new ConfigBuilderGenerator($outputDir))->build(new $configurationClass()); return $loader(); } + + private function assertDirectorySame($expected, $current) + { + $expectedFiles = []; + foreach (new \RecursiveIteratorIterator(new RecursiveDirectoryIterator($expected, \FilesystemIterator::SKIP_DOTS)) as $file) { + if ($file->isDir()) { + continue; + } + $expectedFiles[substr($file->getPathname(), \strlen($expected))] = $file->getPathname(); + } + $currentFiles = []; + foreach (new \RecursiveIteratorIterator(new RecursiveDirectoryIterator($current, \FilesystemIterator::SKIP_DOTS)) as $file) { + if ($file->isDir()) { + continue; + } + $currentFiles[substr($file->getPathname(), \strlen($current))] = $file->getPathname(); + } + + $this->assertSame(array_keys($expectedFiles), array_keys($currentFiles)); + foreach ($expectedFiles as $fileName => $filePath) { + $this->assertFileEquals($filePath, $currentFiles[$fileName]); + } + } } diff --git a/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php b/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php index 1443ca95dd93c..c6d52a147a745 100644 --- a/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php +++ b/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php @@ -121,10 +121,7 @@ public function provideHashedSignature(): iterable { yield [false, 0, "// line change\n\n"]; yield [true, 0, '/** class docblock */']; - - if (\PHP_VERSION_ID >= 80000) { - yield [true, 0, '#[Foo]']; - } + yield [true, 0, '#[Foo]']; if (\PHP_VERSION_ID >= 80100) { yield [true, 0, '#[Foo(new MissingClass)]']; @@ -154,11 +151,8 @@ public function provideHashedSignature(): iterable yield [false, 11, "public function pub(\$arg = null) {\nreturn 123;\n}"]; yield [true, 12, '/** prot docblock */']; yield [true, 13, 'protected function prot($a = [123]) {}']; - - if (\PHP_VERSION_ID >= 80000) { - yield [true, 13, '#[Foo] protected function prot($a = []) {}']; - yield [true, 13, 'protected function prot(#[Foo] $a = []) {}']; - } + yield [true, 13, '#[Foo] protected function prot($a = []) {}']; + yield [true, 13, 'protected function prot(#[Foo] $a = []) {}']; if (\PHP_VERSION_ID >= 80100) { yield [true, 13, '#[Foo(new MissingClass)] protected function prot($a = []) {}']; diff --git a/src/Symfony/Component/Config/composer.json b/src/Symfony/Component/Config/composer.json index d03f53212ff41..1375ad83582a7 100644 --- a/src/Symfony/Component/Config/composer.json +++ b/src/Symfony/Component/Config/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=8.0.2", - "symfony/deprecation-contracts": "^2.1|^3.0", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/filesystem": "^5.4|^6.0", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-php81": "^1.22" @@ -26,7 +26,7 @@ "symfony/event-dispatcher": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", "symfony/messenger": "^5.4|^6.0", - "symfony/service-contracts": "^1.1|^2.0|^3.0", + "symfony/service-contracts": "^1.1|^2|^3", "symfony/yaml": "^5.4|^6.0" }, "conflict": { diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index f47e01d7b2146..b582435f7d102 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -1037,7 +1037,7 @@ protected function getDefaultInputDefinition(): InputDefinition new InputOption('--quiet', '-q', InputOption::VALUE_NONE, 'Do not output any message'), new InputOption('--verbose', '-v|vv|vvv', InputOption::VALUE_NONE, 'Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug'), new InputOption('--version', '-V', InputOption::VALUE_NONE, 'Display this application version'), - new InputOption('--ansi', '', InputOption::VALUE_NEGATABLE, 'Force (or disable --no-ansi) ANSI output', false), + new InputOption('--ansi', '', InputOption::VALUE_NEGATABLE, 'Force (or disable --no-ansi) ANSI output', null), new InputOption('--no-interaction', '-n', InputOption::VALUE_NONE, 'Do not ask any interactive question'), ]); } diff --git a/src/Symfony/Component/Console/CHANGELOG.md b/src/Symfony/Component/Console/CHANGELOG.md index fe66897574b10..9a93c7991de89 100644 --- a/src/Symfony/Component/Console/CHANGELOG.md +++ b/src/Symfony/Component/Console/CHANGELOG.md @@ -27,6 +27,7 @@ CHANGELOG * Add support for bright colors * Add `#[AsCommand]` attribute for declaring commands on PHP 8 * Add `Helper::width()` and `Helper::length()` + * The `--ansi` and `--no-ansi` options now default to `null`. 5.2.0 ----- diff --git a/src/Symfony/Component/Console/Completion/CompletionSuggestions.php b/src/Symfony/Component/Console/Completion/CompletionSuggestions.php index e69c667101187..719118177f354 100644 --- a/src/Symfony/Component/Console/Completion/CompletionSuggestions.php +++ b/src/Symfony/Component/Console/Completion/CompletionSuggestions.php @@ -18,7 +18,7 @@ * * @author Wouter de Jong */ -class CompletionSuggestions +final class CompletionSuggestions { private $valueSuggestions = []; private $optionSuggestions = []; @@ -28,9 +28,9 @@ class CompletionSuggestions * * @return $this */ - public function suggestValue(string $value): static + public function suggestValue(string|Suggestion $value): static { - $this->valueSuggestions[] = $value; + $this->valueSuggestions[] = !$value instanceof Suggestion ? new Suggestion($value) : $value; return $this; } @@ -38,13 +38,15 @@ public function suggestValue(string $value): static /** * Add multiple suggested values at once for an input option or argument. * - * @param string[] $values + * @param list $values * * @return $this */ public function suggestValues(array $values): static { - $this->valueSuggestions = array_merge($this->valueSuggestions, $values); + foreach ($values as $value) { + $this->suggestValue($value); + } return $this; } @@ -86,7 +88,7 @@ public function getOptionSuggestions(): array } /** - * @return string[] + * @return Suggestion[] */ public function getValueSuggestions(): array { diff --git a/src/Symfony/Component/Console/Completion/Output/BashCompletionOutput.php b/src/Symfony/Component/Console/Completion/Output/BashCompletionOutput.php index cfe8415d1a2a0..8d5ffa6b67d4b 100644 --- a/src/Symfony/Component/Console/Completion/Output/BashCompletionOutput.php +++ b/src/Symfony/Component/Console/Completion/Output/BashCompletionOutput.php @@ -21,10 +21,10 @@ class BashCompletionOutput implements CompletionOutputInterface { public function write(CompletionSuggestions $suggestions, OutputInterface $output): void { - $options = $suggestions->getValueSuggestions(); + $values = $suggestions->getValueSuggestions(); foreach ($suggestions->getOptionSuggestions() as $option) { - $options[] = '--'.$option->getName(); + $values[] = '--'.$option->getName(); } - $output->writeln(implode("\n", $options)); + $output->writeln(implode("\n", $values)); } } diff --git a/src/Symfony/Component/Console/Completion/Suggestion.php b/src/Symfony/Component/Console/Completion/Suggestion.php new file mode 100644 index 0000000000000..ff156f84ce7e3 --- /dev/null +++ b/src/Symfony/Component/Console/Completion/Suggestion.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Completion; + +/** + * Represents a single suggested value. + * + * @author Wouter de Jong + */ +class Suggestion +{ + private string $value; + + public function __construct(string $value) + { + $this->value = $value; + } + + public function getValue(): string + { + return $this->value; + } + + public function __toString(): string + { + return $this->getValue(); + } +} diff --git a/src/Symfony/Component/Console/README.md b/src/Symfony/Component/Console/README.md index c89b4a1a2066b..c4c129989cbd9 100644 --- a/src/Symfony/Component/Console/README.md +++ b/src/Symfony/Component/Console/README.md @@ -4,6 +4,18 @@ Console Component The Console component eases the creation of beautiful and testable command line interfaces. +Sponsor +------- + +The Console component for Symfony 5.4/6.0 is [backed][1] by [Les-Tilleuls.coop][2]. + +Les-Tilleuls.coop is a team of 50+ Symfony experts who can help you design, develop and +fix your projects. We provide a wide range of professional services including development, +consulting, coaching, training and audits. We also are highly skilled in JS, Go and DevOps. +We are a worker cooperative! + +Help Symfony by [sponsoring][3] its development! + Resources --------- @@ -18,3 +30,7 @@ Credits `Resources/bin/hiddeninput.exe` is a third party binary provided within this component. Find sources and license at https://github.com/Seldaek/hidden-input. + +[1]: https://symfony.com/backers +[2]: https://les-tilleuls.coop +[3]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/Console/Tester/CommandCompletionTester.php b/src/Symfony/Component/Console/Tester/CommandCompletionTester.php index 95cec8982e70f..ade7327529c32 100644 --- a/src/Symfony/Component/Console/Tester/CommandCompletionTester.php +++ b/src/Symfony/Component/Console/Tester/CommandCompletionTester.php @@ -51,6 +51,6 @@ public function complete(array $input): array $options[] = '--'.$option->getName(); } - return array_merge($options, $suggestions->getValueSuggestions()); + return array_map('strval', array_merge($options, $suggestions->getValueSuggestions())); } } diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_1.json b/src/Symfony/Component/Console/Tests/Fixtures/application_1.json index 8c8ba2285f59a..280a4247eb39f 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/application_1.json +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_1.json @@ -63,7 +63,7 @@ "is_value_required": false, "is_multiple": false, "description": "Force (or disable --no-ansi) ANSI output", - "default": false + "default": null }, "no-ansi": { "name": "--no-ansi", @@ -72,7 +72,7 @@ "is_value_required": false, "is_multiple": false, "description": "Negate the \"--ansi\" option", - "default": false + "default": null }, "no-interaction": { "name": "--no-interaction", @@ -175,7 +175,7 @@ "is_value_required": false, "is_multiple": false, "description": "Force (or disable --no-ansi) ANSI output", - "default": false + "default": null }, "no-ansi": { "name": "--no-ansi", @@ -184,7 +184,7 @@ "is_value_required": false, "is_multiple": false, "description": "Negate the \"--ansi\" option", - "default": false + "default": null }, "no-interaction": { "name": "--no-interaction", @@ -287,7 +287,7 @@ "is_value_required": false, "is_multiple": false, "description": "Force (or disable --no-ansi) ANSI output", - "default": false + "default": null }, "no-ansi": { "name": "--no-ansi", @@ -296,7 +296,7 @@ "is_value_required": false, "is_multiple": false, "description": "Negate the \"--ansi\" option", - "default": false + "default": null }, "no-interaction": { "name": "--no-interaction", @@ -390,7 +390,7 @@ "is_value_required": false, "is_multiple": false, "description": "Force (or disable --no-ansi) ANSI output", - "default": false + "default": null }, "no-ansi": { "name": "--no-ansi", @@ -399,7 +399,7 @@ "is_value_required": false, "is_multiple": false, "description": "Negate the \"--ansi\" option", - "default": false + "default": null }, "no-interaction": { "name": "--no-interaction", diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_1.md b/src/Symfony/Component/Console/Tests/Fixtures/application_1.md index dd88bef8724f6..98474874d2e59 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/application_1.md +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_1.md @@ -111,7 +111,7 @@ Force (or disable --no-ansi) ANSI output * Is value required: no * Is multiple: no * Is negatable: yes -* Default: `false` +* Default: `NULL` #### `--no-interaction|-n` @@ -222,7 +222,7 @@ Force (or disable --no-ansi) ANSI output * Is value required: no * Is multiple: no * Is negatable: yes -* Default: `false` +* Default: `NULL` #### `--no-interaction|-n` @@ -349,7 +349,7 @@ Force (or disable --no-ansi) ANSI output * Is value required: no * Is multiple: no * Is negatable: yes -* Default: `false` +* Default: `NULL` #### `--no-interaction|-n` diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_2.json b/src/Symfony/Component/Console/Tests/Fixtures/application_2.json index 172eaa310fb44..89171150ca858 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/application_2.json +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_2.json @@ -67,7 +67,7 @@ "is_value_required": false, "is_multiple": false, "description": "Force (or disable --no-ansi) ANSI output", - "default": false + "default": null }, "no-ansi": { "name": "--no-ansi", @@ -76,7 +76,7 @@ "is_value_required": false, "is_multiple": false, "description": "Negate the \"--ansi\" option", - "default": false + "default": null }, "no-interaction": { "name": "--no-interaction", @@ -179,7 +179,7 @@ "is_value_required": false, "is_multiple": false, "description": "Force (or disable --no-ansi) ANSI output", - "default": false + "default": null }, "no-ansi": { "name": "--no-ansi", @@ -188,7 +188,7 @@ "is_value_required": false, "is_multiple": false, "description": "Negate the \"--ansi\" option", - "default": false + "default": null }, "no-interaction": { "name": "--no-interaction", @@ -291,7 +291,7 @@ "is_value_required": false, "is_multiple": false, "description": "Force (or disable --no-ansi) ANSI output", - "default": false + "default": null }, "no-ansi": { "name": "--no-ansi", @@ -300,7 +300,7 @@ "is_value_required": false, "is_multiple": false, "description": "Negate the \"--ansi\" option", - "default": false + "default": null }, "no-interaction": { "name": "--no-interaction", @@ -394,7 +394,7 @@ "is_value_required": false, "is_multiple": false, "description": "Force (or disable --no-ansi) ANSI output", - "default": false + "default": null }, "no-ansi": { "name": "--no-ansi", @@ -403,7 +403,7 @@ "is_value_required": false, "is_multiple": false, "description": "Negate the \"--ansi\" option", - "default": false + "default": null }, "no-interaction": { "name": "--no-interaction", @@ -482,7 +482,7 @@ "is_value_required": false, "is_multiple": false, "description": "Force (or disable --no-ansi) ANSI output", - "default": false + "default": null }, "no-ansi": { "name": "--no-ansi", @@ -491,7 +491,7 @@ "is_value_required": false, "is_multiple": false, "description": "Negate the \"--ansi\" option", - "default": false + "default": null }, "no-interaction": { "name": "--no-interaction", @@ -578,7 +578,7 @@ "is_value_required": false, "is_multiple": false, "description": "Force (or disable --no-ansi) ANSI output", - "default": false + "default": null }, "no-ansi": { "name": "--no-ansi", @@ -587,7 +587,7 @@ "is_value_required": false, "is_multiple": false, "description": "Negate the \"--ansi\" option", - "default": false + "default": null }, "no-interaction": { "name": "--no-interaction", @@ -655,7 +655,7 @@ "is_value_required": false, "is_multiple": false, "description": "Force (or disable --no-ansi) ANSI output", - "default": false + "default": null }, "no-ansi": { "name": "--no-ansi", @@ -664,7 +664,7 @@ "is_value_required": false, "is_multiple": false, "description": "Negate the \"--ansi\" option", - "default": false + "default": null }, "no-interaction": { "name": "--no-interaction", @@ -734,7 +734,7 @@ "is_value_required": false, "is_multiple": false, "description": "Force (or disable --no-ansi) ANSI output", - "default": false + "default": null }, "no-ansi": { "name": "--no-ansi", @@ -743,7 +743,7 @@ "is_value_required": false, "is_multiple": false, "description": "Negate the \"--ansi\" option", - "default": false + "default": null }, "no-interaction": { "name": "--no-interaction", diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_2.md b/src/Symfony/Component/Console/Tests/Fixtures/application_2.md index f45be81999c5c..265e7117f21c9 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/application_2.md +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_2.md @@ -124,7 +124,7 @@ Force (or disable --no-ansi) ANSI output * Is value required: no * Is multiple: no * Is negatable: yes -* Default: `false` +* Default: `NULL` #### `--no-interaction|-n` @@ -235,7 +235,7 @@ Force (or disable --no-ansi) ANSI output * Is value required: no * Is multiple: no * Is negatable: yes -* Default: `false` +* Default: `NULL` #### `--no-interaction|-n` @@ -362,7 +362,7 @@ Force (or disable --no-ansi) ANSI output * Is value required: no * Is multiple: no * Is negatable: yes -* Default: `false` +* Default: `NULL` #### `--no-interaction|-n` @@ -437,7 +437,7 @@ Force (or disable --no-ansi) ANSI output * Is value required: no * Is multiple: no * Is negatable: yes -* Default: `false` +* Default: `NULL` #### `--no-interaction|-n` @@ -528,7 +528,7 @@ Force (or disable --no-ansi) ANSI output * Is value required: no * Is multiple: no * Is negatable: yes -* Default: `false` +* Default: `NULL` #### `--no-interaction|-n` @@ -600,7 +600,7 @@ Force (or disable --no-ansi) ANSI output * Is value required: no * Is multiple: no * Is negatable: yes -* Default: `false` +* Default: `NULL` #### `--no-interaction|-n` diff --git a/src/Symfony/Component/Console/Tests/Fixtures/application_mbstring.md b/src/Symfony/Component/Console/Tests/Fixtures/application_mbstring.md index b64976d13a90c..2e6fc5f695b8a 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/application_mbstring.md +++ b/src/Symfony/Component/Console/Tests/Fixtures/application_mbstring.md @@ -115,7 +115,7 @@ Force (or disable --no-ansi) ANSI output * Is value required: no * Is multiple: no * Is negatable: yes -* Default: `false` +* Default: `NULL` #### `--no-interaction|-n` @@ -226,7 +226,7 @@ Force (or disable --no-ansi) ANSI output * Is value required: no * Is multiple: no * Is negatable: yes -* Default: `false` +* Default: `NULL` #### `--no-interaction|-n` @@ -353,7 +353,7 @@ Force (or disable --no-ansi) ANSI output * Is value required: no * Is multiple: no * Is negatable: yes -* Default: `false` +* Default: `NULL` #### `--no-interaction|-n` @@ -444,7 +444,7 @@ Force (or disable --no-ansi) ANSI output * Is value required: no * Is multiple: no * Is negatable: yes -* Default: `false` +* Default: `NULL` #### `--no-interaction|-n` diff --git a/src/Symfony/Component/Console/composer.json b/src/Symfony/Component/Console/composer.json index 9ecb8ffd1adc4..7d3947fcc7ec1 100644 --- a/src/Symfony/Component/Console/composer.json +++ b/src/Symfony/Component/Console/composer.json @@ -18,7 +18,7 @@ "require": { "php": ">=8.0.2", "symfony/polyfill-mbstring": "~1.0", - "symfony/service-contracts": "^1.1|^2.0|^3.0", + "symfony/service-contracts": "^1.1|^2|^3", "symfony/string": "^5.4|^6.0" }, "require-dev": { diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckArgumentsValidityPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckArgumentsValidityPass.php index d7d65a12ab992..e0054ef9d2e84 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/CheckArgumentsValidityPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckArgumentsValidityPass.php @@ -41,7 +41,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed $i = 0; $hasNamedArgs = false; foreach ($value->getArguments() as $k => $v) { - if (\PHP_VERSION_ID >= 80000 && preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $k)) { + if (preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $k)) { $hasNamedArgs = true; continue; } @@ -79,7 +79,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed $i = 0; $hasNamedArgs = false; foreach ($methodCall[1] as $k => $v) { - if (\PHP_VERSION_ID >= 80000 && preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $k)) { + if (preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $k)) { $hasNamedArgs = true; continue; } diff --git a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php index fe4645147c49f..c91d9bdfade26 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php @@ -263,7 +263,7 @@ private function addServices(\DOMElement $parent) private function convertParameters(array $parameters, string $type, \DOMElement $parent, string $keyAttribute = 'key') { - $withKeys = array_keys($parameters) !== range(0, \count($parameters) - 1); + $withKeys = !array_is_list($parameters); foreach ($parameters as $key => $value) { $element = $this->document->createElement($type); if ($withKeys) { diff --git a/src/Symfony/Component/DependencyInjection/composer.json b/src/Symfony/Component/DependencyInjection/composer.json index 35ac8af647f30..192efbdb5adee 100644 --- a/src/Symfony/Component/DependencyInjection/composer.json +++ b/src/Symfony/Component/DependencyInjection/composer.json @@ -18,7 +18,8 @@ "require": { "php": ">=8.0.2", "psr/container": "^1.1|^2.0", - "symfony/deprecation-contracts": "^2.1|^3.0", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/polyfill-php81": "^1.22", "symfony/service-contracts": "^1.1.6|^2.0|^3.0" }, "require-dev": { diff --git a/src/Symfony/Component/ErrorHandler/DebugClassLoader.php b/src/Symfony/Component/ErrorHandler/DebugClassLoader.php index b66adb61fe9a9..d0c9e8d47879c 100644 --- a/src/Symfony/Component/ErrorHandler/DebugClassLoader.php +++ b/src/Symfony/Component/ErrorHandler/DebugClassLoader.php @@ -130,7 +130,7 @@ public function __construct(callable $classLoader) $this->patchTypes += [ 'force' => null, 'php' => \PHP_MAJOR_VERSION.'.'.\PHP_MINOR_VERSION, - 'deprecations' => \PHP_VERSION_ID >= 70400, + 'deprecations' => true, ]; if ('phpdoc' === $this->patchTypes['force']) { @@ -878,7 +878,7 @@ private function normalizeType(string $type, string $class, ?string $parent, ?\R */ private function patchReturnTypeWillChange(\ReflectionMethod $method) { - if (\PHP_VERSION_ID >= 80000 && \count($method->getAttributes(\ReturnTypeWillChange::class))) { + if (\count($method->getAttributes(\ReturnTypeWillChange::class))) { return; } diff --git a/src/Symfony/Component/ErrorHandler/composer.json b/src/Symfony/Component/ErrorHandler/composer.json index 0ce12164fb844..d3cb8035f075b 100644 --- a/src/Symfony/Component/ErrorHandler/composer.json +++ b/src/Symfony/Component/ErrorHandler/composer.json @@ -23,7 +23,7 @@ "require-dev": { "symfony/http-kernel": "^5.4|^6.0", "symfony/serializer": "^5.4|^6.0", - "symfony/deprecation-contracts": "^2.1|^3.0" + "symfony/deprecation-contracts": "^2.1|^3" }, "autoload": { "psr-4": { "Symfony\\Component\\ErrorHandler\\": "" }, diff --git a/src/Symfony/Component/EventDispatcher/composer.json b/src/Symfony/Component/EventDispatcher/composer.json index 5106670b824f7..53a86ee9df7b9 100644 --- a/src/Symfony/Component/EventDispatcher/composer.json +++ b/src/Symfony/Component/EventDispatcher/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=8.0.2", - "symfony/event-dispatcher-contracts": "^2.0|^3.0" + "symfony/event-dispatcher-contracts": "^2|^3" }, "require-dev": { "symfony/dependency-injection": "^5.4|^6.0", @@ -25,7 +25,7 @@ "symfony/config": "^5.4|^6.0", "symfony/error-handler": "^5.4|^6.0", "symfony/http-foundation": "^5.4|^6.0", - "symfony/service-contracts": "^1.1|^2.0|^3.0", + "symfony/service-contracts": "^1.1|^2|^3", "symfony/stopwatch": "^5.4|^6.0", "psr/log": "^1|^2|^3" }, diff --git a/src/Symfony/Component/ExpressionLanguage/composer.json b/src/Symfony/Component/ExpressionLanguage/composer.json index c8dff7d489e64..473f5666de9f3 100644 --- a/src/Symfony/Component/ExpressionLanguage/composer.json +++ b/src/Symfony/Component/ExpressionLanguage/composer.json @@ -18,7 +18,7 @@ "require": { "php": ">=8.0.2", "symfony/cache": "^5.4|^6.0", - "symfony/service-contracts": "^1.1|^2.0|^3.0" + "symfony/service-contracts": "^1.1|^2|^3" }, "autoload": { "psr-4": { "Symfony\\Component\\ExpressionLanguage\\": "" }, diff --git a/src/Symfony/Component/Form/composer.json b/src/Symfony/Component/Form/composer.json index b88e1eeeba108..9bdf5a8778c91 100644 --- a/src/Symfony/Component/Form/composer.json +++ b/src/Symfony/Component/Form/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=8.0.2", - "symfony/deprecation-contracts": "^2.1|^3.0", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/event-dispatcher": "^5.4|^6.0", "symfony/options-resolver": "^5.4|^6.0", "symfony/polyfill-ctype": "~1.8", @@ -25,7 +25,7 @@ "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php81": "^1.23", "symfony/property-access": "^5.4|^6.0", - "symfony/service-contracts": "^1.1|^2.0|^3.0" + "symfony/service-contracts": "^1.1|^2|^3" }, "require-dev": { "doctrine/collections": "~1.0", diff --git a/src/Symfony/Component/HttpClient/HttpClientTrait.php b/src/Symfony/Component/HttpClient/HttpClientTrait.php index 1a5b0a34a2c58..cecb1c0d9220d 100644 --- a/src/Symfony/Component/HttpClient/HttpClientTrait.php +++ b/src/Symfony/Component/HttpClient/HttpClientTrait.php @@ -488,7 +488,7 @@ private static function parseUrl(string $url, array $query = [], array $allowedS throw new InvalidArgumentException(sprintf('Unsupported IDN "%s", try enabling the "intl" PHP extension or running "composer require symfony/polyfill-intl-idn".', $host)); } - $host = \defined('INTL_IDNA_VARIANT_UTS46') ? idn_to_ascii($host, \IDNA_DEFAULT, \INTL_IDNA_VARIANT_UTS46) ?: strtolower($host) : strtolower($host); + $host = \defined('INTL_IDNA_VARIANT_UTS46') ? idn_to_ascii($host, \IDNA_DEFAULT | \IDNA_USE_STD3_RULES | \IDNA_CHECK_BIDI | \IDNA_CHECK_CONTEXTJ | \IDNA_NONTRANSITIONAL_TO_ASCII, \INTL_IDNA_VARIANT_UTS46) ?: strtolower($host) : strtolower($host); $host .= $port ? ':'.$port : ''; } diff --git a/src/Symfony/Component/HttpClient/README.md b/src/Symfony/Component/HttpClient/README.md index 214489b7e7f76..0c55ccc118876 100644 --- a/src/Symfony/Component/HttpClient/README.md +++ b/src/Symfony/Component/HttpClient/README.md @@ -3,6 +3,16 @@ HttpClient component The HttpClient component provides powerful methods to fetch HTTP resources synchronously or asynchronously. +Sponsor +------- + +The Httpclient component for Symfony 5.4/6.0 is [backed][1] by [Klaxoon][2]. + +Klaxoon is a platform that empowers organizations to run effective and +productive workshops easily in a hybrid environment. Anytime, Anywhere. + +Help Symfony by [sponsoring][3] its development! + Resources --------- @@ -11,3 +21,7 @@ Resources * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) + +[1]: https://symfony.com/backers +[2]: https://klaxoon.com +[3]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php index cc44e9d5625cd..b811626c0c670 100644 --- a/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php +++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php @@ -163,6 +163,8 @@ public function provideParseUrl(): iterable yield [[null, null, 'bar', '?a%5Bb%5Bc%5D=d', null], 'bar?a[b[c]=d', []]; yield [[null, null, 'bar', '?a%5Bb%5D%5Bc%5D=dd', null], 'bar?a[b][c]=d&e[f]=g', ['a' => ['b' => ['c' => 'dd']], 'e[f]' => null]]; yield [[null, null, 'bar', '?a=b&a%5Bb%20c%5D=d&e%3Df=%E2%9C%93', null], 'bar?a=b', ['a' => ['b c' => 'd'], 'e=f' => '✓']]; + // IDNA 2008 compliance + yield [['https:', '//xn--fuball-cta.test', null, null, null], 'https://fußball.test']; } /** diff --git a/src/Symfony/Component/HttpClient/composer.json b/src/Symfony/Component/HttpClient/composer.json index f33147e61660c..02a7653b52902 100644 --- a/src/Symfony/Component/HttpClient/composer.json +++ b/src/Symfony/Component/HttpClient/composer.json @@ -23,8 +23,8 @@ "require": { "php": ">=8.0.2", "psr/log": "^1|^2|^3", - "symfony/http-client-contracts": "^3.0", - "symfony/service-contracts": "^1.0|^2.0|^3.0" + "symfony/http-client-contracts": "^3", + "symfony/service-contracts": "^1.0|^2|^3" }, "require-dev": { "amphp/amp": "^2.5", diff --git a/src/Symfony/Component/HttpFoundation/README.md b/src/Symfony/Component/HttpFoundation/README.md index 5cf9007444456..424f2c4f0b848 100644 --- a/src/Symfony/Component/HttpFoundation/README.md +++ b/src/Symfony/Component/HttpFoundation/README.md @@ -4,6 +4,16 @@ HttpFoundation Component The HttpFoundation component defines an object-oriented layer for the HTTP specification. +Sponsor +------- + +The HttpFoundation component for Symfony 5.4/6.0 is [backed][1] by [Laravel][2]. + +Laravel is a PHP web development framework that is passionate about maximum developer +happiness. Laravel is built using a variety of bespoke and Symfony based components. + +Help Symfony by [sponsoring][3] its development! + Resources --------- @@ -12,3 +22,7 @@ Resources * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) + +[1]: https://symfony.com/backers +[2]: https://laravel.com/ +[3]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/HttpFoundation/composer.json b/src/Symfony/Component/HttpFoundation/composer.json index f4a95ba147638..9f5cccc65a8a2 100644 --- a/src/Symfony/Component/HttpFoundation/composer.json +++ b/src/Symfony/Component/HttpFoundation/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=8.0.2", - "symfony/deprecation-contracts": "^2.1|^3.0", + "symfony/deprecation-contracts": "^2.1|^3", "symfony/polyfill-mbstring": "~1.1" }, "require-dev": { diff --git a/src/Symfony/Component/HttpKernel/HttpCache/SubRequestHandler.php b/src/Symfony/Component/HttpKernel/HttpCache/SubRequestHandler.php index a453e432be80d..253071f07da7b 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/SubRequestHandler.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/SubRequestHandler.php @@ -38,6 +38,7 @@ public static function handle(HttpKernelInterface $kernel, Request $request, int 'X_FORWARDED_HOST' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_HOST, 'X_FORWARDED_PROTO' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PROTO, 'X_FORWARDED_PORT' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PORT, + 'X_FORWARDED_PREFIX' => $trustedHeaderSet & Request::HEADER_X_FORWARDED_PREFIX, ]; foreach (array_filter($trustedHeaders) as $name => $key) { $request->headers->remove($name); diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index c5583e49738d0..4fdfde448b00b 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 array $freshCache = []; - public const VERSION = '6.0.0-BETA3'; + public const VERSION = '6.0.0-RC1'; public const VERSION_ID = 60000; public const MAJOR_VERSION = 6; public const MINOR_VERSION = 0; public const RELEASE_VERSION = 0; - public const EXTRA_VERSION = 'BETA3'; + public const EXTRA_VERSION = 'RC1'; public const END_OF_MAINTENANCE = '07/2022'; public const END_OF_LIFE = '07/2022'; diff --git a/src/Symfony/Component/HttpKernel/README.md b/src/Symfony/Component/HttpKernel/README.md index 18d15f5ad835f..ca504178278c4 100644 --- a/src/Symfony/Component/HttpKernel/README.md +++ b/src/Symfony/Component/HttpKernel/README.md @@ -5,6 +5,18 @@ The HttpKernel component provides a structured process for converting a Request into a Response by making use of the EventDispatcher component. It's flexible enough to create full-stack frameworks, micro-frameworks or advanced CMS systems like Drupal. +Sponsor +------- + +The HttpKernel component for Symfony 5.4/6.0 is [backed][1] by [Les-Tilleuls.coop][2]. + +Les-Tilleuls.coop is a team of 50+ Symfony experts who can help you design, develop and +fix your projects. We provide a wide range of professional services including development, +consulting, coaching, training and audits. We also are highly skilled in JS, Go and DevOps. +We are a worker cooperative! + +Help Symfony by [sponsoring][3] its development! + Resources --------- @@ -13,3 +25,7 @@ Resources * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) + +[1]: https://symfony.com/backers +[2]: https://les-tilleuls.coop +[3]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/SubRequestHandlerTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/SubRequestHandlerTest.php index 7ab9b6c45f037..f17abb20281f3 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/SubRequestHandlerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/SubRequestHandlerTest.php @@ -42,6 +42,7 @@ public function testTrustedHeadersAreKept() $request->headers->set('X-Forwarded-Host', 'Good'); $request->headers->set('X-Forwarded-Port', '1234'); $request->headers->set('X-Forwarded-Proto', 'https'); + $request->headers->set('X-Forwarded-Prefix', '/admin'); $kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) { $this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR')); @@ -49,6 +50,7 @@ public function testTrustedHeadersAreKept() $this->assertSame('Good', $request->headers->get('X-Forwarded-Host')); $this->assertSame('1234', $request->headers->get('X-Forwarded-Port')); $this->assertSame('https', $request->headers->get('X-Forwarded-Proto')); + $this->assertSame('/admin', $request->headers->get('X-Forwarded-Prefix')); }); SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MAIN_REQUEST, true); @@ -64,6 +66,7 @@ public function testUntrustedHeadersAreRemoved() $request->headers->set('X-Forwarded-Host', 'Evil'); $request->headers->set('X-Forwarded-Port', '1234'); $request->headers->set('X-Forwarded-Proto', 'http'); + $request->headers->set('X-Forwarded-Prefix', '/admin'); $request->headers->set('Forwarded', 'Evil2'); $kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) { @@ -72,6 +75,7 @@ public function testUntrustedHeadersAreRemoved() $this->assertFalse($request->headers->has('X-Forwarded-Host')); $this->assertFalse($request->headers->has('X-Forwarded-Port')); $this->assertFalse($request->headers->has('X-Forwarded-Proto')); + $this->assertFalse($request->headers->has('X-Forwarded-Prefix')); $this->assertSame('for="10.0.0.1";host="localhost";proto=http', $request->headers->get('Forwarded')); }); @@ -112,12 +116,14 @@ public function testTrustedXForwardedForHeader() $request->headers->set('X-Forwarded-For', '10.0.0.2'); $request->headers->set('X-Forwarded-Host', 'foo.bar'); $request->headers->set('X-Forwarded-Proto', 'https'); + $request->headers->set('X-Forwarded-Prefix', '/admin'); $kernel = new TestSubRequestHandlerKernel(function ($request, $type, $catch) { $this->assertSame('127.0.0.1', $request->server->get('REMOTE_ADDR')); $this->assertSame('10.0.0.2', $request->getClientIp()); $this->assertSame('foo.bar', $request->getHttpHost()); $this->assertSame('https', $request->getScheme()); + $this->assertSame('/admin', $request->getBaseUrl()); }); SubRequestHandler::handle($kernel, $request, HttpKernelInterface::MAIN_REQUEST, true); diff --git a/src/Symfony/Component/HttpKernel/composer.json b/src/Symfony/Component/HttpKernel/composer.json index 4a6c6f0e1f87e..e28f8585624e7 100644 --- a/src/Symfony/Component/HttpKernel/composer.json +++ b/src/Symfony/Component/HttpKernel/composer.json @@ -19,7 +19,6 @@ "php": ">=8.0.2", "symfony/error-handler": "^5.4|^6.0", "symfony/event-dispatcher": "^5.4|^6.0", - "symfony/http-client-contracts": "^1.1|^2.0|^3.0", "symfony/http-foundation": "^5.4|^6.0", "symfony/polyfill-ctype": "^1.8", "psr/log": "^1|^2|^3" @@ -33,11 +32,12 @@ "symfony/dom-crawler": "^5.4|^6.0", "symfony/expression-language": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", + "symfony/http-client-contracts": "^1.1|^2|^3", "symfony/process": "^5.4|^6.0", "symfony/routing": "^5.4|^6.0", "symfony/stopwatch": "^5.4|^6.0", "symfony/translation": "^5.4|^6.0", - "symfony/translation-contracts": "^1.1|^2.0|^3.0", + "symfony/translation-contracts": "^1.1|^2|^3", "psr/cache": "^1.0|^2.0|^3.0", "twig/twig": "^2.13|^3.0.4" }, diff --git a/src/Symfony/Component/Ldap/Tests/Security/CheckLdapCredentialsListenerTest.php b/src/Symfony/Component/Ldap/Tests/Security/CheckLdapCredentialsListenerTest.php index 6c54071bd0c09..56f9eefc5f992 100644 --- a/src/Symfony/Component/Ldap/Tests/Security/CheckLdapCredentialsListenerTest.php +++ b/src/Symfony/Component/Ldap/Tests/Security/CheckLdapCredentialsListenerTest.php @@ -30,6 +30,7 @@ use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge; use Symfony\Component\Security\Http\Authenticator\Passport\Credentials\PasswordCredentials; use Symfony\Component\Security\Http\Authenticator\Passport\Passport; +use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface; use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport; use Symfony\Component\Security\Http\Event\CheckPassportEvent; use Symfony\Contracts\Service\ServiceLocatorTrait; @@ -215,7 +216,10 @@ public function authenticate(Request $request): Passport { } - public function createAuthenticatedToken(Passport $passport, string $firewallName): TokenInterface + /** + * @internal for compatibility with Symfony 5.4 + */ + public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface { } diff --git a/src/Symfony/Component/Mailer/Bridge/Google/Tests/Transport/GmailTransportFactoryTest.php b/src/Symfony/Component/Mailer/Bridge/Google/Tests/Transport/GmailTransportFactoryTest.php index ff9e41058434f..51f0b3ba0f0f0 100644 --- a/src/Symfony/Component/Mailer/Bridge/Google/Tests/Transport/GmailTransportFactoryTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Google/Tests/Transport/GmailTransportFactoryTest.php @@ -12,7 +12,7 @@ class GmailTransportFactoryTest extends TransportFactoryTestCase { public function getFactory(): TransportFactoryInterface { - return new GmailTransportFactory($this->getDispatcher(), $this->getClient(), $this->getLogger()); + return new GmailTransportFactory($this->getDispatcher(), null, $this->getLogger()); } public function supportsProvider(): iterable diff --git a/src/Symfony/Component/Mailer/Bridge/Google/composer.json b/src/Symfony/Component/Mailer/Bridge/Google/composer.json index fa6245f880046..6ff31d950ff8c 100644 --- a/src/Symfony/Component/Mailer/Bridge/Google/composer.json +++ b/src/Symfony/Component/Mailer/Bridge/Google/composer.json @@ -19,9 +19,6 @@ "php": ">=8.0.2", "symfony/mailer": "^5.4|^6.0" }, - "require-dev": { - "symfony/http-client": "^5.4|^6.0" - }, "autoload": { "psr-4": { "Symfony\\Component\\Mailer\\Bridge\\Google\\": "" }, "exclude-from-classmap": [ diff --git a/src/Symfony/Component/Mailer/composer.json b/src/Symfony/Component/Mailer/composer.json index 271fdf45377e0..bd6d83ce5613a 100644 --- a/src/Symfony/Component/Mailer/composer.json +++ b/src/Symfony/Component/Mailer/composer.json @@ -22,10 +22,10 @@ "psr/log": "^1|^2|^3", "symfony/event-dispatcher": "^5.4|^6.0", "symfony/mime": "^5.4|^6.0", - "symfony/service-contracts": "^1.1|^2.0|^3.0" + "symfony/service-contracts": "^1.1|^2|^3" }, "require-dev": { - "symfony/http-client-contracts": "^1.1|^2.0|^3.0", + "symfony/http-client-contracts": "^1.1|^2|^3", "symfony/messenger": "^5.4|^6.0" }, "conflict": { diff --git a/src/Symfony/Component/Messenger/Bridge/AmazonSqs/composer.json b/src/Symfony/Component/Messenger/Bridge/AmazonSqs/composer.json index 96b56333192fe..d2e2f5ddf70bd 100644 --- a/src/Symfony/Component/Messenger/Bridge/AmazonSqs/composer.json +++ b/src/Symfony/Component/Messenger/Bridge/AmazonSqs/composer.json @@ -20,11 +20,11 @@ "async-aws/core": "^1.5", "async-aws/sqs": "^1.0", "symfony/messenger": "^5.4|^6.0", - "symfony/service-contracts": "^1.1|^2.0|^3.0", + "symfony/service-contracts": "^1.1|^2|^3", "psr/log": "^1|^2|^3" }, "require-dev": { - "symfony/http-client-contracts": "^1.0|^2.0|^3.0", + "symfony/http-client-contracts": "^1|^2|^3", "symfony/property-access": "^5.4|^6.0", "symfony/serializer": "^5.4|^6.0" }, diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/composer.json b/src/Symfony/Component/Messenger/Bridge/Doctrine/composer.json index 3246dc95b5680..590d5a49ee43e 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/composer.json +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/composer.json @@ -19,7 +19,7 @@ "php": ">=8.0.2", "doctrine/dbal": "^2.13|^3.0", "symfony/messenger": "^5.4|^6.0", - "symfony/service-contracts": "^1.1|^2.0|^3.0" + "symfony/service-contracts": "^1.1|^2|^3" }, "require-dev": { "doctrine/persistence": "^1.3|^2", diff --git a/src/Symfony/Component/Messenger/README.md b/src/Symfony/Component/Messenger/README.md index a253171a5529c..644269c7f34a1 100644 --- a/src/Symfony/Component/Messenger/README.md +++ b/src/Symfony/Component/Messenger/README.md @@ -4,6 +4,17 @@ Messenger Component The Messenger component helps applications send and receive messages to/from other applications or via message queues. +Sponsor +------- + +The Messenger component for Symfony 5.4/6.0 is [backed][1] by [SensioLabs][2]. + +As the creator of Symfony, SensioLabs supports companies using Symfony, with an +offering encompassing consultancy, expertise, services, training, and technical +assistance to ensure the success of web application development projects. + +Help Symfony by [sponsoring][3] its development! + Resources --------- @@ -12,3 +23,7 @@ Resources * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) + +[1]: https://symfony.com/backers +[2]: https://sensiolabs.com +[3]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/Messenger/composer.json b/src/Symfony/Component/Messenger/composer.json index 961d45046ddc0..0b74341fe269b 100644 --- a/src/Symfony/Component/Messenger/composer.json +++ b/src/Symfony/Component/Messenger/composer.json @@ -29,7 +29,7 @@ "symfony/property-access": "^5.4|^6.0", "symfony/routing": "^5.4|^6.0", "symfony/serializer": "^5.4|^6.0", - "symfony/service-contracts": "^1.1|^2.0|^3.0", + "symfony/service-contracts": "^1.1|^2|^3", "symfony/stopwatch": "^5.4|^6.0", "symfony/validator": "^5.4|^6.0" }, diff --git a/src/Symfony/Component/Mime/Encoder/IdnAddressEncoder.php b/src/Symfony/Component/Mime/Encoder/IdnAddressEncoder.php index a14035ba794b9..b56e7e3963010 100644 --- a/src/Symfony/Component/Mime/Encoder/IdnAddressEncoder.php +++ b/src/Symfony/Component/Mime/Encoder/IdnAddressEncoder.php @@ -35,7 +35,7 @@ public function encodeString(string $address): string $domain = substr($address, $i + 1); if (preg_match('/[^\x00-\x7F]/', $domain)) { - $address = sprintf('%s@%s', $local, idn_to_ascii($domain, 0, \INTL_IDNA_VARIANT_UTS46)); + $address = sprintf('%s@%s', $local, idn_to_ascii($domain, \IDNA_DEFAULT | \IDNA_USE_STD3_RULES | \IDNA_CHECK_BIDI | \IDNA_CHECK_CONTEXTJ | \IDNA_NONTRANSITIONAL_TO_ASCII, \INTL_IDNA_VARIANT_UTS46)); } } diff --git a/src/Symfony/Component/Mime/Tests/Encoder/IdnAddressEncoderTest.php b/src/Symfony/Component/Mime/Tests/Encoder/IdnAddressEncoderTest.php new file mode 100644 index 0000000000000..71e7716f8961b --- /dev/null +++ b/src/Symfony/Component/Mime/Tests/Encoder/IdnAddressEncoderTest.php @@ -0,0 +1,13 @@ +assertSame('test@xn--fuball-cta.test', (new IdnAddressEncoder())->encodeString('test@fußball.test')); + } +} diff --git a/src/Symfony/Component/Notifier/Bridge/FakeChat/composer.json b/src/Symfony/Component/Notifier/Bridge/FakeChat/composer.json index bd0b595b9a7e2..c468fdc955301 100644 --- a/src/Symfony/Component/Notifier/Bridge/FakeChat/composer.json +++ b/src/Symfony/Component/Notifier/Bridge/FakeChat/composer.json @@ -24,7 +24,7 @@ "php": ">=8.0.2", "symfony/http-client": "^5.4|^6.0", "symfony/notifier": "^5.4|^6.0", - "symfony/event-dispatcher-contracts": "^2.0|^3.0", + "symfony/event-dispatcher-contracts": "^2|^3", "symfony/mailer": "^5.4|^6.0" }, "autoload": { diff --git a/src/Symfony/Component/Notifier/Bridge/FakeSms/composer.json b/src/Symfony/Component/Notifier/Bridge/FakeSms/composer.json index ca4de1571db02..ef4daeb1c0c75 100644 --- a/src/Symfony/Component/Notifier/Bridge/FakeSms/composer.json +++ b/src/Symfony/Component/Notifier/Bridge/FakeSms/composer.json @@ -24,7 +24,7 @@ "php": ">=8.0.2", "symfony/http-client": "^5.4|^6.0", "symfony/notifier": "^5.4|^6.0", - "symfony/event-dispatcher-contracts": "^2.0|^3.0", + "symfony/event-dispatcher-contracts": "^2|^3", "symfony/mailer": "^5.4|^6.0" }, "autoload": { diff --git a/src/Symfony/Component/Notifier/Bridge/Mercure/composer.json b/src/Symfony/Component/Notifier/Bridge/Mercure/composer.json index 31b33f014c6f4..06082a225bfa3 100644 --- a/src/Symfony/Component/Notifier/Bridge/Mercure/composer.json +++ b/src/Symfony/Component/Notifier/Bridge/Mercure/composer.json @@ -20,7 +20,7 @@ "ext-json": "*", "symfony/mercure": "^0.5.2", "symfony/notifier": "^5.4|^6.0", - "symfony/service-contracts": "^1.10|^2.0|^3.0" + "symfony/service-contracts": "^1.10|^2|^3" }, "autoload": { "psr-4": { "Symfony\\Component\\Notifier\\Bridge\\Mercure\\": "" }, diff --git a/src/Symfony/Component/Notifier/README.md b/src/Symfony/Component/Notifier/README.md index 79e516f69871d..4a9631653841e 100644 --- a/src/Symfony/Component/Notifier/README.md +++ b/src/Symfony/Component/Notifier/README.md @@ -3,6 +3,19 @@ Notifier Component The Notifier component sends notifications via one or more channels (email, SMS, ...). +Sponsor +------- + +The Notifier component for Symfony 5.4/6.0 is [backed][1] by [Mercure.rocks][2]. + +Create real-time experiences in minutes! Mercure.rocks provides a realtime API service +that is tightly integrated with Symfony: create UIs that update in live with UX Turbo, +send notifications with the Notifier component, expose async APIs with API Platform and +create low level stuffs with the Mercure component. We maintain and scale the complex +infrastructure for you! + +Help Symfony by [sponsoring][3] its development! + Resources --------- @@ -11,3 +24,7 @@ Resources * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) + +[1]: https://symfony.com/backers +[2]: https://mercure.rocks +[3]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/Notifier/composer.json b/src/Symfony/Component/Notifier/composer.json index fe512a4363d0c..b75a8bc5a0fa1 100644 --- a/src/Symfony/Component/Notifier/composer.json +++ b/src/Symfony/Component/Notifier/composer.json @@ -20,8 +20,8 @@ "psr/log": "^1|^2|^3" }, "require-dev": { - "symfony/event-dispatcher-contracts": "^2.0|^3.0", - "symfony/http-client-contracts": "^2.0|^3.0", + "symfony/event-dispatcher-contracts": "^2|^3", + "symfony/http-client-contracts": "^2|^3", "symfony/messenger": "^5.4|^6.0" }, "conflict": { diff --git a/src/Symfony/Component/OptionsResolver/composer.json b/src/Symfony/Component/OptionsResolver/composer.json index eadee6ca4d66a..4fd80d95f6f91 100644 --- a/src/Symfony/Component/OptionsResolver/composer.json +++ b/src/Symfony/Component/OptionsResolver/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=8.0.2", - "symfony/deprecation-contracts": "^2.1|^3.0" + "symfony/deprecation-contracts": "^2.1|^3" }, "autoload": { "psr-4": { "Symfony\\Component\\OptionsResolver\\": "" }, diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 7fab232566011..987259d39ab92 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -335,7 +335,7 @@ public function start(callable $callback = null, array $env = []) $envPairs = []; foreach ($env as $k => $v) { - if (false !== $v) { + if (false !== $v && 'argc' !== $k && 'argv' !== $k) { $envPairs[] = $k.'='.$v; } } @@ -1089,25 +1089,12 @@ public function getEnv(): array /** * Sets the environment variables. * - * Each environment variable value should be a string. - * If it is an array, the variable is ignored. - * If it is false or null, it will be removed when - * env vars are otherwise inherited. - * - * That happens in PHP when 'argv' is registered into - * the $_ENV array for instance. - * - * @param array $env The new environment variables + * @param array $env The new environment variables * * @return $this */ public function setEnv(array $env): static { - // Process cannot handle env values that are arrays - $env = array_filter($env, function ($value) { - return !\is_array($value); - }); - $this->env = $env; return $this; @@ -1602,12 +1589,6 @@ private function getDefaultEnv(): array $env = getenv(); $env = array_intersect_key($env, $_SERVER) ?: $env; - foreach ($_ENV as $k => $v) { - if (\is_string($v)) { - $env[$k] = $v; - } - } - - return $env; + return $_ENV + $env; } } diff --git a/src/Symfony/Component/Process/README.md b/src/Symfony/Component/Process/README.md index afce5e45eee34..8777de4a65c52 100644 --- a/src/Symfony/Component/Process/README.md +++ b/src/Symfony/Component/Process/README.md @@ -3,6 +3,17 @@ Process Component The Process component executes commands in sub-processes. +Sponsor +------- + +The Process component for Symfony 5.4/6.0 is [backed][1] by [SensioLabs][2]. + +As the creator of Symfony, SensioLabs supports companies using Symfony, with an +offering encompassing consultancy, expertise, services, training, and technical +assistance to ensure the success of web application development projects. + +Help Symfony by [sponsoring][3] its development! + Resources --------- @@ -11,3 +22,7 @@ Resources * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) + +[1]: https://symfony.com/backers +[2]: https://sensiolabs.com +[3]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/Security/Core/README.md b/src/Symfony/Component/Security/Core/README.md index 6b3e5c990107c..b47ab331c82b3 100644 --- a/src/Symfony/Component/Security/Core/README.md +++ b/src/Symfony/Component/Security/Core/README.md @@ -6,6 +6,17 @@ which makes it possible to easily separate the actual authorization logic from so called user providers that hold the users credentials. It is inspired by the Java Spring framework. +Sponsor +------- + +The Security component for Symfony 5.4/6.0 is [backed][1] by [SymfonyCasts][2]. + +Learn Symfony faster by watching real projects being built and actively coding +along with them. SymfonyCasts bridges that learning gap, bringing you video +tutorials and coding challenges. Code on! + +Help Symfony by [sponsoring][3] its development! + Resources --------- @@ -14,3 +25,7 @@ Resources * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) + +[1]: https://symfony.com/backers +[2]: https://symfonycasts.com +[3]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php index 03cc6d17e89ed..056123f644baa 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php @@ -94,66 +94,6 @@ public function testSetUser($user) } } -class TestUser -{ - protected $name; - - public function __construct($name) - { - $this->name = $name; - } - - public function __toString(): string - { - return $this->name; - } -} - -class SerializableUser implements UserInterface -{ - private $roles; - private $name; - - public function __construct($name, array $roles = []) - { - $this->name = $name; - $this->roles = $roles; - } - - public function getUsername(): string - { - return $this->name; - } - - public function getUserIdentifier(): string - { - return $this->name; - } - - public function getPassword(): ?string - { - return '***'; - } - - public function getRoles(): array - { - if (empty($this->roles)) { - return ['ROLE_USER']; - } - - return $this->roles; - } - - public function eraseCredentials() - { - } - - public function getSalt(): ?string - { - return null; - } -} - class ConcreteToken extends AbstractToken { private $credentials = 'credentials_value'; diff --git a/src/Symfony/Component/Security/Core/Tests/SecurityTest.php b/src/Symfony/Component/Security/Core/Tests/SecurityTest.php index 53dd23b20b175..064998f97293e 100644 --- a/src/Symfony/Component/Security/Core/Tests/SecurityTest.php +++ b/src/Symfony/Component/Security/Core/Tests/SecurityTest.php @@ -93,11 +93,3 @@ private function createContainer($serviceId, $serviceObject) return $container; } } - -class StringishUser -{ - public function __toString(): string - { - return 'stringish_user'; - } -} diff --git a/src/Symfony/Component/Security/Core/composer.json b/src/Symfony/Component/Security/Core/composer.json index de0dbd21568b2..20c5074d6eb90 100644 --- a/src/Symfony/Component/Security/Core/composer.json +++ b/src/Symfony/Component/Security/Core/composer.json @@ -17,8 +17,8 @@ ], "require": { "php": ">=8.0.2", - "symfony/event-dispatcher-contracts": "^1.1|^2.0|^3.0", - "symfony/service-contracts": "^1.1.6|^2.0|^3.0", + "symfony/event-dispatcher-contracts": "^1.1|^2|^3", + "symfony/service-contracts": "^1.1.6|^2|^3", "symfony/password-hasher": "^5.4|^6.0" }, "require-dev": { diff --git a/src/Symfony/Component/Security/Csrf/README.md b/src/Symfony/Component/Security/Csrf/README.md index 8933061585ff9..a27d877284343 100644 --- a/src/Symfony/Component/Security/Csrf/README.md +++ b/src/Symfony/Component/Security/Csrf/README.md @@ -4,6 +4,17 @@ Security Component - CSRF The Security CSRF (cross-site request forgery) component provides a class `CsrfTokenManager` for generating and validating CSRF tokens. +Sponsor +------- + +The Security component for Symfony 5.4/6.0 is [backed][1] by [SymfonyCasts][2]. + +Learn Symfony faster by watching real projects being built and actively coding +along with them. SymfonyCasts bridges that learning gap, bringing you video +tutorials and coding challenges. Code on! + +Help Symfony by [sponsoring][3] its development! + Resources --------- @@ -12,3 +23,7 @@ Resources * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) + +[1]: https://symfony.com/backers +[2]: https://symfonycasts.com +[3]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/Security/Http/README.md b/src/Symfony/Component/Security/Http/README.md index e12d19fbeb697..594f5adb3aece 100644 --- a/src/Symfony/Component/Security/Http/README.md +++ b/src/Symfony/Component/Security/Http/README.md @@ -6,6 +6,17 @@ which makes it possible to easily separate the actual authorization logic from so called user providers that hold the users credentials. It is inspired by the Java Spring framework. +Sponsor +------- + +The Security component for Symfony 5.4/6.0 is [backed][1] by [SymfonyCasts][2]. + +Learn Symfony faster by watching real projects being built and actively coding +along with them. SymfonyCasts bridges that learning gap, bringing you video +tutorials and coding challenges. Code on! + +Help Symfony by [sponsoring][3] its development! + Resources --------- @@ -14,3 +25,7 @@ Resources * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) + +[1]: https://symfony.com/backers +[2]: https://symfonycasts.com +[3]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/Security/Http/Tests/Authenticator/AbstractAuthenticatorTest.php b/src/Symfony/Component/Security/Http/Tests/Authenticator/AbstractAuthenticatorTest.php index 202a7ee2a9f9c..9562589581b5e 100644 --- a/src/Symfony/Component/Security/Http/Tests/Authenticator/AbstractAuthenticatorTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Authenticator/AbstractAuthenticatorTest.php @@ -43,11 +43,6 @@ public function createToken(Passport $passport, string $firewallName): TokenInte return parent::createToken($passport, $firewallName); } - public function createAuthenticatedToken(PassportInterface $passport, string $firewallName): TokenInterface - { - return parent::createAuthenticatedToken($passport, $firewallName); - } - public function supports(Request $request): ?bool { return null; diff --git a/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php b/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php index 4b45a1ffc91cc..cee61fa03a680 100644 --- a/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php +++ b/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php @@ -36,7 +36,8 @@ class CsvEncoder implements EncoderInterface, DecoderInterface private const UTF8_BOM = "\xEF\xBB\xBF"; - private $formulasStartCharacters = ['=', '-', '+', '@']; + private const FORMULAS_START_CHARACTERS = ['=', '-', '+', '@', "\t", "\r"]; + private $defaultContext = [ self::DELIMITER_KEY => ',', self::ENCLOSURE_KEY => '"', @@ -223,8 +224,8 @@ private function flatten(iterable $array, array &$result, string $keySeparator, if (is_iterable($value)) { $this->flatten($value, $result, $keySeparator, $parentKey.$key.$keySeparator, $escapeFormulas); } else { - if ($escapeFormulas && \in_array(substr((string) $value, 0, 1), $this->formulasStartCharacters, true)) { - $result[$parentKey.$key] = "\t".$value; + if ($escapeFormulas && \in_array(substr((string) $value, 0, 1), self::FORMULAS_START_CHARACTERS, true)) { + $result[$parentKey.$key] = "'".$value; } else { // Ensures an actual value is used when dealing with true and false $result[$parentKey.$key] = false === $value ? 0 : (true === $value ? 1 : $value); diff --git a/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php index 8656a400027b3..87589ee89e64a 100644 --- a/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php @@ -114,7 +114,7 @@ protected function extractAttributes(object $object, string $format = null, arra } } while ($reflectionObject = $reflectionObject->getParentClass()); - return $attributes; + return array_unique($attributes); } /** diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php index c66366a985efa..8752acffc8be8 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php @@ -251,31 +251,52 @@ public function testEncodeFormulas() $this->assertSame(<<<'CSV' 0 -" =2+3" +'=2+3 CSV , $this->encoder->encode(['=2+3'], 'csv')); $this->assertSame(<<<'CSV' 0 -" -2+3" +'-2+3 CSV , $this->encoder->encode(['-2+3'], 'csv')); $this->assertSame(<<<'CSV' 0 -" +2+3" +'+2+3 CSV , $this->encoder->encode(['+2+3'], 'csv')); $this->assertSame(<<<'CSV' 0 -" @MyDataColumn" +'@MyDataColumn CSV , $this->encoder->encode(['@MyDataColumn'], 'csv')); + + $this->assertSame(<<<'CSV' +0 +"' tab" + +CSV + , $this->encoder->encode(["\ttab"], 'csv')); + + $this->assertSame(<<<'CSV' +0 +"'=1+2"";=1+2" + +CSV + , $this->encoder->encode(['=1+2";=1+2'], 'csv')); + + $this->assertSame(<<<'CSV' +0 +"'=1+2'"" ;,=1+2" + +CSV + , $this->encoder->encode(['=1+2\'" ;,=1+2'], 'csv')); } public function testDoNotEncodeFormulas() @@ -307,13 +328,34 @@ public function testDoNotEncodeFormulas() CSV , $this->encoder->encode(['@MyDataColumn'], 'csv')); + + $this->assertSame(<<<'CSV' +0 +" tab" + +CSV + , $this->encoder->encode(["\ttab"], 'csv')); + + $this->assertSame(<<<'CSV' +0 +"=1+2"";=1+2" + +CSV + , $this->encoder->encode(['=1+2";=1+2'], 'csv')); + + $this->assertSame(<<<'CSV' +0 +"=1+2'"" ;,=1+2" + +CSV + , $this->encoder->encode(['=1+2\'" ;,=1+2'], 'csv')); } public function testEncodeFormulasWithSettingsPassedInContext() { $this->assertSame(<<<'CSV' 0 -" =2+3" +'=2+3 CSV , $this->encoder->encode(['=2+3'], 'csv', [ @@ -322,7 +364,7 @@ public function testEncodeFormulasWithSettingsPassedInContext() $this->assertSame(<<<'CSV' 0 -" -2+3" +'-2+3 CSV , $this->encoder->encode(['-2+3'], 'csv', [ @@ -331,7 +373,7 @@ public function testEncodeFormulasWithSettingsPassedInContext() $this->assertSame(<<<'CSV' 0 -" +2+3" +'+2+3 CSV , $this->encoder->encode(['+2+3'], 'csv', [ @@ -340,12 +382,39 @@ public function testEncodeFormulasWithSettingsPassedInContext() $this->assertSame(<<<'CSV' 0 -" @MyDataColumn" +'@MyDataColumn CSV , $this->encoder->encode(['@MyDataColumn'], 'csv', [ CsvEncoder::ESCAPE_FORMULAS_KEY => true, ])); + + $this->assertSame(<<<'CSV' +0 +"' tab" + +CSV + , $this->encoder->encode(["\ttab"], 'csv', [ + CsvEncoder::ESCAPE_FORMULAS_KEY => true, + ])); + + $this->assertSame(<<<'CSV' +0 +"'=1+2"";=1+2" + +CSV + , $this->encoder->encode(['=1+2";=1+2'], 'csv', [ + CsvEncoder::ESCAPE_FORMULAS_KEY => true, + ])); + + $this->assertSame(<<<'CSV' +0 +"'=1+2'"" ;,=1+2" + +CSV + , $this->encoder->encode(['=1+2\'" ;,=1+2'], 'csv', [ + CsvEncoder::ESCAPE_FORMULAS_KEY => true, + ])); } public function testEncodeWithoutHeader() diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index cdfa3c9780d61..d62581cd8e6d1 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -1147,38 +1147,6 @@ public function getIterator(): \ArrayIterator } } -class BazLegacy -{ - public $list; - - public $settings = []; - - public function __construct(array $list) - { - $this->list = new DummyListLegacy($list); - } -} - -class DummyListLegacy implements \Countable, \IteratorAggregate -{ - public $list; - - public function __construct(array $list) - { - $this->list = $list; - } - - public function count(): int - { - return \count($this->list); - } - - public function getIterator(): \Traversable - { - return new \ArrayIterator($this->list); - } -} - interface NormalizerAwareNormalizer extends NormalizerInterface, NormalizerAwareInterface { } diff --git a/src/Symfony/Component/Stopwatch/composer.json b/src/Symfony/Component/Stopwatch/composer.json index 4edea5a4ff414..bb68c24de3f0b 100644 --- a/src/Symfony/Component/Stopwatch/composer.json +++ b/src/Symfony/Component/Stopwatch/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=8.0.2", - "symfony/service-contracts": "^1.0|^2.0|^3.0" + "symfony/service-contracts": "^1|^2|^3" }, "autoload": { "psr-4": { "Symfony\\Component\\Stopwatch\\": "" }, diff --git a/src/Symfony/Component/Translation/Bridge/Crowdin/README.md b/src/Symfony/Component/Translation/Bridge/Crowdin/README.md index 7caef72eee8d9..a1b8a1a6cc46c 100644 --- a/src/Symfony/Component/Translation/Bridge/Crowdin/README.md +++ b/src/Symfony/Component/Translation/Bridge/Crowdin/README.md @@ -20,6 +20,15 @@ where: [Generate Personal Access Token on Crowdin Enterprise](https://support.crowdin.com/enterprise/personal-access-tokens/) +Sponsor +------- + +This bridge for Symfony 5.4/6.0 is [backed][1] by [Crowdin][2]. + +Crowdin is a cloud-based localization management software helping teams to go global and stay agile. + +Help Symfony by [sponsoring][3] its development! + Resources --------- @@ -27,3 +36,7 @@ Resources * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) + +[1]: https://symfony.com/backers +[2]: https://crowdin.com +[3]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/Translation/Bridge/Lokalise/README.md b/src/Symfony/Component/Translation/Bridge/Lokalise/README.md index 64e6cd0de7800..e91ac094f3cab 100644 --- a/src/Symfony/Component/Translation/Bridge/Lokalise/README.md +++ b/src/Symfony/Component/Translation/Bridge/Lokalise/README.md @@ -19,6 +19,16 @@ Go to the Project Settings in Lokalise to find the Project ID. [Generate an API key on Lokalise](https://app.lokalise.com/api2docs/curl/#resource-authentication) +Sponsor +------- + +This bridge for Symfony 5.4/6.0 is [backed][1] by [Lokalise][2]. + +Lokalise is a continuous localization and translation management platform. It integrates +into your development workflow so you can ship localized products, faster. + +Help Symfony by [sponsoring][3] its development! + Resources --------- @@ -26,3 +36,7 @@ Resources * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) + +[1]: https://symfony.com/backers +[2]: https://lokalise.com +[3]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/Translation/README.md b/src/Symfony/Component/Translation/README.md index 720bee3b81086..adda9a5b21e55 100644 --- a/src/Symfony/Component/Translation/README.md +++ b/src/Symfony/Component/Translation/README.md @@ -23,6 +23,16 @@ $translator->addResource('array', [ echo $translator->trans('Hello World!'); // outputs « Bonjour ! » ``` +Sponsor +------- + +The Translation component for Symfony 5.4/6.0 is [backed][1] by: + + * [Crowdin][2], a cloud-based localization management software helping teams to go global and stay agile. + * [Lokalise][3], a continuous localization and translation management platform that integrates into your development workflow so you can ship localized products, faster. + +Help Symfony by [sponsoring][4] its development! + Resources --------- @@ -31,3 +41,8 @@ Resources * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) in the [main Symfony repository](https://github.com/symfony/symfony) + +[1]: https://symfony.com/backers +[2]: https://crowdin.com +[3]: https://lokalise.com +[4]: https://symfony.com/sponsor diff --git a/src/Symfony/Component/Translation/composer.json b/src/Symfony/Component/Translation/composer.json index eafe5c1766bf9..abe8b972c13d4 100644 --- a/src/Symfony/Component/Translation/composer.json +++ b/src/Symfony/Component/Translation/composer.json @@ -28,7 +28,7 @@ "symfony/http-kernel": "^5.4|^6.0", "symfony/intl": "^5.4|^6.0", "symfony/polyfill-intl-icu": "^1.21", - "symfony/service-contracts": "^1.1.2|^2.0|^3.0", + "symfony/service-contracts": "^1.1.2|^2|^3", "symfony/yaml": "^5.4|^6.0", "symfony/finder": "^5.4|^6.0", "psr/log": "^1|^2|^3" diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf index b341436bc5e18..75410192190ef 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf @@ -394,6 +394,14 @@ This value is not a valid CSS color. Tato hodnota není platná barva CSS. + + This value is not a valid CIDR notation. + Tato hodnota není platná notace CIDR. + + + The value of the netmask should be between {{ min }} and {{ max }}. + Hodnota masky sítě musí být mezi {{ min }} a {{ max }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf index 6b1d061b81ed3..090add6bd3413 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf @@ -394,6 +394,14 @@ This value is not a valid CSS color. Este valor não é uma cor de CSS válida. + + This value is not a valid CIDR notation. + Este valor não é uma notação CIDR válida. + + + The value of the netmask should be between {{ min }} and {{ max }}. + O valor da máscara de rede deve estar entre {{ min }} e {{ max }}. + diff --git a/src/Symfony/Component/Validator/composer.json b/src/Symfony/Component/Validator/composer.json index d6da361ec3203..52fd7aababd2b 100644 --- a/src/Symfony/Component/Validator/composer.json +++ b/src/Symfony/Component/Validator/composer.json @@ -19,7 +19,7 @@ "php": ">=8.0.2", "symfony/polyfill-ctype": "~1.8", "symfony/polyfill-mbstring": "~1.0", - "symfony/translation-contracts": "^1.1|^2.0|^3.0" + "symfony/translation-contracts": "^1.1|^2|^3" }, "require-dev": { "symfony/console": "^5.4|^6.0", diff --git a/src/Symfony/Component/VarExporter/Internal/Exporter.php b/src/Symfony/Component/VarExporter/Internal/Exporter.php index 8fa4322bc7244..73a56105984c5 100644 --- a/src/Symfony/Component/VarExporter/Internal/Exporter.php +++ b/src/Symfony/Component/VarExporter/Internal/Exporter.php @@ -88,13 +88,12 @@ public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount $properties = []; $sleep = null; - $arrayValue = (array) $value; $proto = Registry::$prototypes[$class]; if (($value instanceof \ArrayIterator || $value instanceof \ArrayObject) && null !== $proto) { // ArrayIterator and ArrayObject need special care because their "flags" // option changes the behavior of the (array) casting operator. - $properties = self::getArrayObjectProperties($value, $arrayValue, $proto); + [$arrayValue, $properties] = self::getArrayObjectProperties($value, $proto); // populates Registry::$prototypes[$class] with a new instance Registry::getClassReflector($class, Registry::$instantiableWithoutConstructor[$class], Registry::$cloneable[$class]); @@ -106,25 +105,23 @@ public static function prepare($values, $objectsPool, &$refsPool, &$objectsCount $properties[] = $value[$v]; } $properties = ['SplObjectStorage' => ["\0" => $properties]]; + $arrayValue = (array) $value; } elseif ($value instanceof \Serializable || $value instanceof \__PHP_Incomplete_Class) { ++$objectsCount; $objectsPool[$value] = [$id = \count($objectsPool), serialize($value), [], 0]; $value = new Reference($id); goto handle_value; - } - - if (method_exists($class, '__sleep')) { - if (!\is_array($sleep = $value->__sleep())) { - trigger_error('serialize(): __sleep should return an array only containing the names of instance-variables to serialize', \E_USER_NOTICE); - $value = null; - goto handle_value; - } - foreach ($sleep as $name) { - if (property_exists($value, $name) && !$reflector->hasProperty($name)) { - $arrayValue[$name] = $value->$name; + } else { + if (method_exists($class, '__sleep')) { + if (!\is_array($sleep = $value->__sleep())) { + trigger_error('serialize(): __sleep should return an array only containing the names of instance-variables to serialize', \E_USER_NOTICE); + $value = null; + goto handle_value; } + $sleep = array_flip($sleep); } - $sleep = array_flip($sleep); + + $arrayValue = (array) $value; } $proto = (array) $proto; @@ -368,13 +365,13 @@ private static function exportHydrator(Hydrator $value, string $indent, string $ * @param \ArrayIterator|\ArrayObject $value * @param \ArrayIterator|\ArrayObject $proto */ - private static function getArrayObjectProperties($value, array &$arrayValue, $proto): array + private static function getArrayObjectProperties($value, $proto): array { $reflector = $value instanceof \ArrayIterator ? 'ArrayIterator' : 'ArrayObject'; $reflector = Registry::$reflectors[$reflector] ?? Registry::getClassReflector($reflector); $properties = [ - $arrayValue, + $arrayValue = (array) $value, $reflector->getMethod('getFlags')->invoke($value), $value instanceof \ArrayObject ? $reflector->getMethod('getIteratorClass')->invoke($value) : 'ArrayIterator', ]; @@ -400,6 +397,6 @@ private static function getArrayObjectProperties($value, array &$arrayValue, $pr $properties = [$reflector->class => ["\0" => $properties]]; } - return $properties; + return [$arrayValue, $properties]; } } diff --git a/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php b/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php index 0795700f6211a..3ded211f1c9df 100644 --- a/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php +++ b/src/Symfony/Component/VarExporter/Tests/VarExporterTest.php @@ -69,13 +69,10 @@ public function provideFailingSerialization() yield [$a]; - // This test segfaults on the final PHP 7.2 release - if (\PHP_VERSION_ID !== 70234) { - $a = [null, $h]; - $a[0] = &$a; + $a = [null, $h]; + $a[0] = &$a; - yield [$a]; - } + yield [$a]; } /** @@ -181,13 +178,10 @@ public function provideExport() yield ['hard-references', $value]; - // This test segfaults on the final PHP 7.2 release - if (\PHP_VERSION_ID !== 70234) { - $value = []; - $value[0] = &$value; + $value = []; + $value[0] = &$value; - yield ['hard-references-recursive', $value]; - } + yield ['hard-references-recursive', $value]; static $value = [123]; @@ -326,6 +320,13 @@ public function setFlags($flags): void class GoodNight { + public $good; + + public function __construct() + { + unset($this->good); + } + public function __sleep(): array { $this->good = 'night'; diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index b142aeb6ad670..671c133ec309c 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -247,10 +247,11 @@ private static function dumpNull(int $flags): string * * @throws ParseException When malformed inline YAML string is parsed */ - public static function parseScalar(string $scalar, int $flags = 0, array $delimiters = null, int &$i = 0, bool $evaluate = true, array &$references = []): mixed + public static function parseScalar(string $scalar, int $flags = 0, array $delimiters = null, int &$i = 0, bool $evaluate = true, array &$references = [], bool &$isQuoted = null): mixed { if (\in_array($scalar[$i], ['"', "'"], true)) { // quoted scalar + $isQuoted = true; $output = self::parseQuotedScalar($scalar, $i); if (null !== $delimiters) { @@ -264,6 +265,8 @@ public static function parseScalar(string $scalar, int $flags = 0, array $delimi } } else { // "normal" string + $isQuoted = false; + if (!$delimiters) { $output = substr($scalar, $i); $i += \strlen($output); @@ -286,7 +289,7 @@ public static function parseScalar(string $scalar, int $flags = 0, array $delimi } if ($evaluate) { - $output = self::evaluateScalar($output, $flags, $references); + $output = self::evaluateScalar($output, $flags, $references, $isQuoted); } } @@ -298,7 +301,7 @@ public static function parseScalar(string $scalar, int $flags = 0, array $delimi * * @throws ParseException When malformed inline YAML string is parsed */ - private static function parseQuotedScalar(string $scalar, int &$i): string + private static function parseQuotedScalar(string $scalar, int &$i = 0): string { if (!Parser::preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) { throw new ParseException(sprintf('Malformed inline YAML string: "%s".', substr($scalar, $i)), self::$parsedLineNumber + 1, $scalar, self::$parsedFilename); @@ -351,8 +354,7 @@ private static function parseSequence(string $sequence, int $flags, int &$i = 0, $value = self::parseMapping($sequence, $flags, $i, $references); break; default: - $isQuoted = \in_array($sequence[$i], ['"', "'"], true); - $value = self::parseScalar($sequence, $flags, [',', ']'], $i, null === $tag, $references); + $value = self::parseScalar($sequence, $flags, [',', ']'], $i, null === $tag, $references, $isQuoted); // the value can be an array if a reference has been resolved to an array var if (\is_string($value) && !$isQuoted && false !== strpos($value, ': ')) { @@ -497,8 +499,7 @@ private static function parseMapping(string $mapping, int $flags, int &$i = 0, a } break; default: - $isValueQuoted = \in_array($mapping[$i], ['"', "'"]); - $value = self::parseScalar($mapping, $flags, [',', '}', "\n"], $i, null === $tag, $references); + $value = self::parseScalar($mapping, $flags, [',', '}', "\n"], $i, null === $tag, $references, $isValueQuoted); // Spec: Keys MUST be unique; first one wins. // Parser cannot abort this mapping earlier, since lines // are processed sequentially. @@ -535,8 +536,9 @@ private static function parseMapping(string $mapping, int $flags, int &$i = 0, a * * @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved */ - private static function evaluateScalar(string $scalar, int $flags, array &$references = []): mixed + private static function evaluateScalar(string $scalar, int $flags, array &$references = [], bool &$isQuotedString = null): mixed { + $isQuotedString = false; $scalar = trim($scalar); if (0 === strpos($scalar, '*')) { @@ -572,7 +574,14 @@ private static function evaluateScalar(string $scalar, int $flags, array &$refer case '!' === $scalar[0]: switch (true) { case 0 === strpos($scalar, '!!str '): - return (string) substr($scalar, 6); + $s = (string) substr($scalar, 6); + + if (\in_array($s[0] ?? '', ['"', "'"], true)) { + $isQuotedString = true; + $s = self::parseQuotedScalar($s); + } + + return $s; case 0 === strpos($scalar, '! '): return substr($scalar, 2); case 0 === strpos($scalar, '!php/object'): diff --git a/src/Symfony/Component/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php index 9d672bdc9a36b..77fcee7cad830 100644 --- a/src/Symfony/Component/Yaml/Tests/InlineTest.php +++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php @@ -924,21 +924,31 @@ public function ideographicSpaceProvider(): array ]; } + public function testParseSingleQuotedTaggedString() + { + $this->assertSame('foo', Inline::parse("!!str 'foo'")); + } + + public function testParseDoubleQuotedTaggedString() + { + $this->assertSame('foo', Inline::parse('!!str "foo"')); + } + public function testParseQuotedReferenceLikeStringsInMapping() { $yaml = <<assertSame(['foo' => '&foo', 'bar' => '&bar'], Inline::parse($yaml)); + $this->assertSame(['foo' => '&foo', 'bar' => '&bar', 'baz' => '&baz'], Inline::parse($yaml)); } public function testParseQuotedReferenceLikeStringsInSequence() { $yaml = <<assertSame(['&foo', '&bar'], Inline::parse($yaml)); + $this->assertSame(['&foo', '&bar', '&baz'], Inline::parse($yaml)); } } diff --git a/src/Symfony/Contracts/CHANGELOG.md b/src/Symfony/Contracts/CHANGELOG.md index 275415078d4c0..5c9c3d08d4c9e 100644 --- a/src/Symfony/Contracts/CHANGELOG.md +++ b/src/Symfony/Contracts/CHANGELOG.md @@ -1,6 +1,18 @@ CHANGELOG ========= +3.0 +--- + + * Bump to PHP 8 minimum + * Add native return types + * Remove deprecated features + +2.5 +--- + + * Add `SubscribedService` attribute, deprecate current `ServiceSubscriberTrait` usage + 2.4 ---