diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index 27b51d5af7428..9524faefab71d 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -43,7 +43,7 @@ jobs: ([ -d "$COMPOSER_HOME" ] || mkdir "$COMPOSER_HOME") && cp .github/composer-config.json "$COMPOSER_HOME/config.json" export COMPOSER_ROOT_VERSION=$(grep ' VERSION = ' src/Symfony/Component/HttpKernel/Kernel.php | grep -P -o '[0-9]+\.[0-9]+').x-dev composer remove --dev --no-update --no-interaction symfony/phpunit-bridge - composer require --no-progress --ansi --no-plugins psalm/phar phpunit/phpunit:^9.5 php-http/discovery psr/event-dispatcher mongodb/mongodb jetbrains/phpstorm-stubs + composer require --no-progress --ansi --no-plugins psalm/phar:@stable phpunit/phpunit:^9.5 php-http/discovery psr/event-dispatcher mongodb/mongodb jetbrains/phpstorm-stubs - name: Generate Psalm baseline run: | diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml index 94b69e6c9891c..9b902532c1bdc 100644 --- a/.github/workflows/unit-tests.yml +++ b/.github/workflows/unit-tests.yml @@ -155,12 +155,13 @@ jobs: local ok=0 local title="$1$FLIP" local start=$(date -u +%s) - OUTPUT=$(bash -xc "$2" 2>&1) || ok=1 + OUTPUT=$(bash -xc "$2" 2>&1) || ok=$? local end=$(date -u +%s) if [[ $ok -ne 0 ]]; then printf "\n%-70s%10s\n" $title $(($end-$start))s echo "$OUTPUT" + echo "Job exited with: $ok" echo -e "\n::error::KO $title\\n" else printf "::group::%-68s%10s\n" $title $(($end-$start))s diff --git a/CHANGELOG-5.4.md b/CHANGELOG-5.4.md index 958891879ffaf..97a5f10254eef 100644 --- a/CHANGELOG-5.4.md +++ b/CHANGELOG-5.4.md @@ -7,6 +7,34 @@ in 5.4 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v5.4.0...v5.4.1 +* 5.4.34 (2023-12-30) + + * bug #52406 [Validator] Fix `Constraints\Email::ERROR_NAMES` (mathroc) + * bug #53140 [Serializer] Skip uninitialized properties with deep_object_to_populate (mtarld) + * bug #53195 [HttpKernel] Fix default locale is ignored when `set_locale_from_accept_language` is used (jkobus) + * bug #52928 [Dotenv] Allow environment variables starting with an underscore (xabbuh) + * bug #53232 [Notifier] [Smsc] Require login and password (OskarStark) + * bug #53187 [Messenger] Fix using negative delay (J-roen) + * bug #53133 [Validator] Fix using known option names as field names (HypeMC) + * bug #53153 [WebProfilerBundle] Fix JS error when evaluating scripts (jderusse) + * bug #52998 [Notifier] [Bridges] Provide EventDispatcher and HttpClient to the transport (rdavaillaud) + * bug #52817 [Serializer] Do not instantiate object if it is not instantiable (maxbaldanza) + * bug #53079 [DoctrineBridge] Add check for lazy object interface (maxbaldanza) + * bug #53115 [Serializer] Fix partial denormalization with missing constructor arguments (HypeMC) + * bug #53081 [Serializer] Keep stack trace for enum value denormalizer error (kylekatarnls) + * bug #53057 [HttpKernel] Move ``@internal`` from `AbstractSessionListener` class to its methods and properties (Florian-Merle) + * bug #52990 [TwigBridge] don't use deprecated and internal Twig functions (xabbuh) + * bug #52996 [Validator] add missing translation (xabbuh) + * bug #52940 [Console] Fix color support check on non-Windows platforms (theofidry) + * bug #52896 [Messenger] Avoid reconnecting active Redis connections. (BusterNeece) + * bug #52923 Avoid incompatibility with symfony/console 7 (jdecool) + * bug #52927 [Dotenv] Properly handle `SYMFONY_DOTENV_VARS` being the empty string (xabbuh) + * bug #52935 [Validator] Missing translations for Slovak (sk) #51954 (Jan Vernarsky) + * bug #52941 [Console] Fix xterm detection (theofidry) + * bug #52795 [FrameworkBundle]  do not overwrite an application's default serialization context (xabbuh) + * bug #52885 [Serializer] fix nullable int cannot be serialized (nikophil) + * bug #52864 [HttpClient][Mailer][Process] always pass microseconds to usleep as integers (xabbuh) + * 5.4.33 (2023-12-01) * bug #52804 [Serializer] Fix support of plain object types denormalization (andersonamuller) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index a3e1c4ac3a9af..ca870dd304464 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -17,14 +17,14 @@ The Symfony Connect username in parenthesis allows to get more information - Wouter de Jong (wouterj) - Jordi Boggiano (seldaek) - Maxime Steinhausser (ogizanagi) - - Kévin Dunglas (dunglas) - Alexandre Daubois (alexandre-daubois) + - Kévin Dunglas (dunglas) - Victor Berchet (victor) - Ryan Weaver (weaverryan) - Javier Eguiluz (javier.eguiluz) - Jérémy DERUSSÉ (jderusse) - - Roland Franssen - Jules Pietri (heah) + - Roland Franssen - Johannes S (johannes) - Kris Wallsmith (kriswallsmith) - Jakub Zalas (jakubzalas) @@ -40,9 +40,9 @@ The Symfony Connect username in parenthesis allows to get more information - Joseph Bielawski (stloyd) - Drak (drak) - Abdellatif Ait boudad (aitboudad) + - HypeMC (hypemc) - Lukas Kahwe Smith (lsmith) - Kevin Bond (kbond) - - HypeMC (hypemc) - Hamza Amrouche (simperfit) - Martin Hasoň (hason) - Jeremy Mikola (jmikola) @@ -67,14 +67,14 @@ The Symfony Connect username in parenthesis allows to get more information - Francis Besset (francisbesset) - Titouan Galopin (tgalopin) - Pierre du Plessis (pierredup) - - David Maicher (dmaicher) - Gábor Egyed (1ed) + - David Maicher (dmaicher) - Bulat Shakirzyanov (avalanche123) - Iltar van der Berg + - Vincent Langlet (deviling) - Miha Vrhovnik (mvrhov) - Gary PEGEOT (gary-p) - Saša Stamenković (umpirsky) - - Vincent Langlet (deviling) - Allison Guilhem (a_guilhem) - Mathieu Piot (mpiot) - Alexander Schranz (alexander-schranz) @@ -106,6 +106,7 @@ The Symfony Connect username in parenthesis allows to get more information - Alex Pott - Fran Moreno (franmomu) - Arnout Boks (aboks) + - Simon André (simonandre) - Charles Sarrazin (csarrazi) - Ruud Kamphuis (ruudk) - Henrik Westphal (snc) @@ -118,6 +119,7 @@ The Symfony Connect username in parenthesis allows to get more information - Luis Cordova (cordoval) - Antoine Makdessi (amakdessi) - Konstantin Myakshin (koc) + - Hubert Lenoir (hubert_lenoir) - Daniel Holmes (dholmes) - Julien Falque (julienfalque) - Tomas Norkūnas (norkunas) @@ -125,9 +127,8 @@ The Symfony Connect username in parenthesis allows to get more information - Bart van den Burg (burgov) - Vasilij Dusko | CREATION - Jordan Alliot (jalliot) - - Hubert Lenoir (hubert_lenoir) - - John Wards (johnwards) - Massimiliano Arione (garak) + - John Wards (johnwards) - Phil E. Taylor (philetaylor) - Antoine Hérault (herzult) - Konstantin.Myakshin @@ -139,11 +140,12 @@ The Symfony Connect username in parenthesis allows to get more information - gnito-org - Jeroen Spee (jeroens) - Tim Nagel (merk) + - Théo FIDRY - Chris Wilkinson (thewilkybarkid) - Jérôme Vasseur (jvasseur) - Peter Kokot (peterkokot) - Brice BERNARD (brikou) - - Simon André (simonandre) + - Tac Tacelosky (tacman1123) - Michal Piotrowski - marc.weistroff - Rokas Mikalkėnas (rokasm) @@ -151,15 +153,13 @@ The Symfony Connect username in parenthesis allows to get more information - lenar - Vladimir Tsykun (vtsykun) - Jacob Dreesen (jdreesen) - - Tac Tacelosky (tacman1123) - Włodzimierz Gajda (gajdaw) + - Martin Auswöger - Adrien Brault (adrienbrault) - - Théo FIDRY - Florian Voutzinos (florianv) - Teoh Han Hui (teohhanhui) - Przemysław Bogusz (przemyslaw-bogusz) - Colin Frei - - Martin Auswöger - Javier Spagnoletti (phansys) - excelwebzone - Paráda József (paradajozsef) @@ -187,6 +187,7 @@ The Symfony Connect username in parenthesis allows to get more information - Gregor Harlan (gharlan) - Michael Babker (mbabker) - Anthony MARTIN + - Nicolas Philippe (nikophil) - Sebastian Hörl (blogsh) - Tigran Azatyan (tigranazatyan) - Christopher Hertel (chertel) @@ -197,6 +198,7 @@ The Symfony Connect username in parenthesis allows to get more information - Arnaud Kleinpeter (nanocom) - Guilherme Blanco (guilhermeblanco) - Saif Eddin Gmati (azjezz) + - Farhad Safarov (safarov) - Alexis Lefebvre - SpacePossum - Richard van Laak (rvanlaak) @@ -204,9 +206,9 @@ The Symfony Connect username in parenthesis allows to get more information - Maximilian Beckers (maxbeckers) - Andreas Braun - Hugo Alliaume (kocal) - - Nicolas Philippe (nikophil) - Pablo Godel (pgodel) - Alessandro Chitolina (alekitto) + - Tomasz Kowalczyk (thunderer) - Rafael Dohms (rdohms) - jwdeitch - Jérôme Parmentier (lctrs) @@ -223,6 +225,7 @@ The Symfony Connect username in parenthesis allows to get more information - Vyacheslav Pavlov - Albert Casademont (acasademont) - George Mponos (gmponos) + - Roman Martinuk (a2a4) - Richard Shank (iampersistent) - David Prévot (taffit) - Romain Monteil (ker0x) @@ -245,8 +248,8 @@ The Symfony Connect username in parenthesis allows to get more information - Matthieu Ouellette-Vachon (maoueh) - Michał Pipa (michal.pipa) - Dawid Nowak + - Dāvis Zālītis (k0d3r1s) - Jannik Zschiesche - - Roman Martinuk (a2a4) - Amal Raghav (kertz) - Jonathan Ingram - Artur Kotyrba @@ -267,7 +270,6 @@ The Symfony Connect username in parenthesis allows to get more information - Mikael Pajunen - Warnar Boekkooi (boekkooi) - Justin Hileman (bobthecow) - - Tomasz Kowalczyk (thunderer) - Anthony GRASSIOT (antograssiot) - Dmitrii Chekaliuk (lazyhammer) - Clément JOBEILI (dator) @@ -277,7 +279,6 @@ The Symfony Connect username in parenthesis allows to get more information - Arnaud PETITPAS (apetitpa) - Michael Käfer (michael_kaefer) - Dorian Villet (gnutix) - - Dāvis Zālītis (k0d3r1s) - Martin Hujer (martinhujer) - Sergey Linnik (linniksa) - Richard Miller @@ -289,10 +290,11 @@ The Symfony Connect username in parenthesis allows to get more information - Chi-teck - Andre Rømcke (andrerom) - Baptiste Leduc (korbeil) + - Timo Bakx (timobakx) - soyuka - - Farhad Safarov (safarov) - Ruben Gonzalez (rubenrua) - Benjamin Dulau (dbenjamin) + - Daniel Burger - Markus Fasselt (digilist) - Denis Brumann (dbrumann) - mcfedr (mcfedr) @@ -320,7 +322,6 @@ The Symfony Connect username in parenthesis allows to get more information - Dominique Bongiraud - Hugo Monteiro (monteiro) - Bram Leeda (bram123) - - Timo Bakx (timobakx) - Dmitrii Poddubnyi (karser) - Julien Pauli - Michael Lee (zerustech) @@ -343,7 +344,6 @@ The Symfony Connect username in parenthesis allows to get more information - Marcin Sikoń (marphi) - Michele Orselli (orso) - Sven Paulus (subsven) - - Daniel Burger - Maxime Veber (nek-) - Bastien Jaillot (bastnic) - Valentine Boineau (valentineboineau) @@ -372,9 +372,11 @@ The Symfony Connect username in parenthesis allows to get more information - Daniel Tschinder - Christian Schmidt - Alexander Kotynia (olden) + - Yassine Guedidi (yguedidi) - Elnur Abdurrakhimov (elnur) - Manuel Reinhard (sprain) - BoShurik + - Quentin Devos - Adam Prager (padam87) - Benoît Burnichon (bburnichon) - maxime.steinhausser @@ -411,13 +413,17 @@ The Symfony Connect username in parenthesis allows to get more information - Philipp Cordes (corphi) - Chekote - Thomas Adam + - Evert Harmeling (evertharmeling) - jdhoek - Jurica Vlahoviček (vjurica) - Bob den Otter (bopp) - Thomas Schulz (king2500) + - Kyle + - Marko Kaznovac (kaznovac) - Dariusz Rumiński - Philippe SEGATORI (tigitz) - Frank de Jonge + - Andrii Bodnar - Dane Powell - Renan (renanbr) - Sebastien Morel (plopix) @@ -445,7 +451,6 @@ The Symfony Connect username in parenthesis allows to get more information - Marcos Sánchez - Emanuele Panzeri (thepanz) - Zmey - - Quentin Devos - Kim Hemsø Rasmussen (kimhemsoe) - Maximilian Reichel (phramz) - Samaël Villette (samadu61) @@ -457,7 +462,6 @@ The Symfony Connect username in parenthesis allows to get more information - Indra Gunawan (indragunawan) - Michael Holm (hollo) - Arjen van der Meijden - - Yassine Guedidi (yguedidi) - Blanchon Vincent (blanchonvincent) - Michał (bambucha15) - Christian Schmidt @@ -483,6 +487,7 @@ The Symfony Connect username in parenthesis allows to get more information - Quynh Xuan Nguyen (seriquynh) - Gabor Toth (tgabi333) - realmfoo + - Fabien S (bafs) - Simon Podlipsky (simpod) - Thomas Tourlourat (armetiz) - Andrey Esaulov (andremaha) @@ -494,8 +499,8 @@ The Symfony Connect username in parenthesis allows to get more information - Aurelijus Valeiša (aurelijus) - Jan Decavele (jandc) - Gustavo Piltcher - - Evert Harmeling (evertharmeling) - Lee Rowlands + - Anderson Müller - Stepan Tanasiychuk (stfalcon) - Ivan Kurnosov - Tiago Ribeiro (fixe) @@ -504,17 +509,15 @@ The Symfony Connect username in parenthesis allows to get more information - Pavel Batanov (scaytrase) - Francesc Rosàs (frosas) - Bongiraud Dominique - - Kyle - janschoenherr - Emanuele Gaspari (inmarelibero) - - Marko Kaznovac (kaznovac) - - Andrii Bodnar - Artem (artemgenvald) - Thierry T (lepiaf) - Lorenz Schori - Lukáš Holeczy (holicz) - Jeremy Livingston (jeremylivingston) - ivan + - SUMIDA, Ippei (ippey_s) - Urinbayev Shakhobiddin (shokhaa) - Ahmed Raafat - Philippe Segatori @@ -585,7 +588,6 @@ The Symfony Connect username in parenthesis allows to get more information - Greg Thornton (xdissent) - Alex Bowers - Michel Roca (mroca) - - Fabien S (bafs) - Costin Bereveanu (schniper) - Andrii Dembitskyi - Gasan Guseynov (gassan) @@ -629,7 +631,6 @@ The Symfony Connect username in parenthesis allows to get more information - Anthon Pang (robocoder) - Julien Galenski (ruian) - Ben Scott (bpscott) - - Anderson Müller - Pablo Lozano (arkadis) - Brian King - quentin neyrat (qneyrat) @@ -642,7 +643,6 @@ The Symfony Connect username in parenthesis allows to get more information - geoffrey - Benjamin (yzalis) - Jeanmonod David (jeanmonod) - - SUMIDA, Ippei (ippey_s) - Webnet team (webnet) - Tobias Bönner - Ben Ramsey (ramsey) @@ -652,6 +652,7 @@ The Symfony Connect username in parenthesis allows to get more information - Thomas Talbot (ioni) - Marcin Szepczynski (czepol) - Lescot Edouard (idetox) + - Dennis Fridrich (dfridrich) - Mohammad Emran Hasan (phpfour) - Dmitriy Mamontov (mamontovdmitriy) - Jan Schumann @@ -689,6 +690,7 @@ The Symfony Connect username in parenthesis allows to get more information - Restless-ET - Vlad Gregurco (vgregurco) - Artem Stepin (astepin) + - Priyadi Iman Nurcahyo (priyadi) - Boris Vujicic (boris.vujicic) - Dries Vints - Judicaël RUFFIEUX (axanagor) @@ -749,6 +751,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jérémy M (th3mouk) - Trent Steel (trsteel88) - boombatower + - javaDeveloperKid - Alireza Mirsepassi (alirezamirsepassi) - Jérôme Macias (jeromemacias) - Andrey Astakhov (aast) @@ -776,6 +779,7 @@ The Symfony Connect username in parenthesis allows to get more information - Eduardo Oliveira (entering) - Oleksii Zhurbytskyi - Bilge + - Asis Pattisahusiwa - Anatoly Pashin (b1rdex) - Jonathan Johnson (jrjohnson) - Eugene Wissner @@ -929,6 +933,7 @@ The Symfony Connect username in parenthesis allows to get more information - scyzoryck - Kyle Evans (kevans91) - Max Rath (drak3) + - Cristoforo Cervino (cristoforocervino) - marie - Stéphane Escandell (sescandell) - Fractal Zombie @@ -991,7 +996,6 @@ The Symfony Connect username in parenthesis allows to get more information - Martins Sipenko - Guilherme Augusto Henschel - Rostyslav Kinash - - Dennis Fridrich (dfridrich) - Mardari Dorel (dorumd) - Daisuke Ohata - Vincent Simonin @@ -1012,6 +1016,7 @@ The Symfony Connect username in parenthesis allows to get more information - David Molineus - Strate - Anton A. Sumin + - Marko Petrovic - alexandre.lassauge - Israel J. Carberry - Miquel Rodríguez Telep (mrtorrent) @@ -1043,7 +1048,6 @@ The Symfony Connect username in parenthesis allows to get more information - Robin Lehrmann - Szijarto Tamas - Thomas P - - Priyadi Iman Nurcahyo (priyadi) - Jaroslav Kuba - Benjamin Zikarsky (bzikarsky) - Kristijan Kanalaš (kristijan_kanalas_infostud) @@ -1120,6 +1124,7 @@ The Symfony Connect username in parenthesis allows to get more information - Roberto Nygaard - victor-prdh - Davide Borsatto (davide.borsatto) + - Florian Hermann (fhermann) - zenas1210 - Gert de Pagter - Julien DIDIER (juliendidier) @@ -1132,7 +1137,6 @@ The Symfony Connect username in parenthesis allows to get more information - Xesxen - Jeroen van den Enden (endroid) - Arun Philip - - Asis Pattisahusiwa - Pascal Helfenstein - Jesper Skytte (greew) - Petar Obradović @@ -1198,10 +1202,12 @@ The Symfony Connect username in parenthesis allows to get more information - Edvin Hultberg - shubhalgupta - Felds Liscia (felds) + - Jérémy DECOOL (jdecool) - Sergey Panteleev - Andrew Hilobok (hilobok) - Noah Heck (myesain) - Christian Soronellas (theunic) + - Max Baldanza - Volodymyr Panivko - kick-the-bucket - fedor.f @@ -1213,6 +1219,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jeroen Fiege (fieg) - Martin (meckhardt) - Marcel Hernandez + - Evan C - buffcode - Glodzienski - Krzysztof Łabuś (crozin) @@ -1228,7 +1235,6 @@ The Symfony Connect username in parenthesis allows to get more information - Mike Meier (mykon) - Pedro Miguel Maymone de Resende (pedroresende) - stlrnz - - javaDeveloperKid - Masterklavi - Adrien Wilmet (adrienfr) - Franco Traversaro (belinde) @@ -1366,6 +1372,7 @@ The Symfony Connect username in parenthesis allows to get more information - Sascha Dens (saschadens) - Simon Heimberg (simon_heimberg) - Morten Wulff (wulff) + - Kieran - Don Pinkster - Jonas Elfering - Maksim Muruev @@ -1426,6 +1433,7 @@ The Symfony Connect username in parenthesis allows to get more information - Sébastien Santoro (dereckson) - Daniel Alejandro Castro Arellano (lexcast) - Vincent Chalamon + - Alan ZARLI - Thomas Jarrand - Baptiste Leduc (bleduc) - soyuka @@ -1433,6 +1441,7 @@ The Symfony Connect username in parenthesis allows to get more information - Mickael Perraud - Anton Dyshkant - Ramunas Pabreza + - Rafael Villa Verde - Zoran Makrevski (zmakrevski) - Yann LUCAS (drixs6o9) - Kirill Nesmeyanov (serafim) @@ -1528,6 +1537,7 @@ The Symfony Connect username in parenthesis allows to get more information - LHommet Nicolas (nicolaslh) - fabios - Sander Coolen (scoolen) + - Vic D'Elfant (vicdelfant) - Amirreza Shafaat (amirrezashafaat) - Laurent Clouet - Adoni Pavlakis (adoni) @@ -1698,7 +1708,6 @@ The Symfony Connect username in parenthesis allows to get more information - Fabrice Locher - Kamil Szalewski (szal1k) - Andrey Lebedev (alebedev) - - Cristoforo Cervino (cristoforocervino) - Jean-Guilhem Rouel (jean-gui) - Yoann MOROCUTTI - Ivan Yivoff @@ -1830,6 +1839,7 @@ The Symfony Connect username in parenthesis allows to get more information - Gustavo Adrian - Jorrit Schippers (jorrit) - Matthias Neid + - Kev - Yannick - Kuzia - Vladimir Luchaninov (luchaninov) @@ -1966,9 +1976,9 @@ The Symfony Connect username in parenthesis allows to get more information - Mario Young - martkop26 - Evan Shaw + - Raphaël Davaillaud - Sander Hagen - cilefen (cilefen) - - Florian Hermann (fhermann) - Mo Di (modi) - Victor Truhanovich (victor_truhanovich) - Pablo Schläpfer @@ -2018,6 +2028,7 @@ The Symfony Connect username in parenthesis allows to get more information - Adiel Cristo (arcristo) - Christian Flach (cmfcmf) - Fabian Kropfhamer (fabiank) + - Jeffrey Cafferata (jcidnl) - Junaid Farooq (junaidfarooq) - Lars Ambrosius Wallenborn (larsborn) - Oriol Mangas Abellan (oriolman) @@ -2041,6 +2052,7 @@ The Symfony Connect username in parenthesis allows to get more information - Anton Kroshilin - Pierre Tachoire - Dawid Sajdak + - Maxime THIRY - Norman Soetbeer - Ludek Stepan - Mark van den Berg @@ -2089,13 +2101,13 @@ The Symfony Connect username in parenthesis allows to get more information - Berat Doğan - Christian Kolb - Guillaume LECERF + - Alan Scott - Juanmi Rodriguez Cerón - twifty - Andy Raines - François Poguet - Anthony Ferrara - Geoffrey Pécro (gpekz) - - Jérémy DECOOL (jdecool) - Klaas Cuvelier (kcuvelier) - Flavien Knuchel (knuch) - Mathieu TUDISCO (mathieutu) @@ -2128,6 +2140,7 @@ The Symfony Connect username in parenthesis allows to get more information - Ostrzyciel - George Giannoulopoulos - Alexander Pasichnik (alex_brizzz) + - Florian Merle (florian-merle) - Luis Ramirez (luisdeimos) - Ilia Sergunin (maranqz) - Daniel Richter (richtermeister) @@ -2143,6 +2156,7 @@ The Symfony Connect username in parenthesis allows to get more information - marbul - Filippos Karailanidis - Andreas Frömer + - Jeroen Bouwmans - Bikal Basnet - Philip Frank - David Brooks @@ -2210,7 +2224,7 @@ The Symfony Connect username in parenthesis allows to get more information - adhamiamirhossein - Maxim Semkin - Gonzalo Míguez - - Evan C + - Jan Vernarsky - BrokenSourceCode - Fabian Haase - roog @@ -2255,6 +2269,7 @@ The Symfony Connect username in parenthesis allows to get more information - Ivo Valchev - Thomas Hanke - Daniel Tschinder + - Thomas Durand - Arnaud CHASSEUX - Zlatoslav Desyatnikov - Wickex @@ -2325,6 +2340,7 @@ The Symfony Connect username in parenthesis allows to get more information - Charly Terrier (charlypoppins) - Dcp (decap94) - Emre Akinci (emre) + - Rachid Hammaoui (makmaoui) - Chris Maiden (matason) - psampaz (psampaz) - Andrea Ruggiero (pupax) @@ -2412,6 +2428,7 @@ The Symfony Connect username in parenthesis allows to get more information - Michael Simonson (mikes) - Nicolas Badey (nico-b) - Olivier Scherler (oscherler) + - Flo Gleixner (redflo) - Shane Preece (shane) - Stephan Wentz (temp) - Johannes Goslar @@ -2736,6 +2753,7 @@ The Symfony Connect username in parenthesis allows to get more information - helmer - ged15 - Simon Asika + - CDR - Daan van Renterghem - Bálint Szekeres - Boudry Julien @@ -2783,6 +2801,7 @@ The Symfony Connect username in parenthesis allows to get more information - Viet Pham - Alan Bondarchuk - Pchol + - Shamimul Alam - Cyril HERRERA - dropfen - Andrey Chernykh @@ -2829,6 +2848,7 @@ The Symfony Connect username in parenthesis allows to get more information - Trevor N. Suarez (rican7) - Sergii Dolgushev (serhey) - Clément Bertillon (skigun) + - Stiven Llupa (sllupa) - Rein Baarsma (solidwebcode) - tante kinast (tante) - Stephen Lewis (tehanomalousone) @@ -2887,6 +2907,7 @@ The Symfony Connect username in parenthesis allows to get more information - Ashura - Götz Gottwald - Alessandra Lai + - alangvazq - Christoph Krapp - Ernest Hymel - Andrea Civita @@ -2894,6 +2915,7 @@ The Symfony Connect username in parenthesis allows to get more information - LoginovIlya - andreyserdjuk - Nick Chiu + - Thanh Trần - Robert Campbell - Matt Lehner - carlos-ea @@ -2901,11 +2923,11 @@ The Symfony Connect username in parenthesis allows to get more information - Helmut Januschka - Jérémy Benoist - Hein Zaw Htet™ - - Kieran - Ruben Kruiswijk - Cosmin-Romeo TANASE - Ferran Vidal - Michael J + - sal-car - youssef saoubou - Joseph Maarek - Alexander Menk @@ -2914,8 +2936,10 @@ The Symfony Connect username in parenthesis allows to get more information - Jelle Kapitein - Jochen Mandl - elattariyassine + - Asrorbek Sultanov - Marin Nicolae - Gerrit Addiks + - Buster Neece - Albert Prat - Alessandro Loffredo - Ian Phillips @@ -2955,6 +2979,7 @@ The Symfony Connect username in parenthesis allows to get more information - Anton Zagorskii - ging-dev - Maerlyn + - Robert Gurau - Even André Fiskvik - Agata - dakur @@ -2963,6 +2988,7 @@ The Symfony Connect username in parenthesis allows to get more information - Vlad Dumitrache - Erik van Wingerden - Valouleloup + - Pathpat - robmro27 - Vallel Blanco - Alexis MARQUIS @@ -2983,21 +3009,25 @@ The Symfony Connect username in parenthesis allows to get more information - Sylvain METAYER - ddebree - Gyula Szucs + - Dmitriy - Tomas Liubinas - Ivo Valchev - Jan Hort - Klaas Naaijkens + - Bojan - Rafał - Adria Lopez (adlpz) - Adrien Peyre (adpeyre) - Aaron Scherer (aequasi) - Alexandre Jardin (alexandre.jardin) + - Amr Ezzat (amrezzat) - Bart Brouwer (bartbrouwer) - baron (bastien) - Bastien Clément (bastienclement) - Rosio (ben-rosio) - Simon Paarlberg (blamh) - Masao Maeda (brtriver) + - Valery Maslov (coderberg) - Damien Harper (damien.harper) - Darius Leskauskas (darles) - david perez (davidpv) @@ -3082,6 +3112,7 @@ The Symfony Connect username in parenthesis allows to get more information - Saem Ghani - Kévin - Stefan Oderbolz + - valmonzo - Tamás Szigeti - Gabriel Moreira - Alexey Popkov @@ -3224,6 +3255,7 @@ The Symfony Connect username in parenthesis allows to get more information - n-aleha - Talha Zekeriya Durmuş - Anatol Belski + - Javier - Alexis BOYER - Shyim - bch36 @@ -3269,6 +3301,7 @@ The Symfony Connect username in parenthesis allows to get more information - bokonet - Arrilot - andrey-tech + - David Ronchaud - Chris McGehee - Bastien THOMAS - Shaun Simmons @@ -3367,6 +3400,7 @@ The Symfony Connect username in parenthesis allows to get more information - phc - Дмитрий Пацура - Signor Pedro + - RFreij - Matthias Larisch - Maxime P - Sean Templeton @@ -3579,6 +3613,7 @@ The Symfony Connect username in parenthesis allows to get more information - Pierre Geyer (ptheg) - Thomas BERTRAND (sevrahk) - Vladislav (simpson) + - Stefanos Psarras (stefanos) - Matej Žilák (teo_sk) - Gary Houbre (thegarious) - Vladislav Vlastovskiy (vlastv) diff --git a/src/Symfony/Bridge/Doctrine/ManagerRegistry.php b/src/Symfony/Bridge/Doctrine/ManagerRegistry.php index c27a743512764..c3d48fc558518 100644 --- a/src/Symfony/Bridge/Doctrine/ManagerRegistry.php +++ b/src/Symfony/Bridge/Doctrine/ManagerRegistry.php @@ -16,6 +16,7 @@ use ProxyManager\Proxy\LazyLoadingInterface; use Symfony\Bridge\ProxyManager\LazyProxy\Instantiator\RuntimeInstantiator; use Symfony\Component\DependencyInjection\Container; +use Symfony\Component\VarExporter\LazyObjectInterface; /** * References Doctrine connections and entity/document managers. @@ -51,6 +52,13 @@ protected function resetService($name) } $manager = $this->container->get($name); + if ($manager instanceof LazyObjectInterface) { + if (!$manager->resetLazyObject()) { + throw new \LogicException(sprintf('Resetting a non-lazy manager service is not supported. Declare the "%s" service as lazy.', $name)); + } + + return; + } if (!$manager instanceof LazyLoadingInterface) { throw new \LogicException('Resetting a non-lazy manager service is not supported. '.(interface_exists(LazyLoadingInterface::class) && class_exists(RuntimeInstantiator::class) ? sprintf('Declare the "%s" service as lazy.', $name) : 'Try running "composer require symfony/proxy-manager-bridge".')); } diff --git a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php index 01d418ef23829..4c17a806b4281 100644 --- a/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php +++ b/src/Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/DeprecationTest.php @@ -265,7 +265,7 @@ private static function removeDir($dir) rmdir($dir); } - public static function setupBeforeClass(): void + public static function setUpBeforeClass(): void { foreach (get_declared_classes() as $class) { if ('C' === $class[0] && 0 === strpos($class, 'ComposerAutoloaderInit')) { diff --git a/src/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php b/src/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php index 9967639d16636..fa8653c238a1e 100644 --- a/src/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php +++ b/src/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Twig\Node; use Twig\Compiler; +use Twig\Extension\CoreExtension; use Twig\Node\Expression\ArrayExpression; use Twig\Node\Expression\ConstantExpression; use Twig\Node\Expression\FunctionExpression; @@ -50,7 +51,7 @@ public function compile(Compiler $compiler): void $labelIsExpression = false; // Only insert the label into the array if it is not empty - if (!twig_test_empty($label->getAttribute('value'))) { + if (null !== $label->getAttribute('value') && false !== $label->getAttribute('value') && '' !== (string) $label->getAttribute('value')) { $originalVariables = $variables; $variables = new ArrayExpression([], $lineno); $labelKey = new ConstantExpression('label', $lineno); @@ -97,7 +98,12 @@ public function compile(Compiler $compiler): void // Check at runtime whether the label is empty. // If not, add it to the array at runtime. - $compiler->raw('(twig_test_empty($_label_ = '); + if (method_exists(CoreExtension::class, 'testEmpty')) { + $compiler->raw('(CoreExtension::testEmpty($_label_ = '); + } else { + $compiler->raw('(twig_test_empty($_label_ = '); + } + $compiler->subcompile($label); $compiler->raw(') ? [] : ["label" => $_label_])'); } diff --git a/src/Symfony/Bridge/Twig/Tests/Node/SearchAndRenderBlockNodeTest.php b/src/Symfony/Bridge/Twig/Tests/Node/SearchAndRenderBlockNodeTest.php index 42cb1762b050d..b259990e0b7ad 100644 --- a/src/Symfony/Bridge/Twig/Tests/Node/SearchAndRenderBlockNodeTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Node/SearchAndRenderBlockNodeTest.php @@ -15,6 +15,7 @@ use Symfony\Bridge\Twig\Node\SearchAndRenderBlockNode; use Twig\Compiler; use Twig\Environment; +use Twig\Extension\CoreExtension; use Twig\Loader\LoaderInterface; use Twig\Node\Expression\ArrayExpression; use Twig\Node\Expression\ConditionalExpression; @@ -226,8 +227,9 @@ public function testCompileLabelWithLabelThatEvaluatesToNull() // https://github.com/symfony/symfony/issues/5029 $this->assertEquals( sprintf( - '$this->env->getRuntime(\'Symfony\Component\Form\FormRenderer\')->searchAndRenderBlock(%s, \'label\', (twig_test_empty($_label_ = ((true) ? (null) : (null))) ? [] : ["label" => $_label_]))', - $this->getVariableGetter('form') + '$this->env->getRuntime(\'Symfony\Component\Form\FormRenderer\')->searchAndRenderBlock(%s, \'label\', (%s($_label_ = ((true) ? (null) : (null))) ? [] : ["label" => $_label_]))', + $this->getVariableGetter('form'), + method_exists(CoreExtension::class, 'testEmpty') ? 'CoreExtension::testEmpty' : 'twig_test_empty' ), trim($compiler->compile($node)->getSource()) ); @@ -263,8 +265,9 @@ public function testCompileLabelWithLabelThatEvaluatesToNullAndAttributes() // https://github.com/symfony/symfony/issues/5029 $this->assertEquals( sprintf( - '$this->env->getRuntime(\'Symfony\Component\Form\FormRenderer\')->searchAndRenderBlock(%s, \'label\', ["foo" => "bar", "label" => "value in attributes"] + (twig_test_empty($_label_ = ((true) ? (null) : (null))) ? [] : ["label" => $_label_]))', - $this->getVariableGetter('form') + '$this->env->getRuntime(\'Symfony\Component\Form\FormRenderer\')->searchAndRenderBlock(%s, \'label\', ["foo" => "bar", "label" => "value in attributes"] + (%s($_label_ = ((true) ? (null) : (null))) ? [] : ["label" => $_label_]))', + $this->getVariableGetter('form'), + method_exists(CoreExtension::class, 'testEmpty') ? 'CoreExtension::testEmpty' : 'twig_test_empty' ), trim($compiler->compile($node)->getSource()) ); diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Application.php b/src/Symfony/Bundle/FrameworkBundle/Console/Application.php index 55510b9d594e4..7fe7bc937d315 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Application.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Application.php @@ -147,7 +147,7 @@ public function all(string $namespace = null) */ public function getLongVersion() { - return parent::getLongVersion().sprintf(' (env: %s, debug: %s) #StandWithUkraine https://sf.to/ukraine', $this->kernel->getEnvironment(), $this->kernel->isDebug() ? 'true' : 'false'); + return parent::getLongVersion().sprintf(' (env: %s, debug: %s)', $this->kernel->getEnvironment(), $this->kernel->isDebug() ? 'true' : 'false'); } public function add(Command $command) diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php index 85220f1b568fc..d4b9f4181642a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php @@ -145,7 +145,7 @@ protected function generateUrl(string $route, array $parameters = [], int $refer /** * Forwards the request to another controller. * - * @param string $controller The controller name (a string like Bundle\BlogBundle\Controller\PostController::indexAction) + * @param string $controller The controller name (a string like "App\Controller\PostController::index" or "App\Controller\PostController" if it is invokable) */ protected function forward(string $controller, array $path = [], array $query = []): Response { diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index da60eeabb41c9..7529acd605873 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1848,21 +1848,23 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder $container->getDefinition('serializer.name_converter.metadata_aware')->setArgument(1, new Reference($config['name_converter'])); } + $defaultContext = $config['default_context'] ?? []; + + if ($defaultContext) { + $container->setParameter('serializer.default_context', $defaultContext); + } + if (isset($config['circular_reference_handler']) && $config['circular_reference_handler']) { $arguments = $container->getDefinition('serializer.normalizer.object')->getArguments(); - $context = ($arguments[6] ?? []) + ['circular_reference_handler' => new Reference($config['circular_reference_handler'])]; + $context = ($arguments[6] ?? $defaultContext) + ['circular_reference_handler' => new Reference($config['circular_reference_handler'])]; $container->getDefinition('serializer.normalizer.object')->setArgument(5, null); $container->getDefinition('serializer.normalizer.object')->setArgument(6, $context); } if ($config['max_depth_handler'] ?? false) { - $defaultContext = $container->getDefinition('serializer.normalizer.object')->getArgument(6); - $defaultContext += ['max_depth_handler' => new Reference($config['max_depth_handler'])]; - $container->getDefinition('serializer.normalizer.object')->replaceArgument(6, $defaultContext); - } - - if (isset($config['default_context']) && $config['default_context']) { - $container->setParameter('serializer.default_context', $config['default_context']); + $arguments = $container->getDefinition('serializer.normalizer.object')->getArguments(); + $context = ($arguments[6] ?? $defaultContext) + ['max_depth_handler' => new Reference($config['max_depth_handler'])]; + $container->getDefinition('serializer.normalizer.object')->setArgument(6, $context); } } @@ -2592,7 +2594,9 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $ if (ContainerBuilder::willBeAvailable('symfony/mercure-notifier', MercureTransportFactory::class, $parentPackages, true) && ContainerBuilder::willBeAvailable('symfony/mercure-bundle', MercureBundle::class, $parentPackages, true) && \in_array(MercureBundle::class, $container->getParameter('kernel.bundles'), true)) { $container->getDefinition($classToServices[MercureTransportFactory::class]) - ->replaceArgument('$registry', new Reference(HubRegistry::class)); + ->replaceArgument('$registry', new Reference(HubRegistry::class)) + ->replaceArgument('$client', new Reference('http_client', ContainerBuilder::NULL_ON_INVALID_REFERENCE)) + ->replaceArgument('$dispatcher', new Reference('event_dispatcher', ContainerBuilder::NULL_ON_INVALID_REFERENCE)); } elseif (ContainerBuilder::willBeAvailable('symfony/mercure-notifier', MercureTransportFactory::class, $parentPackages, true)) { $container->removeDefinition($classToServices[MercureTransportFactory::class]); } @@ -2600,13 +2604,17 @@ private function registerNotifierConfiguration(array $config, ContainerBuilder $ if (ContainerBuilder::willBeAvailable('symfony/fake-chat-notifier', FakeChatTransportFactory::class, ['symfony/framework-bundle', 'symfony/notifier', 'symfony/mailer'], true)) { $container->getDefinition($classToServices[FakeChatTransportFactory::class]) ->replaceArgument('$mailer', new Reference('mailer')) - ->replaceArgument('$logger', new Reference('logger')); + ->replaceArgument('$logger', new Reference('logger')) + ->replaceArgument('$client', new Reference('http_client', ContainerBuilder::NULL_ON_INVALID_REFERENCE)) + ->replaceArgument('$dispatcher', new Reference('event_dispatcher', ContainerBuilder::NULL_ON_INVALID_REFERENCE)); } if (ContainerBuilder::willBeAvailable('symfony/fake-sms-notifier', FakeSmsTransportFactory::class, ['symfony/framework-bundle', 'symfony/notifier', 'symfony/mailer'], true)) { $container->getDefinition($classToServices[FakeSmsTransportFactory::class]) ->replaceArgument('$mailer', new Reference('mailer')) - ->replaceArgument('$logger', new Reference('logger')); + ->replaceArgument('$logger', new Reference('logger')) + ->replaceArgument('$client', new Reference('http_client', ContainerBuilder::NULL_ON_INVALID_REFERENCE)) + ->replaceArgument('$dispatcher', new Reference('event_dispatcher', ContainerBuilder::NULL_ON_INVALID_REFERENCE)); } if (isset($config['admin_recipients'])) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serializer/CircularReferenceHandler.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serializer/CircularReferenceHandler.php new file mode 100644 index 0000000000000..b4e402a042a4f --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serializer/CircularReferenceHandler.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serializer; + +class CircularReferenceHandler +{ + public function __invoke() + { + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serializer/MaxDepthHandler.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serializer/MaxDepthHandler.php new file mode 100644 index 0000000000000..f76fb3db82985 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Serializer/MaxDepthHandler.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serializer; + +class MaxDepthHandler +{ + public function __invoke() + { + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml index e9620ede4d920..f023f6341970d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml @@ -4,6 +4,8 @@ imports: framework: serializer: enabled: true + circular_reference_handler: Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serializer\CircularReferenceHandler + max_depth_handler: Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serializer\MaxDepthHandler default_context: enable_max_depth: true fake_context_option: foo @@ -57,3 +59,7 @@ services: serializer.encoder.csv.alias: alias: serializer.encoder.csv public: true + + Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serializer\CircularReferenceHandler: ~ + + Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serializer\MaxDepthHandler: ~ diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 24a28dee93223..8479f1d888f78 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -75,7 +75,7 @@ "phpdocumentor/reflection-docblock": "<3.2.2", "phpdocumentor/type-resolver": "<1.4.0", "symfony/asset": "<5.3", - "symfony/console": "<5.2.5", + "symfony/console": "<5.2.5|>=7.0", "symfony/dotenv": "<5.1", "symfony/dom-crawler": "<4.4", "symfony/http-client": "<4.4", diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php index 9d44294a518d5..f222af861e198 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTestCase.php @@ -224,7 +224,7 @@ public function testFirewalls() ], ], $listeners); - $this->assertFalse($container->hasAlias('Symfony\Component\Security\Core\User\UserCheckerInterface', 'No user checker alias is registered when custom user checker services are registered')); + $this->assertFalse($container->hasAlias('Symfony\Component\Security\Core\User\UserCheckerInterface'), 'No user checker alias is registered when custom user checker services are registered'); } /** 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 be979cd6ad231..6187024fa93de 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 @@ -547,7 +547,9 @@ if (typeof Sfjs === 'undefined' || typeof Sfjs.loadToolbar === 'undefined') { /* Evaluate in global scope scripts embedded inside the toolbar */ var i, scripts = [].slice.call(el.querySelectorAll('script')); for (i = 0; i < scripts.length; ++i) { - eval.call({}, scripts[i].firstChild.nodeValue); + if (scripts[i].firstChild) { + eval.call({}, scripts[i].firstChild.nodeValue); + } } el.style.display = -1 !== xhr.responseText.indexOf('sf-toolbarreset') ? 'block' : 'none'; diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/Twig/WebProfilerExtensionTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/Twig/WebProfilerExtensionTest.php index 1bb1296b09903..37438ed560206 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Tests/Twig/WebProfilerExtensionTest.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/Twig/WebProfilerExtensionTest.php @@ -15,8 +15,6 @@ use Symfony\Bundle\WebProfilerBundle\Twig\WebProfilerExtension; use Symfony\Component\VarDumper\Cloner\VarCloner; use Twig\Environment; -use Twig\Extension\CoreExtension; -use Twig\Extension\EscaperExtension; class WebProfilerExtensionTest extends TestCase { @@ -25,9 +23,6 @@ class WebProfilerExtensionTest extends TestCase */ public function testDumpHeaderIsDisplayed(string $message, array $context, bool $dump1HasHeader, bool $dump2HasHeader) { - class_exists(CoreExtension::class); // Load twig_convert_encoding() - class_exists(EscaperExtension::class); // Load twig_escape_filter() - $twigEnvironment = $this->mockTwigEnvironment(); $varCloner = new VarCloner(); diff --git a/src/Symfony/Bundle/WebProfilerBundle/Twig/WebProfilerExtension.php b/src/Symfony/Bundle/WebProfilerBundle/Twig/WebProfilerExtension.php index b5f0f3cad2479..039af91035c29 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Twig/WebProfilerExtension.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Twig/WebProfilerExtension.php @@ -14,6 +14,7 @@ use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\VarDumper\Dumper\HtmlDumper; use Twig\Environment; +use Twig\Extension\EscaperExtension; use Twig\Extension\ProfilerExtension; use Twig\Profiler\Profile; use Twig\TwigFunction; @@ -60,9 +61,6 @@ public function leave(Profile $profile): void } } - /** - * {@inheritdoc} - */ public function getFunctions(): array { return [ @@ -87,12 +85,12 @@ public function dumpData(Environment $env, Data $data, int $maxDepth = 0) public function dumpLog(Environment $env, string $message, Data $context = null) { - $message = twig_escape_filter($env, $message); + $message = self::escape($env, $message); $message = preg_replace('/"(.*?)"/', '"$1"', $message); $replacements = []; foreach ($context ?? [] as $k => $v) { - $k = '{'.twig_escape_filter($env, $k).'}'; + $k = '{'.self::escape($env, $k).'}'; if (str_contains($message, $k)) { $replacements[$k] = $v; } @@ -109,11 +107,18 @@ public function dumpLog(Environment $env, string $message, Data $context = null) return ''.strtr($message, $replacements).''; } - /** - * {@inheritdoc} - */ public function getName() { return 'profiler'; } + + private static function escape(Environment $env, string $s): string + { + if (method_exists(EscaperExtension::class, 'escape')) { + return EscaperExtension::escape($env, $s); + } + + // to be removed when support for Twig 3 is dropped + return twig_escape_filter($env, $s); + } } diff --git a/src/Symfony/Component/Cache/Tests/Adapter/CouchbaseBucketAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/CouchbaseBucketAdapterTest.php index 99acc838e532e..08edff2c33a68 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/CouchbaseBucketAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/CouchbaseBucketAdapterTest.php @@ -33,7 +33,7 @@ class CouchbaseBucketAdapterTest extends AdapterTestCase /** @var \CouchbaseBucket */ protected static $client; - public static function setupBeforeClass(): void + public static function setUpBeforeClass(): void { if (!CouchbaseBucketAdapter::isSupported()) { throw new SkippedTestSuiteError('Couchbase >= 2.6.0 < 3.0.0 is required.'); diff --git a/src/Symfony/Component/Cache/Tests/Adapter/CouchbaseCollectionAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/CouchbaseCollectionAdapterTest.php index 619dac5fd2863..427e04339f944 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/CouchbaseCollectionAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/CouchbaseCollectionAdapterTest.php @@ -33,7 +33,7 @@ class CouchbaseCollectionAdapterTest extends AdapterTestCase /** @var Collection */ protected static $client; - public static function setupBeforeClass(): void + public static function setUpBeforeClass(): void { if (!CouchbaseCollectionAdapter::isSupported()) { self::markTestSkipped('Couchbase >= 3.0.0 < 4.0.0 is required.'); diff --git a/src/Symfony/Component/Cache/Tests/Adapter/RedisArrayAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/RedisArrayAdapterTest.php index 58ca31441f5fb..6323dbd3beabc 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/RedisArrayAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/RedisArrayAdapterTest.php @@ -20,7 +20,7 @@ class RedisArrayAdapterTest extends AbstractRedisAdapterTestCase { public static function setUpBeforeClass(): void { - parent::setupBeforeClass(); + parent::setUpBeforeClass(); if (!class_exists(\RedisArray::class)) { throw new SkippedTestSuiteError('The RedisArray class is required.'); } diff --git a/src/Symfony/Component/Console/Output/StreamOutput.php b/src/Symfony/Component/Console/Output/StreamOutput.php index 7f5551827d586..f057f0e51d159 100644 --- a/src/Symfony/Component/Console/Output/StreamOutput.php +++ b/src/Symfony/Component/Console/Output/StreamOutput.php @@ -64,9 +64,6 @@ public function getStream() return $this->stream; } - /** - * {@inheritdoc} - */ protected function doWrite(string $message, bool $newline) { if ($newline) { @@ -98,18 +95,17 @@ protected function hasColorSupport() return false; } - if ('Hyper' === getenv('TERM_PROGRAM')) { + if (\DIRECTORY_SEPARATOR === '\\' + && \function_exists('sapi_windows_vt100_support') + && @sapi_windows_vt100_support($this->stream) + ) { return true; } - if (\DIRECTORY_SEPARATOR === '\\') { - return (\function_exists('sapi_windows_vt100_support') - && @sapi_windows_vt100_support($this->stream)) - || false !== getenv('ANSICON') - || 'ON' === getenv('ConEmuANSI') - || 'xterm' === getenv('TERM'); - } - - return stream_isatty($this->stream); + return 'Hyper' === getenv('TERM_PROGRAM') + || false !== getenv('ANSICON') + || 'ON' === getenv('ConEmuANSI') + || str_starts_with((string) getenv('TERM'), 'xterm') + || stream_isatty($this->stream); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container8.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container8.php index 0caa0fe3ef2b6..18c78746e4ab6 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container8.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container8.php @@ -12,7 +12,7 @@ 'utf-8 valid string' => "\u{021b}\u{1b56}\ttest", 'binary' => "\xf0\xf0\xf0\xf0", 'binary-control-char' => "This is a Bell char \x07", - 'console banner' => "\e[37;44m#StandWith\e[30;43mUkraine\e[0m", + 'console banner' => "\e[37;44mHello\e[30;43mWorld\e[0m", 'null string' => 'null', 'string of digits' => '123', 'string of digits prefixed with minus character' => '-123', diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services8.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services8.php index 840bab52aa580..feca8339f2ca4 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services8.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services8.php @@ -109,7 +109,7 @@ protected function getDefaultParameters(): array 'utf-8 valid string' => 'ț᭖ test', 'binary' => '', 'binary-control-char' => 'This is a Bell char ', - 'console banner' => '#StandWithUkraine', + 'console banner' => 'HelloWorld', 'null string' => 'null', 'string of digits' => '123', 'string of digits prefixed with minus character' => '-123', diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services8.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services8.xml index 8e095e7119fa9..7c93e8bd39994 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services8.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services8.xml @@ -21,7 +21,7 @@ ț᭖ test 8PDw8A== VGhpcyBpcyBhIEJlbGwgY2hhciAH - G1szNzs0NG0jU3RhbmRXaXRoG1szMDs0M21Va3JhaW5lG1swbQ== + G1szNzs0NG1IZWxsbxtbMzA7NDNtV29ybGQbWzBt null 123 -123 diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services8.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services8.yml index ef9782f0a018b..241a91cb01b9a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services8.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services8.yml @@ -7,7 +7,7 @@ parameters: utf-8 valid string: "ț᭖\ttest" binary: !!binary 8PDw8A== binary-control-char: !!binary VGhpcyBpcyBhIEJlbGwgY2hhciAH - console banner: "\e[37;44m#StandWith\e[30;43mUkraine\e[0m" + console banner: "\e[37;44mHello\e[30;43mWorld\e[0m" null string: 'null' string of digits: '123' string of digits prefixed with minus character: '-123' diff --git a/src/Symfony/Component/Dotenv/Command/DebugCommand.php b/src/Symfony/Component/Dotenv/Command/DebugCommand.php index 8ceb1fd484845..0585043cd9463 100644 --- a/src/Symfony/Component/Dotenv/Command/DebugCommand.php +++ b/src/Symfony/Component/Dotenv/Command/DebugCommand.php @@ -82,7 +82,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int private function getVariables(array $envFiles): array { - $vars = explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? ''); + $dotenvVars = $_SERVER['SYMFONY_DOTENV_VARS'] ?? ''; + + if ('' === $dotenvVars) { + return []; + } + + $vars = explode(',', $dotenvVars); sort($vars); $output = []; diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php index bcf93678f6970..685df57d736f8 100644 --- a/src/Symfony/Component/Dotenv/Dotenv.php +++ b/src/Symfony/Component/Dotenv/Dotenv.php @@ -25,7 +25,7 @@ */ final class Dotenv { - public const VARNAME_REGEX = '(?i:[A-Z][A-Z0-9_]*+)'; + public const VARNAME_REGEX = '(?i:_?[A-Z][A-Z0-9_]*+)'; public const STATE_VARNAME = 0; public const STATE_VALUE = 1; @@ -351,8 +351,8 @@ private function lexValue(): string ++$this->cursor; $value = str_replace(['\\"', '\r', '\n'], ['"', "\r", "\n"], $value); $resolvedValue = $value; - $resolvedValue = $this->resolveVariables($resolvedValue, $loadedVars); $resolvedValue = $this->resolveCommands($resolvedValue, $loadedVars); + $resolvedValue = $this->resolveVariables($resolvedValue, $loadedVars); $resolvedValue = str_replace('\\\\', '\\', $resolvedValue); $v .= $resolvedValue; } else { @@ -374,8 +374,8 @@ private function lexValue(): string } $value = rtrim($value); $resolvedValue = $value; - $resolvedValue = $this->resolveVariables($resolvedValue, $loadedVars); $resolvedValue = $this->resolveCommands($resolvedValue, $loadedVars); + $resolvedValue = $this->resolveVariables($resolvedValue, $loadedVars); $resolvedValue = str_replace('\\\\', '\\', $resolvedValue); if ($resolvedValue === $value && preg_match('/\s+/', $value)) { diff --git a/src/Symfony/Component/Dotenv/Tests/Command/DebugCommandTest.php b/src/Symfony/Component/Dotenv/Tests/Command/DebugCommandTest.php index b3b089e4559c9..b8b7e39008607 100644 --- a/src/Symfony/Component/Dotenv/Tests/Command/DebugCommandTest.php +++ b/src/Symfony/Component/Dotenv/Tests/Command/DebugCommandTest.php @@ -25,6 +25,8 @@ class DebugCommandTest extends TestCase */ public function testErrorOnUninitializedDotenv() { + unset($_SERVER['SYMFONY_DOTENV_VARS']); + $command = new DebugCommand('dev', __DIR__.'/Fixtures/Scenario1'); $command->setHelperSet(new HelperSet([new FormatterHelper()])); $tester = new CommandTester($command); @@ -34,6 +36,30 @@ public function testErrorOnUninitializedDotenv() $this->assertStringContainsString('[ERROR] Dotenv component is not initialized', $output); } + /** + * @runInSeparateProcess + */ + public function testEmptyDotEnvVarsList() + { + $_SERVER['SYMFONY_DOTENV_VARS'] = ''; + + $command = new DebugCommand('dev', __DIR__.'/Fixtures/Scenario1'); + $command->setHelperSet(new HelperSet([new FormatterHelper()])); + $tester = new CommandTester($command); + $tester->execute([]); + $expectedFormat = <<<'OUTPUT' +%a + ---------- ------- ------------ ------%S + Variable Value .env.local .env%S + ---------- ------- ------------ ------%S + + // Note real values might be different between web and CLI.%S +%a +OUTPUT; + + $this->assertStringMatchesFormat($expectedFormat, $tester->getDisplay()); + } + public function testScenario1InDevEnv() { $output = $this->executeCommand(__DIR__.'/Fixtures/Scenario1', 'dev'); diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php index 2089e4bca336c..72d0d5630ec9a 100644 --- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php +++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php @@ -53,6 +53,7 @@ public static function getEnvDataWithFormatErrors() ["FOO=\nBAR=\${FOO:-\'a{a}a}", "Unsupported character \"'\" found in the default value of variable \"\$FOO\". in \".env\" at line 2.\n...\\nBAR=\${FOO:-\'a{a}a}...\n ^ line 2 offset 24"], ["FOO=\nBAR=\${FOO:-a\$a}", "Unsupported character \"\$\" found in the default value of variable \"\$FOO\". in \".env\" at line 2.\n...FOO=\\nBAR=\${FOO:-a\$a}...\n ^ line 2 offset 20"], ["FOO=\nBAR=\${FOO:-a\"a}", "Unclosed braces on variable expansion in \".env\" at line 2.\n...FOO=\\nBAR=\${FOO:-a\"a}...\n ^ line 2 offset 17"], + ['_=FOO', "Invalid character in variable name in \".env\" at line 1.\n..._=FOO...\n ^ line 1 offset 0"], ]; if ('\\' !== \DIRECTORY_SEPARATOR) { @@ -175,6 +176,10 @@ public static function getEnvData() ["FOO=\nBAR=\${FOO:=TEST}", ['FOO' => 'TEST', 'BAR' => 'TEST']], ["FOO=\nBAR=\$FOO:=TEST}", ['FOO' => 'TEST', 'BAR' => 'TEST}']], ["FOO=foo\nFOOBAR=\${FOO}\${BAR}", ['FOO' => 'foo', 'FOOBAR' => 'foo']], + + // underscores + ['_FOO=BAR', ['_FOO' => 'BAR']], + ['_FOO_BAR=FOOBAR', ['_FOO_BAR' => 'FOOBAR']], ]; if ('\\' !== \DIRECTORY_SEPARATOR) { diff --git a/src/Symfony/Component/EventDispatcher/GenericEvent.php b/src/Symfony/Component/EventDispatcher/GenericEvent.php index b32a301ae9b51..4ecd29e3be63b 100644 --- a/src/Symfony/Component/EventDispatcher/GenericEvent.php +++ b/src/Symfony/Component/EventDispatcher/GenericEvent.php @@ -29,7 +29,7 @@ class GenericEvent extends Event implements \ArrayAccess, \IteratorAggregate protected $arguments; /** - * Encapsulate an event with $subject and $args. + * Encapsulate an event with $subject and $arguments. * * @param mixed $subject The subject of the event, usually an object or a callable * @param array $arguments Arguments to store in the event diff --git a/src/Symfony/Component/HttpClient/Response/AsyncContext.php b/src/Symfony/Component/HttpClient/Response/AsyncContext.php index 646458e13c54e..e0c0ebb836d38 100644 --- a/src/Symfony/Component/HttpClient/Response/AsyncContext.php +++ b/src/Symfony/Component/HttpClient/Response/AsyncContext.php @@ -92,7 +92,7 @@ public function pause(float $duration): void if (\is_callable($pause = $this->response->getInfo('pause_handler'))) { $pause($duration); } elseif (0 < $duration) { - usleep(1E6 * $duration); + usleep((int) (1E6 * $duration)); } } diff --git a/src/Symfony/Component/HttpClient/Response/TransportResponseTrait.php b/src/Symfony/Component/HttpClient/Response/TransportResponseTrait.php index 566d61e17611a..0482ccbabf0ba 100644 --- a/src/Symfony/Component/HttpClient/Response/TransportResponseTrait.php +++ b/src/Symfony/Component/HttpClient/Response/TransportResponseTrait.php @@ -303,7 +303,7 @@ public static function stream(iterable $responses, float $timeout = null): \Gene } if (-1 === self::select($multi, min($timeoutMin, $timeoutMax - $elapsedTimeout))) { - usleep(min(500, 1E6 * $timeoutMin)); + usleep((int) min(500, 1E6 * $timeoutMin)); } $elapsedTimeout = microtime(true) - $lastActivity; diff --git a/src/Symfony/Component/HttpFoundation/RequestMatcher.php b/src/Symfony/Component/HttpFoundation/RequestMatcher.php index f2645f9ae9f4a..5212634479834 100644 --- a/src/Symfony/Component/HttpFoundation/RequestMatcher.php +++ b/src/Symfony/Component/HttpFoundation/RequestMatcher.php @@ -91,7 +91,7 @@ public function matchHost(?string $regexp) } /** - * Adds a check for the the URL port. + * Adds a check for the URL port. * * @param int|null $port The port number to connect to */ diff --git a/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php b/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php index cb994cd77d6f7..979154be9a7b0 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php @@ -36,13 +36,15 @@ * * @author Johannes M. Schmitt * @author Tobias Schultze - * - * @internal */ abstract class AbstractSessionListener implements EventSubscriberInterface, ResetInterface { public const NO_AUTO_CACHE_CONTROL_HEADER = 'Symfony-Session-NoAutoCacheControl'; + + /** + * @internal + */ protected $container; private $sessionUsageStack = []; private $debug; @@ -52,6 +54,9 @@ abstract class AbstractSessionListener implements EventSubscriberInterface, Rese */ private $sessionOptions; + /** + * @internal + */ public function __construct(ContainerInterface $container = null, bool $debug = false, array $sessionOptions = []) { $this->container = $container; @@ -59,6 +64,9 @@ public function __construct(ContainerInterface $container = null, bool $debug = $this->sessionOptions = $sessionOptions; } + /** + * @internal + */ public function onKernelRequest(RequestEvent $event) { if (!$event->isMainRequest()) { @@ -94,6 +102,9 @@ public function onKernelRequest(RequestEvent $event) $this->sessionUsageStack[] = $session instanceof Session ? $session->getUsageIndex() : 0; } + /** + * @internal + */ public function onKernelResponse(ResponseEvent $event) { if (!$event->isMainRequest() || (!$this->container->has('initialized_session') && !$event->getRequest()->hasSession())) { @@ -222,6 +233,9 @@ public function onKernelResponse(ResponseEvent $event) } } + /** + * @internal + */ public function onFinishRequest(FinishRequestEvent $event) { if ($event->isMainRequest()) { @@ -229,6 +243,9 @@ public function onFinishRequest(FinishRequestEvent $event) } } + /** + * @internal + */ public function onSessionUsage(): void { if (!$this->debug) { @@ -264,6 +281,9 @@ public function onSessionUsage(): void throw new UnexpectedSessionUsageException('Session was used while the request was declared stateless.'); } + /** + * @internal + */ public static function getSubscribedEvents(): array { return [ @@ -274,6 +294,9 @@ public static function getSubscribedEvents(): array ]; } + /** + * @internal + */ public function reset(): void { if (\PHP_SESSION_ACTIVE === session_status()) { @@ -291,6 +314,8 @@ public function reset(): void /** * Gets the session object. * + * @internal + * * @return SessionInterface|null */ abstract protected function getSession(); diff --git a/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php b/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php index f19e13649e988..2c09e22bda7ac 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/LocaleListener.php @@ -68,8 +68,10 @@ private function setLocale(Request $request) { if ($locale = $request->attributes->get('_locale')) { $request->setLocale($locale); - } elseif ($this->useAcceptLanguageHeader && $this->enabledLocales && ($preferredLanguage = $request->getPreferredLanguage($this->enabledLocales))) { - $request->setLocale($preferredLanguage); + } elseif ($this->useAcceptLanguageHeader && $this->enabledLocales) { + if ($request->getLanguages() && $preferredLanguage = $request->getPreferredLanguage($this->enabledLocales)) { + $request->setLocale($preferredLanguage); + } $request->attributes->set('_vary_by_language', true); } } diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 3cfc3af9a066c..bd6b152b8ac7a 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -78,11 +78,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static $freshCache = []; - public const VERSION = '5.4.33'; - public const VERSION_ID = 50433; + public const VERSION = '5.4.34'; + public const VERSION_ID = 50434; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 4; - public const RELEASE_VERSION = 33; + public const RELEASE_VERSION = 34; public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2024'; diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php index 04d951747407d..e22950ddd913a 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php @@ -130,6 +130,28 @@ public function testRequestPreferredLocaleFromAcceptLanguageHeader() $this->assertEquals('fr', $request->getLocale()); } + public function testRequestDefaultLocaleIfNoAcceptLanguageHeaderIsPresent() + { + $request = new Request(); + $listener = new LocaleListener($this->requestStack, 'de', null, true, ['lt', 'de']); + $event = $this->getEvent($request); + + $listener->setDefaultLocale($event); + $listener->onKernelRequest($event); + $this->assertEquals('de', $request->getLocale()); + } + + public function testRequestVaryByLanguageAttributeIsSetIfUsingAcceptLanguageHeader() + { + $request = new Request(); + $listener = new LocaleListener($this->requestStack, 'de', null, true, ['lt', 'de']); + $event = $this->getEvent($request); + + $listener->setDefaultLocale($event); + $listener->onKernelRequest($event); + $this->assertTrue($request->attributes->get('_vary_by_language')); + } + public function testRequestSecondPreferredLocaleFromAcceptLanguageHeader() { $request = Request::create('/'); diff --git a/src/Symfony/Component/Lock/Tests/Store/MongoDbStoreFactoryTest.php b/src/Symfony/Component/Lock/Tests/Store/MongoDbStoreFactoryTest.php index 7782f9753632a..e5c4d0c8104d0 100644 --- a/src/Symfony/Component/Lock/Tests/Store/MongoDbStoreFactoryTest.php +++ b/src/Symfony/Component/Lock/Tests/Store/MongoDbStoreFactoryTest.php @@ -25,7 +25,7 @@ */ class MongoDbStoreFactoryTest extends TestCase { - public static function setupBeforeClass(): void + public static function setUpBeforeClass(): void { if (!class_exists(Client::class)) { throw new SkippedTestSuiteError('The mongodb/mongodb package is required.'); diff --git a/src/Symfony/Component/Lock/Tests/Store/MongoDbStoreTest.php b/src/Symfony/Component/Lock/Tests/Store/MongoDbStoreTest.php index 7efa540dbe087..3284c1f887895 100644 --- a/src/Symfony/Component/Lock/Tests/Store/MongoDbStoreTest.php +++ b/src/Symfony/Component/Lock/Tests/Store/MongoDbStoreTest.php @@ -30,7 +30,7 @@ class MongoDbStoreTest extends AbstractStoreTestCase { use ExpiringStoreTestTrait; - public static function setupBeforeClass(): void + public static function setUpBeforeClass(): void { if (!class_exists(Client::class)) { throw new SkippedTestSuiteError('The mongodb/mongodb package is required.'); diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesApiAsyncAwsTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesApiAsyncAwsTransportTest.php index 3ad8603790236..82c06195fb7e5 100644 --- a/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesApiAsyncAwsTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesApiAsyncAwsTransportTest.php @@ -37,35 +37,35 @@ public static function getTransportData() { return [ [ - new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY']))), + new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['sharedConfigFile' => false, 'accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY']))), 'ses+api://ACCESS_KEY@us-east-1', ], [ - new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'region' => 'us-west-1']))), + new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['sharedConfigFile' => false, 'accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'region' => 'us-west-1']))), 'ses+api://ACCESS_KEY@us-west-1', ], [ - new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com']))), + new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['sharedConfigFile' => false, 'accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com']))), 'ses+api://ACCESS_KEY@example.com', ], [ - new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com:99']))), + new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['sharedConfigFile' => false, 'accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com:99']))), 'ses+api://ACCESS_KEY@example.com:99', ], [ - new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'sessionToken' => 'SESSION_TOKEN']))), + new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['sharedConfigFile' => false, 'accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'sessionToken' => 'SESSION_TOKEN']))), 'ses+api://ACCESS_KEY@us-east-1', ], [ - new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'region' => 'us-west-1', 'sessionToken' => 'SESSION_TOKEN']))), + new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['sharedConfigFile' => false, 'accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'region' => 'us-west-1', 'sessionToken' => 'SESSION_TOKEN']))), 'ses+api://ACCESS_KEY@us-west-1', ], [ - new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com', 'sessionToken' => 'SESSION_TOKEN']))), + new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['sharedConfigFile' => false, 'accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com', 'sessionToken' => 'SESSION_TOKEN']))), 'ses+api://ACCESS_KEY@example.com', ], [ - new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com:99', 'sessionToken' => 'SESSION_TOKEN']))), + new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['sharedConfigFile' => false, 'accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com:99', 'sessionToken' => 'SESSION_TOKEN']))), 'ses+api://ACCESS_KEY@example.com:99', ], ]; @@ -97,7 +97,7 @@ public function testSend() ]); }); - $transport = new SesApiAsyncAwsTransport(new SesClient(Configuration::create([]), new NullProvider(), $client)); + $transport = new SesApiAsyncAwsTransport(new SesClient(Configuration::create(['sharedConfigFile' => false]), new NullProvider(), $client)); $mail = new Email(); $mail->subject('Hello!') diff --git a/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesHttpAsyncAwsTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesHttpAsyncAwsTransportTest.php index b08e5daccdb2e..943eba309d4ac 100644 --- a/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesHttpAsyncAwsTransportTest.php +++ b/src/Symfony/Component/Mailer/Bridge/Amazon/Tests/Transport/SesHttpAsyncAwsTransportTest.php @@ -37,35 +37,35 @@ public static function getTransportData() { return [ [ - new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY']))), + new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['sharedConfigFile' => false, 'accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY']))), 'ses+https://ACCESS_KEY@us-east-1', ], [ - new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'region' => 'us-west-1']))), + new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['sharedConfigFile' => false, 'accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'region' => 'us-west-1']))), 'ses+https://ACCESS_KEY@us-west-1', ], [ - new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com']))), + new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['sharedConfigFile' => false, 'accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com']))), 'ses+https://ACCESS_KEY@example.com', ], [ - new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com:99']))), + new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['sharedConfigFile' => false, 'accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com:99']))), 'ses+https://ACCESS_KEY@example.com:99', ], [ - new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'sessionToken' => 'SESSION_TOKEN']))), + new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['sharedConfigFile' => false, 'accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'sessionToken' => 'SESSION_TOKEN']))), 'ses+https://ACCESS_KEY@us-east-1', ], [ - new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'region' => 'us-west-1', 'sessionToken' => 'SESSION_TOKEN']))), + new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['sharedConfigFile' => false, 'accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'region' => 'us-west-1', 'sessionToken' => 'SESSION_TOKEN']))), 'ses+https://ACCESS_KEY@us-west-1', ], [ - new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com', 'sessionToken' => 'SESSION_TOKEN']))), + new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['sharedConfigFile' => false, 'accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com', 'sessionToken' => 'SESSION_TOKEN']))), 'ses+https://ACCESS_KEY@example.com', ], [ - new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com:99', 'sessionToken' => 'SESSION_TOKEN']))), + new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['sharedConfigFile' => false, 'accessKeyId' => 'ACCESS_KEY', 'accessKeySecret' => 'SECRET_KEY', 'endpoint' => 'https://example.com:99', 'sessionToken' => 'SESSION_TOKEN']))), 'ses+https://ACCESS_KEY@example.com:99', ], ]; @@ -94,7 +94,7 @@ public function testSend() ]); }); - $transport = new SesHttpAsyncAwsTransport(new SesClient(Configuration::create([]), new NullProvider(), $client)); + $transport = new SesHttpAsyncAwsTransport(new SesClient(Configuration::create(['sharedConfigFile' => false]), new NullProvider(), $client)); $mail = new Email(); $mail->subject('Hello!') diff --git a/src/Symfony/Component/Mailer/Transport/AbstractTransport.php b/src/Symfony/Component/Mailer/Transport/AbstractTransport.php index 85f04a8b8b3ac..ae5b0a820787b 100644 --- a/src/Symfony/Component/Mailer/Transport/AbstractTransport.php +++ b/src/Symfony/Component/Mailer/Transport/AbstractTransport.php @@ -104,7 +104,7 @@ private function checkThrottling() $sleep = (1 / $this->rate) - (microtime(true) - $this->lastSent); if (0 < $sleep) { $this->logger->debug(sprintf('Email transport "%s" sleeps for %.2f seconds', __CLASS__, $sleep)); - usleep($sleep * 1000000); + usleep((int) ($sleep * 1000000)); } $this->lastSent = microtime(true); } diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineIntegrationTest.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineIntegrationTest.php index e4e22565717f6..e1b4d4afdda44 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineIntegrationTest.php @@ -73,11 +73,33 @@ public function testSendWithDelay() $stmt = $stmt->execute(); } - $available_at = new \DateTime($stmt instanceof Result || $stmt instanceof DriverResult ? $stmt->fetchOne() : $stmt->fetchColumn()); + $availableAt = new \DateTime($stmt instanceof Result || $stmt instanceof DriverResult ? $stmt->fetchOne() : $stmt->fetchColumn()); $now = new \DateTime(); $now->modify('+60 seconds'); - $this->assertGreaterThan($now, $available_at); + $this->assertGreaterThan($now, $availableAt); + } + + public function testSendWithNegativeDelay() + { + $this->connection->send('{"message": "Hi I am not actually delayed"}', ['type' => DummyMessage::class], -600000); + + $stmt = $this->driverConnection->createQueryBuilder() + ->select('m.available_at') + ->from('messenger_messages', 'm') + ->where('m.body = :body') + ->setParameter('body', '{"message": "Hi I am not actually delayed"}'); + if (method_exists($stmt, 'executeQuery')) { + $stmt = $stmt->executeQuery(); + } else { + $stmt = $stmt->execute(); + } + + $availableAt = new \DateTime($stmt instanceof Result || $stmt instanceof DriverResult ? $stmt->fetchOne() : $stmt->fetchColumn()); + + $now = new \DateTime(); + $now->modify('-60 seconds'); + $this->assertLessThan($now, $availableAt); } public function testItRetrieveTheFirstAvailableMessage() diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php index bb322e760fbdb..ed9a57a0ce568 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php @@ -125,7 +125,7 @@ public static function buildConfiguration(string $dsn, array $options = []): arr public function send(string $body, array $headers, int $delay = 0): string { $now = new \DateTime(); - $availableAt = (clone $now)->modify(sprintf('+%d seconds', $delay / 1000)); + $availableAt = (clone $now)->modify(sprintf('%+d seconds', $delay / 1000)); $queryBuilder = $this->driverConnection->createQueryBuilder() ->insert($this->configuration['table_name']) diff --git a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisExtIntegrationTest.php b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisExtIntegrationTest.php index 5a418b3204644..bd7e43aefa3a9 100644 --- a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisExtIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisExtIntegrationTest.php @@ -246,15 +246,19 @@ public function testLazy() $connection = Connection::fromDsn('redis://localhost/messenger-lazy?lazy=1', ['delete_after_ack' => true], $redis); $connection->add('1', []); - $this->assertNotEmpty($message = $connection->get()); - $this->assertSame([ - 'message' => json_encode([ - 'body' => '1', - 'headers' => [], - ]), - ], $message['data']); - $connection->reject($message['id']); - $redis->del('messenger-lazy'); + + try { + $this->assertNotEmpty($message = $connection->get()); + $this->assertSame([ + 'message' => json_encode([ + 'body' => '1', + 'headers' => [], + ]), + ], $message['data']); + $connection->reject($message['id']); + } finally { + $redis->del('messenger-lazy'); + } } public function testDbIndex() @@ -283,13 +287,16 @@ public function testFromDsnWithMultipleHosts() public function testJsonError() { $redis = new \Redis(); - $connection = Connection::fromDsn('redis://localhost/json-error', ['delete_after_ack' => true], $redis); + $connection = Connection::fromDsn('redis://localhost/messenger-json-error', ['delete_after_ack' => true], $redis); try { $connection->add("\xB1\x31", []); + + $this->fail('Expected exception to be thrown.'); } catch (TransportException $e) { + $this->assertSame('Malformed UTF-8 characters, possibly incorrectly encoded', $e->getMessage()); + } finally { + $redis->del('messenger-json-error'); } - - $this->assertSame('Malformed UTF-8 characters, possibly incorrectly encoded', $e->getMessage()); } public function testGetNonBlocking() @@ -298,11 +305,14 @@ public function testGetNonBlocking() $connection = Connection::fromDsn('redis://localhost/messenger-getnonblocking', ['delete_after_ack' => true], $redis); - $this->assertNull($connection->get()); // no message, should return null immediately - $connection->add('1', []); - $this->assertNotEmpty($message = $connection->get()); - $connection->reject($message['id']); - $redis->del('messenger-getnonblocking'); + try { + $this->assertNull($connection->get()); // no message, should return null immediately + $connection->add('1', []); + $this->assertNotEmpty($message = $connection->get()); + $connection->reject($message['id']); + } finally { + $redis->del('messenger-getnonblocking'); + } } public function testGetAfterReject() @@ -310,16 +320,18 @@ public function testGetAfterReject() $redis = new \Redis(); $connection = Connection::fromDsn('redis://localhost/messenger-rejectthenget', ['delete_after_ack' => true], $redis); - $connection->add('1', []); - $connection->add('2', []); - - $failing = $connection->get(); - $connection->reject($failing['id']); + try { + $connection->add('1', []); + $connection->add('2', []); - $connection = Connection::fromDsn('redis://localhost/messenger-rejectthenget', ['delete_after_ack' => true]); - $this->assertNotNull($connection->get()); + $failing = $connection->get(); + $connection->reject($failing['id']); - $redis->del('messenger-rejectthenget'); + $connection = Connection::fromDsn('redis://localhost/messenger-rejectthenget', ['delete_after_ack' => true]); + $this->assertNotNull($connection->get()); + } finally { + $redis->del('messenger-rejectthenget'); + } } public function testItProperlyHandlesEmptyMessages() diff --git a/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php index 321b0001ac5f2..df1edaae55774 100644 --- a/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php @@ -117,6 +117,10 @@ public function __construct(array $configuration, array $connectionCredentials = */ private static function initializeRedis(\Redis $redis, string $host, int $port, $auth, int $serializer, int $dbIndex): \Redis { + if ($redis->isConnected()) { + return $redis; + } + $redis->connect($host, $port); $redis->setOption(\Redis::OPT_SERIALIZER, $serializer); diff --git a/src/Symfony/Component/Notifier/Bridge/Clickatell/ClickatellTransport.php b/src/Symfony/Component/Notifier/Bridge/Clickatell/ClickatellTransport.php index 621ab9d430675..cba6d917c03ae 100644 --- a/src/Symfony/Component/Notifier/Bridge/Clickatell/ClickatellTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Clickatell/ClickatellTransport.php @@ -78,7 +78,7 @@ protected function doSend(MessageInterface $message): SentMessage try { $statusCode = $response->getStatusCode(); } catch (TransportExceptionInterface $e) { - throw new TransportException('Could not reach the remote Clicktell server.', $response, 0, $e); + throw new TransportException('Could not reach the remote Clickatell server.', $response, 0, $e); } if (202 === $statusCode) { diff --git a/src/Symfony/Component/Notifier/Bridge/FakeChat/FakeChatTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/FakeChat/FakeChatTransportFactory.php index 9b55acb99a00f..d8467665b48fd 100644 --- a/src/Symfony/Component/Notifier/Bridge/FakeChat/FakeChatTransportFactory.php +++ b/src/Symfony/Component/Notifier/Bridge/FakeChat/FakeChatTransportFactory.php @@ -17,6 +17,8 @@ use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\TransportInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; /** * @author Oskar Stark @@ -27,9 +29,9 @@ final class FakeChatTransportFactory extends AbstractTransportFactory protected $mailer; protected $logger; - public function __construct(MailerInterface $mailer, LoggerInterface $logger) + public function __construct(MailerInterface $mailer, LoggerInterface $logger, EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null) { - parent::__construct(); + parent::__construct($dispatcher, $client); $this->mailer = $mailer; $this->logger = $logger; @@ -47,11 +49,11 @@ public function create(Dsn $dsn): TransportInterface $to = $dsn->getRequiredOption('to'); $from = $dsn->getRequiredOption('from'); - return (new FakeChatEmailTransport($this->mailer, $to, $from))->setHost($mailerTransport); + return (new FakeChatEmailTransport($this->mailer, $to, $from, $this->client, $this->dispatcher))->setHost($mailerTransport); } if ('fakechat+logger' === $scheme) { - return new FakeChatLoggerTransport($this->logger); + return new FakeChatLoggerTransport($this->logger, $this->client, $this->dispatcher); } throw new UnsupportedSchemeException($dsn, 'fakechat', $this->getSupportedSchemes()); diff --git a/src/Symfony/Component/Notifier/Bridge/FakeSms/FakeSmsTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/FakeSms/FakeSmsTransportFactory.php index 55f2162d641d5..f809ce6ad0787 100644 --- a/src/Symfony/Component/Notifier/Bridge/FakeSms/FakeSmsTransportFactory.php +++ b/src/Symfony/Component/Notifier/Bridge/FakeSms/FakeSmsTransportFactory.php @@ -17,6 +17,8 @@ use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\TransportInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; /** * @author James Hemery @@ -28,9 +30,9 @@ final class FakeSmsTransportFactory extends AbstractTransportFactory protected $mailer; protected $logger; - public function __construct(MailerInterface $mailer, LoggerInterface $logger) + public function __construct(MailerInterface $mailer, LoggerInterface $logger, EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null) { - parent::__construct(); + parent::__construct($dispatcher, $client); $this->mailer = $mailer; $this->logger = $logger; @@ -48,11 +50,11 @@ public function create(Dsn $dsn): TransportInterface $to = $dsn->getRequiredOption('to'); $from = $dsn->getRequiredOption('from'); - return (new FakeSmsEmailTransport($this->mailer, $to, $from))->setHost($mailerTransport); + return (new FakeSmsEmailTransport($this->mailer, $to, $from, $this->client, $this->dispatcher))->setHost($mailerTransport); } if ('fakesms+logger' === $scheme) { - return new FakeSmsLoggerTransport($this->logger); + return new FakeSmsLoggerTransport($this->logger, $this->client, $this->dispatcher); } throw new UnsupportedSchemeException($dsn, 'fakesms', $this->getSupportedSchemes()); diff --git a/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatTransport.php b/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatTransport.php index 8a71a7f8e4579..98d1df16b0266 100644 --- a/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatTransport.php @@ -36,7 +36,7 @@ final class GoogleChatTransport extends AbstractTransport private $threadKey; /** - * @param string $space The space name the the webhook url "/v1/spaces//messages" + * @param string $space The space name of the webhook url "/v1/spaces//messages" * @param string $accessKey The "key" parameter of the webhook url * @param string $accessToken The "token" parameter of the webhook url * @param string|null $threadKey Opaque thread identifier string that can be specified to group messages into a single thread. diff --git a/src/Symfony/Component/Notifier/Bridge/Mercure/MercureTransportFactory.php b/src/Symfony/Component/Notifier/Bridge/Mercure/MercureTransportFactory.php index 5bdabcc58b708..f3dc556c52fbf 100644 --- a/src/Symfony/Component/Notifier/Bridge/Mercure/MercureTransportFactory.php +++ b/src/Symfony/Component/Notifier/Bridge/Mercure/MercureTransportFactory.php @@ -18,6 +18,8 @@ use Symfony\Component\Notifier\Transport\AbstractTransportFactory; use Symfony\Component\Notifier\Transport\Dsn; use Symfony\Component\Notifier\Transport\TransportInterface; +use Symfony\Contracts\EventDispatcher\EventDispatcherInterface; +use Symfony\Contracts\HttpClient\HttpClientInterface; /** * @author Mathias Arlaud @@ -26,9 +28,9 @@ final class MercureTransportFactory extends AbstractTransportFactory { private $registry; - public function __construct(HubRegistry $registry) + public function __construct(HubRegistry $registry, EventDispatcherInterface $dispatcher = null, HttpClientInterface $client = null) { - parent::__construct(); + parent::__construct($dispatcher, $client); $this->registry = $registry; } @@ -51,7 +53,7 @@ public function create(Dsn $dsn): TransportInterface throw new IncompleteDsnException(sprintf('Hub "%s" not found. Did you mean one of: "%s"?', $hubId, implode('", "', array_keys($this->registry->all())))); } - return new MercureTransport($hub, $hubId, $topic); + return new MercureTransport($hub, $hubId, $topic, $this->client, $this->dispatcher); } protected function getSupportedSchemes(): array diff --git a/src/Symfony/Component/Notifier/Bridge/Smsc/SmscTransport.php b/src/Symfony/Component/Notifier/Bridge/Smsc/SmscTransport.php index 1bf619fed0cd0..3be143194ac95 100644 --- a/src/Symfony/Component/Notifier/Bridge/Smsc/SmscTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Smsc/SmscTransport.php @@ -34,9 +34,9 @@ final class SmscTransport extends AbstractTransport private $password; private $from; - public function __construct(?string $username, ?string $password, string $from, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null) + public function __construct(string $login, string $password, string $from, HttpClientInterface $client = null, EventDispatcherInterface $dispatcher = null) { - $this->login = $username; + $this->login = $login; $this->password = $password; $this->from = $from; diff --git a/src/Symfony/Component/Process/Pipes/WindowsPipes.php b/src/Symfony/Component/Process/Pipes/WindowsPipes.php index bca84f574dbfc..968dd02629eef 100644 --- a/src/Symfony/Component/Process/Pipes/WindowsPipes.php +++ b/src/Symfony/Component/Process/Pipes/WindowsPipes.php @@ -149,7 +149,7 @@ public function readAndWrite(bool $blocking, bool $close = false): array if ($w) { @stream_select($r, $w, $e, 0, Process::TIMEOUT_PRECISION * 1E6); } elseif ($this->fileHandles) { - usleep(Process::TIMEOUT_PRECISION * 1E6); + usleep((int) (Process::TIMEOUT_PRECISION * 1E6)); } } foreach ($this->fileHandles as $type => $fileHandle) { diff --git a/src/Symfony/Component/Routing/Tests/Generator/Dumper/CompiledUrlGeneratorDumperTest.php b/src/Symfony/Component/Routing/Tests/Generator/Dumper/CompiledUrlGeneratorDumperTest.php index fedd25c71d283..64e47438386d4 100644 --- a/src/Symfony/Component/Routing/Tests/Generator/Dumper/CompiledUrlGeneratorDumperTest.php +++ b/src/Symfony/Component/Routing/Tests/Generator/Dumper/CompiledUrlGeneratorDumperTest.php @@ -123,14 +123,16 @@ public function testDumpWithSimpleLocalizedRoutes() public function testDumpWithRouteNotFoundLocalizedRoutes() { - $this->expectException(RouteNotFoundException::class); - $this->expectExceptionMessage('Unable to generate a URL for the named route "test" as such route does not exist.'); $this->routeCollection->add('test.en', (new Route('/testing/is/fun'))->setDefault('_locale', 'en')->setDefault('_canonical_route', 'test')->setRequirement('_locale', 'en')); $code = $this->generatorDumper->dump(); file_put_contents($this->testTmpFilepath, $code); $projectUrlGenerator = new CompiledUrlGenerator(require $this->testTmpFilepath, new RequestContext('/app.php'), null, 'pl_PL'); + + $this->expectException(RouteNotFoundException::class); + $this->expectExceptionMessage('Unable to generate a URL for the named route "test" as such route does not exist.'); + $projectUrlGenerator->generate('test'); } @@ -183,22 +185,25 @@ public function testDumpWithTooManyRoutes() public function testDumpWithoutRoutes() { - $this->expectException(\InvalidArgumentException::class); file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump()); $projectUrlGenerator = new CompiledUrlGenerator(require $this->testTmpFilepath, new RequestContext('/app.php')); + $this->expectException(\InvalidArgumentException::class); + $projectUrlGenerator->generate('Test', []); } public function testGenerateNonExistingRoute() { - $this->expectException(RouteNotFoundException::class); $this->routeCollection->add('Test', new Route('/test')); file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump()); $projectUrlGenerator = new CompiledUrlGenerator(require $this->testTmpFilepath, new RequestContext()); + + $this->expectException(RouteNotFoundException::class); + $projectUrlGenerator->generate('NonExisting', []); } @@ -287,66 +292,72 @@ public function testAliases() public function testTargetAliasNotExisting() { - $this->expectException(RouteNotFoundException::class); - - $this->routeCollection->addAlias('a', 'not-existing'); + $this->routeCollection->add('not-existing', new Route('/not-existing')); + $this->routeCollection->addAlias('alias', 'not-existing'); file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump()); - $compiledUrlGenerator = new CompiledUrlGenerator(require $this->testTmpFilepath, new RequestContext()); + $compiledRoutes = require $this->testTmpFilepath; + unset($compiledRoutes['alias']); + $this->expectException(RouteNotFoundException::class); + + $compiledUrlGenerator = new CompiledUrlGenerator($compiledRoutes, new RequestContext()); $compiledUrlGenerator->generate('a'); } public function testTargetAliasWithNamePrefixNotExisting() { - $this->expectException(RouteNotFoundException::class); - $subCollection = new RouteCollection(); - $subCollection->addAlias('a', 'not-existing'); + $subCollection->add('not-existing', new Route('/not-existing')); + $subCollection->addAlias('alias', 'not-existing'); $subCollection->addNamePrefix('sub_'); $this->routeCollection->addCollection($subCollection); file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump()); - $compiledUrlGenerator = new CompiledUrlGenerator(require $this->testTmpFilepath, new RequestContext()); + $compiledRoutes = require $this->testTmpFilepath; + unset($compiledRoutes['sub_alias']); - $compiledUrlGenerator->generate('sub_a'); + $this->expectException(RouteNotFoundException::class); + + $compiledUrlGenerator = new CompiledUrlGenerator($compiledRoutes, new RequestContext()); + $compiledUrlGenerator->generate('sub_alias'); } public function testCircularReferenceShouldThrowAnException() { - $this->expectException(RouteCircularReferenceException::class); - $this->expectExceptionMessage('Circular reference detected for route "b", path: "b -> a -> b".'); - $this->routeCollection->addAlias('a', 'b'); $this->routeCollection->addAlias('b', 'a'); + $this->expectException(RouteCircularReferenceException::class); + $this->expectExceptionMessage('Circular reference detected for route "b", path: "b -> a -> b".'); + $this->generatorDumper->dump(); } public function testDeepCircularReferenceShouldThrowAnException() { - $this->expectException(RouteCircularReferenceException::class); - $this->expectExceptionMessage('Circular reference detected for route "b", path: "b -> c -> b".'); - $this->routeCollection->addAlias('a', 'b'); $this->routeCollection->addAlias('b', 'c'); $this->routeCollection->addAlias('c', 'b'); + $this->expectException(RouteCircularReferenceException::class); + $this->expectExceptionMessage('Circular reference detected for route "b", path: "b -> c -> b".'); + $this->generatorDumper->dump(); } public function testIndirectCircularReferenceShouldThrowAnException() { - $this->expectException(RouteCircularReferenceException::class); - $this->expectExceptionMessage('Circular reference detected for route "b", path: "b -> c -> a -> b".'); - $this->routeCollection->addAlias('a', 'b'); $this->routeCollection->addAlias('b', 'c'); $this->routeCollection->addAlias('c', 'a'); + $this->expectException(RouteCircularReferenceException::class); + $this->expectExceptionMessage('Circular reference detected for route "b", path: "b -> c -> a -> b".'); + $this->generatorDumper->dump(); } diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index 80ea6903dad25..0d0181ae84da9 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -378,32 +378,32 @@ protected function instantiateObject(array &$data, string $class, array &$contex } elseif ($allowed && !$ignored && (isset($data[$key]) || \array_key_exists($key, $data))) { $parameterData = $data[$key]; if (null === $parameterData && $constructorParameter->allowsNull()) { - $params[] = null; + $params[$paramName] = null; $unsetKeys[] = $key; continue; } try { - $params[] = $this->denormalizeParameter($reflectionClass, $constructorParameter, $paramName, $parameterData, $context, $format); + $params[$paramName] = $this->denormalizeParameter($reflectionClass, $constructorParameter, $paramName, $parameterData, $context, $format); } catch (NotNormalizableValueException $exception) { if (!isset($context['not_normalizable_value_exceptions'])) { throw $exception; } $context['not_normalizable_value_exceptions'][] = $exception; - $params[] = $parameterData; + $params[$paramName] = $parameterData; } $unsetKeys[] = $key; } elseif (\array_key_exists($key, $context[static::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class] ?? [])) { - $params[] = $context[static::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class][$key]; + $params[$paramName] = $context[static::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class][$key]; } elseif (\array_key_exists($key, $this->defaultContext[self::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class] ?? [])) { - $params[] = $this->defaultContext[self::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class][$key]; + $params[$paramName] = $this->defaultContext[self::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class][$key]; } elseif ($constructorParameter->isDefaultValueAvailable()) { - $params[] = $constructorParameter->getDefaultValue(); + $params[$paramName] = $constructorParameter->getDefaultValue(); } elseif ($constructorParameter->hasType() && $constructorParameter->getType()->allowsNull()) { - $params[] = null; + $params[$paramName] = null; } else { if (!isset($context['not_normalizable_value_exceptions'])) { $missingConstructorArguments[] = $constructorParameter->name; @@ -458,6 +458,15 @@ protected function instantiateObject(array &$data, string $class, array &$contex unset($context['has_constructor']); + if (!$reflectionClass->isInstantiable()) { + throw NotNormalizableValueException::createForUnexpectedDataType( + sprintf('Failed to create object because the class "%s" is not instantiable.', $class), + $data, + ['unknown'], + $context['deserialization_path'] ?? null + ); + } + return new $class(); } diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php index 79ede1a90e698..cd24de5840f5b 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php @@ -403,6 +403,14 @@ public function denormalize($data, string $type, string $format = null, array $c ? $this->classDiscriminatorResolver->getTypeForMappedObject($object) : $this->getAttributeValue($object, $attribute, $format, $attributeContext); } catch (NoSuchPropertyException $e) { + } catch (UninitializedPropertyException $e) { + if (!($context[self::SKIP_UNINITIALIZED_VALUES] ?? $this->defaultContext[self::SKIP_UNINITIALIZED_VALUES] ?? true)) { + throw $e; + } + } catch (\Error $e) { + if (!(($context[self::SKIP_UNINITIALIZED_VALUES] ?? $this->defaultContext[self::SKIP_UNINITIALIZED_VALUES] ?? true) && $this->isUninitializedValueError($e))) { + throw $e; + } } } @@ -524,7 +532,7 @@ private function validateAndDenormalize(array $types, string $currentClass, stri } break; case Type::BUILTIN_TYPE_INT: - if (ctype_digit($data) || '-' === $data[0] && ctype_digit(substr($data, 1))) { + if (ctype_digit($data) || isset($data[0]) && '-' === $data[0] && ctype_digit(substr($data, 1))) { $data = (int) $data; } else { throw NotNormalizableValueException::createForUnexpectedDataType(sprintf('The type of the "%s" attribute for class "%s" must be int ("%s" given).', $attribute, $currentClass, $data), $data, [Type::BUILTIN_TYPE_INT], $context['deserialization_path'] ?? null); diff --git a/src/Symfony/Component/Serializer/Normalizer/BackedEnumNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/BackedEnumNormalizer.php index e7efb0057c09f..995033516c052 100644 --- a/src/Symfony/Component/Serializer/Normalizer/BackedEnumNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/BackedEnumNormalizer.php @@ -65,7 +65,7 @@ public function denormalize($data, string $type, string $format = null, array $c return $type::from($data); } catch (\ValueError $e) { if (isset($context['has_constructor'])) { - throw new InvalidArgumentException('The data must belong to a backed enumeration of type '.$type); + throw new InvalidArgumentException('The data must belong to a backed enumeration of type '.$type, 0, $e); } throw NotNormalizableValueException::createForUnexpectedDataType('The data must belong to a backed enumeration of type '.$type, $data, [$type], $context['deserialization_path'] ?? null, true, 0, $e); diff --git a/src/Symfony/Component/Serializer/Serializer.php b/src/Symfony/Component/Serializer/Serializer.php index 3b9943740e49b..607dc9963d417 100644 --- a/src/Symfony/Component/Serializer/Serializer.php +++ b/src/Symfony/Component/Serializer/Serializer.php @@ -197,6 +197,7 @@ public function normalize($data, string $format = null, array $context = []) * {@inheritdoc} * * @throws NotNormalizableValueException + * @throws PartialDenormalizationException Occurs when one or more properties of $type fails to denormalize */ public function denormalize($data, string $type, string $format = null, array $context = []) { diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/DummyNullableInt.php b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyNullableInt.php new file mode 100644 index 0000000000000..2671f66a97aff --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyNullableInt.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +/** + * @author Nicolas PHILIPPE + */ +class DummyNullableInt +{ + public int|null $value = null; +} diff --git a/src/Symfony/Component/Serializer/Tests/Php80Dummy.php b/src/Symfony/Component/Serializer/Tests/Fixtures/Php80Dummy.php similarity index 84% rename from src/Symfony/Component/Serializer/Tests/Php80Dummy.php rename to src/Symfony/Component/Serializer/Tests/Fixtures/Php80Dummy.php index baa75b1246659..85c354314fccb 100644 --- a/src/Symfony/Component/Serializer/Tests/Php80Dummy.php +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/Php80Dummy.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -namespace Symfony\Component\Serializer\Tests; +namespace Symfony\Component\Serializer\Tests\Fixtures; final class Php80Dummy { diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/Php80WithOptionalConstructorParameter.php b/src/Symfony/Component/Serializer/Tests/Fixtures/Php80WithOptionalConstructorParameter.php new file mode 100644 index 0000000000000..6593635df4125 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/Php80WithOptionalConstructorParameter.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +final class Php80WithOptionalConstructorParameter +{ + public function __construct( + public string $one, + public string $two, + public ?string $three = null, + ) { + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php index 3397cb5047a79..2500327815cf1 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php @@ -15,6 +15,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\PropertyInfo\Extractor\PhpDocExtractor; use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Symfony\Component\Serializer\Exception\NotNormalizableValueException; use Symfony\Component\Serializer\Mapping\AttributeMetadata; use Symfony\Component\Serializer\Mapping\ClassMetadata; use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory; @@ -32,6 +33,7 @@ use Symfony\Component\Serializer\Tests\Fixtures\NullableOptionalConstructorArgumentDummy; use Symfony\Component\Serializer\Tests\Fixtures\StaticConstructorDummy; use Symfony\Component\Serializer\Tests\Fixtures\StaticConstructorNormalizer; +use Symfony\Component\Serializer\Tests\Fixtures\UnitEnumDummy; use Symfony\Component\Serializer\Tests\Fixtures\VariadicConstructorTypedArgsDummy; /** @@ -279,4 +281,16 @@ public function testIgnore() $this->assertSame([], $normalizer->normalize($dummy)); } + + /** + * @requires PHP 8.1.2 + */ + public function testDenormalizeWhenObjectNotInstantiable() + { + $this->expectException(NotNormalizableValueException::class); + + $normalizer = new ObjectNormalizer(); + + $normalizer->denormalize('{}', UnitEnumDummy::class); + } } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/Features/SkipUninitializedValuesTestTrait.php b/src/Symfony/Component/Serializer/Tests/Normalizer/Features/SkipUninitializedValuesTestTrait.php index 0d17ba46dc167..596b3404b7e24 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/Features/SkipUninitializedValuesTestTrait.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/Features/SkipUninitializedValuesTestTrait.php @@ -12,14 +12,14 @@ namespace Symfony\Component\Serializer\Tests\Normalizer\Features; use Symfony\Component\PropertyAccess\Exception\UninitializedPropertyException; -use Symfony\Component\Serializer\Normalizer\NormalizerInterface; +use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; /** * Test AbstractObjectNormalizer::SKIP_UNINITIALIZED_VALUES. */ trait SkipUninitializedValuesTestTrait { - abstract protected function getNormalizerForSkipUninitializedValues(): NormalizerInterface; + abstract protected function getNormalizerForSkipUninitializedValues(): AbstractObjectNormalizer; /** * @requires PHP 7.4 @@ -33,6 +33,15 @@ public function testSkipUninitializedValues(array $context) $normalizer = $this->getNormalizerForSkipUninitializedValues(); $result = $normalizer->normalize($object, null, $context); $this->assertSame(['initialized' => 'value'], $result); + + $normalizer->denormalize( + ['unInitialized' => 'value'], + TypedPropertiesObjectWithGetters::class, + null, + ['object_to_populate' => $objectToPopulate = new TypedPropertiesObjectWithGetters(), 'deep_object_to_populate' => true] + $context + ); + + $this->assertSame('value', $objectToPopulate->getUninitialized()); } public function skipUninitializedValuesFlagProvider(): iterable diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php index e90f221ebc1a9..f6b2c3e69ed9b 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php @@ -496,7 +496,7 @@ protected function getNormalizerForCacheableObjectAttributesTest(): GetSetMethod return new GetSetMethodNormalizer(); } - protected function getNormalizerForSkipUninitializedValues(): NormalizerInterface + protected function getNormalizerForSkipUninitializedValues(): GetSetMethodNormalizer { return new GetSetMethodNormalizer(new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()))); } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php index 868bcce250bbf..a909274ebd1dd 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php @@ -39,6 +39,7 @@ use Symfony\Component\Serializer\Tests\Fixtures\OtherSerializedNameDummy; use Symfony\Component\Serializer\Tests\Fixtures\Php74Dummy; use Symfony\Component\Serializer\Tests\Fixtures\Php74DummyPrivate; +use Symfony\Component\Serializer\Tests\Fixtures\Php80Dummy; use Symfony\Component\Serializer\Tests\Fixtures\SiblingHolder; use Symfony\Component\Serializer\Tests\Normalizer\Features\AttributesTestTrait; use Symfony\Component\Serializer\Tests\Normalizer\Features\CacheableObjectAttributesTestTrait; @@ -56,7 +57,6 @@ use Symfony\Component\Serializer\Tests\Normalizer\Features\TypedPropertiesObject; use Symfony\Component\Serializer\Tests\Normalizer\Features\TypedPropertiesObjectWithGetters; use Symfony\Component\Serializer\Tests\Normalizer\Features\TypeEnforcementTestTrait; -use Symfony\Component\Serializer\Tests\Php80Dummy; /** * @author Kévin Dunglas diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php index 1d1de25b4b698..3257c30fd8578 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php @@ -26,7 +26,6 @@ use Symfony\Component\Serializer\Normalizer\AbstractObjectNormalizer; use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer; use Symfony\Component\Serializer\Normalizer\DenormalizerInterface; -use Symfony\Component\Serializer\Normalizer\NormalizerInterface; use Symfony\Component\Serializer\Normalizer\PropertyNormalizer; use Symfony\Component\Serializer\Serializer; use Symfony\Component\Serializer\SerializerInterface; @@ -455,7 +454,7 @@ protected function getNormalizerForCacheableObjectAttributesTest(): AbstractObje return new PropertyNormalizer(); } - protected function getNormalizerForSkipUninitializedValues(): NormalizerInterface + protected function getNormalizerForSkipUninitializedValues(): PropertyNormalizer { return new PropertyNormalizer(new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()))); } diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index 12d8eeefdd1a0..447e0f882a8c5 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -21,6 +21,7 @@ use Symfony\Component\Serializer\Encoder\DecoderInterface; use Symfony\Component\Serializer\Encoder\EncoderInterface; use Symfony\Component\Serializer\Encoder\JsonEncoder; +use Symfony\Component\Serializer\Encoder\XmlEncoder; use Symfony\Component\Serializer\Exception\ExtraAttributesException; use Symfony\Component\Serializer\Exception\InvalidArgumentException; use Symfony\Component\Serializer\Exception\LogicException; @@ -61,12 +62,14 @@ use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberOne; use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberThree; use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo; +use Symfony\Component\Serializer\Tests\Fixtures\DummyNullableInt; use Symfony\Component\Serializer\Tests\Fixtures\DummyObjectWithEnumConstructor; use Symfony\Component\Serializer\Tests\Fixtures\DummyObjectWithEnumProperty; use Symfony\Component\Serializer\Tests\Fixtures\DummyWithObjectOrNull; use Symfony\Component\Serializer\Tests\Fixtures\FalseBuiltInDummy; use Symfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy; use Symfony\Component\Serializer\Tests\Fixtures\Php74Full; +use Symfony\Component\Serializer\Tests\Fixtures\Php80WithOptionalConstructorParameter; use Symfony\Component\Serializer\Tests\Fixtures\Php80WithPromotedTypedConstructor; use Symfony\Component\Serializer\Tests\Fixtures\TraversableDummy; use Symfony\Component\Serializer\Tests\Fixtures\WithTypedConstructor; @@ -740,6 +743,19 @@ public function testDeserializeWrappedScalar() $this->assertSame(42, $serializer->deserialize('{"wrapper": 42}', 'int', 'json', [UnwrappingDenormalizer::UNWRAP_PATH => '[wrapper]'])); } + /** + * @requires PHP 8 + */ + public function testDeserializeNullableIntInXml() + { + $extractor = new PropertyInfoExtractor([], [new ReflectionExtractor()]); + $serializer = new Serializer([new ObjectNormalizer(null, null, null, $extractor)], ['xml' => new XmlEncoder()]); + + $obj = $serializer->deserialize('', DummyNullableInt::class, 'xml'); + $this->assertInstanceOf(DummyNullableInt::class, $obj); + $this->assertNull($obj->value); + } + public function testUnionTypeDeserializable() { $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader())); @@ -1418,6 +1434,61 @@ public static function provideCollectDenormalizationErrors() [new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()))], ]; } + + /** + * @requires PHP 8 + */ + public function testPartialDenormalizationWithMissingConstructorTypes() + { + $json = '{"one": "one string", "three": "three string"}'; + + $extractor = new PropertyInfoExtractor([], [new ReflectionExtractor()]); + + $serializer = new Serializer( + [new ObjectNormalizer(null, null, null, $extractor)], + ['json' => new JsonEncoder()] + ); + + try { + $serializer->deserialize($json, Php80WithOptionalConstructorParameter::class, 'json', [ + DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true, + ]); + + $this->fail(); + } catch (\Throwable $th) { + $this->assertInstanceOf(PartialDenormalizationException::class, $th); + } + + $this->assertInstanceOf(Php80WithOptionalConstructorParameter::class, $object = $th->getData()); + + $this->assertSame('one string', $object->one); + $this->assertFalse(isset($object->two)); + $this->assertSame('three string', $object->three); + + $exceptionsAsArray = array_map(function (NotNormalizableValueException $e): array { + return [ + 'currentType' => $e->getCurrentType(), + 'expectedTypes' => $e->getExpectedTypes(), + 'path' => $e->getPath(), + 'useMessageForUser' => $e->canUseMessageForUser(), + 'message' => $e->getMessage(), + ]; + }, $th->getErrors()); + + $expected = [ + [ + 'currentType' => 'array', + 'expectedTypes' => [ + 'unknown', + ], + 'path' => null, + 'useMessageForUser' => true, + 'message' => 'Failed to create object because the class misses the "two" property.', + ], + ]; + + $this->assertSame($expected, $exceptionsAsArray); + } } class Model diff --git a/src/Symfony/Component/String/Tests/AbstractUnicodeTestCase.php b/src/Symfony/Component/String/Tests/AbstractUnicodeTestCase.php index d8f71ffd93d6a..83b7d03d30f79 100644 --- a/src/Symfony/Component/String/Tests/AbstractUnicodeTestCase.php +++ b/src/Symfony/Component/String/Tests/AbstractUnicodeTestCase.php @@ -94,14 +94,21 @@ public function testCodePointsAt(array $expected, string $string, int $offset, i public static function provideCodePointsAt(): array { - return [ + $data = [ [[], '', 0], [[], 'a', 1], [[0x53], 'Späßchen', 0], [[0xE4], 'Späßchen', 2], [[0xDF], 'Späßchen', -5], - [[0x260E], '☢☎❄', 1], ]; + + // Skip this set if we encounter an issue in PCRE2 + // @see https://github.com/PCRE2Project/pcre2/issues/361 + if (3 === grapheme_strlen('☢☎❄')) { + $data[] = [[0x260E], '☢☎❄', 1]; + } + + return $data; } public static function provideLength(): array diff --git a/src/Symfony/Component/Validator/Constraints/Collection.php b/src/Symfony/Component/Validator/Constraints/Collection.php index 3f4adb5ac5286..b151f0cd4df67 100644 --- a/src/Symfony/Component/Validator/Constraints/Collection.php +++ b/src/Symfony/Component/Validator/Constraints/Collection.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Validator\Constraints; +use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; /** @@ -41,9 +42,10 @@ class Collection extends Composite */ public function __construct($fields = null, array $groups = null, $payload = null, bool $allowExtraFields = null, bool $allowMissingFields = null, string $extraFieldsMessage = null, string $missingFieldsMessage = null) { - // no known options set? $fields is the fields array if (\is_array($fields) - && !array_intersect(array_keys($fields), ['groups', 'fields', 'allowExtraFields', 'allowMissingFields', 'extraFieldsMessage', 'missingFieldsMessage'])) { + && (($firstField = reset($fields)) instanceof Constraint + || ($firstField[0] ?? null) instanceof Constraint + )) { $fields = ['fields' => $fields]; } diff --git a/src/Symfony/Component/Validator/Constraints/Email.php b/src/Symfony/Component/Validator/Constraints/Email.php index 7976cc4ee3814..b37c6054437b9 100644 --- a/src/Symfony/Component/Validator/Constraints/Email.php +++ b/src/Symfony/Component/Validator/Constraints/Email.php @@ -32,7 +32,7 @@ class Email extends Constraint public const INVALID_FORMAT_ERROR = 'bd79c0ab-ddba-46cc-a703-a7a4b08de310'; protected static $errorNames = [ - self::INVALID_FORMAT_ERROR => 'STRICT_CHECK_FAILED_ERROR', + self::INVALID_FORMAT_ERROR => 'INVALID_FORMAT_ERROR', ]; /** diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf index fce6604a533cd..0487d4225cc3b 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. لا يسمح باستخدام أحرف التراكب المخفية. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + امتداد الملف غير صحيح ({{ extension }}). الامتدادات المسموح بها هي {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf index b3e0999304ae7..756ca28847f40 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.az.xlf @@ -402,6 +402,34 @@ The value of the netmask should be between {{ min }} and {{ max }}. Şəbəkə maskasının dəyəri {{ min }} və {{ max }} arasında olmalıdır. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Fayl adı çox uzundur. {{ filename_max_length }} və ya daha az simvol olmalıdır. + + + The password strength is too low. Please use a stronger password. + Parolun gücü çox zəifdir. Zəhmət olmasa, daha güclü bir parol istifadə edin. + + + This value contains characters that are not allowed by the current restriction-level. + Bu dəyərdə cari məhdudiyyət səviyyəsi tərəfindən icazə verilməyən simvollar var. + + + Using invisible characters is not allowed. + Görünməz simvolların istifadəsinə icazə verilmir. + + + Mixing numbers from different scripts is not allowed. + Fərqli skriptlərdən nömrələrin qarışdırılmasına icazə verilmir. + + + Using hidden overlay characters is not allowed. + Gizli örtülü simvolların istifadəsinə icazə verilmir. + + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Faylın uzantısı yanlışdır ({{ extension }}). İcazə verilən uzantılar {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf index 32bfbabe1745b..bc1c3e4d51011 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf @@ -426,6 +426,14 @@ Using hidden overlay characters is not allowed. Verstecke Overlay-Zeichen sind nicht erlaubt. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Die Dateiendung ist ungültig ({{ extension }}). Gültige Dateiendungen sind {{ extensions }}. + + + The detected character encoding is invalid ({{ detected }}). Allowed encodings are {{ encodings }}. + Der erkannte Zeichensatz ist nicht gültig ({{ detected }}). Gültige Zeichensätze sind {{ encodings }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf index b4a432d87e44c..9c624df363853 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Δεν επιτρέπεται η χρήση κρυφών χαρακτήρων επικάλυψης. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Η επέκταση του αρχείου δεν είναι έγκυρη ({{ extension }}). Οι επιτρεπτόμενες επεκτάσεις είναι {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf index aaf6ada6fc089..6a49fb39f627d 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf @@ -426,6 +426,14 @@ Using hidden overlay characters is not allowed. Using hidden overlay characters is not allowed. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + + + The detected character encoding is invalid ({{ detected }}). Allowed encodings are {{ encodings }}. + The detected character encoding is invalid ({{ detected }}). Allowed encodings are {{ encodings }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf index 55f21271f1bc9..e0003901f8641 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. No está permitido el uso de caracteres superpuestos ocultos. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + La extensión del archivo no es válida ({{ extension }}). Las extensiones permitidas son {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf index 0a796a2dbaeb0..565ca29fb258f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Piilotettuja tarkemerkkejä ei saa käyttää. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Tiedostopääte ({{ extension }}) on virheellinen. Sallitut tiedostopäätteet ovat: {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf index a1186891f4ad2..bc4513bc46951 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf @@ -426,6 +426,14 @@ Using hidden overlay characters is not allowed. Utiliser des caractères de superposition cachés n'est pas autorisé. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + L'extension du fichier est invalide ({{ extension }}). Les extensions autorisées sont {{ extensions }}. + + + The detected character encoding is invalid ({{ detected }}). Allowed encodings are {{ encodings }}. + L'encodage de caractères détecté est invalide ({{ detected }}). Les encodages autorisés sont {{ encodings }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf index 0b57fc98ef56b..327b8d50f7738 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Korištenje skrivenih preklapajućih znakova nije dopušteno. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Ekstenzija datoteke nije valjana ({{ extension }}). Dozvoljene ekstenzije su {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf index c6883c3f7a368..7c117f13138c8 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Rejtett módosító karakterek használata nem megengedett. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + A fájl kiterjesztése érvénytelen ({{ extension }}). Engedélyezett kiterjesztések: {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf index 29960b3da34e5..5ddda209428bc 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Penggunaan karakter overlay yang tersembunyi tidak diperbolehkan. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Ekstensi file tidak valid ({{ extension }}). Ekstensi yang diperbolehkan adalah {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf index d9d9d06611d42..4781b986d3681 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Non è consentito utilizzare caratteri sovrapposti nascosti. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + L'estensione del file non è valida ({{ extension }}). Le estensioni consentite sono {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf index 7e4cac5434a17..9bbf0df3ec191 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. 隠れたオーバレイ文字は使用できません。 + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + ファイルの拡張子が無効です({{ extension }})。有効な拡張子は{{ extensions }}です。 + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf index 32b379e300495..c480904a20119 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf @@ -36,11 +36,11 @@ This field was not expected. - Nebuvo tikimasi Šis laukas. + Nebuvo tikimasi šio laukelio. This field is missing. - Šiame lauke yra dingęs. + Trūkstamas laukelis. This value is not a valid date. @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Draudžiama naudoti paslėptus perdangos simbolius. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Failo plėtinys netinkamas ({{ extension }}). Leidžiami plėtiniai yra {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf index 10768d0e01baf..fa2380040d9de 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Slēptu pārklājuma rakstzīmju izmantošana nav atļauta. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Faila paplašinājums nav derīgs ({{ extension }}). Atļautie paplašinājumi ir {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.mk.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.mk.xlf index eb15989839b8a..12ff9b96633ab 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.mk.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.mk.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Не е дозволено користење на скриени знаци за преклопување. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Зголемувања на датотеката е неважечка ({{ extension }}). Дозволени зголемувања се ({{ extensions }}). + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf index 45cefb3bbd59f..92d7651216bca 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Het gebruik van verborgen overlay-tekens is niet toegestaan. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + De extensie van het bestand is ongeldig ({{ extension }}). Toegestane extensies zijn {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf index e20f490970958..449e05b698103 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf @@ -426,6 +426,14 @@ Using hidden overlay characters is not allowed. Używanie ukrytych znaków nakładki jest niedozwolone. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Rozszerzenie pliku jest nieprawidłowe ({{ extension }}). Dozwolone rozszerzenia to {{ extensions }}. + + + The detected character encoding is invalid ({{ detected }}). Allowed encodings are {{ encodings }}. + Wykryte kodowanie znaków ({{ detected }}) jest nieprawidłowe. Dozwolone kodowania to {{ encodings }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf index 9c3b00e01521f..4b15617702c42 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Não é permitido usar caracteres de sobreposição ocultos. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + A extensão do ficheiro é inválida ({{ extension }}). As extensões permitidas são {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf index 6c826a11a8169..f10fe4df78a21 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Folosirea caracterelor invizibile suprapuse nu este permisă. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Extensia fișierului este invalidă ({{ extension }}). Extensiile permise sunt {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf index 2b66b1eafd954..a457d18f1891e 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Использование невидимых символов наложения запрещено. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Недопустимое расширение файла ({{ extension }}). Разрешенные расширения: {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf index 55a811134dae5..55d5b9713ac8b 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sk.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Hodnota masky siete by mala byť medzi {{ min }} a {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Názov súboru je príliš dlhý. Mal by mať {{ filename_max_length }} znak alebo menej.|Názov súboru je príliš dlhý. Mal by mať {{ filename_max_length }} znaky alebo menej.|Názov súboru je príliš dlhý. Mal by mať {{ filename_max_length }} znakov alebo menej. + + + The password strength is too low. Please use a stronger password. + Sila hesla je príliš nízka. Použite silnejšie heslo. + + + This value contains characters that are not allowed by the current restriction-level. + Táto hodnota obsahuje znaky, ktoré nie sú povolené aktuálnou úrovňou obmedzenia. + + + Using invisible characters is not allowed. + Používanie neviditeľných znakov nie je povolené. + + + Mixing numbers from different scripts is not allowed. + Miešanie čísel z rôznych skriptov nie je povolené. + + + Using hidden overlay characters is not allowed. + Používanie skrytých prekryvných znakov nie je povolené. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf index 462a7752febe5..ff7c06a7cb0f3 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Uporaba skritih prekrivnih znakov ni dovoljena. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Končnica datoteke ni veljavna ({{ extension }}). Dovoljene so naslednje končnice: {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf index 6c0acb9fdf43f..ae49abb468592 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf @@ -386,6 +386,50 @@ This value is not a valid International Securities Identification Number (ISIN). Kjo vlerë nuk është një numër i vlefshëm identifikues ndërkombëtar i sigurisë (ISIN). + + This value should be a valid expression. + Kjo vlerë duhet të jetë një shprehje e vlefshme. + + + This value is not a valid CSS color. + Kjo vlerë nuk është një ngjyrë e vlefshme CSS. + + + This value is not a valid CIDR notation. + Kjo vlerë nuk është një shënim i vlefshëm CIDR. + + + The value of the netmask should be between {{ min }} and {{ max }}. + Vlera e maskës së rrjetit duhet të jetë ndërmjet {{ min }} dhe {{ max }}. + + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Emri i skedarit është shumë i gjatë. Duhet të ketë maksimumi {{ filename_max_length }} karakter ose më pak.|Emri i skedarit është shumë i gjatë. Duhet të ketë maksimumi {{ filename_max_length }} karaktere ose më pak. + + + The password strength is too low. Please use a stronger password. + Fuqia e fjalëkalimit është shumë e ulët. Ju lutemi përdorni një fjalëkalim më të fortë. + + + This value contains characters that are not allowed by the current restriction-level. + Kjo vlerë përmban karaktere që nuk lejohen nga niveli aktual i kufizimit. + + + Using invisible characters is not allowed. + Përdorimi i karaktereve të padukshme nuk lejohet. + + + Mixing numbers from different scripts is not allowed. + Përzierja e numrave nga skriptet e ndryshme nuk lejohet. + + + Using hidden overlay characters is not allowed. + Përdorimi i karaktereve të mbivendosura të fshehura nuk lejohet. + + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Shtesa e skedarit është e pavlefshme ({{ extension }}). Shtesat e lejuara janë {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf index 27e4aabb71e78..9dd577fa650ee 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Cyrl.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Коришћење скривених преклопних карактера није дозвољено. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Екстензија фајла није валидна ({{ extension }}). Дозвољене екстензије су {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf index 5f2402c10bbc5..e7162fa84bd25 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf @@ -4,35 +4,35 @@ This value should be false. - Vrednost bi trebalo da bude netačna. + Vrednost bi trebala da bude netačna. This value should be true. - Vrednost bi trebalo da bude tačna. + Vrednost bi trebala da bude tačna. This value should be of type {{ type }}. - Vrednost bi trebalo da bude tipa {{ type }}. + Vrednost bi trebala da bude tipa {{ type }}. This value should be blank. - Vrednost bi trebalo da bude prazna. + Vrednost bi trebala da bude prazna. The value you selected is not a valid choice. - Odabrana vrednost nije validan izbor. + Vrednost koju ste izabrali nije validan izbor. You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. - Morate odabrati bar {{ limit }} mogućnost.|Morate odabrati bar {{ limit }} mogućnosti.|Morate odabrati bar {{ limit }} mogućnosti. + Morate izabrati najmanje {{ limit }} mogućnosti.|Morate izabrati najmanje {{ limit }} mogućnosti. You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. - Morate odabrati najviše {{ limit }} mogućnost.|Morate odabrati najviše {{ limit }} mogućnosti.|Morate odabrati najviše {{ limit }} mogućnosti. + Morate izabrati najviše {{ limit }} mogućnosti.|Morate izabrati najviše {{ limit }} mogućnosti. One or more of the given values is invalid. - Jedna ili više vrednosti nisu validne. + Jedna ili više od odabranih vrednosti nisu validne. This field was not expected. @@ -44,11 +44,11 @@ This value is not a valid date. - Vrednost nije validan datum. + Vrednost nije validna kao datum. This value is not a valid datetime. - Vrednost nije validno vreme. + Vrednost nije validna kao datum i vreme. This value is not a valid email address. @@ -56,47 +56,47 @@ The file could not be found. - Datoteka ne može biti pronađena. + Fajl ne može biti pronađen. The file is not readable. - Datoteka nije čitljiva. + Fajl nije čitljiv. The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}. - Datoteka je prevelika ({{ size }} {{ suffix }}). Najveća dozvoljena veličina je {{ limit }} {{ suffix }}. + Fajl je preveliki ({{ size }} {{ suffix }}). Najveća dozvoljena veličina fajla je {{ limit }} {{ suffix }}. The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}. - MIME tip datoteke nije validan ({{ type }}). Dozvoljeni MIME tipovi su {{ types }}. + MIME tip fajla nije validan ({{ type }}). Dozvoljeni MIME tipovi su {{ types }}. This value should be {{ limit }} or less. - Vrednost bi trebalo da bude {{ limit }} ili manje. + Vrednost bi trebala da bude {{ limit }} ili manje. This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. - Vrednost je predugačka. Trebalo bi da ima {{ limit }} karakter ili manje.|Vrednost je predugačka. Trebalo bi da ima {{ limit }} karaktera ili manje.|Vrednost je predugačka. Trebalo bi da ima {{ limit }} karaktera ili manje. + Vrednost je predugačka. Trebalo bi da ima {{ limit }} karaktera ili manje.|Vrednost je predugačka. Trebalo bi da ima {{ limit }} karaktera ili manje. This value should be {{ limit }} or more. - Vrednost bi trebalo da bude {{ limit }} ili više. + Vrednost bi trebala da bude {{ limit }} ili više. This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. - Vrednost je prekratka. Trebalo bi da ima {{ limit }} karakter ili više.|Vrednost je prekratka. Trebalo bi da ima {{ limit }} karaktera ili više.|Vrednost je prekratka. Trebalo bi da ima {{ limit }} karaktera ili više. + Vrednost je prekratka. Trebalo bi da ima {{ limit }} karaktera ili više.|Vrednost je prekratka. Trebalo bi da ima {{ limit }} karaktera ili više. This value should not be blank. - Vrednost ne bi trebalo da bude prazna. + Vrednost ne bi trebala da bude prazna. This value should not be null. - Vrednost ne bi trebalo da bude prazna. + Vrednost ne bi trebala da bude null. This value should be null. - Vrednost bi trebalo da bude prazna. + Vrednost bi trebala da bude null. This value is not valid. @@ -112,27 +112,27 @@ The two values should be equal. - Obe vrednosti bi trebalo da budu jednake. + Obe vrednosti bi trebale da budu jednake. The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}. - Datoteka je prevelika. Najveća dozvoljena veličina je {{ limit }} {{ suffix }}. + Fajl je preveliki. Najveća dozvoljena veličina je {{ limit }} {{ suffix }}. The file is too large. - Datoteka je prevelika. + Fajl je preveliki. The file could not be uploaded. - Datoteka ne može biti otpremljena. + Fajl ne može biti otpremljen. This value should be a valid number. - Vrednost bi trebalo da bude validan broj. + Vrednost bi trebala da bude validan broj. This file is not a valid image. - Ova datoteka nije validna slika. + Ovaj fajl nije validan kao slika. This is not a valid IP address. @@ -172,23 +172,23 @@ The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px. - Visina slike je premala ({{ height }} piksela). Najmanja dozvoljena visina je {{ min_height }} piksela. + Visina slike je preniska ({{ height }} piksela). Najmanja dozvoljena visina je {{ min_height }} piksela. This value should be the user's current password. - Vrednost bi trebalo da bude trenutna korisnička lozinka. + Vrednost bi trebala da bude trenutna korisnička lozinka. This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. - Vrednost bi trebalo da ima tačno {{ limit }} karakter.|Vrednost bi trebalo da ima tačno {{ limit }} karaktera.|Vrednost bi trebalo da ima tačno {{ limit }} karaktera. + Vrednost bi trebala da ima tačno {{ limit }} karaktera.|Vrednost bi trebala da ima tačno {{ limit }} karaktera. The file was only partially uploaded. - Datoteka je samo parcijalno otpremljena. + Fajl je samo parcijalno otpremljena. No file was uploaded. - Datoteka nije otpremljena. + Fajl nije otpremljen. No temporary folder was configured in php.ini. @@ -196,7 +196,7 @@ Cannot write temporary file to disk. - Nemoguće pisanje privremene datoteke na disk. + Nije moguće upisati privremeni fajl na disk. A PHP extension caused the upload to fail. @@ -204,79 +204,79 @@ This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. - Ova kolekcija bi trebalo da sadrži {{ limit }} ili više elemenata.|Ova kolekcija bi trebalo da sadrži {{ limit }} ili više elemenata.|Ova kolekcija bi trebalo da sadrži {{ limit }} ili više elemenata. + Ova kolekcija bi trebala da sadrži {{ limit }} ili više elemenata.|Ova kolekcija bi trebala da sadrži {{ limit }} ili više elemenata. This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. - Ova kolekcija bi trebalo da sadrži {{ limit }} ili manje elemenata.|Ova kolekcija bi trebalo da sadrži {{ limit }} ili manje elemenata.|Ova kolekcija bi trebalo da sadrži {{ limit }} ili manje elemenata. + Ova kolekcija bi trebala da sadrži {{ limit }} ili manje elemenata.|Ova kolekcija bi trebala da sadrži {{ limit }} ili manje elemenata. This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. - Ova kolekcija bi trebalo da sadrži tačno {{ limit }} element.|Ova kolekcija bi trebalo da sadrži tačno {{ limit }} elementa.|Ova kolekcija bi trebalo da sadrži tačno {{ limit }} elemenata. + Ova kolekcija bi trebala da sadrži tačno {{ limit }} element.|Ova kolekcija bi trebala da sadrži tačno {{ limit }} elementa. Invalid card number. - Broj kartice nije validan. + Nevalidan broj kartice. Unsupported card type or invalid card number. - Tip kartice nije podržan ili broj kartice nije validan. + Nevalidan broj kartice ili nepodržan tip kartice. This is not a valid International Bank Account Number (IBAN). - Ovo nije validan međunarodni broj bankovnog računa (IBAN). + Nevalidan međunarodni broj bankovnog računa (IBAN). This value is not a valid ISBN-10. - Ovo nije validan ISBN-10. + Nevalidna vrednost ISBN-10. This value is not a valid ISBN-13. - Ovo nije validan ISBN-13. + Nevalidna vrednost ISBN-13. This value is neither a valid ISBN-10 nor a valid ISBN-13. - Ovo nije validan ISBN-10 ili ISBN-13. + Vrednost nije ni validan ISBN-10 ni validan ISBN-13. This value is not a valid ISSN. - Ovo nije validan ISSN. + Nevalidna vrednost ISSN. This value is not a valid currency. - Ovo nije validna valuta. + Vrednost nije validna valuta. This value should be equal to {{ compared_value }}. - Ova vrednost bi trebalo da bude jednaka {{ compared_value }}. + Ova vrednost bi trebala da bude jednaka {{ compared_value }}. This value should be greater than {{ compared_value }}. - Ova vrednost bi trebalo da bude veća od {{ compared_value }}. + Ova vrednost bi trebala da bude veća od {{ compared_value }}. This value should be greater than or equal to {{ compared_value }}. - Ova vrednost bi trebalo da bude veća ili jednaka {{ compared_value }}. + Ova vrednost bi trebala da je veća ili jednaka {{ compared_value }}. This value should be identical to {{ compared_value_type }} {{ compared_value }}. - Ova vrednost bi trebalo da bude identična sa {{ compared_value_type }} {{ compared_value }}. + Ova vrednost bi trebala da bude identična sa {{ compared_value_type }} {{ compared_value }}. This value should be less than {{ compared_value }}. - Ova vrednost bi trebalo da bude manja od {{ compared_value }}. + Ova vrednost bi trebala da bude manja od {{ compared_value }}. This value should be less than or equal to {{ compared_value }}. - Ova vrednost bi trebalo da bude manja ili jednaka {{ compared_value }}. + Ova vrednost bi trebala da bude manja ili jednaka {{ compared_value }}. This value should not be equal to {{ compared_value }}. - Ova vrednost ne bi trebalo da bude jednaka {{ compared_value }}. + Ova vrednost ne bi trebala da bude jednaka {{ compared_value }}. This value should not be identical to {{ compared_value_type }} {{ compared_value }}. - Ova vrednost ne bi trebalo da bude identična sa {{ compared_value_type }} {{ compared_value }}. + Ova vrednost ne bi trebala da bude identična sa {{ compared_value_type }} {{ compared_value }}. The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. @@ -292,7 +292,7 @@ The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. - Slika je pejzažno orijentisana ({{ width }}x{{ height }} piksela). Pejzažna orijentisane slike nisu dozvoljene. + Slika je pejzažno orijentisana ({{ width }}x{{ height }} piksela). Pejzažno orijentisane slike nisu dozvoljene. The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. @@ -300,7 +300,7 @@ An empty file is not allowed. - Prazna datoteka nije dozvoljena. + Prazan fajl nije dozvoljen. The host could not be resolved. @@ -324,7 +324,7 @@ This value should be a multiple of {{ compared_value }}. - Ova vrednost bi trebalo da bude deljiva sa {{ compared_value }}. + Ova vrednost bi trebala da bude višestruka u odnosu na {{ compared_value }}. This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. @@ -332,7 +332,7 @@ This value should be valid JSON. - Ova vrednost bi trebalo da bude validan JSON. + Ova vrednost bi trebala da bude validan JSON. This collection should contain only unique elements. @@ -344,7 +344,7 @@ This value should be either positive or zero. - Ova vrednost bi trebala biti pozitivna ili nula. + Ova vrednost bi trebala biti ili pozitivna ili nula. This value should be negative. @@ -352,7 +352,7 @@ This value should be either negative or zero. - Ova vrednost bi trebala biti negativna ili nula. + Ova vrednost bi trebala biti ili negativna ili nula. This value is not a valid timezone. @@ -360,7 +360,7 @@ This password has been leaked in a data breach, it must not be used. Please use another password. - Ova lozinka je kompromitovana prilikom prethodnih napada, nemojte je koristiti. Koristite drugu lozinku. + Lozinka je kompromitovana prilikom curenja podataka usled napada, nemojte je koristiti. Koristite drugu lozinku. This value should be between {{ min }} and {{ max }}. @@ -372,11 +372,11 @@ The number of elements in this collection should be a multiple of {{ compared_value }}. - Broj elemenata u ovoj kolekciji bi trebalo da bude deljiv sa {{ compared_value }}. + Broj elemenata u ovoj kolekciji bi trebala da bude višestruka u odnosu na {{ compared_value }}. This value should satisfy at least one of the following constraints: - Ova vrednost bi trebalo da zadovoljava namjanje jedno od narednih ograničenja: + Ova vrednost bi trebala da zadovoljava namjanje jedno od narednih ograničenja: Each element of this collection should satisfy its own set of constraints. @@ -384,7 +384,7 @@ This value is not a valid International Securities Identification Number (ISIN). - Ova vrednost nije ispravna međunarodna identifikaciona oznaka hartija od vrednosti (ISIN). + Ova vrednost nije ispravan međunarodni sigurnosni i identifikacioni broj (ISIN). This value should be a valid expression. @@ -392,11 +392,11 @@ This value is not a valid CSS color. - Ova vrednost nije ispravna CSS boja. + Ova vrednost nije validna CSS boja. This value is not a valid CIDR notation. - Ova vrednost nije ispravna CIDR notacija. + Ova vrednost nije validna CIDR notacija. The value of the netmask should be between {{ min }} and {{ max }}. @@ -404,7 +404,7 @@ The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. - Naziv datoteke je suviše dugačak. Treba da ima {{ filename_max_length }} karakter ili manje.|Naziv datoteke je suviše dugačak. Treba da ima {{ filename_max_length }} karaktera ili manje. + Naziv fajla je suviše dugačak. Treba da ima {{ filename_max_length }} karaktera ili manje.|Naziv fajla je suviše dugačak. Treba da ima {{ filename_max_length }} karaktera ili manje. The password strength is too low. Please use a stronger password. @@ -424,7 +424,11 @@ Using hidden overlay characters is not allowed. - Korišćenje skrivenih preklopnih karaktera nije dozvoljeno. + Korišćenje skrivenih pokrivenih karaktera nije dozvoljeno. + + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Ekstenzija fajla je nevalidna ({{ extension }}). Dozvoljene ekstenzije su {{ extensions }}. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf index b7b77b6371100..aee80ac4d629a 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Användning av dolda överlagringstecken är inte tillåtet. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Filtillägget är ogiltigt ({{ extension }}). Tillåtna filtillägg är {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf index 09e841565504f..b0bb1565d073a 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf @@ -364,7 +364,7 @@ This value should be between {{ min }} and {{ max }}. - Bu değer arasında olmalıdır {{ min }} ve {{ max }}. + Bu değer {{ min }} ve {{ max }} arasında olmalıdır. This value is not a valid hostname. @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Gizli üstü kaplama karakterlerinin kullanılması izin verilmez. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Dosya uzantısı geçersiz ({{ extension }}). İzin verilen uzantılar {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf index d12b4db8c9459..160352a0f573a 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Використання прихованих накладених символів не допускається. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Розширення файлу недопустиме ({{ extension }}). Дозволені розширення {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf index 63a79a084a924..3e58e24c58bbf 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Yashirin qoplamali belgilardan foydalanish taqiqlangan. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Fayl kengaytmasi yaroqsiz ({{ extension }}). Ruxsat berilgan kengaytmalar {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf index 4de9de6fb8c81..b3c60a0a4e38f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. Sử dụng các ký tự lớp phủ ẩn không được phép. + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + Phần mở rộng của tệp không hợp lệ ({{ extension }}). Phần mở rộng cho phép là {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf index b1804bfce793b..d74c2e9ba77f0 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf @@ -426,6 +426,10 @@ Using hidden overlay characters is not allowed. 不允許使用隱藏的覆蓋字元。 + + The extension of the file is invalid ({{ extension }}). Allowed extensions are {{ extensions }}. + 無效的副檔名 ({{ extension }}). 允許的副檔名有 {{ extensions }}. + diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CollectionTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CollectionTest.php index a362e96ceec88..e5685a4acc7ed 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CollectionTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CollectionTest.php @@ -18,6 +18,7 @@ use Symfony\Component\Validator\Constraints\Required; use Symfony\Component\Validator\Constraints\Valid; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; +use Symfony\Component\Validator\Exception\InvalidOptionsException; /** * @author Bernhard Schussek @@ -34,7 +35,7 @@ public function testRejectInvalidFieldsOption() public function testRejectNonConstraints() { - $this->expectException(ConstraintDefinitionException::class); + $this->expectException(InvalidOptionsException::class); new Collection([ 'foo' => 'bar', ]); @@ -113,4 +114,43 @@ public function testConstraintHasDefaultGroupWithOptionalValues() $this->assertEquals(['Default'], $constraint->fields['foo']->groups); $this->assertEquals(['Default'], $constraint->fields['bar']->groups); } + + public function testOnlySomeKeysAreKnowOptions() + { + $constraint = new Collection([ + 'fields' => [new Required()], + 'properties' => [new Required()], + 'catalog' => [new Optional()], + ]); + + $this->assertArrayHasKey('fields', $constraint->fields); + $this->assertInstanceOf(Required::class, $constraint->fields['fields']); + $this->assertArrayHasKey('properties', $constraint->fields); + $this->assertInstanceOf(Required::class, $constraint->fields['properties']); + $this->assertArrayHasKey('catalog', $constraint->fields); + $this->assertInstanceOf(Optional::class, $constraint->fields['catalog']); + } + + public function testAllKeysAreKnowOptions() + { + $constraint = new Collection([ + 'fields' => [ + 'fields' => [new Required()], + 'properties' => [new Required()], + 'catalog' => [new Optional()], + ], + 'allowExtraFields' => true, + 'extraFieldsMessage' => 'foo bar baz', + ]); + + $this->assertArrayHasKey('fields', $constraint->fields); + $this->assertInstanceOf(Required::class, $constraint->fields['fields']); + $this->assertArrayHasKey('properties', $constraint->fields); + $this->assertInstanceOf(Required::class, $constraint->fields['properties']); + $this->assertArrayHasKey('catalog', $constraint->fields); + $this->assertInstanceOf(Optional::class, $constraint->fields['catalog']); + + $this->assertTrue($constraint->allowExtraFields); + $this->assertSame('foo bar baz', $constraint->extraFieldsMessage); + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CssColorValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CssColorValidatorTest.php index 95b0b6f29ea34..5c7904a8001af 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CssColorValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CssColorValidatorTest.php @@ -418,11 +418,22 @@ public function getInvalidHSLA(): array return [['hsla(1000, 1000%, 20000%, 999)'], ['hsla(-100, -10%, -2%, 999)'], ['hsla(a, b, c, d)'], ['hsla(a, b%, c%, d)'], ['hsla( 9 99% , 99 9% , 9 %']]; } - public function testUnknownFormatsOnValidateTriggerException() + /** + * @dataProvider getInvalidFormats + */ + public function testUnknownFormatAsStringThrowsException($formats) { $this->expectException(\InvalidArgumentException::class); $this->expectExceptionMessage('The "formats" parameter value is not valid. It must contain one or more of the following values: "hex_long, hex_long_with_alpha, hex_short, hex_short_with_alpha, basic_named_colors, extended_named_colors, system_colors, keywords, rgb, rgba, hsl, hsla".'); - $constraint = new CssColor('Unknown Format'); - $this->validator->validate('#F4B907', $constraint); + + new CssColor($formats); + } + + public static function getInvalidFormats(): array + { + return [ + 'as string' => ['Unknown Format'], + 'as array' => [['Unknown Format']], + ]; } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/FileValidatorTestCase.php b/src/Symfony/Component/Validator/Tests/Constraints/FileValidatorTestCase.php index cd16f8b4b0682..23d8a96ca267f 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/FileValidatorTestCase.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/FileValidatorTestCase.php @@ -230,11 +230,9 @@ public function testMaxSizeNotExceeded($bytesWritten, $limit) public function testInvalidMaxSize() { $this->expectException(ConstraintDefinitionException::class); - $constraint = new File([ + new File([ 'maxSize' => '1abc', ]); - - $this->validator->validate($this->path, $constraint); } public static function provideBinaryFormatTests() diff --git a/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php b/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php index 5157b4d8560dd..e88408bf693dd 100644 --- a/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php +++ b/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php @@ -116,27 +116,13 @@ public function testValid() public function testWithTooManyInitialPlaces() { - $this->expectException(InvalidDefinitionException::class); - $this->expectExceptionMessage('The state machine "foo" cannot store many places. But the definition has 2 initial places. Only one is supported.'); $places = range('a', 'c'); $transitions = []; $definition = new Definition($places, $transitions, ['a', 'b']); - (new StateMachineValidator())->validate($definition, 'foo'); - - // the test ensures that the validation does not fail (i.e. it does not throw any exceptions) - $this->addToAssertionCount(1); + $this->expectException(InvalidDefinitionException::class); + $this->expectExceptionMessage('The state machine "foo" cannot store many places. But the definition has 2 initial places. Only one is supported.'); - // The graph looks like: - // - // +----+ +----+ +---+ - // | a | --> | t1 | --> | b | - // +----+ +----+ +---+ - // | - // | - // v - // +----+ +----+ - // | t2 | --> | c | - // +----+ +----+ + (new StateMachineValidator())->validate($definition, 'foo'); } }