diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php
index 290e3f20cad0b..b699003177332 100644
--- a/.php-cs-fixer.dist.php
+++ b/.php-cs-fixer.dist.php
@@ -29,16 +29,17 @@
'@Symfony' => true,
'@Symfony:risky' => true,
'protected_to_private' => false,
- 'native_constant_invocation' => ['strict' => false],
'no_superfluous_phpdoc_tags' => [
'remove_inheritdoc' => true,
'allow_unused_params' => true, // for future-ready params, to be replaced with https://github.com/PHP-CS-Fixer/PHP-CS-Fixer/issues/7377
],
- 'nullable_type_declaration_for_default_null_value' => true,
'header_comment' => ['header' => $fileHeaderComment],
+ // TODO: Remove once the "compiler_optimized" set includes "sprintf"
+ 'native_function_invocation' => ['include' => ['@compiler_optimized', 'sprintf'], 'scope' => 'namespaced', 'strict' => true],
+ 'nullable_type_declaration' => true,
+ 'nullable_type_declaration_for_default_null_value' => true,
'modernize_strpos' => true,
'get_class_to_class_keyword' => true,
- 'nullable_type_declaration' => true,
])
->setRiskyAllowed(true)
->setFinder(
@@ -47,11 +48,6 @@
->append([__FILE__])
->notPath('#/Fixtures/#')
->exclude([
- // directories containing files with content that is autogenerated by `var_export`, which breaks CS in output code
- // fixture templates
- 'Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Custom',
- // resource templates
- 'Symfony/Bundle/FrameworkBundle/Resources/views/Form',
// explicit trigger_error tests
'Symfony/Bridge/PhpUnit/Tests/DeprecationErrorHandler/',
'Symfony/Component/Intl/Resources/data/',
@@ -65,10 +61,6 @@
->notPath('#Symfony/Bridge/PhpUnit/.*Legacy#')
// file content autogenerated by `var_export`
->notPath('Symfony/Component/Translation/Tests/Fixtures/resources.php')
- // file content autogenerated by `VarExporter::export`
- ->notPath('Symfony/Component/Serializer/Tests/Fixtures/serializer.class.metadata.php')
- // test template
- ->notPath('Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Custom/_name_entry_label.html.php')
// explicit trigger_error tests
->notPath('Symfony/Component/ErrorHandler/Tests/DebugClassLoaderTest.php')
// stop removing spaces on the end of the line in strings
@@ -79,6 +71,10 @@
->notPath('Symfony/Component/Cache/Traits/Redis6Proxy.php')
->notPath('Symfony/Component/Cache/Traits/RedisCluster5Proxy.php')
->notPath('Symfony/Component/Cache/Traits/RedisCluster6Proxy.php')
+ // svg
+ ->notPath('Symfony/Component/ErrorHandler/Resources/assets/images/symfony-ghost.svg.php')
+ // HTML templates
+ ->notPath('#Symfony/.*\.html\.php#')
)
->setCacheFile('.php-cs-fixer.cache')
;
diff --git a/CHANGELOG-6.4.md b/CHANGELOG-6.4.md
index 5fac4dddffe18..6171610473139 100644
--- a/CHANGELOG-6.4.md
+++ b/CHANGELOG-6.4.md
@@ -7,6 +7,41 @@ in 6.4 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v6.4.0...v6.4.1
+* 6.4.9 (2024-06-28)
+
+ * bug #57553 [HttpKernel] Enable optional cache-warmers when cache-dir != build-dir (nicolas-grekas)
+ * bug #57497 [String] Fixed u()->snake(), b()->snake() and s()->snake() methods (arczinosek)
+ * bug #57574 [Filesystem] Fix Filesystem::remove() on Windows (nicolas-grekas)
+ * bug #57572 [DoctrineBridge] Fix compat with DI >= 6.4 (nicolas-grekas)
+ * bug #57538 [String] Add `alias` case to `EnglishInflector` (alexandre-daubois)
+ * bug #57533 [FrameworkBundle] Throw runtime exception when trying to use asset-mapper while http-client is disabled (nicolas-grekas)
+ * bug #57520 [SecurityBundle] Remove unused memory users’ `name` attribute from the XSD (MatTheCat)
+ * feature #57557 Ibexa is sponsoring Symfony 5.4, thanks to them! \o/ (nicolas-grekas)
+ * bug #57569 [HttpClient][Mailer] Revert "Let curl handle transfer encoding", use HTTP/1.1 for Mailgun (nicolas-grekas)
+ * bug #57499 [Mailer] Add additional headers in Scaleway bridge (MrMicky-FR)
+ * bug #57460 [VarExporter] fix contravariance problem with __unserialize() in lazy proxy (nikophil)
+ * bug #57397 [VarDumper] Fix FFI caster test (alexandre-daubois)
+ * bug #57453 [HttpClient] Fix parsing SSE (fancyweb)
+ * bug #57467 [SecurityBundle] Add `provider` XML attribute to the authenticators it’s missing from (MatTheCat)
+ * bug #57384 [Notifier] Fix thread key in GoogleChat bridge (romain-jacquart)
+ * bug #57372 [HttpKernel][Security] Fix accessing session for stateless request (VincentLanglet)
+ * bug #57112 [Messenger] Handle `AMQPConnectionException` when publishing a message (jwage)
+ * bug #57341 [Serializer] properly handle invalid data for false/true types (xabbuh)
+ * bug #57187 [Serializer] Fix `ObjectNormalizer` with property path (HypeMC)
+ * bug #57355 [ErrorHandler] Fix rendered exception code highlighting on PHP 8.3 (tscni)
+ * bug #57310 [DependencyInjection] Fix ternary in `AutowireCallable` attribute (alamirault)
+ * bug #57273 [FrameworkBundle] Fix setting default context for certain normalizers (HypeMC)
+ * bug #57395 [Notifier] send the recipient phone number as an array (xabbuh)
+ * bug #52699 [Serializer] [PropertyAccessor] Ignore non-collection interface generics (mtarld)
+ * bug #54634 [String] Fix #54611 pluralization of -on ending words + singularization of -a ending foreign words (Geordie, DesLynx)
+ * bug #57213 [Validator] [UniqueValidator] Use correct variable as parameter in (custom) error message (seho-nl, Sebastien Hoek)
+ * bug #54920 [Messenger] Comply with Amazon SQS requirements for message body (VincentLanglet)
+ * bug #57321 [AssetMapper] fix npm version constraint conversion (Jean-Beru)
+ * bug #57110 [PhpUnitBridge] Fix error handler triggered outside of tests (HypeMC)
+ * bug #57297 [FrameworkBundle] not registered definitions must not be modified (xabbuh)
+ * bug #57234 [String] Fix Inflector for 'hardware' (podhy)
+ * bug #57224 [Mime] Use streams instead of loading raw message generator into memory (bytestream)
+
* 6.4.8 (2024-06-02)
* bug #57284 [Mime] Fix TextPart using an unknown File (fabpot)
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 2c65442650d09..92dac23ccbd1c 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -13,8 +13,8 @@ The Symfony Connect username in parenthesis allows to get more information
- Tobias Schultze (tobion)
- Grégoire Pineau (lyrixx)
- Thomas Calvet (fancyweb)
- - Christophe Coevoet (stof)
- Alexandre Daubois (alexandre-daubois)
+ - Christophe Coevoet (stof)
- Wouter de Jong (wouterj)
- Jordi Boggiano (seldaek)
- Maxime Steinhausser (ogizanagi)
@@ -35,9 +35,9 @@ The Symfony Connect username in parenthesis allows to get more information
- Jérôme Tamarelle (gromnan)
- Samuel ROZE (sroze)
- Antoine Lamirault (alamirault)
+ - HypeMC (hypemc)
- Pascal Borreli (pborreli)
- Romain Neutron
- - HypeMC (hypemc)
- Joseph Bielawski (stloyd)
- Drak (drak)
- Abdellatif Ait boudad (aitboudad)
@@ -61,6 +61,7 @@ The Symfony Connect username in parenthesis allows to get more information
- William DURAND
- ornicar
- Dany Maillard (maidmaid)
+ - Simon André (simonandre)
- Eriksen Costa
- Diego Saint Esteben (dosten)
- stealth35 (stealth35)
@@ -69,20 +70,19 @@ The Symfony Connect username in parenthesis allows to get more information
- Francis Besset (francisbesset)
- Titouan Galopin (tgalopin)
- Pierre du Plessis (pierredup)
- - Simon André (simonandre)
- David Maicher (dmaicher)
- Bulat Shakirzyanov (avalanche123)
- Iltar van der Berg
- Miha Vrhovnik (mvrhov)
+ - Tomasz Kowalczyk (thunderer)
- Gary PEGEOT (gary-p)
+ - Mathias Arlaud (mtarld)
- Saša Stamenković (umpirsky)
- Allison Guilhem (a_guilhem)
- Mathieu Piot (mpiot)
- Mathieu Santostefano (welcomattic)
- Alexander Schranz (alexander-schranz)
- Vasilij Duško (staff)
- - Tomasz Kowalczyk (thunderer)
- - Mathias Arlaud (mtarld)
- Sarah Khalil (saro0h)
- Laurent VOULLEMIER (lvo)
- Konstantin Kudryashov (everzet)
@@ -95,8 +95,8 @@ The Symfony Connect username in parenthesis allows to get more information
- Dariusz Ruminski
- Henrik Bjørnskov (henrikbjorn)
- David Buchmann (dbu)
- - Andrej Hudec (pulzarraider)
- Ruud Kamphuis (ruudk)
+ - Andrej Hudec (pulzarraider)
- Jáchym Toušek (enumag)
- Christian Raue
- Eric Clemmons (ericclemmons)
@@ -162,9 +162,9 @@ The Symfony Connect username in parenthesis allows to get more information
- Teoh Han Hui (teohhanhui)
- Przemysław Bogusz (przemyslaw-bogusz)
- Colin Frei
+ - Nicolas Philippe (nikophil)
- excelwebzone
- Paráda József (paradajozsef)
- - Nicolas Philippe (nikophil)
- Baptiste Clavié (talus)
- Alexander Schwenn (xelaris)
- Fabien Pennequin (fabienpennequin)
@@ -181,24 +181,27 @@ The Symfony Connect username in parenthesis allows to get more information
- François-Xavier de Guillebon (de-gui_f)
- Maximilian Beckers (maxbeckers)
- noniagriconomie
+ - Valtteri R (valtzu)
- Eric GELOEN (gelo)
- Gabriel Caruso
- Stefano Sala (stefano.sala)
- Ion Bazan (ionbazan)
+ - Niels Keurentjes (curry684)
- OGAWA Katsuhiro (fivestar)
- Jhonny Lidfors (jhonne)
+ - Dāvis Zālītis (k0d3r1s)
- Juti Noppornpitak (shiroyuki)
- Gregor Harlan (gharlan)
+ - Hugo Alliaume (kocal)
- Anthony MARTIN
- Andreas Schempp (aschempp)
- Sebastian Hörl (blogsh)
- Tigran Azatyan (tigranazatyan)
+ - Florent Mata (fmata)
- Christopher Hertel (chertel)
- Jonathan Scheiber (jmsche)
- Daniel Gomes (danielcsgomes)
- Hidenori Goto (hidenorigoto)
- - Niels Keurentjes (curry684)
- - Dāvis Zālītis (k0d3r1s)
- Arnaud Kleinpeter (nanocom)
- Guilherme Blanco (guilhermeblanco)
- Saif Eddin Gmati (azjezz)
@@ -207,10 +210,7 @@ The Symfony Connect username in parenthesis allows to get more information
- SpacePossum
- Richard van Laak (rvanlaak)
- Andreas Braun
- - Hugo Alliaume (kocal)
- - Valtteri R (valtzu)
- Pablo Godel (pgodel)
- - Florent Mata (fmata)
- Alessandro Chitolina (alekitto)
- Rafael Dohms (rdohms)
- Roman Martinuk (a2a4)
@@ -220,6 +220,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Jérôme Parmentier (lctrs)
- Ahmed TAILOULOUTE (ahmedtai)
- Simon Berger
+ - soyuka
- Jérémy Derussé
- Matthieu Napoli (mnapoli)
- Tomas Votruba (tomas_votruba)
@@ -240,6 +241,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Fabien Bourigault (fbourigault)
- Olivier Dolbeau (odolbeau)
- Rouven Weßling (realityking)
+ - Bob van de Vijver (bobvandevijver)
- Daniel Burger
- Ben Davies (bendavies)
- YaFou
@@ -254,6 +256,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Matthieu Ouellette-Vachon (maoueh)
- Michał Pipa (michal.pipa)
- Dawid Nowak
+ - Philipp Wahala (hifi)
- Jannik Zschiesche
- Amal Raghav (kertz)
- Jonathan Ingram
@@ -270,7 +273,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Sébastien Alfaiate (seb33300)
- James Halsall (jaitsu)
- Christian Scheb
- - Bob van de Vijver (bobvandevijver)
- Guillaume (guill)
- Mikael Pajunen
- Warnar Boekkooi (boekkooi)
@@ -298,7 +300,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Baptiste Leduc (korbeil)
- Karoly Gossler (connorhu)
- Timo Bakx (timobakx)
- - soyuka
+ - Giorgio Premi
- Ruben Gonzalez (rubenrua)
- Benjamin Dulau (dbenjamin)
- Markus Fasselt (digilist)
@@ -317,9 +319,9 @@ The Symfony Connect username in parenthesis allows to get more information
- sun (sun)
- Larry Garfield (crell)
- Leo Feyer
- - Philipp Wahala (hifi)
- Victor Bocharsky (bocharsky_bw)
- Nikolay Labinskiy (e-moe)
+ - Asis Pattisahusiwa
- Martin Schuhfuß (usefulthink)
- apetitpa
- Guilliam Xavier
@@ -334,7 +336,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Nate Wiebe (natewiebe13)
- Joe Bennett (kralos)
- Leszek Prabucki (l3l0)
- - Giorgio Premi
+ - Wojciech Kania
- Thomas Lallement (raziel057)
- Yassine Guedidi (yguedidi)
- François Zaninotto (fzaninotto)
@@ -399,16 +401,17 @@ The Symfony Connect username in parenthesis allows to get more information
- Artem Lopata
- Patrick McDougle (patrick-mcdougle)
- Marc Weistroff (futurecat)
+ - Michał (bambucha15)
- Danny Berger (dpb587)
- Alif Rachmawadi
- Anton Chernikov (anton_ch1989)
- Pierre-Yves Lebecq (pylebecq)
- Benjamin Leveque (benji07)
- Jordan Samouh (jordansamouh)
- - Wojciech Kania
- Sullivan SENECHAL (soullivaneuh)
- Loick Piera (pyrech)
- Uwe Jäger (uwej711)
+ - javaDeveloperKid
- W0rma
- Lynn van der Berg (kjarli)
- Michaël Perrin (michael.perrin)
@@ -418,11 +421,11 @@ The Symfony Connect username in parenthesis allows to get more information
- Marvin Petker
- GordonsLondon
- Ray
- - Asis Pattisahusiwa
- Philipp Cordes (corphi)
- Chekote
- Thomas Adam
- Evert Harmeling (evertharmeling)
+ - Anderson Müller
- jdhoek
- Jurica Vlahoviček (vjurica)
- Bob den Otter (bopp)
@@ -467,9 +470,9 @@ The Symfony Connect username in parenthesis allows to get more information
- Iker Ibarguren (ikerib)
- Michael Holm (hollo)
- Blanchon Vincent (blanchonvincent)
- - Michał (bambucha15)
- Christian Schmidt
- Ben Hakim
+ - Stiven Llupa (sllupa)
- Marco Petersen (ocrampete16)
- Bohan Yang (brentybh)
- Vilius Grigaliūnas
@@ -478,7 +481,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Thomas Bisignani (toma)
- Florian Klein (docteurklein)
- Damien Alexandre (damienalexandre)
- - javaDeveloperKid
- Manuel Kießling (manuelkiessling)
- Alexey Kopytko (sanmai)
- Warxcell (warxcell)
@@ -504,7 +506,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Jan Decavele (jandc)
- Gustavo Piltcher
- Lee Rowlands
- - Anderson Müller
- Stepan Tanasiychuk (stfalcon)
- Ivan Kurnosov
- Tiago Ribeiro (fixe)
@@ -540,6 +541,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Francesco Levorato
- Vitaliy Zakharov (zakharovvi)
- Tobias Sjösten (tobiassjosten)
+ - Michael Hirschler (mvhirsch)
- Gyula Sallai (salla)
- Hendrik Luup (hluup)
- Inal DJAFAR (inalgnu)
@@ -547,6 +549,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Martin Herndl (herndlm)
- Dmytro Borysovskyi (dmytr0)
- Johann Pardanaud
+ - Kai Dederichs
- Pavel Kirpitsov (pavel-kirpichyov)
- Robert Meijers
- Artur Eshenbrener
@@ -561,7 +564,6 @@ The Symfony Connect username in parenthesis allows to get more information
- FORT Pierre-Louis (plfort)
- Terje Bråten
- Gonzalo Vilaseca (gonzalovilaseca)
- - Stiven Llupa (sllupa)
- Tarmo Leppänen (tarlepp)
- Jakub Kucharovic (jkucharovic)
- Daniel STANCU
@@ -692,7 +694,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Desjardins Jérôme (jewome62)
- Arturs Vonda
- Matthew Smeets
- - Michael Hirschler (mvhirsch)
- Toni Rudolf (toooni)
- Stefan Gehrig (sgehrig)
- vagrant
@@ -705,6 +706,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Restless-ET
- Vlad Gregurco (vgregurco)
- Artem Stepin (astepin)
+ - Jérémy DECOOL (jdecool)
- Boris Vujicic (boris.vujicic)
- Dries Vints
- Judicaël RUFFIEUX (axanagor)
@@ -722,7 +724,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Vitaliy Tverdokhlib (vitaliytv)
- Ariel Ferrandini (aferrandini)
- BASAK Semih (itsemih)
- - Kai Dederichs
- Dirk Pahl (dirkaholic)
- Cédric Lombardot (cedriclombardot)
- Jérémy REYNAUD (babeuloula)
@@ -749,6 +750,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Roberto Espinoza (respinoza)
- Pierre Rineau
- Soufian EZ ZANTAR (soezz)
+ - Ivan Mezinov
- Marek Zajac
- Adam Harvey
- ilyes kooli (skafandri)
@@ -770,6 +772,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Andrey Astakhov (aast)
- ReenExe
- Fabian Lange (codingfabian)
+ - kylekatarnls (kylekatarnls)
- Yoshio HANAWA
- Jan van Thoor (janvt)
- Joshua Nye
@@ -1012,6 +1015,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Martins Sipenko
- Guilherme Augusto Henschel
- Rostyslav Kinash
+ - Christophe V. (cvergne)
- Mardari Dorel (dorumd)
- Daisuke Ohata
- Vincent Simonin
@@ -1021,6 +1025,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Andy Palmer (andyexeter)
- Andrew Neil Forster (krciga22)
- Stefan Warman (warmans)
+ - Faizan Akram Dar (faizanakram)
- Tristan Maindron (tmaindron)
- Behnoush Norouzali (behnoush)
- Marko H. Tamminen (gzumba)
@@ -1054,6 +1059,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Kevin SCHNEKENBURGER
- Fabien Salles (blacked)
- Andreas Erhard (andaris)
+ - alexpozzi
- Michael Devery (mickadoo)
- Gregor Nathanael Meyer (spackmat)
- Antoine Corcy
@@ -1171,15 +1177,16 @@ The Symfony Connect username in parenthesis allows to get more information
- Alex Xandra Albert Sim
- Sergey Yastrebov
- Carson Full (carsonfull)
- - kylekatarnls (kylekatarnls)
- Steve Grunwell
- Yuen-Chi Lian
- Mathias Brodala (mbrodala)
- Robert Fischer (sandoba)
- Tarjei Huse (tarjei)
+ - mfettig
- Besnik Br
- Issam Raouf (iraouf)
- Simon Mönch
+ - Sherin Bloemendaal
- Jose Gonzalez
- Jonathan (jlslew)
- Claudio Zizza
@@ -1188,6 +1195,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Christian Stoller (naitsirch)
- Dave Marshall (davedevelopment)
- Jakub Kulhan (jakubkulhan)
+ - Paweł Niedzielski (steveb)
- Shaharia Azam
- avorobiev
- Gerben Oolbekkink
@@ -1226,7 +1234,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Edvin Hultberg
- shubhalgupta
- Felds Liscia (felds)
- - Jérémy DECOOL (jdecool)
- Sergey Panteleev
- Alexander Grimalovsky (flying)
- Andrew Hilobok (hilobok)
@@ -1276,6 +1283,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Cyril Pascal (paxal)
- Pedro Casado (pdr33n)
- Jayson Xu (superjavason)
+ - acoulton
- DemigodCode
- fago
- Jan Prieser
@@ -1453,6 +1461,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Robert Gruendler (pulse00)
- Sebastian Paczkowski (sebpacz)
- Simon Terrien (sterrien)
+ - Stephan Vierkant (svierkant)
- Benoît Merlet (trompette)
- Brad Jones
- datibbaw
@@ -1470,6 +1479,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Baptiste Leduc (bleduc)
- soyuka
- Patrick Kaufmann
+ - Ismail Özgün Turan (dadeather)
- Mickael Perraud
- Anton Dyshkant
- Rafael Villa Verde
@@ -1488,6 +1498,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Stewart Malik
- Renan Taranto (renan-taranto)
- Ninos Ego
+ - Samael tomas
- Stefan Graupner (efrane)
- Gemorroj (gemorroj)
- Adrien Chinour
@@ -1652,6 +1663,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Ksaveras Šakys (xawiers)
- Shaun Simmons
- Ariel J. Birnbaum
+ - Yannick
- Patrick Luca Fazzi (ap3ir0n)
- Danijel Obradović
- Pablo Borowicz
@@ -1710,6 +1722,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Łukasz Chruściel (lchrusciel)
- Jan Vernieuwe (vernija)
- Antanas Arvasevicius
+ - Adam Kiss
- Pierre Dudoret
- Michal Trojanowski
- Thomas
@@ -1790,6 +1803,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Eddie Abou-Jaoude (eddiejaoude)
- Haritz Iturbe (hizai)
- Nerijus Arlauskas (nercury)
+ - Rutger Hertogh
- Diego Sapriza
- Joan Cruz
- inspiran
@@ -1854,6 +1868,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Thomason, James
- Dario Savella
- Gordienko Vladislav
+ - Joas Schilling
- Ener-Getick
- Moza Bogdan (bogdan_moza)
- johan Vlaar
@@ -1913,6 +1928,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Takashi Kanemoto (ttskch)
- Aleksei Lebedev
- dlorek
+ - Oriol Viñals
- Stuart Fyfe
- Jason Schilling (chapterjason)
- David de Boer (ddeboer)
@@ -1963,7 +1979,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Ismail Turan
- error56
- Felicitus
- - alexpozzi
- Jorge Vahldick (jvahldick)
- Krzysztof Przybyszewski (kprzybyszewski)
- Vladimir Mantulo (mantulo)
@@ -2057,7 +2072,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Adam Wójs (awojs)
- Justin Reherman (jreherman)
- Rubén Calvo (rubencm)
- - Paweł Niedzielski (steveb)
- Abdul.Mohsen B. A. A
- Cédric Girard
- Peter Jaap Blaakmeer
@@ -2242,6 +2256,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Luis Galeas
- Bogdan Scordaliu
- Martin Pärtel
+ - PHAS Developer
- Daniel Rotter (danrot)
- Frédéric Bouchery (fbouchery)
- Jacek Kobus (jackks)
@@ -2260,7 +2275,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Jeroen de Graaf
- Ulrik McArdle
- BiaDd
- - mfettig
- Oleksii Bulba
- Ramon Cuñat
- mboultoureau
@@ -2317,6 +2331,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Starfox64
- Ivo Valchev
- Thomas Hanke
+ - ffd000
- Daniel Tschinder
- Thomas Durand
- Arnaud CHASSEUX
@@ -2330,7 +2345,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Rafał Muszyński (rafmus90)
- Sébastien Decrême (sebdec)
- Timothy Anido (xanido)
- - acoulton
- Mara Blaga
- Rick Prent
- skalpa
@@ -2398,6 +2412,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Andrea Ruggiero (pupax)
- Stan Jansen (stanjan)
- Maxwell Vandervelde
+ - karstennilsen
- kaywalker
- Sebastian Ionescu
- Robert Kopera
@@ -2448,6 +2463,7 @@ The Symfony Connect username in parenthesis allows to get more information
- tadas
- Bastien Picharles
- Kirk Madera
+ - Linas Ramanauskas
- mamazu
- Keith Maika
- izenin
@@ -2460,6 +2476,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Victor Garcia
- Juan Mrad
- Denis Yuzhanin
+ - k-sahara
- Flavian Sierk
- Rik van der Heijden
- knezmilos13
@@ -2520,6 +2537,7 @@ The Symfony Connect username in parenthesis allows to get more information
- tpetry
- JustDylan23
- Juraj Surman
+ - ywisax
- Martin Eckhardt
- natechicago
- Victor
@@ -2572,6 +2590,7 @@ The Symfony Connect username in parenthesis allows to get more information
- catch
- aetxebeste
- Roberto Guido
+ - ElisDN
- roromix
- Vitali Tsyrkin
- Juga Paazmaya
@@ -2953,6 +2972,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Patrizio Bekerle
- Tom Maguire
- Mateusz Lerczak
+ - Tim Porter
- Richard Quadling
- Rainrider
- David Zuelke
@@ -3063,6 +3083,7 @@ The Symfony Connect username in parenthesis allows to get more information
- dakur
- florian-michael-mast
- tourze
+ - sam-bee
- Vlad Dumitrache
- wetternest
- Erik van Wingerden
@@ -3076,6 +3097,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Matheus Gontijo
- Gerrit Drost
- Linnaea Von Lavia
+ - Andrew Brown
- Javan Eskander
- Lenar Lõhmus
- Cristian Gonzalez
@@ -3307,6 +3329,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Karim Miladi
- Michael Genereux
- Greg Korba
+ - Camille Islasse
- patrick-mcdougle
- Tyler Stroud
- Dariusz Czech
@@ -3347,12 +3370,14 @@ The Symfony Connect username in parenthesis allows to get more information
- wiseguy1394
- adam-mospan
- Steve Hyde
+ - AbdelatifAitBara
- nerdgod
- Sam Williams
- Ettore Del Negro
- Guillaume Aveline
- Adrian Philipp
- James Michael DuPont
+ - Simone Ruggieri
- Markus Tacker
- Tomáš Votruba
- Kasperki
@@ -3420,6 +3445,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Ayke Halder
- Thorsten Hallwas
- Brian Freytag
+ - Arend Hummeling
- Marco Pfeiffer
- Alex Nostadt
- Michael Squires
@@ -3502,6 +3528,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Yendric
- ADmad
- Nicolas Roudaire
+ - Marc Jauvin
- Matthias Meyer
- Abdouni Karim (abdounikarim)
- Temuri Takalandze (abgeo)
@@ -3544,7 +3571,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Elliot Anderson (elliot)
- Erwan Nader (ernadoo)
- Fabien D. (fabd)
- - Faizan Akram Dar (faizanakram)
- Carsten Eilers (fnc)
- Sorin Gitlan (forapathy)
- Fraller Balázs (fracsi)
@@ -3626,7 +3652,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Christopher Georg (sky-chris)
- Volker (skydiablo)
- Julien Sanchez (sumbobyboys)
- - Stephan Vierkant (svierkant)
- Ron Gähler (t-ronx)
- Guillermo Gisinger (t3chn0r)
- Tom Newby (tomnewbyau)
@@ -3637,6 +3662,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Moritz Kraft (userfriendly)
- Víctor Mateo (victormateo)
- Vincent MOULENE (vints24)
+ - Verlhac Gaëtan (viviengaetan)
- David Grüner (vworldat)
- Eugene Babushkin (warl)
- Wouter Sioen (wouter_sioen)
diff --git a/src/Symfony/Bridge/Doctrine/ManagerRegistry.php b/src/Symfony/Bridge/Doctrine/ManagerRegistry.php
index bcd16dc06e6f3..27ab1ca5050d5 100644
--- a/src/Symfony/Bridge/Doctrine/ManagerRegistry.php
+++ b/src/Symfony/Bridge/Doctrine/ManagerRegistry.php
@@ -61,6 +61,8 @@ function (&$wrappedInstance, LazyLoadingInterface $manager) use ($name) {
}
if (isset($this->fileMap[$name])) {
$wrappedInstance = $this->load($this->fileMap[$name], false);
+ } elseif ((new \ReflectionMethod($this, $this->methodMap[$name]))->isStatic()) {
+ $wrappedInstance = $this->{$this->methodMap[$name]}($this, false);
} else {
$wrappedInstance = $this->{$this->methodMap[$name]}(false);
}
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/DummyManager.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/DummyManager.php
new file mode 100644
index 0000000000000..04e5a2acdd334
--- /dev/null
+++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/DummyManager.php
@@ -0,0 +1,69 @@
+'.PhpDumperTest::dumpLazyServiceProjectServiceContainer());
- }
+ $container = new ContainerBuilder();
+
+ $container->register('foo', DummyManager::class)->setPublic(true);
+ $container->getDefinition('foo')->setLazy(true)->addTag('proxy', ['interface' => ObjectManager::class]);
+ $container->compile();
+
+ $dumper = new PhpDumper($container);
+ $dumper->setProxyDumper(new ProxyDumper());
+
+ eval('?>'.$dumper->dump(['class' => 'LazyServiceProjectServiceContainer']));
}
public function testResetService()
@@ -47,7 +55,7 @@ public function testResetService()
$registry->resetManager();
$this->assertSame($foo, $container->get('foo'));
- $this->assertInstanceOf(\stdClass::class, $foo);
+ $this->assertInstanceOf(ObjectManager::class, $foo);
$this->assertFalse(property_exists($foo, 'bar'));
}
@@ -80,7 +88,7 @@ public function testResetServiceWillNotNestFurtherLazyServicesWithinEachOther()
$service = $container->get('foo');
- self::assertInstanceOf(\stdClass::class, $service);
+ self::assertInstanceOf(DummyManager::class, $service);
self::assertInstanceOf(LazyLoadingInterface::class, $service);
self::assertInstanceOf(ValueHolderInterface::class, $service);
self::assertFalse($service->isProxyInitialized());
@@ -94,7 +102,7 @@ public function testResetServiceWillNotNestFurtherLazyServicesWithinEachOther()
$service->initializeProxy();
$wrappedValue = $service->getWrappedValueHolderValue();
- self::assertInstanceOf(\stdClass::class, $wrappedValue);
+ self::assertInstanceOf(DummyManager::class, $wrappedValue);
self::assertNotInstanceOf(LazyLoadingInterface::class, $wrappedValue);
self::assertNotInstanceOf(ValueHolderInterface::class, $wrappedValue);
}
@@ -107,7 +115,7 @@ private function dumpLazyServiceProjectAsFilesServiceContainer()
$container = new ContainerBuilder();
- $container->register('foo', \stdClass::class)
+ $container->register('foo', DummyManager::class)
->setPublic(true)
->setLazy(true);
$container->compile();
diff --git a/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php b/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php
index 1b32453d1a85a..fa44ba0a00bbb 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/ManagerRegistryTest.php
@@ -11,7 +11,9 @@
namespace Symfony\Bridge\Doctrine\Tests;
+use Doctrine\Persistence\ObjectManager;
use PHPUnit\Framework\TestCase;
+use Symfony\Bridge\Doctrine\Tests\Fixtures\DummyManager;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Dumper\PhpDumper;
@@ -24,8 +26,8 @@ public static function setUpBeforeClass(): void
{
$container = new ContainerBuilder();
- $container->register('foo', \stdClass::class)->setPublic(true);
- $container->getDefinition('foo')->setLazy(true)->addTag('proxy', ['interface' => \stdClass::class]);
+ $container->register('foo', DummyManager::class)->setPublic(true);
+ $container->getDefinition('foo')->setLazy(true)->addTag('proxy', ['interface' => ObjectManager::class]);
$container->compile();
$dumper = new PhpDumper($container);
@@ -46,8 +48,8 @@ public function testResetService()
$registry->resetManager();
$this->assertSame($foo, $container->get('foo'));
- $this->assertInstanceOf(\stdClass::class, $foo);
- $this->assertFalse(property_exists($foo, 'bar'));
+ $this->assertInstanceOf(ObjectManager::class, $foo);
+ $this->assertFalse(isset($foo->bar));
}
/**
@@ -79,7 +81,7 @@ public function testResetServiceWillNotNestFurtherLazyServicesWithinEachOther()
$service = $container->get('foo');
- self::assertInstanceOf(\stdClass::class, $service);
+ self::assertInstanceOf(ObjectManager::class, $service);
self::assertInstanceOf(LazyObjectInterface::class, $service);
self::assertFalse($service->isLazyObjectInitialized());
@@ -92,7 +94,7 @@ public function testResetServiceWillNotNestFurtherLazyServicesWithinEachOther()
$service->initializeLazyObject();
$wrappedValue = $service->initializeLazyObject();
- self::assertInstanceOf(\stdClass::class, $wrappedValue);
+ self::assertInstanceOf(DummyManager::class, $wrappedValue);
self::assertNotInstanceOf(LazyObjectInterface::class, $wrappedValue);
}
@@ -104,10 +106,10 @@ private function dumpLazyServiceDoctrineBridgeContainerAsFiles()
$container = new ContainerBuilder();
- $container->register('foo', \stdClass::class)
+ $container->register('foo', DummyManager::class)
->setPublic(true)
->setLazy(true)
- ->addTag('proxy', ['interface' => \stdClass::class]);
+ ->addTag('proxy', ['interface' => ObjectManager::class]);
$container->compile();
$fileSystem = new Filesystem();
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityTest.php
index 4380bba494bba..fbfc2cb39b4ed 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityTest.php
@@ -60,6 +60,13 @@ public function testAttributeWithGroupsAndPaylod()
self::assertSame('some attached data', $constraint->payload);
self::assertSame(['some_group'], $constraint->groups);
}
+
+ public function testValueOptionConfiguresFields()
+ {
+ $constraint = new UniqueEntity(['value' => 'email']);
+
+ $this->assertSame('email', $constraint->fields);
+ }
}
#[UniqueEntity(['email'], message: 'myMessage')]
diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
index 7ec293a06a41f..2b1b590c33f31 100644
--- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
+++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
@@ -11,6 +11,7 @@
namespace Symfony\Bridge\PhpUnit;
+use PHPUnit\Framework\TestCase;
use PHPUnit\Framework\TestResult;
use PHPUnit\Runner\ErrorHandler;
use PHPUnit\Util\Error\Handler;
@@ -376,22 +377,26 @@ private static function getPhpUnitErrorHandler(): callable
if ('PHPUnit\Util\ErrorHandler::handleError' === $eh) {
return $eh;
- } elseif (ErrorHandler::class === $eh) {
- return function (int $errorNumber, string $errorString, string $errorFile, int $errorLine) {
- ErrorHandler::instance()($errorNumber, $errorString, $errorFile, $errorLine);
-
- return true;
- };
}
foreach (debug_backtrace(\DEBUG_BACKTRACE_PROVIDE_OBJECT | \DEBUG_BACKTRACE_IGNORE_ARGS) as $frame) {
- if (isset($frame['object']) && $frame['object'] instanceof TestResult) {
+ if (!isset($frame['object'])) {
+ continue;
+ }
+
+ if ($frame['object'] instanceof TestResult) {
return new $eh(
$frame['object']->getConvertDeprecationsToExceptions(),
$frame['object']->getConvertErrorsToExceptions(),
$frame['object']->getConvertNoticesToExceptions(),
$frame['object']->getConvertWarningsToExceptions()
);
+ } elseif (ErrorHandler::class === $eh && $frame['object'] instanceof TestCase) {
+ return function (int $errorNumber, string $errorString, string $errorFile, int $errorLine) {
+ ErrorHandler::instance()($errorNumber, $errorString, $errorFile, $errorLine);
+
+ return true;
+ };
}
}
diff --git a/src/Symfony/Bridge/Twig/Extension/CodeExtension.php b/src/Symfony/Bridge/Twig/Extension/CodeExtension.php
index d738178e0ae57..63718e32bb2db 100644
--- a/src/Symfony/Bridge/Twig/Extension/CodeExtension.php
+++ b/src/Symfony/Bridge/Twig/Extension/CodeExtension.php
@@ -128,10 +128,10 @@ public function fileExcerpt(string $file, int $line, int $srcContext = 3): ?stri
if (\PHP_VERSION_ID >= 80300) {
// remove main pre/code tags
$code = preg_replace('#^
\s*(.*)\s*#s', '\\1', $code);
- // split multiline code tags
- $code = preg_replace_callback('#]++)>((?:[^<]*+\\n)++[^<]*+)#', fn ($m) => "".str_replace("\n", "\n", $m[2]).'', $code);
- // Convert spaces to html entities to preserve indentation when rendered
- $code = str_replace(' ', ' ', $code);
+ // split multiline span tags
+ $code = preg_replace_callback('#]++)>((?:[^<\\n]*+\\n)++[^<]*+)#', function ($m) {
+ return "".str_replace("\n", "\n", $m[2]).'';
+ }, $code);
$content = explode("\n", $code);
} else {
// remove main code/span tags
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index 45b9ba7bf87ed..84dbeabe98bdd 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -349,7 +349,7 @@ public function load(array $configs, ContainerBuilder $container)
throw new LogicException('AssetMapper support cannot be enabled as the AssetMapper component is not installed. Try running "composer require symfony/asset-mapper".');
}
- $this->registerAssetMapperConfiguration($config['asset_mapper'], $container, $loader, $this->readConfigEnabled('assets', $container, $config['assets']));
+ $this->registerAssetMapperConfiguration($config['asset_mapper'], $container, $loader, $this->readConfigEnabled('assets', $container, $config['assets']), $this->readConfigEnabled('http_client', $container, $config['http_client']));
} else {
$container->removeDefinition('cache.asset_mapper');
}
@@ -1330,12 +1330,14 @@ private function registerAssetsConfiguration(array $config, ContainerBuilder $co
}
}
- private function registerAssetMapperConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader, bool $assetEnabled): void
+ private function registerAssetMapperConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader, bool $assetEnabled, bool $httpClientEnabled): void
{
$loader->load('asset_mapper.php');
- if (!$assetEnabled) {
- $container->removeDefinition('asset_mapper.asset_package');
+ if (!$httpClientEnabled) {
+ $container->register('asset_mapper.http_client', HttpClientInterface::class)
+ ->addTag('container.error')
+ ->addError('You cannot use the AssetMapper integration since the HttpClient component is not enabled. Try enabling the "framework.http_client" config option.');
}
$paths = $config['paths'];
@@ -1996,19 +1998,25 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder
$container->setParameter('serializer.default_context', $defaultContext);
}
+ if (!$container->hasDefinition('serializer.normalizer.object')) {
+ return;
+ }
+
$arguments = $container->getDefinition('serializer.normalizer.object')->getArguments();
- $context = [];
+ $context = $arguments[6] ?? $defaultContext;
if (isset($config['circular_reference_handler']) && $config['circular_reference_handler']) {
- $context += ($arguments[6] ?? $defaultContext) + ['circular_reference_handler' => new Reference($config['circular_reference_handler'])];
+ $context += ['circular_reference_handler' => new Reference($config['circular_reference_handler'])];
$container->getDefinition('serializer.normalizer.object')->setArgument(5, null);
}
if ($config['max_depth_handler'] ?? false) {
- $context += ($arguments[6] ?? $defaultContext) + ['max_depth_handler' => new Reference($config['max_depth_handler'])];
+ $context += ['max_depth_handler' => new Reference($config['max_depth_handler'])];
}
$container->getDefinition('serializer.normalizer.object')->setArgument(6, $context);
+
+ $container->getDefinition('serializer.normalizer.property')->setArgument(5, $defaultContext);
}
private function registerPropertyInfoConfiguration(ContainerBuilder $container, PhpFileLoader $loader): void
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/asset_mapper.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/asset_mapper.php
index b7ce65f030345..404e7af18d0a1 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/asset_mapper.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/asset_mapper.php
@@ -54,6 +54,8 @@
])
->alias(AssetMapperInterface::class, 'asset_mapper')
+ ->alias('asset_mapper.http_client', 'http_client')
+
->set('asset_mapper.mapped_asset_factory', MappedAssetFactory::class)
->args([
service('asset_mapper.public_assets_path_resolver'),
@@ -197,7 +199,7 @@
])
->set('asset_mapper.importmap.resolver', JsDelivrEsmResolver::class)
- ->args([service('http_client')])
+ ->args([service('asset_mapper.http_client')])
->set('asset_mapper.importmap.renderer', ImportMapRenderer::class)
->args([
@@ -212,12 +214,12 @@
->set('asset_mapper.importmap.auditor', ImportMapAuditor::class)
->args([
service('asset_mapper.importmap.config_reader'),
- service('http_client'),
+ service('asset_mapper.http_client'),
])
->set('asset_mapper.importmap.update_checker', ImportMapUpdateChecker::class)
->args([
service('asset_mapper.importmap.config_reader'),
- service('http_client'),
+ service('asset_mapper.http_client'),
])
->set('asset_mapper.importmap.command.require', ImportMapRequireCommand::class)
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php
index 385d9430168d2..85231d0bf3ac0 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.php
@@ -144,7 +144,6 @@
service('property_info')->ignoreOnInvalid(),
service('serializer.mapping.class_discriminator_resolver')->ignoreOnInvalid(),
null,
- [],
])
->alias(PropertyNormalizer::class, 'serializer.normalizer.property')
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/AbstractWebTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/AbstractWebTestCase.php
index 085cb812eba69..17ff5ed732971 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/AbstractWebTestCase.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/AbstractWebTestCase.php
@@ -53,7 +53,7 @@ protected static function getKernelClass(): string
protected static function createKernel(array $options = []): KernelInterface
{
- $class = self::getKernelClass();
+ $class = static::getKernelClass();
if (!isset($options['test_case'])) {
throw new \InvalidArgumentException('The option "test_case" must be set.');
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SerializerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SerializerTest.php
index 2856816d187a1..9d75c5bf675a2 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SerializerTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SerializerTest.php
@@ -12,6 +12,9 @@
namespace Symfony\Bundle\FrameworkBundle\Tests\Functional;
use Symfony\Bundle\FrameworkBundle\Tests\Fixtures\TranslatableBackedEnum;
+use Symfony\Bundle\FrameworkBundle\Tests\Functional\app\AppKernel;
+use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* @author Kévin Dunglas
@@ -35,39 +38,58 @@ public function testDeserializeArrayOfObject()
$this->assertEquals($expected, $result);
}
- /**
- * @dataProvider provideNormalizersAndEncodersWithDefaultContextOption
- */
- public function testNormalizersAndEncodersUseDefaultContextConfigOption(string $normalizerId)
+ public function testNormalizersAndEncodersUseDefaultContextConfigOption()
{
- static::bootKernel(['test_case' => 'Serializer']);
+ /** @var SerializerKernel $kernel */
+ $kernel = static::bootKernel(['test_case' => 'Serializer', 'root_config' => 'default_context.yaml']);
+
+ foreach ($kernel->normalizersAndEncoders as $normalizerOrEncoderId) {
+ if (!static::getContainer()->has($normalizerOrEncoderId)) {
+ continue;
+ }
+
+ $normalizerOrEncoder = static::getContainer()->get($normalizerOrEncoderId);
- $normalizer = static::getContainer()->get($normalizerId);
+ $reflectionObject = new \ReflectionObject($normalizerOrEncoder);
+ $property = $reflectionObject->getProperty('defaultContext');
- $reflectionObject = new \ReflectionObject($normalizer);
- $property = $reflectionObject->getProperty('defaultContext');
+ $defaultContext = $property->getValue($normalizerOrEncoder);
- $defaultContext = $property->getValue($normalizer);
+ self::assertArrayHasKey('fake_context_option', $defaultContext);
+ self::assertEquals('foo', $defaultContext['fake_context_option']);
+ }
+ }
- self::assertArrayHasKey('fake_context_option', $defaultContext);
- self::assertEquals('foo', $defaultContext['fake_context_option']);
+ protected static function getKernelClass(): string
+ {
+ return SerializerKernel::class;
}
+}
+
+class SerializerKernel extends AppKernel implements CompilerPassInterface
+{
+ public $normalizersAndEncoders = [
+ 'serializer.normalizer.property.alias', // Special case as this normalizer isn't tagged
+ ];
- public static function provideNormalizersAndEncodersWithDefaultContextOption(): array
+ public function process(ContainerBuilder $container): void
{
- return [
- ['serializer.normalizer.constraint_violation_list.alias'],
- ['serializer.normalizer.dateinterval.alias'],
- ['serializer.normalizer.datetime.alias'],
- ['serializer.normalizer.json_serializable.alias'],
- ['serializer.normalizer.problem.alias'],
- ['serializer.normalizer.uid.alias'],
- ['serializer.normalizer.translatable.alias'],
- ['serializer.normalizer.object.alias'],
- ['serializer.encoder.xml.alias'],
- ['serializer.encoder.yaml.alias'],
- ['serializer.encoder.csv.alias'],
- ];
+ $services = array_merge(
+ $container->findTaggedServiceIds('serializer.normalizer'),
+ $container->findTaggedServiceIds('serializer.encoder')
+ );
+ foreach ($services as $serviceId => $attributes) {
+ $class = $container->getDefinition($serviceId)->getClass();
+ if (null === $reflectionConstructor = (new \ReflectionClass($class))->getConstructor()) {
+ continue;
+ }
+ foreach ($reflectionConstructor->getParameters() as $reflectionParam) {
+ if ('array $defaultContext' === $reflectionParam->getType()->getName().' $'.$reflectionParam->getName()) {
+ $this->normalizersAndEncoders[] = $serviceId.'.alias';
+ break;
+ }
+ }
+ }
}
public function testSerializeTranslatableBackedEnum()
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php
index 06dc2d637a8e5..2fdbaea0fd9e8 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AppKernel.php
@@ -49,6 +49,11 @@ public function __construct($varDir, $testCase, $rootConfig, $environment, $debu
parent::__construct($environment, $debug);
}
+ protected function getContainerClass(): string
+ {
+ return parent::getContainerClass().substr(md5($this->rootConfig), -16);
+ }
+
public function registerBundles(): iterable
{
if (!file_exists($filename = $this->getProjectDir().'/'.$this->testCase.'/bundles.php')) {
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml
index 987cc384c7207..2f20dab9e8bc3 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml
@@ -10,7 +10,6 @@ framework:
max_depth_handler: Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serializer\MaxDepthHandler
default_context:
enable_max_depth: true
- fake_context_option: foo
property_info: { enabled: true }
services:
@@ -18,54 +17,6 @@ services:
alias: serializer
public: true
- serializer.normalizer.constraint_violation_list.alias:
- alias: serializer.normalizer.constraint_violation_list
- public: true
-
- serializer.normalizer.dateinterval.alias:
- alias: serializer.normalizer.dateinterval
- public: true
-
- serializer.normalizer.datetime.alias:
- alias: serializer.normalizer.datetime
- public: true
-
- serializer.normalizer.json_serializable.alias:
- alias: serializer.normalizer.json_serializable
- public: true
-
- serializer.normalizer.problem.alias:
- alias: serializer.normalizer.problem
- public: true
-
- serializer.normalizer.uid.alias:
- alias: serializer.normalizer.uid
- public: true
-
- serializer.normalizer.translatable.alias:
- alias: serializer.normalizer.translatable
- public: true
-
- serializer.normalizer.property.alias:
- alias: serializer.normalizer.property
- public: true
-
- serializer.normalizer.object.alias:
- alias: serializer.normalizer.object
- public: true
-
- serializer.encoder.xml.alias:
- alias: serializer.encoder.xml
- public: true
-
- serializer.encoder.yaml.alias:
- alias: serializer.encoder.yaml
- public: true
-
- serializer.encoder.csv.alias:
- alias: serializer.encoder.csv
- public: true
-
Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serializer\CircularReferenceHandler: ~
Symfony\Bundle\FrameworkBundle\Tests\Fixtures\Serializer\MaxDepthHandler: ~
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/default_context.yaml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/default_context.yaml
new file mode 100644
index 0000000000000..de6114c5d4bb8
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/default_context.yaml
@@ -0,0 +1,59 @@
+imports:
+ - { resource: ../config/default.yml }
+
+framework:
+ serializer:
+ enabled: true
+ circular_reference_handler: ~ # This must be null
+ max_depth_handler: ~ # This must be null
+ default_context:
+ fake_context_option: foo
+
+services:
+ serializer.normalizer.constraint_violation_list.alias:
+ alias: serializer.normalizer.constraint_violation_list
+ public: true
+
+ serializer.normalizer.dateinterval.alias:
+ alias: serializer.normalizer.dateinterval
+ public: true
+
+ serializer.normalizer.datetime.alias:
+ alias: serializer.normalizer.datetime
+ public: true
+
+ serializer.normalizer.json_serializable.alias:
+ alias: serializer.normalizer.json_serializable
+ public: true
+
+ serializer.normalizer.object.alias:
+ alias: serializer.normalizer.object
+ public: true
+
+ serializer.normalizer.problem.alias:
+ alias: serializer.normalizer.problem
+ public: true
+
+ serializer.normalizer.property.alias:
+ alias: serializer.normalizer.property
+ public: true
+
+ serializer.normalizer.uid.alias:
+ alias: serializer.normalizer.uid
+ public: true
+
+ serializer.encoder.csv.alias:
+ alias: serializer.encoder.csv
+ public: true
+
+ serializer.encoder.json.alias:
+ alias: serializer.encoder.json
+ public: true
+
+ serializer.encoder.xml.alias:
+ alias: serializer.encoder.xml
+ public: true
+
+ serializer.encoder.yaml.alias:
+ alias: serializer.encoder.yaml
+ public: true
diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd b/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd
index ab4899d771201..bf15a5db164ec 100644
--- a/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd
+++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/schema/security-1.0.xsd
@@ -113,7 +113,6 @@
-
@@ -208,6 +207,7 @@
+
diff --git a/src/Symfony/Bundle/SecurityBundle/Security/FirewallAwareTrait.php b/src/Symfony/Bundle/SecurityBundle/Security/FirewallAwareTrait.php
index d422675377afa..c5f04511752f1 100644
--- a/src/Symfony/Bundle/SecurityBundle/Security/FirewallAwareTrait.php
+++ b/src/Symfony/Bundle/SecurityBundle/Security/FirewallAwareTrait.php
@@ -44,7 +44,7 @@ private function getForFirewall(): object
if (!$this->locator->has($firewallName)) {
$message = 'No '.$serviceIdentifier.' found for this firewall.';
if (\defined(static::class.'::FIREWALL_OPTION')) {
- $message .= sprintf('Did you forget to add a "'.static::FIREWALL_OPTION.'" key under your "%s" firewall?', $firewallName);
+ $message .= sprintf(' Did you forget to add a "'.static::FIREWALL_OPTION.'" key under your "%s" firewall?', $firewallName);
}
throw new \LogicException($message);
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml
index 66dd30ea8d26a..f54c5064de23b 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/container1.xml
@@ -64,9 +64,8 @@
-
+
- app.user_checkerROLE_USER
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/firewall_provider.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/firewall_provider.xml
index 52a64d2f42908..e2f0e9865c251 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/firewall_provider.xml
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/firewall_provider.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/firewall_undefined_provider.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/firewall_undefined_provider.xml
index a61d597fad573..e7f3e6873dfa8 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/firewall_undefined_provider.xml
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/firewall_undefined_provider.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/listener_provider.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/listener_provider.xml
index 1ba3c5e5098e4..462136c682cc5 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/listener_provider.xml
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/listener_provider.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/listener_undefined_provider.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/listener_undefined_provider.xml
index 314f25d263d71..cb82f2cc509f4 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/listener_undefined_provider.xml
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/listener_undefined_provider.xml
@@ -15,7 +15,7 @@
-
+
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/no_custom_user_checker.xml b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/no_custom_user_checker.xml
index 6b51f236a50a7..2e0e75eabcb37 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/no_custom_user_checker.xml
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Fixtures/xml/no_custom_user_checker.xml
@@ -22,7 +22,6 @@
-
diff --git a/src/Symfony/Component/AssetMapper/ImportMap/ImportMapRenderer.php b/src/Symfony/Component/AssetMapper/ImportMap/ImportMapRenderer.php
index e8ad69953cf1c..ebd2948c56790 100644
--- a/src/Symfony/Component/AssetMapper/ImportMap/ImportMapRenderer.php
+++ b/src/Symfony/Component/AssetMapper/ImportMap/ImportMapRenderer.php
@@ -27,7 +27,9 @@
*/
class ImportMapRenderer
{
- private const DEFAULT_ES_MODULE_SHIMS_POLYFILL_URL = 'https://ga.jspm.io/npm:es-module-shims@1.8.0/dist/es-module-shims.js';
+ // https://generator.jspm.io/#S2NnYGAIzSvJLMlJTWEAAMYOgCAOAA
+ private const DEFAULT_ES_MODULE_SHIMS_POLYFILL_URL = 'https://ga.jspm.io/npm:es-module-shims@1.10.0/dist/es-module-shims.js';
+ private const DEFAULT_ES_MODULE_SHIMS_POLYFILL_INTEGRITY = 'sha384-ie1x72Xck445i0j4SlNJ5W5iGeL3Dpa0zD48MZopgWsjNB/lt60SuG1iduZGNnJn';
public function __construct(
private readonly ImportMapGenerator $importMapGenerator,
diff --git a/src/Symfony/Component/AssetMapper/ImportMap/ImportMapVersionChecker.php b/src/Symfony/Component/AssetMapper/ImportMap/ImportMapVersionChecker.php
index b0af5736eb821..6a2cf579956bd 100644
--- a/src/Symfony/Component/AssetMapper/ImportMap/ImportMapVersionChecker.php
+++ b/src/Symfony/Component/AssetMapper/ImportMap/ImportMapVersionChecker.php
@@ -137,7 +137,7 @@ public static function convertNpmConstraint(string $versionConstraint): ?string
if (str_contains($segment, '-') && !preg_match('/-(alpha|beta|rc)\./', $segment)) {
// This is a range
[$start, $end] = explode('-', $segment);
- $processedSegments[] = '>='.self::cleanVersionSegment(trim($start)).' <='.self::cleanVersionSegment(trim($end));
+ $processedSegments[] = self::cleanVersionSegment(trim($start)).' - '.self::cleanVersionSegment(trim($end));
} elseif (preg_match('/^~(\d+\.\d+)$/', $segment, $matches)) {
// Handle the tilde when only major.minor specified
$baseVersion = $matches[1];
diff --git a/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapVersionCheckerTest.php b/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapVersionCheckerTest.php
index 43346d3de33aa..2d6582c1d6cc4 100644
--- a/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapVersionCheckerTest.php
+++ b/src/Symfony/Component/AssetMapper/Tests/ImportMap/ImportMapVersionCheckerTest.php
@@ -261,6 +261,26 @@ public static function getCheckVersionsTests()
new PackageVersionProblem('foo', 'bar', 'some/repo', '1.5.0'),
],
];
+
+ yield 'single with range constraint but no problem' => [
+ [
+ self::createRemoteEntry('foo', version: '1.0'),
+ self::createRemoteEntry('bar', version: '2.0.3'),
+ ],
+ [
+ 'foo' => ['bar'],
+ 'bar' => [],
+ ],
+ [
+ [
+ 'url' => '/foo/1.0',
+ 'response' => [
+ 'dependencies' => ['bar' => '1.11 - 2'],
+ ],
+ ],
+ ],
+ [],
+ ];
}
/**
@@ -297,22 +317,22 @@ public static function getNpmSpecificVersionConstraints()
// Hyphen Ranges
yield 'hyphen range simple' => [
'1.0.0 - 2.0.0',
- '>=1.0.0 <=2.0.0',
+ '1.0.0 - 2.0.0',
];
yield 'hyphen range with v prefix' => [
'v1.0.0 - 2.0.0',
- '>=1.0.0 <=2.0.0',
+ '1.0.0 - 2.0.0',
];
yield 'hyphen range without patch' => [
'1.0 - 2.0',
- '>=1.0 <=2.0',
+ '1.0 - 2.0',
];
yield 'hyphen range with no spaces' => [
'1.0-v2.0',
- '>=1.0 <=2.0',
+ '1.0 - 2.0',
];
// .x Wildcards
@@ -386,7 +406,7 @@ public static function getNpmSpecificVersionConstraints()
yield 'multiple constraints with space and or operator' => [
'1.2.7 || 1.2.9- v2.0.0',
- '1.2.7 || >=1.2.9 <=2.0.0',
+ '1.2.7 || 1.2.9 - 2.0.0',
];
yield 'tilde constraint with patch version no change' => [
diff --git a/src/Symfony/Component/Console/Completion/CompletionInput.php b/src/Symfony/Component/Console/Completion/CompletionInput.php
index 7ba41c0839da4..79c2f659a92c2 100644
--- a/src/Symfony/Component/Console/Completion/CompletionInput.php
+++ b/src/Symfony/Component/Console/Completion/CompletionInput.php
@@ -53,7 +53,7 @@ public static function fromString(string $inputStr, int $currentIndex): self
* Create an input based on an COMP_WORDS token list.
*
* @param string[] $tokens the set of split tokens (e.g. COMP_WORDS or argv)
- * @param $currentIndex the index of the cursor (e.g. COMP_CWORD)
+ * @param int $currentIndex the index of the cursor (e.g. COMP_CWORD)
*/
public static function fromTokens(array $tokens, int $currentIndex): self
{
diff --git a/src/Symfony/Component/Console/Tests/Completion/CompletionInputTest.php b/src/Symfony/Component/Console/Tests/Completion/CompletionInputTest.php
index 5b6a8e42de94f..df0d081fd9acb 100644
--- a/src/Symfony/Component/Console/Tests/Completion/CompletionInputTest.php
+++ b/src/Symfony/Component/Console/Tests/Completion/CompletionInputTest.php
@@ -132,4 +132,19 @@ public static function provideFromStringData()
yield ['bin/console cache:clear "multi word string"', ['bin/console', 'cache:clear', '"multi word string"']];
yield ['bin/console cache:clear \'multi word string\'', ['bin/console', 'cache:clear', '\'multi word string\'']];
}
+
+ public function testToString()
+ {
+ $input = CompletionInput::fromTokens(['foo', 'bar', 'baz'], 0);
+ $this->assertSame('foo| bar baz', (string) $input);
+
+ $input = CompletionInput::fromTokens(['foo', 'bar', 'baz'], 1);
+ $this->assertSame('foo bar| baz', (string) $input);
+
+ $input = CompletionInput::fromTokens(['foo', 'bar', 'baz'], 2);
+ $this->assertSame('foo bar baz|', (string) $input);
+
+ $input = CompletionInput::fromTokens(['foo', 'bar', 'baz'], 11);
+ $this->assertSame('foo bar baz |', (string) $input);
+ }
}
diff --git a/src/Symfony/Component/DependencyInjection/Attribute/AutowireCallable.php b/src/Symfony/Component/DependencyInjection/Attribute/AutowireCallable.php
index f14d9066d33d0..da9ac0d0014d9 100644
--- a/src/Symfony/Component/DependencyInjection/Attribute/AutowireCallable.php
+++ b/src/Symfony/Component/DependencyInjection/Attribute/AutowireCallable.php
@@ -42,7 +42,7 @@ public function __construct(
public function buildDefinition(mixed $value, ?string $type, \ReflectionParameter $parameter): Definition
{
- return (new Definition($type = \is_string($this->lazy) ? $this->lazy : ($type ?: 'Closure')))
+ return (new Definition($type = \is_array($this->lazy) ? current($this->lazy) : ($type ?: 'Closure')))
->setFactory(['Closure', 'fromCallable'])
->setArguments([\is_array($value) ? $value + [1 => '__invoke'] : $value])
->setLazy($this->lazy || 'Closure' !== $type && 'callable' !== (string) $parameter->getType());
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Attribute/AutowireCallableTest.php b/src/Symfony/Component/DependencyInjection/Tests/Attribute/AutowireCallableTest.php
index f5aeb35d44939..9e1a0d85429ff 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Attribute/AutowireCallableTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Attribute/AutowireCallableTest.php
@@ -93,4 +93,35 @@ public function testArrayCallableWithServiceOnly()
self::assertEquals([new Reference('my_service'), '__invoke'], $attribute->value);
self::assertFalse($attribute->lazy);
}
+
+ public function testLazyAsArrayInDefinition()
+ {
+ $attribute = new AutowireCallable(callable: [Foo::class, 'myMethod'], lazy: 'my_lazy_class');
+
+ self::assertSame([Foo::class, 'myMethod'], $attribute->value);
+
+ $definition = $attribute->buildDefinition('my_value', 'my_custom_type', new \ReflectionParameter([Foo::class, 'myMethod'], 'myParameter'));
+
+ self::assertSame('my_lazy_class', $definition->getClass());
+ self::assertTrue($definition->isLazy());
+ }
+
+ public function testLazyIsFalseInDefinition()
+ {
+ $attribute = new AutowireCallable(callable: [Foo::class, 'myMethod'], lazy: false);
+
+ self::assertFalse($attribute->lazy);
+
+ $definition = $attribute->buildDefinition('my_value', 'my_custom_type', new \ReflectionParameter([Foo::class, 'myMethod'], 'myParameter'));
+
+ self::assertSame('my_custom_type', $definition->getClass());
+ self::assertFalse($definition->isLazy());
+ }
+}
+
+class Foo
+{
+ public function myMethod(callable $myParameter)
+ {
+ }
}
diff --git a/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php b/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php
index b6d76ff151516..17745c8170818 100644
--- a/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php
+++ b/src/Symfony/Component/ErrorHandler/ErrorRenderer/HtmlErrorRenderer.php
@@ -252,10 +252,10 @@ private function fileExcerpt(string $file, int $line, int $srcContext = 3): stri
if (\PHP_VERSION_ID >= 80300) {
// remove main pre/code tags
$code = preg_replace('#^\s*(.*)\s*#s', '\\1', $code);
- // split multiline code tags
- $code = preg_replace_callback('#]++)>((?:[^<]*+\\n)++[^<]*+)#', fn ($m) => "".str_replace("\n", "\n", $m[2]).'', $code);
- // Convert spaces to html entities to preserve indentation when rendered
- $code = str_replace(' ', ' ', $code);
+ // split multiline span tags
+ $code = preg_replace_callback('#]++)>((?:[^<\\n]*+\\n)++[^<]*+)#', function ($m) {
+ return "".str_replace("\n", "\n", $m[2]).'';
+ }, $code);
$content = explode("\n", $code);
} else {
// remove main code/span tags
diff --git a/src/Symfony/Component/ErrorHandler/Resources/assets/css/exception.css b/src/Symfony/Component/ErrorHandler/Resources/assets/css/exception.css
index 3e6eae5a92273..e4d1f11e928ea 100644
--- a/src/Symfony/Component/ErrorHandler/Resources/assets/css/exception.css
+++ b/src/Symfony/Component/ErrorHandler/Resources/assets/css/exception.css
@@ -349,7 +349,7 @@ header .container { display: flex; justify-content: space-between; }
.trace-code li { color: #969896; margin: 0; padding-left: 10px; float: left; width: 100%; }
.trace-code li + li { margin-top: 5px; }
.trace-code li.selected { background: var(--trace-selected-background); margin-top: 2px; }
-.trace-code li code { color: var(--base-6); white-space: nowrap; }
+.trace-code li code { color: var(--base-6); white-space: pre; }
.trace-as-text .stacktrace { line-height: 1.8; margin: 0 0 15px; white-space: pre-wrap; }
diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php
index 52ecfbda65c05..37556e3d8a81b 100644
--- a/src/Symfony/Component/Filesystem/Filesystem.php
+++ b/src/Symfony/Component/Filesystem/Filesystem.php
@@ -172,7 +172,7 @@ private static function doRemove(array $files, bool $isRecursive): void
}
} elseif (is_dir($file)) {
if (!$isRecursive) {
- $tmpName = \dirname(realpath($file)).'/.'.strrev(strtr(base64_encode(random_bytes(2)), '/=', '-_'));
+ $tmpName = \dirname(realpath($file)).'/.!'.strrev(strtr(base64_encode(random_bytes(2)), '/=', '-!'));
if (file_exists($tmpName)) {
try {
diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php
index bc8a5cecaa259..4e1d9351a69ba 100644
--- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php
+++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php
@@ -171,17 +171,17 @@ public function testCopyForOriginUrlsAndExistingLocalFileDefaultsToCopy()
}
$finder = new PhpExecutableFinder();
- $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', 'localhost:8057']));
+ $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', 'localhost:8857']));
$process->setWorkingDirectory(__DIR__.'/Fixtures/web');
$process->start();
do {
usleep(50000);
- } while (!@fopen('http://localhost:8057', 'r'));
+ } while (!@fopen('http://localhost:8857', 'r'));
try {
- $sourceFilePath = 'http://localhost:8057/logo_symfony_header.png';
+ $sourceFilePath = 'http://localhost:8857/logo_symfony_header.png';
$targetFilePath = $this->workspace.\DIRECTORY_SEPARATOR.'copy_target_file';
file_put_contents($targetFilePath, 'TARGET FILE');
$this->filesystem->copy($sourceFilePath, $targetFilePath, false);
diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php
index fef0ad09a9079..4446a031e9695 100644
--- a/src/Symfony/Component/HttpClient/CurlHttpClient.php
+++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php
@@ -250,8 +250,9 @@ public function request(string $method, string $url, array $options = []): Respo
if (isset($options['normalized_headers']['content-length'][0])) {
$curlopts[\CURLOPT_INFILESIZE] = (int) substr($options['normalized_headers']['content-length'][0], \strlen('Content-Length: '));
- } elseif (!isset($options['normalized_headers']['transfer-encoding'])) {
- $curlopts[\CURLOPT_INFILESIZE] = -1;
+ }
+ if (!isset($options['normalized_headers']['transfer-encoding'])) {
+ $curlopts[\CURLOPT_HTTPHEADER][] = 'Transfer-Encoding:'.(isset($curlopts[\CURLOPT_INFILESIZE]) ? '' : ' chunked');
}
if ('POST' !== $method) {
diff --git a/src/Symfony/Component/HttpClient/EventSourceHttpClient.php b/src/Symfony/Component/HttpClient/EventSourceHttpClient.php
index 4e551ac0409f6..b5f88ddbabe8f 100644
--- a/src/Symfony/Component/HttpClient/EventSourceHttpClient.php
+++ b/src/Symfony/Component/HttpClient/EventSourceHttpClient.php
@@ -11,6 +11,7 @@
namespace Symfony\Component\HttpClient;
+use Symfony\Component\HttpClient\Chunk\DataChunk;
use Symfony\Component\HttpClient\Chunk\ServerSentEvent;
use Symfony\Component\HttpClient\Exception\EventSourceException;
use Symfony\Component\HttpClient\Response\AsyncContext;
@@ -121,17 +122,30 @@ public function request(string $method, string $url, array $options = []): Respo
return;
}
- $rx = '/((?:\r\n){2,}|\r{2,}|\n{2,})/';
- $content = $state->buffer.$chunk->getContent();
-
if ($chunk->isLast()) {
- $rx = substr_replace($rx, '|$', -2, 0);
+ if ('' !== $content = $state->buffer) {
+ $state->buffer = '';
+ yield new DataChunk(-1, $content);
+ }
+
+ yield $chunk;
+
+ return;
}
- $events = preg_split($rx, $content, -1, \PREG_SPLIT_DELIM_CAPTURE);
+
+ $content = $state->buffer.$chunk->getContent();
+ $events = preg_split('/((?:\r\n){2,}|\r{2,}|\n{2,})/', $content, -1, \PREG_SPLIT_DELIM_CAPTURE);
$state->buffer = array_pop($events);
for ($i = 0; isset($events[$i]); $i += 2) {
- $event = new ServerSentEvent($events[$i].$events[1 + $i]);
+ $content = $events[$i].$events[1 + $i];
+ if (!preg_match('/(?:^|\r\n|[\r\n])[^:\r\n]/', $content)) {
+ yield new DataChunk(-1, $content);
+
+ continue;
+ }
+
+ $event = new ServerSentEvent($content);
if ('' !== $event->getId()) {
$context->setInfo('last_event_id', $state->lastEventId = $event->getId());
@@ -143,17 +157,6 @@ public function request(string $method, string $url, array $options = []): Respo
yield $event;
}
-
- if (preg_match('/^(?::[^\r\n]*+(?:\r\n|[\r\n]))+$/m', $state->buffer)) {
- $content = $state->buffer;
- $state->buffer = '';
-
- yield $context->createChunk($content);
- }
-
- if ($chunk->isLast()) {
- yield $chunk;
- }
});
}
}
diff --git a/src/Symfony/Component/HttpClient/Tests/EventSourceHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/EventSourceHttpClientTest.php
index 629655392ce81..de199ac729a59 100644
--- a/src/Symfony/Component/HttpClient/Tests/EventSourceHttpClientTest.php
+++ b/src/Symfony/Component/HttpClient/Tests/EventSourceHttpClientTest.php
@@ -15,9 +15,11 @@
use Symfony\Component\HttpClient\Chunk\DataChunk;
use Symfony\Component\HttpClient\Chunk\ErrorChunk;
use Symfony\Component\HttpClient\Chunk\FirstChunk;
+use Symfony\Component\HttpClient\Chunk\LastChunk;
use Symfony\Component\HttpClient\Chunk\ServerSentEvent;
use Symfony\Component\HttpClient\EventSourceHttpClient;
use Symfony\Component\HttpClient\Exception\EventSourceException;
+use Symfony\Component\HttpClient\MockHttpClient;
use Symfony\Component\HttpClient\Response\MockResponse;
use Symfony\Component\HttpClient\Response\ResponseStream;
use Symfony\Contracts\HttpClient\HttpClientInterface;
@@ -34,7 +36,11 @@ class EventSourceHttpClientTest extends TestCase
*/
public function testGetServerSentEvents(string $sep)
{
- $rawData = <<assertSame(['Accept: text/event-stream', 'Cache-Control: no-cache'], $options['headers']);
+
+ return new MockResponse([
+ str_replace("\n", $sep, << false, 'http_method' => 'GET', 'url' => 'http://localhost:8080/events', 'response_headers' => ['content-type: text/event-stream']]);
- $responseStream = new ResponseStream((function () use ($response, $chunk) {
- yield $response => new FirstChunk();
- yield $response => $chunk;
- yield $response => new ErrorChunk(0, 'timeout');
- })());
-
- $hasCorrectHeaders = function ($options) {
- $this->assertSame(['Accept: text/event-stream', 'Cache-Control: no-cache'], $options['headers']);
-
- return true;
- };
-
- $httpClient = $this->createMock(HttpClientInterface::class);
- $httpClient->method('request')->with('GET', 'http://localhost:8080/events', $this->callback($hasCorrectHeaders))->willReturn($response);
-
- $httpClient->method('stream')->willReturn($responseStream);
-
- $es = new EventSourceHttpClient($httpClient);
+TXT
+ ),
+ ], [
+ 'canceled' => false,
+ 'http_method' => 'GET',
+ 'url' => 'http://localhost:8080/events',
+ 'response_headers' => ['content-type: text/event-stream'],
+ ]);
+ }));
$res = $es->connect('http://localhost:8080/events');
$expected = [
new FirstChunk(),
new ServerSentEvent(str_replace("\n", $sep, "event: builderror\nid: 46\ndata: {\"foo\": \"bar\"}\n\n")),
new ServerSentEvent(str_replace("\n", $sep, "event: reload\nid: 47\ndata: {}\n\n")),
- new ServerSentEvent(str_replace("\n", $sep, "event: reload\nid: 48\ndata: {}\n\n")),
+ new DataChunk(-1, str_replace("\n", $sep, ": this is a oneline comment\n\n")),
+ new DataChunk(-1, str_replace("\n", $sep, ": this is a\n: multiline comment\n\n")),
+ new ServerSentEvent(str_replace("\n", $sep, ": comments are ignored\nevent: reload\n: anywhere\nid: 48\ndata: {}\n\n")),
new ServerSentEvent(str_replace("\n", $sep, "data: test\ndata:test\nid: 49\nevent: testEvent\n\n\n")),
new ServerSentEvent(str_replace("\n", $sep, "id: 50\ndata: \ndata\ndata: \ndata\ndata: \n\n")),
+ new DataChunk(-1, str_replace("\n", $sep, "id: 60\ndata")),
+ new LastChunk("\r\n" === $sep ? 355 : 322),
];
- $i = 0;
-
- $this->expectExceptionMessage('Response has been canceled');
- while ($res) {
- if ($i > 0) {
- $res->cancel();
- }
- foreach ($es->stream($res) as $chunk) {
- if ($chunk->isTimeout()) {
- continue;
- }
-
- if ($chunk->isLast()) {
- continue;
- }
-
- $this->assertEquals($expected[$i++], $chunk);
- }
+ foreach ($es->stream($res) as $chunk) {
+ $this->assertEquals(array_shift($expected), $chunk);
}
+ $this->assertSame([], $expected);
}
public function testPostServerSentEvents()
diff --git a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php
index 926192dd42666..12951b495c7e8 100644
--- a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php
+++ b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php
@@ -63,7 +63,7 @@ public function collect(Request $request, Response $response, ?\Throwable $excep
$sessionMetadata = [];
$sessionAttributes = [];
$flashes = [];
- if ($request->hasSession()) {
+ if (!$request->attributes->getBoolean('_stateless') && $request->hasSession()) {
$session = $request->getSession();
if ($session->isStarted()) {
$sessionMetadata['Created'] = date(\DATE_RFC822, $session->getMetadataBag()->getCreated());
diff --git a/src/Symfony/Component/HttpKernel/Event/KernelEvent.php b/src/Symfony/Component/HttpKernel/Event/KernelEvent.php
index e64cc419b91e4..02426c52a19d7 100644
--- a/src/Symfony/Component/HttpKernel/Event/KernelEvent.php
+++ b/src/Symfony/Component/HttpKernel/Event/KernelEvent.php
@@ -16,7 +16,7 @@
use Symfony\Contracts\EventDispatcher\Event;
/**
- * Base class for events thrown in the HttpKernel component.
+ * Base class for events dispatched in the HttpKernel component.
*
* @author Bernhard Schussek
*/
diff --git a/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php b/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php
index 5d16823fceddd..1f30582f4a010 100644
--- a/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php
+++ b/src/Symfony/Component/HttpKernel/EventListener/ProfilerListener.php
@@ -97,7 +97,7 @@ public function onKernelResponse(ResponseEvent $event): void
return;
}
- $session = $request->hasPreviousSession() ? $request->getSession() : null;
+ $session = !$request->attributes->getBoolean('_stateless') && $request->hasPreviousSession() ? $request->getSession() : null;
if ($session instanceof Session) {
$usageIndexValue = $usageIndexReference = &$session->getUsageIndex();
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index 8ffde8fe164a9..d20596d9c3298 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -76,11 +76,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
*/
private static array $freshCache = [];
- public const VERSION = '6.4.8';
- public const VERSION_ID = 60408;
+ public const VERSION = '6.4.9';
+ public const VERSION_ID = 60409;
public const MAJOR_VERSION = 6;
public const MINOR_VERSION = 4;
- public const RELEASE_VERSION = 8;
+ public const RELEASE_VERSION = 9;
public const EXTRA_VERSION = '';
public const END_OF_MAINTENANCE = '11/2026';
@@ -539,10 +539,17 @@ protected function initializeContainer()
touch($oldContainerDir.'.legacy');
}
- $preload = $this instanceof WarmableInterface ? (array) $this->warmUp($this->container->getParameter('kernel.cache_dir'), $buildDir) : [];
+ $cacheDir = $this->container->getParameter('kernel.cache_dir');
+ $preload = $this instanceof WarmableInterface ? (array) $this->warmUp($cacheDir, $buildDir) : [];
if ($this->container->has('cache_warmer')) {
- $preload = array_merge($preload, (array) $this->container->get('cache_warmer')->warmUp($this->container->getParameter('kernel.cache_dir'), $buildDir));
+ $cacheWarmer = $this->container->get('cache_warmer');
+
+ if ($cacheDir !== $buildDir) {
+ $cacheWarmer->enableOptionalWarmers();
+ }
+
+ $preload = array_merge($preload, (array) $cacheWarmer->warmUp($cacheDir, $buildDir));
}
if ($preload && file_exists($preloadFile = $buildDir.'/'.$class.'.preload.php')) {
diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/ProfilerListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/ProfilerListenerTest.php
index 57f8f53b1e9f7..fdf550d0ecd41 100644
--- a/src/Symfony/Component/HttpKernel/Tests/EventListener/ProfilerListenerTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/ProfilerListenerTest.php
@@ -40,8 +40,8 @@ public function testKernelTerminate()
->willReturn($profile);
$kernel = $this->createMock(HttpKernelInterface::class);
- $mainRequest = $this->createMock(Request::class);
- $subRequest = $this->createMock(Request::class);
+ $mainRequest = new Request();
+ $subRequest = new Request();
$response = $this->createMock(Response::class);
$requestStack = new RequestStack();
diff --git a/src/Symfony/Component/Mailer/Bridge/Infobip/README.md b/src/Symfony/Component/Mailer/Bridge/Infobip/README.md
index c86458c3991f9..b040f259e20b5 100644
--- a/src/Symfony/Component/Mailer/Bridge/Infobip/README.md
+++ b/src/Symfony/Component/Mailer/Bridge/Infobip/README.md
@@ -12,10 +12,24 @@ MAILER_DSN=infobip+api://KEY@BASE_URL
MAILER_DSN=infobip+smtp://KEY@default
```
+Custom Headers
+--------------
+
+This transport supports the following custom headers:
+
+| Header | Type | Description |
+| -------------------------------- | ------- | -------------------------------------------------------------------------------------------- |
+| `X-Infobip-IntermediateReport` | boolean | The real-time Intermediate delivery report that will be sent on your callback server. |
+| `X-Infobip-NotifyUrl` | string | The URL on your callback server on which the Delivery report will be sent. |
+| `X-Infobip-NotifyContentType` | string | Preferred Delivery report content type. Can be application/json or application/xml. |
+| `X-Infobip-MessageId` | string | The ID that uniquely identifies the message sent to a recipient. |
+| `X-Infobip-Track` | boolean | Enable or disable open and click tracking. |
+
Resources
---------
-* [Infobip Api Docs](https://www.infobip.com/docs/api#channels/email)
-* [Contributing](https://symfony.com/doc/current/contributing/index.html)
-* [Report issues](https://github.com/symfony/symfony/issues) and
- [send Pull Requests](https://github.com/symfony/symfony/pulls)
- in the [main Symfony repository](https://github.com/symfony/symfony)
+
+ * [Infobip Api Docs](https://www.infobip.com/docs/api#channels/email)
+ * [Contributing](https://symfony.com/doc/current/contributing/index.html)
+ * [Report issues](https://github.com/symfony/symfony/issues) and
+ [send Pull Requests](https://github.com/symfony/symfony/pulls)
+ in the [main Symfony repository](https://github.com/symfony/symfony)
diff --git a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHttpTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHttpTransport.php
index 626a494d158fc..ca0100918dde8 100644
--- a/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHttpTransport.php
+++ b/src/Symfony/Component/Mailer/Bridge/Mailgun/Transport/MailgunHttpTransport.php
@@ -63,6 +63,7 @@ protected function doSendHttp(SentMessage $message): ResponseInterface
$endpoint = sprintf('%s/v3/%s/messages.mime', $this->getEndpoint(), urlencode($this->domain));
$response = $this->client->request('POST', 'https://'.$endpoint, [
+ 'http_version' => '1.1',
'auth_basic' => 'api:'.$this->key,
'headers' => $headers,
'body' => $body->bodyToIterable(),
diff --git a/src/Symfony/Component/Mailer/Bridge/Scaleway/Tests/Transport/ScalewayApiTransportTest.php b/src/Symfony/Component/Mailer/Bridge/Scaleway/Tests/Transport/ScalewayApiTransportTest.php
index 0d91d002cd21c..f31e041ea73d0 100644
--- a/src/Symfony/Component/Mailer/Bridge/Scaleway/Tests/Transport/ScalewayApiTransportTest.php
+++ b/src/Symfony/Component/Mailer/Bridge/Scaleway/Tests/Transport/ScalewayApiTransportTest.php
@@ -69,6 +69,8 @@ public function testSend()
$this->assertSame('attachment.txt', $body['attachments'][0]['name']);
$this->assertSame('text/plain', $body['attachments'][0]['type']);
$this->assertSame(base64_encode('some attachment'), $body['attachments'][0]['content']);
+ $this->assertSame('Reply-To', $body['additional_headers'][0]['key']);
+ $this->assertStringContainsString('foo@bar.fr', $body['additional_headers'][0]['value']);
return new JsonMockResponse(['emails' => [['message_id' => 'foobar']]], [
'http_code' => 200,
@@ -81,6 +83,7 @@ public function testSend()
$mail->subject('Hello!')
->to(new Address('saif.gmati@symfony.com', 'Saif Eddin'))
->from(new Address('fabpot@symfony.com', 'Fabien'))
+ ->replyTo(new Address('foo@bar.fr', 'Foo'))
->text('Hello There!')
->addPart(new DataPart('some attachment', 'attachment.txt', 'text/plain'));
diff --git a/src/Symfony/Component/Mailer/Bridge/Scaleway/Transport/ScalewayApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Scaleway/Transport/ScalewayApiTransport.php
index 60cb198d3b5ab..3c277abb6e719 100644
--- a/src/Symfony/Component/Mailer/Bridge/Scaleway/Transport/ScalewayApiTransport.php
+++ b/src/Symfony/Component/Mailer/Bridge/Scaleway/Transport/ScalewayApiTransport.php
@@ -101,6 +101,9 @@ private function getPayload(Email $email, Envelope $envelope): array
if ($attachements = $this->prepareAttachments($email)) {
$payload['attachments'] = $attachements;
}
+ if ($headers = $this->getCustomHeaders($email)) {
+ $payload['additional_headers'] = $headers;
+ }
return $payload;
}
@@ -122,6 +125,24 @@ private function prepareAttachments(Email $email): array
return $attachments;
}
+ private function getCustomHeaders(Email $email): array
+ {
+ $headers = [];
+ $headersToBypass = ['from', 'to', 'cc', 'bcc', 'subject', 'content-type', 'sender'];
+ foreach ($email->getHeaders()->all() as $name => $header) {
+ if (\in_array($name, $headersToBypass, true)) {
+ continue;
+ }
+
+ $headers[] = [
+ 'key' => $header->getName(),
+ 'value' => $header->getBodyAsString(),
+ ];
+ }
+
+ return $headers;
+ }
+
private function formatAddress(Address $address): array
{
$array = ['email' => $address->getAddress()];
diff --git a/src/Symfony/Component/Mailer/MailerInterface.php b/src/Symfony/Component/Mailer/MailerInterface.php
index 8d9540a3e5e3f..ebac4b53efa4e 100644
--- a/src/Symfony/Component/Mailer/MailerInterface.php
+++ b/src/Symfony/Component/Mailer/MailerInterface.php
@@ -15,7 +15,7 @@
use Symfony\Component\Mime\RawMessage;
/**
- * Interface for mailers able to send emails synchronous and/or asynchronous.
+ * Interface for mailers able to send emails synchronously and/or asynchronously.
*
* Implementations must support synchronous and asynchronous sending.
*
diff --git a/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Tests/Transport/AmazonSqsSenderTest.php b/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Tests/Transport/AmazonSqsSenderTest.php
index 80840c859cb05..d11a5d8037b27 100644
--- a/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Tests/Transport/AmazonSqsSenderTest.php
+++ b/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Tests/Transport/AmazonSqsSenderTest.php
@@ -72,4 +72,19 @@ public function testSendWithAmazonSqsXrayTraceHeaderStamp()
$sender = new AmazonSqsSender($connection, $serializer);
$sender->send($envelope);
}
+
+ public function testSendEncodeBodyToRespectAmazonRequirements()
+ {
+ $envelope = new Envelope(new DummyMessage('Oy'));
+ $encoded = ['body' => "\x7", 'headers' => ['type' => DummyMessage::class]];
+
+ $connection = $this->createMock(Connection::class);
+ $connection->expects($this->once())->method('send')->with(base64_encode($encoded['body']), $encoded['headers']);
+
+ $serializer = $this->createMock(SerializerInterface::class);
+ $serializer->method('encode')->with($envelope)->willReturn($encoded);
+
+ $sender = new AmazonSqsSender($connection, $serializer);
+ $sender->send($envelope);
+ }
}
diff --git a/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Transport/AmazonSqsSender.php b/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Transport/AmazonSqsSender.php
index ca13e0c737311..eba67c1ca1b2c 100644
--- a/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Transport/AmazonSqsSender.php
+++ b/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Transport/AmazonSqsSender.php
@@ -35,6 +35,7 @@ public function __construct(Connection $connection, SerializerInterface $seriali
public function send(Envelope $envelope): Envelope
{
$encodedMessage = $this->serializer->encode($envelope);
+ $encodedMessage = $this->complyWithAmazonSqsRequirements($encodedMessage);
/** @var DelayStamp|null $delayStamp */
$delayStamp = $envelope->last(DelayStamp::class);
@@ -69,4 +70,20 @@ public function send(Envelope $envelope): Envelope
return $envelope;
}
+
+ /**
+ * @see https://docs.aws.amazon.com/AWSSimpleQueueService/latest/APIReference/API_SendMessage.html
+ *
+ * @param array{body: string, headers?: array} $encodedMessage
+ *
+ * @return array{body: string, headers?: array}
+ */
+ private function complyWithAmazonSqsRequirements(array $encodedMessage): array
+ {
+ if (preg_match('/[^\x20-\x{D7FF}\xA\xD\x9\x{E000}-\x{FFFD}\x{10000}-\x{10FFFF}]/u', $encodedMessage['body'])) {
+ $encodedMessage['body'] = base64_encode($encodedMessage['body']);
+ }
+
+ return $encodedMessage;
+ }
}
diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrinePostgreSqlFilterIntegrationTest.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrinePostgreSqlFilterIntegrationTest.php
new file mode 100644
index 0000000000000..9a4738be2ed97
--- /dev/null
+++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrinePostgreSqlFilterIntegrationTest.php
@@ -0,0 +1,119 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Messenger\Bridge\Doctrine\Tests\Transport;
+
+use Doctrine\DBAL\Configuration;
+use Doctrine\DBAL\Connection;
+use Doctrine\DBAL\DriverManager;
+use Doctrine\DBAL\Schema\Column;
+use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory;
+use Doctrine\DBAL\Schema\Sequence;
+use Doctrine\DBAL\Schema\Table;
+use Doctrine\DBAL\Tools\DsnParser;
+use Doctrine\DBAL\Types\Type;
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\Messenger\Bridge\Doctrine\Transport\PostgreSqlConnection;
+
+/**
+ * This test checks on a postgres connection whether the doctrine asset filter works as expected.
+ *
+ * @requires extension pdo_pgsql
+ *
+ * @group integration
+ */
+class DoctrinePostgreSqlFilterIntegrationTest extends TestCase
+{
+ private Connection $driverConnection;
+
+ protected function setUp(): void
+ {
+ if (!$host = getenv('POSTGRES_HOST')) {
+ $this->markTestSkipped('Missing POSTGRES_HOST env variable');
+ }
+
+ $url = "pdo-pgsql://postgres:password@$host";
+ $params = (new DsnParser())->parse($url);
+ $config = new Configuration();
+ if (class_exists(DefaultSchemaManagerFactory::class)) {
+ $config->setSchemaManagerFactory(new DefaultSchemaManagerFactory());
+ }
+
+ $this->driverConnection = DriverManager::getConnection($params, $config);
+
+ $this->createAssets();
+ }
+
+ protected function tearDown(): void
+ {
+ $this->removeAssets();
+
+ $this->driverConnection->close();
+ }
+
+ public function testFilterAssets()
+ {
+ $schemaManager = $this->driverConnection->createSchemaManager();
+
+ $this->assertFalse($schemaManager->tablesExist(['queue_table']));
+ $this->assertTrue($schemaManager->tablesExist(['app_table']));
+ $this->assertTrue($this->hasSequence('app_table_id'));
+
+ $connection = new PostgreSqlConnection(['table_name' => 'queue_table'], $this->driverConnection);
+ $connection->setup();
+
+ $schemaManager = $this->driverConnection->createSchemaManager();
+
+ $this->assertTrue($schemaManager->tablesExist(['queue_table']));
+ $this->assertTrue($schemaManager->tablesExist(['app_table']));
+ $this->assertTrue($this->hasSequence('app_table_id'));
+ }
+
+ private function createAssets(): void
+ {
+ $this->removeAssets();
+
+ $schemaManager = $this->driverConnection->createSchemaManager();
+ $schemaManager->createTable(new Table('app_table', [new Column('id', Type::getType('integer'))]));
+ $schemaManager->createSequence(new Sequence('app_table_id'));
+ }
+
+ private function removeAssets(): void
+ {
+ $schemaManager = $this->driverConnection->createSchemaManager();
+
+ if ($schemaManager->tablesExist(['queue_table'])) {
+ $schemaManager->dropTable('queue_table');
+ }
+
+ if ($schemaManager->tablesExist(['app_table'])) {
+ $schemaManager->dropTable('app_table');
+ }
+
+ if ($this->hasSequence('app_table_id')) {
+ $schemaManager->dropSequence('app_table_id');
+ }
+ }
+
+ private function hasSequence(string $name): bool
+ {
+ $schemaManager = $this->driverConnection->createSchemaManager();
+
+ $sequences = $schemaManager->listSequences();
+ foreach ($sequences as $sequence) {
+ if ($sequence->getName() === $name) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+}
diff --git a/src/Symfony/Component/Messenger/EventListener/DispatchPcntlSignalListener.php b/src/Symfony/Component/Messenger/EventListener/DispatchPcntlSignalListener.php
index 37b88ca1b852a..258ce64480344 100644
--- a/src/Symfony/Component/Messenger/EventListener/DispatchPcntlSignalListener.php
+++ b/src/Symfony/Component/Messenger/EventListener/DispatchPcntlSignalListener.php
@@ -21,6 +21,10 @@ class DispatchPcntlSignalListener implements EventSubscriberInterface
{
public function onWorkerRunning(): void
{
+ if (!\function_exists('pcntl_signal_dispatch')) {
+ return;
+ }
+
pcntl_signal_dispatch();
}
diff --git a/src/Symfony/Component/Mime/RawMessage.php b/src/Symfony/Component/Mime/RawMessage.php
index 62f3491ba12e4..484ffb0073f6a 100644
--- a/src/Symfony/Component/Mime/RawMessage.php
+++ b/src/Symfony/Component/Mime/RawMessage.php
@@ -18,7 +18,8 @@
*/
class RawMessage
{
- private iterable|string $message;
+ /** @var iterable|string|resource */
+ private $message;
private bool $isGeneratorClosed;
public function __construct(iterable|string $message)
@@ -26,12 +27,23 @@ public function __construct(iterable|string $message)
$this->message = $message;
}
+ public function __destruct()
+ {
+ if (\is_resource($this->message)) {
+ fclose($this->message);
+ }
+ }
+
public function toString(): string
{
if (\is_string($this->message)) {
return $this->message;
}
+ if (\is_resource($this->message)) {
+ return stream_get_contents($this->message, -1, 0);
+ }
+
$message = '';
foreach ($this->message as $chunk) {
$message .= $chunk;
@@ -53,10 +65,19 @@ public function toIterable(): iterable
return;
}
+ if (\is_resource($this->message)) {
+ rewind($this->message);
+ while ($line = fgets($this->message)) {
+ yield $line;
+ }
+
+ return;
+ }
+
if ($this->message instanceof \Generator) {
- $message = '';
+ $message = fopen('php://temp', 'w+');
foreach ($this->message as $chunk) {
- $message .= $chunk;
+ fwrite($message, $chunk);
yield $chunk;
}
$this->isGeneratorClosed = !$this->message->valid();
diff --git a/src/Symfony/Component/Mime/Tests/Part/DataPartTest.php b/src/Symfony/Component/Mime/Tests/Part/DataPartTest.php
index 70ab2d7c30a8c..4ac1fa5aab631 100644
--- a/src/Symfony/Component/Mime/Tests/Part/DataPartTest.php
+++ b/src/Symfony/Component/Mime/Tests/Part/DataPartTest.php
@@ -143,15 +143,15 @@ public function testFromPathWithUrl()
}
$finder = new PhpExecutableFinder();
- $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', 'localhost:8057']));
+ $process = new Process(array_merge([$finder->find(false)], $finder->findArguments(), ['-dopcache.enable=0', '-dvariables_order=EGPCS', '-S', 'localhost:8856']));
$process->setWorkingDirectory(__DIR__.'/../Fixtures/web');
$process->start();
try {
do {
usleep(50000);
- } while (!@fopen('http://localhost:8057', 'r'));
- $p = DataPart::fromPath($file = 'http://localhost:8057/logo_symfony_header.png');
+ } while (!@fopen('http://localhost:8856', 'r'));
+ $p = DataPart::fromPath($file = 'http://localhost:8856/logo_symfony_header.png');
$content = file_get_contents($file);
$this->assertEquals($content, $p->getBody());
$maxLineLength = 76;
diff --git a/src/Symfony/Component/Mime/composer.json b/src/Symfony/Component/Mime/composer.json
index c9cf9eaaa0f60..ae5ca36d8e940 100644
--- a/src/Symfony/Component/Mime/composer.json
+++ b/src/Symfony/Component/Mime/composer.json
@@ -29,14 +29,14 @@
"symfony/process": "^5.4|^6.4|^7.0",
"symfony/property-access": "^5.4|^6.0|^7.0",
"symfony/property-info": "^5.4|^6.0|^7.0",
- "symfony/serializer": "^6.3.2|^7.0"
+ "symfony/serializer": "^6.4.3|^7.0.3"
},
"conflict": {
"egulias/email-validator": "~3.0.0",
"phpdocumentor/reflection-docblock": "<3.2.2",
"phpdocumentor/type-resolver": "<1.4.0",
"symfony/mailer": "<5.4",
- "symfony/serializer": "<6.3.2"
+ "symfony/serializer": "<6.4.3|>7.0,<7.0.3"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Mime\\": "" },
diff --git a/src/Symfony/Component/Notifier/Bridge/Clickatell/ClickatellTransport.php b/src/Symfony/Component/Notifier/Bridge/Clickatell/ClickatellTransport.php
index 65321f79ca793..75621994d2c2e 100644
--- a/src/Symfony/Component/Notifier/Bridge/Clickatell/ClickatellTransport.php
+++ b/src/Symfony/Component/Notifier/Bridge/Clickatell/ClickatellTransport.php
@@ -63,7 +63,7 @@ protected function doSend(MessageInterface $message): SentMessage
$options = [];
$options['from'] = $message->getFrom() ?: $this->from;
- $options['to'] = $message->getPhone();
+ $options['to'] = [$message->getPhone()];
$options['text'] = $message->getSubject();
$response = $this->client->request('POST', $endpoint, [
diff --git a/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatTransport.php b/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatTransport.php
index 944c5d2c46ec0..0cb81e6ef594b 100644
--- a/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatTransport.php
+++ b/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatTransport.php
@@ -91,15 +91,24 @@ protected function doSend(MessageInterface $message): SentMessage
$threadKey = $options->getThreadKey() ?: $this->threadKey;
+ $threadKey = $options->getThreadKey() ?: $this->threadKey;
+
$url = sprintf('https://%s/v1/spaces/%s/messages?key=%s&token=%s%s',
$this->getEndpoint(),
$this->space,
urlencode($this->accessKey),
urlencode($this->accessToken),
- $threadKey ? '&threadKey='.urlencode($threadKey) : ''
+ $threadKey ? '&messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD' : ''
);
+
+ $body = array_filter($options->toArray());
+
+ if ($threadKey) {
+ $body['thread']['threadKey'] = $threadKey;
+ }
+
$response = $this->client->request('POST', $url, [
- 'json' => array_filter($options->toArray()),
+ 'json' => $body,
]);
try {
diff --git a/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportTest.php b/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportTest.php
index 4f423290c3608..2b277f910b0b9 100644
--- a/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportTest.php
+++ b/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportTest.php
@@ -108,11 +108,11 @@ public function testSendWithOptions()
->method('getContent')
->willReturn('{"name":"spaces/My-Space/messages/abcdefg.hijklmno"}');
- $expectedBody = json_encode(['text' => $message]);
+ $expectedBody = json_encode(['text' => $message, 'thread' => ['threadKey' => 'My-Thread']]);
$client = new MockHttpClient(function (string $method, string $url, array $options = []) use ($response, $expectedBody): ResponseInterface {
$this->assertSame('POST', $method);
- $this->assertSame('https://chat.googleapis.com/v1/spaces/My-Space/messages?key=theAccessKey&token=theAccessToken%3D&threadKey=My-Thread', $url);
+ $this->assertSame('https://chat.googleapis.com/v1/spaces/My-Space/messages?key=theAccessKey&token=theAccessToken%3D&messageReplyOption=REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD', $url);
$this->assertSame($expectedBody, $options['body']);
return $response;
diff --git a/src/Symfony/Component/Notifier/ChatterInterface.php b/src/Symfony/Component/Notifier/ChatterInterface.php
index 915190e623aaa..6d89ca921e970 100644
--- a/src/Symfony/Component/Notifier/ChatterInterface.php
+++ b/src/Symfony/Component/Notifier/ChatterInterface.php
@@ -14,7 +14,7 @@
use Symfony\Component\Notifier\Transport\TransportInterface;
/**
- * Interface for classes able to send chat messages synchronous and/or asynchronous.
+ * Interface for classes able to send chat messages synchronously and/or asynchronously.
*
* @author Fabien Potencier
*/
diff --git a/src/Symfony/Component/Notifier/TexterInterface.php b/src/Symfony/Component/Notifier/TexterInterface.php
index e65547755cd70..a044bb6d5d835 100644
--- a/src/Symfony/Component/Notifier/TexterInterface.php
+++ b/src/Symfony/Component/Notifier/TexterInterface.php
@@ -14,7 +14,7 @@
use Symfony\Component\Notifier\Transport\TransportInterface;
/**
- * Interface for classes able to send SMS messages synchronous and/or asynchronous.
+ * Interface for classes able to send SMS messages synchronously and/or asynchronously.
*
* @author Fabien Potencier
*/
diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php
index 252df9914f683..9d7e69633d578 100644
--- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php
+++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php
@@ -398,6 +398,11 @@ public function testUnknownPseudoType()
$this->assertEquals([new Type(Type::BUILTIN_TYPE_OBJECT, false, 'scalar')], $this->extractor->getTypes(PseudoTypeDummy::class, 'unknownPseudoType'));
}
+ public function testGenericInterface()
+ {
+ $this->assertNull($this->extractor->getTypes(Dummy::class, 'genericInterface'));
+ }
+
/**
* @dataProvider constructorTypesProvider
*/
diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php
index e2da679865abf..0d1163d3ba295 100644
--- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php
+++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpStanExtractorTest.php
@@ -385,7 +385,7 @@ public static function unionTypesProvider(): array
['b', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [new Type(Type::BUILTIN_TYPE_INT)], [new Type(Type::BUILTIN_TYPE_STRING), new Type(Type::BUILTIN_TYPE_INT)])]],
['c', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [], [new Type(Type::BUILTIN_TYPE_STRING), new Type(Type::BUILTIN_TYPE_INT)])]],
['d', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [new Type(Type::BUILTIN_TYPE_STRING), new Type(Type::BUILTIN_TYPE_INT)], [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [], [new Type(Type::BUILTIN_TYPE_STRING)])])]],
- ['e', [new Type(Type::BUILTIN_TYPE_OBJECT, true, Dummy::class, true, [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [], [new Type(Type::BUILTIN_TYPE_STRING)])], [new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [new Type(Type::BUILTIN_TYPE_INT)], [new Type(Type::BUILTIN_TYPE_STRING, false, null, true, [], [new Type(Type::BUILTIN_TYPE_OBJECT, false, DefaultValue::class)])])]), new Type(Type::BUILTIN_TYPE_OBJECT, false, ParentDummy::class)]],
+ ['e', [new Type(Type::BUILTIN_TYPE_OBJECT, true, Dummy::class, false, [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [], [new Type(Type::BUILTIN_TYPE_STRING)])], [new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [new Type(Type::BUILTIN_TYPE_INT)], [new Type(Type::BUILTIN_TYPE_OBJECT, false, \Traversable::class, true, [], [new Type(Type::BUILTIN_TYPE_OBJECT, false, DefaultValue::class)])])]), new Type(Type::BUILTIN_TYPE_OBJECT, false, ParentDummy::class)]],
['f', null],
['g', [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, [], [new Type(Type::BUILTIN_TYPE_STRING), new Type(Type::BUILTIN_TYPE_INT)])]],
];
@@ -477,6 +477,11 @@ public static function php80TypesProvider()
[Php80PromotedDummy::class, 'promoted', null],
];
}
+
+ public function testGenericInterface()
+ {
+ $this->assertNull($this->extractor->getTypes(Dummy::class, 'genericInterface'));
+ }
}
class PhpStanOmittedParamTagTypeDocBlock
diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php
index 1b0c9f4b46cf2..832db51c81690 100644
--- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php
+++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php
@@ -68,6 +68,7 @@ public function testGetProperties()
'arrayOfMixed',
'listOfStrings',
'parentAnnotation',
+ 'genericInterface',
'foo',
'foo2',
'foo3',
@@ -132,6 +133,7 @@ public function testGetPropertiesWithCustomPrefixes()
'arrayOfMixed',
'listOfStrings',
'parentAnnotation',
+ 'genericInterface',
'foo',
'foo2',
'foo3',
@@ -185,6 +187,7 @@ public function testGetPropertiesWithNoPrefixes()
'arrayOfMixed',
'listOfStrings',
'parentAnnotation',
+ 'genericInterface',
'foo',
'foo2',
'foo3',
diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php
index c76f7a7c8b296..1478c87f551b6 100644
--- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php
+++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php
@@ -165,6 +165,11 @@ class Dummy extends ParentDummy
*/
public $parentAnnotation;
+ /**
+ * @var \BackedEnum
+ */
+ public $genericInterface;
+
public static function getStatic()
{
}
diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyUnionType.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyUnionType.php
index 86ddb8a1650eb..7e2e1aa3ec8f7 100644
--- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyUnionType.php
+++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DummyUnionType.php
@@ -40,7 +40,7 @@ class DummyUnionType
public $d;
/**
- * @var (Dummy, (int | (string)[])> | ParentDummy | null)
+ * @var (Dummy, (int | (\Traversable)[])> | ParentDummy | null)
*/
public $e;
diff --git a/src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php b/src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php
index b77da7d3f1ffe..bde63b89f67f2 100644
--- a/src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php
+++ b/src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php
@@ -105,9 +105,9 @@ public function getTypes(DocType $varType): array
/**
* Creates a {@see Type} from a PHPDoc type.
*/
- private function createType(DocType $type, bool $nullable, ?string $docType = null): ?Type
+ private function createType(DocType $type, bool $nullable): ?Type
{
- $docType ??= (string) $type;
+ $docType = (string) $type;
if ($type instanceof Collection) {
$fqsen = $type->getFqsen();
@@ -118,10 +118,17 @@ private function createType(DocType $type, bool $nullable, ?string $docType = nu
[$phpType, $class] = $this->getPhpTypeAndClass((string) $fqsen);
+ $collection = \is_a($class, \Traversable::class, true) || \is_a($class, \ArrayAccess::class, true);
+
+ // it's safer to fall back to other extractors if the generic type is too abstract
+ if (!$collection && !class_exists($class)) {
+ return null;
+ }
+
$keys = $this->getTypes($type->getKeyType());
$values = $this->getTypes($type->getValueType());
- return new Type($phpType, $nullable, $class, true, $keys, $values);
+ return new Type($phpType, $nullable, $class, $collection, $keys, $values);
}
// Cannot guess
diff --git a/src/Symfony/Component/PropertyInfo/Util/PhpStanTypeHelper.php b/src/Symfony/Component/PropertyInfo/Util/PhpStanTypeHelper.php
index 0a02071ec70b7..f8cc166f3be99 100644
--- a/src/Symfony/Component/PropertyInfo/Util/PhpStanTypeHelper.php
+++ b/src/Symfony/Component/PropertyInfo/Util/PhpStanTypeHelper.php
@@ -125,6 +125,13 @@ private function extractTypes(TypeNode $node, NameScope $nameScope): array
return [$mainType];
}
+ $collection = $mainType->isCollection() || \in_array($mainType->getClassName(), [\Traversable::class, \Iterator::class, \IteratorAggregate::class, \ArrayAccess::class, \Generator::class], true);
+
+ // it's safer to fall back to other extractors if the generic type is too abstract
+ if (!$collection && !class_exists($mainType->getClassName())) {
+ return [];
+ }
+
$collectionKeyTypes = $mainType->getCollectionKeyTypes();
$collectionKeyValues = [];
if (1 === \count($node->genericTypes)) {
@@ -140,7 +147,7 @@ private function extractTypes(TypeNode $node, NameScope $nameScope): array
}
}
- return [new Type($mainType->getBuiltinType(), $mainType->isNullable(), $mainType->getClassName(), true, $collectionKeyTypes, $collectionKeyValues)];
+ return [new Type($mainType->getBuiltinType(), $mainType->isNullable(), $mainType->getClassName(), $collection, $collectionKeyTypes, $collectionKeyValues)];
}
if ($node instanceof ArrayShapeNode) {
return [new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true)];
diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.ca.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.ca.xlf
index 6d7dc7fc23e33..93ff24f330735 100644
--- a/src/Symfony/Component/Security/Core/Resources/translations/security.ca.xlf
+++ b/src/Symfony/Component/Security/Core/Resources/translations/security.ca.xlf
@@ -64,7 +64,7 @@
Too many failed login attempts, please try again later.
- Massa intents d'inici de sessió fallits, torneu-ho a provar més tard.
+ Massa intents d'inici de sessió fallits, si us plau torneu-ho a provar més tard.Invalid or expired login link.
@@ -72,11 +72,11 @@
Too many failed login attempts, please try again in %minutes% minute.
- Massa intents d'inici de sessió fallits, torneu-ho a provar en %minutes% minut.
+ Massa intents d'inici de sessió fallits, si us plau torneu-ho a provar en %minutes% minut.Too many failed login attempts, please try again in %minutes% minutes.
- Massa intents fallits d'inici de sessió, torneu-ho a provar d'aquí a %minutes% minuts.
+ Massa intents d'inici de sessió fallits, si us plau torneu-ho a provar en %minutes% minuts.