diff --git a/CHANGELOG-6.4.md b/CHANGELOG-6.4.md
index 0640c9486abb1..dc52e3c7b4c0d 100644
--- a/CHANGELOG-6.4.md
+++ b/CHANGELOG-6.4.md
@@ -7,6 +7,23 @@ 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.20 (2025-03-28)
+
+ * bug #60054 [Form] Use duplicate_preferred_choices to set value of ChoiceType (aleho)
+ * bug #59858 Update `JsDelivrEsmResolver::IMPORT_REGEX` to support dynamic imports (natepage)
+ * bug #60019 [HttpKernel] Fix `TraceableEventDispatcher` when the `Stopwatch` service has been reset (lyrixx)
+ * bug #59975 [HttpKernel] Only remove `E_WARNING` from error level during kernel init (fritzmg)
+ * bug #59988 [FrameworkBundle] Remove redundant `name` attribute from `default_context` (HypeMC)
+ * bug #59949 [Process] Use a pipe for stderr in pty mode to avoid mixed output between stdout and stderr (joelwurtz)
+ * bug #59940 [Cache] Fix missing cache data in profiler (dcmbrs)
+ * bug #59965 [VarExporter] Fix support for hooks and asymmetric visibility (nicolas-grekas)
+ * bug #59874 [Console] fix progress bar messing output in section when there is an EOL (joelwurtz)
+ * bug #59888 [PhpUnitBridge] don't trigger "internal" deprecations for PHPUnit Stub objects (xabbuh)
+ * bug #59830 [Yaml] drop comments while lexing unquoted strings (xabbuh)
+ * bug #59884 [VarExporter] Fix support for asymmetric visibility (nicolas-grekas)
+ * bug #59881 [VarExporter] Fix support for abstract properties (nicolas-grekas)
+ * bug #59841 [Cache] fix cache data collector on late collect (dcmbrs)
+
* 6.4.19 (2025-02-26)
* bug #59198 [Messenger] Filter out non-consumable receivers when registering `ConsumeMessagesCommand` (wazum)
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index f8902ba18f029..ffc3b6feae6fd 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -50,8 +50,8 @@ The Symfony Connect username in parenthesis allows to get more information
- Benjamin Eberlei (beberlei)
- Igor Wiedler
- Jan Schädlich (jschaedl)
- - Mathieu Lechat (mat_the_cat)
- Mathias Arlaud (mtarld)
+ - Mathieu Lechat (mat_the_cat)
- Simon André (simonandre)
- Vincent Langlet (deviling)
- Matthias Pigulla (mpdude)
@@ -65,6 +65,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Dany Maillard (maidmaid)
- Eriksen Costa
- Diego Saint Esteben (dosten)
+ - Dariusz Ruminski
- stealth35 (stealth35)
- Alexander Mols (asm89)
- Gábor Egyed (1ed)
@@ -73,7 +74,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Titouan Galopin (tgalopin)
- Pierre du Plessis (pierredup)
- David Maicher (dmaicher)
- - Dariusz Ruminski
- Tomasz Kowalczyk (thunderer)
- Bulat Shakirzyanov (avalanche123)
- Iltar van der Berg
@@ -97,11 +97,11 @@ The Symfony Connect username in parenthesis allows to get more information
- David Buchmann (dbu)
- Ruud Kamphuis (ruudk)
- Andrej Hudec (pulzarraider)
- - Jáchym Toušek (enumag)
- Tomas Norkūnas (norkunas)
+ - Jáchym Toušek (enumag)
+ - Hubert Lenoir (hubert_lenoir)
- Christian Raue
- Eric Clemmons (ericclemmons)
- - Hubert Lenoir (hubert_lenoir)
- Denis (yethee)
- Alex Pott
- Michel Weimerskirch (mweimerskirch)
@@ -117,10 +117,11 @@ The Symfony Connect username in parenthesis allows to get more information
- Antoine Makdessi (amakdessi)
- Ener-Getick
- Graham Campbell (graham)
+ - Massimiliano Arione (garak)
+ - Joel Wurtz (brouznouf)
- Tugdual Saunier (tucksaun)
- Lee McDermott
- Brandon Turner
- - Massimiliano Arione (garak)
- Luis Cordova (cordoval)
- Phil E. Taylor (philetaylor)
- Konstantin Myakshin (koc)
@@ -131,11 +132,10 @@ The Symfony Connect username in parenthesis allows to get more information
- Vasilij Dusko | CREATION
- Jordan Alliot (jalliot)
- Théo FIDRY
- - Joel Wurtz (brouznouf)
- John Wards (johnwards)
+ - Valtteri R (valtzu)
- Yanick Witschi (toflar)
- Antoine Hérault (herzult)
- - Valtteri R (valtzu)
- Konstantin.Myakshin
- Jeroen Spee (jeroens)
- Arnaud Le Blanc (arnaud-lb)
@@ -165,6 +165,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Przemysław Bogusz (przemyslaw-bogusz)
- Colin Frei
- excelwebzone
+ - Florent Morselli (spomky_)
- Paráda József (paradajozsef)
- Maximilian Beckers (maxbeckers)
- Baptiste Clavié (talus)
@@ -194,7 +195,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Niels Keurentjes (curry684)
- OGAWA Katsuhiro (fivestar)
- Jhonny Lidfors (jhonne)
- - Florent Morselli (spomky_)
+ - soyuka
- Juti Noppornpitak (shiroyuki)
- Gregor Harlan (gharlan)
- Anthony MARTIN
@@ -222,7 +223,6 @@ 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)
- Bob van de Vijver (bobvandevijver)
@@ -236,6 +236,7 @@ The Symfony Connect username in parenthesis allows to get more information
- George Mponos (gmponos)
- Richard Shank (iampersistent)
- Roland Franssen :)
+ - Fritz Michael Gschwantner (fritzmg)
- Romain Monteil (ker0x)
- Sergey (upyx)
- Marco Pivetta (ocramius)
@@ -265,7 +266,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Artur Kotyrba
- Wouter J
- Tyson Andre
- - Fritz Michael Gschwantner (fritzmg)
- GDIBass
- Samuel NELA (snela)
- Baptiste Leduc (korbeil)
@@ -308,11 +308,13 @@ The Symfony Connect username in parenthesis allows to get more information
- Karoly Gossler (connorhu)
- Timo Bakx (timobakx)
- Giorgio Premi
+ - Alan Poulain (alanpoulain)
- Ruben Gonzalez (rubenrua)
- Benjamin Dulau (dbenjamin)
- Markus Fasselt (digilist)
- Denis Brumann (dbrumann)
- mcfedr (mcfedr)
+ - Loick Piera (pyrech)
- Remon van de Kamp
- Mathieu Lemoine (lemoinem)
- Christian Schmidt
@@ -355,11 +357,11 @@ The Symfony Connect username in parenthesis allows to get more information
- fd6130 (fdtvui)
- Antonio J. García Lagar (ajgarlag)
- Priyadi Iman Nurcahyo (priyadi)
- - Alan Poulain (alanpoulain)
- Oleg Andreyev (oleg.andreyev)
- Maciej Malarz (malarzm)
- Marcin Sikoń (marphi)
- Michele Orselli (orso)
+ - Arjen van der Meijden
- Sven Paulus (subsven)
- Peter Kruithof (pkruithof)
- Alex Hofbauer (alexhofbauer)
@@ -372,7 +374,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Jérémie Augustin (jaugustin)
- Edi Modrić (emodric)
- Pascal Montoya
- - Loick Piera (pyrech)
- Julien Brochet
- François Pluchino (francoispluchino)
- Tristan Darricau (tristandsensio)
@@ -406,7 +407,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Iker Ibarguren (ikerib)
- Roman Ring (inori)
- Xavier Montaña Carreras (xmontana)
- - Arjen van der Meijden
- Romaric Drigon (romaricdrigon)
- Sylvain Fabre (sylfabre)
- Xavier Perez
@@ -480,6 +480,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Michael Hirschler (mvhirsch)
- Michael Holm (hollo)
- Robert Meijers
+ - roman joly (eltharin)
- Blanchon Vincent (blanchonvincent)
- Cédric Anne
- Christian Schmidt
@@ -565,6 +566,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Kai Dederichs
- Pavel Kirpitsov (pavel-kirpichyov)
- Artur Eshenbrener
+ - Issam Raouf (iraouf)
- Harm van Tilborg (hvt)
- Thomas Perez (scullwm)
- Gwendolen Lynch
@@ -589,7 +591,6 @@ The Symfony Connect username in parenthesis allows to get more information
- hossein zolfi (ocean)
- Alexander Menshchikov
- Clément Gautier (clementgautier)
- - roman joly (eltharin)
- James Gilliland (neclimdul)
- Sanpi (sanpi)
- Eduardo Gulias (egulias)
@@ -634,6 +635,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Ivan Sarastov (isarastov)
- flack (flack)
- Shein Alexey
+ - Pierre Ambroise (dotordu)
- Joe Lencioni
- Daniel Tschinder
- Diego Agulló (aeoris)
@@ -695,6 +697,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Neil Peyssard (nepey)
- Niklas Fiekas
- Mark Challoner (markchalloner)
+ - Vincent Chalamon
- Andreas Hennings
- Markus Bachmann (baachi)
- Gunnstein Lye (glye)
@@ -702,6 +705,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Yi-Jyun Pan
- Sergey Melesh (sergex)
- Greg Anderson
+ - Arnaud De Abreu (arnaud-deabreu)
- lancergr
- Benjamin Zaslavsky (tiriel)
- Tri Pham (phamuyentri)
@@ -758,6 +762,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Tristan Pouliquen
- Miro Michalicka
- Hans Mackowiak
+ - Dalibor Karlović
- M. Vondano
- Dominik Zogg
- Maximilian Zumbansen
@@ -855,10 +860,10 @@ The Symfony Connect username in parenthesis allows to get more information
- Andrew Udvare (audvare)
- siganushka (siganushka)
- alexpods
+ - Quentin Schuler (sukei)
- Adam Szaraniec
- Dariusz Ruminski
- Bahman Mehrdad (bahman)
- - Pierre Ambroise (dotordu)
- Romain Gautier (mykiwi)
- Link1515
- Matthieu Bontemps
@@ -998,12 +1003,12 @@ The Symfony Connect username in parenthesis allows to get more information
- Alexandre Dupuy (satchette)
- Michel Hunziker
- Malte Blättermann
- - Arnaud De Abreu (arnaud-deabreu)
- Simeon Kolev (simeon_kolev9)
- Joost van Driel (j92)
- Jonas Elfering
- Mihai Stancu
- Nahuel Cuesta (ncuesta)
+ - Santiago San Martin
- Chris Boden (cboden)
- EStyles (insidestyles)
- Christophe Villeger (seragan)
@@ -1017,6 +1022,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Maxime Douailin
- Jean Pasdeloup
- Maxime COLIN (maximecolin)
+ - Loïc Ovigne (oviglo)
- Lorenzo Millucci (lmillucci)
- Javier López (loalf)
- Reinier Kip
@@ -1044,7 +1050,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Rodrigo Aguilera
- Vladimir Varlamov (iamvar)
- Aurimas Niekis (gcds)
- - Vincent Chalamon
- Matthieu Calie (matth--)
- Sem Schidler (xvilo)
- Benjamin Schoch (bschoch)
@@ -1193,7 +1198,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Gert de Pagter
- Julien DIDIER (juliendidier)
- Ворожцов Максим (myks92)
- - Dalibor Karlović
- Randy Geraads
- Kevin van Sonsbeek (kevin_van_sonsbeek)
- Simo Heinonen (simoheinonen)
@@ -1208,6 +1212,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Arun Philip
- Pascal Helfenstein
- Jesper Skytte (greew)
+ - NanoSector
- Petar Obradović
- Baldur Rensch (brensch)
- Carl Casbolt (carlcasbolt)
@@ -1225,7 +1230,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Travis Carden (traviscarden)
- mfettig
- Besnik Br
- - Issam Raouf (iraouf)
- Simon Mönch
- Valmonzo
- Sherin Bloemendaal
@@ -1235,6 +1239,7 @@ The Symfony Connect username in parenthesis allows to get more information
- aegypius
- Ilia (aliance)
- Christian Stoller (naitsirch)
+ - COMBROUSE Dimitri
- Dave Marshall (davedevelopment)
- Jakub Kulhan (jakubkulhan)
- Paweł Niedzielski (steveb)
@@ -1372,7 +1377,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Pierre Vanliefland (pvanliefland)
- Roy Klutman (royklutman)
- Sofiane HADDAG (sofhad)
- - Quentin Schuler (sukei)
- Antoine M
- frost-nzcr4
- Shahriar56
@@ -1530,6 +1534,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Rootie
- Sébastien Santoro (dereckson)
- Daniel Alejandro Castro Arellano (lexcast)
+ - Jiří Bok
- Vincent Chalamon
- Farhad Hedayatifard
- Alan ZARLI
@@ -1602,6 +1607,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Chris Jones (leek)
- neghmurken
- stefan.r
+ - Florian Cellier
- xaav
- Jean-Christophe Cuvelier [Artack]
- Mahmoud Mostafa (mahmoud)
@@ -1717,6 +1723,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Abdiel Carrazana (abdielcs)
- joris
- Vadim Tyukov (vatson)
+ - alanzarli
- Arman
- Gabi Udrescu
- Adamo Crespi (aerendir)
@@ -1740,6 +1747,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Ondřej Frei
- Bruno Rodrigues de Araujo (brunosinister)
- Máximo Cuadros (mcuadros)
+ - Arkalo2
- Jacek Wilczyński (jacekwilczynski)
- Christoph Kappestein
- Camille Baronnet
@@ -1906,6 +1914,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Kamil Musial
- Lucas Bustamante
- Olaf Klischat
+ - Andrii
- orlovv
- Claude Dioudonnat
- Jonathan Hedstrom
@@ -1944,6 +1953,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Bruno MATEU
- Jeremy Bush
- Lucas Bäuerle
+ - Steven RENAUX (steven_renaux)
- Laurens Laman
- Thomason, James
- Dario Savella
@@ -1977,7 +1987,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Oleg Sedinkin (akeylimepie)
- Jérémy Jourdin (jjk801)
- BRAMILLE Sébastien (oktapodia)
- - Loïc Ovigne (oviglo)
- Artem Kolesnikov (tyomo4ka)
- Markkus Millend
- Clément
@@ -2000,6 +2009,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Barthold Bos
- cthulhu
- Andoni Larzabal (andonilarz)
+ - Wolfgang Klinger (wolfgangklingerplan2net)
- Staormin
- Dmitry Derepko
- Rémi Leclerc
@@ -2669,6 +2679,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Juraj Surman
- Martin Eckhardt
- natechicago
+ - DaikiOnodera
- Victor
- Andreas Allacher
- Abdelilah Jabri
@@ -2686,6 +2697,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Anton Sukhachev (mrsuh)
- Pavlo Pelekh (pelekh)
- Stefan Kleff (stefanxl)
+ - RichardGuilland
- Marcel Siegert
- ryunosuke
- Bruno BOUTAREL
@@ -2750,6 +2762,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Paul Seiffert (seiffert)
- Vasily Khayrulin (sirian)
- Stas Soroka (stasyan)
+ - Thomas Dubuffet (thomasdubuffet)
- Stefan Hüsges (tronsha)
- Jake Bishop (yakobeyak)
- Dan Blows
@@ -2850,12 +2863,13 @@ The Symfony Connect username in parenthesis allows to get more information
- Bernhard Rusch
- David Stone
- Vincent Bouzeran
+ - fabi
- Grayson Koonce
- Ruben Jansen
+ - nathanpage
- Wissame MEKHILEF
- Mihai Stancu
- shreypuranik
- - NanoSector
- Thibaut Salanon
- Romain Dorgueil
- Christopher Parotat
@@ -2941,6 +2955,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Yasmany Cubela Medina (bitgandtter)
- Michał Dąbrowski (defrag)
- Aryel Tupinamba (dfkimera)
+ - Elías (eliasfernandez)
- Hans Höchtl (hhoechtl)
- Simone Fumagalli (hpatoio)
- Brian Graham (incognito)
@@ -3182,6 +3197,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Buster Neece
- Albert Prat
- Alessandro Loffredo
+ - Tim Düsterhus
- Ian Phillips
- Carlos Tasada
- Remi Collet
@@ -3273,6 +3289,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Rosio (ben-rosio)
- Simon Paarlberg (blamh)
- Masao Maeda (brtriver)
+ - Alexander Dmitryuk (coden1)
- Valery Maslov (coderberg)
- Damien Harper (damien.harper)
- Darius Leskauskas (darles)
@@ -3648,6 +3665,7 @@ The Symfony Connect username in parenthesis allows to get more information
- jwaguet
- Diego Campoy
- Oncle Tom
+ - Roland Franssen :)
- Sam Anthony
- Christian Stocker
- Oussama Elgoumri
@@ -3674,6 +3692,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Sean Templeton
- Willem Mouwen
- db306
+ - Bohdan Pliachenko
- Dr. Gianluigi "Zane" Zanettini
- Michaël VEROUX
- Julia
@@ -3860,6 +3879,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Dionysis Arvanitis
- Sergey Fedotov
- Konstantin Scheumann
+ - Josef Hlavatý
- Michael
- fh-github@fholzhauer.de
- rogamoore
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php
index efb28dbdff66c..4d2fb4472655b 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php
@@ -16,6 +16,7 @@
use Doctrine\ORM\EntityRepository;
use Doctrine\ORM\Mapping\ClassMetadata;
use Doctrine\ORM\Mapping\ClassMetadataInfo;
+use Doctrine\ORM\Mapping\PropertyAccessors\RawValuePropertyAccessor;
use Doctrine\ORM\Tools\SchemaTool;
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\Persistence\ObjectManager;
@@ -115,11 +116,21 @@ class_exists(ClassMetadataInfo::class) ? ClassMetadataInfo::class : ClassMetadat
->willReturn(true)
;
$refl = $this->createMock(\ReflectionProperty::class);
+ $refl
+ ->method('getName')
+ ->willReturn('name')
+ ;
$refl
->method('getValue')
->willReturn(true)
;
- $classMetadata->reflFields = ['name' => $refl];
+
+ if (property_exists(ClassMetadata::class, 'propertyAccessors')) {
+ $classMetadata->propertyAccessors['name'] = RawValuePropertyAccessor::fromReflectionProperty($refl);
+ } else {
+ $classMetadata->reflFields = ['name' => $refl];
+ }
+
$em->expects($this->any())
->method('getClassMetadata')
->willReturn($classMetadata)
diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php
index b356f8068c15d..8089f820af124 100644
--- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php
+++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php
@@ -11,6 +11,7 @@
namespace Symfony\Bridge\Doctrine\Validator\Constraints;
+use Doctrine\ORM\Mapping\ClassMetadata as OrmClassMetadata;
use Doctrine\Persistence\ManagerRegistry;
use Doctrine\Persistence\Mapping\ClassMetadata;
use Doctrine\Persistence\ObjectManager;
@@ -92,7 +93,11 @@ public function validate(mixed $entity, Constraint $constraint)
throw new ConstraintDefinitionException(sprintf('The field "%s" is not mapped by Doctrine, so it cannot be validated for uniqueness.', $fieldName));
}
- $fieldValue = $class->reflFields[$fieldName]->getValue($entity);
+ if (property_exists(OrmClassMetadata::class, 'propertyAccessors')) {
+ $fieldValue = $class->propertyAccessors[$fieldName]->getValue($entity);
+ } else {
+ $fieldValue = $class->reflFields[$fieldName]->getValue($entity);
+ }
if (null === $fieldValue && $this->ignoreNullForField($constraint, $fieldName)) {
$hasIgnorableNullValue = true;
diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig
index 02628b5a14446..d43b40a0764e2 100644
--- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig
+++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig
@@ -85,7 +85,7 @@
{{- block('choice_widget_options') -}}
{%- else -%}
-
+
{%- endif -%}
{% endfor %}
{%- endblock choice_widget_options -%}
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractDivLayoutTestCase.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractDivLayoutTestCase.php
index a02fca4bc54ca..bfbd458e97b3f 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractDivLayoutTestCase.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractDivLayoutTestCase.php
@@ -856,6 +856,56 @@ public function testMultipleChoiceExpandedWithLabelsSetFalseByCallable()
);
}
+ public function testSingleChoiceWithoutDuplicatePreferredIsSelected()
+ {
+ $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&d', [
+ 'choices' => ['Choice&A' => '&a', 'Choice&B' => '&b', 'Choice&C' => '&c', 'Choice&D' => '&d'],
+ 'preferred_choices' => ['&b', '&d'],
+ 'duplicate_preferred_choices' => false,
+ 'multiple' => false,
+ 'expanded' => false,
+ ]);
+
+ $this->assertWidgetMatchesXpath($form->createView(), ['separator' => '-- sep --'],
+ '/select
+ [@name="name"]
+ [
+ ./option[@value="&d"][@selected="selected"]
+ /following-sibling::option[@disabled="disabled"][.="-- sep --"]
+ /following-sibling::option[@value="&a"][not(@selected)]
+ /following-sibling::option[@value="&c"][not(@selected)]
+ ]
+ [count(./option)=5]
+'
+ );
+ }
+
+ public function testSingleChoiceWithoutDuplicateNotPreferredIsSelected()
+ {
+ $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\ChoiceType', '&d', [
+ 'choices' => ['Choice&A' => '&a', 'Choice&B' => '&b', 'Choice&C' => '&c', 'Choice&D' => '&d'],
+ 'preferred_choices' => ['&b', '&d'],
+ 'duplicate_preferred_choices' => true,
+ 'multiple' => false,
+ 'expanded' => false,
+ ]);
+
+ $this->assertWidgetMatchesXpath($form->createView(), ['separator' => '-- sep --'],
+ '/select
+ [@name="name"]
+ [
+ ./option[@value="&d"][not(@selected)]
+ /following-sibling::option[@disabled="disabled"][.="-- sep --"]
+ /following-sibling::option[@value="&a"][not(@selected)]
+ /following-sibling::option[@value="&b"][not(@selected)]
+ /following-sibling::option[@value="&c"][not(@selected)]
+ /following-sibling::option[@value="&d"][@selected="selected"]
+ ]
+ [count(./option)=7]
+'
+ );
+ }
+
public function testFormEndWithRest()
{
$view = $this->factory->createNamedBuilder('name', 'Symfony\Component\Form\Extension\Core\Type\FormType')
diff --git a/src/Symfony/Bridge/Twig/Tests/NodeVisitor/TwigNodeProvider.php b/src/Symfony/Bridge/Twig/Tests/NodeVisitor/TwigNodeProvider.php
index 69cf6beca0c44..4fc96d8af5fb5 100644
--- a/src/Symfony/Bridge/Twig/Tests/NodeVisitor/TwigNodeProvider.php
+++ b/src/Symfony/Bridge/Twig/Tests/NodeVisitor/TwigNodeProvider.php
@@ -15,6 +15,7 @@
use Symfony\Bridge\Twig\Node\TransNode;
use Twig\Attribute\FirstClassTwigCallableReady;
use Twig\Node\BodyNode;
+use Twig\Node\EmptyNode;
use Twig\Node\Expression\ArrayExpression;
use Twig\Node\Expression\ConstantExpression;
use Twig\Node\Expression\FilterExpression;
@@ -28,13 +29,15 @@ class TwigNodeProvider
{
public static function getModule($content)
{
+ $emptyNodeExists = class_exists(EmptyNode::class);
+
return new ModuleNode(
new BodyNode([new ConstantExpression($content, 0)]),
null,
- new ArrayExpression([], 0),
- new ArrayExpression([], 0),
- new ArrayExpression([], 0),
- null,
+ $emptyNodeExists ? new EmptyNode() : new ArrayExpression([], 0),
+ $emptyNodeExists ? new EmptyNode() : new ArrayExpression([], 0),
+ $emptyNodeExists ? new EmptyNode() : new ArrayExpression([], 0),
+ $emptyNodeExists ? new EmptyNode() : null,
new Source('', '')
);
}
diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json
index 2b7a6a3993357..f663de11da0b9 100644
--- a/src/Symfony/Bridge/Twig/composer.json
+++ b/src/Symfony/Bridge/Twig/composer.json
@@ -29,7 +29,7 @@
"symfony/asset-mapper": "^6.3|^7.0",
"symfony/dependency-injection": "^5.4|^6.0|^7.0",
"symfony/finder": "^5.4|^6.0|^7.0",
- "symfony/form": "^6.4|^7.0",
+ "symfony/form": "^6.4.20|^7.2.5",
"symfony/html-sanitizer": "^6.1|^7.0",
"symfony/http-foundation": "^5.4|^6.0|^7.0",
"symfony/http-kernel": "^6.4|^7.0",
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
index 1939337bb0e24..cb52a0704fd99 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
@@ -1196,7 +1196,6 @@ private function addSerializerSection(ArrayNodeDefinition $rootNode, callable $e
->end()
->arrayNode('default_context')
->normalizeKeys(false)
- ->useAttributeAsKey('name')
->validate()
->ifTrue(fn () => $this->debug && class_exists(JsonParser::class))
->then(fn (array $v) => $v + [JsonDecode::DETAILED_ERROR_MESSAGES => true])
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index 1c57253353630..f585b5bbb784b 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -2004,24 +2004,22 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder
$container->setParameter('serializer.default_context', $defaultContext);
}
- if (!$container->hasDefinition('serializer.normalizer.object')) {
- return;
- }
+ if ($container->hasDefinition('serializer.normalizer.object')) {
+ $arguments = $container->getDefinition('serializer.normalizer.object')->getArguments();
+ $context = $arguments[6] ?? $defaultContext;
- $arguments = $container->getDefinition('serializer.normalizer.object')->getArguments();
- $context = $arguments[6] ?? $defaultContext;
+ if (isset($config['circular_reference_handler']) && $config['circular_reference_handler']) {
+ $context += ['circular_reference_handler' => new Reference($config['circular_reference_handler'])];
+ $container->getDefinition('serializer.normalizer.object')->setArgument(5, null);
+ }
- if (isset($config['circular_reference_handler']) && $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 += ['max_depth_handler' => new Reference($config['max_depth_handler'])];
+ }
- if ($config['max_depth_handler'] ?? false) {
- $context += ['max_depth_handler' => new Reference($config['max_depth_handler'])];
+ $container->getDefinition('serializer.normalizer.object')->setArgument(6, $context);
}
- $container->getDefinition('serializer.normalizer.object')->setArgument(6, $context);
-
$container->getDefinition('serializer.normalizer.property')->setArgument(5, $defaultContext);
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/HttpClientAssertionsTrait.php b/src/Symfony/Bundle/FrameworkBundle/Test/HttpClientAssertionsTrait.php
index 20c64608e9dde..01a27ea87e5ac 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Test/HttpClientAssertionsTrait.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Test/HttpClientAssertionsTrait.php
@@ -14,10 +14,9 @@
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Component\HttpClient\DataCollector\HttpClientDataCollector;
-/*
+/**
* @author Mathieu Santostefano
*/
-
trait HttpClientAssertionsTrait
{
public static function assertHttpClientRequest(string $expectedUrl, string $expectedMethod = 'GET', string|array|null $expectedBody = null, array $expectedHeaders = [], string $httpClientId = 'http_client'): void
diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/NotificationAssertionsTrait.php b/src/Symfony/Bundle/FrameworkBundle/Test/NotificationAssertionsTrait.php
index b68473561eb4d..2c4c5467d4ebd 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Test/NotificationAssertionsTrait.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Test/NotificationAssertionsTrait.php
@@ -17,7 +17,7 @@
use Symfony\Component\Notifier\Message\MessageInterface;
use Symfony\Component\Notifier\Test\Constraint as NotifierConstraint;
-/*
+/**
* @author Smaïne Milianni
*/
trait NotificationAssertionsTrait
diff --git a/src/Symfony/Component/AssetMapper/ImportMap/Resolver/JsDelivrEsmResolver.php b/src/Symfony/Component/AssetMapper/ImportMap/Resolver/JsDelivrEsmResolver.php
index 93338a1b63201..1da5a394b799a 100644
--- a/src/Symfony/Component/AssetMapper/ImportMap/Resolver/JsDelivrEsmResolver.php
+++ b/src/Symfony/Component/AssetMapper/ImportMap/Resolver/JsDelivrEsmResolver.php
@@ -28,7 +28,7 @@ final class JsDelivrEsmResolver implements PackageResolverInterface
public const URL_PATTERN_DIST = self::URL_PATTERN_DIST_CSS.'/+esm';
public const URL_PATTERN_ENTRYPOINT = 'https://data.jsdelivr.com/v1/packages/npm/%s@%s/entrypoints';
- public const IMPORT_REGEX = '#(?:import\s*(?:[\w$]+,)?(?:(?:\{[^}]*\}|[\w$]+|\*\s*as\s+[\w$]+)\s*\bfrom\s*)?|export\s*(?:\{[^}]*\}|\*)\s*from\s*)("/npm/((?:@[^/]+/)?[^@]+?)(?:@([^/]+))?((?:/[^/]+)*?)/\+esm")#';
+ public const IMPORT_REGEX = '#(?:import\s*(?:[\w$]+,)?(?:(?:\{[^}]*\}|[\w$]+|\*\s*as\s+[\w$]+)\s*\bfrom\s*)?|export\s*(?:\{[^}]*\}|\*)\s*from\s*|await\simport\()("/npm/((?:@[^/]+/)?[^@]+?)(?:@([^/]+))?((?:/[^/]+)*?)/\+esm")(?:\)*)#';
private const ES_MODULE_SHIMS = 'es-module-shims';
diff --git a/src/Symfony/Component/AssetMapper/Tests/ImportMap/Resolver/JsDelivrEsmResolverTest.php b/src/Symfony/Component/AssetMapper/Tests/ImportMap/Resolver/JsDelivrEsmResolverTest.php
index 8b7d82c8c6f06..d9650fd7c29d3 100644
--- a/src/Symfony/Component/AssetMapper/Tests/ImportMap/Resolver/JsDelivrEsmResolverTest.php
+++ b/src/Symfony/Component/AssetMapper/Tests/ImportMap/Resolver/JsDelivrEsmResolverTest.php
@@ -693,6 +693,13 @@ public static function provideImportRegex(): iterable
['jquery', '3.7.0'],
],
];
+
+ yield 'dynamic import with path' => [
+ 'return(await import("/npm/@datadog/browser-rum@6.3.0/esm/boot/startRecording.js/+esm")).startRecording',
+ [
+ ['@datadog/browser-rum/esm/boot/startRecording.js', '6.3.0'],
+ ],
+ ];
}
private static function createRemoteEntry(string $importName, string $version, ImportMapType $type = ImportMapType::JS, ?string $packageSpecifier = null): ImportMapEntry
diff --git a/src/Symfony/Component/Cache/DataCollector/CacheDataCollector.php b/src/Symfony/Component/Cache/DataCollector/CacheDataCollector.php
index b9bcdaf132572..22a5a0391673f 100644
--- a/src/Symfony/Component/Cache/DataCollector/CacheDataCollector.php
+++ b/src/Symfony/Component/Cache/DataCollector/CacheDataCollector.php
@@ -38,15 +38,7 @@ public function addInstance(string $name, TraceableAdapter $instance): void
public function collect(Request $request, Response $response, ?\Throwable $exception = null): void
{
- $empty = ['calls' => [], 'adapters' => [], 'config' => [], 'options' => [], 'statistics' => []];
- $this->data = ['instances' => $empty, 'total' => $empty];
- foreach ($this->instances as $name => $instance) {
- $this->data['instances']['calls'][$name] = $instance->getCalls();
- $this->data['instances']['adapters'][$name] = get_debug_type($instance->getPool());
- }
-
- $this->data['instances']['statistics'] = $this->calculateStatistics();
- $this->data['total']['statistics'] = $this->calculateTotalStatistics();
+ $this->lateCollect();
}
public function reset(): void
@@ -59,6 +51,15 @@ public function reset(): void
public function lateCollect(): void
{
+ $empty = ['calls' => [], 'adapters' => [], 'config' => [], 'options' => [], 'statistics' => []];
+ $this->data = ['instances' => $empty, 'total' => $empty];
+ foreach ($this->instances as $name => $instance) {
+ $this->data['instances']['calls'][$name] = $instance->getCalls();
+ $this->data['instances']['adapters'][$name] = get_debug_type($instance->getPool());
+ }
+
+ $this->data['instances']['statistics'] = $this->calculateStatistics();
+ $this->data['total']['statistics'] = $this->calculateTotalStatistics();
$this->data['instances']['calls'] = $this->cloneVar($this->data['instances']['calls']);
}
diff --git a/src/Symfony/Component/Cache/Tests/DataCollector/CacheDataCollectorTest.php b/src/Symfony/Component/Cache/Tests/DataCollector/CacheDataCollectorTest.php
index a00954b6cb828..7a2f36abb4df3 100644
--- a/src/Symfony/Component/Cache/Tests/DataCollector/CacheDataCollectorTest.php
+++ b/src/Symfony/Component/Cache/Tests/DataCollector/CacheDataCollectorTest.php
@@ -17,6 +17,7 @@
use Symfony\Component\Cache\DataCollector\CacheDataCollector;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\VarDumper\Cloner\Data;
class CacheDataCollectorTest extends TestCase
{
@@ -104,6 +105,27 @@ public function testCollectBeforeEnd()
$this->assertEquals($stats[self::INSTANCE_NAME]['misses'], 1, 'misses');
}
+ public function testLateCollect()
+ {
+ $adapter = new TraceableAdapter(new NullAdapter());
+
+ $collector = new CacheDataCollector();
+ $collector->addInstance(self::INSTANCE_NAME, $adapter);
+
+ $adapter->get('foo', function () use ($collector) {
+ $collector->lateCollect();
+
+ return 123;
+ });
+
+ $stats = $collector->getStatistics();
+ $this->assertGreaterThan(0, $stats[self::INSTANCE_NAME]['time']);
+ $this->assertEquals($stats[self::INSTANCE_NAME]['hits'], 0, 'hits');
+ $this->assertEquals($stats[self::INSTANCE_NAME]['misses'], 1, 'misses');
+ $this->assertEquals($stats[self::INSTANCE_NAME]['calls'], 1, 'calls');
+ $this->assertInstanceOf(Data::class, $collector->getCalls());
+ }
+
private function getCacheDataCollectorStatisticsFromEvents(array $traceableAdapterEvents)
{
$traceableAdapterMock = $this->createMock(TraceableAdapter::class);
diff --git a/src/Symfony/Component/Console/Helper/ProgressBar.php b/src/Symfony/Component/Console/Helper/ProgressBar.php
index 23157e3c7b2db..3dc06d7b483a8 100644
--- a/src/Symfony/Component/Console/Helper/ProgressBar.php
+++ b/src/Symfony/Component/Console/Helper/ProgressBar.php
@@ -486,12 +486,21 @@ private function overwrite(string $message): void
if ($this->output instanceof ConsoleSectionOutput) {
$messageLines = explode("\n", $this->previousMessage);
$lineCount = \count($messageLines);
+
+ $lastLineWithoutDecoration = Helper::removeDecoration($this->output->getFormatter(), end($messageLines) ?? '');
+
+ // When the last previous line is empty (without formatting) it is already cleared by the section output, so we don't need to clear it again
+ if ('' === $lastLineWithoutDecoration) {
+ --$lineCount;
+ }
+
foreach ($messageLines as $messageLine) {
$messageLineLength = Helper::width(Helper::removeDecoration($this->output->getFormatter(), $messageLine));
if ($messageLineLength > $this->terminal->getWidth()) {
$lineCount += floor($messageLineLength / $this->terminal->getWidth());
}
}
+
$this->output->clear($lineCount);
} else {
$lineCount = substr_count($this->previousMessage, "\n");
diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php
index a1db94583db49..615237f1f5a45 100644
--- a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php
+++ b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php
@@ -416,6 +416,81 @@ public function testOverwriteWithSectionOutput()
);
}
+ public function testOverwriteWithSectionOutputAndEol()
+ {
+ $sections = [];
+ $stream = $this->getOutputStream(true);
+ $output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter());
+
+ $bar = new ProgressBar($output, 50, 0);
+ $bar->setFormat('[%bar%] %percent:3s%%' . PHP_EOL . '%message%' . PHP_EOL);
+ $bar->setMessage('');
+ $bar->start();
+ $bar->display();
+ $bar->setMessage('Doing something...');
+ $bar->advance();
+ $bar->setMessage('Doing something foo...');
+ $bar->advance();
+
+ rewind($output->getStream());
+ $this->assertEquals(escapeshellcmd(
+ '[>---------------------------] 0%'.\PHP_EOL.\PHP_EOL.
+ "\x1b[2A\x1b[0J".'[>---------------------------] 2%'.\PHP_EOL. 'Doing something...' . \PHP_EOL .
+ "\x1b[2A\x1b[0J".'[=>--------------------------] 4%'.\PHP_EOL. 'Doing something foo...' . \PHP_EOL),
+ escapeshellcmd(stream_get_contents($output->getStream()))
+ );
+ }
+
+ public function testOverwriteWithSectionOutputAndEolWithEmptyMessage()
+ {
+ $sections = [];
+ $stream = $this->getOutputStream(true);
+ $output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter());
+
+ $bar = new ProgressBar($output, 50, 0);
+ $bar->setFormat('[%bar%] %percent:3s%%' . PHP_EOL . '%message%');
+ $bar->setMessage('Start');
+ $bar->start();
+ $bar->display();
+ $bar->setMessage('');
+ $bar->advance();
+ $bar->setMessage('Doing something...');
+ $bar->advance();
+
+ rewind($output->getStream());
+ $this->assertEquals(escapeshellcmd(
+ '[>---------------------------] 0%'.\PHP_EOL.'Start'.\PHP_EOL.
+ "\x1b[2A\x1b[0J".'[>---------------------------] 2%'.\PHP_EOL .
+ "\x1b[1A\x1b[0J".'[=>--------------------------] 4%'.\PHP_EOL. 'Doing something...' . \PHP_EOL),
+ escapeshellcmd(stream_get_contents($output->getStream()))
+ );
+ }
+
+ public function testOverwriteWithSectionOutputAndEolWithEmptyMessageComment()
+ {
+ $sections = [];
+ $stream = $this->getOutputStream(true);
+ $output = new ConsoleSectionOutput($stream->getStream(), $sections, $stream->getVerbosity(), $stream->isDecorated(), new OutputFormatter());
+
+ $bar = new ProgressBar($output, 50, 0);
+ $bar->setFormat('[%bar%] %percent:3s%%' . PHP_EOL . '%message%');
+ $bar->setMessage('Start');
+ $bar->start();
+ $bar->display();
+ $bar->setMessage('');
+ $bar->advance();
+ $bar->setMessage('Doing something...');
+ $bar->advance();
+
+ rewind($output->getStream());
+ $this->assertEquals(escapeshellcmd(
+ '[>---------------------------] 0%'.\PHP_EOL."\x1b[33mStart\x1b[39m".\PHP_EOL.
+ "\x1b[2A\x1b[0J".'[>---------------------------] 2%'.\PHP_EOL .
+ "\x1b[1A\x1b[0J".'[=>--------------------------] 4%'.\PHP_EOL. "\x1b[33mDoing something...\x1b[39m" . \PHP_EOL),
+ escapeshellcmd(stream_get_contents($output->getStream()))
+ );
+ }
+
public function testOverwriteWithAnsiSectionOutput()
{
// output has 43 visible characters plus 2 invisible ANSI characters
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_wither_lazy.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_wither_lazy.php
index d5c3738a62a0b..81dd1a0b9c9cb 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_wither_lazy.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_wither_lazy.php
@@ -76,7 +76,7 @@ class WitherProxy580fe0f extends \Symfony\Component\DependencyInjection\Tests\Co
use \Symfony\Component\VarExporter\LazyProxyTrait;
private const LAZY_OBJECT_PROPERTY_SCOPES = [
- 'foo' => [parent::class, 'foo', null],
+ 'foo' => [parent::class, 'foo', null, 4],
];
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_wither_lazy_non_shared.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_wither_lazy_non_shared.php
index 0867347a6f845..8952ebd6d8ac9 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_wither_lazy_non_shared.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services_wither_lazy_non_shared.php
@@ -78,7 +78,7 @@ class WitherProxyDd381be extends \Symfony\Component\DependencyInjection\Tests\Co
use \Symfony\Component\VarExporter\LazyProxyTrait;
private const LAZY_OBJECT_PROPERTY_SCOPES = [
- 'foo' => [parent::class, 'foo', null],
+ 'foo' => [parent::class, 'foo', null, 4],
];
}
diff --git a/src/Symfony/Component/DependencyInjection/composer.json b/src/Symfony/Component/DependencyInjection/composer.json
index dc4a9feaf8556..86b05b91727d2 100644
--- a/src/Symfony/Component/DependencyInjection/composer.json
+++ b/src/Symfony/Component/DependencyInjection/composer.json
@@ -20,7 +20,7 @@
"psr/container": "^1.1|^2.0",
"symfony/deprecation-contracts": "^2.5|^3",
"symfony/service-contracts": "^2.5|^3.0",
- "symfony/var-exporter": "^6.2.10|^7.0"
+ "symfony/var-exporter": "^6.4.20|^7.2.5"
},
"require-dev": {
"symfony/yaml": "^5.4|^6.0|^7.0",
diff --git a/src/Symfony/Component/ErrorHandler/DebugClassLoader.php b/src/Symfony/Component/ErrorHandler/DebugClassLoader.php
index b6ad33a632dd3..3f2a136247b4a 100644
--- a/src/Symfony/Component/ErrorHandler/DebugClassLoader.php
+++ b/src/Symfony/Component/ErrorHandler/DebugClassLoader.php
@@ -18,6 +18,7 @@
use Phake\IMock;
use PHPUnit\Framework\MockObject\Matcher\StatelessInvocation;
use PHPUnit\Framework\MockObject\MockObject;
+use PHPUnit\Framework\MockObject\Stub;
use Prophecy\Prophecy\ProphecySubjectInterface;
use ProxyManager\Proxy\ProxyInterface;
use Symfony\Component\DependencyInjection\Argument\LazyClosure;
@@ -253,6 +254,7 @@ public static function checkClasses(): bool
for (; $i < \count($symbols); ++$i) {
if (!is_subclass_of($symbols[$i], MockObject::class)
+ && !is_subclass_of($symbols[$i], Stub::class)
&& !is_subclass_of($symbols[$i], ProphecySubjectInterface::class)
&& !is_subclass_of($symbols[$i], Proxy::class)
&& !is_subclass_of($symbols[$i], ProxyInterface::class)
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
index 35dcf1b1b9659..32bc67766732b 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
@@ -281,6 +281,8 @@ public function buildView(FormView $view, FormInterface $form, array $options)
*/
public function finishView(FormView $view, FormInterface $form, array $options)
{
+ $view->vars['duplicate_preferred_choices'] = $options['duplicate_preferred_choices'];
+
if ($options['expanded']) {
// Radio buttons should have the same name as the parent
$childName = $view->vars['full_name'];
diff --git a/src/Symfony/Component/Form/Resources/translations/validators.es.xlf b/src/Symfony/Component/Form/Resources/translations/validators.es.xlf
index 301e2b33f7ed3..a9989737c33eb 100644
--- a/src/Symfony/Component/Form/Resources/translations/validators.es.xlf
+++ b/src/Symfony/Component/Form/Resources/translations/validators.es.xlf
@@ -52,7 +52,7 @@
Please enter a valid date.
- Por favor, ingrese una fecha valida.
+ Por favor, ingrese una fecha válida.
Please select a valid file.
diff --git a/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php b/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php
index d31ce75816cf2..f3101d5b14f19 100644
--- a/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php
+++ b/src/Symfony/Component/HttpKernel/Debug/TraceableEventDispatcher.php
@@ -66,7 +66,11 @@ protected function afterDispatch(string $eventName, object $event): void
if (null === $sectionId) {
break;
}
- $this->stopwatch->stopSection($sectionId);
+ try {
+ $this->stopwatch->stopSection($sectionId);
+ } catch (\LogicException) {
+ // The stop watch service might have been reset in the meantime
+ }
break;
case KernelEvents::TERMINATE:
// In the special case described in the `preDispatch` method above, the `$token` section
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index 087a393071a9d..49f3b698acc66 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.19';
- public const VERSION_ID = 60419;
+ public const VERSION = '6.4.20';
+ public const VERSION_ID = 60420;
public const MAJOR_VERSION = 6;
public const MINOR_VERSION = 4;
- public const RELEASE_VERSION = 19;
+ public const RELEASE_VERSION = 20;
public const EXTRA_VERSION = '';
public const END_OF_MAINTENANCE = '11/2026';
@@ -407,7 +407,8 @@ protected function initializeContainer()
$cachePath = $cache->getPath();
// Silence E_WARNING to ignore "include" failures - don't use "@" to prevent silencing fatal errors
- $errorLevel = error_reporting(\E_ALL ^ \E_WARNING);
+ $errorLevel = error_reporting();
+ error_reporting($errorLevel & ~\E_WARNING);
try {
if (is_file($cachePath) && \is_object($this->container = include $cachePath)
diff --git a/src/Symfony/Component/Process/Pipes/UnixPipes.php b/src/Symfony/Component/Process/Pipes/UnixPipes.php
index 7bd0db0e94b45..a0e48dd3634c1 100644
--- a/src/Symfony/Component/Process/Pipes/UnixPipes.php
+++ b/src/Symfony/Component/Process/Pipes/UnixPipes.php
@@ -74,7 +74,7 @@ public function getDescriptors(): array
return [
['pty'],
['pty'],
- ['pty'],
+ ['pipe', 'w'], // stderr needs to be in a pipe to correctly split error and output, since PHP will use the same stream for both
];
}
diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php
index 0f302c2aabd3c..e9c7527c42c89 100644
--- a/src/Symfony/Component/Process/Tests/ProcessTest.php
+++ b/src/Symfony/Component/Process/Tests/ProcessTest.php
@@ -540,6 +540,20 @@ public function testExitCodeTextIsNullWhenExitCodeIsNull()
$this->assertNull($process->getExitCodeText());
}
+ public function testStderrNotMixedWithStdout()
+ {
+ if (!Process::isPtySupported()) {
+ $this->markTestSkipped('PTY is not supported on this operating system.');
+ }
+
+ $process = $this->getProcess('echo "foo" && echo "bar" >&2');
+ $process->setPty(true);
+ $process->run();
+
+ $this->assertSame("foo\r\n", $process->getOutput());
+ $this->assertSame("bar\n", $process->getErrorOutput());
+ }
+
public function testPTYCommand()
{
if (!Process::isPtySupported()) {
diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf
index c4b36fd45f7f0..f6d2e0c28a33e 100644
--- a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf
+++ b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf
@@ -444,31 +444,31 @@
This value is too short. It should contain at least one word.|This value is too short. It should contain at least {{ min }} words.
- この値は短すぎます。少なくとも 1 つの単語を含める必要があります。|この値は短すぎます。少なくとも {{ min }} 個の単語を含める必要があります。
+ この値は短すぎます。{{ min }}単語以上にする必要があります。
This value is too long. It should contain one word.|This value is too long. It should contain {{ max }} words or less.
- この値は長すぎます。1 つの単語のみを含める必要があります。|この値は長すぎます。{{ max }} 個以下の単語を含める必要があります。
+ この値は長すぎます。{{ max }}単語以下にする必要があります。
This value does not represent a valid week in the ISO 8601 format.
- この値は ISO 8601 形式の有効な週を表していません。
+ この値は ISO 8601 形式の有効な週を表していません。
This value is not a valid week.
- この値は有効な週ではありません。
+ この値は有効な週ではありません。
This value should not be before week "{{ min }}".
- この値は週 "{{ min }}" より前であってはなりません。
+ この値は週 "{{ min }}" より前であってはいけません。
This value should not be after week "{{ max }}".
- この値は週 "{{ max }}" 以降であってはなりません。
+ この値は週 "{{ max }}" 以降であってはいけません。
This value is not a valid slug.
- この値は有効なスラグではありません。
+ この値は有効なスラグではありません。