diff --git a/CHANGELOG-6.3.md b/CHANGELOG-6.3.md
index d50e65ef16b3f..a7490b8179172 100644
--- a/CHANGELOG-6.3.md
+++ b/CHANGELOG-6.3.md
@@ -7,6 +7,38 @@ in 6.3 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v6.3.0...v6.3.1
+* 6.3.9 (2023-11-29)
+
+ * bug #52786 [Serializer] Revert allowed attributes fix (mtarld)
+ * bug #52780 [DependencyInjection] don't check parameter values if they are not set (xabbuh)
+ * bug #52762 [VarExporter] Work around php/php-src#12695 for lazy objects, fixing nullsafe-related behavior (nicolas-grekas)
+ * bug #52759 [VarExporter] Fix serializing objects that implement __sleep() and that are made lazy (nicolas-grekas)
+ * bug #52767 [Serializer] Fix normalization relying on allowed attributes only (mtarld)
+ * bug #52727 [String] Fix Inflector for 'icon' (podhy)
+ * bug #52677 [Translation] [Lokalise] Fix language format on Lokalise Provider (welcoMattic)
+ * bug #52715 [Cache] fix detecting the database server version (xabbuh)
+ * bug #52688 [Cache] Add url decoding of password in `RedisTrait` DSN (alexandre-daubois)
+ * bug #52172 [Serializer] Fix denormalizing empty string into `object|null` parameter (Jeroeny)
+ * bug #52693 [Messenger] Fix message handlers with multiple `from_transports` (valtzu)
+ * bug #52684 [PropertyInfo] Fixed promoted property type detection for `PhpStanExtractor` (LastDragon-ru)
+ * bug #52681 [Serializer] Fix support for DiscriminatorMap in PropertyNormalizer (mtarld)
+ * bug #52680 [Serializer] Fix access to private properties/getters when using the ``@Ignore`` annotation (mtarld)
+ * bug #52713 [Serializer] Fix deserialization_path missing using contructor (mtarld)
+ * bug #52683 [Serializer] Fix constructor deserialization path (mtarld)
+ * bug #52707 [HttpKernel] Fix logging deprecations to the "php" channel when channel "deprecation" is not defined (nicolas-grekas)
+ * bug #52589 [Serializer] Fix XML attributes not added on empty node (mtarld)
+ * bug #52686 [Cache] fix detecting the server version with Doctrine DBAL 4 (xabbuh)
+ * bug #52629 [Messenger] Fix support for Redis Sentinel using php-redis 6.0.0 (pepeh)
+ * bug #52459 [Cache][HttpFoundation][Lock] Fix PDO store not creating table + add tests (HypeMC)
+ * bug #52626 [Serializer] Fix denormalizing date intervals having both weeks and days (oneNevan)
+ * bug #52578 [Serializer] Fix denormalize constructor arguments (mtarld)
+ * bug #52526 Add some more non-countable English nouns (paullallier)
+ * bug #52631 [DomCrawler] Revert "bug #52579 UriResolver support path with colons" (lyrixx)
+ * bug #52618 [VarExporter] Fix handling mangled property names returned by __sleep() (nicolas-grekas)
+ * bug #52588 [Messenger] Use extension_loaded call to check if pcntl extension is loaded, as SIGTERM might be set be swoole (Sergii Dolgushev)
+ * bug #52579 [DomCrawler] UriResolver support path with colons (vdauchy)
+ * bug #52581 [Messenger] attach all required parameters to query (xabbuh)
+
* 6.3.8 (2023-11-10)
* bug #51666 [RateLimiter] CompoundLimiter was accepting requests even when some limiters already consumed all tokens (10n)
diff --git a/CHANGELOG-6.4.md b/CHANGELOG-6.4.md
index 60185b4c5470a..582a03377b9da 100644
--- a/CHANGELOG-6.4.md
+++ b/CHANGELOG-6.4.md
@@ -7,6 +7,21 @@ 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.1 (2023-12-01)
+
+ * bug #52814 [Workflow] Add `getEnabledTransition()` to TraceableWorkflow (alexandre-daubois)
+ * bug #52852 [Serializer] Fix TranslatableNormalizer when the Translator is disabled (Jean-Beru)
+ * bug #52836 [DependencyInjection] Fix parsing named autowiring aliases that contain underscores (nicolas-grekas)
+ * bug #52804 [Serializer] Fix support of plain object types denormalization (andersonamuller)
+ * bug #52845 [Routing] Restore aliases removal in RouteCollection::remove() (fancyweb)
+ * bug #52846 [PhpUnitBridge] run composer update for compatibility with PHPUnit versions shipping composer.lock (xabbuh)
+ * bug #52823 add parameter types in query builder (javiercno)
+ * bug #52825 [AssetMapper] Upgrade asset mapper to 6.4 fails due to invalid entries "downloaded_to" and "preload" (redflo)
+ * bug #52808 [DependencyInjection] Fix dumping containers with null-referenced services (nicolas-grekas)
+ * bug #52797 [VarExporter] Fix lazy ghost trait when using nullsafe operator (nicolas-grekas)
+ * bug #52806 [Routing] Fix removing aliases pointing to removed route in `RouteCollection::remove()` (fancyweb)
+ * bug #52805 [Routing] Fix conflicting FQCN aliases with route name (fancyweb)
+
* 6.4.0 (2023-11-29)
* bug #52786 [Serializer] Revert allowed attributes fix (mtarld)
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index b7f58c00c8501..ce074d555f730 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -6,45 +6,45 @@ Symfony is the result of the work of many people who made the code better.
The Symfony Connect username in parenthesis allows to get more information
- Fabien Potencier (fabpot)
- Nicolas Grekas (nicolas-grekas)
- - Christian Flothmann (xabbuh)
- Alexander M. Turek (derrabus)
+ - Christian Flothmann (xabbuh)
- Bernhard Schussek (bschussek)
- Robin Chalas (chalas_r)
- Tobias Schultze (tobion)
- Grégoire Pineau (lyrixx)
- Thomas Calvet (fancyweb)
- Christophe Coevoet (stof)
- - Jordi Boggiano (seldaek)
- Wouter de Jong (wouterj)
+ - Jordi Boggiano (seldaek)
- Maxime Steinhausser (ogizanagi)
- Kévin Dunglas (dunglas)
- Victor Berchet (victor)
- Ryan Weaver (weaverryan)
- - Jérémy DERUSSÉ (jderusse)
+ - Alexandre Daubois (alexandre-daubois)
- Javier Eguiluz (javier.eguiluz)
+ - Jérémy DERUSSÉ (jderusse)
- Roland Franssen
+ - Jules Pietri (heah)
- Johannes S (johannes)
- Kris Wallsmith (kriswallsmith)
- Jakub Zalas (jakubzalas)
- - Alexandre Daubois (alexandre-daubois)
- - Jules Pietri (heah)
- Oskar Stark (oskarstark)
- Yonel Ceruto (yonelceruto)
- Hugo Hamon (hhamon)
- Tobias Nyholm (tobias)
- Samuel ROZE (sroze)
- Pascal Borreli (pborreli)
+ - Jérôme Tamarelle (gromnan)
- Romain Neutron
+ - Antoine Lamirault (alamirault)
- Joseph Bielawski (stloyd)
- Drak (drak)
- Abdellatif Ait boudad (aitboudad)
- - Jérôme Tamarelle (gromnan)
- Lukas Kahwe Smith (lsmith)
- - Antoine Lamirault (alamirault)
- - Hamza Amrouche (simperfit)
- Kevin Bond (kbond)
- - Martin Hasoň (hason)
- HypeMC (hypemc)
+ - Hamza Amrouche (simperfit)
+ - Martin Hasoň (hason)
- Jeremy Mikola (jmikola)
- Jean-François Simon (jfsimon)
- Benjamin Eberlei (beberlei)
@@ -72,26 +72,27 @@ The Symfony Connect username in parenthesis allows to get more information
- Bulat Shakirzyanov (avalanche123)
- Iltar van der Berg
- Miha Vrhovnik (mvrhov)
+ - Gary PEGEOT (gary-p)
- Saša Stamenković (umpirsky)
+ - Vincent Langlet (deviling)
+ - Allison Guilhem (a_guilhem)
- Mathieu Piot (mpiot)
- Alexander Schranz (alexander-schranz)
- Vasilij Duško (staff)
- - Vincent Langlet (deviling)
+ - Mathieu Santostefano (welcomattic)
- Sarah Khalil (saro0h)
- Laurent VOULLEMIER (lvo)
- Konstantin Kudryashov (everzet)
- Guilhem N (guilhemn)
- Bilal Amarni (bamarni)
- Eriksen Costa
- - Gary PEGEOT (gary-p)
- - Mathieu Santostefano (welcomattic)
- Florin Patan (florinpatan)
- Vladimir Reznichenko (kalessil)
- Peter Rehm (rpet)
- Henrik Bjørnskov (henrikbjorn)
- - Allison Guilhem (a_guilhem)
- Andrej Hudec (pulzarraider)
- Jáchym Toušek (enumag)
+ - Mathias Arlaud (mtarld)
- David Buchmann (dbu)
- Dariusz Ruminski
- Christian Raue
@@ -103,6 +104,8 @@ The Symfony Connect username in parenthesis allows to get more information
- Alex Pott
- Fran Moreno (franmomu)
- Arnout Boks (aboks)
+ - Frank A. Fiebig (fafiebig)
+ - Baldini
- Charles Sarrazin (csarrazi)
- Ruud Kamphuis (ruudk)
- Henrik Westphal (snc)
@@ -114,7 +117,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Brandon Turner
- Luis Cordova (cordoval)
- Antoine Makdessi (amakdessi)
- - Mathias Arlaud (mtarld)
- Konstantin Myakshin (koc)
- Daniel Holmes (dholmes)
- Julien Falque (julienfalque)
@@ -134,14 +136,14 @@ The Symfony Connect username in parenthesis allows to get more information
- Joel Wurtz (brouznouf)
- Sebastiaan Stok (sstok)
- Maxime STEINHAUSSER
- - Frank A. Fiebig (fafiebig)
- gnito-org
- - Baldini
+ - Jeroen Spee (jeroens)
- Tim Nagel (merk)
- Chris Wilkinson (thewilkybarkid)
- Jérôme Vasseur (jvasseur)
- Peter Kokot (peterkokot)
- Brice BERNARD (brikou)
+ - Simon André (simonandre)
- Michal Piotrowski
- marc.weistroff
- Rokas Mikalkėnas (rokasm)
@@ -149,9 +151,8 @@ The Symfony Connect username in parenthesis allows to get more information
- lenar
- Jacob Dreesen (jdreesen)
- Włodzimierz Gajda (gajdaw)
- - Simon André (simonandre)
- Adrien Brault (adrienbrault)
- - Jeroen Spee (jeroens)
+ - Tac Tacelosky (tacman1123)
- Théo FIDRY
- Florian Voutzinos (florianv)
- Teoh Han Hui (teohhanhui)
@@ -159,8 +160,10 @@ The Symfony Connect username in parenthesis allows to get more information
- Colin Frei
- Javier Spagnoletti (phansys)
- excelwebzone
+ - Vladimir Tsykun (vtsykun)
- Paráda József (paradajozsef)
- Baptiste Clavié (talus)
+ - Martin Auswöger
- Alexander Schwenn (xelaris)
- Fabien Pennequin (fabienpennequin)
- Gordon Franke (gimler)
@@ -190,6 +193,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Jonathan Scheiber (jmsche)
- Daniel Gomes (danielcsgomes)
- Hidenori Goto (hidenorigoto)
+ - Niels Keurentjes (curry684)
- Arnaud Kleinpeter (nanocom)
- Guilherme Blanco (guilhermeblanco)
- Saif Eddin Gmati (azjezz)
@@ -216,7 +220,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Sokolov Evgeniy (ewgraf)
- Andréia Bohner (andreia)
- Tom Van Looy (tvlooy)
- - Niels Keurentjes (curry684)
- Vyacheslav Pavlov
- Albert Casademont (acasademont)
- George Mponos (gmponos)
@@ -229,6 +232,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Vincent Touzet (vincenttouzet)
- Olivier Dolbeau (odolbeau)
- Rouven Weßling (realityking)
+ - Valtteri R (valtzu)
- Ben Davies (bendavies)
- YaFou
- Clemens Tolboom
@@ -237,7 +241,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Alessandro Lai (jean85)
- 77web
- Gocha Ossinkine (ossinkine)
- - Martin Auswöger
- Jesse Rushlow (geeshoe)
- Matthieu Ouellette-Vachon (maoueh)
- Michał Pipa (michal.pipa)
@@ -252,25 +255,23 @@ The Symfony Connect username in parenthesis allows to get more information
- Roland Franssen :)
- GDIBass
- Samuel NELA (snela)
- - Tac Tacelosky (tacman1123)
- Vincent AUBERT (vincent)
- Fabien Bourigault (fbourigault)
- Michael Voříšek
- zairig imad (zairigimad)
- Colin O'Dell (colinodell)
- Sébastien Alfaiate (seb33300)
- - Valtteri R (valtzu)
- James Halsall (jaitsu)
- Christian Scheb
- Guillaume (guill)
- Mikael Pajunen
- Warnar Boekkooi (boekkooi)
- Justin Hileman (bobthecow)
+ - Tomasz Kowalczyk (thunderer)
- Anthony GRASSIOT (antograssiot)
- Dmitrii Chekaliuk (lazyhammer)
- Clément JOBEILI (dator)
- Andreas Möller (localheinz)
- - Vladimir Tsykun (vtsykun)
- Marek Štípek (maryo)
- Daniel Espendiller
- Arnaud PETITPAS (apetitpa)
@@ -341,7 +342,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Marcin Sikoń (marphi)
- Michele Orselli (orso)
- Sven Paulus (subsven)
- - Tomasz Kowalczyk (thunderer)
- Daniel Burger
- Maxime Veber (nek-)
- Bastien Jaillot (bastnic)
@@ -365,6 +365,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Florent Morselli (spomky_)
- dFayet
- Rob Frawley 2nd (robfrawley)
+ - Bram Leeda (bram123)
- Nikita Konstantinov (unkind)
- Dariusz
- Francois Zaninotto
@@ -413,6 +414,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Jurica Vlahoviček (vjurica)
- Bob den Otter (bopp)
- Thomas Schulz (king2500)
+ - Dariusz Rumiński
- Philippe SEGATORI (tigitz)
- Frank de Jonge
- Dane Powell
@@ -472,6 +474,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Warxcell (warxcell)
- Atsuhiro KUBO (iteman)
- rudy onfroy (ronfroy)
+ - Marvin Petker
- Serkan Yildiz (srknyldz)
- Andrew Moore (finewolf)
- Bertrand Zuchuat (garfield-fr)
@@ -503,7 +506,6 @@ The Symfony Connect username in parenthesis allows to get more information
- janschoenherr
- Emanuele Gaspari (inmarelibero)
- Marko Kaznovac (kaznovac)
- - Dariusz Rumiński
- Andrii Bodnar
- Artem (artemgenvald)
- Thierry T (lepiaf)
@@ -515,6 +517,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Ahmed Raafat
- Philippe Segatori
- Thibaut Cheymol (tcheymol)
+ - Herberto Graca
- Erin Millard
- Matthew Lewinski (lewinski)
- Islam Israfilov (islam93)
@@ -535,6 +538,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Dmytro Borysovskyi (dmytr0)
- Johann Pardanaud
- Pavel Kirpitsov (pavel-kirpichyov)
+ - Robert Meijers
- Artur Eshenbrener
- Harm van Tilborg (hvt)
- Thomas Perez (scullwm)
@@ -676,13 +680,13 @@ The Symfony Connect username in parenthesis allows to get more information
- Toni Rudolf (toooni)
- Stefan Gehrig (sgehrig)
- vagrant
+ - Matthias Krauser (mkrauser)
- Benjamin Cremer (bcremer)
- Maarten de Boer (mdeboer)
- Asier Illarramendi (doup)
- AKeeman (akeeman)
- Martijn Cuppens
- Restless-ET
- - Robert Meijers
- Vlad Gregurco (vgregurco)
- Artem Stepin (astepin)
- Boris Vujicic (boris.vujicic)
@@ -945,7 +949,6 @@ The Symfony Connect username in parenthesis allows to get more information
- EStyles (insidestyles)
- Christophe Villeger (seragan)
- Krystian Marcisz (simivar)
- - Matthias Krauser (mkrauser)
- Julien Fredon
- Xavier Leune (xleune)
- Hany el-Kerdany
@@ -1192,6 +1195,7 @@ The Symfony Connect username in parenthesis allows to get more information
- John Bohn (jbohn)
- Jason Tan (jt2k)
- Edvin Hultberg
+ - shubhalgupta
- Felds Liscia (felds)
- Sergey Panteleev
- Andrew Hilobok (hilobok)
@@ -1368,6 +1372,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Emil Einarsson
- 243083df
- Thibault Duplessis
+ - katario
- Rimas Kudelis
- Marc Abramowitz
- Matthias Schmidt
@@ -1827,7 +1832,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Matthias Neid
- Yannick
- Kuzia
- - Bram Leeda
- Vladimir Luchaninov (luchaninov)
- spdionis
- maxime.perrimond
@@ -1841,6 +1845,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Dmitry Derepko
- Rémi Leclerc
- Jan Vernarsky
+ - Ionut Cioflan
- Sergio
- Jonas Hünig
- Mehrdad
@@ -1852,6 +1857,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Jan Walther (janwalther)
- Juan Miguel Besada Vidal (soutlink)
- Takashi Kanemoto (ttskch)
+ - Aleksei Lebedev
- dlorek
- Stuart Fyfe
- Jason Schilling (chapterjason)
@@ -1982,6 +1988,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Tobias Feijten (tobias93)
- mohammadreza honarkhah
- Jessica F Martinez
+ - paullallier
- Artem Oliinyk (artemoliynyk)
- Andrea Quintino (dirk39)
- Andreas Heigl (heiglandreas)
@@ -2231,8 +2238,10 @@ The Symfony Connect username in parenthesis allows to get more information
- Michael Olšavský
- Jay Severson
- Benny Born
+ - Vincent Vermeulen
- Stefan Moonen
- Emirald Mateli
+ - Robert
- René Kerner
- Nathaniel Catchpole
- upchuk
@@ -2305,6 +2314,7 @@ The Symfony Connect username in parenthesis allows to get more information
- rkerner
- Alex Silcock
- Raphael Hardt
+ - Ivan Nemets
- Qingshan Luo
- Ergie Gonzaga
- Matthew J Mucklo
@@ -2452,6 +2462,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Martin Schophaus (m_schophaus_adcada)
- Martynas Sudintas (martiis)
- Anton Sukhachev (mrsuh)
+ - Pavlo Pelekh (pelekh)
- Stefan Kleff (stefanxl)
- Thijs-jan Veldhuizen (tjveldhuizen)
- Vitaliy Zhuk (zhukv)
@@ -2707,6 +2718,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Rénald Casagraude (rcasagraude)
- Robin Duval (robin-duval)
- Mohammad Ali Sarbanha (sarbanha)
+ - Sergii Dolgushev (sergii-swds)
- Steeve Titeca (stiteca)
- Artem Lopata (bumz)
- alex
@@ -2781,6 +2793,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Chansig
- Tischoi
- divinity76
+ - vdauchy
- Andreas Hasenack
- J Bruni
- Alexey Prilipko
@@ -2827,6 +2840,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Vladimir Sadicov (xtech)
- Marcel Berteler
- sdkawata
+ - Frederik Schmitt
- Peter van Dommelen
- Tim van Densen
- Andrzej
@@ -3148,6 +3162,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Tema Yud
- Matt Fields
- Olatunbosun Egberinde
+ - Johannes
- Andras Debreczeni
- Knallcharge
- Vladimir Sazhin
@@ -3360,6 +3375,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Lin Lu
- arduanov
- sualko
+ - Marc Bennewitz
- Fabien
- Martin Komischke
- Yendric
diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php
index f928c87139fe6..b7967deffa998 100644
--- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php
+++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php
@@ -265,7 +265,7 @@
putenv("COMPOSER_ROOT_VERSION=$PHPUNIT_VERSION.99");
$q = '\\' === \DIRECTORY_SEPARATOR && \PHP_VERSION_ID < 80000 ? '"' : '';
// --no-suggest is not in the list to keep compat with composer 1.0, which is shipped with Ubuntu 16.04LTS
- $exit = proc_close(proc_open("$q$COMPOSER install --no-dev --prefer-dist --no-progress $q", [], $p, getcwd()));
+ $exit = proc_close(proc_open("$q$COMPOSER update --no-dev --prefer-dist --no-progress $q", [], $p, getcwd()));
putenv('COMPOSER_ROOT_VERSION'.(false !== $prevRoot ? '='.$prevRoot : ''));
if ($prevCacheDir) {
putenv("COMPOSER_CACHE_DIR=$prevCacheDir");
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index 8a42bfb29ee20..4ff8d5de3d346 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -1938,7 +1938,7 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder
$container->removeDefinition('serializer.mapping.cache_class_metadata_factory');
}
- if (!class_exists(Translator::class)) {
+ if (!$this->readConfigEnabled('translator', $container, $config)) {
$container->removeDefinition('serializer.normalizer.translatable');
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Routing/AnnotatedRouteControllerLoader.php b/src/Symfony/Bundle/FrameworkBundle/Routing/AnnotatedRouteControllerLoader.php
index 9fb17d8d7291d..e9cf9b95c846d 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Routing/AnnotatedRouteControllerLoader.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Routing/AnnotatedRouteControllerLoader.php
@@ -19,7 +19,7 @@ class_exists(AttributeRouteControllerLoader::class);
/**
* @deprecated since Symfony 6.4, to be removed in 7.0, use {@link AttributeRouteControllerLoader} instead
*/
- class AnnotatedRouteControllerLoader
+ class AnnotatedRouteControllerLoader extends AttributeRouteControllerLoader
{
}
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/serializer_without_translator.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/serializer_without_translator.php
new file mode 100644
index 0000000000000..acf0130806b6b
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/serializer_without_translator.php
@@ -0,0 +1,14 @@
+loadFromExtension('framework', [
+ 'annotations' => false,
+ 'http_method_override' => false,
+ 'handle_all_throwables' => true,
+ 'php_errors' => ['log' => true],
+ 'serializer' => [
+ 'enabled' => true,
+ ],
+ 'translator' => [
+ 'enabled' => false,
+ ],
+]);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/serializer_without_translator.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/serializer_without_translator.xml
new file mode 100644
index 0000000000000..584937b0ac4d8
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/serializer_without_translator.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/serializer_without_translator.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/serializer_without_translator.yml
new file mode 100644
index 0000000000000..33ee3f4b881c1
--- /dev/null
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/serializer_without_translator.yml
@@ -0,0 +1,10 @@
+framework:
+ annotations: false
+ http_method_override: false
+ handle_all_throwables: true
+ php_errors:
+ log: true
+ serializer:
+ enabled: true
+ translator:
+ enabled: false
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php
index 70e0132926b28..7caaa77bf6f49 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php
@@ -1501,6 +1501,12 @@ public function testSerializerEnabled()
$this->assertEquals($container->getDefinition('serializer.normalizer.object')->getArgument(6)['max_depth_handler'], new Reference('my.max.depth.handler'));
}
+ public function testSerializerWithoutTranslator()
+ {
+ $container = $this->createContainerFromFile('serializer_without_translator');
+ $this->assertFalse($container->hasDefinition('serializer.normalizer.translatable'));
+ }
+
public function testRegisterSerializerExtractor()
{
$container = $this->createContainerFromFile('full');
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 016e41291fdbb..e35d5fa288dd2 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml
@@ -3,6 +3,7 @@ imports:
framework:
http_method_override: false
+ translator: true
serializer:
enabled: true
default_context:
diff --git a/src/Symfony/Component/AssetMapper/ImportMap/ImportMapConfigReader.php b/src/Symfony/Component/AssetMapper/ImportMap/ImportMapConfigReader.php
index cbcd8024e0d34..cbb597856f774 100644
--- a/src/Symfony/Component/AssetMapper/ImportMap/ImportMapConfigReader.php
+++ b/src/Symfony/Component/AssetMapper/ImportMap/ImportMapConfigReader.php
@@ -41,7 +41,7 @@ public function getEntries(): ImportMapEntries
$entries = new ImportMapEntries();
foreach ($importMapConfig ?? [] as $importName => $data) {
- $validKeys = ['path', 'version', 'type', 'entrypoint', 'url', 'package_specifier'];
+ $validKeys = ['path', 'version', 'type', 'entrypoint', 'url', 'package_specifier', 'downloaded_to', 'preload'];
if ($invalidKeys = array_diff(array_keys($data), $validKeys)) {
throw new \InvalidArgumentException(sprintf('The following keys are not valid for the importmap entry "%s": "%s". Valid keys are: "%s".', $importName, implode('", "', $invalidKeys), implode('", "', $validKeys)));
}
@@ -51,6 +51,20 @@ public function getEntries(): ImportMapEntries
trigger_deprecation('symfony/asset-mapper', '6.4', 'The "url" option is deprecated, use "version" instead.');
}
+ // should solve itself when the config is written again
+ if (isset($data['downloaded_to'])) {
+ trigger_deprecation('symfony/asset-mapper', '6.4', 'The "downloaded_to" option is deprecated and will be removed.');
+ // remove deprecated downloaded_to
+ unset($data['downloaded_to']);
+ }
+
+ // should solve itself when the config is written again
+ if (isset($data['preload'])) {
+ trigger_deprecation('symfony/asset-mapper', '6.4', 'The "preload" option is deprecated, preloading is automatically done.');
+ // remove deprecated preload
+ unset($data['preload']);
+ }
+
$type = isset($data['type']) ? ImportMapType::tryFrom($data['type']) : ImportMapType::JS;
$isEntrypoint = $data['entrypoint'] ?? false;
diff --git a/src/Symfony/Component/Console/README.md b/src/Symfony/Component/Console/README.md
index 92f70e714c550..e9013182a373e 100644
--- a/src/Symfony/Component/Console/README.md
+++ b/src/Symfony/Component/Console/README.md
@@ -7,7 +7,14 @@ interfaces.
Sponsor
-------
-Help Symfony by [sponsoring][1] its development!
+The Console component for Symfony 6.4 is [backed][1] by [Les-Tilleuls.coop][2].
+
+Les-Tilleuls.coop is a team of 70+ Symfony experts who can help you design, develop and
+fix your projects. They provide a wide range of professional services including development,
+consulting, coaching, training and audits. They also are highly skilled in JS, Go and DevOps.
+They are a worker cooperative!
+
+Help Symfony by [sponsoring][3] its development!
Resources
---------
@@ -24,4 +31,6 @@ Credits
`Resources/bin/hiddeninput.exe` is a third party binary provided within this
component. Find sources and license at https://github.com/Seldaek/hidden-input.
-[1]: https://symfony.com/sponsor
+[1]: https://symfony.com/backers
+[2]: https://les-tilleuls.coop
+[3]: https://symfony.com/sponsor
diff --git a/src/Symfony/Component/DependencyInjection/Attribute/Target.php b/src/Symfony/Component/DependencyInjection/Attribute/Target.php
index c3f22127bc847..6fbb3ad42b6a4 100644
--- a/src/Symfony/Component/DependencyInjection/Attribute/Target.php
+++ b/src/Symfony/Component/DependencyInjection/Attribute/Target.php
@@ -36,10 +36,12 @@ public function getParsedName(): string
return lcfirst(str_replace(' ', '', ucwords(preg_replace('/[^a-zA-Z0-9\x7f-\xff]++/', ' ', $this->name))));
}
- public static function parseName(\ReflectionParameter $parameter, self &$attribute = null): string
+ public static function parseName(\ReflectionParameter $parameter, self &$attribute = null, string &$parsedName = null): string
{
$attribute = null;
if (!$target = $parameter->getAttributes(self::class)[0] ?? null) {
+ $parsedName = (new self($parameter->name))->getParsedName();
+
return $parameter->name;
}
@@ -57,6 +59,6 @@ public static function parseName(\ReflectionParameter $parameter, self &$attribu
throw new InvalidArgumentException(sprintf('Invalid #[Target] name "%s" on parameter "$%s" of "%s()": the first character must be a letter.', $name, $parameter->name, $function));
}
- return $parsedName;
+ return preg_match('/^[a-zA-Z0-9_\x7f-\xff]++$/', $name) ? $name : $parsedName;
}
}
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
index ee3ba948b5126..9786ec4de2082 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
@@ -454,20 +454,30 @@ private function getAutowiredReference(TypedReference $reference, bool $filterTy
$name = $target = (array_filter($reference->getAttributes(), static fn ($a) => $a instanceof Target)[0] ?? null)?->name;
if (null !== $name ??= $reference->getName()) {
+ if ($this->container->has($alias = $type.' $'.$name) && !$this->container->findDefinition($alias)->isAbstract()) {
+ return new TypedReference($alias, $type, $reference->getInvalidBehavior());
+ }
+
+ if (null !== ($alias = $this->getCombinedAlias($type, $name)) && !$this->container->findDefinition($alias)->isAbstract()) {
+ return new TypedReference($alias, $type, $reference->getInvalidBehavior());
+ }
+
$parsedName = (new Target($name))->getParsedName();
if ($this->container->has($alias = $type.' $'.$parsedName) && !$this->container->findDefinition($alias)->isAbstract()) {
return new TypedReference($alias, $type, $reference->getInvalidBehavior());
}
- if (null !== ($alias = $this->getCombinedAlias($type, $parsedName) ?? null) && !$this->container->findDefinition($alias)->isAbstract()) {
+ if (null !== ($alias = $this->getCombinedAlias($type, $parsedName)) && !$this->container->findDefinition($alias)->isAbstract()) {
return new TypedReference($alias, $type, $reference->getInvalidBehavior());
}
- if ($this->container->has($name) && !$this->container->findDefinition($name)->isAbstract()) {
+ if (($this->container->has($n = $name) && !$this->container->findDefinition($n)->isAbstract())
+ || ($this->container->has($n = $parsedName) && !$this->container->findDefinition($n)->isAbstract())
+ ) {
foreach ($this->container->getAliases() as $id => $alias) {
- if ($name === (string) $alias && str_starts_with($id, $type.' $')) {
- return new TypedReference($name, $type, $reference->getInvalidBehavior());
+ if ($n === (string) $alias && str_starts_with($id, $type.' $')) {
+ return new TypedReference($n, $type, $reference->getInvalidBehavior());
}
}
}
@@ -481,7 +491,7 @@ private function getAutowiredReference(TypedReference $reference, bool $filterTy
return new TypedReference($type, $type, $reference->getInvalidBehavior());
}
- if (null !== ($alias = $this->getCombinedAlias($type) ?? null) && !$this->container->findDefinition($alias)->isAbstract()) {
+ if (null !== ($alias = $this->getCombinedAlias($type)) && !$this->container->findDefinition($alias)->isAbstract()) {
return new TypedReference($alias, $type, $reference->getInvalidBehavior());
}
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php
index 68835d52aaec9..2fa7db848c599 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php
@@ -190,16 +190,19 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
$typeHint = ltrim(ProxyHelper::exportType($parameter) ?? '', '?');
- $name = Target::parseName($parameter);
+ $name = Target::parseName($parameter, parsedName: $parsedName);
- if ($typeHint && \array_key_exists($k = preg_replace('/(^|[(|&])\\\\/', '\1', $typeHint).' $'.$name, $bindings)) {
+ if ($typeHint && (
+ \array_key_exists($k = preg_replace('/(^|[(|&])\\\\/', '\1', $typeHint).' $'.$name, $bindings)
+ || \array_key_exists($k = preg_replace('/(^|[(|&])\\\\/', '\1', $typeHint).' $'.$parsedName, $bindings)
+ )) {
$arguments[$key] = $this->getBindingValue($bindings[$k]);
continue;
}
- if (\array_key_exists('$'.$name, $bindings)) {
- $arguments[$key] = $this->getBindingValue($bindings['$'.$name]);
+ if (\array_key_exists($k = '$'.$name, $bindings) || \array_key_exists($k = '$'.$parsedName, $bindings)) {
+ $arguments[$key] = $this->getBindingValue($bindings[$k]);
continue;
}
@@ -210,7 +213,7 @@ protected function processValue(mixed $value, bool $isRoot = false): mixed
continue;
}
- if (isset($bindingNames[$name]) || isset($bindingNames[$parameter->name])) {
+ if (isset($bindingNames[$name]) || isset($bindingNames[$parsedName]) || isset($bindingNames[$parameter->name])) {
$bindingKey = array_search($binding, $bindings, true);
$argumentType = substr($bindingKey, 0, strpos($bindingKey, ' '));
$this->errorMessages[] = sprintf('Did you forget to add the type "%s" to argument "$%s" of method "%s::%s()"?', $argumentType, $parameter->name, $reflectionMethod->class, $reflectionMethod->name);
diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
index ff11062b99b9a..65985fd9c404c 100644
--- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
+++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
@@ -258,6 +258,7 @@ public function dump(array $options = []): string|array
docStar}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php
index fc8cba8e83cb6..3588a5b2a594a 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php
@@ -1301,6 +1301,18 @@ public function testAutowireWithNamedArgs()
$this->assertEquals([new TypedReference(A::class, A::class), 'abc'], $container->getDefinition('foo')->getArguments());
}
+ public function testAutowireUnderscoreNamedArgument()
+ {
+ $container = new ContainerBuilder();
+
+ $container->autowire(\DateTimeImmutable::class.' $now_datetime', \DateTimeImmutable::class);
+ $container->autowire('foo', UnderscoreNamedArgument::class)->setPublic(true);
+
+ (new AutowirePass())->process($container);
+
+ $this->assertInstanceOf(\DateTimeImmutable::class, $container->get('foo')->now_datetime);
+ }
+
public function testAutowireDefaultValueParametersLike()
{
$container = new ContainerBuilder();
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterServiceSubscribersPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterServiceSubscribersPassTest.php
index 972f8d8169d15..d9e3e921eab5c 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterServiceSubscribersPassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/RegisterServiceSubscribersPassTest.php
@@ -403,7 +403,7 @@ public static function getSubscribedServices(): array
$expected = [
'some.service' => new ServiceClosureArgument(new TypedReference('stdClass $someService', 'stdClass')),
- 'some_service' => new ServiceClosureArgument(new TypedReference('stdClass $someService', 'stdClass')),
+ 'some_service' => new ServiceClosureArgument(new TypedReference('stdClass $some_service', 'stdClass')),
'another_service' => new ServiceClosureArgument(new TypedReference('stdClass $anotherService', 'stdClass')),
];
$this->assertEquals($expected, $container->getDefinition((string) $locator->getFactory()[0])->getArgument(0));
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php
index d75b20bb77315..a8e71068775b4 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php
@@ -227,6 +227,14 @@ public function __construct(A $a, Lille $lille, $foo = 'some_val')
}
}
+class UnderscoreNamedArgument
+{
+ public function __construct(
+ public \DateTimeImmutable $now_datetime,
+ ) {
+ }
+}
+
/*
* Classes used for testing createResourceForClass
*/
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services10_as_files.txt b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services10_as_files.txt
index beb30fb3d196f..54189a28f4add 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services10_as_files.txt
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services10_as_files.txt
@@ -13,6 +13,7 @@ return [
namespace Container%s;
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
+use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
/**
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt
index 6c04f84c6782d..0cebc1f09445d 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_as_files.txt
@@ -23,6 +23,7 @@ return [
namespace Container%s;
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
+use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
/**
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_deprecated_parameters_as_files.txt b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_deprecated_parameters_as_files.txt
index 55c5776ac6f44..f3442bc370f7d 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_deprecated_parameters_as_files.txt
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_deprecated_parameters_as_files.txt
@@ -5,6 +5,7 @@ Array
namespace Container%s;
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
+use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
/**
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_non_shared_lazy_as_files.txt b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_non_shared_lazy_as_files.txt
index 7c1f4ca682ea2..488895d7c1b6e 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_non_shared_lazy_as_files.txt
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_non_shared_lazy_as_files.txt
@@ -5,6 +5,7 @@ Array
namespace Container%s;
use Symfony\Component\DependencyInjection\Argument\RewindableGenerator;
+use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
/**
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services14.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services14.xml
index bad2ec0ab377c..cc0310ceb2931 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services14.xml
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services14.xml
@@ -3,10 +3,6 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services https://symfony.com/schema/dic/services/services-1.0.xsd">
-
- app
-
-
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php
index 29cacc24223cc..34d4f53b1a1d7 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php
@@ -15,6 +15,7 @@
use Symfony\Component\Form\ChoiceList\View\ChoiceView;
use Symfony\Component\Form\FormError;
use Symfony\Component\Form\FormInterface;
+use Symfony\Component\Intl\Intl;
use Symfony\Component\Intl\Util\IntlTestHelper;
use Symfony\Component\OptionsResolver\Exception\InvalidOptionsException;
@@ -94,6 +95,10 @@ public function testSubmitFromSingleTextDateTime()
// we test against "de_DE", so we need the full implementation
IntlTestHelper::requireFullIntl($this, false);
+ if ('71.1' === Intl::getIcuVersion()) {
+ $this->markTestSkipped('Skipping test due to a bug in ICU 71.1.');
+ }
+
\Locale::setDefault('de_DE');
$form = $this->factory->create(static::TESTED_TYPE, null, [
@@ -116,6 +121,10 @@ public function testSubmitFromSingleTextDateTimeImmutable()
// we test against "de_DE", so we need the full implementation
IntlTestHelper::requireFullIntl($this, false);
+ if ('71.1' === Intl::getIcuVersion()) {
+ $this->markTestSkipped('Skipping test due to a bug in ICU 71.1.');
+ }
+
\Locale::setDefault('de_DE');
$form = $this->factory->create(static::TESTED_TYPE, null, [
@@ -139,6 +148,10 @@ public function testSubmitFromSingleTextString()
// we test against "de_DE", so we need the full implementation
IntlTestHelper::requireFullIntl($this, false);
+ if ('71.1' === Intl::getIcuVersion()) {
+ $this->markTestSkipped('Skipping test due to a bug in ICU 71.1.');
+ }
+
\Locale::setDefault('de_DE');
$form = $this->factory->create(static::TESTED_TYPE, null, [
@@ -161,6 +174,10 @@ public function testSubmitFromSingleTextTimestamp()
// we test against "de_DE", so we need the full implementation
IntlTestHelper::requireFullIntl($this, false);
+ if ('71.1' === Intl::getIcuVersion()) {
+ $this->markTestSkipped('Skipping test due to a bug in ICU 71.1.');
+ }
+
\Locale::setDefault('de_DE');
$form = $this->factory->create(static::TESTED_TYPE, null, [
@@ -185,6 +202,10 @@ public function testSubmitFromSingleTextRaw()
// we test against "de_DE", so we need the full implementation
IntlTestHelper::requireFullIntl($this, false);
+ if ('71.1' === Intl::getIcuVersion()) {
+ $this->markTestSkipped('Skipping test due to a bug in ICU 71.1.');
+ }
+
\Locale::setDefault('de_DE');
$form = $this->factory->create(static::TESTED_TYPE, null, [
diff --git a/src/Symfony/Component/HttpKernel/Debug/FileLinkFormatter.php b/src/Symfony/Component/HttpKernel/Debug/FileLinkFormatter.php
index 23ced22fc9486..600a460fb6fbb 100644
--- a/src/Symfony/Component/HttpKernel/Debug/FileLinkFormatter.php
+++ b/src/Symfony/Component/HttpKernel/Debug/FileLinkFormatter.php
@@ -25,7 +25,7 @@ class_alias(ErrorHandlerFileLinkFormatter::class, FileLinkFormatter::class);
/**
* @deprecated since Symfony 6.4, use FileLinkFormatter from the ErrorHandler component instead
*/
- class FileLinkFormatter
+ class FileLinkFormatter extends ErrorHandlerFileLinkFormatter
{
}
}
diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php
index d43c6a3aef11f..f2cf2422b0689 100644
--- a/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php
+++ b/src/Symfony/Component/HttpKernel/DependencyInjection/RegisterControllerArgumentLocatorsPass.php
@@ -128,6 +128,8 @@ public function process(ContainerBuilder $container)
$type = preg_replace('/(^|[(|&])\\\\/', '\1', $target = ltrim(ProxyHelper::exportType($p) ?? '', '?'));
$invalidBehavior = ContainerInterface::IGNORE_ON_INVALID_REFERENCE;
$autowireAttributes = $autowire ? $emptyAutowireAttributes : [];
+ $parsedName = $p->name;
+ $k = null;
if (isset($arguments[$r->name][$p->name])) {
$target = $arguments[$r->name][$p->name];
@@ -138,7 +140,11 @@ public function process(ContainerBuilder $container)
} elseif ($p->allowsNull() && !$p->isOptional()) {
$invalidBehavior = ContainerInterface::NULL_ON_INVALID_REFERENCE;
}
- } elseif (isset($bindings[$bindingName = $type.' $'.$name = Target::parseName($p)]) || isset($bindings[$bindingName = '$'.$name]) || isset($bindings[$bindingName = $type])) {
+ } elseif (isset($bindings[$bindingName = $type.' $'.$name = Target::parseName($p, $k, $parsedName)])
+ || isset($bindings[$bindingName = $type.' $'.$parsedName])
+ || isset($bindings[$bindingName = '$'.$name])
+ || isset($bindings[$bindingName = $type])
+ ) {
$binding = $bindings[$bindingName];
[$bindingValue, $bindingId, , $bindingType, $bindingFile] = $binding->getValues();
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index 39170e8333e20..4258dec601a47 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.0';
- public const VERSION_ID = 60400;
+ public const VERSION = '6.4.1';
+ public const VERSION_ID = 60401;
public const MAJOR_VERSION = 6;
public const MINOR_VERSION = 4;
- public const RELEASE_VERSION = 0;
+ public const RELEASE_VERSION = 1;
public const EXTRA_VERSION = '';
public const END_OF_MAINTENANCE = '11/2026';
diff --git a/src/Symfony/Component/HttpKernel/UriSigner.php b/src/Symfony/Component/HttpKernel/UriSigner.php
index 877d832e9dae2..fb5383cdec2f3 100644
--- a/src/Symfony/Component/HttpKernel/UriSigner.php
+++ b/src/Symfony/Component/HttpKernel/UriSigner.php
@@ -21,7 +21,7 @@ class_exists(HttpFoundationUriSigner::class);
/**
* @deprecated since Symfony 6.4, to be removed in 7.0, use {@link HttpFoundationUriSigner} instead
*/
- class UriSigner
+ class UriSigner extends HttpFoundationUriSigner
{
}
}
diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php
index 3fd296472307b..2c787e9cca0c3 100644
--- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php
+++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php
@@ -184,7 +184,7 @@ public function get(): ?array
if ($this->driverConnection->getDatabasePlatform() instanceof OraclePlatform) {
$query = $this->createQueryBuilder('w')
->where('w.id IN ('.str_replace('SELECT a.* FROM', 'SELECT a.id FROM', $sql).')')
- ->setParameters($query->getParameters());
+ ->setParameters($query->getParameters(), $query->getParameterTypes());
if (method_exists(QueryBuilder::class, 'forUpdate')) {
$query->forUpdate();
diff --git a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php
index fa04a0ca4bb86..b2c52ce9e0626 100644
--- a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php
+++ b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php
@@ -19,7 +19,7 @@ class_exists(AttributeClassLoader::class);
/**
* @deprecated since Symfony 6.4, to be removed in 7.0, use {@link AttributeClassLoader} instead
*/
- class AnnotationClassLoader
+ abstract class AnnotationClassLoader extends AttributeClassLoader
{
}
}
diff --git a/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php
index 80cec1f5ddf7e..169b1e60ac740 100644
--- a/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php
+++ b/src/Symfony/Component/Routing/Loader/AnnotationDirectoryLoader.php
@@ -19,7 +19,7 @@ class_exists(AttributeDirectoryLoader::class);
/**
* @deprecated since Symfony 6.4, to be removed in 7.0, use {@link AttributeDirectoryLoader} instead
*/
- class AnnotationDirectoryLoader
+ class AnnotationDirectoryLoader extends AttributeDirectoryLoader
{
}
}
diff --git a/src/Symfony/Component/Routing/Loader/AnnotationFileLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationFileLoader.php
index 296f312d6848a..60487bb27812b 100644
--- a/src/Symfony/Component/Routing/Loader/AnnotationFileLoader.php
+++ b/src/Symfony/Component/Routing/Loader/AnnotationFileLoader.php
@@ -19,7 +19,7 @@ class_exists(AttributeFileLoader::class);
/**
* @deprecated since Symfony 6.4, to be removed in 7.0, use {@link AttributeFileLoader} instead
*/
- class AnnotationFileLoader
+ class AnnotationFileLoader extends AttributeFileLoader
{
}
}
diff --git a/src/Symfony/Component/Routing/Loader/AttributeClassLoader.php b/src/Symfony/Component/Routing/Loader/AttributeClassLoader.php
index cd12b87155a40..679b0c84557bb 100644
--- a/src/Symfony/Component/Routing/Loader/AttributeClassLoader.php
+++ b/src/Symfony/Component/Routing/Loader/AttributeClassLoader.php
@@ -144,7 +144,9 @@ public function load(mixed $class, string $type = null): RouteCollection
if (1 === $collection->count() - \count($routeNamesBefore)) {
$newRouteName = current(array_diff(array_keys($collection->all()), $routeNamesBefore));
- $collection->addAlias(sprintf('%s::%s', $class->name, $method->name), $newRouteName);
+ if ($newRouteName !== $aliasName = sprintf('%s::%s', $class->name, $method->name)) {
+ $collection->addAlias($aliasName, $newRouteName);
+ }
}
}
if (0 === $collection->count() && $class->hasMethod('__invoke')) {
@@ -155,8 +157,14 @@ public function load(mixed $class, string $type = null): RouteCollection
}
}
if ($fqcnAlias && 1 === $collection->count()) {
- $collection->addAlias($class->name, $invokeRouteName = key($collection->all()));
- $collection->addAlias(sprintf('%s::__invoke', $class->name), $invokeRouteName);
+ $invokeRouteName = key($collection->all());
+ if ($invokeRouteName !== $class->name) {
+ $collection->addAlias($class->name, $invokeRouteName);
+ }
+
+ if ($invokeRouteName !== $aliasName = sprintf('%s::__invoke', $class->name)) {
+ $collection->addAlias($aliasName, $invokeRouteName);
+ }
}
if ($this->hasDeprecatedAnnotations) {
diff --git a/src/Symfony/Component/Routing/RouteCollection.php b/src/Symfony/Component/Routing/RouteCollection.php
index 0175e3abfeb19..0a04387ce34df 100644
--- a/src/Symfony/Component/Routing/RouteCollection.php
+++ b/src/Symfony/Component/Routing/RouteCollection.php
@@ -147,9 +147,24 @@ public function get(string $name): ?Route
*/
public function remove(string|array $name)
{
+ $routes = [];
foreach ((array) $name as $n) {
+ if (isset($this->routes[$n])) {
+ $routes[] = $n;
+ }
+
unset($this->routes[$n], $this->priorities[$n], $this->aliases[$n]);
}
+
+ if (!$routes) {
+ return;
+ }
+
+ foreach ($this->aliases as $k => $alias) {
+ if (\in_array($alias->getId(), $routes, true)) {
+ unset($this->aliases[$k]);
+ }
+ }
}
/**
diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/AnnotationFixtures/InvokableFQCNAliasConflictController.php b/src/Symfony/Component/Routing/Tests/Fixtures/AnnotationFixtures/InvokableFQCNAliasConflictController.php
new file mode 100644
index 0000000000000..1155b87daeaf5
--- /dev/null
+++ b/src/Symfony/Component/Routing/Tests/Fixtures/AnnotationFixtures/InvokableFQCNAliasConflictController.php
@@ -0,0 +1,15 @@
+assertEquals(new Alias('lol'), $routes->getAlias($this->getNamespace().'\InvokableController::__invoke'));
}
+ public function testInvokableFQCNAliasConflictController()
+ {
+ $routes = $this->loader->load($this->getNamespace().'\InvokableFQCNAliasConflictController');
+ $this->assertCount(1, $routes);
+ $this->assertEquals('/foobarccc', $routes->get($this->getNamespace().'\InvokableFQCNAliasConflictController')->getPath());
+ $this->assertNull($routes->getAlias($this->getNamespace().'\InvokableFQCNAliasConflictController'));
+ $this->assertEquals(new Alias($this->getNamespace().'\InvokableFQCNAliasConflictController'), $routes->getAlias($this->getNamespace().'\InvokableFQCNAliasConflictController::__invoke'));
+ }
+
public function testInvokableMethodControllerLoader()
{
$routes = $this->loader->load($this->getNamespace().'\InvokableMethodController');
diff --git a/src/Symfony/Component/Routing/Tests/RouteCollectionTest.php b/src/Symfony/Component/Routing/Tests/RouteCollectionTest.php
index a191c88a61849..7625bcf54ebdb 100644
--- a/src/Symfony/Component/Routing/Tests/RouteCollectionTest.php
+++ b/src/Symfony/Component/Routing/Tests/RouteCollectionTest.php
@@ -219,17 +219,22 @@ public function testGet()
public function testRemove()
{
$collection = new RouteCollection();
- $collection->add('foo', $foo = new Route('/foo'));
+ $collection->add('foo', new Route('/foo'));
$collection1 = new RouteCollection();
$collection1->add('bar', $bar = new Route('/bar'));
$collection->addCollection($collection1);
$collection->add('last', $last = new Route('/last'));
+ $collection->addAlias('alias_removed_when_removing_route_foo', 'foo');
+ $collection->addAlias('alias_directly_removed', 'bar');
$collection->remove('foo');
$this->assertSame(['bar' => $bar, 'last' => $last], $collection->all(), '->remove() can remove a single route');
+ $collection->remove('alias_directly_removed');
+ $this->assertNull($collection->getAlias('alias_directly_removed'));
$collection->remove(['bar', 'last']);
$this->assertSame([], $collection->all(), '->remove() accepts an array and can remove multiple routes at once');
+ $this->assertNull($collection->getAlias('alias_removed_when_removing_route_foo'));
}
public function testSetHost()
diff --git a/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php b/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php
index f5c8f9ccc12bc..5ffbb3406bc74 100644
--- a/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php
+++ b/src/Symfony/Component/Serializer/Mapping/Loader/AnnotationLoader.php
@@ -19,7 +19,7 @@ class_exists(AttributeLoader::class);
/**
* @deprecated since Symfony 6.4, to be removed in 7.0, use {@link AttributeLoader} instead
*/
- class AnnotationLoader
+ class AnnotationLoader extends AttributeLoader
{
}
}
diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
index c6f279dcfdda5..a6dbf3dc9df44 100644
--- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
+++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
@@ -547,7 +547,7 @@ private function validateAndDenormalize(array $types, string $currentClass, stri
$expectedTypes[Type::BUILTIN_TYPE_OBJECT === $builtinType && $class ? $class : $builtinType] = true;
- if (Type::BUILTIN_TYPE_OBJECT === $builtinType) {
+ if (Type::BUILTIN_TYPE_OBJECT === $builtinType && null !== $class) {
if (!$this->serializer instanceof DenormalizerInterface) {
throw new LogicException(sprintf('Cannot denormalize attribute "%s" for class "%s" because injected serializer is not a denormalizer.', $attribute, $class));
}
diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php
index 2c274c20d681a..13a34fa233457 100644
--- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php
+++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php
@@ -121,6 +121,17 @@ public function testDenormalizeWithExtraAttributesAndNoGroupsWithMetadataFactory
);
}
+ public function testDenormalizePlainObject()
+ {
+ $extractor = new PhpDocExtractor();
+ $normalizer = new ObjectNormalizer(null, null, null, $extractor);
+ $dummy = $normalizer->denormalize(['plainObject' => (object) ['foo' => 'bar']], DummyWithPlainObject::class);
+
+ $this->assertInstanceOf(DummyWithPlainObject::class, $dummy);
+ $this->assertInstanceOf(\stdClass::class, $dummy->plainObject);
+ $this->assertSame('bar', $dummy->plainObject->foo);
+ }
+
public function testDenormalizeWithDuplicateNestedAttributes()
{
$this->expectException(LogicException::class);
@@ -1104,6 +1115,12 @@ protected function setAttributeValue(object $object, string $attribute, $value,
}
}
+class DummyWithPlainObject
+{
+ /** @var object */
+ public $plainObject;
+}
+
class ObjectWithBasicProperties
{
/** @var bool */
diff --git a/src/Symfony/Component/VarExporter/LazyGhostTrait.php b/src/Symfony/Component/VarExporter/LazyGhostTrait.php
index a25fc21a85bb2..26f7bc2cd4759 100644
--- a/src/Symfony/Component/VarExporter/LazyGhostTrait.php
+++ b/src/Symfony/Component/VarExporter/LazyGhostTrait.php
@@ -166,8 +166,9 @@ public function &__get($name): mixed
if ($state && (null === $scope || isset($propertyScopes["\0$scope\0$name"]))) {
if (LazyObjectState::STATUS_INITIALIZED_FULL === $state->status) {
// Work around php/php-src#12695
- $property = $propertyScopes[null === $scope ? $name : "\0$scope\0$name"][3]
- ?? (Hydrator::$propertyScopes[$this::class] = Hydrator::getPropertyScopes($this::class))[3];
+ $property = null === $scope ? $name : "\0$scope\0$name";
+ $property = $propertyScopes[$property][3]
+ ?? Hydrator::$propertyScopes[$this::class][$property][3] = new \ReflectionProperty($scope ?? $class, $name);
} else {
$property = null;
}
diff --git a/src/Symfony/Component/VarExporter/Tests/Fixtures/LazyGhost/ChildMagicClass.php b/src/Symfony/Component/VarExporter/Tests/Fixtures/LazyGhost/ChildMagicClass.php
index 6cac9ffc03d01..ca6b235eba66d 100644
--- a/src/Symfony/Component/VarExporter/Tests/Fixtures/LazyGhost/ChildMagicClass.php
+++ b/src/Symfony/Component/VarExporter/Tests/Fixtures/LazyGhost/ChildMagicClass.php
@@ -18,5 +18,14 @@ class ChildMagicClass extends MagicClass implements LazyObjectInterface
{
use LazyGhostTrait;
+ private const LAZY_OBJECT_PROPERTY_SCOPES = [
+ "\0".self::class."\0".'data' => [self::class, 'data', null],
+ "\0".self::class."\0".'lazyObjectState' => [self::class, 'lazyObjectState', null],
+ "\0".parent::class."\0".'data' => [parent::class, 'data', null],
+ 'cloneCounter' => [self::class, 'cloneCounter', null],
+ 'data' => [self::class, 'data', null],
+ 'lazyObjectState' => [self::class, 'lazyObjectState', null],
+ ];
+
private int $data = 123;
}
diff --git a/src/Symfony/Component/Workflow/Debug/TraceableWorkflow.php b/src/Symfony/Component/Workflow/Debug/TraceableWorkflow.php
index b8ac0867d4194..6d0afd80cf620 100644
--- a/src/Symfony/Component/Workflow/Debug/TraceableWorkflow.php
+++ b/src/Symfony/Component/Workflow/Debug/TraceableWorkflow.php
@@ -16,6 +16,7 @@
use Symfony\Component\Workflow\Marking;
use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface;
use Symfony\Component\Workflow\Metadata\MetadataStoreInterface;
+use Symfony\Component\Workflow\Transition;
use Symfony\Component\Workflow\TransitionBlockerList;
use Symfony\Component\Workflow\WorkflowInterface;
@@ -57,6 +58,11 @@ public function getEnabledTransitions(object $subject): array
return $this->callInner(__FUNCTION__, \func_get_args());
}
+ public function getEnabledTransition(object $subject, string $name): ?Transition
+ {
+ return $this->callInner(__FUNCTION__, \func_get_args());
+ }
+
public function getName(): string
{
return $this->workflow->getName();
diff --git a/src/Symfony/Component/Workflow/Tests/Debug/TraceableWorkflowTest.php b/src/Symfony/Component/Workflow/Tests/Debug/TraceableWorkflowTest.php
new file mode 100644
index 0000000000000..5bfcee9b9f25e
--- /dev/null
+++ b/src/Symfony/Component/Workflow/Tests/Debug/TraceableWorkflowTest.php
@@ -0,0 +1,100 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Workflow\Tests\Debug;
+
+use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\TestCase;
+use Symfony\Component\Stopwatch\Stopwatch;
+use Symfony\Component\Workflow\Debug\TraceableWorkflow;
+use Symfony\Component\Workflow\Marking;
+use Symfony\Component\Workflow\TransitionBlockerList;
+use Symfony\Component\Workflow\Workflow;
+
+class TraceableWorkflowTest extends TestCase
+{
+ private MockObject|Workflow $innerWorkflow;
+
+ private StopWatch $stopwatch;
+
+ private TraceableWorkflow $traceableWorkflow;
+
+ protected function setUp(): void
+ {
+ $this->innerWorkflow = $this->createMock(Workflow::class);
+ $this->stopwatch = new Stopwatch();
+
+ $this->traceableWorkflow = new TraceableWorkflow(
+ $this->innerWorkflow,
+ $this->stopwatch
+ );
+ }
+
+ /**
+ * @dataProvider provideFunctionNames
+ */
+ public function testCallsInner(string $function, array $args, mixed $returnValue)
+ {
+ $this->innerWorkflow->expects($this->once())
+ ->method($function)
+ ->willReturn($returnValue);
+
+ $this->assertSame($returnValue, $this->traceableWorkflow->{$function}(...$args));
+
+ $calls = $this->traceableWorkflow->getCalls();
+
+ $this->assertCount(1, $calls);
+ $this->assertSame($function, $calls[0]['method']);
+ $this->assertArrayHasKey('duration', $calls[0]);
+ $this->assertSame($returnValue, $calls[0]['return']);
+ }
+
+ public function testCallsInnerCatchesException()
+ {
+ $exception = new \Exception('foo');
+ $this->innerWorkflow->expects($this->once())
+ ->method('can')
+ ->willThrowException($exception);
+
+ try {
+ $this->traceableWorkflow->can(new \stdClass(), 'foo');
+
+ $this->fail('An exception should have been thrown.');
+ } catch (\Exception $e) {
+ $this->assertSame($exception, $e);
+
+ $calls = $this->traceableWorkflow->getCalls();
+
+ $this->assertCount(1, $calls);
+ $this->assertSame('can', $calls[0]['method']);
+ $this->assertArrayHasKey('duration', $calls[0]);
+ $this->assertArrayHasKey('exception', $calls[0]);
+ $this->assertSame($exception, $calls[0]['exception']);
+ }
+ }
+
+ public static function provideFunctionNames(): \Generator
+ {
+ $subject = new \stdClass();
+
+ yield ['getMarking', [$subject], new Marking(['place' => 1])];
+
+ yield ['can', [$subject, 'foo'], true];
+
+ yield ['buildTransitionBlockerList', [$subject, 'foo'], new TransitionBlockerList()];
+
+ yield ['apply', [$subject, 'foo'], new Marking(['place' => 1])];
+
+ yield ['getEnabledTransitions', [$subject], []];
+
+ yield ['getEnabledTransition', [$subject, 'foo'], null];
+ }
+}
diff --git a/src/Symfony/Component/Workflow/composer.json b/src/Symfony/Component/Workflow/composer.json
index 689219800eea1..2c277fcc090e5 100644
--- a/src/Symfony/Component/Workflow/composer.json
+++ b/src/Symfony/Component/Workflow/composer.json
@@ -31,6 +31,7 @@
"symfony/expression-language": "^5.4|^6.0|^7.0",
"symfony/http-kernel": "^6.4|^7.0",
"symfony/security-core": "^5.4|^6.0|^7.0",
+ "symfony/stopwatch": "^5.4|^6.0|^7.0",
"symfony/validator": "^5.4|^6.0|^7.0"
},
"conflict": {