diff --git a/.github/ISSUE_TEMPLATE/1_Bug_report.yaml b/.github/ISSUE_TEMPLATE/1_Bug_report.yaml
new file mode 100644
index 0000000000000..5518d4e4ad79d
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/1_Bug_report.yaml
@@ -0,0 +1,38 @@
+name: 🐛 Bug Report
+description: ⚠️ See below for security reports
+labels: Bug
+
+body:
+ - type: input
+ id: affected-versions
+ attributes:
+ label: Symfony version(s) affected
+ placeholder: x.y.z
+ validations:
+ required: true
+ - type: textarea
+ id: description
+ attributes:
+ label: Description
+ description: A clear and consise description of the problem
+ validations:
+ required: true
+ - type: textarea
+ id: how-to-reproduce
+ attributes:
+ label: How to reproduce
+ description: |
+ Code and/or config needed to reproduce the problem.
+ If it's a complex bug, create a "bug reproducer" as explained in https://symfony.com/doc/current/contributing/code/reproducer.html
+ validations:
+ required: true
+ - type: textarea
+ id: possible-solution
+ attributes:
+ label: Possible Solution
+ description: "Optional: only if you have suggestions on a fix/reason for the bug"
+ - type: textarea
+ id: additional-context
+ attributes:
+ label: Additional Context
+ description: "Optional: any other context about the problem: log messages, screenshots, etc."
diff --git a/.github/ISSUE_TEMPLATE/2_Feature_request.yaml b/.github/ISSUE_TEMPLATE/2_Feature_request.yaml
new file mode 100644
index 0000000000000..bd300eb1e82b2
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/2_Feature_request.yaml
@@ -0,0 +1,17 @@
+name: 🚀 Feature Request
+description: RFC and ideas for new features and improvements
+body:
+ - type: textarea
+ id: description
+ attributes:
+ label: Description
+ description: A clear and concise description of the new feature
+ validations:
+ required: true
+ - type: textarea
+ id: example
+ attributes:
+ label: Example
+ description: |
+ A simple example of the new feature in action (include PHP code, YAML config, etc.)
+ If the new feature changes an existing feature, include a simple before/after comparison.
diff --git a/CHANGELOG-5.3.md b/CHANGELOG-5.3.md
index 3cd96283ed8b6..dff9252ddcf24 100644
--- a/CHANGELOG-5.3.md
+++ b/CHANGELOG-5.3.md
@@ -7,6 +7,46 @@ in 5.3 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.3.0...v5.3.1
+* 5.3.10 (2021-10-29)
+
+ * bug #43798 [Dotenv] Duplicate $_SERVER values in $_ENV if they don't exist (fancyweb)
+ * bug #43799 [PhpUnitBridge] fix symlink to bridge in docker by making its path relative (nicolas-grekas)
+ * bug #43801 [TwigBundle] fix auto-enabling assets/expression/routing/yaml/workflow extensions (nicolas-grekas)
+ * bug #43790 [String] Fix inflector for "zombies" (acodispo)
+ * bug #43781 [Messenger] Fix `TraceableMessageBus` implementation so it can compute caller even when used within a callback (Ocramius)
+ * bug #43589 [Lock] Fix incorrect return type in PostgreSqlStore (GromNaN)
+ * bug #43627 [Framework][Secrets] Fix service definition when local vault is disabled (GromNaN)
+ * bug #43579 [DependencyInjection] Fix autowiring tagged arguments from attributes (Okhoshi)
+ * bug #43655 [VarDumper] Fix dumping twig templates found in exceptions (event15)
+ * bug #43484 [Messenger] Fix Redis Transport when username is empty (villfa)
+ * bug #43659 Fix logging of impersonator introduced in 5.3 (johanwilfer)
+ * bug #43630 [Messenger] Fix unwrapping the Postgres connection in DBAL 3 (derrabus)
+ * bug #43568 [Messenger] fix: TypeError in PhpSerializer::encode() (dsech)
+ * bug #43591 [Config] Fix files sorting in GlobResource (lyrixx)
+ * bug #43569 [HttpClient] fix collecting debug info on destruction of CurlResponse (nicolas-grekas)
+ * bug #43545 [DependencyInjection] fix "url" env var processor (nicolas-grekas)
+ * bug #43537 [HttpClient] fix RetryableHttpClient when a response is canceled (nicolas-grekas)
+ * bug #43533 [Uid] fix 4 missing bits of entropy in UUIDv4 (nicolas-grekas)
+ * bug #43376 [Runtime] Fix class validation of composer "extra.runtime.class" (piku235)
+ * bug #43413 [VarDumper] Fix error with uninitialized XMLReader (villfa)
+ * bug #43439 [Notifier] [RocketChat] Fix undefined index for message id (OskarStark)
+ * bug #43408 [Notifier] Fix 'Undefined array key' error in FirebaseTransport (villfa)
+ * bug #43388 [Validator] Fixes URL validation for single-char subdomains (DfKimera)
+ * bug #41534 [Form] Fix ChoiceType to effectively set and use translator (marek-binkowski-sim)
+ * bug #43364 [Translation] Use symfony default locale when pulling translations from providers (Yoann MOROCUTTI)
+ * bug #43333 [HttpClient] fix missing kernel.reset tag on TraceableHttpClient services (nicolas-grekas)
+ * bug #43302 [Cache] Commit items implicitly only when deferred keys are requested (Sergey Belyshkin)
+ * bug #43330 [Cache][Lock] fix SQLSRV throws for method_exists() (GDmac)
+ * bug #43270 [VarDumper] Fix handling of "new" in initializers on PHP 8.1 (nicolas-grekas)
+ * bug #43312 [Translation] [Bridge] [Lokalise] do not export empty strings (taranovegor)
+ * bug #43277 [DependencyInjection] fix support for "new" in initializers on PHP 8.1 (nicolas-grekas)
+ * bug #43243 [HttpClient] accept headers when CURLE_RECV_ERROR is received before the content (nicolas-grekas)
+ * bug #43208 [Serializer] Attributes that extend serializer`s annotations are not ignored by the serialization process (Alexander Onatskiy)
+ * bug #43241 [PhpUnitBridge] Do not override correct triggering file for return type deprecations (wouterj)
+ * bug #43204 [Serializer] Fix denormalizing XML array with empty body (5.x) (alexandre-daubois)
+ * bug #43205 [Serializer] Fix denormalizing XML array with empty body (4.4) (alexandre-daubois)
+ * bug #43235 [Security] Remove annoying deprecation in `UsageTrackingTokenStorage` (chalasr)
+
* 5.3.9 (2021-09-28)
* Fix subtree split issue
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index f804602f54457..507ca7e28d68b 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -7,16 +7,16 @@ The Symfony Connect username in parenthesis allows to get more information
- Fabien Potencier (fabpot)
- Nicolas Grekas (nicolas-grekas)
- Christian Flothmann (xabbuh)
- - Bernhard Schussek (bschussek)
- Alexander M. Turek (derrabus)
+ - Bernhard Schussek (bschussek)
- Tobias Schultze (tobion)
- Robin Chalas (chalas_r)
- Christophe Coevoet (stof)
- Wouter De Jong (wouterj)
- Jérémy DERUSSÉ (jderusse)
- Maxime Steinhausser (ogizanagi)
- - Kévin Dunglas (dunglas)
- Grégoire Pineau (lyrixx)
+ - Kévin Dunglas (dunglas)
- Jordi Boggiano (seldaek)
- Victor Berchet (victor)
- Javier Eguiluz (javier.eguiluz)
@@ -66,8 +66,8 @@ The Symfony Connect username in parenthesis allows to get more information
- stealth35 (stealth35)
- Alexander Mols (asm89)
- Titouan Galopin (tgalopin)
- - Vasilij Dusko | CREATION
- Laurent VOULLEMIER (lvo)
+ - Vasilij Dusko | CREATION
- Bulat Shakirzyanov (avalanche123)
- David Maicher (dmaicher)
- gadelat (gadelat)
@@ -81,17 +81,17 @@ The Symfony Connect username in parenthesis allows to get more information
- Konstantin Kudryashov (everzet)
- Vladimir Reznichenko (kalessil)
- Bilal Amarni (bamarni)
+ - Jérôme Tamarelle (gromnan)
- Florin Patan (florinpatan)
- Jáchym Toušek (enumag)
- - Jérôme Tamarelle (gromnan)
- Alex Pott
- Michel Weimerskirch (mweimerskirch)
- Andrej Hudec (pulzarraider)
- Christian Raue
- Issei Murasawa (issei_m)
+ - Antoine M (amakdessi)
- Eric Clemmons (ericclemmons)
- Charles Sarrazin (csarrazi)
- - Antoine M (amakdessi)
- Vasilij Dusko
- Douglas Greenshields (shieldo)
- Graham Campbell (graham)
@@ -107,18 +107,18 @@ The Symfony Connect username in parenthesis allows to get more information
- Brandon Turner
- Luis Cordova (cordoval)
- Daniel Holmes (dholmes)
+ - Alexander Schranz (alexander-schranz)
- Sebastiaan Stok (sstok)
- Toni Uebernickel (havvg)
- Bart van den Burg (burgov)
- Jordan Alliot (jalliot)
- John Wards (johnwards)
- - Alexander Schranz (alexander-schranz)
- Baptiste Clavié (talus)
- Antoine Hérault (herzult)
- Paráda József (paradajozsef)
+ - Vincent Langlet (deviling)
- Arnaud Le Blanc (arnaud-lb)
- Przemysław Bogusz (przemyslaw-bogusz)
- - Vincent Langlet (deviling)
- Maxime STEINHAUSSER
- Tomas Norkūnas (norkunas)
- Michal Piotrowski (eventhorizon)
@@ -126,13 +126,13 @@ The Symfony Connect username in parenthesis allows to get more information
- Massimiliano Arione (garak)
- Mathias Arlaud (mtarld)
- Tim Nagel (merk)
+ - HypeMC (hypemc)
- Chris Wilkinson (thewilkybarkid)
- Peter Kokot (maastermedia)
- Lars Strojny (lstrojny)
- Brice BERNARD (brikou)
- Ahmed TAILOULOUTE (ahmedtai)
- Gregor Harlan (gharlan)
- - HypeMC (hypemc)
- marc.weistroff
- lenar
- Alexander Schwenn (xelaris)
@@ -148,6 +148,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Théo FIDRY (theofidry)
- Florian Voutzinos (florianv)
- Teoh Han Hui (teohhanhui)
+ - Alexandre Daubois (alexandre-daubois)
- Colin Frei
- Javier Spagnoletti (phansys)
- Joshua Thijssen
@@ -156,26 +157,26 @@ The Symfony Connect username in parenthesis allows to get more information
- excelwebzone
- Gordon Franke (gimler)
- Saif Eddin Gmati (azjezz)
- - Alexandre Daubois (alexandre-daubois)
+ - Richard van Laak (rvanlaak)
- Jesse Rushlow (geeshoe)
- Fabien Pennequin (fabienpennequin)
+ - Mathieu Santostefano (welcomattic)
- Olivier Dolbeau (odolbeau)
- Smaine Milianni (ismail1432)
- - Richard van Laak (rvanlaak)
- Eric GELOEN (gelo)
+ - Gary PEGEOT (gary-p)
- Matthieu Napoli (mnapoli)
+ - Maxime Helias (maxhelias)
- Jannik Zschiesche (apfelbox)
- - Mathieu Santostefano (welcomattic)
- Robert Schönthal (digitalkaoz)
- Florian Lonqueu-Brochard (florianlb)
- Tigran Azatyan (tigranazatyan)
- YaFou
- - Gary PEGEOT (gary-p)
- Gabriel Caruso (carusogabriel)
+ - Ruud Kamphuis (ruudk)
- Stefano Sala (stefano.sala)
- Andréia Bohner (andreia)
- Evgeniy (ewgraf)
- - Maxime Helias (maxhelias)
- Vincent AUBERT (vincent)
- Juti Noppornpitak (shiroyuki)
- Anthony MARTIN (xurudragon)
@@ -184,11 +185,12 @@ The Symfony Connect username in parenthesis allows to get more information
- Hidenori Goto (hidenorigoto)
- Jan Rosier (rosier)
- Alessandro Chitolina (alekitto)
- - Ruud Kamphuis (ruudk)
+ - Ion Bazan (ionbazan)
- Albert Casademont (acasademont)
- Arnaud Kleinpeter (nanocom)
- Guilherme Blanco (guilhermeblanco)
- SpacePossum
+ - Alexander Menshchikov (zmey_kk)
- Pablo Godel (pgodel)
- Andreas Braun
- Jérémie Augustin (jaugustin)
@@ -201,7 +203,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Jeroen Spee (jeroens)
- Fabien Bourigault (fbourigault)
- Joe Bennett (kralos)
- - Alexander Menshchikov (zmey_kk)
- Mikael Pajunen
- Andreas Schempp (aschempp)
- Romaric Drigon (romaricdrigon)
@@ -241,6 +242,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Dmitrii Poddubnyi (karser)
- Michael Babker (mbabker)
- Tien Vo (tienvx)
+ - Simon Berger
- Timothée Barray (tyx)
- James Halsall (jaitsu)
- Florent Mata (fmata)
@@ -270,7 +272,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Sebastien Morel (plopix)
- Baptiste Leduc (korbeil)
- mcfedr (mcfedr)
- - Simon Berger
- Ruben Gonzalez (rubenrua)
- Benjamin Dulau (dbenjamin)
- Baptiste Lafontaine (magnetik)
@@ -282,7 +283,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Guillaume Pédelagrabe
- Noel Guilbert (noel)
- Anthony GRASSIOT (antograssiot)
- - Ion Bazan (ionbazan)
- Stadly
- Stepan Anchugov (kix)
- François Pluchino (francoispluchino)
@@ -351,6 +351,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Sébastien Lavoie (lavoiesl)
- Dariusz
- Farhad Safarov (safarov)
+ - BoShurik
- Thomas Lallement (raziel057)
- Francois Zaninotto
- Claude Khedhiri (ck-developer)
@@ -429,6 +430,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Wouter Van Hecke
- Iker Ibarguren (ikerib)
- Bob van de Vijver (bobvandevijver)
+ - Soner Sayakci
- Peter Kruithof (pkruithof)
- Michael Holm (hollo)
- Sylvain Fabre (sylfabre)
@@ -499,7 +501,6 @@ The Symfony Connect username in parenthesis allows to get more information
- ivan
- Greg Anderson
- Tri Pham (phamuyentri)
- - BoShurik
- Gennady Telegin (gtelegin)
- Krystian Marcisz (simivar)
- Toni Rudolf (toooni)
@@ -524,8 +525,8 @@ The Symfony Connect username in parenthesis allows to get more information
- Dmytro Borysovskyi (dmytr0)
- Tomasz Kowalczyk (thunderer)
- Artur Eshenbrener
- - Soner Sayakci
- Thomas Perez (scullwm)
+ - Yoann RENARD (yrenard)
- Felix Labrecque
- Yaroslav Kiliba
- Terje Bråten
@@ -619,6 +620,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Alexandru Furculita (afurculita)
- Valentin Jonovs (valentins-jonovs)
- Bastien DURAND (deamon)
+ - Antonio Jose Cerezo (ajcerezo)
- Jeanmonod David (jeanmonod)
- Christin Gruber (christingruber)
- Andrey Sevastianov
@@ -670,7 +672,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Andrew M-Y (andr)
- Krasimir Bosilkov (kbosilkov)
- Marcin Michalski (marcinmichalski)
- - Yoann RENARD (yrenard)
- Vitaliy Tverdokhlib (vitaliytv)
- Ariel Ferrandini (aferrandini)
- Niklas Keller
@@ -694,6 +695,7 @@ The Symfony Connect username in parenthesis allows to get more information
- franek (franek)
- Raulnet
- Christian Wahler
+ - Dries Vints
- Giso Stallenberg (gisostallenberg)
- Gintautas Miselis
- Rob Bast
@@ -714,6 +716,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Patrick Reimers (preimers)
- insekticid
- Alexander Obuhovich (aik099)
+ - Jérémy M (th3mouk)
- Vitaliy Ryaboy (vitaliy)
- boombatower
- Fabrice Bernhard (fabriceb)
@@ -753,6 +756,7 @@ The Symfony Connect username in parenthesis allows to get more information
- ondrowan
- Barry vd. Heuvel (barryvdh)
- Jon Dufresne
+ - Fabien S (bafs)
- Evan S Kaufman (evanskaufman)
- Alex Bacart
- mcben
@@ -773,6 +777,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Andrew Udvare (audvare)
- alexpods
- Dennis Langen (nijusan)
+ - Hubert Lenoir (hubert_lenoir)
- Adam Szaraniec (mimol)
- Dariusz Ruminski
- Erik Trapman (eriktrapman)
@@ -847,6 +852,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Thiago Cordeiro (thiagocordeiro)
- Jan Behrens
- Dragos Protung (dragosprotung)
+ - Romain Monteil (ker0x)
- Mantas Var (mvar)
- Terje Bråten
- Yann LUCAS (drixs6o9)
@@ -872,7 +878,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Jean-Christophe Cuvelier [Artack]
- julien57
- Julien Montel (julienmgel)
- - Antonio Jose Cerezo (ajcerezo)
- Mátyás Somfai (smatyas)
- Alexandre Tranchant (alexandre_t)
- Anthony Moutte
@@ -1114,11 +1119,13 @@ The Symfony Connect username in parenthesis allows to get more information
- Aurélien Fontaine
- Pascal Helfenstein
- Baldur Rensch (brensch)
+ - Carl Casbolt (carlcasbolt)
- Vladyslav Petrovych
- Hugo Sales
- Alex Xandra Albert Sim
- Carson Full
- Sergey Yastrebov
+ - kylekatarnls (kylekatarnls)
- Trent Steel (trsteel88)
- Yuen-Chi Lian
- Tarjei Huse (tarjei)
@@ -1175,6 +1182,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Christian Soronellas (theunic)
- kick-the-bucket
- fedor.f
+ - Bilge
- Yosmany Garcia (yosmanyga)
- Jeremiasz Major
- Wouter de Wild
@@ -1186,7 +1194,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Krzysiek Łabuś
- Juraj Surman
- Camille Dejoye
- - Fabien S (bafs)
- 1ma (jautenim)
- Douglas Hammond (wizhippo)
- Xavier Lacot (xavier)
@@ -1210,7 +1217,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Dmitry Pigin (dotty)
- Vincent Composieux (eko)
- Jayson Xu (superjavason)
- - Hubert Lenoir (hubert_lenoir)
- fago
- popnikos
- Tito Costa
@@ -1235,14 +1241,15 @@ The Symfony Connect username in parenthesis allows to get more information
- Reen Lokum
- Martin Parsiegla (spea)
- Bernhard Rusch
+ - bhavin (bhavin4u)
- Ivan
- Quentin Schuler
+ - Nico Haase
- Pierre Vanliefland (pvanliefland)
- Roy Klutman (royklutman)
- Sofiane HADDAG (sofhad)
- frost-nzcr4
- Taylor Otwell
- - Dries Vints
- Sami Mussbach
- Kien Nguyen
- Foxprodev
@@ -1279,6 +1286,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Cyrille Bourgois (cyrilleb)
- Gerard van Helden (drm)
- Johnny Peck (johnnypeck)
+ - Jordi Sala Morales (jsala)
- Marcos Rezende (rezehnde)
- Roman Anasal
- Ivan Menshykov
@@ -1324,7 +1332,6 @@ The Symfony Connect username in parenthesis allows to get more information
- abdul malik ikhsan (samsonasik)
- Henry Snoek (snoek09)
- Dmitry (staratel)
- - Jérémy M (th3mouk)
- Tito Miguel Costa (titomiguelcosta)
- Simone Di Maulo (toretto460)
- Christian Morgan
@@ -1355,6 +1362,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Arno Geurts
- Adán Lobato (adanlobato)
- Ian Jenkins (jenkoian)
+ - Kai Eichinger (kai_eichinger)
- Hugo Alliaume (kocal)
- Marcos Gómez Vilches (markitosgv)
- Matthew Davis (mdavis1982)
@@ -1404,6 +1412,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Vincent MOULENE (vints24)
- Koen Kuipers
- datibbaw
+ - Nicolas de Marqué (nicola)
- Antoine Leblanc
- Andre Johnson
- Marco Pfeiffer
@@ -1412,7 +1421,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Daniel Alejandro Castro Arellano (lexcast)
- Aleksandar Dimitrov (netbull)
- Gary Houbre (thegarious)
- - Romain Monteil (ker0x)
- sensio
- Thomas Jarrand
- Antoine Bluchet (soyuka)
@@ -1421,6 +1429,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Paul Oms
- Reece Fowell (reecefowell)
- stefan.r
+ - Htun Htun Htet (ryanhhh91)
- Guillaume Gammelin
- Valérian Galliat
- d-ph
@@ -1490,6 +1499,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Ken Stanley
- ivan
- Zachary Tong (polyfractal)
+ - Oleg Krasavin (okwinza)
- Mario Blažek (marioblazek)
- Jure (zamzung)
- Michael Nelson
@@ -1562,6 +1572,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Antanas Arvasevicius
- Pierre Dudoret
- Thomas
+ - Georgi Georgiev
- Maximilian Berghoff (electricmaxxx)
- nacho
- Piotr Antosik (antek88)
@@ -1621,6 +1632,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Maximilian Ruta (deltachaos)
- Mickaël Isaert (misaert)
- Jakub Sacha
+ - Julius Kiekbusch
- Olaf Klischat
- orlovv
- Claude Dioudonnat
@@ -1644,6 +1656,7 @@ The Symfony Connect username in parenthesis allows to get more information
- James Hudson
- Stephen Clouse
- e-ivanov
+ - Nathanaël Martel (nathanaelmartel)
- Einenlum
- Jochen Bayer (jocl)
- Patrick Carlo-Hickman
@@ -1669,6 +1682,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Neil Katin
- David Otton
- Will Donohoe
+ - gnito-org
- peter
- Jérémy Jourdin (jjk801)
- BRAMILLE Sébastien (oktapodia)
@@ -1697,7 +1711,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Juan Miguel Besada Vidal (soutlink)
- dlorek
- Stuart Fyfe
- - Carl Casbolt (carlcasbolt)
- David de Boer (ddeboer)
- Eno Mullaraj (emullaraj)
- Nathan PAGE (nathix)
@@ -1752,6 +1765,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Clement Herreman (clemherreman)
- Dan Ionut Dumitriu (danionut90)
- Vladislav Rastrusny (fractalizer)
+ - Vlad Gapanovich (gapik)
- Alexander Kurilo (kamazee)
- Nyro (nyro)
- Marco
@@ -1801,6 +1815,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Artem Stepin (astepin)
- Christian Flach (cmfcmf)
- Cédric Girard (enk_)
+ - Fabian Kropfhamer (fabiank)
- Lars Ambrosius Wallenborn (larsborn)
- Oriol Mangas Abellan (oriolman)
- Sebastian Göttschkes (sgoettschkes)
@@ -1912,7 +1927,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Martin Pärtel
- Daniel Rotter (danrot)
- Frédéric Bouchery (fbouchery)
- - kylekatarnls (kylekatarnls)
- Patrick Daley (padrig)
- Foxprodev
- Max Summe
@@ -1923,6 +1937,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Tadcka
- Beth Binkovitz
- Gonzalo Míguez
+ - Fabian Haase
- Romain Geissler
- Adrien Moiruad
- Tomaz Ahlin
@@ -1994,6 +2009,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Ergie Gonzaga
- Matthew J Mucklo
- AnrDaemon
+ - Anthony Massard (decap94)
- Emre Akinci (emre)
- Chris Maiden (matason)
- fdgdfg (psampaz)
@@ -2119,6 +2135,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Sergey Fokin (tyraelqp)
- Evrard Boulou
- pborreli
+ - Bernat Llibre
- Boris Betzholz
- Eric Caron
- 2manypeople
@@ -2234,10 +2251,12 @@ The Symfony Connect username in parenthesis allows to get more information
- Felix Marezki
- Normunds
- Luiz “Felds” Liscia
+ - Yuri Karaban
- Johan
- Thomas Rothe
- Martin
- nietonfir
+ - Andriy
- alefranz
- David Barratt
- Andrea Giannantonio
@@ -2278,7 +2297,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Alessio Baglio (ioalessio)
- Johannes Müller (johmue)
- Jordi Llonch (jordillonch)
- - Jordi Sala Morales (jsala)
- Mouad ZIANI (mouadziani)
- Nicholas Ruunu (nicholasruunu)
- Jeroen van den Nieuwenhuisen (nieuwenhuisen)
@@ -2473,8 +2491,10 @@ The Symfony Connect username in parenthesis allows to get more information
- Maerlyn
- Even André Fiskvik
- Agata
+ - dakur
- Александр Ли
- Arjan Keeman
+ - Vlad Dumitrache
- Erik van Wingerden
- Valouleloup
- robmro27
@@ -2602,6 +2622,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Paulius Jarmalavičius (pjarmalavicius)
- Ramon Henrique Ornelas (ramonornela)
- Ricardo de Vries (ricknox)
+ - Ruslan Zavacky (ruslanzavacky)
- Stefano Cappellini (stefano_cappellini)
- Thomas Dutrion (theocrite)
- Till Klampaeckel (till)
@@ -2639,7 +2660,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Jordan Hoff
- znerol
- Christian Eikermann
- - Kai Eichinger
- Antonio Angelino
- Jens Schulze
- Matt Fields
@@ -2702,10 +2722,12 @@ The Symfony Connect username in parenthesis allows to get more information
- Adrian Philipp
- James Michael DuPont
- Kasperki
+ - dima-gr
- Tammy D
- Rodolfo Ruiz
- Enrico
- Ryan Rud
+ - Christopher Georg
- Ondrej Slinták
- vlechemin
- Brian Corrigan
@@ -2798,6 +2820,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Дмитрий Пацура
- Signor Pedro
- Matthias Larisch
+ - Maxime P
- ilyes kooli
- Ilia Lazarev
- Michaël VEROUX
@@ -2806,7 +2829,6 @@ The Symfony Connect username in parenthesis allows to get more information
- arduanov
- sualko
- Molkobain
- - Bilge
- Yendric
- ADmad
- Nicolas Roudaire
@@ -2978,7 +3000,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Maxime COLIN (maximecolin)
- Muharrem Demirci (mdemirci)
- Evgeny Z (meze)
- - Nicolas de Marqué (nicola)
- Pierre Geyer (ptheg)
- Thomas BERTRAND (sevrahk)
- Matej Žilák (teo_sk)
diff --git a/UPGRADE-5.3.md b/UPGRADE-5.3.md
index 6a1552e3a8700..166e2ba9b8d33 100644
--- a/UPGRADE-5.3.md
+++ b/UPGRADE-5.3.md
@@ -106,9 +106,6 @@ Routing
Security
--------
- * Deprecate using `UsageTrackingTokenStorage` with tracking enabled without a main request. Use the untracked token
- storage (service ID: `security.untracked_token_storage`) instead, or disable usage tracking
- completely using `UsageTrackingTokenStorage::disableUsageTracking()`.
* [BC BREAK] Remove method `checkIfCompletelyResolved()` from `PassportInterface`, checking that passport badges are
resolved is up to `AuthenticatorManager`
* Deprecate class `User`, use `InMemoryUser` or your own implementation instead.
diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php
index f9bd78619d6b5..5a0514e323071 100644
--- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php
+++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler/Deprecation.php
@@ -87,7 +87,7 @@ public function __construct($message, array $trace, $file)
$this->getOriginalFilesStack();
array_splice($this->originalFilesStack, 0, $j, [$this->triggeringFile]);
- if (preg_match('/(?|"([^"]++)" that is deprecated|should implement method "(?:static )?([^:]++))/', $message, $m) || preg_match('/^(?:The|Method) "([^":]++)/', $message, $m)) {
+ if (preg_match('/(?|"([^"]++)" that is deprecated|should implement method "(?:static )?([^:]++))/', $message, $m) || (false === strpos($message, '()" will return') && false === strpos($message, 'native return type declaration') && preg_match('/^(?:The|Method) "([^":]++)/', $message, $m))) {
$this->triggeringFile = (new \ReflectionClass($m[1]))->getFileName();
array_unshift($this->originalFilesStack, $this->triggeringFile);
}
diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php
index c92b47f3c0236..d8b546a6f8b27 100644
--- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php
+++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php
@@ -94,8 +94,8 @@
};
if (\PHP_VERSION_ID >= 80000) {
- // PHP 8 requires PHPUnit 9.3+
- $PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '9.4') ?: '9.4';
+ // PHP 8 requires PHPUnit 9.3+, PHP 8.1 requires PHPUnit 9.5+
+ $PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '9.5') ?: '9.5';
} elseif (\PHP_VERSION_ID >= 70200) {
// PHPUnit 8 requires PHP 7.2+
$PHPUNIT_VERSION = $getEnvVar('SYMFONY_PHPUNIT_VERSION', '8.5') ?: '8.5';
@@ -122,7 +122,7 @@
}
$oldPwd = getcwd();
-$PHPUNIT_DIR = $getEnvVar('SYMFONY_PHPUNIT_DIR', $root.'/vendor/bin/.phpunit');
+$PHPUNIT_DIR = rtrim($getEnvVar('SYMFONY_PHPUNIT_DIR', $root.'/vendor/bin/.phpunit'), '/'.\DIRECTORY_SEPARATOR);
$PHP = defined('PHP_BINARY') ? \PHP_BINARY : 'php';
$PHP = escapeshellarg($PHP);
if ('phpdbg' === \PHP_SAPI) {
@@ -239,6 +239,10 @@
$passthruOrFail("$COMPOSER config --unset platform.php");
}
if (file_exists($path = $root.'/vendor/symfony/phpunit-bridge')) {
+ $p = str_repeat('../', substr_count("$PHPUNIT_DIR/$PHPUNIT_VERSION_DIR", '/', strlen($root))).'vendor/symfony/phpunit-bridge';
+ if (realpath($p) === realpath($path)) {
+ $path = $p;
+ }
$passthruOrFail("$COMPOSER require --no-update symfony/phpunit-bridge \"*@dev\"");
$passthruOrFail("$COMPOSER config repositories.phpunit-bridge path ".escapeshellarg(str_replace('/', \DIRECTORY_SEPARATOR, $path)));
if ('\\' === \DIRECTORY_SEPARATOR) {
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.php
index f6a3063aadf3d..d2db4d4052d59 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/console.php
@@ -298,7 +298,7 @@
->set('console.command.secrets_list', SecretsListCommand::class)
->args([
service('secrets.vault'),
- service('secrets.local_vault'),
+ service('secrets.local_vault')->ignoreOnInvalid(),
])
->tag('console.command')
@@ -312,7 +312,7 @@
->set('console.command.secrets_encrypt_from_local', SecretsEncryptFromLocalCommand::class)
->args([
service('secrets.vault'),
- service('secrets.local_vault'),
+ service('secrets.local_vault')->ignoreOnInvalid(),
])
->tag('console.command')
;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
index bc46570744d16..c86e15751362f 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
@@ -344,15 +344,6 @@
-
-
-
-
-
-
-
-
-
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php
index e400b95506b73..d9f4b1192f456 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php
@@ -126,7 +126,7 @@ public function testRateLimiterLockFactory()
});
$this->expectException(OutOfBoundsException::class);
- $this->expectExceptionMessage('The argument "2" doesn\'t exist.');
+ $this->expectExceptionMessageMatches('/^The argument "2" doesn\'t exist.*\.$/');
$container->getDefinition('limiter.without_lock')->getArgument(2);
}
diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php
index a18de86e7b02d..12724e0f1cc65 100644
--- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php
+++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php
@@ -27,19 +27,19 @@ class ExtensionPass implements CompilerPassInterface
{
public function process(ContainerBuilder $container)
{
- if (!$container::willBeAvailable('symfony/asset', Packages::class, ['symfony/twig-bundle'])) {
+ if (!class_exists(Packages::class)) {
$container->removeDefinition('twig.extension.assets');
}
- if (!$container::willBeAvailable('symfony/expression-language', Expression::class, ['symfony/twig-bundle'])) {
+ if (!class_exists(Expression::class)) {
$container->removeDefinition('twig.extension.expression');
}
- if (!$container::willBeAvailable('symfony/routing', UrlGeneratorInterface::class, ['symfony/twig-bundle'])) {
+ if (!interface_exists(UrlGeneratorInterface::class)) {
$container->removeDefinition('twig.extension.routing');
}
- if (!$container::willBeAvailable('symfony/yaml', Yaml::class, ['symfony/twig-bundle'])) {
+ if (!class_exists(Yaml::class)) {
$container->removeDefinition('twig.extension.yaml');
}
@@ -115,7 +115,7 @@ public function process(ContainerBuilder $container)
$container->getDefinition('twig.extension.expression')->addTag('twig.extension');
}
- if (!$container::willBeAvailable('symfony/workflow', Workflow::class, ['symfony/twig-bundle']) || !$container->has('workflow.registry')) {
+ if (!class_exists(Workflow::class) || !$container->has('workflow.registry')) {
$container->removeDefinition('workflow.twig_extension');
} else {
$container->getDefinition('workflow.twig_extension')->addTag('twig.extension');
diff --git a/src/Symfony/Component/Cache/Adapter/PdoAdapter.php b/src/Symfony/Component/Cache/Adapter/PdoAdapter.php
index b54841f0c0fbc..7a47e589e0063 100644
--- a/src/Symfony/Component/Cache/Adapter/PdoAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/PdoAdapter.php
@@ -123,7 +123,7 @@ public function createTable()
$this->addTableToSchema($schema);
foreach ($schema->toSql($conn->getDatabasePlatform()) as $sql) {
- if (method_exists($conn, 'executeStatement')) {
+ if ($conn instanceof Connection && method_exists($conn, 'executeStatement')) {
$conn->executeStatement($sql);
} else {
$conn->exec($sql);
@@ -158,7 +158,7 @@ public function createTable()
throw new \DomainException(sprintf('Creating the cache table is currently not implemented for PDO driver "%s".', $this->driver));
}
- if (method_exists($conn, 'executeStatement')) {
+ if ($conn instanceof Connection && method_exists($conn, 'executeStatement')) {
$conn->executeStatement($sql);
} else {
$conn->exec($sql);
@@ -307,7 +307,7 @@ protected function doClear(string $namespace)
}
try {
- if (method_exists($conn, 'executeStatement')) {
+ if ($conn instanceof Connection && method_exists($conn, 'executeStatement')) {
$conn->executeStatement($sql);
} else {
$conn->exec($sql);
diff --git a/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php
index cd0eaa774bc49..a9048995c2abb 100644
--- a/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php
@@ -157,9 +157,10 @@ public function invalidateTags(array $tags)
*/
public function hasItem($key)
{
- if ($this->deferred) {
+ if (\is_string($key) && isset($this->deferred[$key])) {
$this->commit();
}
+
if (!$this->pool->hasItem($key)) {
return false;
}
@@ -200,18 +201,21 @@ public function getItem($key)
*/
public function getItems(array $keys = [])
{
- if ($this->deferred) {
- $this->commit();
- }
$tagKeys = [];
+ $commit = false;
foreach ($keys as $key) {
if ('' !== $key && \is_string($key)) {
+ $commit = $commit || isset($this->deferred[$key]);
$key = static::TAGS_PREFIX.$key;
$tagKeys[$key] = $key;
}
}
+ if ($commit) {
+ $this->commit();
+ }
+
try {
$items = $this->pool->getItems($tagKeys + $keys);
} catch (InvalidArgumentException $e) {
diff --git a/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php b/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php
index ca7a030fdff2d..b34aa466ceb77 100644
--- a/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php
+++ b/src/Symfony/Component/Cache/Traits/AbstractAdapterTrait.php
@@ -208,10 +208,11 @@ public function deleteItems(array $keys)
*/
public function getItem($key)
{
- if ($this->deferred) {
+ $id = $this->getId($key);
+
+ if (isset($this->deferred[$key])) {
$this->commit();
}
- $id = $this->getId($key);
$isHit = false;
$value = null;
@@ -234,14 +235,18 @@ public function getItem($key)
*/
public function getItems(array $keys = [])
{
- if ($this->deferred) {
- $this->commit();
- }
$ids = [];
+ $commit = false;
foreach ($keys as $key) {
$ids[] = $this->getId($key);
+ $commit = $commit || isset($this->deferred[$key]);
+ }
+
+ if ($commit) {
+ $this->commit();
}
+
try {
$items = $this->doFetch($ids);
} catch (\Exception $e) {
diff --git a/src/Symfony/Component/Config/Resource/GlobResource.php b/src/Symfony/Component/Config/Resource/GlobResource.php
index 2ac06986d5b31..31937bc9037e6 100644
--- a/src/Symfony/Component/Config/Resource/GlobResource.php
+++ b/src/Symfony/Component/Config/Resource/GlobResource.php
@@ -119,7 +119,7 @@ public function getIterator(): \Traversable
}
if (null !== $paths) {
- sort($paths);
+ natsort($paths);
foreach ($paths as $path) {
if ($this->excludedPrefixes) {
$normalizedPath = str_replace('\\', '/', $path);
@@ -152,7 +152,7 @@ function (\SplFileInfo $file, $path) {
),
\RecursiveIteratorIterator::LEAVES_ONLY
));
- uasort($files, 'strnatcmp');
+ uksort($files, 'strnatcmp');
foreach ($files as $path => $info) {
if ($info->isFile()) {
diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php
index fd90959281713..28931358dd68b 100644
--- a/src/Symfony/Component/Console/Helper/QuestionHelper.php
+++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php
@@ -205,7 +205,7 @@ protected function formatChoiceQuestionChoices(ChoiceQuestion $question, string
{
$messages = [];
- $maxWidth = max(array_map('self::width', array_keys($choices = $question->getChoices())));
+ $maxWidth = max(array_map([__CLASS__, 'width'], array_keys($choices = $question->getChoices())));
foreach ($choices as $key => $value) {
$padding = str_repeat(' ', $maxWidth - self::width($key));
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
index ddfc5fd382143..b4c1615b396c7 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
@@ -40,6 +40,7 @@ class AutowirePass extends AbstractRecursivePass
private $decoratedClass;
private $decoratedId;
private $methodCalls;
+ private $defaultArgument;
private $getPreviousValue;
private $decoratedMethodIndex;
private $decoratedMethodArgumentIndex;
@@ -48,6 +49,10 @@ class AutowirePass extends AbstractRecursivePass
public function __construct(bool $throwOnAutowireException = true)
{
$this->throwOnAutowiringException = $throwOnAutowireException;
+ $this->defaultArgument = new class() {
+ public $value;
+ public $names;
+ };
}
/**
@@ -62,6 +67,7 @@ public function process(ContainerBuilder $container)
$this->decoratedClass = null;
$this->decoratedId = null;
$this->methodCalls = null;
+ $this->defaultArgument->names = null;
$this->getPreviousValue = null;
$this->decoratedMethodIndex = null;
$this->decoratedMethodArgumentIndex = null;
@@ -153,14 +159,13 @@ private function autowireCalls(\ReflectionClass $reflectionClass, bool $isRoot,
$this->decoratedClass = null;
$this->getPreviousValue = null;
- if ($isRoot && ($definition = $this->container->getDefinition($this->currentId)) && ($decoratedDefinition = $definition->getDecoratedService()) && null !== ($innerId = $decoratedDefinition[0]) && $this->container->has($innerId)) {
- // If the class references to itself and is decorated, provide the inner service id and class to not get a circular reference
- $this->decoratedClass = $this->container->findDefinition($innerId)->getClass();
- $this->decoratedId = $decoratedDefinition[1] ?? $this->currentId.'.inner';
+ if ($isRoot && ($definition = $this->container->getDefinition($this->currentId)) && null !== ($this->decoratedId = $definition->innerServiceId) && $this->container->has($this->decoratedId)) {
+ $this->decoratedClass = $this->container->findDefinition($this->decoratedId)->getClass();
}
+ $patchedIndexes = [];
+
foreach ($this->methodCalls as $i => $call) {
- $this->decoratedMethodIndex = $i;
[$method, $arguments] = $call;
if ($method instanceof \ReflectionFunctionAbstract) {
@@ -177,13 +182,39 @@ private function autowireCalls(\ReflectionClass $reflectionClass, bool $isRoot,
}
}
- $arguments = $this->autowireMethod($reflectionMethod, $arguments, $checkAttributes);
+ $arguments = $this->autowireMethod($reflectionMethod, $arguments, $checkAttributes, $i);
if ($arguments !== $call[1]) {
$this->methodCalls[$i][1] = $arguments;
+ $patchedIndexes[] = $i;
}
}
+ // use named arguments to skip complex default values
+ foreach ($patchedIndexes as $i) {
+ $namedArguments = null;
+ $arguments = $this->methodCalls[$i][1];
+
+ foreach ($arguments as $j => $value) {
+ if ($namedArguments && !$value instanceof $this->defaultArgument) {
+ unset($arguments[$j]);
+ $arguments[$namedArguments[$j]] = $value;
+ }
+ if ($namedArguments || !$value instanceof $this->defaultArgument) {
+ continue;
+ }
+
+ if (\PHP_VERSION_ID >= 80100 && (\is_array($value->value) ? $value->value : \is_object($value->value))) {
+ unset($arguments[$j]);
+ $namedArguments = $value->names;
+ } else {
+ $arguments[$j] = $value->value;
+ }
+ }
+
+ $this->methodCalls[$i][1] = $arguments;
+ }
+
return $this->methodCalls;
}
@@ -194,7 +225,7 @@ private function autowireCalls(\ReflectionClass $reflectionClass, bool $isRoot,
*
* @throws AutowiringFailedException
*/
- private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, array $arguments, bool $checkAttributes): array
+ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, array $arguments, bool $checkAttributes, int $methodIndex): array
{
$class = $reflectionMethod instanceof \ReflectionMethod ? $reflectionMethod->class : $this->currentId;
$method = $reflectionMethod->name;
@@ -202,8 +233,11 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
if ($reflectionMethod->isVariadic()) {
array_pop($parameters);
}
+ $this->defaultArgument->names = new \ArrayObject();
foreach ($parameters as $index => $parameter) {
+ $this->defaultArgument->names[$index] = $parameter->name;
+
if (\array_key_exists($index, $arguments) && '' !== $arguments[$index]) {
continue;
}
@@ -241,7 +275,8 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
// be false when isOptional() returns true. If the
// argument *is* optional, allow it to be missing
if ($parameter->isOptional()) {
- continue;
+ --$index;
+ break;
}
$type = ProxyHelper::getTypeHint($reflectionMethod, $parameter, false);
$type = $type ? sprintf('is type-hinted "%s"', ltrim($type, '\\')) : 'has no type-hint';
@@ -250,7 +285,8 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
}
// specifically pass the default value
- $arguments[$index] = $parameter->getDefaultValue();
+ $arguments[$index] = clone $this->defaultArgument;
+ $arguments[$index]->value = $parameter->getDefaultValue();
continue;
}
@@ -260,7 +296,8 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
$failureMessage = $this->createTypeNotFoundMessageCallback($ref, sprintf('argument "$%s" of method "%s()"', $parameter->name, $class !== $this->currentId ? $class.'::'.$method : $method));
if ($parameter->isDefaultValueAvailable()) {
- $value = $parameter->getDefaultValue();
+ $value = clone $this->defaultArgument;
+ $value->value = $parameter->getDefaultValue();
} elseif (!$parameter->allowsNull()) {
throw new AutowiringFailedException($this->currentId, $failureMessage);
}
@@ -281,6 +318,7 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
} else {
$arguments[$index] = new TypedReference($this->decoratedId, $this->decoratedClass);
$this->getPreviousValue = $getValue;
+ $this->decoratedMethodIndex = $methodIndex;
$this->decoratedMethodArgumentIndex = $index;
continue;
@@ -292,8 +330,7 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a
if ($parameters && !isset($arguments[++$index])) {
while (0 <= --$index) {
- $parameter = $parameters[$index];
- if (!$parameter->isDefaultValueAvailable() || $parameter->getDefaultValue() !== $arguments[$index]) {
+ if (!$arguments[$index] instanceof $this->defaultArgument) {
break;
}
unset($arguments[$index]);
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckArgumentsValidityPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckArgumentsValidityPass.php
index 348498db269cf..93808b201d220 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/CheckArgumentsValidityPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckArgumentsValidityPass.php
@@ -39,7 +39,13 @@ protected function processValue($value, bool $isRoot = false)
}
$i = 0;
+ $hasNamedArgs = false;
foreach ($value->getArguments() as $k => $v) {
+ if (\PHP_VERSION_ID >= 80000 && preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $k)) {
+ $hasNamedArgs = true;
+ continue;
+ }
+
if ($k !== $i++) {
if (!\is_int($k)) {
$msg = sprintf('Invalid constructor argument for service "%s": integer expected but found string "%s". Check your service definition.', $this->currentId, $k);
@@ -57,11 +63,27 @@ protected function processValue($value, bool $isRoot = false)
throw new RuntimeException($msg);
}
}
+
+ if ($hasNamedArgs) {
+ $msg = sprintf('Invalid constructor argument for service "%s": cannot use positional argument after named argument. Check your service definition.', $this->currentId);
+ $value->addError($msg);
+ if ($this->throwExceptions) {
+ throw new RuntimeException($msg);
+ }
+
+ break;
+ }
}
foreach ($value->getMethodCalls() as $methodCall) {
$i = 0;
+ $hasNamedArgs = false;
foreach ($methodCall[1] as $k => $v) {
+ if (\PHP_VERSION_ID >= 80000 && preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $k)) {
+ $hasNamedArgs = true;
+ continue;
+ }
+
if ($k !== $i++) {
if (!\is_int($k)) {
$msg = sprintf('Invalid argument for method call "%s" of service "%s": integer expected but found string "%s". Check your service definition.', $methodCall[0], $this->currentId, $k);
@@ -79,6 +101,16 @@ protected function processValue($value, bool $isRoot = false)
throw new RuntimeException($msg);
}
}
+
+ if ($hasNamedArgs) {
+ $msg = sprintf('Invalid argument for method call "%s" of service "%s": cannot use positional argument after named argument. Check your service definition.', $methodCall[0], $this->currentId);
+ $value->addError($msg);
+ if ($this->throwExceptions) {
+ throw new RuntimeException($msg);
+ }
+
+ break;
+ }
}
}
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php
index fe7d29e26e210..ff72ce41ced26 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php
@@ -110,7 +110,7 @@ public function process(ContainerBuilder $container)
protected function processValue($value, bool $isRoot = false)
{
if ($value instanceof ArgumentInterface) {
- // Reference found in ArgumentInterface::getValues() are not inlineable
+ // References found in ArgumentInterface::getValues() are not inlineable
return $value;
}
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php
index 47f51c2478940..ed8e696bb2853 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php
@@ -62,10 +62,11 @@ public function __construct()
new AutowireRequiredMethodsPass(),
new AutowireRequiredPropertiesPass(),
new ResolveBindingsPass(),
+ new ServiceLocatorTagPass(),
+ new DecoratorServicePass(),
new CheckDefinitionValidityPass(),
new AutowirePass(false),
new ServiceLocatorTagPass(),
- new DecoratorServicePass(),
new ResolveTaggedIteratorArgumentPass(),
new ResolveServiceSubscribersPass(),
new ResolveReferencesToAliasesPass(),
diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
index da745850d5713..cd7ae70b8afdf 100644
--- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
+++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
@@ -739,8 +739,8 @@ private function addServiceMethodCalls(Definition $definition, string $variableN
$calls = '';
foreach ($definition->getMethodCalls() as $k => $call) {
$arguments = [];
- foreach ($call[1] as $value) {
- $arguments[] = $this->dumpValue($value);
+ foreach ($call[1] as $i => $value) {
+ $arguments[] = (\is_string($i) ? $i.': ' : '').$this->dumpValue($value);
}
$witherAssignation = '';
@@ -1132,8 +1132,8 @@ private function addNewInstance(Definition $definition, string $return = '', str
}
$arguments = [];
- foreach ($definition->getArguments() as $value) {
- $arguments[] = $this->dumpValue($value);
+ foreach ($definition->getArguments() as $i => $value) {
+ $arguments[] = (\is_string($i) ? $i.': ' : '').$this->dumpValue($value);
}
if (null !== $definition->getFactory()) {
diff --git a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php
index 9a28350796d76..8a454e9f00722 100644
--- a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php
+++ b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php
@@ -258,10 +258,8 @@ public function getEnv(string $prefix, string $name, \Closure $getEnv)
'fragment' => null,
];
- if (null !== $parsedEnv['path']) {
- // remove the '/' separator
- $parsedEnv['path'] = '/' === $parsedEnv['path'] ? null : substr($parsedEnv['path'], 1);
- }
+ // remove the '/' separator
+ $parsedEnv['path'] = '/' === ($parsedEnv['path'] ?? '/') ? '' : substr($parsedEnv['path'], 1);
return $parsedEnv;
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php
index 33e9adecfb4ea..9867e73293653 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php
@@ -985,8 +985,8 @@ public function testAutowireDecorator()
->setAutowired(true)
;
- (new AutowirePass())->process($container);
(new DecoratorServicePass())->process($container);
+ (new AutowirePass())->process($container);
$definition = $container->getDefinition(Decorator::class);
$this->assertSame(Decorator::class.'.inner', (string) $definition->getArgument(1));
@@ -1008,8 +1008,8 @@ public function testAutowireDecoratorChain()
->setAutowired(true)
;
- (new AutowirePass())->process($container);
(new DecoratorServicePass())->process($container);
+ (new AutowirePass())->process($container);
$definition = $container->getDefinition(DecoratedDecorator::class);
$this->assertSame(DecoratedDecorator::class.'.inner', (string) $definition->getArgument(0));
@@ -1026,8 +1026,8 @@ public function testAutowireDecoratorRenamedId()
->setAutowired(true)
;
- (new AutowirePass())->process($container);
(new DecoratorServicePass())->process($container);
+ (new AutowirePass())->process($container);
$definition = $container->getDefinition(Decorator::class);
$this->assertSame('renamed', (string) $definition->getArgument(1));
@@ -1044,11 +1044,12 @@ public function testDoNotAutowireDecoratorWhenSeveralArgumentOfTheType()
->setAutowired(true)
;
+ (new DecoratorServicePass())->process($container);
try {
(new AutowirePass())->process($container);
$this->fail('AutowirePass should have thrown an exception');
} catch (AutowiringFailedException $e) {
- $this->assertSame('Cannot autowire service "Symfony\Component\DependencyInjection\Tests\Compiler\NonAutowirableDecorator": argument "$decorated1" of method "__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\DecoratorInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "Symfony\Component\DependencyInjection\Tests\Compiler\Decorated", "Symfony\Component\DependencyInjection\Tests\Compiler\NonAutowirableDecorator".', (string) $e->getMessage());
+ $this->assertSame('Cannot autowire service "Symfony\Component\DependencyInjection\Tests\Compiler\NonAutowirableDecorator": argument "$decorated1" of method "__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\DecoratorInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "Symfony\Component\DependencyInjection\Tests\Compiler\NonAutowirableDecorator", "Symfony\Component\DependencyInjection\Tests\Compiler\NonAutowirableDecorator.inner".', (string) $e->getMessage());
}
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckArgumentsValidityPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckArgumentsValidityPassTest.php
index 1253abb37ff80..322dcd2583fbe 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckArgumentsValidityPassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/CheckArgumentsValidityPassTest.php
@@ -46,22 +46,22 @@ public function testProcess()
*/
public function testException(array $arguments, array $methodCalls)
{
- $this->expectException(RuntimeException::class);
$container = new ContainerBuilder();
$definition = $container->register('foo');
$definition->setArguments($arguments);
$definition->setMethodCalls($methodCalls);
$pass = new CheckArgumentsValidityPass();
+ $this->expectException(RuntimeException::class);
$pass->process($container);
}
public function definitionProvider()
{
return [
- [[null, 'a' => 'a'], []],
+ [['a' => 'a', null], []],
[[1 => 1], []],
- [[], [['baz', [null, 'a' => 'a']]]],
+ [[], [['baz', ['a' => 'a', null]]]],
[[], [['baz', [1 => 1]]]],
];
}
@@ -70,7 +70,7 @@ public function testNoException()
{
$container = new ContainerBuilder();
$definition = $container->register('foo');
- $definition->setArguments([null, 'a' => 'a']);
+ $definition->setArguments(['a' => 'a', null]);
$pass = new CheckArgumentsValidityPass(false);
$pass->process($container);
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php
index 848bb7445e10a..2cc52e91d88e8 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php
@@ -175,6 +175,33 @@ public function testCanDecorateServiceLocator()
$this->assertSame($container->get('foo'), $container->get(DecoratedServiceLocator::class)->get('foo'));
}
+ public function testAliasDecoratedService()
+ {
+ $container = new ContainerBuilder();
+
+ $container->register('service', ServiceLocator::class)
+ ->setPublic(true)
+ ->setArguments([[]])
+ ;
+ $container->register('decorator', DecoratedServiceLocator::class)
+ ->setDecoratedService('service')
+ ->setAutowired(true)
+ ->setPublic(true)
+ ;
+ $container->setAlias(ServiceLocator::class, 'decorator.inner')
+ ->setPublic(true)
+ ;
+ $container->register('user_service', DecoratedServiceLocator::class)
+ ->setAutowired(true)
+ ;
+
+ $container->compile();
+
+ $this->assertInstanceOf(DecoratedServiceLocator::class, $container->get('service'));
+ $this->assertInstanceOf(ServiceLocator::class, $container->get(ServiceLocator::class));
+ $this->assertSame($container->get('service'), $container->get('decorator'));
+ }
+
/**
* @dataProvider getYamlCompileTests
*/
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
index f49484794d3f4..f3b0528d02ceb 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
@@ -45,6 +45,7 @@
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooClassWithEnumAttribute;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooUnitEnum;
use Symfony\Component\DependencyInjection\Tests\Fixtures\FooWithAbstractArgument;
+use Symfony\Component\DependencyInjection\Tests\Fixtures\NewInInitializer;
use Symfony\Component\DependencyInjection\Tests\Fixtures\ScalarFactory;
use Symfony\Component\DependencyInjection\Tests\Fixtures\StubbedTranslator;
use Symfony\Component\DependencyInjection\Tests\Fixtures\TestDefinition1;
@@ -1207,6 +1208,24 @@ public function testDumpHandlesObjectClassNames()
$this->assertInstanceOf(\stdClass::class, $container->get('bar'));
}
+ /**
+ * @requires PHP 8.1
+ */
+ public function testNewInInitializer()
+ {
+ $container = new ContainerBuilder();
+ $container
+ ->register('foo', NewInInitializer::class)
+ ->setPublic(true)
+ ->setAutowired(true)
+ ->setArguments(['$bar' => 234]);
+
+ $container->compile();
+
+ $dumper = new PhpDumper($container);
+ $this->assertStringEqualsFile(self::$fixturesPath.'/php/services_new_in_initializer.php', $dumper->dump());
+ }
+
/**
* @requires PHP 8.1
*/
diff --git a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php
index 109fb27e7190f..0b84145beda02 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php
@@ -640,8 +640,8 @@ public function testGetEnvUrlPath(?string $expected, string $url)
public function provideGetEnvUrlPath()
{
return [
- [null, 'https://symfony.com'],
- [null, 'https://symfony.com/'],
+ ['', 'https://symfony.com'],
+ ['', 'https://symfony.com/'],
['/', 'https://symfony.com//'],
['blog', 'https://symfony.com/blog'],
['blog/', 'https://symfony.com/blog/'],
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/NewInInitializer.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/NewInInitializer.php
new file mode 100644
index 0000000000000..4309ab330bd9c
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/NewInInitializer.php
@@ -0,0 +1,10 @@
+services = $this->privates = [];
+ $this->methodMap = [
+ 'foo' => 'getFooService',
+ ];
+
+ $this->aliases = [];
+ }
+
+ public function compile(): void
+ {
+ throw new LogicException('You cannot compile a dumped container that was already compiled.');
+ }
+
+ public function isCompiled(): bool
+ {
+ return true;
+ }
+
+ public function getRemovedIds(): array
+ {
+ return [
+ 'Psr\\Container\\ContainerInterface' => true,
+ 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true,
+ ];
+ }
+
+ /**
+ * Gets the public 'foo' shared autowired service.
+ *
+ * @return \Symfony\Component\DependencyInjection\Tests\Fixtures\NewInInitializer
+ */
+ protected function getFooService()
+ {
+ return $this->services['foo'] = new \Symfony\Component\DependencyInjection\Tests\Fixtures\NewInInitializer(bar: 234);
+ }
+}
diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php
index ade7fa5978a0b..4d2cf32ed3dfb 100644
--- a/src/Symfony/Component/Dotenv/Dotenv.php
+++ b/src/Symfony/Component/Dotenv/Dotenv.php
@@ -191,8 +191,12 @@ public function populate(array $values, bool $overrideExistingVars = false): voi
foreach ($values as $name => $value) {
$notHttpName = 0 !== strpos($name, 'HTTP_');
+ if (isset($_SERVER[$name]) && $notHttpName && !isset($_ENV[$name])) {
+ $_ENV[$name] = $_SERVER[$name];
+ }
+
// don't check existence with getenv() because of thread safety issues
- if (!isset($loadedVars[$name]) && (!$overrideExistingVars && (isset($_ENV[$name]) || (isset($_SERVER[$name]) && $notHttpName)))) {
+ if (!isset($loadedVars[$name]) && !$overrideExistingVars && isset($_ENV[$name])) {
continue;
}
diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php
index 44244b11d334c..682e81e88b884 100644
--- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php
+++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php
@@ -226,63 +226,71 @@ public function testLoad()
public function testLoadEnv()
{
- unset($_ENV['FOO']);
- unset($_ENV['BAR']);
- unset($_SERVER['FOO']);
- unset($_SERVER['BAR']);
- putenv('FOO');
- putenv('BAR');
+ $resetContext = static function (): void {
+ unset($_ENV['SYMFONY_DOTENV_VARS']);
+ unset($_ENV['FOO']);
+ unset($_ENV['TEST_APP_ENV']);
+ unset($_SERVER['SYMFONY_DOTENV_VARS']);
+ unset($_SERVER['FOO']);
+ unset($_SERVER['TEST_APP_ENV']);
+ putenv('SYMFONY_DOTENV_VARS');
+ putenv('FOO');
+ putenv('TEST_APP_ENV');
+ };
@mkdir($tmpdir = sys_get_temp_dir().'/dotenv');
$path = tempnam($tmpdir, 'sf-');
// .env
-
file_put_contents($path, 'FOO=BAR');
+
+ $resetContext();
(new Dotenv())->usePutenv()->loadEnv($path, 'TEST_APP_ENV');
$this->assertSame('BAR', getenv('FOO'));
$this->assertSame('dev', getenv('TEST_APP_ENV'));
// .env.local
+ file_put_contents("$path.local", 'FOO=localBAR');
+ $resetContext();
$_SERVER['TEST_APP_ENV'] = 'local';
- file_put_contents("$path.local", 'FOO=localBAR');
(new Dotenv())->usePutenv()->loadEnv($path, 'TEST_APP_ENV');
$this->assertSame('localBAR', getenv('FOO'));
// special case for test
-
+ $resetContext();
$_SERVER['TEST_APP_ENV'] = 'test';
(new Dotenv())->usePutenv()->loadEnv($path, 'TEST_APP_ENV');
$this->assertSame('BAR', getenv('FOO'));
// .env.dev
-
- unset($_SERVER['TEST_APP_ENV']);
file_put_contents("$path.dev", 'FOO=devBAR');
+
+ $resetContext();
(new Dotenv())->usePutenv()->loadEnv($path, 'TEST_APP_ENV');
$this->assertSame('devBAR', getenv('FOO'));
// .env.dev.local
-
file_put_contents("$path.dev.local", 'FOO=devlocalBAR');
+
+ $resetContext();
(new Dotenv())->usePutenv()->loadEnv($path, 'TEST_APP_ENV');
$this->assertSame('devlocalBAR', getenv('FOO'));
+ unlink("$path.local");
+ unlink("$path.dev");
+ unlink("$path.dev.local");
// .env.dist
+ file_put_contents("$path.dist", 'FOO=distBAR');
+ $resetContext();
unlink($path);
- file_put_contents("$path.dist", 'BAR=distBAR');
(new Dotenv())->usePutenv()->loadEnv($path, 'TEST_APP_ENV');
- $this->assertSame('distBAR', getenv('BAR'));
-
- putenv('FOO');
- putenv('BAR');
+ $this->assertSame('distBAR', getenv('FOO'));
unlink("$path.dist");
- unlink("$path.local");
- unlink("$path.dev");
- unlink("$path.dev.local");
+
+ $resetContext();
rmdir($tmpdir);
}
@@ -475,26 +483,42 @@ public function testDoNotUsePutenv()
$this->assertFalse(getenv('TEST_USE_PUTENV'));
}
+ public function testSERVERVarsDuplicationInENV()
+ {
+ unset($_ENV['SYMFONY_DOTENV_VARS'], $_SERVER['SYMFONY_DOTENV_VARS'], $_ENV['FOO']);
+ $_SERVER['FOO'] = 'CCC';
+
+ (new Dotenv())->populate(['FOO' => 'BAR']);
+
+ $this->assertSame('CCC', $_ENV['FOO']);
+ }
+
public function testBootEnv()
{
+ $resetContext = static function (): void {
+ unset($_SERVER['SYMFONY_DOTENV_VARS'], $_ENV['SYMFONY_DOTENV_VARS']);
+ unset($_SERVER['TEST_APP_ENV'], $_ENV['TEST_APP_ENV']);
+ unset($_SERVER['TEST_APP_DEBUG'], $_ENV['TEST_APP_DEBUG']);
+ unset($_SERVER['FOO'], $_ENV['FOO']);
+ };
+
@mkdir($tmpdir = sys_get_temp_dir().'/dotenv');
$path = tempnam($tmpdir, 'sf-');
file_put_contents($path, 'FOO=BAR');
+ $resetContext();
(new Dotenv('TEST_APP_ENV', 'TEST_APP_DEBUG'))->bootEnv($path);
-
$this->assertSame('BAR', $_SERVER['FOO']);
-
- unset($_SERVER['FOO'], $_ENV['FOO']);
unlink($path);
file_put_contents($path.'.local.php', ' "dev", "FOO" => "BAR"];');
+ $resetContext();
(new Dotenv('TEST_APP_ENV', 'TEST_APP_DEBUG'))->bootEnv($path);
$this->assertSame('BAR', $_SERVER['FOO']);
$this->assertSame('1', $_SERVER['TEST_APP_DEBUG']);
-
- unset($_SERVER['FOO'], $_ENV['FOO']);
unlink($path.'.local.php');
+
+ $resetContext();
rmdir($tmpdir);
}
}
diff --git a/src/Symfony/Component/Form/Extension/Core/CoreExtension.php b/src/Symfony/Component/Form/Extension/Core/CoreExtension.php
index 9c19603df003a..c6768b86b497a 100644
--- a/src/Symfony/Component/Form/Extension/Core/CoreExtension.php
+++ b/src/Symfony/Component/Form/Extension/Core/CoreExtension.php
@@ -45,7 +45,7 @@ protected function loadTypes()
new Type\FormType($this->propertyAccessor),
new Type\BirthdayType(),
new Type\CheckboxType(),
- new Type\ChoiceType($this->choiceListFactory),
+ new Type\ChoiceType($this->choiceListFactory, $this->translator),
new Type\CollectionType(),
new Type\CountryType(),
new Type\DateIntervalType(),
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
index c2899bbd78ad9..6b8757c075b15 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
@@ -63,6 +63,11 @@ public function __construct(ChoiceListFactoryInterface $choiceListFactory = null
)
);
+ if (null !== $translator && !$translator instanceof TranslatorInterface) {
+ throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be han instance of "%s", "%s" given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
+ }
+ $this->translator = $translator;
+
// BC, to be removed in 6.0
if ($this->choiceListFactory instanceof CachingFactoryDecorator) {
return;
@@ -73,11 +78,6 @@ public function __construct(ChoiceListFactoryInterface $choiceListFactory = null
if ($ref->getNumberOfParameters() < 3) {
trigger_deprecation('symfony/form', '5.1', 'Not defining a third parameter "callable|null $filter" in "%s::%s()" is deprecated.', $ref->class, $ref->name);
}
-
- if (null !== $translator && !$translator instanceof TranslatorInterface) {
- throw new \TypeError(sprintf('Argument 2 passed to "%s()" must be han instance of "%s", "%s" given.', __METHOD__, TranslatorInterface::class, \is_object($translator) ? \get_class($translator) : \gettype($translator)));
- }
- $this->translator = $translator;
}
/**
diff --git a/src/Symfony/Component/Form/Resources/translations/validators.bs.xlf b/src/Symfony/Component/Form/Resources/translations/validators.bs.xlf
index 259b05f842995..319f91544d50c 100644
--- a/src/Symfony/Component/Form/Resources/translations/validators.bs.xlf
+++ b/src/Symfony/Component/Form/Resources/translations/validators.bs.xlf
@@ -16,7 +16,7 @@
This value is not a valid HTML5 color.
- Ova vrijednost nije ispravna HTML5 boja.
+ Ova vrijednost nije važeća HTML5 boja.Please enter a valid birthdate.
diff --git a/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf b/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf
index 1bbe090f34472..4ed719917549d 100644
--- a/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf
+++ b/src/Symfony/Component/Form/Resources/translations/validators.fa.xlf
@@ -24,7 +24,7 @@
The selected choice is invalid.
- گزینهی انتخابشده نامعتبر است
+ گزینهی انتخابشده نامعتبر است.The collection is invalid.
@@ -40,7 +40,7 @@
Please select a valid currency.
- لطفاً یک واحد پولی معتبر انتخاب کنید.
+ لطفاً یک واحد پول معتبر انتخاب کنید.Please choose a valid date interval.
@@ -72,7 +72,7 @@
Please select a valid locale.
- لطفاً یک جغرافیای (locale) معتبر انتخاب کنید.
+ لطفاً یک منطقهجغرافیایی (locale) معتبر انتخاب کنید.Please enter a valid money amount.
@@ -116,11 +116,11 @@
The checkbox has an invalid value.
- کادر انتخاب (checkbox) دارای مقداری نامعتبر است.
+ کادر انتخاب (checkbox) دارای مقداری نامعتبر است.Please enter a valid email address.
- لطفاً یک آدرس رایانامهی معتبر وارد کنید.
+ لطفاً یک آدرس رایانامه (ایمیل) معتبر وارد کنید.Please select a valid option.
diff --git a/src/Symfony/Component/Form/Resources/translations/validators.fr.xlf b/src/Symfony/Component/Form/Resources/translations/validators.fr.xlf
index f40dea752d3dd..d65826467229f 100644
--- a/src/Symfony/Component/Form/Resources/translations/validators.fr.xlf
+++ b/src/Symfony/Component/Form/Resources/translations/validators.fr.xlf
@@ -4,7 +4,7 @@
This form should not contain extra fields.
- Ce formulaire ne doit pas contenir des champs supplémentaires.
+ Ce formulaire ne doit pas contenir de champs supplémentaires.The uploaded file was too large. Please try to upload a smaller file.
diff --git a/src/Symfony/Component/Form/Resources/translations/validators.hr.xlf b/src/Symfony/Component/Form/Resources/translations/validators.hr.xlf
index a04ab1283f840..9f17b5ea1eb37 100644
--- a/src/Symfony/Component/Form/Resources/translations/validators.hr.xlf
+++ b/src/Symfony/Component/Form/Resources/translations/validators.hr.xlf
@@ -16,7 +16,7 @@
This value is not a valid HTML5 color.
- Ova vrijednost nije ispravna HTML5 boja.
+ Ova vrijednost nije važeća HTML5 boja.Please enter a valid birthdate.
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTranslationTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTranslationTest.php
new file mode 100644
index 0000000000000..defb5dbe52e64
--- /dev/null
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTranslationTest.php
@@ -0,0 +1,73 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Form\Tests\Extension\Core\Type;
+
+use Symfony\Component\Form\Extension\Core\CoreExtension;
+use Symfony\Component\Form\Test\TypeTestCase;
+use Symfony\Contracts\Translation\TranslatorInterface;
+
+class ChoiceTypeTranslationTest extends TypeTestCase
+{
+ public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\ChoiceType';
+
+ private $choices = [
+ 'Bernhard' => 'a',
+ 'Fabien' => 'b',
+ 'Kris' => 'c',
+ 'Jon' => 'd',
+ 'Roman' => 'e',
+ ];
+
+ protected function getExtensions()
+ {
+ $translator = $this->createMock(TranslatorInterface::class);
+ $translator->expects($this->any())->method('trans')
+ ->willReturnCallback(function ($key, $params) {
+ return strtr(sprintf('Translation of: %s', $key), $params);
+ }
+ );
+
+ return array_merge(parent::getExtensions(), [new CoreExtension(null, null, $translator)]);
+ }
+
+ public function testInvalidMessageAwarenessForMultiple()
+ {
+ $form = $this->factory->create(static::TESTED_TYPE, null, [
+ 'multiple' => true,
+ 'expanded' => false,
+ 'choices' => $this->choices,
+ 'invalid_message' => 'You are not able to use value "{{ value }}"',
+ ]);
+
+ $form->submit(['My invalid choice']);
+ $this->assertEquals(
+ "ERROR: Translation of: You are not able to use value \"My invalid choice\"\n",
+ (string) $form->getErrors(true)
+ );
+ }
+
+ public function testInvalidMessageAwarenessForMultipleWithoutScalarOrArrayViewData()
+ {
+ $form = $this->factory->create(static::TESTED_TYPE, null, [
+ 'multiple' => true,
+ 'expanded' => false,
+ 'choices' => $this->choices,
+ 'invalid_message' => 'You are not able to use value "{{ value }}"',
+ ]);
+
+ $form->submit(new \stdClass());
+ $this->assertEquals(
+ "ERROR: Translation of: You are not able to use value \"stdClass\"\n",
+ (string) $form->getErrors(true)
+ );
+ }
+}
diff --git a/src/Symfony/Component/HttpClient/DependencyInjection/HttpClientPass.php b/src/Symfony/Component/HttpClient/DependencyInjection/HttpClientPass.php
index 5ed88909eba67..73f88651345d3 100644
--- a/src/Symfony/Component/HttpClient/DependencyInjection/HttpClientPass.php
+++ b/src/Symfony/Component/HttpClient/DependencyInjection/HttpClientPass.php
@@ -42,6 +42,7 @@ public function process(ContainerBuilder $container)
foreach ($container->findTaggedServiceIds($this->clientTag) as $id => $tags) {
$container->register('.debug.'.$id, TraceableHttpClient::class)
->setArguments([new Reference('.debug.'.$id.'.inner'), new Reference('debug.stopwatch', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)])
+ ->addTag('kernel.reset', ['method' => 'reset'])
->setDecoratedService($id);
$container->getDefinition('data_collector.http_client')
->addMethodCall('registerClient', [$id, new Reference('.debug.'.$id)]);
diff --git a/src/Symfony/Component/HttpClient/EventSourceHttpClient.php b/src/Symfony/Component/HttpClient/EventSourceHttpClient.php
index 81d9f4bfc8bf8..7ac8940b6cada 100644
--- a/src/Symfony/Component/HttpClient/EventSourceHttpClient.php
+++ b/src/Symfony/Component/HttpClient/EventSourceHttpClient.php
@@ -78,7 +78,7 @@ public function request(string $method, string $url, array $options = []): Respo
try {
$isTimeout = $chunk->isTimeout();
- if (null !== $chunk->getInformationalStatus()) {
+ if (null !== $chunk->getInformationalStatus() || $context->getInfo('canceled')) {
yield $chunk;
return;
diff --git a/src/Symfony/Component/HttpClient/Response/AsyncResponse.php b/src/Symfony/Component/HttpClient/Response/AsyncResponse.php
index 06518f1a2cb3a..3d07cba9b9b43 100644
--- a/src/Symfony/Component/HttpClient/Response/AsyncResponse.php
+++ b/src/Symfony/Component/HttpClient/Response/AsyncResponse.php
@@ -247,7 +247,7 @@ public static function stream(iterable $responses, float $timeout = null, string
}
}
- if (!$client) {
+ if (!$client || !$wrappedResponses) {
return;
}
diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php
index 9d289d84770fa..001c037394fd3 100644
--- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php
+++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php
@@ -247,13 +247,15 @@ public function getContent(bool $throw = true): string
public function __destruct()
{
- curl_setopt($this->handle, \CURLOPT_VERBOSE, false);
+ try {
+ if (null === $this->timeout) {
+ return; // Unused pushed response
+ }
- if (null === $this->timeout) {
- return; // Unused pushed response
+ $this->doDestruct();
+ } finally {
+ curl_setopt($this->handle, \CURLOPT_VERBOSE, false);
}
-
- $this->doDestruct();
}
/**
@@ -313,6 +315,10 @@ private static function perform(ClientState $multi, array &$responses = null): v
}
}
+ if (\CURLE_RECV_ERROR === $result && 'H' === $waitFor[0] && 400 <= ($responses[(int) $ch]->info['http_code'] ?? 0)) {
+ $multi->handlesActivity[$id][] = new FirstChunk();
+ }
+
$multi->handlesActivity[$id][] = null;
$multi->handlesActivity[$id][] = \in_array($result, [\CURLE_OK, \CURLE_TOO_MANY_REDIRECTS], true) || '_0' === $waitFor || curl_getinfo($ch, \CURLINFO_SIZE_DOWNLOAD) === curl_getinfo($ch, \CURLINFO_CONTENT_LENGTH_DOWNLOAD) ? null : new TransportException(sprintf('%s for "%s".', curl_strerror($result), curl_getinfo($ch, \CURLINFO_EFFECTIVE_URL)));
}
diff --git a/src/Symfony/Component/HttpClient/Response/MockResponse.php b/src/Symfony/Component/HttpClient/Response/MockResponse.php
index bdb655926628f..71fe8fbd17592 100644
--- a/src/Symfony/Component/HttpClient/Response/MockResponse.php
+++ b/src/Symfony/Component/HttpClient/Response/MockResponse.php
@@ -105,7 +105,11 @@ public function cancel(): void
{
$this->info['canceled'] = true;
$this->info['error'] = 'Response has been canceled.';
- $this->body = null;
+ try {
+ $this->body = null;
+ } catch (TransportException $e) {
+ // ignore errors when canceling
+ }
}
/**
diff --git a/src/Symfony/Component/HttpClient/RetryableHttpClient.php b/src/Symfony/Component/HttpClient/RetryableHttpClient.php
index afab2f8d0388b..97b48da423a85 100644
--- a/src/Symfony/Component/HttpClient/RetryableHttpClient.php
+++ b/src/Symfony/Component/HttpClient/RetryableHttpClient.php
@@ -59,7 +59,7 @@ public function request(string $method, string $url, array $options = []): Respo
return new AsyncResponse($this->client, $method, $url, $options, function (ChunkInterface $chunk, AsyncContext $context) use ($method, $url, $options, &$retryCount, &$content, &$firstChunk) {
$exception = null;
try {
- if ($chunk->isTimeout() || null !== $chunk->getInformationalStatus()) {
+ if ($chunk->isTimeout() || null !== $chunk->getInformationalStatus() || $context->getInfo('canceled')) {
yield $chunk;
return;
@@ -76,23 +76,14 @@ public function request(string $method, string $url, array $options = []): Respo
}
if (false === $shouldRetry) {
- $context->passthru();
- if (null !== $firstChunk) {
- yield $firstChunk;
- yield $context->createChunk($content);
- yield $chunk;
- } else {
- yield $chunk;
- }
- $content = '';
+ yield from $this->passthru($context, $firstChunk, $content, $chunk);
return;
}
}
} elseif ($chunk->isFirst()) {
if (false === $shouldRetry = $this->strategy->shouldRetry($context, null, null)) {
- $context->passthru();
- yield $chunk;
+ yield from $this->passthru($context, $firstChunk, $content, $chunk);
return;
}
@@ -105,9 +96,9 @@ public function request(string $method, string $url, array $options = []): Respo
return;
}
} else {
- $content .= $chunk->getContent();
-
if (!$chunk->isLast()) {
+ $content .= $chunk->getContent();
+
return;
}
@@ -116,10 +107,7 @@ public function request(string $method, string $url, array $options = []): Respo
}
if (false === $shouldRetry) {
- $context->passthru();
- yield $firstChunk;
- yield $context->createChunk($content);
- $content = '';
+ yield from $this->passthru($context, $firstChunk, $content, $chunk);
return;
}
@@ -159,4 +147,22 @@ private function getDelayFromHeader(array $headers): ?int
return null;
}
+
+ private function passthru(AsyncContext $context, ?ChunkInterface $firstChunk, string &$content, ChunkInterface $lastChunk): \Generator
+ {
+ $context->passthru();
+
+ if (null !== $firstChunk) {
+ yield $firstChunk;
+ }
+
+ if ('' !== $content) {
+ $chunk = $context->createChunk($content);
+ $content = '';
+
+ yield $chunk;
+ }
+
+ yield $lastChunk;
+ }
}
diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php
index 87a460741e334..59e4dc1da7cc8 100644
--- a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php
+++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php
@@ -361,4 +361,16 @@ public function testHandleIsRemovedOnException()
$this->assertCount(0, $clientState->openHandles);
}
}
+
+ public function testDebugInfoOnDestruct()
+ {
+ $client = $this->getHttpClient(__FUNCTION__);
+
+ $traceInfo = [];
+ $client->request('GET', 'http://localhost:8057', ['on_progress' => function (int $dlNow, int $dlSize, array $info) use (&$traceInfo) {
+ $traceInfo = $info;
+ }]);
+
+ $this->assertNotEmpty($traceInfo['debug']);
+ }
}
diff --git a/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php
index e088ad03ffb84..415eb41d51ad6 100644
--- a/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php
+++ b/src/Symfony/Component/HttpClient/Tests/RetryableHttpClientTest.php
@@ -4,6 +4,7 @@
use PHPUnit\Framework\TestCase;
use Symfony\Component\HttpClient\Exception\ServerException;
+use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\NativeHttpClient;
use Symfony\Component\HttpClient\Response\AsyncContext;
@@ -159,4 +160,22 @@ public function shouldRetry(AsyncContext $context, ?string $responseContent, ?Tr
$this->assertCount(2, $logger->logs);
$this->assertSame('Try #{count} after {delay}ms: Could not resolve host "does.not.exists".', $logger->logs[0]);
}
+
+ public function testCancelOnTimeout()
+ {
+ $client = HttpClient::create();
+
+ if ($client instanceof NativeHttpClient) {
+ $this->markTestSkipped('NativeHttpClient cannot timeout before receiving headers');
+ }
+
+ $client = new RetryableHttpClient($client);
+
+ $response = $client->request('GET', 'https://example.com/');
+
+ foreach ($client->stream($response, 0) as $chunk) {
+ $this->assertTrue($chunk->isTimeout());
+ $response->cancel();
+ }
+ }
}
diff --git a/src/Symfony/Component/HttpFoundation/IpUtils.php b/src/Symfony/Component/HttpFoundation/IpUtils.php
index 68426f5b0bddc..6d98e5cd35bc3 100644
--- a/src/Symfony/Component/HttpFoundation/IpUtils.php
+++ b/src/Symfony/Component/HttpFoundation/IpUtils.php
@@ -36,6 +36,10 @@ private function __construct()
*/
public static function checkIp(?string $requestIp, $ips)
{
+ if (null === $requestIp) {
+ return false;
+ }
+
if (!\is_array($ips)) {
$ips = [$ips];
}
diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php
index 6393cc2790d62..853b81fbea318 100644
--- a/src/Symfony/Component/HttpFoundation/Response.php
+++ b/src/Symfony/Component/HttpFoundation/Response.php
@@ -138,7 +138,7 @@ class Response
*
* The list of codes is complete according to the
* {@link https://www.iana.org/assignments/http-status-codes/http-status-codes.xhtml Hypertext Transfer Protocol (HTTP) Status Code Registry}
- * (last updated 2016-03-01).
+ * (last updated 2018-09-21).
*
* Unless otherwise noted, the status code is defined in RFC2616.
*
diff --git a/src/Symfony/Component/HttpFoundation/Tests/Fixtures/xml/http-status-codes.xml b/src/Symfony/Component/HttpFoundation/Tests/Fixtures/xml/http-status-codes.xml
new file mode 100644
index 0000000000000..9e506696a4ca4
--- /dev/null
+++ b/src/Symfony/Component/HttpFoundation/Tests/Fixtures/xml/http-status-codes.xml
@@ -0,0 +1,375 @@
+
+
+
+
+ Hypertext Transfer Protocol (HTTP) Status Code Registry
+ 2018-09-21
+
+ HTTP Status Codes
+
+ IETF Review
+ 1xx: Informational - Request received, continuing process
+ 2xx: Success - The action was successfully received, understood, and accepted
+ 3xx: Redirection - Further action must be taken in order to complete the request
+ 4xx: Client Error - The request contains bad syntax or cannot be fulfilled
+ 5xx: Server Error - The server failed to fulfill an apparently valid request
+
+
+ 100
+ Continue
+ RFC7231, Section 6.2.1
+
+
+ 101
+ Switching Protocols
+ RFC7231, Section 6.2.2
+
+
+ 102
+ Processing
+
+
+
+ 103
+ Early Hints
+
+
+
+ 104-199
+ Unassigned
+
+
+ 200
+ OK
+ RFC7231, Section 6.3.1
+
+
+ 201
+ Created
+ RFC7231, Section 6.3.2
+
+
+ 202
+ Accepted
+ RFC7231, Section 6.3.3
+
+
+ 203
+ Non-Authoritative Information
+ RFC7231, Section 6.3.4
+
+
+ 204
+ No Content
+ RFC7231, Section 6.3.5
+
+
+ 205
+ Reset Content
+ RFC7231, Section 6.3.6
+
+
+ 206
+ Partial Content
+ RFC7233, Section 4.1
+
+
+ 207
+ Multi-Status
+
+
+
+ 208
+ Already Reported
+
+
+
+ 209-225
+ Unassigned
+
+
+ 226
+ IM Used
+
+
+
+ 227-299
+ Unassigned
+
+
+ 300
+ Multiple Choices
+ RFC7231, Section 6.4.1
+
+
+ 301
+ Moved Permanently
+ RFC7231, Section 6.4.2
+
+
+ 302
+ Found
+ RFC7231, Section 6.4.3
+
+
+ 303
+ See Other
+ RFC7231, Section 6.4.4
+
+
+ 304
+ Not Modified
+ RFC7232, Section 4.1
+
+
+ 305
+ Use Proxy
+ RFC7231, Section 6.4.5
+
+
+ 306
+ (Unused)
+ RFC7231, Section 6.4.6
+
+
+ 307
+ Temporary Redirect
+ RFC7231, Section 6.4.7
+
+
+ 308
+ Permanent Redirect
+
+
+
+ 309-399
+ Unassigned
+
+
+ 400
+ Bad Request
+ RFC7231, Section 6.5.1
+
+
+ 401
+ Unauthorized
+ RFC7235, Section 3.1
+
+
+ 402
+ Payment Required
+ RFC7231, Section 6.5.2
+
+
+ 403
+ Forbidden
+ RFC7231, Section 6.5.3
+
+
+ 404
+ Not Found
+ RFC7231, Section 6.5.4
+
+
+ 405
+ Method Not Allowed
+ RFC7231, Section 6.5.5
+
+
+ 406
+ Not Acceptable
+ RFC7231, Section 6.5.6
+
+
+ 407
+ Proxy Authentication Required
+ RFC7235, Section 3.2
+
+
+ 408
+ Request Timeout
+ RFC7231, Section 6.5.7
+
+
+ 409
+ Conflict
+ RFC7231, Section 6.5.8
+
+
+ 410
+ Gone
+ RFC7231, Section 6.5.9
+
+
+ 411
+ Length Required
+ RFC7231, Section 6.5.10
+
+
+ 412
+ Precondition Failed
+ RFC7232, Section 4.2
+ RFC8144, Section 3.2
+
+
+ 413
+ Payload Too Large
+ RFC7231, Section 6.5.11
+
+
+ 414
+ URI Too Long
+ RFC7231, Section 6.5.12
+
+
+ 415
+ Unsupported Media Type
+ RFC7231, Section 6.5.13
+ RFC7694, Section 3
+
+
+ 416
+ Range Not Satisfiable
+ RFC7233, Section 4.4
+
+
+ 417
+ Expectation Failed
+ RFC7231, Section 6.5.14
+
+
+ 418-420
+ Unassigned
+
+
+ 421
+ Misdirected Request
+ RFC7540, Section 9.1.2
+
+
+ 422
+ Unprocessable Entity
+
+
+
+ 423
+ Locked
+
+
+
+ 424
+ Failed Dependency
+
+
+
+ 425
+ Too Early
+
+
+
+ 426
+ Upgrade Required
+ RFC7231, Section 6.5.15
+
+
+ 427
+ Unassigned
+
+
+ 428
+ Precondition Required
+
+
+
+ 429
+ Too Many Requests
+
+
+
+ 430
+ Unassigned
+
+
+ 431
+ Request Header Fields Too Large
+
+
+
+ 432-450
+ Unassigned
+
+
+ 451
+ Unavailable For Legal Reasons
+
+
+
+ 452-499
+ Unassigned
+
+
+ 500
+ Internal Server Error
+ RFC7231, Section 6.6.1
+
+
+ 501
+ Not Implemented
+ RFC7231, Section 6.6.2
+
+
+ 502
+ Bad Gateway
+ RFC7231, Section 6.6.3
+
+
+ 503
+ Service Unavailable
+ RFC7231, Section 6.6.4
+
+
+ 504
+ Gateway Timeout
+ RFC7231, Section 6.6.5
+
+
+ 505
+ HTTP Version Not Supported
+ RFC7231, Section 6.6.6
+
+
+ 506
+ Variant Also Negotiates
+
+
+
+ 507
+ Insufficient Storage
+
+
+
+ 508
+ Loop Detected
+
+
+
+ 509
+ Unassigned
+
+
+ 510
+ Not Extended
+
+
+
+ 511
+ Network Authentication Required
+
+
+
+ 512-599
+ Unassigned
+
+
+
+
diff --git a/src/Symfony/Component/HttpFoundation/Tests/IpUtilsTest.php b/src/Symfony/Component/HttpFoundation/Tests/IpUtilsTest.php
index 2510b830a17d1..48509f9667cd7 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/IpUtilsTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/IpUtilsTest.php
@@ -39,6 +39,8 @@ public function getIpv4Data()
[true, '1.2.3.4', '192.168.1.0/0'],
[false, '1.2.3.4', '256.256.256/0'], // invalid CIDR notation
[false, 'an_invalid_ip', '192.168.1.0/24'],
+ [false, '', '1.2.3.4/1'],
+ [false, null, '1.2.3.4/1'],
];
}
@@ -69,6 +71,8 @@ public function getIpv6Data()
[false, '2a01:198:603:0:396e:4789:8e99:890f', ['::1', '1a01:198:603:0::/65']],
[false, '}__test|O:21:"JDatabaseDriverMysqli":3:{s:2', '::1'],
[false, '2a01:198:603:0:396e:4789:8e99:890f', 'unknown'],
+ [false, '', '::1'],
+ [false, null, '::1'],
];
}
diff --git a/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php
index c44ecc1f6099b..8e15f7a664af4 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php
@@ -1050,25 +1050,10 @@ protected function provideResponse()
*/
public function ianaCodesReasonPhrasesProvider()
{
- if (!\in_array('https', stream_get_wrappers(), true)) {
- $this->markTestSkipped('The "https" wrapper is not available');
- }
-
+ // XML taken from https://www.iana.org/assignments/http-status-codes/http-status-codes.xml
+ // (might not be up-to-date for older Symfony versions)
$ianaHttpStatusCodes = new \DOMDocument();
-
- $context = stream_context_create([
- 'http' => [
- 'method' => 'GET',
- 'timeout' => 30,
- 'user_agent' => __METHOD__,
- ],
- ]);
-
- if (!$rawStatusCodes = file_get_contents('https://www.iana.org/assignments/http-status-codes/http-status-codes.xml', false, $context)) {
- $this->markTestSkipped('The IANA server is throttling the list of status codes');
- }
-
- $ianaHttpStatusCodes->loadXML($rawStatusCodes);
+ $ianaHttpStatusCodes->load(__DIR__.'/Fixtures/xml/http-status-codes.xml');
if (!$ianaHttpStatusCodes->relaxNGValidate(__DIR__.'/schema/http-status-codes.rng')) {
self::fail('Invalid IANA\'s HTTP status code list.');
}
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index 7645f3df37e69..ca588639cb3cc 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -75,11 +75,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
private static $freshCache = [];
- public const VERSION = '5.3.9';
- public const VERSION_ID = 50309;
+ public const VERSION = '5.3.10';
+ public const VERSION_ID = 50310;
public const MAJOR_VERSION = 5;
public const MINOR_VERSION = 3;
- public const RELEASE_VERSION = 9;
+ public const RELEASE_VERSION = 10;
public const EXTRA_VERSION = '';
public const END_OF_MAINTENANCE = '01/2022';
diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/FragmentHandlerTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/FragmentHandlerTest.php
index b78fba4ce477f..1d0eb90bf6fdb 100644
--- a/src/Symfony/Component/HttpKernel/Tests/Fragment/FragmentHandlerTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/FragmentHandlerTest.php
@@ -19,9 +19,6 @@
use Symfony\Component\HttpKernel\Fragment\FragmentHandler;
use Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface;
-/**
- * @group time-sensitive
- */
class FragmentHandlerTest extends TestCase
{
private $requestStack;
@@ -71,7 +68,20 @@ public function testDeliverWithUnsuccessfulResponse()
public function testRender()
{
- $handler = $this->getHandler($this->returnValue(new Response('foo')), ['/', Request::create('/'), ['foo' => 'foo', 'ignore_errors' => true]]);
+ $expectedRequest = Request::create('/');
+ $handler = $this->getHandler(
+ $this->returnValue(new Response('foo')),
+ [
+ '/',
+ $this->callback(function (Request $request) use ($expectedRequest) {
+ $expectedRequest->server->remove('REQUEST_TIME_FLOAT');
+ $request->server->remove('REQUEST_TIME_FLOAT');
+
+ return $expectedRequest == $request;
+ }),
+ ['foo' => 'foo', 'ignore_errors' => true],
+ ]
+ );
$this->assertEquals('foo', $handler->render('/', 'foo', ['foo' => 'foo']));
}
diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php
index acd9df73753af..c22a426d7d31e 100644
--- a/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php
@@ -261,13 +261,18 @@ public function testIpAddressOfRangedTrustedProxyIsSetAsRemote()
/**
* Creates a Kernel expecting a request equals to $request.
*/
- private function getKernelExpectingRequest(Request $request, $strict = false)
+ private function getKernelExpectingRequest(Request $expectedRequest)
{
$kernel = $this->createMock(HttpKernelInterface::class);
$kernel
->expects($this->once())
->method('handle')
- ->with($request)
+ ->with($this->callback(function (Request $request) use ($expectedRequest) {
+ $expectedRequest->server->remove('REQUEST_TIME_FLOAT');
+ $request->server->remove('REQUEST_TIME_FLOAT');
+
+ return $expectedRequest == $request;
+ }))
->willReturn(new Response('foo'));
return $kernel;
diff --git a/src/Symfony/Component/Lock/Store/PdoStore.php b/src/Symfony/Component/Lock/Store/PdoStore.php
index b300e9fff3a5e..20673a7342fc7 100644
--- a/src/Symfony/Component/Lock/Store/PdoStore.php
+++ b/src/Symfony/Component/Lock/Store/PdoStore.php
@@ -272,7 +272,7 @@ public function createTable(): void
$this->addTableToSchema($schema);
foreach ($schema->toSql($conn->getDatabasePlatform()) as $sql) {
- if (method_exists($conn, 'executeStatement')) {
+ if ($conn instanceof Connection && method_exists($conn, 'executeStatement')) {
$conn->executeStatement($sql);
} else {
$conn->exec($sql);
@@ -302,7 +302,7 @@ public function createTable(): void
throw new \DomainException(sprintf('Creating the lock table is currently not implemented for PDO driver "%s".', $driver));
}
- if (method_exists($conn, 'executeStatement')) {
+ if ($conn instanceof Connection && method_exists($conn, 'executeStatement')) {
$conn->executeStatement($sql);
} else {
$conn->exec($sql);
@@ -333,7 +333,7 @@ private function prune(): void
$sql = "DELETE FROM $this->table WHERE $this->expirationCol <= {$this->getCurrentTimestampStatement()}";
$conn = $this->getConnection();
- if (method_exists($conn, 'executeStatement')) {
+ if ($conn instanceof Connection && method_exists($conn, 'executeStatement')) {
$conn->executeStatement($sql);
} else {
$conn->exec($sql);
diff --git a/src/Symfony/Component/Lock/Store/PostgreSqlStore.php b/src/Symfony/Component/Lock/Store/PostgreSqlStore.php
index 9fdbe94bac2ba..0e472d2c82717 100644
--- a/src/Symfony/Component/Lock/Store/PostgreSqlStore.php
+++ b/src/Symfony/Component/Lock/Store/PostgreSqlStore.php
@@ -18,7 +18,7 @@
use Symfony\Component\Lock\Exception\InvalidArgumentException;
use Symfony\Component\Lock\Exception\LockConflictedException;
use Symfony\Component\Lock\Key;
-use Symfony\Component\Lock\PersistingStoreInterface;
+use Symfony\Component\Lock\SharedLockStoreInterface;
/**
* PostgreSqlStore is a PersistingStoreInterface implementation using
@@ -276,7 +276,7 @@ private function checkDriver(): void
}
}
- private function getInternalStore(): PersistingStoreInterface
+ private function getInternalStore(): SharedLockStoreInterface
{
$namespace = spl_object_hash($this->getConnection());
diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/PostgreSqlConnection.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/PostgreSqlConnection.php
index 34fa328486e7a..d59e7b52c15ed 100644
--- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/PostgreSqlConnection.php
+++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/PostgreSqlConnection.php
@@ -11,6 +11,7 @@
namespace Symfony\Component\Messenger\Bridge\Doctrine\Transport;
+use Doctrine\DBAL\Driver\PDO\Connection as DoctrinePdoConnection;
use Doctrine\DBAL\Schema\Table;
/**
@@ -72,7 +73,12 @@ public function get(): ?array
$this->listening = true;
}
- $notification = $this->driverConnection->getWrappedConnection()->pgsqlGetNotify(\PDO::FETCH_ASSOC, $this->configuration['get_notify_timeout']);
+ $wrappedConnection = $this->driverConnection->getWrappedConnection();
+ if (!$wrappedConnection instanceof \PDO && $wrappedConnection instanceof DoctrinePdoConnection) {
+ $wrappedConnection = $wrappedConnection->getWrappedConnection();
+ }
+
+ $notification = $wrappedConnection->pgsqlGetNotify(\PDO::FETCH_ASSOC, $this->configuration['get_notify_timeout']);
if (
// no notifications, or for another table or queue
(false === $notification || $notification['message'] !== $this->configuration['table_name'] || $notification['payload'] !== $this->configuration['queue_name']) &&
diff --git a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/ConnectionTest.php b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/ConnectionTest.php
index 1754c83da008c..ae71c08e6c617 100644
--- a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/ConnectionTest.php
+++ b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/ConnectionTest.php
@@ -155,7 +155,7 @@ public function testKeepGettingPendingMessages()
$redis->expects($this->exactly(3))->method('xreadgroup')
->with('symfony', 'consumer', ['queue' => 0], 1, null)
- ->willReturn(['queue' => [['message' => '{"body":"Test","headers":[]}']]]);
+ ->willReturn(['queue' => [['message' => json_encode(['body' => 'Test', 'headers' => []])]]]);
$connection = Connection::fromDsn('redis://localhost/queue', [], $redis);
$this->assertNotNull($connection->get());
@@ -183,6 +183,9 @@ public function provideAuthDsn(): \Generator
{
yield 'Password only' => ['password', 'redis://password@localhost/queue'];
yield 'User and password' => [['user', 'password'], 'redis://user:password@localhost/queue'];
+ yield 'User and colon' => ['user', 'redis://user:@localhost/queue'];
+ yield 'Colon and password' => ['password', 'redis://:password@localhost/queue'];
+ yield 'Colon and falsy password' => ['0', 'redis://:0@localhost/queue'];
}
public function testAuthFromOptions()
diff --git a/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php
index 7ffd04caa97f5..bfb712dbf3efe 100644
--- a/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php
+++ b/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php
@@ -236,11 +236,13 @@ public static function fromDsn(string $dsn, array $redisOptions = [], $redis = n
];
if (isset($parsedUrl['host'])) {
+ $pass = '' !== ($parsedUrl['pass'] ?? '') ? $parsedUrl['pass'] : null;
+ $user = '' !== ($parsedUrl['user'] ?? '') ? $parsedUrl['user'] : null;
$connectionCredentials = [
'host' => $parsedUrl['host'] ?? '127.0.0.1',
'port' => $parsedUrl['port'] ?? 6379,
// See: https://github.com/phpredis/phpredis/#auth
- 'auth' => $redisOptions['auth'] ?? (isset($parsedUrl['pass']) && isset($parsedUrl['user']) ? [$parsedUrl['user'], $parsedUrl['pass']] : $parsedUrl['pass'] ?? $parsedUrl['user'] ?? null),
+ 'auth' => $redisOptions['auth'] ?? (null !== $pass && null !== $user ? [$user, $pass] : ($pass ?? $user)),
];
$pathParts = explode('/', rtrim($parsedUrl['path'] ?? '', '/'));
diff --git a/src/Symfony/Component/Messenger/Tests/TraceableMessageBusTest.php b/src/Symfony/Component/Messenger/Tests/TraceableMessageBusTest.php
index d0b7db99e0c9d..0b57cf37bad6c 100644
--- a/src/Symfony/Component/Messenger/Tests/TraceableMessageBusTest.php
+++ b/src/Symfony/Component/Messenger/Tests/TraceableMessageBusTest.php
@@ -156,4 +156,22 @@ public function testItTracesExceptions()
],
], $actualTracedMessage);
}
+
+ public function testItTracesExceptionsWhenMessageBusIsFiredFromArrayCallback()
+ {
+ $message = new DummyMessage('Hello');
+ $exception = new \RuntimeException();
+
+ $bus = $this->createMock(MessageBusInterface::class);
+ $bus->expects($this->once())
+ ->method('dispatch')
+ ->with($message)
+ ->willThrowException($exception);
+
+ $traceableBus = new TraceableMessageBus($bus);
+
+ $this->expectExceptionObject($exception);
+
+ array_map([$traceableBus, 'dispatch'], [$message]);
+ }
}
diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php
index 96f4503c2eede..891683790ad47 100644
--- a/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php
+++ b/src/Symfony/Component/Messenger/Tests/Transport/Serialization/PhpSerializerTest.php
@@ -53,6 +53,18 @@ public function testDecodingFailsWithBadFormat()
]);
}
+ public function testDecodingFailsWithBadBase64Body()
+ {
+ $this->expectException(MessageDecodingFailedException::class);
+ $this->expectExceptionMessageMatches('/Could not decode/');
+
+ $serializer = new PhpSerializer();
+
+ $serializer->decode([
+ 'body' => 'x',
+ ]);
+ }
+
public function testDecodingFailsWithBadClass()
{
$this->expectException(MessageDecodingFailedException::class);
diff --git a/src/Symfony/Component/Messenger/TraceableMessageBus.php b/src/Symfony/Component/Messenger/TraceableMessageBus.php
index b6784af706c57..df595b0867fa5 100644
--- a/src/Symfony/Component/Messenger/TraceableMessageBus.php
+++ b/src/Symfony/Component/Messenger/TraceableMessageBus.php
@@ -62,8 +62,8 @@ private function getCaller(): array
{
$trace = debug_backtrace(\DEBUG_BACKTRACE_IGNORE_ARGS, 8);
- $file = $trace[1]['file'];
- $line = $trace[1]['line'];
+ $file = $trace[1]['file'] ?? null;
+ $line = $trace[1]['line'] ?? null;
$handleTraitFile = (new \ReflectionClass(HandleTrait::class))->getFileName();
$found = false;
@@ -97,9 +97,12 @@ private function getCaller(): array
}
}
- $name = str_replace('\\', '/', $file);
- $name = substr($name, strrpos($name, '/') + 1);
+ $name = str_replace('\\', '/', (string) $file);
- return compact('name', 'file', 'line');
+ return [
+ 'name' => substr($name, strrpos($name, '/') + 1),
+ 'file' => $file,
+ 'line' => $line,
+ ];
}
}
diff --git a/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php b/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php
index 3a4804903c673..0516ee2f40292 100644
--- a/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php
+++ b/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php
@@ -58,6 +58,10 @@ public function encode(Envelope $envelope): array
private function safelyUnserialize(string $contents)
{
+ if ('' === $contents) {
+ throw new MessageDecodingFailedException('Could not decode an empty message using PHP serialization.');
+ }
+
$signalingException = new MessageDecodingFailedException(sprintf('Could not decode message using PHP serialization: %s.', $contents));
$prevUnserializeHandler = ini_set('unserialize_callback_func', self::class.'::handleUnserializeCallback');
$prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$prevErrorHandler, $signalingException) {
diff --git a/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php b/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php
index 526ad5eb6ac85..70cce2b680c3c 100644
--- a/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php
+++ b/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php
@@ -83,15 +83,17 @@ protected function doSend(MessageInterface $message): SentMessage
$contentType = $response->getHeaders(false)['content-type'][0] ?? '';
$jsonContents = 0 === strpos($contentType, 'application/json') ? $response->toArray(false) : null;
+ $errorMessage = null;
- if (200 !== $statusCode) {
- $errorMessage = $jsonContents ? $jsonContents['results']['error'] : $response->getContent(false);
+ if ($jsonContents && isset($jsonContents['results'][0]['error'])) {
+ $errorMessage = $jsonContents['results'][0]['error'];
+ } elseif (200 !== $statusCode) {
+ $errorMessage = $response->getContent(false);
+ }
+ if (null !== $errorMessage) {
throw new TransportException('Unable to post the Firebase message: '.$errorMessage, $response);
}
- if ($jsonContents && isset($jsonContents['results'][0]['error'])) {
- throw new TransportException('Unable to post the Firebase message: '.$jsonContents['results'][0]['error'], $response);
- }
$success = $response->toArray(false);
diff --git a/src/Symfony/Component/Notifier/Bridge/Firebase/Tests/FirebaseTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Firebase/Tests/FirebaseTransportTest.php
index 7a28b4f32f5df..5f8d52aa6440a 100644
--- a/src/Symfony/Component/Notifier/Bridge/Firebase/Tests/FirebaseTransportTest.php
+++ b/src/Symfony/Component/Notifier/Bridge/Firebase/Tests/FirebaseTransportTest.php
@@ -11,13 +11,18 @@
namespace Symfony\Component\Notifier\Bridge\Firebase\Tests;
+use Symfony\Component\HttpClient\MockHttpClient;
+use Symfony\Component\HttpClient\Response\MockResponse;
+use Symfony\Component\Notifier\Bridge\Firebase\FirebaseOptions;
use Symfony\Component\Notifier\Bridge\Firebase\FirebaseTransport;
+use Symfony\Component\Notifier\Exception\TransportException;
use Symfony\Component\Notifier\Message\ChatMessage;
use Symfony\Component\Notifier\Message\MessageInterface;
use Symfony\Component\Notifier\Message\SmsMessage;
use Symfony\Component\Notifier\Test\TransportTestCase;
use Symfony\Component\Notifier\Transport\TransportInterface;
use Symfony\Contracts\HttpClient\HttpClientInterface;
+use Symfony\Contracts\HttpClient\ResponseInterface;
/**
* @author Oskar Stark
@@ -47,4 +52,34 @@ public function unsupportedMessagesProvider(): iterable
yield [new SmsMessage('0611223344', 'Hello!')];
yield [$this->createMock(MessageInterface::class)];
}
+
+ /**
+ * @dataProvider sendWithErrorThrowsExceptionProvider
+ */
+ public function testSendWithErrorThrowsTransportException(ResponseInterface $response)
+ {
+ $this->expectException(TransportException::class);
+
+ $client = new MockHttpClient(static function () use ($response): ResponseInterface {
+ return $response;
+ });
+ $options = new class('recipient-id', []) extends FirebaseOptions {};
+
+ $transport = $this->createTransport($client);
+
+ $transport->send(new ChatMessage('Hello!', $options));
+ }
+
+ public function sendWithErrorThrowsExceptionProvider(): iterable
+ {
+ yield [new MockResponse(
+ json_encode(['results' => [['error' => 'testErrorCode']]]),
+ ['response_headers' => ['content-type' => ['application/json']], 'http_code' => 200]
+ )];
+
+ yield [new MockResponse(
+ json_encode(['results' => [['error' => 'testErrorCode']]]),
+ ['response_headers' => ['content-type' => ['application/json']], 'http_code' => 400]
+ )];
+ }
}
diff --git a/src/Symfony/Component/Notifier/Bridge/RocketChat/RocketChatTransport.php b/src/Symfony/Component/Notifier/Bridge/RocketChat/RocketChatTransport.php
index 891d12752bc46..925dcb78a81e9 100644
--- a/src/Symfony/Component/Notifier/Bridge/RocketChat/RocketChatTransport.php
+++ b/src/Symfony/Component/Notifier/Bridge/RocketChat/RocketChatTransport.php
@@ -99,7 +99,10 @@ protected function doSend(MessageInterface $message): SentMessage
$success = $response->toArray(false);
$sentMessage = new SentMessage($message, (string) $this);
- $sentMessage->setMessageId($success['message']['_id']);
+
+ if (isset($success['message']['_id'])) {
+ $sentMessage->setMessageId($success['message']['_id']);
+ }
return $sentMessage;
}
diff --git a/src/Symfony/Component/Runtime/Internal/ComposerPlugin.php b/src/Symfony/Component/Runtime/Internal/ComposerPlugin.php
index 77c48b3f0b380..8247b858e66b5 100644
--- a/src/Symfony/Component/Runtime/Internal/ComposerPlugin.php
+++ b/src/Symfony/Component/Runtime/Internal/ComposerPlugin.php
@@ -18,7 +18,6 @@
use Composer\Plugin\PluginInterface;
use Composer\Script\ScriptEvents;
use Symfony\Component\Filesystem\Filesystem;
-use Symfony\Component\Runtime\RuntimeInterface;
use Symfony\Component\Runtime\SymfonyRuntime;
/**
@@ -98,10 +97,6 @@ public function updateAutoloadFile(): void
$runtimeClass = $extra['class'] ?? SymfonyRuntime::class;
- if (SymfonyRuntime::class !== $runtimeClass && !is_subclass_of($runtimeClass, RuntimeInterface::class)) {
- throw new \InvalidArgumentException(sprintf('Class "%s" listed under "extra.runtime.class" in your composer.json file '.(class_exists($runtimeClass) ? 'should implement "%s".' : 'not found.'), $runtimeClass, RuntimeInterface::class));
- }
-
unset($extra['class'], $extra['autoload_template']);
$code = strtr(file_get_contents($autoloadTemplate), [
diff --git a/src/Symfony/Component/Runtime/Tests/phpt/command_list.phpt b/src/Symfony/Component/Runtime/Tests/phpt/command_list.phpt
index 0383b35871660..ff1b6b3e06474 100644
--- a/src/Symfony/Component/Runtime/Tests/phpt/command_list.phpt
+++ b/src/Symfony/Component/Runtime/Tests/phpt/command_list.phpt
@@ -32,7 +32,7 @@ Options:
--no-debug Switches off debug mode.
-v|vv|vvv, --verbose Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
-Available commands:
+Available commands:%A
help Display%S help for a command
list List%S commands
my_command Hello description
diff --git a/src/Symfony/Component/Security/CHANGELOG.md b/src/Symfony/Component/Security/CHANGELOG.md
index 7dff040837c0d..c80d2dde00f29 100644
--- a/src/Symfony/Component/Security/CHANGELOG.md
+++ b/src/Symfony/Component/Security/CHANGELOG.md
@@ -38,7 +38,6 @@ The CHANGELOG for version 5.4 and newer can be found in the security sub-package
* Add `LegacyPasswordAuthenticatedUserInterface` for user classes that use user-provided salts in addition to passwords
* Deprecate all classes in the `Core\Encoder\` sub-namespace, use the `PasswordHasher` component instead
* Deprecate the `SessionInterface $session` constructor argument of `SessionTokenStorage`, inject a `\Symfony\Component\HttpFoundation\RequestStack $requestStack` instead
- * Deprecate using `UsageTrackingTokenStorage` without a main request
* Deprecate the `session` service provided by the ServiceLocator injected in `UsageTrackingTokenStorage`, provide a `request_stack` service instead
* Deprecate using `SessionTokenStorage` outside a request context, it will throw a `SessionNotFoundException` in Symfony 6.0
* Randomize CSRF tokens to harden BREACH attacks
diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/Storage/UsageTrackingTokenStorage.php b/src/Symfony/Component/Security/Core/Authentication/Token/Storage/UsageTrackingTokenStorage.php
index 4b2cac747abf5..27398059dd975 100644
--- a/src/Symfony/Component/Security/Core/Authentication/Token/Storage/UsageTrackingTokenStorage.php
+++ b/src/Symfony/Component/Security/Core/Authentication/Token/Storage/UsageTrackingTokenStorage.php
@@ -101,8 +101,6 @@ private function shouldTrackUsage(): bool
}
if (!$this->container->get('request_stack')->getMainRequest()) {
- trigger_deprecation('symfony/security-core', '5.3', 'Using "%s" (service ID: "security.token_storage") outside the request-response cycle is deprecated, use the "%s" class (service ID: "security.untracked_token_storage") instead or disable usage tracking using "disableUsageTracking()".', __CLASS__, TokenStorage::class);
-
return false;
}
diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.bs.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.bs.xlf
index 2eae0ff22ec62..15fe823d8f911 100644
--- a/src/Symfony/Component/Security/Core/Resources/translations/security.bs.xlf
+++ b/src/Symfony/Component/Security/Core/Resources/translations/security.bs.xlf
@@ -70,6 +70,14 @@
Invalid or expired login link.Link za prijavljivanje je istekao ili je neispravan.
+
+ Too many failed login attempts, please try again in %minutes% minute.
+ Previše neuspjelih pokušaja prijave, pokušajte ponovo za %minutes% minuta.
+
+
+ Too many failed login attempts, please try again in %minutes% minutes.
+ Previše neuspjelih pokušaja prijave, pokušajte ponovo za %minutes% minuta.
+
diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.da.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.da.xlf
index c83d27c5e0b59..9b8ca4c68b2a3 100644
--- a/src/Symfony/Component/Security/Core/Resources/translations/security.da.xlf
+++ b/src/Symfony/Component/Security/Core/Resources/translations/security.da.xlf
@@ -70,6 +70,14 @@
Invalid or expired login link.Ugyldigt eller udløbet login link.
+
+ Too many failed login attempts, please try again in %minutes% minute.
+ For mange fejlede login forsøg, prøv igen om %minutes% minut.
+
+
+ Too many failed login attempts, please try again in %minutes% minutes.
+ For mange fejlede login forsøg, prøv igen om %minutes% minutter.
+
An authentication exception occurred.
- Isang pambihirang pagpaptunay ang nangyari.
+ Nagkaroon ng isang pagbubukod sa pagpapatotoo.Authentication credentials could not be found.
- Hindi mahanap ang mga kinakailangan na dokumento para sa pagpapatunay.
+ Hindi matagpuan ang mga kredensyal ng pagpapatotoo.Authentication request could not be processed due to a system problem.
- Hindi maproseso ang iyong hiling dahil may problema sa sistema.
+ Ang kahilingan sa pagpapatotoo ay hindi naproseso dahil sa isang problema sa system.Invalid credentials.
- Hindi balidong mga dokumento.
+ Di-wastong mga kredensyal.Cookie has already been used by someone else.
@@ -28,31 +28,31 @@
Invalid CSRF token.
- Hindi balidong mga token ng CSRF.
+ Di-wastong token ng CSRF.No authentication provider found to support the authentication token.
- Walang nakitang nagbibibagay ng suporta sa token ng pagpapatunay.
+ Walang nahanap na provider ng pagpapatotoo upang suportahan ang token ng pagpapatotoo.No session available, it either timed out or cookies are not enabled.
- Walang sesyon ng magagamit, ito ay nawalan ng oras o hindi pinagana.
+ Walang magagamit na session, alinman sa nag-time out o ang cookies ay hindi pinagana.No token could be found.
- Walang token na nahanap.
+ Walang makitang token.Username could not be found.
- Walang username na makita.
+ Hindi makita ang username.Account has expired.
- Ang account ay nag-expire na.
+ Nag-expire na ang account.Credentials have expired.
- Ang mga kinakailangang dokumento ay nag expire na.
+ Nag-expire na ang mga kredensyal.Account is disabled.
@@ -60,11 +60,11 @@
Account is locked.
- Ang account ay nakasara.
+ Ang account ay naka-lock.Too many failed login attempts, please try again later.
- Madaming bagsak na pagtatangka, pakisubukan ulit mamaya.
+ Napakaraming nabigong mga pagtatangka sa pag-login, mangyaring subukang muli sa ibang pagkakataon.Invalid or expired login link.
@@ -72,11 +72,11 @@
Too many failed login attempts, please try again in %minutes% minute.
- Madaming bagsak na pagtatangka, pakisubukan ulit pagkatapos ng %minutes% minuto.
+ Napakaraming nabigong mga pagtatangka sa pag-login, pakisubukan ulit sa% minuto% minuto.Too many failed login attempts, please try again in %minutes% minute.
- Madaming bagsak na pagtatangka, pakisubukan ulit pagkatapos ng %minutes% minuto.
+ Napakaraming nabigong mga pagtatangka sa pag-login, pakisubukan ulit sa% minuto% minuto.