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>) #StandWith>Ukraine> 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' => '[37;44m#StandWith[30;43mUkraine[0m',
+ 'console banner' => '[37;44mHello[30;43mWorld[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/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 @@
ț᭖ test8PDw8A==VGhpcyBpcyBhIEJlbGwgY2hhciAH
- G1szNzs0NG0jU3RhbmRXaXRoG1szMDs0M21Va3JhaW5lG1swbQ==
+ G1szNzs0NG1IZWxsbxtbMzA7NDNtV29ybGQbWzBtnull123-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 }}.
+
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 }}.