diff --git a/.appveyor.yml b/.appveyor.yml
index c786f6f9d786e..648c9a9849e6e 100644
--- a/.appveyor.yml
+++ b/.appveyor.yml
@@ -46,6 +46,8 @@ install:
- php composer.phar self-update
- copy /Y .github\composer-config.json %APPDATA%\Composer\config.json
- php composer.phar global require --no-progress --no-scripts --no-plugins symfony/flex dev-master
+ - git config --global user.email ""
+ - git config --global user.name "Symfony"
- php .github/build-packages.php "HEAD^" src\Symfony\Bridge\PhpUnit src\Symfony\Contracts
- IF %APPVEYOR_REPO_BRANCH%==master (SET COMPOSER_ROOT_VERSION=dev-master) ELSE (SET COMPOSER_ROOT_VERSION=%APPVEYOR_REPO_BRANCH%.x-dev)
- php composer.phar update --no-progress --no-suggest --ansi
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index e459d1e55f616..9e23ca5c1ea74 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -4,7 +4,7 @@
/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @dunglas
# Form
/src/Symfony/Bridge/Twig/Extension/FormExtension.php @xabbuh
-/src/Symfony/Bridge/Twig/Form/* @xabbuh
+/src/Symfony/Bridge/Twig/Form/ @xabbuh
/src/Symfony/Bridge/Twig/Node/FormThemeNode.php @xabbuh
/src/Symfony/Bridge/Twig/Node/RenderBlockNode.php @xabbuh
/src/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php @xabbuh
@@ -13,34 +13,34 @@
/src/Symfony/Bridge/Twig/Tests/TokenParser/FormThemeTokenParserTest.php @xabbuh
/src/Symfony/Bridge/Twig/TokenParser/FormThemeTokenParser.php @xabbuh
/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/FormPass.php @xabbuh
-/src/Symfony/Bundle/FrameworkBundle/Resources/views/* @xabbuh
+/src/Symfony/Bundle/FrameworkBundle/Resources/views/ @xabbuh
/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php @xabbuh
/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/FormPassTest.php @xabbuh
/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php @xabbuh
/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php @xabbuh
-/src/Symfony/Component/Form/* @xabbuh
+/src/Symfony/Component/Form/ @xabbuh
# HttpKernel
/src/Symfony/Component/HttpKernel/Log/Logger.php @dunglas
# LDAP
-/src/Symfony/Component/Ldap/* @csarrazi
+/src/Symfony/Component/Ldap/ @csarrazi
# Lock
-/src/Symfony/Component/Lock/* @jderusse
+/src/Symfony/Component/Lock/ @jderusse
# Messenger
-/src/Symfony/Bridge/Doctrine/Messenger/* @sroze
-/src/Symfony/Component/Messenger/* @sroze
+/src/Symfony/Bridge/Doctrine/Messenger/ @sroze
+/src/Symfony/Component/Messenger/ @sroze
# PropertyInfo
-/src/Symfony/Component/PropertyInfo/* @dunglas
-/src/Symfony/Bridge/Doctrine/PropertyInfo/* @dunglas
+/src/Symfony/Component/PropertyInfo/ @dunglas
+/src/Symfony/Bridge/Doctrine/PropertyInfo/ @dunglas
# Serializer
-/src/Symfony/Component/Serializer/* @dunglas
+/src/Symfony/Component/Serializer/ @dunglas
# WebLink
-/src/Symfony/Component/WebLink/* @dunglas
+/src/Symfony/Component/WebLink/ @dunglas
# Workflow
/src/Symfony/Bridge/Twig/Extension/WorkflowExtension.php @lyrixx
/src/Symfony/Bridge/Twig/Tests/Extension/WorkflowExtensionTest.php @lyrixx
/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php @lyrixx
/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ValidateWorkflowsPass.php @lyrixx
/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/WorkflowGuardListenerPass.php @lyrixx
-/src/Symfony/Component/Workflow/* @lyrixx
+/src/Symfony/Component/Workflow/ @lyrixx
# Yaml
-/src/Symfony/Component/Yaml/* @xabbuh
+/src/Symfony/Component/Yaml/ @xabbuh
diff --git a/.github/build-packages.php b/.github/build-packages.php
index d859e3ec808a1..81a309911135c 100644
--- a/.github/build-packages.php
+++ b/.github/build-packages.php
@@ -47,7 +47,7 @@
if (isset($preferredInstall[$package->name]) && 'source' === $preferredInstall[$package->name]) {
passthru("cd $dir && tar -cf package.tar --exclude='package.tar' *");
} else {
- passthru("cd $dir && git init && git add . && git commit --author \"Symfony <>\" -m - && git archive -o package.tar HEAD && rm .git/ -Rf");
+ passthru("cd $dir && git init && git add . && git commit -q -m - && git archive -o package.tar HEAD && rm .git/ -Rf");
}
if (!isset($package->extra->{'branch-alias'}->{'dev-master'})) {
diff --git a/.travis.yml b/.travis.yml
index aedc228105a81..5b09c1fb3463f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -202,6 +202,9 @@ install:
- |
# Create local composer packages for each patched components and reference them in composer.json files when cross-testing components
+ git config --global user.email ""
+ git config --global user.name "Symfony"
+
if [[ ! $deps ]]; then
php .github/build-packages.php HEAD^ src/Symfony/Bridge/PhpUnit src/Symfony/Contracts
else
diff --git a/CHANGELOG-4.3.md b/CHANGELOG-4.3.md
index 0d1862231449a..5707e18c465a7 100644
--- a/CHANGELOG-4.3.md
+++ b/CHANGELOG-4.3.md
@@ -7,6 +7,49 @@ in 4.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/v4.3.0...v4.3.1
+* 4.3.6 (2019-11-01)
+
+ * bug #34198 [HttpClient] Fix perf issue when doing thousands of requests with curl (nicolas-grekas)
+ * bug #33998 [Config] Disable default alphabet sorting in glob function due of unstable sort (hurricane-voronin)
+ * bug #34144 [Serializer] Improve messages for unexpected resources values (fancyweb)
+ * bug #34186 [HttpClient] always return the empty string when the response cannot have a body (nicolas-grekas)
+ * bug #34167 [HttpFoundation] Allow to not pass a parameter to Request::isMethodSafe() (dunglas)
+ * bug #33828 [DoctrineBridge] Auto-validation must work if no regex are passed (dunglas)
+ * bug #34080 [SecurityBundle] correct types for default arguments for firewall configs (shieldo)
+ * bug #34152 [Workflow] Made the configuration more robust for the 'property' key (lyrixx)
+ * bug #34154 [HttpClient] fix handling of 3xx with no Location header - ignore Content-Length when no body is expected (nicolas-grekas)
+ * bug #34140 [Security/Core] make NativePasswordEncoder use sodium to validate passwords when possible (nicolas-grekas)
+ * bug #33999 [Form] Make sure to collect child forms created on *_SET_DATA events (yceruto)
+ * bug #34090 [WebProfilerBundle] Improve display in Email panel for dark theme (antograssiot)
+ * bug #34116 [HttpClient] ignore the body of responses to HEAD requests (nicolas-grekas)
+ * bug #32456 [Messenger] use database platform to convert correctly the DateTime (roukmoute)
+ * bug #34107 [Messenger] prevent infinite redelivery loops and blocked queues (Tobion)
+ * bug #32341 [Messenger] Show exceptions after multiple retries (TimoBakx)
+ * bug #34082 Revert "[Messenger] Fix exception message of failed message is dropped (Tobion)
+ * bug #34021 [TwigBridge] do not render errors for checkboxes twice (xabbuh)
+ * bug #34017 [Messenger] Fix ignored options in redis transport (chalasr)
+ * bug #34041 [HttpKernel] fix wrong removal of the just generated container dir (nicolas-grekas)
+ * bug #34024 [Routing] fix route loading with wildcard, but dir or file is empty (gseidel)
+ * bug #34023 [Dotenv] allow LF in single-quoted strings (nicolas-grekas)
+ * bug #33818 [Yaml] Throw exception for tagged invalid inline elements (gharlan)
+ * bug #33994 [Mailer] Fix Mandrill Transport API payload for named addresses (Michaël Perrin)
+ * bug #33985 [HttpClient] workaround curl_multi_select() issue (nicolas-grekas)
+ * bug #33948 [PropertyInfo] Respect property name case when guessing from public method name (antograssiot)
+ * bug #33962 [Cache] fixed TagAwareAdapter returning invalid cache (v-m-i)
+ * bug #33958 [DI] Add extra type check to php dumper (gquemener)
+ * bug #33965 [HttpFoundation] Add plus character `+` to legal mime subtype (ilzrv)
+ * bug #32943 [Dotenv] search variable values in ENV first then env file (soufianZantar)
+ * bug #33943 [VarDumper] fix resetting the "bold" state in CliDumper (nicolas-grekas)
+ * bug #33936 [HttpClient] Missing argument in method_exists (detinkin)
+ * bug #33937 [Cache] ignore unserialization failures in AbstractTagAwareAdapter::doDelete() (nicolas-grekas)
+ * bug #33935 [HttpClient] send `Accept: */*` by default, fix removing it when needed (nicolas-grekas)
+ * bug #33922 [Cache] remove implicit dependency on symfony/filesystem (nicolas-grekas)
+ * bug #33927 Allow to set SameSite config to 'none' (ihmels)
+ * bug #33930 [Cache] clean tags folder on invalidation (nicolas-grekas)
+ * bug #33919 [VarDumper] fix array key error for class SymfonyCaster (zcodes)
+ * bug #33885 [Form][DateTimeImmutableToDateTimeTransformer] Preserve microseconds and use \DateTime::createFromImmutable() when available (fancyweb)
+ * bug #33900 [HttpKernel] Fix to populate $dotenvVars in data collector when not using putenv() (mynameisbogdan)
+
* 4.3.5 (2019-10-07)
* bug #33742 [Crawler] document $default as string|null (nicolas-grekas)
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 963f9e960293c..2cf905be32e88 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -6,36 +6,36 @@ Symfony is the result of the work of many people who made the code better
- Fabien Potencier (fabpot)
- Nicolas Grekas (nicolas-grekas)
- - Bernhard Schussek (bschussek)
- Christian Flothmann (xabbuh)
+ - Bernhard Schussek (bschussek)
- Tobias Schultze (tobion)
- Christophe Coevoet (stof)
- Robin Chalas (chalas_r)
- Jordi Boggiano (seldaek)
- - Victor Berchet (victor)
- Kévin Dunglas (dunglas)
+ - Victor Berchet (victor)
- Maxime Steinhausser (ogizanagi)
- Ryan Weaver (weaverryan)
- Javier Eguiluz (javier.eguiluz)
- - Jakub Zalas (jakubzalas)
- Roland Franssen (ro0)
+ - Jakub Zalas (jakubzalas)
- Johannes S (johannes)
- - Kris Wallsmith (kriswallsmith)
- Grégoire Pineau (lyrixx)
+ - Kris Wallsmith (kriswallsmith)
- Hugo Hamon (hhamon)
+ - Yonel Ceruto (yonelceruto)
- Abdellatif Ait boudad (aitboudad)
- Samuel ROZE (sroze)
- - Yonel Ceruto (yonelceruto)
- Romain Neutron (romain)
- Pascal Borreli (pborreli)
- Wouter De Jong (wouterj)
- Joseph Bielawski (stloyd)
- Karma Dordrak (drak)
- Lukas Kahwe Smith (lsmith)
+ - Alexander M. Turek (derrabus)
- Martin Hasoň (hason)
- Hamza Amrouche (simperfit)
- Jeremy Mikola (jmikola)
- - Alexander M. Turek (derrabus)
- Jean-François Simon (jfsimon)
- Jules Pietri (heah)
- Benjamin Eberlei (beberlei)
@@ -44,21 +44,21 @@ Symfony is the result of the work of many people who made the code better
- Eriksen Costa (eriksencosta)
- Guilhem Niot (energetick)
- Sarah Khalil (saro0h)
+ - Thomas Calvet (fancyweb)
- Tobias Nyholm (tobias)
- Jonathan Wage (jwage)
- Lynn van der Berg (kjarli)
- Diego Saint Esteben (dosten)
- - Thomas Calvet (fancyweb)
- Alexandre Salomé (alexandresalome)
- William Durand (couac)
- ornicar
+ - Pierre du Plessis (pierredup)
- Dany Maillard (maidmaid)
- Francis Besset (francisbesset)
- stealth35 (stealth35)
- Alexander Mols (asm89)
- - Pierre du Plessis (pierredup)
- - Matthias Pigulla (mpdude)
- Konstantin Myakshin (koc)
+ - Matthias Pigulla (mpdude)
- Bulat Shakirzyanov (avalanche123)
- Grégoire Paris (greg0ire)
- Saša Stamenković (umpirsky)
@@ -69,13 +69,13 @@ Symfony is the result of the work of many people who made the code better
- Miha Vrhovnik
- Diego Saint Esteben (dii3g0)
- Gábor Egyed (1ed)
- - Konstantin Kudryashov (everzet)
- Titouan Galopin (tgalopin)
+ - Konstantin Kudryashov (everzet)
+ - David Maicher (dmaicher)
- Bilal Amarni (bamarni)
- Mathieu Piot (mpiot)
- - David Maicher (dmaicher)
- - Florin Patan (florinpatan)
- Gabriel Ostrolucký (gadelat)
+ - Florin Patan (florinpatan)
- Vladimir Reznichenko (kalessil)
- Jáchym Toušek (enumag)
- Michel Weimerskirch (mweimerskirch)
@@ -83,6 +83,7 @@ Symfony is the result of the work of many people who made the code better
- Issei Murasawa (issei_m)
- Eric Clemmons (ericclemmons)
- Charles Sarrazin (csarrazi)
+ - Jan Schädlich (jschaedl)
- Christian Raue
- Arnout Boks (aboks)
- Deni
@@ -90,7 +91,6 @@ Symfony is the result of the work of many people who made the code better
- Dariusz Górecki (canni)
- Douglas Greenshields (shieldo)
- David Buchmann (dbu)
- - Jan Schädlich (jschaedl)
- Dariusz Ruminski
- Lee McDermott
- Brandon Turner
@@ -114,30 +114,30 @@ Symfony is the result of the work of many people who made the code better
- Baptiste Clavié (talus)
- marc.weistroff
- Tomáš Votruba (tomas_votruba)
+ - Jérôme Vasseur (jvasseur)
- lenar
- Alexander Schwenn (xelaris)
- Włodzimierz Gajda (gajdaw)
- - Jérôme Vasseur (jvasseur)
+ - Sebastiaan Stok (sstok)
+ - Adrien Brault (adrienbrault)
- Peter Kokot (maastermedia)
- Jacob Dreesen (jdreesen)
- Florian Voutzinos (florianv)
- - Sebastiaan Stok (sstok)
- Colin Frei
- Javier Spagnoletti (phansys)
- - Adrien Brault (adrienbrault)
- Joshua Thijssen
- Daniel Wehner (dawehner)
- excelwebzone
- Gordon Franke (gimler)
+ - Teoh Han Hui (teohhanhui)
- Oskar Stark (oskarstark)
+ - Alex Pott
- Fabien Pennequin (fabienpennequin)
- Théo FIDRY (theofidry)
- - Teoh Han Hui (teohhanhui)
- Eric GELOEN (gelo)
- Joel Wurtz (brouznouf)
- Lars Strojny (lstrojny)
- Tugdual Saunier (tucksaun)
- - Alex Pott
- Jannik Zschiesche (apfelbox)
- Robert Schönthal (digitalkaoz)
- Florian Lonqueu-Brochard (florianlb)
@@ -152,6 +152,7 @@ Symfony is the result of the work of many people who made the code better
- Daniel Gomes (danielcsgomes)
- Hidenori Goto (hidenorigoto)
- Andréia Bohner (andreia)
+ - Julien Falque (julienfalque)
- Arnaud Kleinpeter (nanocom)
- Guilherme Blanco (guilhermeblanco)
- SpacePossum
@@ -160,7 +161,6 @@ Symfony is the result of the work of many people who made the code better
- François-Xavier de Guillebon (de-gui_f)
- Oleg Voronkovich
- Philipp Wahala (hifi)
- - Julien Falque (julienfalque)
- Rafael Dohms (rdohms)
- jwdeitch
- Mikael Pajunen
@@ -172,6 +172,7 @@ Symfony is the result of the work of many people who made the code better
- Richard Shank (iampersistent)
- Thomas Rabaix (rande)
- Vincent Touzet (vincenttouzet)
+ - Gregor Harlan (gharlan)
- jeremyFreeAgent (jeremyfreeagent)
- Rouven Weßling (realityking)
- Alexander Schranz (alexander-schranz)
@@ -193,6 +194,7 @@ Symfony is the result of the work of many people who made the code better
- James Halsall (jaitsu)
- Matthieu Napoli (mnapoli)
- Florent Mata (fmata)
+ - Arman Hosseini
- Warnar Boekkooi (boekkooi)
- Dmitrii Chekaliuk (lazyhammer)
- Clément JOBEILI (dator)
@@ -206,11 +208,11 @@ Symfony is the result of the work of many people who made the code better
- Mario A. Alvarez Garcia (nomack84)
- Dennis Benkert (denderello)
- DQNEO
- - Gregor Harlan (gharlan)
+ - mcfedr (mcfedr)
- Gary PEGEOT (gary-p)
- Ruben Gonzalez (rubenrua)
- Benjamin Dulau (dbenjamin)
- - Arman Hosseini
+ - Andreas Braun
- Mathieu Lemoine (lemoinem)
- Christian Schmidt
- Andreas Hucks (meandmymonkey)
@@ -241,7 +243,6 @@ Symfony is the result of the work of many people who made the code better
- jeff
- John Kary (johnkary)
- Andreas Schempp (aschempp)
- - Andreas Braun
- Justin Hileman (bobthecow)
- Blanchon Vincent (blanchonvincent)
- Michele Orselli (orso)
@@ -265,7 +266,6 @@ Symfony is the result of the work of many people who made the code better
- julien pauli (jpauli)
- Lorenz Schori
- Sébastien Lavoie (lavoiesl)
- - mcfedr (mcfedr)
- Dariusz
- Michael Babker (mbabker)
- Francois Zaninotto
@@ -314,12 +314,14 @@ Symfony is the result of the work of many people who made the code better
- Jhonny Lidfors (jhonne)
- Diego Agulló (aeoris)
- jdhoek
+ - Maxime Helias (maxhelias)
- David Prévot
- Bob den Otter (bopp)
- Thomas Schulz (king2500)
- Frank de Jonge (frenkynet)
- Nikita Konstantinov
- Wodor Wodorski
+ - dFayet
- Thomas Lallement (raziel057)
- Colin O'Dell (colinodell)
- Giorgio Premi
@@ -343,6 +345,7 @@ Symfony is the result of the work of many people who made the code better
- Christian Schmidt
- Patrick Landolt (scube)
- MatTheCat
+ - David Badura (davidbadura)
- Chad Sikorra (chadsikorra)
- Chris Smith (cs278)
- Florian Klein (docteurklein)
@@ -361,6 +364,7 @@ Symfony is the result of the work of many people who made the code better
- Jerzy Zawadzki (jzawadzki)
- Wouter J
- Ismael Ambrosi (iambrosi)
+ - Ruud Kamphuis (ruudk)
- Emmanuel BORGES (eborges78)
- Aurelijus Valeiša (aurelijus)
- Jan Decavele (jandc)
@@ -374,7 +378,6 @@ Symfony is the result of the work of many people who made the code better
- Francesc Rosàs (frosas)
- Romain Pierre (romain-pierre)
- Julien Galenski (ruian)
- - Maxime Helias
- Bongiraud Dominique
- janschoenherr
- Emanuele Gaspari (inmarelibero)
@@ -382,7 +385,6 @@ Symfony is the result of the work of many people who made the code better
- Berny Cantos (xphere81)
- Thierry Thuon (lepiaf)
- Ricard Clau (ricardclau)
- - dFayet
- Mark Challoner (markchalloner)
- Gennady Telegin (gtelegin)
- Erin Millard
@@ -410,10 +412,10 @@ Symfony is the result of the work of many people who made the code better
- Robbert Klarenbeek (robbertkl)
- Eric Masoero (eric-masoero)
- JhonnyL
- - David Badura (davidbadura)
- hossein zolfi (ocean)
- Clément Gautier (clementgautier)
- Thomas Bisignani (toma)
+ - Dāvis Zālītis (k0d3r1s)
- Sanpi
- Eduardo Gulias (egulias)
- giulio de donato (liuggio)
@@ -436,6 +438,7 @@ Symfony is the result of the work of many people who made the code better
- Tamas Szijarto
- Michele Locati
- Pavel Volokitin (pvolok)
+ - Valentine Boineau (valentineboineau)
- Arthur de Moulins (4rthem)
- Matthias Althaus (althaus)
- Nicolas Dewez (nicolas_dewez)
@@ -447,13 +450,13 @@ Symfony is the result of the work of many people who made the code better
- Joe Lencioni
- Daniel Tschinder
- vladimir.reznichenko
- - Ruud Kamphuis (ruudk)
- Kai
- Lee Rowlands
- Krzysztof Piasecki (krzysztek)
- Maximilian Reichel (phramz)
- Loick Piera (pyrech)
- Alain Hippolyte (aloneh)
+ - Grenier Kévin (mcsky_biig)
- Karoly Negyesi (chx)
- Ivan Kurnosov
- Xavier HAUSHERR
@@ -481,9 +484,11 @@ Symfony is the result of the work of many people who made the code better
- Jeanmonod David (jeanmonod)
- Christopher Davis (chrisguitarguy)
- Webnet team (webnet)
+ - Farhad Safarov
- Jan Schumann
- Niklas Fiekas
- Markus Bachmann (baachi)
+ - Kévin THERAGE (kevin_therage)
- lancergr
- Mihai Stancu
- Ivan Nikolaev (destillat)
@@ -499,6 +504,7 @@ Symfony is the result of the work of many people who made the code better
- EdgarPE
- Florian Pfitzer (marmelatze)
- Asier Illarramendi (doup)
+ - Sylvain Fabre (sylfabre)
- Martijn Cuppens
- Vlad Gregurco (vgregurco)
- Maciej Malarz (malarzm)
@@ -517,6 +523,7 @@ Symfony is the result of the work of many people who made the code better
- Tobias Weichart
- Gonzalo Vilaseca (gonzalovilaseca)
- Marcin Sikoń (marphi)
+ - Tien Vo (tienvx)
- Denis Brumann (dbrumann)
- Dominik Zogg (dominik.zogg)
- Marek Pietrzak
@@ -533,6 +540,7 @@ Symfony is the result of the work of many people who made the code better
- Anton Bakai
- Martin Auswöger
- Rhodri Pugh (rodnaph)
+ - battye
- Sam Fleming (sam_fleming)
- Alex Bakhturin
- Patrick Reimers (preimers)
@@ -606,7 +614,6 @@ Symfony is the result of the work of many people who made the code better
- Nate (frickenate)
- Timothée Barray (tyx)
- jhonnyL
- - Grenier Kévin (mcsky_biig)
- sasezaki
- Dawid Pakuła (zulusx)
- Florian Rey (nervo)
@@ -621,6 +628,7 @@ Symfony is the result of the work of many people who made the code better
- Kevin Saliou (kbsali)
- Shawn Iwinski
- Gawain Lynch (gawain)
+ - mmokhi
- NothingWeAre
- Ryan
- Alexander Deruwe (aderuwe)
@@ -643,9 +651,11 @@ Symfony is the result of the work of many people who made the code better
- Disquedur
- Michiel Boeckaert (milio)
- Geoffrey Tran (geoff)
+ - Kyle
- Jan Behrens
- Mantas Var (mvar)
- Chris Tanaskoski
+ - Terje Bråten
- Sebastian Krebs
- Piotr Stankowski
- Baptiste Leduc (bleduc)
@@ -669,6 +679,7 @@ Symfony is the result of the work of many people who made the code better
- Kyle Evans (kevans91)
- Charles-Henri Bruyand
- Max Rath (drak3)
+ - Oleg Andreyev
- Stéphane Escandell (sescandell)
- Konstantin S. M. Möllers (ksmmoellers)
- James Johnston
@@ -676,7 +687,6 @@ Symfony is the result of the work of many people who made the code better
- Alexandre Dupuy (satchette)
- Malte Blättermann
- Desjardins Jérôme (jewome62)
- - Kévin THERAGE (kevin_therage)
- Simeon Kolev (simeon_kolev9)
- Joost van Driel (j92)
- Jonas Elfering
@@ -693,7 +703,6 @@ Symfony is the result of the work of many people who made the code better
- Gunnstein Lye (glye)
- Maxime Douailin
- Jean Pasdeloup (pasdeloup)
- - Sylvain Fabre (sylfabre)
- Benjamin Cremer (bcremer)
- Javier López (loalf)
- Reinier Kip
@@ -712,6 +721,7 @@ Symfony is the result of the work of many people who made the code better
- DerManoMann
- Rostyslav Kinash
- Dennis Fridrich (dfridrich)
+ - Mardari Dorel (dorumd)
- Daisuke Ohata
- Vincent Simonin
- Alex Bogomazov (alebo)
@@ -730,6 +740,7 @@ Symfony is the result of the work of many people who made the code better
- Miquel Rodríguez Telep (mrtorrent)
- Sergey Kolodyazhnyy (skolodyazhnyy)
- umpirski
+ - M. Vondano
- Quentin de Longraye (quentinus95)
- Chris Heng (gigablah)
- Shaun Simmons (simshaun)
@@ -750,7 +761,7 @@ Symfony is the result of the work of many people who made the code better
- Kristijan Kanalas
- Stephan Vock
- Benjamin Zikarsky (bzikarsky)
- - battye
+ - Ruben Jacobs (rubenj)
- Simon Schick (simonsimcity)
- redstar504
- Tristan Roussel
@@ -799,6 +810,7 @@ Symfony is the result of the work of many people who made the code better
- Indra Gunawan (guind)
- Peter Ward
- Davide Borsatto (davide.borsatto)
+ - Markus Fasselt (digilist)
- Julien DIDIER (juliendidier)
- Dominik Ritter (dritter)
- Sebastian Grodzicki (sgrodzicki)
@@ -935,7 +947,6 @@ Symfony is the result of the work of many people who made the code better
- Benoît Bourgeois
- mantulo
- Stefan Kruppa
- - mmokhi
- corphi
- JoppeDC
- grizlik
@@ -1005,10 +1016,8 @@ Symfony is the result of the work of many people who made the code better
- Pablo Lozano (arkadis)
- Erik Saunier (snickers)
- Rootie
- - Kyle
- Daniel Alejandro Castro Arellano (lexcast)
- sensio
- - Terje Bråten
- Thomas Jarrand
- Antoine Bluchet (soyuka)
- Sebastien Morel (plopix)
@@ -1031,7 +1040,6 @@ Symfony is the result of the work of many people who made the code better
- The Whole Life to Learn
- Mikkel Paulson
- ergiegonzaga
- - Farhad Safarov
- Liverbool (liverbool)
- Sam Malone
- Phan Thanh Ha (haphan)
@@ -1039,7 +1047,9 @@ Symfony is the result of the work of many people who made the code better
- neghmurken
- xaav
- Mahmoud Mostafa (mahmoud)
+ - Julien Turby
- Ahmed Abdou
+ - Daniel Iwaniec
- Pieter
- Michael Tibben
- Billie Thompson
@@ -1115,6 +1125,7 @@ Symfony is the result of the work of many people who made the code better
- Chris Tiearney
- Oliver Hoff
- Ole Rößner (basster)
+ - rtek
- Faton (notaf)
- Tom Houdmont
- Per Sandström (per)
@@ -1133,6 +1144,7 @@ Symfony is the result of the work of many people who made the code better
- ilyes kooli
- gr1ev0us
- mlazovla
+ - Alejandro Diaz Torres
- Max Beutel
- Antanas Arvasevicius
- Pierre Dudoret
@@ -1152,6 +1164,7 @@ Symfony is the result of the work of many people who made the code better
- Ken Marfilla (marfillaster)
- benatespina (benatespina)
- Denis Kop
+ - HypeMC
- Jean-Guilhem Rouel (jean-gui)
- jfcixmedia
- Dominic Tubach
@@ -1167,6 +1180,7 @@ Symfony is the result of the work of many people who made the code better
- Soner Sayakci
- hugofonseca (fonsecas72)
- Marc Duboc (icemad)
+ - Matthias Krauser (mkrauser)
- Martynas Narbutas
- Toon Verwerft (veewee)
- Bailey Parker
@@ -1216,6 +1230,7 @@ Symfony is the result of the work of many people who made the code better
- Mathias STRASSER (roukmoute)
- Thomason, James
- Gordienko Vladislav
+ - marie
- Viacheslav Sychov
- Alexandre Quercia (alquerci)
- Helmut Hummel (helhum)
@@ -1307,8 +1322,8 @@ Symfony is the result of the work of many people who made the code better
- Ilia (aliance)
- Chris McCafferty (cilefen)
- Mo Di (modi)
- - Tien Vo (tienvx)
- Pablo Schläpfer
+ - SuRiKmAn
- Gert de Pagter
- Jelte Steijaert (jelte)
- David Négrier (moufmouf)
@@ -1319,11 +1334,13 @@ Symfony is the result of the work of many people who made the code better
- Alex Vasilchenko
- sez-open
- Xavier Coureau
+ - fruty
- ConneXNL
- Aharon Perkel
- matze
- Rubén Calvo (rubencm)
- Abdul.Mohsen B. A. A
+ - Swen van Zanten
- Benoît Burnichon
- pthompson
- Malaney J. Hill
@@ -1360,6 +1377,7 @@ Symfony is the result of the work of many people who made the code better
- sl_toto (sl_toto)
- Walter Dal Mut (wdalmut)
- abluchet
+ - Ruud Arentsen
- Matthieu
- Albin Kerouaton
- Sébastien HOUZÉ
@@ -1385,11 +1403,11 @@ Symfony is the result of the work of many people who made the code better
- Constantine Shtompel
- Jules Lamur
- Renato Mendes Figueiredo
+ - pdommelen
- Eric Stern
- ShiraNai7
- Cedrick Oka
- Antal Áron (antalaron)
- - Markus Fasselt (digilist)
- Vašek Purchart (vasek-purchart)
- Janusz Jabłoński (yanoosh)
- Fleuv
@@ -1408,6 +1426,7 @@ Symfony is the result of the work of many people who made the code better
- Andreas Frömer
- Philip Frank
- Lance McNearney
+ - Jeroen Spee (jeroens)
- Giorgio Premi
- ncou
- Ian Carroll
@@ -1420,6 +1439,7 @@ Symfony is the result of the work of many people who made the code better
- Luis Galeas
- Martin Pärtel
- Bastien Jaillot (bastnic)
+ - Daniel Rotter (danrot)
- Frédéric Bouchery (fbouchery)
- Patrick Daley (padrig)
- Xavier Briand (xavierbriand)
@@ -1440,7 +1460,6 @@ Symfony is the result of the work of many people who made the code better
- Daniel González Zaballos (dem3trio)
- Emmanuel Vella (emmanuel.vella)
- Guillaume BRETOU (guiguiboy)
- - Dāvis Zālītis (k0d3r1s)
- Carsten Nielsen (phreaknerd)
- Roger Guasch (rogerguasch)
- Jay Severson
@@ -1559,6 +1578,7 @@ Symfony is the result of the work of many people who made the code better
- povilas
- Gavin Staniforth
- Alessandro Tagliapietra (alex88)
+ - Andy Palmer (andyexeter)
- Biji (biji)
- Jérôme Tanghe (deuchnord)
- Alex Teterin (errogaht)
@@ -1606,7 +1626,6 @@ Symfony is the result of the work of many people who made the code better
- Jibé Barth (jibbarth)
- Matthew Foster (mfoster)
- Reyo Stallenberg (reyostallenberg)
- - Ruben Jacobs (rubenj)
- Paul Seiffert (seiffert)
- Vasily Khayrulin (sirian)
- Stefan Koopmanschap (skoop)
@@ -1648,6 +1667,7 @@ Symfony is the result of the work of many people who made the code better
- Peter Bex
- Manatsawin Hanmongkolchai
- Gunther Konig
+ - Joe Springe
- Mickael GOETZ
- Maciej Schmidt
- Dennis Væversted
@@ -1677,12 +1697,12 @@ Symfony is the result of the work of many people who made the code better
- me_shaon
- 蝦米
- Grayson Koonce (breerly)
- - Mardari Dorel (dorumd)
- Andrey Helldar (helldar)
- Karim Cassam Chenaï (ka)
- Maksym Slesarenko (maksym_slesarenko)
- Michal Kurzeja (mkurzeja)
- Nicolas Bastien (nicolas_bastien)
+ - Peter Bowyer (pbowyer)
- Nikola Svitlica (thecelavi)
- Denis (yethee)
- Andrew Zhilin (zhil)
@@ -1760,7 +1780,6 @@ Symfony is the result of the work of many people who made the code better
- Yannick Warnier (ywarnier)
- Kevin Decherf
- Jason Woods
- - Oleg Andreyev
- klemens
- dened
- Dmitry Korotovsky
@@ -1777,6 +1796,7 @@ Symfony is the result of the work of many people who made the code better
- taiiiraaa
- Trevor Suarez
- gedrox
+ - Bohan Yang
- Alan Bondarchuk
- Joe Bennett
- dropfen
@@ -1810,6 +1830,7 @@ Symfony is the result of the work of many people who made the code better
- Jan Marek (janmarek)
- Mark de Haan (markdehaan)
- Dan Patrick (mdpatrick)
+ - Geoffrey Monte (numerogeek)
- Pedro Magalhães (pmmaga)
- Rares Vlaseanu (raresvla)
- tante kinast (tante)
@@ -1907,6 +1928,7 @@ Symfony is the result of the work of many people who made the code better
- hainey
- Juan M Martínez
- Gilles Gauthier
+ - Pavinthan
- ddebree
- Kuba Werłos
- Gyula Szucs
@@ -2032,11 +2054,13 @@ Symfony is the result of the work of many people who made the code better
- jc
- BenjaminBeck
- Aurelijus Rožėnas
+ - Beno!t POLASZEK
- Jordan Hoff
- znerol
- Christian Eikermann
- Kai Eichinger
- Antonio Angelino
+ - Jens Schulze
- Matt Fields
- Niklas Keller
- Andras Debreczeni
@@ -2115,6 +2139,7 @@ Symfony is the result of the work of many people who made the code better
- Lebnik
- nsbx
- Shude
+ - Richard Hodgson
- Ondřej Führer
- Sema
- Elan Ruusamäe
@@ -2134,6 +2159,7 @@ Symfony is the result of the work of many people who made the code better
- Benjamin Long
- Ben Miller
- Peter Gribanov
+ - Matteo Galli
- kwiateusz
- jspee
- Ilya Bulakh
@@ -2172,6 +2198,7 @@ Symfony is the result of the work of many people who made the code better
- Lin Lu
- arduanov
- sualko
+ - Molkobain
- Bilge
- ADmad
- Nicolas Roudaire
@@ -2282,6 +2309,7 @@ Symfony is the result of the work of many people who made the code better
- Wouter Sioen (wouter_sioen)
- Xavier Amado (xamado)
- Jesper Søndergaard Pedersen (zerrvox)
+ - Alexander Menshchikov (zmey_kk)
- Florent Cailhol
- szymek
- Kovacs Nicolas
diff --git a/link b/link
index d839f8f8072d9..08687bbba5cc7 100755
--- a/link
+++ b/link
@@ -66,6 +66,6 @@ foreach (glob("$pathToProject/vendor/symfony/*", GLOB_ONLYDIR | GLOB_NOSORT) as
echo "\"$package\" has been linked to \"$sfPackages[$package]\".".PHP_EOL;
}
-foreach (glob("$pathToProject/var/cache/*") as $cacheDir) {
+foreach (glob("$pathToProject/var/cache/*", GLOB_NOSORT) as $cacheDir) {
$filesystem->remove($cacheDir);
}
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypePerformanceTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypePerformanceTest.php
index e5d4303911105..d7d7cae5ecda9 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypePerformanceTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypePerformanceTest.php
@@ -30,7 +30,7 @@ class EntityTypePerformanceTest extends FormPerformanceTestCase
*/
private $em;
- protected static $supportedFeatureSetVersion = 304;
+ protected static $supportedFeatureSetVersion = 403;
protected function getExtensions()
{
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php
index 0f530d37d62a4..0367fc3edfad4 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php
@@ -58,7 +58,7 @@ class EntityTypeTest extends BaseTypeTest
*/
private $emRegistry;
- protected static $supportedFeatureSetVersion = 304;
+ protected static $supportedFeatureSetVersion = 403;
protected function setUp(): void
{
@@ -187,7 +187,7 @@ public function testSetDataToUninitializedEntityWithNonRequiredQueryBuilder()
public function testConfigureQueryBuilderWithNonQueryBuilderAndNonClosure()
{
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
- $field = $this->factory->createNamed('name', static::TESTED_TYPE, null, [
+ $this->factory->createNamed('name', static::TESTED_TYPE, null, [
'em' => 'default',
'class' => self::SINGLE_IDENT_CLASS,
'query_builder' => new \stdClass(),
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php
index 2dcab2533d375..fbae0fbde2dac 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php
@@ -173,7 +173,7 @@ public function testClassValidator(bool $expected, string $classValidatorRegexp
public function regexpProvider()
{
return [
- [false, null],
+ [true, null],
[true, '{^'.preg_quote(DoctrineLoaderEntity::class).'$|^'.preg_quote(Entity::class).'$}'],
[false, '{^'.preg_quote(Entity::class).'$}'],
];
diff --git a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php
index 76a2b4d8b0288..138b5d1cbbeee 100644
--- a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php
+++ b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php
@@ -43,7 +43,7 @@ public function __construct(EntityManagerInterface $entityManager, string $class
public function loadClassMetadata(ClassMetadata $metadata): bool
{
$className = $metadata->getClassName();
- if (null === $this->classValidatorRegexp || !preg_match($this->classValidatorRegexp, $className)) {
+ if (null !== $this->classValidatorRegexp && !preg_match($this->classValidatorRegexp, $className)) {
return false;
}
diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php
index 03696c69f0e4d..ed84eedf4a92a 100644
--- a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php
+++ b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php
@@ -257,14 +257,11 @@ public function endTest($test, $time)
if (class_exists('PHPUnit_Util_Blacklist', false)) {
$Test = 'PHPUnit_Util_Test';
$BaseTestRunner = 'PHPUnit_Runner_BaseTestRunner';
- $Warning = 'PHPUnit_Framework_Warning';
} else {
$Test = 'PHPUnit\Util\Test';
$BaseTestRunner = 'PHPUnit\Runner\BaseTestRunner';
- $Warning = 'PHPUnit\Framework\Warning';
}
$className = \get_class($test);
- $classGroups = $Test::getGroups($className);
$groups = $Test::getGroups($className, $test->getName(false));
if (null !== $this->reportUselessTests) {
diff --git a/src/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php b/src/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php
index 612bec14e5329..8925d588772a8 100644
--- a/src/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php
+++ b/src/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php
@@ -28,7 +28,6 @@ public function compile(Compiler $compiler)
preg_match('/_([^_]+)$/', $this->getAttribute('name'), $matches);
- $label = null;
$arguments = iterator_to_array($this->getNode('arguments'));
$blockNameSuffix = $matches[1];
diff --git a/src/Symfony/Bridge/Twig/Node/TransNode.php b/src/Symfony/Bridge/Twig/Node/TransNode.php
index cedc6b740e08d..e844801a5f0ce 100644
--- a/src/Symfony/Bridge/Twig/Node/TransNode.php
+++ b/src/Symfony/Bridge/Twig/Node/TransNode.php
@@ -57,8 +57,6 @@ public function compile(Compiler $compiler)
}
list($msg, $defaults) = $this->compileString($this->getNode('body'), $defaults, (bool) $vars);
- $method = !$this->hasNode('count') ? 'trans' : 'transChoice';
-
$compiler
->write('echo $this->env->getExtension(\'Symfony\Bridge\Twig\Extension\TranslationExtension\')->trans(')
->subcompile($msg)
diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_horizontal_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_horizontal_layout.html.twig
index 7fcea4b0ecd25..e37de07d6b071 100644
--- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_horizontal_layout.html.twig
+++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_horizontal_layout.html.twig
@@ -82,7 +82,6 @@ col-sm-10
{{- form_widget(form) -}}
{{- form_help(form) -}}
- {{- form_errors(form) -}}
{#--#}
{%- endblock checkbox_row %}
diff --git a/src/Symfony/Bridge/Twig/Tests/AppVariableTest.php b/src/Symfony/Bridge/Twig/Tests/AppVariableTest.php
index 06130dc817f3a..59539f278c05a 100644
--- a/src/Symfony/Bridge/Twig/Tests/AppVariableTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/AppVariableTest.php
@@ -180,10 +180,10 @@ public function testGetFlashes()
$flashMessages = $this->setFlashMessages();
$this->assertEquals($flashMessages, $this->appVariable->getFlashes([]));
- $flashMessages = $this->setFlashMessages();
+ $this->setFlashMessages();
$this->assertEquals([], $this->appVariable->getFlashes('this-does-not-exist'));
- $flashMessages = $this->setFlashMessages();
+ $this->setFlashMessages();
$this->assertEquals(
['this-does-not-exist' => []],
$this->appVariable->getFlashes(['this-does-not-exist'])
diff --git a/src/Symfony/Bridge/Twig/Tests/Command/LintCommandTest.php b/src/Symfony/Bridge/Twig/Tests/Command/LintCommandTest.php
index c862b08fe111d..a3362372c662a 100644
--- a/src/Symfony/Bridge/Twig/Tests/Command/LintCommandTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Command/LintCommandTest.php
@@ -52,7 +52,7 @@ public function testLintFileNotReadable()
$filename = $this->createFile('');
unlink($filename);
- $ret = $tester->execute(['filename' => [$filename]], ['decorated' => false]);
+ $tester->execute(['filename' => [$filename]], ['decorated' => false]);
}
public function testLintFileCompileTimeException()
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/StopwatchExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/StopwatchExtensionTest.php
index 2b38122e56410..35f3baa1b9b99 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/StopwatchExtensionTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/StopwatchExtensionTest.php
@@ -34,7 +34,7 @@ public function testTiming($template, $events)
$twig->addExtension(new StopwatchExtension($this->getStopwatch($events)));
try {
- $nodes = $twig->render('template');
+ $twig->render('template');
} catch (RuntimeError $e) {
throw $e->getPrevious();
}
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php
index 81a5718496c02..7f2b3bb836b05 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php
@@ -58,14 +58,14 @@ public function testTransUnknownKeyword()
{
$this->expectException('Twig\Error\SyntaxError');
$this->expectExceptionMessage('Unexpected token. Twig was looking for the "with", "from", or "into" keyword in "index" at line 3.');
- $output = $this->getTemplate("{% trans \n\nfoo %}{% endtrans %}")->render();
+ $this->getTemplate("{% trans \n\nfoo %}{% endtrans %}")->render();
}
public function testTransComplexBody()
{
$this->expectException('Twig\Error\SyntaxError');
$this->expectExceptionMessage('A message inside a trans tag must be a simple text in "index" at line 2.');
- $output = $this->getTemplate("{% trans %}\n{{ 1 + 2 }}{% endtrans %}")->render();
+ $this->getTemplate("{% trans %}\n{{ 1 + 2 }}{% endtrans %}")->render();
}
/**
@@ -75,7 +75,7 @@ public function testTransChoiceComplexBody()
{
$this->expectException('Twig\Error\SyntaxError');
$this->expectExceptionMessage('A message inside a transchoice tag must be a simple text in "index" at line 2.');
- $output = $this->getTemplate("{% transchoice count %}\n{{ 1 + 2 }}{% endtranschoice %}")->render();
+ $this->getTemplate("{% transchoice count %}\n{{ 1 + 2 }}{% endtranschoice %}")->render();
}
public function getTransTests()
diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
index 6687647ed8ce0..7fa6f3fc7a8dc 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php
@@ -508,7 +508,6 @@ private function renderEventListenerTable(EventDispatcherInterface $eventDispatc
$tableHeaders = ['Order', 'Callable', 'Priority'];
$tableRows = [];
- $order = 1;
foreach ($eventListeners as $order => $listener) {
$tableRows[] = [sprintf('#%d', $order + 1), $this->formatCallable($listener), $eventDispatcher->getListenerPriority($event, $listener)];
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
index 6d6195bbc9956..2b76352048c1c 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php
@@ -303,7 +303,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode)
->end()
->end()
->scalarNode('property')
- ->defaultValue('marking')
+ ->defaultNull() // In Symfony 5.0, set "marking" as default property
->end()
->scalarNode('service')
->cannotBeEmpty()
@@ -481,6 +481,14 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode)
return $v;
})
->end()
+ ->validate()
+ ->ifTrue(function ($v) {
+ return isset($v['marking_store']['property'])
+ && (!isset($v['marking_store']['type']) || 'method' !== $v['marking_store']['type'])
+ ;
+ })
+ ->thenInvalid('"property" option is only supported by the "method" marking store.')
+ ->end()
->end()
->end()
->end()
@@ -542,7 +550,7 @@ private function addSessionSection(ArrayNodeDefinition $rootNode)
->scalarNode('cookie_domain')->end()
->enumNode('cookie_secure')->values([true, false, 'auto'])->end()
->booleanNode('cookie_httponly')->defaultTrue()->end()
- ->enumNode('cookie_samesite')->values([null, Cookie::SAMESITE_LAX, Cookie::SAMESITE_STRICT])->defaultNull()->end()
+ ->enumNode('cookie_samesite')->values([null, Cookie::SAMESITE_LAX, Cookie::SAMESITE_STRICT, Cookie::SAMESITE_NONE])->defaultNull()->end()
->booleanNode('use_cookies')->end()
->scalarNode('gc_divisor')->end()
->scalarNode('gc_probability')->defaultValue(1)->end()
diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
index 8cb3fdd242cde..a913f4f93db40 100644
--- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php
@@ -666,7 +666,7 @@ private function registerWorkflowConfiguration(array $config, ContainerBuilder $
if ('method' === $workflow['marking_store']['type']) {
$markingStoreDefinition->setArguments([
'state_machine' === $type, //single state
- $workflow['marking_store']['property'],
+ $workflow['marking_store']['property'] ?? 'marking',
]);
} else {
foreach ($workflow['marking_store']['arguments'] as $argument) {
@@ -997,8 +997,6 @@ private function registerAssetsConfiguration(array $config, ContainerBuilder $co
{
$loader->load('assets.xml');
- $defaultVersion = null;
-
if ($config['version_strategy']) {
$defaultVersion = new Reference($config['version_strategy']);
} else {
@@ -1649,6 +1647,7 @@ private function registerMessengerConfiguration(array $config, ContainerBuilder
$defaultMiddleware = [
'before' => [
['id' => 'add_bus_name_stamp_middleware'],
+ ['id' => 'reject_redelivered_message_middleware'],
['id' => 'dispatch_after_current_bus'],
['id' => 'failed_message_processing_middleware'],
],
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml
index 5ef47e751efd0..f50b613dc7856 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.xml
@@ -48,6 +48,8 @@
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php b/src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php
index 1e6b90a9bf107..03b87fd6ebb8d 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Routing/DelegatingLoader.php
@@ -98,11 +98,6 @@ public function load($resource, $type = null)
}
}
- if (1 === substr_count($controller, ':')) {
- $nonDeprecatedNotation = str_replace(':', '::', $controller);
- // TODO deprecate this in 5.1
- }
-
$route->setDefault('_controller', $controller);
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php
index b65c6421a7525..7586e29818b02 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php
@@ -277,8 +277,7 @@ public function testFileWhichDoesNotExist()
$this->expectException('Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException');
$controller = $this->createController();
- /* @var BinaryFileResponse $response */
- $response = $controller->file('some-file.txt', 'test.php');
+ $controller->file('some-file.txt', 'test.php');
}
public function testIsGranted()
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
index 8f54c30c091ee..5f2e007ddbcd4 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
@@ -316,7 +316,7 @@ public function testWorkflowLegacy()
public function testWorkflowAreValidated()
{
$this->expectException('Symfony\Component\Workflow\Exception\InvalidDefinitionException');
- $this->expectExceptionMessage('A transition from a place/state must have an unique name. Multiple transitions named "go" from place/state "first" where found on StateMachine "my_workflow".');
+ $this->expectExceptionMessage('A transition from a place/state must have an unique name. Multiple transitions named "go" from place/state "first" were found on StateMachine "my_workflow".');
$this->createContainerFromFile('workflow_not_valid');
}
@@ -739,6 +739,7 @@ public function testMessengerWithMultipleBuses()
$this->assertSame([], $container->getDefinition('messenger.bus.commands')->getArgument(0));
$this->assertEquals([
['id' => 'add_bus_name_stamp_middleware', 'arguments' => ['messenger.bus.commands']],
+ ['id' => 'reject_redelivered_message_middleware'],
['id' => 'dispatch_after_current_bus'],
['id' => 'failed_message_processing_middleware'],
['id' => 'send_message'],
@@ -748,6 +749,7 @@ public function testMessengerWithMultipleBuses()
$this->assertSame([], $container->getDefinition('messenger.bus.events')->getArgument(0));
$this->assertEquals([
['id' => 'add_bus_name_stamp_middleware', 'arguments' => ['messenger.bus.events']],
+ ['id' => 'reject_redelivered_message_middleware'],
['id' => 'dispatch_after_current_bus'],
['id' => 'failed_message_processing_middleware'],
['id' => 'with_factory', 'arguments' => ['foo', true, ['bar' => 'baz']]],
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php
index 66099e29cc33e..da540da12b1f9 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/PhpFrameworkExtensionTest.php
@@ -56,7 +56,7 @@ public function testAssetPackageCannotHavePathAndUrl()
public function testWorkflowValidationStateMachine()
{
$this->expectException('Symfony\Component\Workflow\Exception\InvalidDefinitionException');
- $this->expectExceptionMessage('A transition from a place/state must have an unique name. Multiple transitions named "a_to_b" from place/state "a" where found on StateMachine "article".');
+ $this->expectExceptionMessage('A transition from a place/state must have an unique name. Multiple transitions named "a_to_b" from place/state "a" were found on StateMachine "article".');
$this->createContainerFromClosure(function ($container) {
$container->loadFromExtension('framework', [
'workflows' => [
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/DependencyInjection/TestExtension.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/DependencyInjection/TestExtension.php
index 59670fdd19a24..0ae7669ce803a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/DependencyInjection/TestExtension.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/DependencyInjection/TestExtension.php
@@ -26,7 +26,7 @@ class TestExtension extends Extension implements PrependExtensionInterface
public function load(array $configs, ContainerBuilder $container)
{
$configuration = $this->getConfiguration($configs, $container);
- $config = $this->processConfiguration($configuration, $configs);
+ $this->processConfiguration($configuration, $configs);
$container->setAlias('test.annotation_reader', new Alias('annotation_reader', true));
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDumpTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDumpTest.php
index 8f826714782a9..f543058440582 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDumpTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDumpTest.php
@@ -18,14 +18,14 @@ class ContainerDumpTest extends AbstractWebTestCase
{
public function testContainerCompilationInDebug()
{
- $client = $this->createClient(['test_case' => 'ContainerDump', 'root_config' => 'config.yml']);
+ $this->createClient(['test_case' => 'ContainerDump', 'root_config' => 'config.yml']);
$this->assertTrue(static::$container->has('serializer'));
}
public function testContainerCompilation()
{
- $client = $this->createClient(['test_case' => 'ContainerDump', 'root_config' => 'config.yml', 'debug' => false]);
+ $this->createClient(['test_case' => 'ContainerDump', 'root_config' => 'config.yml', 'debug' => false]);
$this->assertTrue(static::$container->has('serializer'));
}
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SessionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SessionTest.php
index c99b5e073e49a..3a87f7e4e6e0a 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SessionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SessionTest.php
@@ -59,7 +59,7 @@ public function testFlash($config, $insulate)
}
// set flash
- $crawler = $client->request('GET', '/session_setflash/Hello%20world.');
+ $client->request('GET', '/session_setflash/Hello%20world.');
// check flash displays on redirect
$this->assertStringContainsString('Hello world.', $client->followRedirect()->text());
diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json
index 2c198d2ca7105..57c344f68f22e 100644
--- a/src/Symfony/Bundle/FrameworkBundle/composer.json
+++ b/src/Symfony/Bundle/FrameworkBundle/composer.json
@@ -42,7 +42,7 @@
"symfony/expression-language": "~3.4|~4.0",
"symfony/http-client": "^4.3",
"symfony/mailer": "^4.3",
- "symfony/messenger": "^4.3",
+ "symfony/messenger": "^4.3.6",
"symfony/mime": "^4.3",
"symfony/process": "~3.4|~4.0",
"symfony/security-csrf": "~3.4|~4.0",
@@ -54,7 +54,7 @@
"symfony/twig-bundle": "~2.8|~3.2|~4.0",
"symfony/validator": "^4.1",
"symfony/var-dumper": "^4.3",
- "symfony/workflow": "^4.3",
+ "symfony/workflow": "^4.3.6",
"symfony/yaml": "~3.4|~4.0",
"symfony/property-info": "~3.4|~4.0",
"symfony/lock": "~3.4|~4.0",
@@ -73,14 +73,14 @@
"symfony/dotenv": "<4.2",
"symfony/dom-crawler": "<4.3",
"symfony/form": "<4.3",
- "symfony/messenger": "<4.3",
+ "symfony/messenger": "<4.3.6",
"symfony/property-info": "<3.4",
"symfony/serializer": "<4.2",
"symfony/stopwatch": "<3.4",
"symfony/translation": "<4.3",
"symfony/twig-bridge": "<4.1.1",
"symfony/validator": "<4.1",
- "symfony/workflow": "<4.3"
+ "symfony/workflow": "<4.3.6"
},
"suggest": {
"ext-apcu": "For best performance of the system caches",
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php
index f7500f05e3b9f..28103a3522542 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php
@@ -144,7 +144,7 @@ public function addConfiguration(NodeDefinition $node)
if ('secure' === $name) {
$builder->enumNode($name)->values([true, false, 'auto'])->defaultValue('auto' === $value ? null : $value);
} elseif ('samesite' === $name) {
- $builder->enumNode($name)->values([null, Cookie::SAMESITE_LAX, Cookie::SAMESITE_STRICT])->defaultValue($value);
+ $builder->enumNode($name)->values([null, Cookie::SAMESITE_LAX, Cookie::SAMESITE_STRICT, Cookie::SAMESITE_NONE])->defaultValue($value);
} elseif (\is_bool($value)) {
$builder->booleanNode($name)->defaultValue($value);
} else {
diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml
index 1d2f0c4e503b3..9dfa8c2337dc4 100644
--- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml
+++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml
@@ -148,15 +148,15 @@
-
-
+ false
+ false
-
+ null
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php
index 7e583facf7b09..450cb68ab119a 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php
@@ -258,7 +258,6 @@ public function providerCollectDecisionLog(): \Generator
$eventDispatcher = $this->getMockBuilder(EventDispatcherInterface::class)->getMockForAbstractClass();
$decoratedVoter1 = new TraceableVoter($voter1, $eventDispatcher);
- $decoratedVoter2 = new TraceableVoter($voter2, $eventDispatcher);
yield [
AccessDecisionManager::STRATEGY_AFFIRMATIVE,
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AbstractFactoryTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AbstractFactoryTest.php
index 9eb9a08177700..01e03b0312bd9 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AbstractFactoryTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/AbstractFactoryTest.php
@@ -61,7 +61,7 @@ public function testDefaultFailureHandler($serviceId, $defaultHandlerInjection)
$options['failure_handler'] = $serviceId;
}
- list($container, $authProviderId, $listenerId, $entryPointId) = $this->callFactory('foo', $options, 'user_provider', 'entry_point');
+ list($container) = $this->callFactory('foo', $options, 'user_provider', 'entry_point');
$definition = $container->getDefinition('abstract_listener.foo');
$arguments = $definition->getArguments();
@@ -99,7 +99,7 @@ public function testDefaultSuccessHandler($serviceId, $defaultHandlerInjection)
$options['success_handler'] = $serviceId;
}
- list($container, $authProviderId, $listenerId, $entryPointId) = $this->callFactory('foo', $options, 'user_provider', 'entry_point');
+ list($container) = $this->callFactory('foo', $options, 'user_provider', 'entry_point');
$definition = $container->getDefinition('abstract_listener.foo');
$arguments = $definition->getArguments();
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/GuardAuthenticationFactoryTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/GuardAuthenticationFactoryTest.php
index f327eece8f99c..fd812c13ae04c 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/GuardAuthenticationFactoryTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Security/Factory/GuardAuthenticationFactoryTest.php
@@ -159,7 +159,7 @@ public function testCreateWithEntryPoint()
'authenticators' => ['authenticator123', 'authenticatorABC'],
'entry_point' => 'authenticatorABC',
];
- list($container, $entryPointId) = $this->executeCreate($config, null);
+ list(, $entryPointId) = $this->executeCreate($config, null);
$this->assertEquals('authenticatorABC', $entryPointId);
}
@@ -172,7 +172,7 @@ private function executeCreate(array $config, $defaultEntryPointId)
$userProviderId = 'my_user_provider';
$factory = new GuardAuthenticationFactory();
- list($providerId, $listenerId, $entryPointId) = $factory->create($container, $id, $config, $userProviderId, $defaultEntryPointId);
+ list(, , $entryPointId) = $factory->create($container, $id, $config, $userProviderId, $defaultEntryPointId);
return [$container, $entryPointId];
}
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/MissingUserProviderTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/MissingUserProviderTest.php
index d795980b3ef38..6c8ba6482e45b 100644
--- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/MissingUserProviderTest.php
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/MissingUserProviderTest.php
@@ -24,7 +24,7 @@ public function testUserProviderIsNeeded()
$response = $client->getResponse();
$this->assertSame(500, $response->getStatusCode());
- $this->stringContains('Symfony\Component\Config\Definition\Exception\InvalidConfigurationException', $response->getContent());
- $this->stringContains('"default" firewall requires a user provider but none was defined.', $response->getContent());
+ $this->assertStringContainsString('Symfony\Component\Config\Definition\Exception\InvalidConfigurationException', $response->getContent());
+ $this->assertStringContainsString('"default" firewall requires a user provider but none was defined', html_entity_decode($response->getContent()));
}
}
diff --git a/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig b/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig
index 8c1f9af2a0d18..b7eb560002f9b 100644
--- a/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig
+++ b/src/Symfony/Bundle/TwigBundle/Resources/views/exception.css.twig
@@ -28,6 +28,7 @@
--shadow: 0px 0px 1px rgba(128, 128, 128, .2);
--border: 1px solid #e0e0e0;
--background-error: var(--color-error);
+ --trace-selected-background: #F7E5A1;
--highlight-comment: #969896;
--highlight-default: #222222;
--highlight-keyword: #a71d5d;
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig
index d737ab0e063ad..e5a731cf19ca8 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig
+++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig
@@ -46,6 +46,8 @@
--base-4: #666;
--base-5: #444;
--base-6: #222;
+ --card-label-background: #eee;
+ --card-label-color: var(--base-6);
}
.theme-dark {
@@ -85,6 +87,8 @@
--base-4: #666;
--base-5: #e0e0e0;
--base-6: #f5f5f5;
+ --card-label-background: var(--tab-active-background);
+ --card-label-color: var(--tab-active-color);
}
{# Basic styles
@@ -436,8 +440,8 @@ table tbody td.num-col {
margin-top: 0;
}
.card .label {
- background-color: #EEE;
- color: var(--base-6);
+ background-color: var(--card-label-background);
+ color: var(--card-label-color);
}
{# Status
diff --git a/src/Symfony/Component/BrowserKit/Tests/CookieTest.php b/src/Symfony/Component/BrowserKit/Tests/CookieTest.php
index b705e6c6d4fdd..6318cae2d5c16 100644
--- a/src/Symfony/Component/BrowserKit/Tests/CookieTest.php
+++ b/src/Symfony/Component/BrowserKit/Tests/CookieTest.php
@@ -201,7 +201,7 @@ public function testConstructException()
{
$this->expectException('UnexpectedValueException');
$this->expectExceptionMessage('The cookie expiration time "string" is not valid.');
- $cookie = new Cookie('foo', 'bar', 'string');
+ new Cookie('foo', 'bar', 'string');
}
public function testSameSite()
diff --git a/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php
index 5e535e51fcb4b..13a4968ac596d 100644
--- a/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/AbstractTagAwareAdapter.php
@@ -229,10 +229,14 @@ public function deleteItems(array $keys)
unset($this->deferred[$key]);
}
- foreach ($this->doFetch($ids) as $id => $value) {
- foreach ($value['tags'] ?? [] as $tag) {
- $tagData[$this->getId(self::TAGS_PREFIX.$tag)][] = $id;
+ try {
+ foreach ($this->doFetch($ids) as $id => $value) {
+ foreach ($value['tags'] ?? [] as $tag) {
+ $tagData[$this->getId(self::TAGS_PREFIX.$tag)][] = $id;
+ }
}
+ } catch (\Exception $e) {
+ // ignore unserialization failures
}
try {
diff --git a/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php
index 0dd81a99704ed..67801e8ab9cc7 100644
--- a/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/FilesystemTagAwareAdapter.php
@@ -11,12 +11,10 @@
namespace Symfony\Component\Cache\Adapter;
-use Symfony\Component\Cache\Exception\LogicException;
use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
use Symfony\Component\Cache\PruneableInterface;
use Symfony\Component\Cache\Traits\FilesystemTrait;
-use Symfony\Component\Filesystem\Filesystem;
/**
* Stores tag id <> cache id relationship as a symlink, and lookup on invalidation calls.
@@ -29,8 +27,8 @@
class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements PruneableInterface
{
use FilesystemTrait {
- doSave as doSaveCache;
- doDelete as doDeleteCache;
+ doSave as private doSaveCache;
+ doDelete as private doDeleteCache;
}
/**
@@ -38,11 +36,6 @@ class FilesystemTagAwareAdapter extends AbstractTagAwareAdapter implements Prune
*/
private const TAG_FOLDER = 'tags';
- /**
- * @var Filesystem|null
- */
- private $fs;
-
public function __construct(string $namespace = '', int $defaultLifetime = 0, string $directory = null, MarshallerInterface $marshaller = null)
{
$this->marshaller = $marshaller ?? new DefaultMarshaller();
@@ -57,7 +50,6 @@ protected function doSave(array $values, ?int $lifetime, array $addTagData = [],
{
$failed = $this->doSaveCache($values, $lifetime);
- $fs = $this->getFilesystem();
// Add Tags as symlinks
foreach ($addTagData as $tagId => $ids) {
$tagFolder = $this->getTagFolder($tagId);
@@ -67,12 +59,15 @@ protected function doSave(array $values, ?int $lifetime, array $addTagData = [],
}
$file = $this->getFile($id);
- $fs->symlink($file, $this->getFile($id, true, $tagFolder));
+
+ if (!@symlink($file, $this->getFile($id, true, $tagFolder))) {
+ @unlink($file);
+ $failed[] = $id;
+ }
}
}
// Unlink removed Tags
- $files = [];
foreach ($removeTagData as $tagId => $ids) {
$tagFolder = $this->getTagFolder($tagId);
foreach ($ids as $id) {
@@ -80,10 +75,9 @@ protected function doSave(array $values, ?int $lifetime, array $addTagData = [],
continue;
}
- $files[] = $this->getFile($id, false, $tagFolder);
+ @unlink($this->getFile($id, false, $tagFolder));
}
}
- $fs->remove($files);
return $failed;
}
@@ -96,15 +90,12 @@ protected function doDelete(array $ids, array $tagData = []): bool
$ok = $this->doDeleteCache($ids);
// Remove tags
- $files = [];
- $fs = $this->getFilesystem();
foreach ($tagData as $tagId => $idMap) {
$tagFolder = $this->getTagFolder($tagId);
foreach ($idMap as $id) {
- $files[] = $this->getFile($id, false, $tagFolder);
+ @unlink($this->getFile($id, false, $tagFolder));
}
}
- $fs->remove($files);
return $ok;
}
@@ -115,33 +106,45 @@ protected function doDelete(array $ids, array $tagData = []): bool
protected function doInvalidate(array $tagIds): bool
{
foreach ($tagIds as $tagId) {
- $tagsFolder = $this->getTagFolder($tagId);
- if (!file_exists($tagsFolder)) {
+ if (!file_exists($tagFolder = $this->getTagFolder($tagId))) {
continue;
}
- foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($tagsFolder, \FilesystemIterator::SKIP_DOTS)) as $itemLink) {
- if (!$itemLink->isLink()) {
- throw new LogicException('Expected a (sym)link when iterating over tag folder, non link found: '.$itemLink);
+ set_error_handler(static function () {});
+
+ try {
+ if (rename($tagFolder, $renamed = substr_replace($tagFolder, bin2hex(random_bytes(4)), -1))) {
+ $tagFolder = $renamed.\DIRECTORY_SEPARATOR;
+ } else {
+ $renamed = null;
+ }
+
+ foreach (new \RecursiveIteratorIterator(new \RecursiveDirectoryIterator($tagFolder, \FilesystemIterator::SKIP_DOTS | \FilesystemIterator::CURRENT_AS_PATHNAME)) as $itemLink) {
+ unlink(realpath($itemLink) ?: $itemLink);
+ unlink($itemLink);
}
- $valueFile = $itemLink->getRealPath();
- if ($valueFile && file_exists($valueFile)) {
- @unlink($valueFile);
+ if (null === $renamed) {
+ continue;
}
- @unlink((string) $itemLink);
+ $chars = '+-ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
+
+ for ($i = 0; $i < 38; ++$i) {
+ for ($j = 0; $j < 38; ++$j) {
+ rmdir($tagFolder.$chars[$i].\DIRECTORY_SEPARATOR.$chars[$j]);
+ }
+ rmdir($tagFolder.$chars[$i]);
+ }
+ rmdir($renamed);
+ } finally {
+ restore_error_handler();
}
}
return true;
}
- private function getFilesystem(): Filesystem
- {
- return $this->fs ?? $this->fs = new Filesystem();
- }
-
private function getTagFolder(string $tagId): string
{
return $this->getFile($tagId, false, $this->directory.self::TAG_FOLDER.\DIRECTORY_SEPARATOR).\DIRECTORY_SEPARATOR;
diff --git a/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php
index 3bc5d84b62eab..b83b09b013dee 100644
--- a/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php
@@ -97,7 +97,7 @@ protected function doSave(array $values, ?int $lifetime, array $addTagData = [],
}
// While pipeline isn't supported on RedisCluster, other setups will at least benefit from doing this in one op
- $results = $this->pipeline(static function () use ($serialized, $lifetime, $addTagData, $delTagData) {
+ $results = $this->pipeline(static function () use ($serialized, $lifetime, $addTagData, $delTagData, $failed) {
// Store cache items, force a ttl if none is set, as there is no MSETEX we need to set each one
foreach ($serialized as $id => $value) {
yield 'setEx' => [
@@ -109,11 +109,15 @@ protected function doSave(array $values, ?int $lifetime, array $addTagData = [],
// Add and Remove Tags
foreach ($addTagData as $tagId => $ids) {
- yield 'sAdd' => array_merge([$tagId], $ids);
+ if (!$failed || $ids = array_diff($ids, $failed)) {
+ yield 'sAdd' => array_merge([$tagId], $ids);
+ }
}
foreach ($delTagData as $tagId => $ids) {
- yield 'sRem' => array_merge([$tagId], $ids);
+ if (!$failed || $ids = array_diff($ids, $failed)) {
+ yield 'sRem' => array_merge([$tagId], $ids);
+ }
}
});
diff --git a/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php
index fd810f726ea73..8bcf57e82c16a 100644
--- a/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php
@@ -160,7 +160,14 @@ public function hasItem($key)
if (!$this->pool->hasItem($key)) {
return false;
}
- if (!$itemTags = $this->pool->getItem(static::TAGS_PREFIX.$key)->get()) {
+
+ $itemTags = $this->pool->getItem(static::TAGS_PREFIX.$key);
+
+ if (!$itemTags->isHit()) {
+ return false;
+ }
+
+ if (!$itemTags = $itemTags->get()) {
return true;
}
@@ -300,7 +307,10 @@ private function generateItems($items, array $tagKeys)
}
unset($tagKeys[$key]);
- $itemTags[$key] = $item->get() ?: [];
+
+ if ($item->isHit()) {
+ $itemTags[$key] = $item->get() ?: [];
+ }
if (!$tagKeys) {
$tagVersions = $this->getTagVersions($itemTags);
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
index 63a7f39e537c2..a6132ebca2fc9 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
@@ -87,8 +87,8 @@ public function testRecursiveGet()
$cache = $this->createCachePool(0, __FUNCTION__);
$v = $cache->get('k1', function () use (&$counter, $cache) {
- $v = $cache->get('k2', function () use (&$counter) { return ++$counter; });
- $v = $cache->get('k2', function () use (&$counter) { return ++$counter; });
+ $cache->get('k2', function () use (&$counter) { return ++$counter; });
+ $v = $cache->get('k2', function () use (&$counter) { return ++$counter; }); // ensure the callback is called once
return $v;
});
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/MaxIdLengthAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/MaxIdLengthAdapterTest.php
index 724aa9451cbce..8d0b70d619690 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/MaxIdLengthAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/MaxIdLengthAdapterTest.php
@@ -70,7 +70,7 @@ public function testTooLongNamespace()
{
$this->expectException('Symfony\Component\Cache\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Namespace must be 26 chars max, 40 given ("----------------------------------------")');
- $cache = $this->getMockBuilder(MaxIdLengthAdapter::class)
+ $this->getMockBuilder(MaxIdLengthAdapter::class)
->setConstructorArgs([str_repeat('-', 40)])
->getMock();
}
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/NullAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/NullAdapterTest.php
index 6c5710a7e4e29..ae3de76dc135d 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/NullAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/NullAdapterTest.php
@@ -39,7 +39,7 @@ public function testGet()
$adapter = $this->createCachePool();
$fetched = [];
- $item = $adapter->get('myKey', function ($item) use (&$fetched) { $fetched[] = $item; });
+ $adapter->get('myKey', function ($item) use (&$fetched) { $fetched[] = $item; });
$this->assertCount(1, $fetched);
$item = $fetched[0];
$this->assertFalse($item->isHit());
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PdoDbalAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PdoDbalAdapterTest.php
index 573a1b1d01394..d4071baedbc91 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/PdoDbalAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/PdoDbalAdapterTest.php
@@ -31,8 +31,6 @@ public static function setUpBeforeClass(): void
}
self::$dbFile = tempnam(sys_get_temp_dir(), 'sf_sqlite_cache');
-
- $pool = new PdoAdapter(DriverManager::getConnection(['driver' => 'pdo_sqlite', 'path' => self::$dbFile]));
}
public static function tearDownAfterClass(): void
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php
index ef939bae8c929..b4e1ebbcd83c6 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php
@@ -99,6 +99,84 @@ public function testKnownTagVersionsTtl()
$this->assertTrue($pool->getItem('foo')->isHit());
}
+ public function testTagEntryIsCreatedForItemWithoutTags()
+ {
+ $pool = $this->createCachePool();
+
+ $itemKey = 'foo';
+ $item = $pool->getItem($itemKey);
+ $pool->save($item);
+
+ $adapter = new FilesystemAdapter();
+ $this->assertTrue($adapter->hasItem(TagAwareAdapter::TAGS_PREFIX.$itemKey));
+ }
+
+ public function testHasItemReturnsFalseWhenPoolDoesNotHaveItemTags()
+ {
+ $pool = $this->createCachePool();
+
+ $itemKey = 'foo';
+ $item = $pool->getItem($itemKey);
+ $pool->save($item);
+
+ $anotherPool = $this->createCachePool();
+
+ $adapter = new FilesystemAdapter();
+ $adapter->deleteItem(TagAwareAdapter::TAGS_PREFIX.$itemKey); //simulate item losing tags pair
+
+ $this->assertFalse($anotherPool->hasItem($itemKey));
+ }
+
+ public function testGetItemReturnsCacheMissWhenPoolDoesNotHaveItemTags()
+ {
+ $pool = $this->createCachePool();
+
+ $itemKey = 'foo';
+ $item = $pool->getItem($itemKey);
+ $pool->save($item);
+
+ $anotherPool = $this->createCachePool();
+
+ $adapter = new FilesystemAdapter();
+ $adapter->deleteItem(TagAwareAdapter::TAGS_PREFIX.$itemKey); //simulate item losing tags pair
+
+ $item = $anotherPool->getItem($itemKey);
+ $this->assertFalse($item->isHit());
+ }
+
+ public function testHasItemReturnsFalseWhenPoolDoesNotHaveItemAndOnlyHasTags()
+ {
+ $pool = $this->createCachePool();
+
+ $itemKey = 'foo';
+ $item = $pool->getItem($itemKey);
+ $pool->save($item);
+
+ $anotherPool = $this->createCachePool();
+
+ $adapter = new FilesystemAdapter();
+ $adapter->deleteItem($itemKey); //simulate losing item but keeping tags
+
+ $this->assertFalse($anotherPool->hasItem($itemKey));
+ }
+
+ public function testGetItemReturnsCacheMissWhenPoolDoesNotHaveItemAndOnlyHasTags()
+ {
+ $pool = $this->createCachePool();
+
+ $itemKey = 'foo';
+ $item = $pool->getItem($itemKey);
+ $pool->save($item);
+
+ $anotherPool = $this->createCachePool();
+
+ $adapter = new FilesystemAdapter();
+ $adapter->deleteItem($itemKey); //simulate losing item but keeping tags
+
+ $item = $anotherPool->getItem($itemKey);
+ $this->assertFalse($item->isHit());
+ }
+
/**
* @return MockObject|PruneableCacheInterface
*/
diff --git a/src/Symfony/Component/Cache/Traits/MemcachedTrait.php b/src/Symfony/Component/Cache/Traits/MemcachedTrait.php
index 484c44a7eb3a4..ccfc66b4a785a 100644
--- a/src/Symfony/Component/Cache/Traits/MemcachedTrait.php
+++ b/src/Symfony/Component/Cache/Traits/MemcachedTrait.php
@@ -281,6 +281,7 @@ protected function doDelete(array $ids)
foreach ($this->checkResultCode($this->getClient()->deleteMulti($encodedIds)) as $result) {
if (\Memcached::RES_SUCCESS !== $result && \Memcached::RES_NOTFOUND !== $result) {
$ok = false;
+ break;
}
}
diff --git a/src/Symfony/Component/Config/Resource/GlobResource.php b/src/Symfony/Component/Config/Resource/GlobResource.php
index fce8f6e2062a0..bf332fde32722 100644
--- a/src/Symfony/Component/Config/Resource/GlobResource.php
+++ b/src/Symfony/Component/Config/Resource/GlobResource.php
@@ -99,7 +99,9 @@ public function getIterator()
$prefix = str_replace('\\', '/', $this->prefix);
if (0 !== strpos($this->prefix, 'phar://') && false === strpos($this->pattern, '/**/') && (\defined('GLOB_BRACE') || false === strpos($this->pattern, '{'))) {
- foreach (glob($this->prefix.$this->pattern, \defined('GLOB_BRACE') ? GLOB_BRACE : 0) as $path) {
+ $paths = glob($this->prefix.$this->pattern, GLOB_NOSORT | (\defined('GLOB_BRACE') ? GLOB_BRACE : 0));
+ sort($paths);
+ foreach ($paths as $path) {
if ($this->excludedPrefixes) {
$normalizedPath = str_replace('\\', '/', $path);
do {
diff --git a/src/Symfony/Component/Config/ResourceCheckerConfigCache.php b/src/Symfony/Component/Config/ResourceCheckerConfigCache.php
index 34dc35d5f51f8..c30686721a6cc 100644
--- a/src/Symfony/Component/Config/ResourceCheckerConfigCache.php
+++ b/src/Symfony/Component/Config/ResourceCheckerConfigCache.php
@@ -154,7 +154,6 @@ private function getMetaFile()
private function safelyUnserialize($file)
{
- $e = null;
$meta = false;
$content = file_get_contents($file);
$signalingException = new \UnexpectedValueException();
diff --git a/src/Symfony/Component/Config/Tests/Loader/DelegatingLoaderTest.php b/src/Symfony/Component/Config/Tests/Loader/DelegatingLoaderTest.php
index 07bd379b27a37..78c83044d8bc1 100644
--- a/src/Symfony/Component/Config/Tests/Loader/DelegatingLoaderTest.php
+++ b/src/Symfony/Component/Config/Tests/Loader/DelegatingLoaderTest.php
@@ -19,7 +19,7 @@ class DelegatingLoaderTest extends TestCase
{
public function testConstructor()
{
- $loader = new DelegatingLoader($resolver = new LoaderResolver());
+ new DelegatingLoader($resolver = new LoaderResolver());
$this->assertTrue(true, '__construct() takes a loader resolver as its first argument');
}
diff --git a/src/Symfony/Component/Config/Tests/Resource/ClassExistenceResourceTest.php b/src/Symfony/Component/Config/Tests/Resource/ClassExistenceResourceTest.php
index 6b38e33baf4a2..ad331240debaf 100644
--- a/src/Symfony/Component/Config/Tests/Resource/ClassExistenceResourceTest.php
+++ b/src/Symfony/Component/Config/Tests/Resource/ClassExistenceResourceTest.php
@@ -67,7 +67,7 @@ public function testExistsKo()
$loadedClass = 123;
- $res = new ClassExistenceResource('MissingFooClass', false);
+ new ClassExistenceResource('MissingFooClass', false);
$this->assertSame(123, $loadedClass);
} finally {
diff --git a/src/Symfony/Component/Config/Tests/Resource/DirectoryResourceTest.php b/src/Symfony/Component/Config/Tests/Resource/DirectoryResourceTest.php
index 90b70cc7249e7..aaadc8c4f430b 100644
--- a/src/Symfony/Component/Config/Tests/Resource/DirectoryResourceTest.php
+++ b/src/Symfony/Component/Config/Tests/Resource/DirectoryResourceTest.php
@@ -67,7 +67,7 @@ public function testResourceDoesNotExist()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessageRegExp('/The directory ".*" does not exist./');
- $resource = new DirectoryResource('/____foo/foobar'.mt_rand(1, 999999));
+ new DirectoryResource('/____foo/foobar'.mt_rand(1, 999999));
}
public function testIsFresh()
@@ -165,7 +165,7 @@ public function testSerializeUnserialize()
{
$resource = new DirectoryResource($this->directory, '/\.(foo|xml)$/');
- $unserialized = unserialize(serialize($resource));
+ unserialize(serialize($resource));
$this->assertSame(realpath($this->directory), $resource->getResource());
$this->assertSame('/\.(foo|xml)$/', $resource->getPattern());
diff --git a/src/Symfony/Component/Config/Tests/Resource/FileResourceTest.php b/src/Symfony/Component/Config/Tests/Resource/FileResourceTest.php
index 864604bb5b38f..f85a820fb95bb 100644
--- a/src/Symfony/Component/Config/Tests/Resource/FileResourceTest.php
+++ b/src/Symfony/Component/Config/Tests/Resource/FileResourceTest.php
@@ -57,7 +57,7 @@ public function testResourceDoesNotExist()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessageRegExp('/The file ".*" does not exist./');
- $resource = new FileResource('/____foo/foobar'.mt_rand(1, 999999));
+ new FileResource('/____foo/foobar'.mt_rand(1, 999999));
}
public function testIsFresh()
@@ -76,7 +76,7 @@ public function testIsFreshForDeletedResources()
public function testSerializeUnserialize()
{
- $unserialized = unserialize(serialize($this->resource));
+ unserialize(serialize($this->resource));
$this->assertSame(realpath($this->file), $this->resource->getResource());
}
diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php
index 6bf1c4a50e5ae..ed72c6dfae926 100644
--- a/src/Symfony/Component/Console/Tests/ApplicationTest.php
+++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php
@@ -568,7 +568,7 @@ public function testFindAlternativeExceptionMessageMultiple()
// Subnamespace + plural
try {
- $a = $application->find('foo3:');
+ $application->find('foo3:');
$this->fail('->find() should throw an Symfony\Component\Console\Exception\CommandNotFoundException if a command is ambiguous because of a subnamespace, with alternatives');
} catch (\Exception $e) {
$this->assertInstanceOf('Symfony\Component\Console\Exception\CommandNotFoundException', $e);
diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressIndicatorTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressIndicatorTest.php
index 6d803fc251efe..1428cf5e97a5f 100644
--- a/src/Symfony/Component/Console/Tests/Helper/ProgressIndicatorTest.php
+++ b/src/Symfony/Component/Console/Tests/Helper/ProgressIndicatorTest.php
@@ -104,7 +104,7 @@ public function testCannotSetInvalidIndicatorCharacters()
{
$this->expectException('InvalidArgumentException');
$this->expectExceptionMessage('Must have at least 2 indicator value characters.');
- $bar = new ProgressIndicator($this->getOutputStream(), null, 100, ['1']);
+ new ProgressIndicator($this->getOutputStream(), null, 100, ['1']);
}
public function testCannotStartAlreadyStartedIndicator()
diff --git a/src/Symfony/Component/Console/Tests/Output/ConsoleSectionOutputTest.php b/src/Symfony/Component/Console/Tests/Output/ConsoleSectionOutputTest.php
index e8d9a8b49253d..e8c65f9b21649 100644
--- a/src/Symfony/Component/Console/Tests/Output/ConsoleSectionOutputTest.php
+++ b/src/Symfony/Component/Console/Tests/Output/ConsoleSectionOutputTest.php
@@ -118,8 +118,8 @@ public function testOverwriteMultipleLines()
public function testAddingMultipleSections()
{
$sections = [];
- $output1 = new ConsoleSectionOutput($this->stream, $sections, OutputInterface::VERBOSITY_NORMAL, true, new OutputFormatter());
- $output2 = new ConsoleSectionOutput($this->stream, $sections, OutputInterface::VERBOSITY_NORMAL, true, new OutputFormatter());
+ new ConsoleSectionOutput($this->stream, $sections, OutputInterface::VERBOSITY_NORMAL, true, new OutputFormatter());
+ new ConsoleSectionOutput($this->stream, $sections, OutputInterface::VERBOSITY_NORMAL, true, new OutputFormatter());
$this->assertCount(2, $sections);
}
diff --git a/src/Symfony/Component/Debug/DebugClassLoader.php b/src/Symfony/Component/Debug/DebugClassLoader.php
index 42e803b9db4ed..1926775fd7e1b 100644
--- a/src/Symfony/Component/Debug/DebugClassLoader.php
+++ b/src/Symfony/Component/Debug/DebugClassLoader.php
@@ -482,7 +482,7 @@ private function darwinRealpath($real)
}
if (isset($dirFiles[$file])) {
- return $real .= $dirFiles[$file];
+ return $real.$dirFiles[$file];
}
$kFile = strtolower($file);
@@ -501,7 +501,7 @@ private function darwinRealpath($real)
self::$darwinCache[$kDir][1] = $dirFiles;
}
- return $real .= $dirFiles[$kFile];
+ return $real.$dirFiles[$kFile];
}
/**
diff --git a/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php b/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php
index 994a5efca1545..5498d9d4ab126 100644
--- a/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php
+++ b/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php
@@ -294,7 +294,7 @@ function () {},
// assertEquals() does not like NAN values.
$this->assertEquals($array[$i][0], 'float');
- $this->assertNan($array[$i++][1]);
+ $this->assertNan($array[$i][1]);
}
public function testRecursionInArguments()
diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
index 64dfee8573763..48267b0d033df 100644
--- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
+++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
@@ -256,7 +256,7 @@ public function dump(array $options = [])
foreach ($ids as $id) {
$c .= ' '.$this->doExport($id)." => true,\n";
}
- $files['removed-ids.php'] = $c .= "];\n";
+ $files['removed-ids.php'] = $c."];\n";
}
foreach ($this->generateServiceFiles($services) as $file => $c) {
@@ -1889,7 +1889,7 @@ private function isSingleUsePrivateNode(ServiceReferenceGraphNode $node): bool
if (!$value = $edge->getSourceNode()->getValue()) {
continue;
}
- if ($edge->isLazy() || !$value->isShared()) {
+ if ($edge->isLazy() || !$value instanceof Definition || !$value->isShared()) {
return false;
}
$ids[$edge->getSourceNode()->getId()] = true;
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AnalyzeServiceReferencesPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AnalyzeServiceReferencesPassTest.php
index 48c3df595c3dc..a075b51d41ae2 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AnalyzeServiceReferencesPassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AnalyzeServiceReferencesPassTest.php
@@ -24,28 +24,28 @@ public function testProcess()
{
$container = new ContainerBuilder();
- $a = $container
+ $container
->register('a')
->addArgument($ref1 = new Reference('b'))
;
- $b = $container
+ $container
->register('b')
->addMethodCall('setA', [$ref2 = new Reference('a')])
;
- $c = $container
+ $container
->register('c')
->addArgument($ref3 = new Reference('a'))
->addArgument($ref4 = new Reference('b'))
;
- $d = $container
+ $container
->register('d')
->setProperty('foo', $ref5 = new Reference('b'))
;
- $e = $container
+ $container
->register('e')
->setConfigurator([$ref6 = new Reference('b'), 'methodName'])
;
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php
index 83d3e23d3ba5a..fc300fde21c11 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php
@@ -50,7 +50,7 @@ public function testProcessRemovesAndInlinesRecursively()
->setPublic(true)
;
- $b = $container
+ $container
->register('b', '\stdClass')
->addArgument(new Reference('c'))
->setPublic(false)
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveChildDefinitionsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveChildDefinitionsPassTest.php
index 1dc2046453f4d..dfe37445d4e88 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveChildDefinitionsPassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveChildDefinitionsPassTest.php
@@ -363,7 +363,7 @@ public function testBindings()
->setBindings(['a' => '1', 'b' => '2'])
;
- $child = $container->setDefinition('child', new ChildDefinition('parent'))
+ $container->setDefinition('child', new ChildDefinition('parent'))
->setBindings(['b' => 'B', 'c' => 'C'])
;
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveClassPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveClassPassTest.php
index 0ab6303164688..81e05fb284bf2 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveClassPassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveClassPassTest.php
@@ -87,8 +87,8 @@ public function testAmbiguousChildDefinition()
$this->expectException('Symfony\Component\DependencyInjection\Exception\InvalidArgumentException');
$this->expectExceptionMessage('Service definition "App\Foo\Child" has a parent but no class, and its name looks like a FQCN. Either the class is missing or you want to inherit it from the parent service. To resolve this ambiguity, please rename this service to a non-FQCN (e.g. using dots), or create the missing class.');
$container = new ContainerBuilder();
- $parent = $container->register('App\Foo', null);
- $child = $container->setDefinition('App\Foo\Child', new ChildDefinition('App\Foo'));
+ $container->register('App\Foo', null);
+ $container->setDefinition('App\Foo\Child', new ChildDefinition('App\Foo'));
(new ResolveClassPass())->process($container);
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php
index 4113c6941402c..fb3b2e99628d2 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php
@@ -1272,7 +1272,7 @@ public function testNoClassFromGlobalNamespaceClassId()
$this->expectExceptionMessage('The definition for "DateTime" has no class attribute, and appears to reference a class or interface in the global namespace.');
$container = new ContainerBuilder();
- $definition = $container->register(\DateTime::class);
+ $container->register(\DateTime::class);
$container->compile();
}
@@ -1302,7 +1302,7 @@ public function testNoClassFromNonClassId()
$this->expectExceptionMessage('The definition for "123_abc" has no class.');
$container = new ContainerBuilder();
- $definition = $container->register('123_abc');
+ $container->register('123_abc');
$container->compile();
}
@@ -1312,7 +1312,7 @@ public function testNoClassFromNsSeparatorId()
$this->expectExceptionMessage('The definition for "\foo" has no class.');
$container = new ContainerBuilder();
- $definition = $container->register('\\foo');
+ $container->register('\\foo');
$container->compile();
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
index 20dada9b0b121..b78fcb32e4363 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
@@ -1036,7 +1036,7 @@ public function testInlineSelfRef()
->setPublic(true)
->addArgument($baz);
- $passConfig = $container->getCompiler()->getPassConfig();
+ $container->getCompiler()->getPassConfig();
$container->compile();
$dumper = new PhpDumper($container);
@@ -1128,7 +1128,6 @@ public function testAdawsonContainer()
$container->compile();
$dumper = new PhpDumper($container);
- $dump = $dumper->dump();
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_adawson.php', $dumper->dump());
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php
index 7b8800f195df1..b520a8cc58b03 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php
@@ -882,7 +882,6 @@ public function testTsantosContainer()
$container->compile();
$dumper = new PhpDumper($container);
- $dump = $dumper->dump();
$this->assertStringEqualsFile(self::$fixturesPath.'/php/services_tsantos.php', $dumper->dump());
}
diff --git a/src/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php b/src/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php
index 61e776736a4b5..176ea5927fe1c 100644
--- a/src/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php
+++ b/src/Symfony/Component/DomCrawler/Tests/Field/ChoiceFormFieldTest.php
@@ -19,7 +19,7 @@ public function testInitialize()
{
$node = $this->createNode('textarea', '');
try {
- $field = new ChoiceFormField($node);
+ new ChoiceFormField($node);
$this->fail('->initialize() throws a \LogicException if the node is not an input or a select');
} catch (\LogicException $e) {
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is not an input or a select');
@@ -27,7 +27,7 @@ public function testInitialize()
$node = $this->createNode('input', '', ['type' => 'text']);
try {
- $field = new ChoiceFormField($node);
+ new ChoiceFormField($node);
$this->fail('->initialize() throws a \LogicException if the node is an input with a type different from checkbox or radio');
} catch (\LogicException $e) {
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is an input with a type different from checkbox or radio');
diff --git a/src/Symfony/Component/DomCrawler/Tests/Field/FileFormFieldTest.php b/src/Symfony/Component/DomCrawler/Tests/Field/FileFormFieldTest.php
index 9b359d69785b3..b14bcc855e2ab 100644
--- a/src/Symfony/Component/DomCrawler/Tests/Field/FileFormFieldTest.php
+++ b/src/Symfony/Component/DomCrawler/Tests/Field/FileFormFieldTest.php
@@ -24,7 +24,7 @@ public function testInitialize()
$node = $this->createNode('textarea', '');
try {
- $field = new FileFormField($node);
+ new FileFormField($node);
$this->fail('->initialize() throws a \LogicException if the node is not an input field');
} catch (\LogicException $e) {
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is not an input field');
@@ -32,7 +32,7 @@ public function testInitialize()
$node = $this->createNode('input', '', ['type' => 'text']);
try {
- $field = new FileFormField($node);
+ new FileFormField($node);
$this->fail('->initialize() throws a \LogicException if the node is not a file input field');
} catch (\LogicException $e) {
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is not a file input field');
diff --git a/src/Symfony/Component/DomCrawler/Tests/Field/InputFormFieldTest.php b/src/Symfony/Component/DomCrawler/Tests/Field/InputFormFieldTest.php
index 5758f1b7bb3fe..a1f327bbc2f81 100644
--- a/src/Symfony/Component/DomCrawler/Tests/Field/InputFormFieldTest.php
+++ b/src/Symfony/Component/DomCrawler/Tests/Field/InputFormFieldTest.php
@@ -24,7 +24,7 @@ public function testInitialize()
$node = $this->createNode('textarea', '');
try {
- $field = new InputFormField($node);
+ new InputFormField($node);
$this->fail('->initialize() throws a \LogicException if the node is not an input');
} catch (\LogicException $e) {
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is not an input');
@@ -32,7 +32,7 @@ public function testInitialize()
$node = $this->createNode('input', '', ['type' => 'checkbox']);
try {
- $field = new InputFormField($node);
+ new InputFormField($node);
$this->fail('->initialize() throws a \LogicException if the node is a checkbox');
} catch (\LogicException $e) {
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is a checkbox');
@@ -40,7 +40,7 @@ public function testInitialize()
$node = $this->createNode('input', '', ['type' => 'file']);
try {
- $field = new InputFormField($node);
+ new InputFormField($node);
$this->fail('->initialize() throws a \LogicException if the node is a file');
} catch (\LogicException $e) {
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is a file');
diff --git a/src/Symfony/Component/DomCrawler/Tests/Field/TextareaFormFieldTest.php b/src/Symfony/Component/DomCrawler/Tests/Field/TextareaFormFieldTest.php
index 5d4d0038260db..192984ce29c2f 100644
--- a/src/Symfony/Component/DomCrawler/Tests/Field/TextareaFormFieldTest.php
+++ b/src/Symfony/Component/DomCrawler/Tests/Field/TextareaFormFieldTest.php
@@ -24,7 +24,7 @@ public function testInitialize()
$node = $this->createNode('input', '');
try {
- $field = new TextareaFormField($node);
+ new TextareaFormField($node);
$this->fail('->initialize() throws a \LogicException if the node is not a textarea');
} catch (\LogicException $e) {
$this->assertTrue(true, '->initialize() throws a \LogicException if the node is not a textarea');
diff --git a/src/Symfony/Component/DomCrawler/Tests/FormTest.php b/src/Symfony/Component/DomCrawler/Tests/FormTest.php
index 97ae46fe027f7..6fe44de5344f6 100644
--- a/src/Symfony/Component/DomCrawler/Tests/FormTest.php
+++ b/src/Symfony/Component/DomCrawler/Tests/FormTest.php
@@ -39,14 +39,14 @@ public function testConstructorThrowsExceptionIfTheNodeHasNoFormAncestor()
$nodes = $dom->getElementsByTagName('input');
try {
- $form = new Form($nodes->item(0), 'http://example.com');
+ new Form($nodes->item(0), 'http://example.com');
$this->fail('__construct() throws a \\LogicException if the node has no form ancestor');
} catch (\LogicException $e) {
$this->assertTrue(true, '__construct() throws a \\LogicException if the node has no form ancestor');
}
try {
- $form = new Form($nodes->item(1), 'http://example.com');
+ new Form($nodes->item(1), 'http://example.com');
$this->fail('__construct() throws a \\LogicException if the input type is not submit, button, or image');
} catch (\LogicException $e) {
$this->assertTrue(true, '__construct() throws a \\LogicException if the input type is not submit, button, or image');
@@ -55,7 +55,7 @@ public function testConstructorThrowsExceptionIfTheNodeHasNoFormAncestor()
$nodes = $dom->getElementsByTagName('button');
try {
- $form = new Form($nodes->item(0), 'http://example.com');
+ new Form($nodes->item(0), 'http://example.com');
$this->fail('__construct() throws a \\LogicException if the node has no form ancestor');
} catch (\LogicException $e) {
$this->assertTrue(true, '__construct() throws a \\LogicException if the node has no form ancestor');
@@ -63,11 +63,19 @@ public function testConstructorThrowsExceptionIfTheNodeHasNoFormAncestor()
}
/**
- * __construct() should throw \\LogicException if the form attribute is invalid.
+ * @dataProvider constructorThrowsExceptionIfNoRelatedFormProvider
+ *
+ * __construct() should throw a \LogicException if the form attribute is invalid.
*/
- public function testConstructorThrowsExceptionIfNoRelatedForm()
+ public function testConstructorThrowsExceptionIfNoRelatedForm(\DOMElement $node)
{
$this->expectException('LogicException');
+
+ new Form($node, 'http://example.com');
+ }
+
+ public function constructorThrowsExceptionIfNoRelatedFormProvider()
+ {
$dom = new \DOMDocument();
$dom->loadHTML('
@@ -81,8 +89,10 @@ public function testConstructorThrowsExceptionIfNoRelatedForm()
$nodes = $dom->getElementsByTagName('input');
- $form = new Form($nodes->item(0), 'http://example.com');
- $form = new Form($nodes->item(1), 'http://example.com');
+ return [
+ [$nodes->item(0)],
+ [$nodes->item(1)],
+ ];
}
public function testConstructorLoadsOnlyFieldsOfTheRightForm()
diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php
index 66a2c105a8832..5c41d81d96554 100644
--- a/src/Symfony/Component/Dotenv/Dotenv.php
+++ b/src/Symfony/Component/Dotenv/Dotenv.php
@@ -257,29 +257,24 @@ private function lexValue()
throw $this->createFormatException('Whitespace are not supported before the value');
}
+ $loadedVars = array_flip(explode(',', isset($_SERVER['SYMFONY_DOTENV_VARS']) ? $_SERVER['SYMFONY_DOTENV_VARS'] : (isset($_ENV['SYMFONY_DOTENV_VARS']) ? $_ENV['SYMFONY_DOTENV_VARS'] : '')));
+ unset($loadedVars['']);
$v = '';
do {
if ("'" === $this->data[$this->cursor]) {
- $value = '';
- ++$this->cursor;
+ $len = 0;
- while ("\n" !== $this->data[$this->cursor]) {
- if ("'" === $this->data[$this->cursor]) {
- break;
- }
- $value .= $this->data[$this->cursor];
- ++$this->cursor;
+ do {
+ if ($this->cursor + ++$len === $this->end) {
+ $this->cursor += $len;
- if ($this->cursor === $this->end) {
throw $this->createFormatException('Missing quote to end the value');
}
- }
- if ("\n" === $this->data[$this->cursor]) {
- throw $this->createFormatException('Missing quote to end the value');
- }
- ++$this->cursor;
- $v .= $value;
+ } while ("'" !== $this->data[$this->cursor + $len]);
+
+ $v .= substr($this->data, 1 + $this->cursor, $len - 1);
+ $this->cursor += 1 + $len;
} elseif ('"' === $this->data[$this->cursor]) {
$value = '';
++$this->cursor;
@@ -295,8 +290,8 @@ private function lexValue()
++$this->cursor;
$value = str_replace(['\\"', '\r', '\n'], ['"', "\r", "\n"], $value);
$resolvedValue = $value;
- $resolvedValue = $this->resolveVariables($resolvedValue);
- $resolvedValue = $this->resolveCommands($resolvedValue);
+ $resolvedValue = $this->resolveVariables($resolvedValue, $loadedVars);
+ $resolvedValue = $this->resolveCommands($resolvedValue, $loadedVars);
$resolvedValue = str_replace('\\\\', '\\', $resolvedValue);
$v .= $resolvedValue;
} else {
@@ -318,8 +313,8 @@ private function lexValue()
}
$value = rtrim($value);
$resolvedValue = $value;
- $resolvedValue = $this->resolveVariables($resolvedValue);
- $resolvedValue = $this->resolveCommands($resolvedValue);
+ $resolvedValue = $this->resolveVariables($resolvedValue, $loadedVars);
+ $resolvedValue = $this->resolveCommands($resolvedValue, $loadedVars);
$resolvedValue = str_replace('\\\\', '\\', $resolvedValue);
if ($resolvedValue === $value && preg_match('/\s+/', $value)) {
@@ -372,7 +367,7 @@ private function skipEmptyLines()
}
}
- private function resolveCommands($value)
+ private function resolveCommands($value, $loadedVars)
{
if (false === strpos($value, '$')) {
return $value;
@@ -388,7 +383,7 @@ private function resolveCommands($value)
)
/x';
- return preg_replace_callback($regex, function ($matches) {
+ return preg_replace_callback($regex, function ($matches) use ($loadedVars) {
if ('\\' === $matches[1]) {
return substr($matches[0], 1);
}
@@ -403,7 +398,15 @@ private function resolveCommands($value)
$process = method_exists(Process::class, 'fromShellCommandline') ? Process::fromShellCommandline('echo '.$matches[0]) : new Process('echo '.$matches[0]);
$process->inheritEnvironmentVariables(true);
- $process->setEnv($this->values);
+
+ $env = [];
+ foreach ($this->values as $name => $value) {
+ if (isset($loadedVars[$name]) || (!isset($_ENV[$name]) && !(isset($_SERVER[$name]) && 0 !== strpos($name, 'HTTP_')))) {
+ $env[$name] = $value;
+ }
+ }
+ $process->setEnv($env);
+
try {
$process->mustRun();
} catch (ProcessException $e) {
@@ -414,7 +417,7 @@ private function resolveCommands($value)
}, $value);
}
- private function resolveVariables($value)
+ private function resolveVariables($value, array $loadedVars)
{
if (false === strpos($value, '$')) {
return $value;
@@ -430,7 +433,7 @@ private function resolveVariables($value)
(?P\})? # optional closing brace
/x';
- $value = preg_replace_callback($regex, function ($matches) {
+ $value = preg_replace_callback($regex, function ($matches) use ($loadedVars) {
// odd number of backslashes means the $ character is escaped
if (1 === \strlen($matches['backslashes']) % 2) {
return substr($matches[0], 1);
@@ -446,14 +449,16 @@ private function resolveVariables($value)
}
$name = $matches['name'];
- if (isset($this->values[$name])) {
+ if (isset($loadedVars[$name]) && isset($this->values[$name])) {
$value = $this->values[$name];
- } elseif (isset($_SERVER[$name]) && 0 !== strpos($name, 'HTTP_')) {
- $value = $_SERVER[$name];
} elseif (isset($_ENV[$name])) {
$value = $_ENV[$name];
+ } elseif (isset($_SERVER[$name]) && 0 !== strpos($name, 'HTTP_')) {
+ $value = $_SERVER[$name];
+ } elseif (isset($this->values[$name])) {
+ $value = $this->values[$name];
} else {
- $value = (string) getenv($name);
+ $value = '';
}
if (!$matches['opening_brace'] && isset($matches['closing_brace'])) {
diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php
index beda74838d594..e2b387ebc4ecd 100644
--- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php
+++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php
@@ -40,7 +40,7 @@ public function getEnvDataWithFormatErrors()
['FOO', "Missing = in the environment variable declaration in \".env\" at line 1.\n...FOO...\n ^ line 1 offset 3"],
['FOO="foo', "Missing quote to end the value in \".env\" at line 1.\n...FOO=\"foo...\n ^ line 1 offset 8"],
['FOO=\'foo', "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo...\n ^ line 1 offset 8"],
- ['FOO=\'foo'."\n", "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo\\n...\n ^ line 1 offset 8"],
+ ['FOO=\'foo'."\n", "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo\\n...\n ^ line 1 offset 9"],
['export FOO', "Unable to unset an environment variable in \".env\" at line 1.\n...export FOO...\n ^ line 1 offset 10"],
['FOO=${FOO', "Unclosed braces on variable expansion in \".env\" at line 1.\n...FOO=\${FOO...\n ^ line 1 offset 9"],
['FOO= BAR', "Whitespace are not supported before the value in \".env\" at line 1.\n...FOO= BAR...\n ^ line 1 offset 4"],
@@ -69,6 +69,7 @@ public function testParse($data, $expected)
public function getEnvData()
{
putenv('LOCAL=local');
+ $_ENV['LOCAL'] = 'local';
$_ENV['REMOTE'] = 'remote';
$_SERVER['SERVERVAR'] = 'servervar';
@@ -111,6 +112,7 @@ public function getEnvData()
['FOO="bar\rfoo"', ['FOO' => "bar\rfoo"]],
['FOO=\'bar\nfoo\'', ['FOO' => 'bar\nfoo']],
['FOO=\'bar\rfoo\'', ['FOO' => 'bar\rfoo']],
+ ["FOO='bar\nfoo'", ['FOO' => "bar\nfoo"]],
['FOO=" FOO "', ['FOO' => ' FOO ']],
['FOO=" "', ['FOO' => ' ']],
['PATH="c:\\\\"', ['PATH' => 'c:\\']],
@@ -413,6 +415,22 @@ public function testOverridingEnvVarsWithNamesMemorizedInSpecialVar()
$this->assertSame('/var/www', getenv('DOCUMENT_ROOT'));
}
+ public function testGetVariablesValueFromEnvFirst()
+ {
+ $_ENV['APP_ENV'] = 'prod';
+ $dotenv = new Dotenv(true);
+
+ $test = "APP_ENV=dev\nTEST1=foo1_\${APP_ENV}";
+ $values = $dotenv->parse($test);
+ $this->assertSame('foo1_prod', $values['TEST1']);
+
+ if ('\\' !== \DIRECTORY_SEPARATOR) {
+ $test = "APP_ENV=dev\nTEST2=foo2_\$(php -r 'echo \$_SERVER[\"APP_ENV\"];')";
+ $values = $dotenv->parse($test);
+ $this->assertSame('foo2_prod', $values['TEST2']);
+ }
+ }
+
/**
* @group legacy
* @expectedDeprecation The default value of "$usePutenv" argument of "%s" will be changed from "true" to "false" in Symfony 5.0. You should define its value explicitly.
diff --git a/src/Symfony/Component/Dotenv/composer.json b/src/Symfony/Component/Dotenv/composer.json
index 872ff3a4c5be8..dddeab1fb7e7f 100644
--- a/src/Symfony/Component/Dotenv/composer.json
+++ b/src/Symfony/Component/Dotenv/composer.json
@@ -19,7 +19,7 @@
"php": "^7.1.3"
},
"require-dev": {
- "symfony/process": "~3.4|~4.0"
+ "symfony/process": "^3.4.2|^4.0"
},
"autoload": {
"psr-4": { "Symfony\\Component\\Dotenv\\": "" },
diff --git a/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php b/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php
index 92c2483790393..6e01b250caca5 100644
--- a/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php
+++ b/src/Symfony/Component/ExpressionLanguage/Tests/ExpressionLanguageTest.php
@@ -158,7 +158,7 @@ public function testCachingWithDifferentNamesOrder()
$cacheMock = $this->getMockBuilder('Psr\Cache\CacheItemPoolInterface')->getMock();
$cacheItemMock = $this->getMockBuilder('Psr\Cache\CacheItemInterface')->getMock();
$expressionLanguage = new ExpressionLanguage($cacheMock);
- $savedParsedExpressions = [];
+ $savedParsedExpression = null;
$cacheMock
->expects($this->exactly(2))
diff --git a/src/Symfony/Component/Finder/Finder.php b/src/Symfony/Component/Finder/Finder.php
index 3a0c3105ad0a9..b3931e0d81813 100644
--- a/src/Symfony/Component/Finder/Finder.php
+++ b/src/Symfony/Component/Finder/Finder.php
@@ -595,7 +595,8 @@ public function in($dirs)
foreach ((array) $dirs as $dir) {
if (is_dir($dir)) {
$resolvedDirs[] = $this->normalizeDir($dir);
- } elseif ($glob = glob($dir, (\defined('GLOB_BRACE') ? GLOB_BRACE : 0) | GLOB_ONLYDIR)) {
+ } elseif ($glob = glob($dir, (\defined('GLOB_BRACE') ? GLOB_BRACE : 0) | GLOB_ONLYDIR | GLOB_NOSORT)) {
+ sort($glob);
$resolvedDirs = array_merge($resolvedDirs, array_map([$this, 'normalizeDir'], $glob));
} else {
throw new DirectoryNotFoundException(sprintf('The "%s" directory does not exist.', $dir));
diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformer.php
index b0737393e4e3f..167ea57faebbf 100644
--- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformer.php
+++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformer.php
@@ -40,7 +40,11 @@ public function transform($value)
throw new TransformationFailedException('Expected a \DateTimeImmutable.');
}
- return \DateTime::createFromFormat(\DateTime::RFC3339, $value->format(\DateTime::RFC3339));
+ if (\PHP_VERSION_ID >= 70300) {
+ return \DateTime::createFromImmutable($value);
+ }
+
+ return \DateTime::createFromFormat('U.u', $value->format('U.u'))->setTimezone($value->getTimezone());
}
/**
diff --git a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php
index df7726a83f019..c2492fb662566 100644
--- a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php
+++ b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php
@@ -131,7 +131,8 @@ public function collectDefaultData(FormInterface $form)
$hash = spl_object_hash($form);
if (!isset($this->dataByForm[$hash])) {
- $this->dataByForm[$hash] = [];
+ // field was created by form event
+ $this->collectConfiguration($form);
}
$this->dataByForm[$hash] = array_replace(
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformerTest.php
index 9313e4f1785cf..c8b6549778cce 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformerTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeImmutableToDateTimeTransformerTest.php
@@ -16,16 +16,33 @@
class DateTimeImmutableToDateTimeTransformerTest extends TestCase
{
- public function testTransform()
+ /**
+ * @dataProvider provider
+ */
+ public function testTransform(\DateTime $expectedOutput, \DateTimeImmutable $input)
{
$transformer = new DateTimeImmutableToDateTimeTransformer();
- $input = new \DateTimeImmutable('2010-02-03 04:05:06 UTC');
- $expectedOutput = new \DateTime('2010-02-03 04:05:06 UTC');
$actualOutput = $transformer->transform($input);
- $this->assertInstanceOf(\DateTime::class, $actualOutput);
$this->assertEquals($expectedOutput, $actualOutput);
+ $this->assertEquals($expectedOutput->getTimezone(), $actualOutput->getTimezone());
+ }
+
+ public function provider()
+ {
+ return [
+ [
+ new \DateTime('2010-02-03 04:05:06 UTC'),
+ new \DateTimeImmutable('2010-02-03 04:05:06 UTC'),
+ ],
+ [
+ (new \DateTime('2019-10-07 +11:00'))
+ ->setTime(14, 27, 11, 10042),
+ (new \DateTimeImmutable('2019-10-07 +11:00'))
+ ->setTime(14, 27, 11, 10042),
+ ],
+ ];
}
public function testTransformEmpty()
@@ -43,16 +60,17 @@ public function testTransformFail()
$transformer->transform(new \DateTime());
}
- public function testReverseTransform()
+ /**
+ * @dataProvider provider
+ */
+ public function testReverseTransform(\DateTime $input, \DateTimeImmutable $expectedOutput)
{
$transformer = new DateTimeImmutableToDateTimeTransformer();
- $input = new \DateTime('2010-02-03 04:05:06 UTC');
- $expectedOutput = new \DateTimeImmutable('2010-02-03 04:05:06 UTC');
$actualOutput = $transformer->reverseTransform($input);
- $this->assertInstanceOf(\DateTimeImmutable::class, $actualOutput);
$this->assertEquals($expectedOutput, $actualOutput);
+ $this->assertEquals($expectedOutput->getTimezone(), $actualOutput->getTimezone());
}
public function testReverseTransformEmpty()
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php
index 309a5dc4e3f46..808571cbef41e 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php
@@ -181,10 +181,10 @@ public function testTransformRequiresValidDateTime()
public function testTransformWrapsIntlErrors()
{
- $transformer = new DateTimeToLocalizedStringTransformer();
-
$this->markTestIncomplete('Checking for intl errors needs to be reimplemented');
+ $transformer = new DateTimeToLocalizedStringTransformer();
+
// HOW TO REPRODUCE?
//$this->expectException('Symfony\Component\Form\Extension\Core\DataTransformer\TransformationFailedException');
diff --git a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php
index 82eec8a45cf24..768002de46213 100644
--- a/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/DataCollector/FormDataCollectorTest.php
@@ -13,10 +13,20 @@
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
+use Symfony\Component\EventDispatcher\EventDispatcher;
+use Symfony\Component\Form\Extension\Core\CoreExtension;
+use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper;
+use Symfony\Component\Form\Extension\Core\Type\CollectionType;
+use Symfony\Component\Form\Extension\Core\Type\FormType;
+use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\Extension\DataCollector\FormDataCollector;
use Symfony\Component\Form\Form;
use Symfony\Component\Form\FormBuilder;
+use Symfony\Component\Form\FormFactory;
+use Symfony\Component\Form\FormInterface;
+use Symfony\Component\Form\FormRegistry;
use Symfony\Component\Form\FormView;
+use Symfony\Component\Form\ResolvedFormTypeFactory;
class FormDataCollectorTest extends TestCase
{
@@ -69,9 +79,9 @@ protected function setUp(): void
{
$this->dataExtractor = $this->getMockBuilder('Symfony\Component\Form\Extension\DataCollector\FormDataExtractorInterface')->getMock();
$this->dataCollector = new FormDataCollector($this->dataExtractor);
- $this->dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock();
- $this->factory = $this->getMockBuilder('Symfony\Component\Form\FormFactoryInterface')->getMock();
- $this->dataMapper = $this->getMockBuilder('Symfony\Component\Form\DataMapperInterface')->getMock();
+ $this->dispatcher = new EventDispatcher();
+ $this->factory = new FormFactory(new FormRegistry([new CoreExtension()], new ResolvedFormTypeFactory()));
+ $this->dataMapper = new PropertyPathMapper();
$this->form = $this->createForm('name');
$this->childForm = $this->createForm('child');
$this->view = new FormView();
@@ -726,6 +736,56 @@ public function testReset()
);
}
+ public function testCollectMissingDataFromChildFormAddedOnFormEvents()
+ {
+ $form = $this->factory->createNamedBuilder('root', FormType::class, ['items' => null])
+ ->add('items', CollectionType::class, [
+ 'entry_type' => TextType::class,
+ 'allow_add' => true,
+ // data is locked and modelData (null) is different to the
+ // configured data, so modifications of the configured data
+ // won't be allowed at this point. It also means *_SET_DATA
+ // events won't dispatched either. Therefore, no child form
+ // is created during the mapping of data to the form.
+ 'data' => ['foo'],
+ ])
+ ->getForm()
+ ;
+ $this->dataExtractor->expects($extractConfiguration = $this->exactly(4))
+ ->method('extractConfiguration')
+ ->willReturn([])
+ ;
+ $this->dataExtractor->expects($extractDefaultData = $this->exactly(4))
+ ->method('extractDefaultData')
+ ->willReturnCallback(static function (FormInterface $form) {
+ // this simulate the call in extractDefaultData() method
+ // where (if defaultDataSet is false) it fires *_SET_DATA
+ // events, adding the form related to the configured data
+ $form->getNormData();
+
+ return [];
+ })
+ ;
+ $this->dataExtractor->expects($this->exactly(4))
+ ->method('extractSubmittedData')
+ ->willReturn([])
+ ;
+
+ $this->dataCollector->collectConfiguration($form);
+ $this->assertSame(2, $extractConfiguration->getInvocationCount(), 'only "root" and "items" forms were collected, the "items" children do not exist yet.');
+
+ $this->dataCollector->collectDefaultData($form);
+ $this->assertSame(3, $extractConfiguration->getInvocationCount(), 'extracted missing configuration of the "items" children ["0" => foo].');
+ $this->assertSame(3, $extractDefaultData->getInvocationCount());
+ $this->assertSame(['foo'], $form->get('items')->getData());
+
+ $form->submit(['items' => ['foo', 'bar']]);
+ $this->dataCollector->collectSubmittedData($form);
+ $this->assertSame(4, $extractConfiguration->getInvocationCount(), 'extracted missing configuration of the "items" children ["1" => bar].');
+ $this->assertSame(4, $extractDefaultData->getInvocationCount(), 'extracted missing default data of the "items" children ["1" => bar].');
+ $this->assertSame(['foo', 'bar'], $form->get('items')->getData());
+ }
+
private function createForm($name)
{
$builder = new FormBuilder($name, null, $this->dispatcher, $this->factory);
diff --git a/src/Symfony/Component/Form/Tests/VersionAwareTest.php b/src/Symfony/Component/Form/Tests/VersionAwareTest.php
index 2b8489a6a27cf..578bebcb0800f 100644
--- a/src/Symfony/Component/Form/Tests/VersionAwareTest.php
+++ b/src/Symfony/Component/Form/Tests/VersionAwareTest.php
@@ -13,7 +13,7 @@
trait VersionAwareTest
{
- protected static $supportedFeatureSetVersion = 304;
+ protected static $supportedFeatureSetVersion = 403;
/**
* @param int $requiredFeatureSetVersion
diff --git a/src/Symfony/Component/HttpClient/CurlHttpClient.php b/src/Symfony/Component/HttpClient/CurlHttpClient.php
index 83413a23edf45..56a129783d481 100644
--- a/src/Symfony/Component/HttpClient/CurlHttpClient.php
+++ b/src/Symfony/Component/HttpClient/CurlHttpClient.php
@@ -197,6 +197,8 @@ public function request(string $method, string $url, array $options = []): Respo
if ('POST' === $method) {
// Use CURLOPT_POST to have browser-like POST-to-GET redirects for 301, 302 and 303
$curlopts[CURLOPT_POST] = true;
+ } elseif ('HEAD' === $method) {
+ $curlopts[CURLOPT_NOBODY] = true;
} else {
$curlopts[CURLOPT_CUSTOMREQUEST] = $method;
}
@@ -220,7 +222,7 @@ public function request(string $method, string $url, array $options = []): Respo
// Prevent curl from sending its default Accept and Expect headers
foreach (['accept', 'expect'] as $header) {
- if (!isset($options['normalized_headers'][$header])) {
+ if (!isset($options['normalized_headers'][$header][0])) {
$curlopts[CURLOPT_HTTPHEADER][] = $header.':';
}
}
@@ -413,7 +415,7 @@ private static function createRedirectResolver(array $options, string $host): \C
return 0 !== stripos($h, 'Host:');
});
- if (isset($options['normalized_headers']['authorization']) || isset($options['normalized_headers']['cookie'])) {
+ if (isset($options['normalized_headers']['authorization'][0]) || isset($options['normalized_headers']['cookie'][0])) {
$redirectHeaders['no_auth'] = array_filter($options['headers'], static function ($h) {
return 0 !== stripos($h, 'Authorization:') && 0 !== stripos($h, 'Cookie:');
});
diff --git a/src/Symfony/Component/HttpClient/HttpClientTrait.php b/src/Symfony/Component/HttpClient/HttpClientTrait.php
index 3fd9814df68f0..2914ab20b6022 100644
--- a/src/Symfony/Component/HttpClient/HttpClientTrait.php
+++ b/src/Symfony/Component/HttpClient/HttpClientTrait.php
@@ -57,7 +57,7 @@ private static function prepareRequest(?string $method, ?string $url, array $opt
}
if (!isset($options['normalized_headers']['accept'])) {
- $options['normalized_headers']['accept'] = [$options['headers'][] = 'Accept: *'];
+ $options['normalized_headers']['accept'] = [$options['headers'][] = 'Accept: */*'];
}
if (isset($options['body'])) {
@@ -196,7 +196,7 @@ private static function normalizeHeaders(array $headers): array
$normalizedHeaders = [];
foreach ($headers as $name => $values) {
- if (\is_object($values) && method_exists('__toString')) {
+ if (\is_object($values) && method_exists($values, '__toString')) {
$values = (string) $values;
}
diff --git a/src/Symfony/Component/HttpClient/Response/CurlResponse.php b/src/Symfony/Component/HttpClient/Response/CurlResponse.php
index 532f4130860f3..6771dcb6f218a 100644
--- a/src/Symfony/Component/HttpClient/Response/CurlResponse.php
+++ b/src/Symfony/Component/HttpClient/Response/CurlResponse.php
@@ -142,7 +142,6 @@ public function __construct(CurlClientState $multi, $ch, array $options = null,
// Schedule the request in a non-blocking way
$multi->openHandles[$id] = [$ch, $options];
curl_multi_add_handle($multi->handle, $ch);
- self::perform($multi);
}
/**
@@ -274,6 +273,11 @@ private static function perform(CurlClientState $multi, array &$responses = null
*/
private static function select(CurlClientState $multi, float $timeout): int
{
+ if (\PHP_VERSION_ID < 70123 || (70200 <= \PHP_VERSION_ID && \PHP_VERSION_ID < 70211)) {
+ // workaround https://bugs.php.net/76480
+ $timeout = min($timeout, 0.01);
+ }
+
return curl_multi_select($multi->handle, $timeout);
}
@@ -318,6 +322,7 @@ private static function parseHeaderLine($ch, string $data, array &$info, array &
if (200 > $statusCode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE)) {
$multi->handlesActivity[$id][] = new InformationalChunk($statusCode, $headers);
+ $location = null;
return \strlen($data);
}
@@ -341,9 +346,7 @@ private static function parseHeaderLine($ch, string $data, array &$info, array &
}
}
- $location = null;
-
- if ($statusCode < 300 || 400 <= $statusCode || curl_getinfo($ch, CURLINFO_REDIRECT_COUNT) === $options['max_redirects']) {
+ if ($statusCode < 300 || 400 <= $statusCode || null === $location || curl_getinfo($ch, CURLINFO_REDIRECT_COUNT) === $options['max_redirects']) {
// Headers and redirects completed, time to get the response's body
$multi->handlesActivity[$id][] = new FirstChunk();
@@ -356,6 +359,8 @@ private static function parseHeaderLine($ch, string $data, array &$info, array &
$logger->info(sprintf('Redirecting: "%s %s"', $info['http_code'], $info['redirect_url']));
}
+ $location = null;
+
return \strlen($data);
}
}
diff --git a/src/Symfony/Component/HttpClient/Response/MockResponse.php b/src/Symfony/Component/HttpClient/Response/MockResponse.php
index fa8abebea447b..3856112a09d39 100644
--- a/src/Symfony/Component/HttpClient/Response/MockResponse.php
+++ b/src/Symfony/Component/HttpClient/Response/MockResponse.php
@@ -176,7 +176,7 @@ protected static function perform(ClientState $multi, array &$responses): void
try {
$offset = 0;
$chunk[1]->getStatusCode();
- $response->headers = $chunk[1]->getHeaders(false);
+ $chunk[1]->getHeaders(false);
self::readResponse($response, $chunk[0], $chunk[1], $offset);
$multi->handlesActivity[$id][] = new FirstChunk();
} catch (\Throwable $e) {
@@ -257,7 +257,7 @@ private static function readResponse(self $response, array $options, ResponseInt
$info = $mock->getInfo() ?: [];
$response->info['http_code'] = ($info['http_code'] ?? 0) ?: $mock->getStatusCode() ?: 200;
$response->addResponseHeaders($info['response_headers'] ?? [], $response->info, $response->headers);
- $dlSize = isset($response->headers['content-encoding']) ? 0 : (int) ($response->headers['content-length'][0] ?? 0);
+ $dlSize = isset($response->headers['content-encoding']) || 'HEAD' === $response->info['http_method'] || \in_array($response->info['http_code'], [204, 304], true) ? 0 : (int) ($response->headers['content-length'][0] ?? 0);
$response->info = [
'start_time' => $response->info['start_time'],
diff --git a/src/Symfony/Component/HttpClient/Response/NativeResponse.php b/src/Symfony/Component/HttpClient/Response/NativeResponse.php
index 2f414e3ba2d17..a9865ed09e494 100644
--- a/src/Symfony/Component/HttpClient/Response/NativeResponse.php
+++ b/src/Symfony/Component/HttpClient/Response/NativeResponse.php
@@ -174,8 +174,16 @@ private function open(): void
$this->inflate = null;
}
- $this->multi->openHandles[$this->id] = [$h, $this->buffer, $this->inflate, $this->content, $this->onProgress, &$this->remaining, &$this->info];
$this->multi->handlesActivity[$this->id] = [new FirstChunk()];
+
+ if ('HEAD' === $context['http']['method'] || \in_array($this->info['http_code'], [204, 304], true)) {
+ $this->multi->handlesActivity[$this->id][] = null;
+ $this->multi->handlesActivity[$this->id][] = null;
+
+ return;
+ }
+
+ $this->multi->openHandles[$this->id] = [$h, $this->buffer, $this->inflate, $this->content, $this->onProgress, &$this->remaining, &$this->info];
}
/**
diff --git a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php
index 8a1d9a9077ce1..7e0e06b8dcebc 100644
--- a/src/Symfony/Component/HttpClient/Response/ResponseTrait.php
+++ b/src/Symfony/Component/HttpClient/Response/ResponseTrait.php
@@ -104,7 +104,6 @@ public function getContent(bool $throw = true): string
if (null === $this->content) {
$content = null;
- $chunk = null;
foreach (self::stream([$this]) as $chunk) {
if (!$chunk->isLast()) {
@@ -112,11 +111,15 @@ public function getContent(bool $throw = true): string
}
}
- if (null === $content) {
- throw new TransportException('Cannot get the content of the response twice: the request was issued with option "buffer" set to false.');
+ if (null !== $content) {
+ return $content;
}
- return $content;
+ if ('HEAD' === $this->info['http_method'] || \in_array($this->info['http_code'], [204, 304], true)) {
+ return '';
+ }
+
+ throw new TransportException('Cannot get the content of the response twice: the request was issued with option "buffer" set to false.');
}
foreach (self::stream([$this]) as $chunk) {
diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php
index 3d5a70a0a96e5..2acf01fd0a642 100644
--- a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php
+++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php
@@ -15,6 +15,59 @@
abstract class HttpClientTestCase extends BaseHttpClientTestCase
{
+ public function testAcceptHeader()
+ {
+ $client = $this->getHttpClient(__FUNCTION__);
+
+ $response = $client->request('GET', 'http://localhost:8057');
+ $requestHeaders = $response->toArray();
+
+ $this->assertSame('*/*', $requestHeaders['HTTP_ACCEPT']);
+
+ $response = $client->request('GET', 'http://localhost:8057', [
+ 'headers' => [
+ 'Accept' => 'foo/bar',
+ ],
+ ]);
+ $requestHeaders = $response->toArray();
+
+ $this->assertSame('foo/bar', $requestHeaders['HTTP_ACCEPT']);
+
+ $response = $client->request('GET', 'http://localhost:8057', [
+ 'headers' => [
+ 'Accept' => null,
+ ],
+ ]);
+ $requestHeaders = $response->toArray();
+
+ $this->assertArrayNotHasKey('HTTP_ACCEPT', $requestHeaders);
+ }
+
+ public function testInfoOnCanceledResponse()
+ {
+ $this->markTestSkipped('Implemented as of version 4.4');
+ }
+
+ public function testBufferSink()
+ {
+ $this->markTestSkipped('Implemented as of version 4.4');
+ }
+
+ public function testConditionalBuffering()
+ {
+ $this->markTestSkipped('Implemented as of version 4.4');
+ }
+
+ public function testReentrantBufferCallback()
+ {
+ $this->markTestSkipped('Implemented as of version 4.4');
+ }
+
+ public function testThrowingBufferCallback()
+ {
+ $this->markTestSkipped('Implemented as of version 4.4');
+ }
+
public function testMaxDuration()
{
$this->markTestSkipped('Implemented as of version 4.4');
diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php
index 559f2b62270df..e1636a5d5f84d 100644
--- a/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php
+++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTraitTest.php
@@ -172,7 +172,7 @@ public function provideRemoveDotSegments()
public function testAuthBearerOption()
{
[, $options] = self::prepareRequest('POST', 'http://example.com', ['auth_bearer' => 'foobar'], HttpClientInterface::OPTIONS_DEFAULTS);
- $this->assertSame(['Accept: *', 'Authorization: Bearer foobar'], $options['headers']);
+ $this->assertSame(['Accept: */*', 'Authorization: Bearer foobar'], $options['headers']);
$this->assertSame(['Authorization: Bearer foobar'], $options['normalized_headers']['authorization']);
}
diff --git a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php
index 8a3936b442f7a..f8f2c3e18b1db 100644
--- a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php
+++ b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php
@@ -36,6 +36,7 @@ protected function getHttpClient(string $testCase): HttpClientInterface
"SERVER_NAME": "127.0.0.1",
"REQUEST_URI": "/",
"REQUEST_METHOD": "GET",
+ "HTTP_ACCEPT": "*/*",
"HTTP_FOO": "baR",
"HTTP_HOST": "localhost:8057"
}';
@@ -47,7 +48,7 @@ protected function getHttpClient(string $testCase): HttpClientInterface
return new MockHttpClient(function (string $method, string $url, array $options) use ($client) {
try {
// force the request to be completed so that we don't test side effects of the transport
- $response = $client->request($method, $url, $options);
+ $response = $client->request($method, $url, ['buffer' => false] + $options);
$content = $response->getContent(false);
return new MockResponse($content, $response->getInfo());
@@ -113,6 +114,12 @@ protected function getHttpClient(string $testCase): HttpClientInterface
$responses[] = $mock;
break;
+ case 'testAcceptHeader':
+ $responses[] = new MockResponse($body, ['response_headers' => $headers]);
+ $responses[] = new MockResponse(str_replace('*/*', 'foo/bar', $body), ['response_headers' => $headers]);
+ $responses[] = new MockResponse(str_replace('"HTTP_ACCEPT": "*/*",', '', $body), ['response_headers' => $headers]);
+ break;
+
case 'testResolve':
$responses[] = new MockResponse($body, ['response_headers' => $headers]);
$responses[] = new MockResponse($body, ['response_headers' => $headers]);
diff --git a/src/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php b/src/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php
index 9633f0174ec69..7a6da17dc0358 100644
--- a/src/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php
+++ b/src/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php
@@ -94,7 +94,7 @@ public function guess($path)
$type = trim(ob_get_clean());
- if (!preg_match('#^([a-z0-9\-]+/[a-z0-9\-\.]+)#i', $type, $match)) {
+ if (!preg_match('#^([a-z0-9\-]+/[a-z0-9\-\+\.]+)#i', $type, $match)) {
// it's not a type, but an error message
return null;
}
diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php
index 9af2c28256fab..db82ffce815a6 100644
--- a/src/Symfony/Component/HttpFoundation/Request.php
+++ b/src/Symfony/Component/HttpFoundation/Request.php
@@ -1447,14 +1447,11 @@ public function isMethod($method)
*
* @see https://tools.ietf.org/html/rfc7231#section-4.2.1
*
- * @param bool $andCacheable Adds the additional condition that the method should be cacheable. True by default.
- *
* @return bool
*/
- public function isMethodSafe(/* $andCacheable = true */)
+ public function isMethodSafe()
{
- if (!\func_num_args() || func_get_arg(0)) {
- // setting $andCacheable to false should be deprecated in 4.1
+ if (\func_num_args() > 0 && func_get_arg(0)) {
throw new \BadMethodCallException('Checking only for cacheable HTTP methods with Symfony\Component\HttpFoundation\Request::isMethodSafe() is not supported.');
}
diff --git a/src/Symfony/Component/HttpFoundation/Tests/File/UploadedFileTest.php b/src/Symfony/Component/HttpFoundation/Tests/File/UploadedFileTest.php
index b31bfcb5bb1be..17d319581f97f 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/File/UploadedFileTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/File/UploadedFileTest.php
@@ -152,7 +152,7 @@ public function testMoveLocalFileIsNotAllowed()
UPLOAD_ERR_OK
);
- $movedFile = $file->move(__DIR__.'/Fixtures/directory');
+ $file->move(__DIR__.'/Fixtures/directory');
}
public function failedUploadedFile()
diff --git a/src/Symfony/Component/HttpFoundation/Tests/HeaderBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/HeaderBagTest.php
index dcc266f69c41a..cabe038bdf00b 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/HeaderBagTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/HeaderBagTest.php
@@ -59,7 +59,7 @@ public function testGetDateException()
{
$this->expectException('RuntimeException');
$bag = new HeaderBag(['foo' => 'Tue']);
- $headerDate = $bag->getDate('foo');
+ $bag->getDate('foo');
}
public function testGetCacheControlHeader()
diff --git a/src/Symfony/Component/HttpFoundation/Tests/RedirectResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/RedirectResponseTest.php
index 92f4876da4ff1..e1ff3bf2bdb98 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/RedirectResponseTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/RedirectResponseTest.php
@@ -29,13 +29,13 @@ public function testGenerateMetaRedirect()
public function testRedirectResponseConstructorNullUrl()
{
$this->expectException('InvalidArgumentException');
- $response = new RedirectResponse(null);
+ new RedirectResponse(null);
}
public function testRedirectResponseConstructorWrongStatusCode()
{
$this->expectException('InvalidArgumentException');
- $response = new RedirectResponse('foo.bar', 404);
+ new RedirectResponse('foo.bar', 404);
}
public function testGenerateLocationHeader()
diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
index d56ef31476f59..03493b5327304 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php
@@ -2132,7 +2132,7 @@ public function testMethodSafeChecksCacheable()
$this->expectException('BadMethodCallException');
$request = new Request();
$request->setMethod('OPTIONS');
- $request->isMethodSafe();
+ $request->isMethodSafe(true);
}
/**
diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/NativeFileSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/NativeFileSessionHandlerTest.php
index cd167fb13ab0d..368af6a3e3e10 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/NativeFileSessionHandlerTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/NativeFileSessionHandlerTest.php
@@ -27,7 +27,7 @@ class NativeFileSessionHandlerTest extends TestCase
{
public function testConstruct()
{
- $storage = new NativeSessionStorage(['name' => 'TESTING'], new NativeFileSessionHandler(sys_get_temp_dir()));
+ new NativeSessionStorage(['name' => 'TESTING'], new NativeFileSessionHandler(sys_get_temp_dir()));
$this->assertEquals('user', ini_get('session.save_handler'));
@@ -40,7 +40,7 @@ public function testConstruct()
*/
public function testConstructSavePath($savePath, $expectedSavePath, $path)
{
- $handler = new NativeFileSessionHandler($savePath);
+ new NativeFileSessionHandler($savePath);
$this->assertEquals($expectedSavePath, ini_get('session.save_path'));
$this->assertDirectoryExists(realpath($path));
@@ -61,13 +61,13 @@ public function savePathDataProvider()
public function testConstructException()
{
$this->expectException('InvalidArgumentException');
- $handler = new NativeFileSessionHandler('something;invalid;with;too-many-args');
+ new NativeFileSessionHandler('something;invalid;with;too-many-args');
}
public function testConstructDefault()
{
$path = ini_get('session.save_path');
- $storage = new NativeSessionStorage(['name' => 'TESTING'], new NativeFileSessionHandler());
+ new NativeSessionStorage(['name' => 'TESTING'], new NativeFileSessionHandler());
$this->assertEquals($path, ini_get('session.save_path'));
}
diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/NullSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/NullSessionHandlerTest.php
index 0d246e1aa560b..f793db144c6ac 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/NullSessionHandlerTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/NullSessionHandlerTest.php
@@ -28,7 +28,7 @@ class NullSessionHandlerTest extends TestCase
{
public function testSaveHandlers()
{
- $storage = $this->getStorage();
+ $this->getStorage();
$this->assertEquals('user', ini_get('session.save_handler'));
}
diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php
index d080ce3ca6e5c..5aee54bab160e 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/PdoSessionHandlerTest.php
@@ -54,7 +54,7 @@ public function testWrongPdoErrMode()
$pdo = $this->getMemorySqlitePdo();
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_SILENT);
- $storage = new PdoSessionHandler($pdo);
+ new PdoSessionHandler($pdo);
}
public function testInexistentTable()
diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/NativeSessionStorageTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/NativeSessionStorageTest.php
index 17f46bef5e1a1..4efc8d2e9aa97 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/NativeSessionStorageTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/NativeSessionStorageTest.php
@@ -145,7 +145,7 @@ public function testDefaultSessionCacheLimiter()
{
$this->iniSet('session.cache_limiter', 'nocache');
- $storage = new NativeSessionStorage();
+ new NativeSessionStorage();
$this->assertEquals('', ini_get('session.cache_limiter'));
}
@@ -153,7 +153,7 @@ public function testExplicitSessionCacheLimiter()
{
$this->iniSet('session.cache_limiter', 'nocache');
- $storage = new NativeSessionStorage(['cache_limiter' => 'public']);
+ new NativeSessionStorage(['cache_limiter' => 'public']);
$this->assertEquals('public', ini_get('session.cache_limiter'));
}
diff --git a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php
index 32624c963fa07..144ef46742a04 100644
--- a/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php
+++ b/src/Symfony/Component/HttpKernel/DataCollector/RequestDataCollector.php
@@ -49,7 +49,6 @@ public function collect(Request $request, Response $response, \Exception $except
}
}
- $content = null;
try {
$content = $request->getContent();
} catch (\LogicException $e) {
@@ -59,7 +58,6 @@ public function collect(Request $request, Response $response, \Exception $except
$sessionMetadata = [];
$sessionAttributes = [];
- $session = null;
$flashes = [];
if ($request->hasSession()) {
$session = $request->getSession();
@@ -80,9 +78,9 @@ public function collect(Request $request, Response $response, \Exception $except
}
$dotenvVars = [];
- foreach (explode(',', getenv('SYMFONY_DOTENV_VARS')) as $name) {
- if ('' !== $name && false !== $value = getenv($name)) {
- $dotenvVars[$name] = $value;
+ foreach (explode(',', $_SERVER['SYMFONY_DOTENV_VARS'] ?? $_ENV['SYMFONY_DOTENV_VARS'] ?? '') as $name) {
+ if ('' !== $name && isset($_ENV[$name])) {
+ $dotenvVars[$name] = $_ENV[$name];
}
}
diff --git a/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php b/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php
index 25c071c335a02..3bdf0f5199891 100644
--- a/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php
+++ b/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php
@@ -130,7 +130,6 @@ public function update(Response $response)
$response->headers->set('Cache-Control', implode(', ', array_keys($flags)));
$maxAge = null;
- $sMaxage = null;
if (is_numeric($this->ageDirectives['max-age'])) {
$maxAge = $this->ageDirectives['max-age'] + $this->age;
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index 7d18d221d5c18..d91b4f64d9ce6 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -73,11 +73,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
private $requestStackSize = 0;
private $resetServices = false;
- const VERSION = '4.3.5';
- const VERSION_ID = 40305;
+ const VERSION = '4.3.6';
+ const VERSION_ID = 40306;
const MAJOR_VERSION = 4;
const MINOR_VERSION = 3;
- const RELEASE_VERSION = 5;
+ const RELEASE_VERSION = 6;
const EXTRA_VERSION = '';
const END_OF_MAINTENANCE = '01/2020';
@@ -754,7 +754,7 @@ protected function dumpContainer(ConfigCache $cache, ContainerBuilder $container
$fs->dumpFile($dir.$file, $code);
@chmod($dir.$file, 0666 & ~umask());
}
- $legacyFile = \dirname($dir.$file).'.legacy';
+ $legacyFile = \dirname($dir.key($content)).'.legacy';
if (file_exists($legacyFile)) {
@unlink($legacyFile);
}
diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php
index 3c5b19783774f..624658f727cef 100644
--- a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php
@@ -256,7 +256,7 @@ public function testArgumentWithNoTypeHintIsOk()
public function testControllersAreMadePublic()
{
$container = new ContainerBuilder();
- $resolver = $container->register('argument_resolver.service')->addArgument([]);
+ $container->register('argument_resolver.service')->addArgument([]);
$container->register('foo', ArgumentWithoutTypeController::class)
->setPublic(false)
@@ -364,7 +364,7 @@ public function testBindingsOnChildDefinitions()
public function testNotTaggedControllerServiceReceivesLocatorArgument()
{
$container = new ContainerBuilder();
- $resolver = $container->register('argument_resolver.not_tagged_controller')->addArgument([]);
+ $container->register('argument_resolver.not_tagged_controller')->addArgument([]);
$pass = new RegisterControllerArgumentLocatorsPass();
$pass->process($container);
diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php
index 2887c14f5d574..6e56dbe0bbd97 100644
--- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php
@@ -52,7 +52,7 @@ public function testReadsAnEmptyArrayWithReadWhenNothingCachedAtKey()
public function testUnlockFileThatDoesExist()
{
- $cacheKey = $this->storeSimpleEntry();
+ $this->storeSimpleEntry();
$this->store->lock($this->request);
$this->assertTrue($this->store->unlock($this->request));
@@ -92,7 +92,7 @@ public function testSetsTheXContentDigestResponseHeaderBeforeStoring()
{
$cacheKey = $this->storeSimpleEntry();
$entries = $this->getStoreMetadata($cacheKey);
- list($req, $res) = $entries[0];
+ list(, $res) = $entries[0];
$this->assertEquals('en9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08', $res['x-content-digest'][0]);
}
@@ -208,7 +208,7 @@ public function testOverwritesNonVaryingResponseWithStore()
{
$req1 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']);
$res1 = new Response('test 1', 200, ['Vary' => 'Foo Bar']);
- $key = $this->store->write($req1, $res1);
+ $this->store->write($req1, $res1);
$this->assertEquals($this->getStorePath('en'.hash('sha256', 'test 1')), $this->store->lookup($req1)->getContent());
$req2 = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Bling', 'HTTP_BAR' => 'Bam']);
@@ -229,7 +229,7 @@ public function testLocking()
$req = Request::create('/test', 'get', [], [], [], ['HTTP_FOO' => 'Foo', 'HTTP_BAR' => 'Bar']);
$this->assertTrue($this->store->lock($req));
- $path = $this->store->lock($req);
+ $this->store->lock($req);
$this->assertTrue($this->store->isLocked($req));
$this->store->unlock($req);
diff --git a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/Api/MandrillTransport.php b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/Api/MandrillTransport.php
index 9217eaa49f46b..c8e313e7b7391 100644
--- a/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/Api/MandrillTransport.php
+++ b/src/Symfony/Component/Mailer/Bridge/Mailchimp/Http/Api/MandrillTransport.php
@@ -17,6 +17,7 @@
use Symfony\Component\Mailer\SmtpEnvelope;
use Symfony\Component\Mailer\Transport\Http\Api\AbstractApiTransport;
use Symfony\Component\Mime\Email;
+use Symfony\Component\Mime\NamedAddress;
use Symfony\Contracts\HttpClient\HttpClientInterface;
/**
@@ -60,11 +61,15 @@ private function getPayload(Email $email, SmtpEnvelope $envelope): array
'html' => $email->getHtmlBody(),
'text' => $email->getTextBody(),
'subject' => $email->getSubject(),
- 'from_email' => $envelope->getSender()->toString(),
+ 'from_email' => $envelope->getSender()->getAddress(),
'to' => $this->getRecipients($email, $envelope),
],
];
+ if ($envelope->getSender() instanceof NamedAddress) {
+ $payload['message']['from_name'] = $envelope->getSender()->getName();
+ }
+
foreach ($email->getAttachments() as $attachment) {
$headers = $attachment->getPreparedHeaders();
$disposition = $headers->getHeaderBody('Content-Disposition');
@@ -104,10 +109,16 @@ protected function getRecipients(Email $email, SmtpEnvelope $envelope): array
$type = 'cc';
}
- $recipients[] = [
- 'email' => $recipient->toString(),
+ $recipientPayload = [
+ 'email' => $recipient->getAddress(),
'type' => $type,
];
+
+ if ($recipient instanceof NamedAddress) {
+ $recipientPayload['name'] = $recipient->getName();
+ }
+
+ $recipients[] = $recipientPayload;
}
return $recipients;
diff --git a/src/Symfony/Component/Mailer/Tests/SmtpEnvelopeTest.php b/src/Symfony/Component/Mailer/Tests/SmtpEnvelopeTest.php
index f963a5a0f4af4..edb8b97cabbf8 100644
--- a/src/Symfony/Component/Mailer/Tests/SmtpEnvelopeTest.php
+++ b/src/Symfony/Component/Mailer/Tests/SmtpEnvelopeTest.php
@@ -41,13 +41,13 @@ public function testConstructorWithAddressRecipients()
public function testConstructorWithNoRecipients()
{
$this->expectException(\InvalidArgumentException::class);
- $e = new SmtpEnvelope(new Address('fabien@symfony.com'), []);
+ new SmtpEnvelope(new Address('fabien@symfony.com'), []);
}
public function testConstructorWithWrongRecipients()
{
$this->expectException(\InvalidArgumentException::class);
- $e = new SmtpEnvelope(new Address('fabien@symfony.com'), ['lucas@symfony.com']);
+ new SmtpEnvelope(new Address('fabien@symfony.com'), ['lucas@symfony.com']);
}
public function testSenderFromHeaders()
diff --git a/src/Symfony/Component/Messenger/Command/AbstractFailedMessagesCommand.php b/src/Symfony/Component/Messenger/Command/AbstractFailedMessagesCommand.php
index 194d42c109ac4..291ed85aeba57 100644
--- a/src/Symfony/Component/Messenger/Command/AbstractFailedMessagesCommand.php
+++ b/src/Symfony/Component/Messenger/Command/AbstractFailedMessagesCommand.php
@@ -62,8 +62,7 @@ protected function displaySingleMessage(Envelope $envelope, SymfonyStyle $io)
/** @var SentToFailureTransportStamp|null $sentToFailureTransportStamp */
$sentToFailureTransportStamp = $envelope->last(SentToFailureTransportStamp::class);
- /** @var RedeliveryStamp|null $lastRedeliveryStamp */
- $lastRedeliveryStamp = $envelope->last(RedeliveryStamp::class);
+ $lastRedeliveryStampWithException = $this->getLastRedeliveryStampWithException($envelope);
$rows = [
['Class', \get_class($envelope->getMessage())],
@@ -73,13 +72,13 @@ protected function displaySingleMessage(Envelope $envelope, SymfonyStyle $io)
$rows[] = ['Message Id', $id];
}
- $flattenException = null === $lastRedeliveryStamp ? null : $lastRedeliveryStamp->getFlattenException();
+ $flattenException = null === $lastRedeliveryStampWithException ? null : $lastRedeliveryStampWithException->getFlattenException();
if (null === $sentToFailureTransportStamp) {
$io->warning('Message does not appear to have been sent to this transport after failing');
} else {
$rows = array_merge($rows, [
- ['Failed at', null === $lastRedeliveryStamp ? '' : $lastRedeliveryStamp->getRedeliveredAt()->format('Y-m-d H:i:s')],
- ['Error', null === $lastRedeliveryStamp ? '' : $lastRedeliveryStamp->getExceptionMessage()],
+ ['Failed at', null === $lastRedeliveryStampWithException ? '' : $lastRedeliveryStampWithException->getRedeliveredAt()->format('Y-m-d H:i:s')],
+ ['Error', null === $lastRedeliveryStampWithException ? '' : $lastRedeliveryStampWithException->getExceptionMessage()],
['Error Class', null === $flattenException ? '(unknown)' : $flattenException->getClass()],
['Transport', $sentToFailureTransportStamp->getOriginalReceiverName()],
]);
@@ -121,4 +120,16 @@ protected function getReceiver(): ReceiverInterface
{
return $this->receiver;
}
+
+ protected function getLastRedeliveryStampWithException(Envelope $envelope): ?RedeliveryStamp
+ {
+ /** @var RedeliveryStamp $stamp */
+ foreach (array_reverse($envelope->all(RedeliveryStamp::class)) as $stamp) {
+ if (null !== $stamp->getExceptionMessage()) {
+ return $stamp;
+ }
+ }
+
+ return null;
+ }
}
diff --git a/src/Symfony/Component/Messenger/Command/FailedMessagesShowCommand.php b/src/Symfony/Component/Messenger/Command/FailedMessagesShowCommand.php
index 0444d79f447ff..b0f16b704e3d8 100644
--- a/src/Symfony/Component/Messenger/Command/FailedMessagesShowCommand.php
+++ b/src/Symfony/Component/Messenger/Command/FailedMessagesShowCommand.php
@@ -18,7 +18,6 @@
use Symfony\Component\Console\Output\ConsoleOutputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
-use Symfony\Component\Messenger\Stamp\RedeliveryStamp;
use Symfony\Component\Messenger\Transport\Receiver\ListableReceiverInterface;
/**
@@ -83,14 +82,13 @@ private function listMessages(SymfonyStyle $io, int $max)
$rows = [];
foreach ($envelopes as $envelope) {
- /** @var RedeliveryStamp|null $lastRedeliveryStamp */
- $lastRedeliveryStamp = $envelope->last(RedeliveryStamp::class);
+ $lastRedeliveryStampWithException = $this->getLastRedeliveryStampWithException($envelope);
$rows[] = [
$this->getMessageId($envelope),
\get_class($envelope->getMessage()),
- null === $lastRedeliveryStamp ? '' : $lastRedeliveryStamp->getRedeliveredAt()->format('Y-m-d H:i:s'),
- null === $lastRedeliveryStamp ? '' : $lastRedeliveryStamp->getExceptionMessage(),
+ null === $lastRedeliveryStampWithException ? '' : $lastRedeliveryStampWithException->getRedeliveredAt()->format('Y-m-d H:i:s'),
+ null === $lastRedeliveryStampWithException ? '' : $lastRedeliveryStampWithException->getExceptionMessage(),
];
}
diff --git a/src/Symfony/Component/Messenger/Exception/RejectRedeliveredMessageException.php b/src/Symfony/Component/Messenger/Exception/RejectRedeliveredMessageException.php
new file mode 100644
index 0000000000000..79b94fa2656f2
--- /dev/null
+++ b/src/Symfony/Component/Messenger/Exception/RejectRedeliveredMessageException.php
@@ -0,0 +1,21 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Messenger\Exception;
+
+/**
+ * @author Tobias Schultze
+ *
+ * @experimental in 4.3
+ */
+class RejectRedeliveredMessageException extends RuntimeException
+{
+}
diff --git a/src/Symfony/Component/Messenger/Middleware/RejectRedeliveredMessageMiddleware.php b/src/Symfony/Component/Messenger/Middleware/RejectRedeliveredMessageMiddleware.php
new file mode 100644
index 0000000000000..2c6e6b6ff718f
--- /dev/null
+++ b/src/Symfony/Component/Messenger/Middleware/RejectRedeliveredMessageMiddleware.php
@@ -0,0 +1,50 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Messenger\Middleware;
+
+use Symfony\Component\Messenger\Envelope;
+use Symfony\Component\Messenger\Exception\RejectRedeliveredMessageException;
+use Symfony\Component\Messenger\Stamp\ReceivedStamp;
+use Symfony\Component\Messenger\Transport\AmqpExt\AmqpReceivedStamp;
+
+/**
+ * Middleware that throws a RejectRedeliveredMessageException when a message is detected that has been redelivered by AMQP.
+ *
+ * The middleware runs before the HandleMessageMiddleware and prevents redelivered messages from being handled directly.
+ * The thrown exception is caught by the worker and will trigger the retry logic according to the retry strategy.
+ *
+ * AMQP redelivers messages when they do not get acknowledged or rejected. This can happen when the connection times out
+ * or an exception is thrown before acknowledging or rejecting. When such errors happen again while handling the
+ * redelivered message, the message would get redelivered again and again. The purpose of this middleware is to prevent
+ * infinite redelivery loops and to unblock the queue by republishing the redelivered messages as retries with a retry
+ * limit and potential delay.
+ *
+ * @experimental in 4.3
+ *
+ * @author Tobias Schultze
+ */
+class RejectRedeliveredMessageMiddleware implements MiddlewareInterface
+{
+ public function handle(Envelope $envelope, StackInterface $stack): Envelope
+ {
+ // ignore the dispatched messages for retry
+ if (null !== $envelope->last(ReceivedStamp::class)) {
+ $amqpReceivedStamp = $envelope->last(AmqpReceivedStamp::class);
+
+ if ($amqpReceivedStamp instanceof AmqpReceivedStamp && $amqpReceivedStamp->getAmqpEnvelope()->isRedelivery()) {
+ throw new RejectRedeliveredMessageException('Redelivered message from AMQP detected that will be rejected and trigger the retry logic.');
+ }
+ }
+
+ return $stack->next()->handle($envelope, $stack);
+ }
+}
diff --git a/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesRetryCommandTest.php b/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesRetryCommandTest.php
index bc69a1c2e8a2e..bcc67f79d566b 100644
--- a/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesRetryCommandTest.php
+++ b/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesRetryCommandTest.php
@@ -13,15 +13,12 @@
use PHPUnit\Framework\TestCase;
use Symfony\Component\Console\Tester\CommandTester;
-use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\Messenger\Command\FailedMessagesRetryCommand;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\MessageBusInterface;
-use Symfony\Component\Messenger\Retry\RetryStrategyInterface;
-use Symfony\Component\Messenger\Stamp\ReceivedStamp;
-use Symfony\Component\Messenger\Stamp\RedeliveryStamp;
use Symfony\Component\Messenger\Transport\Receiver\ListableReceiverInterface;
+use Symfony\Component\Messenger\Worker;
class FailedMessagesRetryCommandTest extends TestCase
{
@@ -37,52 +34,16 @@ public function testBasicRun()
// the bus should be called in the worker
$bus->expects($this->exactly(2))->method('dispatch')->willReturn(new Envelope(new \stdClass()));
- $command = new FailedMessagesRetryCommand('failure_receiver', $receiver, $bus, $dispatcher);
+ $command = new FailedMessagesRetryCommand(
+ 'failure_receiver',
+ $receiver,
+ $bus,
+ $dispatcher
+ );
$tester = new CommandTester($command);
$tester->execute(['id' => [10, 12]]);
$this->assertStringContainsString('[OK]', $tester->getDisplay());
}
-
- public function testExceptionOnRetry()
- {
- $receiver = $this->createMock(ListableReceiverInterface::class);
- $receiver->expects($this->once())->method('find')->with(10)->willReturn(new Envelope(new \stdClass()));
- // message will eventually be ack'ed in Worker
- $receiver->expects($this->once())->method('ack');
-
- $dispatcher = $this->createMock(EventDispatcherInterface::class);
- $bus = $this->createMock(MessageBusInterface::class);
- // the bus should be called in the worker
- $bus->expects($this->at(0))
- ->method('dispatch')
- ->with($this->callback(function (Envelope $envelope) {
- $lastReceivedStamp = $envelope->last(ReceivedStamp::class);
-
- return $lastReceivedStamp instanceof ReceivedStamp && \is_string($lastReceivedStamp->getTransportName());
- }))
- ->will($this->throwException(new \Exception('Mock test exception')));
-
- $bus->expects($this->at(1))
- ->method('dispatch')
- ->with($this->callback(function (Envelope $envelope) {
- $lastRedeliveryStamp = $envelope->last(RedeliveryStamp::class);
-
- return $lastRedeliveryStamp instanceof RedeliveryStamp &&
- \is_string($lastRedeliveryStamp->getExceptionMessage()) &&
- $lastRedeliveryStamp->getFlattenException() instanceof FlattenException;
- }))
- ->willReturn(new Envelope(new \stdClass()));
-
- $retryStrategy = $this->createMock(RetryStrategyInterface::class);
- $retryStrategy->expects($this->once())->method('isRetryable')->with($this->isInstanceOf(Envelope::class))->willReturn(true);
-
- $command = new FailedMessagesRetryCommand('failure_receiver', $receiver, $bus, $dispatcher, $retryStrategy);
-
- $tester = new CommandTester($command);
- $tester->execute(['id' => [10]]);
-
- $this->assertStringContainsString('[OK]', $tester->getDisplay());
- }
}
diff --git a/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php b/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php
index bd77f3f14f8a8..f632d9890b343 100644
--- a/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php
+++ b/src/Symfony/Component/Messenger/Tests/Command/FailedMessagesShowCommandTest.php
@@ -58,4 +58,40 @@ public function testBasicRun()
$redeliveryStamp->getRedeliveredAt()->format('Y-m-d H:i:s')),
$tester->getDisplay(true));
}
+
+ public function testMultipleRedeliveryFails()
+ {
+ $sentToFailureStamp = new SentToFailureTransportStamp('async');
+ $redeliveryStamp1 = new RedeliveryStamp(0, 'failure_receiver', 'Things are bad!');
+ $redeliveryStamp2 = new RedeliveryStamp(0, 'failure_receiver');
+ $envelope = new Envelope(new \stdClass(), [
+ new TransportMessageIdStamp(15),
+ $sentToFailureStamp,
+ $redeliveryStamp1,
+ $redeliveryStamp2,
+ ]);
+ $receiver = $this->createMock(ListableReceiverInterface::class);
+ $receiver->expects($this->once())->method('find')->with(15)->willReturn($envelope);
+
+ $command = new FailedMessagesShowCommand(
+ 'failure_receiver',
+ $receiver
+ );
+
+ $tester = new CommandTester($command);
+ $tester->execute(['id' => 15]);
+
+ $this->assertStringContainsString(sprintf(<<getRedeliveredAt()->format('Y-m-d H:i:s')),
+ $tester->getDisplay(true));
+ }
}
diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php
index 6e7724d506927..b7ac30bee1c8a 100644
--- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php
+++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php
@@ -44,8 +44,11 @@ public function testGetAMessageWillChangeItsStatus()
$queryBuilder
->method('getParameters')
->willReturn([]);
+ $queryBuilder
+ ->method('getParameterTypes')
+ ->willReturn([]);
$driverConnection
- ->method('prepare')
+ ->method('executeQuery')
->willReturn($stmt);
$connection = new Connection([], $driverConnection, $schemaSynchronizer);
@@ -65,13 +68,17 @@ public function testGetWithNoPendingMessageWillReturnNull()
$queryBuilder
->method('getParameters')
->willReturn([]);
+ $queryBuilder
+ ->method('getParameterTypes')
+ ->willReturn([]);
$driverConnection->expects($this->once())
->method('createQueryBuilder')
->willReturn($queryBuilder);
- $driverConnection->method('prepare')
- ->willReturn($stmt);
$driverConnection->expects($this->never())
->method('update');
+ $driverConnection
+ ->method('executeQuery')
+ ->willReturn($stmt);
$connection = new Connection([], $driverConnection, $schemaSynchronizer);
$doctrineEnvelope = $connection->get();
@@ -273,7 +280,7 @@ public function testFind()
->method('getParameters')
->willReturn([]);
$driverConnection
- ->method('prepare')
+ ->method('executeQuery')
->willReturn($stmt);
$connection = new Connection([], $driverConnection, $schemaSynchronizer);
@@ -316,8 +323,11 @@ public function testFindAll()
$queryBuilder
->method('getParameters')
->willReturn([]);
+ $queryBuilder
+ ->method('getParameterTypes')
+ ->willReturn([]);
$driverConnection
- ->method('prepare')
+ ->method('executeQuery')
->willReturn($stmt);
$connection = new Connection([], $driverConnection, $schemaSynchronizer);
diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php
index fa05a43b0b66b..a01e68db39e2a 100644
--- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php
+++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php
@@ -80,25 +80,25 @@ public function testItRetrieveTheFirstAvailableMessage()
'body' => '{"message": "Hi handled"}',
'headers' => json_encode(['type' => DummyMessage::class]),
'queue_name' => 'default',
- 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')),
- 'available_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')),
- 'delivered_at' => Connection::formatDateTime(new \DateTime()),
+ 'created_at' => $this->formatDateTime(new \DateTime('2019-03-15 12:00:00')),
+ 'available_at' => $this->formatDateTime(new \DateTime('2019-03-15 12:00:00')),
+ 'delivered_at' => $this->formatDateTime(new \DateTime()),
]);
// one available later
$this->driverConnection->insert('messenger_messages', [
'body' => '{"message": "Hi delayed"}',
'headers' => json_encode(['type' => DummyMessage::class]),
'queue_name' => 'default',
- 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')),
- 'available_at' => Connection::formatDateTime(new \DateTime('2019-03-15 13:00:00')),
+ 'created_at' => $this->formatDateTime(new \DateTime('2019-03-15 12:00:00')),
+ 'available_at' => $this->formatDateTime(new \DateTime('2019-03-15 13:00:00')),
]);
// one available
$this->driverConnection->insert('messenger_messages', [
'body' => '{"message": "Hi available"}',
'headers' => json_encode(['type' => DummyMessage::class]),
'queue_name' => 'default',
- 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')),
- 'available_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:30:00')),
+ 'created_at' => $this->formatDateTime(new \DateTime('2019-03-15 12:00:00')),
+ 'available_at' => $this->formatDateTime(new \DateTime('2019-03-15 12:30:00')),
]);
$encoded = $this->connection->get();
@@ -114,33 +114,33 @@ public function testItCountMessages()
'body' => '{"message": "Hi handled"}',
'headers' => json_encode(['type' => DummyMessage::class]),
'queue_name' => 'default',
- 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')),
- 'available_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')),
- 'delivered_at' => Connection::formatDateTime(new \DateTime()),
+ 'created_at' => $this->formatDateTime(new \DateTime('2019-03-15 12:00:00')),
+ 'available_at' => $this->formatDateTime(new \DateTime('2019-03-15 12:00:00')),
+ 'delivered_at' => $this->formatDateTime(new \DateTime()),
]);
// one available later
$this->driverConnection->insert('messenger_messages', [
'body' => '{"message": "Hi delayed"}',
'headers' => json_encode(['type' => DummyMessage::class]),
'queue_name' => 'default',
- 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')),
- 'available_at' => Connection::formatDateTime((new \DateTime())->modify('+1 minute')),
+ 'created_at' => $this->formatDateTime(new \DateTime('2019-03-15 12:00:00')),
+ 'available_at' => $this->formatDateTime((new \DateTime())->modify('+1 minute')),
]);
// one available
$this->driverConnection->insert('messenger_messages', [
'body' => '{"message": "Hi available"}',
'headers' => json_encode(['type' => DummyMessage::class]),
'queue_name' => 'default',
- 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')),
- 'available_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:30:00')),
+ 'created_at' => $this->formatDateTime(new \DateTime('2019-03-15 12:00:00')),
+ 'available_at' => $this->formatDateTime(new \DateTime('2019-03-15 12:30:00')),
]);
// another available
$this->driverConnection->insert('messenger_messages', [
'body' => '{"message": "Hi available"}',
'headers' => json_encode(['type' => DummyMessage::class]),
'queue_name' => 'default',
- 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')),
- 'available_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:30:00')),
+ 'created_at' => $this->formatDateTime(new \DateTime('2019-03-15 12:00:00')),
+ 'available_at' => $this->formatDateTime(new \DateTime('2019-03-15 12:30:00')),
]);
$this->assertSame(2, $this->connection->getMessageCount());
@@ -155,16 +155,16 @@ public function testItRetrieveTheMessageThatIsOlderThanRedeliverTimeout()
'body' => '{"message": "Hi requeued"}',
'headers' => json_encode(['type' => DummyMessage::class]),
'queue_name' => 'default',
- 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')),
- 'available_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')),
- 'delivered_at' => Connection::formatDateTime($twoHoursAgo),
+ 'created_at' => $this->formatDateTime(new \DateTime('2019-03-15 12:00:00')),
+ 'available_at' => $this->formatDateTime(new \DateTime('2019-03-15 12:00:00')),
+ 'delivered_at' => $this->formatDateTime($twoHoursAgo),
]);
$this->driverConnection->insert('messenger_messages', [
'body' => '{"message": "Hi available"}',
'headers' => json_encode(['type' => DummyMessage::class]),
'queue_name' => 'default',
- 'created_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:00:00')),
- 'available_at' => Connection::formatDateTime(new \DateTime('2019-03-15 12:30:00')),
+ 'created_at' => $this->formatDateTime(new \DateTime('2019-03-15 12:00:00')),
+ 'available_at' => $this->formatDateTime(new \DateTime('2019-03-15 12:30:00')),
]);
$next = $this->connection->get();
@@ -181,4 +181,9 @@ public function testTheTransportIsSetupOnGet()
$envelope = $this->connection->get();
$this->assertEquals('the body', $envelope['body']);
}
+
+ private function formatDateTime(\DateTime $dateTime)
+ {
+ return $dateTime->format($this->driverConnection->getDatabasePlatform()->getDateTimeFormatString());
+ }
}
diff --git a/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php
index 4e525702aa5f8..81baaac8d96a2 100644
--- a/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php
+++ b/src/Symfony/Component/Messenger/Tests/Transport/RedisExt/ConnectionTest.php
@@ -57,13 +57,8 @@ public function testFromDsn()
public function testFromDsnWithOptions()
{
$this->assertEquals(
- new Connection(['stream' => 'queue', 'group' => 'group1', 'consumer' => 'consumer1', 'auto_setup' => false], [
- 'host' => 'localhost',
- 'port' => 6379,
- ], [
- 'serializer' => 2,
- ]),
- Connection::fromDsn('redis://localhost/queue/group1/consumer1', ['serializer' => 2, 'auto_setup' => false])
+ Connection::fromDsn('redis://localhost', ['stream' => 'queue', 'group' => 'group1', 'consumer' => 'consumer1', 'auto_setup' => false, 'serializer' => 2]),
+ Connection::fromDsn('redis://localhost/queue/group1/consumer1?serializer=2&auto_setup=0')
);
}
@@ -99,7 +94,21 @@ public function testAuth()
$redis = $this->getMockBuilder(\Redis::class)->disableOriginalConstructor()->getMock();
$redis->expects($this->exactly(1))->method('auth')
- ->with('password');
+ ->with('password')
+ ->willReturn(true);
+
+ Connection::fromDsn('redis://password@localhost/queue', [], $redis);
+ }
+
+ public function testFailedAuth()
+ {
+ $this->expectException(\InvalidArgumentException::class);
+ $this->expectExceptionMessage('Redis connection failed');
+ $redis = $this->getMockBuilder(\Redis::class)->disableOriginalConstructor()->getMock();
+
+ $redis->expects($this->exactly(1))->method('auth')
+ ->with('password')
+ ->willReturn(false);
Connection::fromDsn('redis://password@localhost/queue', [], $redis);
}
diff --git a/src/Symfony/Component/Messenger/Tests/WorkerTest.php b/src/Symfony/Component/Messenger/Tests/WorkerTest.php
index ad7477253e86b..9a09c0a04a333 100644
--- a/src/Symfony/Component/Messenger/Tests/WorkerTest.php
+++ b/src/Symfony/Component/Messenger/Tests/WorkerTest.php
@@ -118,8 +118,8 @@ public function testDispatchCausesRetry()
}
});
- // old message acknowledged
- $this->assertSame(1, $receiver->getAcknowledgeCount());
+ // old message rejected
+ $this->assertSame(1, $receiver->getRejectCount());
}
public function testUnrecoverableMessageHandlingExceptionPreventsRetries()
diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php
index 2c8bcd35cc459..f665e8b31c492 100644
--- a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php
+++ b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php
@@ -124,8 +124,14 @@ public function send(string $body, array $headers, int $delay = 0): string
$body,
json_encode($headers),
$this->configuration['queue_name'],
- self::formatDateTime($now),
- self::formatDateTime($availableAt),
+ $now,
+ $availableAt,
+ ], [
+ null,
+ null,
+ null,
+ Type::DATETIME,
+ Type::DATETIME,
]);
return $this->driverConnection->lastInsertId();
@@ -143,7 +149,8 @@ public function get(): ?array
// use SELECT ... FOR UPDATE to lock table
$doctrineEnvelope = $this->executeQuery(
$query->getSQL().' '.$this->driverConnection->getDatabasePlatform()->getWriteLockSQL(),
- $query->getParameters()
+ $query->getParameters(),
+ $query->getParameterTypes()
)->fetch();
if (false === $doctrineEnvelope) {
@@ -160,8 +167,10 @@ public function get(): ?array
->where('id = ?');
$now = new \DateTime();
$this->executeQuery($queryBuilder->getSQL(), [
- self::formatDateTime($now),
+ $now,
$doctrineEnvelope['id'],
+ ], [
+ Type::DATETIME,
]);
$this->driverConnection->commit();
@@ -228,7 +237,7 @@ public function getMessageCount(): int
->select('COUNT(m.id) as message_count')
->setMaxResults(1);
- return $this->executeQuery($queryBuilder->getSQL(), $queryBuilder->getParameters())->fetchColumn();
+ return $this->executeQuery($queryBuilder->getSQL(), $queryBuilder->getParameters(), $queryBuilder->getParameterTypes())->fetchColumn();
}
public function findAll(int $limit = null): array
@@ -238,7 +247,7 @@ public function findAll(int $limit = null): array
$queryBuilder->setMaxResults($limit);
}
- $data = $this->executeQuery($queryBuilder->getSQL(), $queryBuilder->getParameters())->fetchAll();
+ $data = $this->executeQuery($queryBuilder->getSQL(), $queryBuilder->getParameters(), $queryBuilder->getParameterTypes())->fetchAll();
return array_map(function ($doctrineEnvelope) {
return $this->decodeEnvelopeHeaders($doctrineEnvelope);
@@ -267,9 +276,12 @@ private function createAvailableMessagesQueryBuilder(): QueryBuilder
->andWhere('m.available_at <= ?')
->andWhere('m.queue_name = ?')
->setParameters([
- self::formatDateTime($redeliverLimit),
- self::formatDateTime($now),
+ $redeliverLimit,
+ $now,
$this->configuration['queue_name'],
+ ], [
+ Type::DATETIME,
+ Type::DATETIME,
]);
}
@@ -280,12 +292,10 @@ private function createQueryBuilder(): QueryBuilder
->from($this->configuration['table_name'], 'm');
}
- private function executeQuery(string $sql, array $parameters = [])
+ private function executeQuery(string $sql, array $parameters = [], array $types = [])
{
- $stmt = null;
try {
- $stmt = $this->driverConnection->prepare($sql);
- $stmt->execute($parameters);
+ $stmt = $this->driverConnection->executeQuery($sql, $parameters, $types);
} catch (TableNotFoundException $e) {
if ($this->driverConnection->isTransactionActive()) {
throw $e;
@@ -295,11 +305,7 @@ private function executeQuery(string $sql, array $parameters = [])
if ($this->autoSetup) {
$this->setup();
}
- // statement not prepared ? SQLite throw on exception on prepare if the table does not exist
- if (null === $stmt) {
- $stmt = $this->driverConnection->prepare($sql);
- }
- $stmt->execute($parameters);
+ $stmt = $this->driverConnection->executeQuery($sql, $parameters, $types);
}
return $stmt;
@@ -332,11 +338,6 @@ private function getSchema(): Schema
return $schema;
}
- public static function formatDateTime(\DateTimeInterface $dateTime)
- {
- return $dateTime->format('Y-m-d\TH:i:s');
- }
-
private function decodeEnvelopeHeaders(array $doctrineEnvelope): array
{
$doctrineEnvelope['headers'] = json_decode($doctrineEnvelope['headers'], true);
diff --git a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php
index 59ec9f029d6a4..6ded724ca5bfa 100644
--- a/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php
+++ b/src/Symfony/Component/Messenger/Transport/RedisExt/Connection.php
@@ -20,6 +20,7 @@
*
* @author Alexander Schranz
* @author Antoine Bluchet
+ * @author Robin Chalas
*
* @internal
* @final
@@ -52,8 +53,8 @@ public function __construct(array $configuration, array $connectionCredentials =
$this->connection->connect($connectionCredentials['host'] ?? '127.0.0.1', $connectionCredentials['port'] ?? 6379);
$this->connection->setOption(\Redis::OPT_SERIALIZER, $redisOptions['serializer'] ?? \Redis::SERIALIZER_PHP);
- if (isset($connectionCredentials['auth'])) {
- $this->connection->auth($connectionCredentials['auth']);
+ if (isset($connectionCredentials['auth']) && !$this->connection->auth($connectionCredentials['auth'])) {
+ throw new InvalidArgumentException(sprintf('Redis connection failed: %s', $redis->getLastError()));
}
$this->stream = $configuration['stream'] ?? self::DEFAULT_OPTIONS['stream'];
@@ -70,9 +71,9 @@ public static function fromDsn(string $dsn, array $redisOptions = [], \Redis $re
$pathParts = explode('/', $parsedUrl['path'] ?? '');
- $stream = $pathParts[1] ?? null;
- $group = $pathParts[2] ?? null;
- $consumer = $pathParts[3] ?? null;
+ $stream = $pathParts[1] ?? $redisOptions['stream'] ?? null;
+ $group = $pathParts[2] ?? $redisOptions['group'] ?? null;
+ $consumer = $pathParts[3] ?? $redisOptions['consumer'] ?? null;
$connectionCredentials = [
'host' => $parsedUrl['host'] ?? '127.0.0.1',
@@ -105,7 +106,6 @@ public function get(): ?array
$messageId = '0'; // will receive consumers pending messages
}
- $e = null;
try {
$messages = $this->connection->xreadgroup(
$this->group,
diff --git a/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php b/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php
index 793da4a44802a..9a42bcc699bbf 100644
--- a/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php
+++ b/src/Symfony/Component/Messenger/Transport/Serialization/PhpSerializer.php
@@ -52,7 +52,6 @@ public function encode(Envelope $envelope): array
private function safelyUnserialize($contents)
{
- $e = null;
$signalingException = new MessageDecodingFailedException(sprintf('Could not decode message using PHP serialization: %s.', $contents));
$prevUnserializeHandler = ini_set('unserialize_callback_func', self::class.'::handleUnserializeCallback');
$prevErrorHandler = set_error_handler(function ($type, $msg, $file, $line, $context = []) use (&$prevErrorHandler, $signalingException) {
diff --git a/src/Symfony/Component/Messenger/Worker.php b/src/Symfony/Component/Messenger/Worker.php
index 3ce1bd79e5857..6205baefd43bd 100644
--- a/src/Symfony/Component/Messenger/Worker.php
+++ b/src/Symfony/Component/Messenger/Worker.php
@@ -12,13 +12,13 @@
namespace Symfony\Component\Messenger;
use Psr\Log\LoggerInterface;
-use Symfony\Component\Debug\Exception\FlattenException;
use Symfony\Component\EventDispatcher\LegacyEventDispatcherProxy;
use Symfony\Component\Messenger\Event\WorkerMessageFailedEvent;
use Symfony\Component\Messenger\Event\WorkerMessageHandledEvent;
use Symfony\Component\Messenger\Event\WorkerMessageReceivedEvent;
use Symfony\Component\Messenger\Event\WorkerStoppedEvent;
use Symfony\Component\Messenger\Exception\HandlerFailedException;
+use Symfony\Component\Messenger\Exception\RejectRedeliveredMessageException;
use Symfony\Component\Messenger\Exception\UnrecoverableExceptionInterface;
use Symfony\Component\Messenger\Retry\RetryStrategyInterface;
use Symfony\Component\Messenger\Stamp\DelayStamp;
@@ -136,6 +136,13 @@ private function handleMessage(Envelope $envelope, ReceiverInterface $receiver,
try {
$envelope = $this->bus->dispatch($envelope->with(new ReceivedStamp($transportName)));
} catch (\Throwable $throwable) {
+ $rejectFirst = $throwable instanceof RejectRedeliveredMessageException;
+ if ($rejectFirst) {
+ // redelivered messages are rejected first so that continuous failures in an event listener or while
+ // publishing for retry does not cause infinite redelivery loops
+ $receiver->reject($envelope);
+ }
+
if ($throwable instanceof HandlerFailedException) {
$envelope = $throwable->getEnvelope();
}
@@ -154,18 +161,18 @@ private function handleMessage(Envelope $envelope, ReceiverInterface $receiver,
// add the delay and retry stamp info + remove ReceivedStamp
$retryEnvelope = $envelope->with(new DelayStamp($delay))
- ->with(new RedeliveryStamp($retryCount, $transportName, $throwable->getMessage(), $this->flattenedException($throwable)))
+ ->with(new RedeliveryStamp($retryCount, $transportName))
->withoutAll(ReceivedStamp::class);
- // re-send the message
+ // re-send the message for retry
$this->bus->dispatch($retryEnvelope);
- // acknowledge the previous message has received
- $receiver->ack($envelope);
} else {
if (null !== $this->logger) {
$this->logger->critical('Error thrown while handling message {class}. Removing from transport after {retryCount} retries. Error: "{error}"', $context + ['retryCount' => $retryCount, 'error' => $throwable->getMessage(), 'exception' => $throwable]);
}
+ }
+ if (!$rejectFirst) {
$receiver->reject($envelope);
}
@@ -217,17 +224,4 @@ private function shouldRetry(\Throwable $e, Envelope $envelope, RetryStrategyInt
return $retryStrategy->isRetryable($envelope);
}
-
- private function flattenedException(\Throwable $throwable): ?FlattenException
- {
- if (!class_exists(FlattenException::class)) {
- return null;
- }
-
- if ($throwable instanceof HandlerFailedException) {
- $throwable = $throwable->getNestedExceptions()[0];
- }
-
- return FlattenException::createFromThrowable($throwable);
- }
}
diff --git a/src/Symfony/Component/Mime/CharacterStream.php b/src/Symfony/Component/Mime/CharacterStream.php
index 9b80b2efa481a..045b477093c66 100644
--- a/src/Symfony/Component/Mime/CharacterStream.php
+++ b/src/Symfony/Component/Mime/CharacterStream.php
@@ -116,7 +116,6 @@ public function read(int $length): ?string
if ($this->currentPos >= $this->charCount) {
return null;
}
- $ret = null;
$length = ($this->currentPos + $length > $this->charCount) ? $this->charCount - $this->currentPos : $length;
if ($this->fixedWidth > 0) {
$len = $length * $this->fixedWidth;
diff --git a/src/Symfony/Component/Mime/FileBinaryMimeTypeGuesser.php b/src/Symfony/Component/Mime/FileBinaryMimeTypeGuesser.php
index a25ebe4d5cdcd..e00ce6525b71a 100644
--- a/src/Symfony/Component/Mime/FileBinaryMimeTypeGuesser.php
+++ b/src/Symfony/Component/Mime/FileBinaryMimeTypeGuesser.php
@@ -85,7 +85,7 @@ public function guessMimeType(string $path): ?string
$type = trim(ob_get_clean());
- if (!preg_match('#^([a-z0-9\-]+/[a-z0-9\-\.]+)#i', $type, $match)) {
+ if (!preg_match('#^([a-z0-9\-]+/[a-z0-9\-\+\.]+)#i', $type, $match)) {
// it's not a type, but an error message
return null;
}
diff --git a/src/Symfony/Component/Mime/Tests/EmailTest.php b/src/Symfony/Component/Mime/Tests/EmailTest.php
index 764f66b079480..1822da12aaa45 100644
--- a/src/Symfony/Component/Mime/Tests/EmailTest.php
+++ b/src/Symfony/Component/Mime/Tests/EmailTest.php
@@ -320,8 +320,6 @@ public function testGenerateBody()
$e->text('text content');
$e->attach($file);
$e->attach($image, 'test.gif');
- $fullhtml = new TextPart($content, 'utf-8', 'html');
- $inlinedimg = (new DataPart($image, 'test.gif'))->asInline();
$body = $e->getBody();
$this->assertInstanceOf(MixedPart::class, $body);
$this->assertCount(2, $related = $body->getParts());
@@ -378,7 +376,7 @@ public function testSerialize()
$e->from('fabien@symfony.com');
$e->text($r);
$e->html($r);
- $contents = file_get_contents($name = __DIR__.'/Fixtures/mimetypes/test', 'r');
+ $name = __DIR__.'/Fixtures/mimetypes/test';
$file = fopen($name, 'r');
$e->attach($file, 'test');
$expected = clone $e;
diff --git a/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php b/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php
index 3568c9a6e45d6..e2eb75a6977f3 100644
--- a/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php
+++ b/src/Symfony/Component/Mime/Tests/Header/HeadersTest.php
@@ -173,8 +173,6 @@ public function testAllReturnsEmptyArrayIfNoneSet()
public function testRemoveRemovesAllHeadersWithName()
{
- $header0 = new UnstructuredHeader('X-Test', 'some@id');
- $header1 = new UnstructuredHeader('X-Test', 'other@id');
$headers = new Headers();
$headers->addIdHeader('X-Test', 'some@id');
$headers->addIdHeader('X-Test', 'other@id');
@@ -185,7 +183,6 @@ public function testRemoveRemovesAllHeadersWithName()
public function testHasIsNotCaseSensitive()
{
- $header = new IdentificationHeader('Message-ID', 'some@id');
$headers = new Headers();
$headers->addIdHeader('Message-ID', 'some@id');
$this->assertTrue($headers->has('message-id'));
@@ -209,7 +206,6 @@ public function testAllIsNotCaseSensitive()
public function testRemoveIsNotCaseSensitive()
{
- $header = new IdentificationHeader('Message-ID', 'some@id');
$headers = new Headers();
$headers->addIdHeader('Message-ID', 'some@id');
$headers->remove('message-id');
diff --git a/src/Symfony/Component/Mime/Tests/Header/IdentificationHeaderTest.php b/src/Symfony/Component/Mime/Tests/Header/IdentificationHeaderTest.php
index b7f0095d3a164..7d274ab162d55 100644
--- a/src/Symfony/Component/Mime/Tests/Header/IdentificationHeaderTest.php
+++ b/src/Symfony/Component/Mime/Tests/Header/IdentificationHeaderTest.php
@@ -103,7 +103,7 @@ public function testInvalidIdLeftThrowsException()
{
$this->expectException('Exception');
$this->expectExceptionMessage('Email "a b c@d" does not comply with addr-spec of RFC 2822.');
- $header = new IdentificationHeader('References', 'a b c@d');
+ new IdentificationHeader('References', 'a b c@d');
}
public function testIdRightCanBeDotAtom()
@@ -139,7 +139,7 @@ public function testInvalidIdRightThrowsException()
{
$this->expectException('Exception');
$this->expectExceptionMessage('Email "a@b c d" does not comply with addr-spec of RFC 2822.');
- $header = new IdentificationHeader('References', 'a@b c d');
+ new IdentificationHeader('References', 'a@b c d');
}
public function testMissingAtSignThrowsException()
@@ -149,7 +149,7 @@ public function testMissingAtSignThrowsException()
/* -- RFC 2822, 3.6.4.
msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]
*/
- $header = new IdentificationHeader('References', 'abc');
+ new IdentificationHeader('References', 'abc');
}
public function testSetBody()
diff --git a/src/Symfony/Component/Mime/Tests/Header/PathHeaderTest.php b/src/Symfony/Component/Mime/Tests/Header/PathHeaderTest.php
index 6bc029aee4cea..a8386f89462a9 100644
--- a/src/Symfony/Component/Mime/Tests/Header/PathHeaderTest.php
+++ b/src/Symfony/Component/Mime/Tests/Header/PathHeaderTest.php
@@ -26,7 +26,7 @@ public function testSingleAddressCanBeSetAndFetched()
public function testAddressMustComplyWithRfc2822()
{
$this->expectException('Exception');
- $header = new PathHeader('Return-Path', new Address('chr is@swiftmailer.org'));
+ new PathHeader('Return-Path', new Address('chr is@swiftmailer.org'));
}
public function testValueIsAngleAddrWithValidAddress()
diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php
index f47aef128451a..e9de7800b6540 100644
--- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php
+++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php
@@ -917,7 +917,7 @@ public function offsetGet($option/*, bool $triggerDeprecation = true*/)
// Validate the type of the resolved option
if (isset($this->allowedTypes[$option])) {
- $valid = false;
+ $valid = true;
$invalidTypes = [];
foreach ($this->allowedTypes[$option] as $type) {
@@ -929,13 +929,18 @@ public function offsetGet($option/*, bool $triggerDeprecation = true*/)
}
if (!$valid) {
- $keys = array_keys($invalidTypes);
-
- if (1 === \count($keys) && '[]' === substr($keys[0], -2)) {
- throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but one of the elements is of type "%s".', $option, $this->formatValue($value), implode('" or "', $this->allowedTypes[$option]), $keys[0]));
+ $fmtActualValue = $this->formatValue($value);
+ $fmtAllowedTypes = implode('" or "', $this->allowedTypes[$option]);
+ $fmtProvidedTypes = implode('|', array_keys($invalidTypes));
+ $allowedContainsArrayType = \count(array_filter($this->allowedTypes[$option], static function ($item) {
+ return '[]' === substr(self::$typeAliases[$item] ?? $item, -2);
+ })) > 0;
+
+ if (\is_array($value) && $allowedContainsArrayType) {
+ throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but one of the elements is of type "%s".', $option, $fmtActualValue, $fmtAllowedTypes, $fmtProvidedTypes));
}
- throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but is of type "%s".', $option, $this->formatValue($value), implode('" or "', $this->allowedTypes[$option]), implode('|', array_keys($invalidTypes))));
+ throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but is of type "%s".', $option, $fmtActualValue, $fmtAllowedTypes, $fmtProvidedTypes));
}
}
@@ -1040,26 +1045,23 @@ private function verifyTypes(string $type, $value, array &$invalidTypes, int $le
{
if (\is_array($value) && '[]' === substr($type, -2)) {
$type = substr($type, 0, -2);
+ $valid = true;
foreach ($value as $val) {
if (!$this->verifyTypes($type, $val, $invalidTypes, $level + 1)) {
- return false;
+ $valid = false;
}
}
- return true;
+ return $valid;
}
if (('null' === $type && null === $value) || (\function_exists($func = 'is_'.$type) && $func($value)) || $value instanceof $type) {
return true;
}
- if (!$invalidTypes) {
- $suffix = '';
- while (\strlen($suffix) < $level * 2) {
- $suffix .= '[]';
- }
- $invalidTypes[$this->formatTypeOf($value).$suffix] = true;
+ if (!$invalidTypes || $level > 0) {
+ $invalidTypes[$this->formatTypeOf($value)] = true;
}
return false;
diff --git a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php
index 43ebf408e90b0..0211b22b26c00 100644
--- a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php
+++ b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php
@@ -776,7 +776,7 @@ public function testFailIfSetAllowedTypesFromLazyOption()
public function testResolveFailsIfInvalidTypedArray()
{
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
- $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[]", but one of the elements is of type "DateTime[]".');
+ $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[]", but one of the elements is of type "DateTime".');
$this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'int[]');
@@ -796,7 +796,7 @@ public function testResolveFailsWithNonArray()
public function testResolveFailsIfTypedArrayContainsInvalidTypes()
{
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
- $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[]", but one of the elements is of type "stdClass[]".');
+ $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[]", but one of the elements is of type "stdClass|array|DateTime".');
$this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'int[]');
$values = range(1, 5);
@@ -811,7 +811,7 @@ public function testResolveFailsIfTypedArrayContainsInvalidTypes()
public function testResolveFailsWithCorrectLevelsButWrongScalar()
{
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
- $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "double[][]".');
+ $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "double".');
$this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'int[][]');
@@ -847,6 +847,11 @@ public function provideInvalidTypes()
[42, 'string', 'The option "option" with value 42 is expected to be of type "string", but is of type "integer".'],
[null, 'string', 'The option "option" with value null is expected to be of type "string", but is of type "NULL".'],
['bar', '\stdClass', 'The option "option" with value "bar" is expected to be of type "\stdClass", but is of type "string".'],
+ [['foo', 12], 'string[]', 'The option "option" with value array is expected to be of type "string[]", but one of the elements is of type "integer".'],
+ [123, ['string[]', 'string'], 'The option "option" with value 123 is expected to be of type "string[]" or "string", but is of type "integer".'],
+ [[null], ['string[]', 'string'], 'The option "option" with value array is expected to be of type "string[]" or "string", but one of the elements is of type "NULL".'],
+ [['string', null], ['string[]', 'string'], 'The option "option" with value array is expected to be of type "string[]" or "string", but one of the elements is of type "NULL".'],
+ [[\stdClass::class], ['string'], 'The option "option" with value array is expected to be of type "string", but is of type "array".'],
];
}
@@ -1898,7 +1903,7 @@ public function testNested2Arrays()
public function testNestedArraysException()
{
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
- $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "float[][][][]", but one of the elements is of type "integer[][][][]".');
+ $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "float[][][][]", but one of the elements is of type "integer".');
$this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'float[][][][]');
@@ -1916,7 +1921,7 @@ public function testNestedArraysException()
public function testNestedArrayException1()
{
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
- $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "boolean[][]".');
+ $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "boolean|string|array".');
$this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'int[][]');
$this->resolver->resolve([
@@ -1929,7 +1934,7 @@ public function testNestedArrayException1()
public function testNestedArrayException2()
{
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
- $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "boolean[][]".');
+ $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "boolean|string|array".');
$this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'int[][]');
$this->resolver->resolve([
@@ -1942,7 +1947,7 @@ public function testNestedArrayException2()
public function testNestedArrayException3()
{
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
- $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[][][]", but one of the elements is of type "string[][]".');
+ $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[][][]", but one of the elements is of type "string|integer".');
$this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'string[][][]');
$this->resolver->resolve([
@@ -1955,7 +1960,7 @@ public function testNestedArrayException3()
public function testNestedArrayException4()
{
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
- $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[][][]", but one of the elements is of type "integer[][][]".');
+ $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[][][]", but one of the elements is of type "integer".');
$this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'string[][][]');
$this->resolver->resolve([
@@ -1969,7 +1974,7 @@ public function testNestedArrayException4()
public function testNestedArrayException5()
{
$this->expectException('Symfony\Component\OptionsResolver\Exception\InvalidOptionsException');
- $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[]", but one of the elements is of type "array[]".');
+ $this->expectExceptionMessage('The option "foo" with value array is expected to be of type "string[]", but one of the elements is of type "array".');
$this->resolver->setDefined('foo');
$this->resolver->setAllowedTypes('foo', 'string[]');
$this->resolver->resolve([
diff --git a/src/Symfony/Component/Process/Tests/ExecutableFinderTest.php b/src/Symfony/Component/Process/Tests/ExecutableFinderTest.php
index a400273964613..2a0278f8e0456 100644
--- a/src/Symfony/Component/Process/Tests/ExecutableFinderTest.php
+++ b/src/Symfony/Component/Process/Tests/ExecutableFinderTest.php
@@ -132,9 +132,6 @@ public function testFindProcessInOpenBasedir()
$this->assertSamePath(PHP_BINARY, $result);
}
- /**
- * @requires PHP 5.4
- */
public function testFindBatchExecutableOnWindows()
{
if (ini_get('open_basedir')) {
diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php
index c7a96d4bf9969..d2f1a5150893a 100644
--- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php
+++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php
@@ -119,8 +119,8 @@ public function getProperties($class, array $context = [])
if (!$propertyName || isset($properties[$propertyName])) {
continue;
}
- if (!$reflectionClass->hasProperty($propertyName) && !preg_match('/^[A-Z]{2,}/', $propertyName)) {
- $propertyName = lcfirst($propertyName);
+ if ($reflectionClass->hasProperty($lowerCasedPropertyName = lcfirst($propertyName)) || (!$reflectionClass->hasProperty($propertyName) && !preg_match('/^[A-Z]{2,}/', $propertyName))) {
+ $propertyName = $lowerCasedPropertyName;
}
$properties[$propertyName] = $propertyName;
}
diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php
index fe8d52a3c503a..8b2d087be8d8a 100644
--- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php
+++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php
@@ -67,6 +67,8 @@ public function testGetProperties()
'123',
'self',
'realParent',
+ 'xTotals',
+ 'YT',
'c',
'd',
'e',
diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php
index 9bd856bd47df5..460c08d3628e5 100644
--- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php
+++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php
@@ -93,6 +93,16 @@ class Dummy extends ParentDummy
*/
public $j;
+ /**
+ * @var array
+ */
+ private $xTotals;
+
+ /**
+ * @var string
+ */
+ private $YT;
+
/**
* This should not be removed.
*
@@ -181,4 +191,18 @@ public function setSelf(self $self)
public function setRealParent(parent $realParent)
{
}
+
+ /**
+ * @return array
+ */
+ public function getXTotals()
+ {
+ }
+
+ /**
+ * @return string
+ */
+ public function getYT()
+ {
+ }
}
diff --git a/src/Symfony/Component/Routing/Loader/Configurator/RoutingConfigurator.php b/src/Symfony/Component/Routing/Loader/Configurator/RoutingConfigurator.php
index a315cfb4ad07e..b8155b1f61b9e 100644
--- a/src/Symfony/Component/Routing/Loader/Configurator/RoutingConfigurator.php
+++ b/src/Symfony/Component/Routing/Loader/Configurator/RoutingConfigurator.php
@@ -39,7 +39,8 @@ public function __construct(RouteCollection $collection, PhpFileLoader $loader,
final public function import($resource, $type = null, $ignoreErrors = false)
{
$this->loader->setCurrentDir(\dirname($this->path));
- $imported = $this->loader->import($resource, $type, $ignoreErrors, $this->file);
+ $imported = $this->loader->import($resource, $type, $ignoreErrors, $this->file) ?: [];
+
if (!\is_array($imported)) {
return new ImportConfigurator($this->collection, $imported);
}
diff --git a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php
index ed4faf3915b72..bd61721fe2c17 100644
--- a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php
+++ b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php
@@ -169,7 +169,7 @@ protected function parseImport(RouteCollection $collection, \DOMElement $node, $
$this->setCurrentDir(\dirname($path));
/** @var RouteCollection[] $imported */
- $imported = $this->import($resource, ('' !== $type ? $type : null), false, $file);
+ $imported = $this->import($resource, ('' !== $type ? $type : null), false, $file) ?: [];
if (!\is_array($imported)) {
$imported = [$imported];
diff --git a/src/Symfony/Component/Routing/Loader/YamlFileLoader.php b/src/Symfony/Component/Routing/Loader/YamlFileLoader.php
index 15c223ecadcf4..d9d7d28af1ca0 100644
--- a/src/Symfony/Component/Routing/Loader/YamlFileLoader.php
+++ b/src/Symfony/Component/Routing/Loader/YamlFileLoader.php
@@ -187,7 +187,7 @@ protected function parseImport(RouteCollection $collection, array $config, $path
$this->setCurrentDir(\dirname($path));
- $imported = $this->import($config['resource'], $type, false, $file);
+ $imported = $this->import($config['resource'], $type, false, $file) ?: [];
if (!\is_array($imported)) {
$imported = [$imported];
diff --git a/src/Symfony/Component/Routing/Matcher/Dumper/CompiledUrlMatcherDumper.php b/src/Symfony/Component/Routing/Matcher/Dumper/CompiledUrlMatcherDumper.php
index ab67e6885ac92..b3a93886796b4 100644
--- a/src/Symfony/Component/Routing/Matcher/Dumper/CompiledUrlMatcherDumper.php
+++ b/src/Symfony/Component/Routing/Matcher/Dumper/CompiledUrlMatcherDumper.php
@@ -121,7 +121,7 @@ static function (\$condition, \$context, \$request) { // \$checkCondition
}
}
EOF;
- $compiledRoutes[4] = $forDump ? $checkConditionCode .= ",\n" : eval('return '.$checkConditionCode.';');
+ $compiledRoutes[4] = $forDump ? $checkConditionCode.",\n" : eval('return '.$checkConditionCode.';');
} else {
$compiledRoutes[4] = $forDump ? " null, // \$checkCondition\n" : null;
}
diff --git a/src/Symfony/Component/Routing/Tests/Annotation/RouteTest.php b/src/Symfony/Component/Routing/Tests/Annotation/RouteTest.php
index 58c59dcbbfa15..2c193a8a09588 100644
--- a/src/Symfony/Component/Routing/Tests/Annotation/RouteTest.php
+++ b/src/Symfony/Component/Routing/Tests/Annotation/RouteTest.php
@@ -19,13 +19,13 @@ class RouteTest extends TestCase
public function testInvalidRouteParameter()
{
$this->expectException('BadMethodCallException');
- $route = new Route(['foo' => 'bar']);
+ new Route(['foo' => 'bar']);
}
public function testTryingToSetLocalesDirectly()
{
$this->expectException('BadMethodCallException');
- $route = new Route(['locales' => ['nl' => 'bar']]);
+ new Route(['locales' => ['nl' => 'bar']]);
}
/**
diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/FooTrait.php b/src/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/FooTrait.php
index ee8f4b071a368..c06fb43f6887e 100644
--- a/src/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/FooTrait.php
+++ b/src/Symfony/Component/Routing/Tests/Fixtures/AnnotatedClasses/FooTrait.php
@@ -6,7 +6,7 @@ trait FooTrait
{
public function doBar()
{
- $baz = self::class;
+ self::class;
if (true) {
}
}
diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/controller/empty_wildcard/.gitignore b/src/Symfony/Component/Routing/Tests/Fixtures/controller/empty_wildcard/.gitignore
new file mode 100644
index 0000000000000..e69de29bb2d1d
diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/import_with_name_prefix/routing.yml b/src/Symfony/Component/Routing/Tests/Fixtures/import_with_name_prefix/routing.yml
index 90dce0ea1bfc4..057b7b2d6b9ce 100644
--- a/src/Symfony/Component/Routing/Tests/Fixtures/import_with_name_prefix/routing.yml
+++ b/src/Symfony/Component/Routing/Tests/Fixtures/import_with_name_prefix/routing.yml
@@ -5,3 +5,7 @@ api:
resource: ../controller/routing.yml
name_prefix: api_
prefix: /api
+
+empty_wildcard:
+ resource: ../controller/empty_wildcard/*
+ prefix: /empty_wildcard
diff --git a/src/Symfony/Component/Routing/Tests/Generator/Dumper/CompiledUrlGeneratorDumperTest.php b/src/Symfony/Component/Routing/Tests/Generator/Dumper/CompiledUrlGeneratorDumperTest.php
index 513e1c80e1e66..521f0f126cda7 100644
--- a/src/Symfony/Component/Routing/Tests/Generator/Dumper/CompiledUrlGeneratorDumperTest.php
+++ b/src/Symfony/Component/Routing/Tests/Generator/Dumper/CompiledUrlGeneratorDumperTest.php
@@ -194,7 +194,7 @@ public function testGenerateNonExistingRoute()
file_put_contents($this->testTmpFilepath, $this->generatorDumper->dump());
$projectUrlGenerator = new CompiledUrlGenerator(require $this->testTmpFilepath, new RequestContext());
- $url = $projectUrlGenerator->generate('NonExisting', []);
+ $projectUrlGenerator->generate('NonExisting', []);
}
public function testDumpForRouteWithDefaults()
diff --git a/src/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php b/src/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php
index 8ea60eb279f3c..5e81b8f5d5755 100644
--- a/src/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php
+++ b/src/Symfony/Component/Routing/Tests/Generator/Dumper/PhpGeneratorDumperTest.php
@@ -211,7 +211,7 @@ public function testGenerateNonExistingRoute()
include $this->testTmpFilepath;
$projectUrlGenerator = new \NonExistingRoutesUrlGenerator(new RequestContext());
- $url = $projectUrlGenerator->generate('NonExisting', []);
+ $projectUrlGenerator->generate('NonExisting', []);
}
public function testDumpForRouteWithDefaults()
diff --git a/src/Symfony/Component/Routing/Tests/RouteCompilerTest.php b/src/Symfony/Component/Routing/Tests/RouteCompilerTest.php
index a54e18b583834..5729d4caa5450 100644
--- a/src/Symfony/Component/Routing/Tests/RouteCompilerTest.php
+++ b/src/Symfony/Component/Routing/Tests/RouteCompilerTest.php
@@ -247,7 +247,7 @@ public function testRouteWithSameVariableTwice()
$this->expectException('LogicException');
$route = new Route('/{name}/{name}');
- $compiled = $route->compile();
+ $route->compile();
}
public function testRouteCharsetMismatch()
@@ -255,7 +255,7 @@ public function testRouteCharsetMismatch()
$this->expectException('LogicException');
$route = new Route("/\xE9/{bar}", [], ['bar' => '.'], ['utf8' => true]);
- $compiled = $route->compile();
+ $route->compile();
}
public function testRequirementCharsetMismatch()
@@ -263,7 +263,7 @@ public function testRequirementCharsetMismatch()
$this->expectException('LogicException');
$route = new Route('/foo/{bar}', [], ['bar' => "\xE9"], ['utf8' => true]);
- $compiled = $route->compile();
+ $route->compile();
}
public function testRouteWithFragmentAsPathParameter()
@@ -271,7 +271,7 @@ public function testRouteWithFragmentAsPathParameter()
$this->expectException('InvalidArgumentException');
$route = new Route('/{_fragment}');
- $compiled = $route->compile();
+ $route->compile();
}
/**
diff --git a/src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php
index 1e09992afed4e..364cd19236ec2 100644
--- a/src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php
+++ b/src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php
@@ -45,7 +45,7 @@ public function __construct(int $opsLimit = null, int $memLimit = null, int $cos
throw new \InvalidArgumentException('$cost must be in the range of 4-31.');
}
- $this->algo = \defined('PASSWORD_ARGON2I') ? max(PASSWORD_DEFAULT, \defined('PASSWORD_ARGON2ID') ? PASSWORD_ARGON2ID : PASSWORD_ARGON2I) : PASSWORD_DEFAULT;
+ $this->algo = \defined('PASSWORD_ARGON2ID') ? PASSWORD_ARGON2ID : (\defined('PASSWORD_ARGON2I') ? PASSWORD_ARGON2I : PASSWORD_BCRYPT);
$this->options = [
'cost' => $cost,
'time_cost' => $opsLimit,
@@ -59,20 +59,13 @@ public function __construct(int $opsLimit = null, int $memLimit = null, int $cos
*/
public function encodePassword($raw, $salt)
{
- if (\strlen($raw) > self::MAX_PASSWORD_LENGTH) {
+ if (\strlen($raw) > self::MAX_PASSWORD_LENGTH || (PASSWORD_BCRYPT === $this->algo && 72 < \strlen($raw))) {
throw new BadCredentialsException('Invalid password.');
}
// Ignore $salt, the auto-generated one is always the best
- $encoded = password_hash($raw, $this->algo, $this->options);
-
- if (72 < \strlen($raw) && 0 === strpos($encoded, '$2')) {
- // BCrypt encodes only the first 72 chars
- throw new BadCredentialsException('Invalid password.');
- }
-
- return $encoded;
+ return password_hash($raw, $this->algo, $this->options);
}
/**
@@ -80,11 +73,23 @@ public function encodePassword($raw, $salt)
*/
public function isPasswordValid($encoded, $raw, $salt)
{
- if (72 < \strlen($raw) && 0 === strpos($encoded, '$2')) {
- // BCrypt encodes only the first 72 chars
+ if (\strlen($raw) > self::MAX_PASSWORD_LENGTH) {
return false;
}
- return \strlen($raw) <= self::MAX_PASSWORD_LENGTH && password_verify($raw, $encoded);
+ if (0 === strpos($encoded, '$2')) {
+ // BCrypt encodes only the first 72 chars
+ return 72 >= \strlen($raw) && password_verify($raw, $encoded);
+ }
+
+ if (\extension_loaded('sodium') && version_compare(\SODIUM_LIBRARY_VERSION, '1.0.14', '>=')) {
+ return sodium_crypto_pwhash_str_verify($encoded, $raw);
+ }
+
+ if (\extension_loaded('libsodium') && version_compare(phpversion('libsodium'), '1.0.14', '>=')) {
+ return \Sodium\crypto_pwhash_str_verify($encoded, $raw);
+ }
+
+ return password_verify($raw, $encoded);
}
}
diff --git a/src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php
index 934a3fdfca528..9c794004111a6 100644
--- a/src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php
+++ b/src/Symfony/Component/Security/Core/Encoder/SodiumPasswordEncoder.php
@@ -93,6 +93,6 @@ public function isPasswordValid($encoded, $raw, $salt)
return \Sodium\crypto_pwhash_str_verify($encoded, $raw);
}
- throw new LogicException('Libsodium is not available. You should either install the sodium extension, upgrade to PHP 7.2+ or use a different encoder.');
+ return false;
}
}
diff --git a/src/Symfony/Component/Security/Core/Tests/Encoder/EncoderFactoryTest.php b/src/Symfony/Component/Security/Core/Tests/Encoder/EncoderFactoryTest.php
index 0b2c36c72de4a..48b7ebcbb269f 100644
--- a/src/Symfony/Component/Security/Core/Tests/Encoder/EncoderFactoryTest.php
+++ b/src/Symfony/Component/Security/Core/Tests/Encoder/EncoderFactoryTest.php
@@ -117,7 +117,7 @@ public function testGetInvalidNamedEncoderForEncoderAware()
$user = new EncAwareUser('user', 'pass');
$user->encoderName = 'invalid_encoder_name';
- $encoder = $factory->getEncoder($user);
+ $factory->getEncoder($user);
}
public function testGetEncoderForEncoderAwareWithClassName()
diff --git a/src/Symfony/Component/Security/Guard/Tests/Provider/GuardAuthenticationProviderTest.php b/src/Symfony/Component/Security/Guard/Tests/Provider/GuardAuthenticationProviderTest.php
index 17b4ab98f92df..2ad03a5ce385a 100644
--- a/src/Symfony/Component/Security/Guard/Tests/Provider/GuardAuthenticationProviderTest.php
+++ b/src/Symfony/Component/Security/Guard/Tests/Provider/GuardAuthenticationProviderTest.php
@@ -162,7 +162,7 @@ public function testGuardWithNoLongerAuthenticatedTriggersLogout()
$token->setAuthenticated(false);
$provider = new GuardAuthenticationProvider([], $this->userProvider, $providerKey, $this->userChecker);
- $actualToken = $provider->authenticate($token);
+ $provider->authenticate($token);
}
public function testSupportsChecksGuardAuthenticatorsTokenOrigin()
diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php
index 7cb438e3a7834..5eed09392802e 100644
--- a/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php
+++ b/src/Symfony/Component/Security/Http/Tests/Firewall/LogoutListenerTest.php
@@ -21,7 +21,7 @@ class LogoutListenerTest extends TestCase
{
public function testHandleUnmatchedPath()
{
- list($listener, $tokenStorage, $httpUtils, $options) = $this->getListener();
+ list($listener, , $httpUtils, $options) = $this->getListener();
list($event, $request) = $this->getGetResponseEvent();
@@ -131,7 +131,7 @@ public function testSuccessHandlerReturnsNonResponse()
$this->expectException('RuntimeException');
$successHandler = $this->getSuccessHandler();
- list($listener, $tokenStorage, $httpUtils, $options) = $this->getListener($successHandler);
+ list($listener, , $httpUtils, $options) = $this->getListener($successHandler);
list($event, $request) = $this->getGetResponseEvent();
@@ -153,7 +153,7 @@ public function testCsrfValidationFails()
$this->expectException('Symfony\Component\Security\Core\Exception\LogoutException');
$tokenManager = $this->getTokenManager();
- list($listener, $tokenStorage, $httpUtils, $options) = $this->getListener(null, $tokenManager);
+ list($listener, , $httpUtils, $options) = $this->getListener(null, $tokenManager);
list($event, $request) = $this->getGetResponseEvent();
diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/RememberMeListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/RememberMeListenerTest.php
index c50b8c218c2d0..ceb557b139d0a 100644
--- a/src/Symfony/Component/Security/Http/Tests/Firewall/RememberMeListenerTest.php
+++ b/src/Symfony/Component/Security/Http/Tests/Firewall/RememberMeListenerTest.php
@@ -224,7 +224,7 @@ public function testOnCoreSecurity()
public function testSessionStrategy()
{
- list($listener, $tokenStorage, $service, $manager, , $dispatcher, $sessionStrategy) = $this->getListener(false, true, true);
+ list($listener, $tokenStorage, $service, $manager, , , $sessionStrategy) = $this->getListener(false, true, true);
$tokenStorage
->expects($this->once())
@@ -289,7 +289,7 @@ public function testSessionStrategy()
public function testSessionIsMigratedByDefault()
{
- list($listener, $tokenStorage, $service, $manager, , $dispatcher, $sessionStrategy) = $this->getListener(false, true, false);
+ list($listener, $tokenStorage, $service, $manager) = $this->getListener(false, true, false);
$tokenStorage
->expects($this->once())
diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/RemoteUserAuthenticationListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/RemoteUserAuthenticationListenerTest.php
index 02d1ba03ce441..fd29297a5778e 100644
--- a/src/Symfony/Component/Security/Http/Tests/Firewall/RemoteUserAuthenticationListenerTest.php
+++ b/src/Symfony/Component/Security/Http/Tests/Firewall/RemoteUserAuthenticationListenerTest.php
@@ -60,7 +60,7 @@ public function testGetPreAuthenticatedDataNoUser()
$method = new \ReflectionMethod($listener, 'getPreAuthenticatedData');
$method->setAccessible(true);
- $result = $method->invokeArgs($listener, [$request]);
+ $method->invokeArgs($listener, [$request]);
}
public function testGetPreAuthenticatedDataWithDifferentKeys()
diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/X509AuthenticationListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/X509AuthenticationListenerTest.php
index e35e685d5bf88..c81b2d589ed06 100644
--- a/src/Symfony/Component/Security/Http/Tests/Firewall/X509AuthenticationListenerTest.php
+++ b/src/Symfony/Component/Security/Http/Tests/Firewall/X509AuthenticationListenerTest.php
@@ -98,7 +98,7 @@ public function testGetPreAuthenticatedDataNoData()
$method = new \ReflectionMethod($listener, 'getPreAuthenticatedData');
$method->setAccessible(true);
- $result = $method->invokeArgs($listener, [$request]);
+ $method->invokeArgs($listener, [$request]);
}
public function testGetPreAuthenticatedDataWithDifferentKeys()
diff --git a/src/Symfony/Component/Security/Http/Tests/FirewallTest.php b/src/Symfony/Component/Security/Http/Tests/FirewallTest.php
index bb81bc36a7086..e3e04d8f1573d 100644
--- a/src/Symfony/Component/Security/Http/Tests/FirewallTest.php
+++ b/src/Symfony/Component/Security/Http/Tests/FirewallTest.php
@@ -14,7 +14,6 @@
use PHPUnit\Framework\TestCase;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\HttpKernelInterface;
use Symfony\Component\Security\Http\Firewall;
@@ -52,8 +51,6 @@ public function testOnKernelRequestRegistersExceptionListener()
public function testOnKernelRequestStopsWhenThereIsAResponse()
{
- $response = new Response();
-
$called = [];
$first = function () use (&$called) {
diff --git a/src/Symfony/Component/Security/Http/Tests/RememberMe/ResponseListenerTest.php b/src/Symfony/Component/Security/Http/Tests/RememberMe/ResponseListenerTest.php
index 912868a25621f..9c4fa730b1143 100644
--- a/src/Symfony/Component/Security/Http/Tests/RememberMe/ResponseListenerTest.php
+++ b/src/Symfony/Component/Security/Http/Tests/RememberMe/ResponseListenerTest.php
@@ -66,8 +66,6 @@ public function testRememberMeCookieIsNotSendWithResponse()
public function testItSubscribesToTheOnKernelResponseEvent()
{
- $listener = new ResponseListener();
-
$this->assertSame([KernelEvents::RESPONSE => 'onKernelResponse'], ResponseListener::getSubscribedEvents());
}
diff --git a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php
index 30bcacec95c42..9a92d5d866ad1 100644
--- a/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php
+++ b/src/Symfony/Component/Serializer/Encoder/XmlEncoder.php
@@ -465,7 +465,7 @@ private function buildXml(\DOMNode $parentNode, $data, string $xmlRootNodeName =
return $this->appendNode($parentNode, $data, 'data');
}
- throw new NotEncodableValueException(sprintf('An unexpected value could not be serialized: %s', var_export($data, true)));
+ throw new NotEncodableValueException(sprintf('An unexpected value could not be serialized: %s', !\is_resource($data) ? var_export($data, true) : sprintf('%s resource', get_resource_type($data))));
}
/**
diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php
index 5f165b56ac774..056744fa4b0f8 100644
--- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php
+++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php
@@ -552,7 +552,6 @@ protected function createChildContext(array $parentContext, $attribute/*, ?strin
{
if (\func_num_args() < 3) {
@trigger_error(sprintf('Method "%s::%s()" will have a third "?string $format" argument in version 5.0; not defining it is deprecated since Symfony 4.3.', \get_class($this), __FUNCTION__), E_USER_DEPRECATED);
- $format = null;
}
if (isset($parentContext[self::ATTRIBUTES][$attribute])) {
$parentContext[self::ATTRIBUTES] = $parentContext[self::ATTRIBUTES][$attribute];
diff --git a/src/Symfony/Component/Serializer/Serializer.php b/src/Symfony/Component/Serializer/Serializer.php
index 8b5230724a6ec..3b439abdcc3c3 100644
--- a/src/Symfony/Component/Serializer/Serializer.php
+++ b/src/Symfony/Component/Serializer/Serializer.php
@@ -173,7 +173,7 @@ public function normalize($data, $format = null, array $context = [])
throw new NotNormalizableValueException(sprintf('Could not normalize object of type %s, no supporting normalizer found.', \get_class($data)));
}
- throw new NotNormalizableValueException(sprintf('An unexpected value could not be normalized: %s', var_export($data, true)));
+ throw new NotNormalizableValueException(sprintf('An unexpected value could not be normalized: %s', !\is_resource($data) ? var_export($data, true) : sprintf('%s resource', get_resource_type($data))));
}
/**
diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php
index 60e73aa36fdb9..3df016f067640 100644
--- a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php
+++ b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php
@@ -14,6 +14,7 @@
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
+use Symfony\Component\Serializer\Exception\NotEncodableValueException;
use Symfony\Component\Serializer\Normalizer\CustomNormalizer;
use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
use Symfony\Component\Serializer\Serializer;
@@ -796,6 +797,14 @@ public function testEncodeXmlWithDateTimeObjectField()
$this->assertEquals($this->createXmlWithDateTimeField(), $actualXml);
}
+ public function testNotEncodableValueExceptionMessageForAResource()
+ {
+ $this->expectException(NotEncodableValueException::class);
+ $this->expectExceptionMessage('An unexpected value could not be serialized: stream resource');
+
+ (new XmlEncoder())->encode(tmpfile(), 'xml');
+ }
+
public function testEncodeComment()
{
$expected = <<<'XML'
diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php
index ed0b35b3d5b5f..7cfab8c94985b 100644
--- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php
+++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php
@@ -17,6 +17,7 @@
use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Exception\InvalidArgumentException;
+use Symfony\Component\Serializer\Exception\NotNormalizableValueException;
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping;
use Symfony\Component\Serializer\Mapping\ClassMetadata;
@@ -468,6 +469,14 @@ public function testExceptionWhenTypeIsNotInTheBodyToDeserialiaze()
$this->serializerWithClassDiscriminator()->deserialize('{"one":1}', DummyMessageInterface::class, 'json');
}
+ public function testNotNormalizableValueExceptionMessageForAResource()
+ {
+ $this->expectException(NotNormalizableValueException::class);
+ $this->expectExceptionMessage('An unexpected value could not be normalized: stream resource');
+
+ (new Serializer())->normalize(tmpfile());
+ }
+
private function serializerWithClassDiscriminator()
{
$classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
diff --git a/src/Symfony/Component/Templating/Tests/Loader/FilesystemLoaderTest.php b/src/Symfony/Component/Templating/Tests/Loader/FilesystemLoaderTest.php
index 36a63bce3b679..242dc42a63bd7 100644
--- a/src/Symfony/Component/Templating/Tests/Loader/FilesystemLoaderTest.php
+++ b/src/Symfony/Component/Templating/Tests/Loader/FilesystemLoaderTest.php
@@ -27,7 +27,6 @@ public static function setUpBeforeClass(): void
public function testConstructor()
{
$pathPattern = self::$fixturesPath.'/templates/%name%.%engine%';
- $path = self::$fixturesPath.'/templates';
$loader = new ProjectTemplateLoader2($pathPattern);
$this->assertEquals([$pathPattern], $loader->getTemplatePathPatterns(), '__construct() takes a path as its second argument');
$loader = new ProjectTemplateLoader2([$pathPattern]);
diff --git a/src/Symfony/Component/Translation/Resources/bin/translation-status.php b/src/Symfony/Component/Translation/Resources/bin/translation-status.php
index 669b8f2864730..44918c92ec527 100644
--- a/src/Symfony/Component/Translation/Resources/bin/translation-status.php
+++ b/src/Symfony/Component/Translation/Resources/bin/translation-status.php
@@ -89,7 +89,8 @@ function findTranslationFiles($originalFilePath, $localeToAnalyze)
$originalFileName = basename($originalFilePath);
$translationFileNamePattern = str_replace('.en.', '.*.', $originalFileName);
- $translationFiles = glob($translationsDir.'/'.$translationFileNamePattern);
+ $translationFiles = glob($translationsDir.'/'.$translationFileNamePattern, GLOB_NOSORT);
+ sort($translationFiles);
foreach ($translationFiles as $filePath) {
$locale = extractLocaleFromFilePath($filePath);
diff --git a/src/Symfony/Component/Validator/Constraints/FileValidator.php b/src/Symfony/Component/Validator/Constraints/FileValidator.php
index 72666692138f7..145607964d7ff 100644
--- a/src/Symfony/Component/Validator/Constraints/FileValidator.php
+++ b/src/Symfony/Component/Validator/Constraints/FileValidator.php
@@ -61,7 +61,7 @@ public function validate($value, Constraint $constraint)
$binaryFormat = null === $constraint->binaryFormat ? true : $constraint->binaryFormat;
}
- list($sizeAsString, $limitAsString, $suffix) = $this->factorizeSizes(0, $limitInBytes, $binaryFormat);
+ list(, $limitAsString, $suffix) = $this->factorizeSizes(0, $limitInBytes, $binaryFormat);
$this->context->buildViolation($constraint->uploadIniSizeErrorMessage)
->setParameter('{{ limit }}', $limitAsString)
->setParameter('{{ suffix }}', $suffix)
diff --git a/src/Symfony/Component/Validator/DependencyInjection/AddAutoMappingConfigurationPass.php b/src/Symfony/Component/Validator/DependencyInjection/AddAutoMappingConfigurationPass.php
index 177f42e655d84..f28b78650ca0e 100644
--- a/src/Symfony/Component/Validator/DependencyInjection/AddAutoMappingConfigurationPass.php
+++ b/src/Symfony/Component/Validator/DependencyInjection/AddAutoMappingConfigurationPass.php
@@ -59,6 +59,10 @@ public function process(ContainerBuilder $container)
$validatorBuilder = $container->getDefinition($this->validatorBuilderService);
foreach ($container->findTaggedServiceIds($this->tag) as $id => $tags) {
$regexp = $this->getRegexp(array_merge($globalNamespaces, $servicesToNamespaces[$id] ?? []));
+ if (null === $regexp) {
+ $container->removeDefinition($id);
+ continue;
+ }
$container->getDefinition($id)->setArgument('$classValidatorRegexp', $regexp);
$validatorBuilder->addMethodCall('addLoader', [new Reference($id)]);
diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf
index db534528d1d99..bfa9b1284e8d9 100644
--- a/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf
+++ b/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf
@@ -334,6 +334,38 @@
This value should be valid JSON.
Verdien er ikke gyldig JSON.
+
+ This collection should contain only unique elements.
+ Samlingen kan kun inneholde unike elementer.
+
+
+ This value should be positive.
+ Denne verdien må være positiv.
+
+
+ This value should be either positive or zero.
+ Denne verdien må være positiv eller null.
+
+
+ This value should be negative.
+ Denne verdien må være negativ.
+
+
+ This value should be either negative or zero.
+ Denne verdien må være negativ eller null.
+
+
+ This value is not a valid timezone.
+ Verdien er ikke en gyldig tidssone.
+
+
+ This password has been leaked in a data breach, it must not be used. Please use another password.
+ Dette passordet er lekket i et datainnbrudd, det må ikke tas i bruk. Vennligst bruk et annet passord.
+
+
+ This value should be between {{ min }} and {{ max }}.
+ Verdien må være mellom {{ min }} og {{ max }}.
+
diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf
index db534528d1d99..bfa9b1284e8d9 100644
--- a/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf
+++ b/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf
@@ -334,6 +334,38 @@
This value should be valid JSON.
Verdien er ikke gyldig JSON.
+
+ This collection should contain only unique elements.
+ Samlingen kan kun inneholde unike elementer.
+
+
+ This value should be positive.
+ Denne verdien må være positiv.
+
+
+ This value should be either positive or zero.
+ Denne verdien må være positiv eller null.
+
+
+ This value should be negative.
+ Denne verdien må være negativ.
+
+
+ This value should be either negative or zero.
+ Denne verdien må være negativ eller null.
+
+
+ This value is not a valid timezone.
+ Verdien er ikke en gyldig tidssone.
+
+
+ This password has been leaked in a data breach, it must not be used. Please use another password.
+ Dette passordet er lekket i et datainnbrudd, det må ikke tas i bruk. Vennligst bruk et annet passord.
+
+
+ This value should be between {{ min }} and {{ max }}.
+ Verdien må være mellom {{ min }} og {{ max }}.
+