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'); } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

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


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy