diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml
index 9c126e2ef2422..c5c9bfecf4d09 100644
--- a/.github/workflows/psalm.yml
+++ b/.github/workflows/psalm.yml
@@ -52,5 +52,4 @@ jobs:
- name: Psalm
run: |
- ./vendor/bin/psalm.phar --no-progress
- ./vendor/bin/psalm.phar --output-format=github --no-progress
+ ./vendor/bin/psalm.phar --no-progress || ./vendor/bin/psalm.phar --output-format=github --no-progress
diff --git a/.github/workflows/unit-tests.yml b/.github/workflows/unit-tests.yml
index 430d67c4c8cda..1eefe6f5583c6 100644
--- a/.github/workflows/unit-tests.yml
+++ b/.github/workflows/unit-tests.yml
@@ -15,18 +15,18 @@ jobs:
runs-on: Ubuntu-20.04
env:
- extensions: amqp,apcu,igbinary,intl,mbstring,memcached,mongodb,redis
+ extensions: amqp,apcu,igbinary,intl,mbstring,memcached,mongodb,redis-5.3.4
strategy:
matrix:
include:
- php: '7.2'
- - php: '8.0'
+ - php: '8.1'
- php: '7.4'
mode: high-deps
- php: '8.0'
mode: low-deps
- - php: '8.1'
+ - php: '8.2'
mode: experimental
fail-fast: false
@@ -36,11 +36,10 @@ jobs:
with:
fetch-depth: 2
- - name: Configure for PHP 8.1
- if: "${{ matrix.php == '8.1' }}"
+ - name: Configure for PHP >= 8.2
+ if: "${{ matrix.php >= '8.2' }}"
run: |
- echo "extensions=mbstring" >> $GITHUB_ENV
- composer config platform.php 8.0.99
+ composer config platform.php 8.1.99
- name: Setup PHP
uses: shivammathur/setup-php@v2
@@ -136,7 +135,7 @@ jobs:
echo "::endgroup::"
- name: Patch return types
- if: "${{ matrix.php == '8.0' && ! matrix.mode }}"
+ if: "${{ matrix.php == '8.1' && ! matrix.mode }}"
run: |
sed -i 's/"\*\*\/Tests\/"//' composer.json
composer install -q --optimize-autoloader
diff --git a/CHANGELOG-5.3.md b/CHANGELOG-5.3.md
index c949725e03b9b..bd3f2385357e7 100644
--- a/CHANGELOG-5.3.md
+++ b/CHANGELOG-5.3.md
@@ -7,6 +7,38 @@ in 5.3 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v5.3.0...v5.3.1
+* 5.3.8 (2021-09-28)
+
+ * bug #43206 [Workflow] Add missing audit-trail settings in framework workflow con… (Stephan Wentz)
+ * bug #42354 [Ldap][Security] Make LdapAuthenticator an EntryPoint (dcp-dev, chalasr)
+ * bug #43146 [SecurityBundle] Fixed LogicException message of FirewallAwareTrait (fkropfhamer)
+ * bug #43158 [Cache] Fix invalidating tags on Redis <5 (wouterj)
+ * bug #43179 [Ldap] Fix `resource` type checks & docblocks on PHP 8.1 (chalasr)
+ * bug #43174 [Messenger] relax parameter type (xabbuh)
+ * bug #43137 [FrameworkBundle] Avoid secrets:decrypt-to-local command to fail (noniagriconomie)
+ * bug #43171 [VarDumper] fix dumping typed references from properties (nicolas-grekas)
+ * bug #43124 [Messenger] [Redis] Allow authentication with user and password (GaryPEGEOT)
+ * bug #39350 [FrameworkBundle] Remove translation data_collector BEFORE adding it to profiler (l-vo)
+ * bug #43115 [DependencyInjection] Fix iterator in ServiceConfigurator (jderusse)
+ * bug #43073 [Notifier] Update FirebaseTransport.php (dima-gr)
+ * bug #43031 [Form] Do not trim unassigned unicode characters (simonberger)
+ * bug #43058 [WebProfilerBundle] Fix displaying certain configs (HypeMC)
+ * bug #43022 [PhpUnitBridge] Track unsilenced deprecations only for userland (nicolas-grekas)
+ * bug #42979 [FrameworkBundle] fix session-related BC layer triggering deprecation (nicolas-grekas)
+ * bug #42672 [PropertyAccess] Fix Regression in PropertyAccessor::isWritable() (haase-fabian)
+ * bug #42976 [Mime] Allow array as input for RawMessage (derrabus)
+ * bug #42932 [Messenger] Support rediss in transport bridge (RuslanZavacky)
+ * bug #42771 [FrameworkBundle] Match 5.3 and 5.1 mailer configuration (wizardz)
+ * bug #42098 [PropertyInfo] Support for intersection types (derrabus)
+ * bug #42904 [Cache] Make sure PdoAdapter::prune() always returns a bool (derrabus)
+ * bug #42896 [HttpClient] Fix handling timeouts when responses are destructed (nicolas-grekas)
+ * bug #42862 [Framework] Clean "about" command help after Environment section was removed (GromNaN)
+ * bug #42835 [Cache] Fix implicit float to int cast (derrabus)
+ * bug #42831 [Mime] Update mime types (fabpot)
+ * bug #42830 [HttpKernel] Fix empty timeline in profiler (nicodmf)
+ * bug #42815 [DependencyInjection] Fix circular reference in autowired decorators (shyim)
+ * bug #42819 Fix tests failing with DBAL 3 (derrabus)
+
* 5.3.7 (2021-08-30)
* bug #42769 [HttpClient] Don't pass float to `usleep()` (derrabus)
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 5c9b27862671f..f804602f54457 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -12,10 +12,10 @@ The Symfony Connect username in parenthesis allows to get more information
- Tobias Schultze (tobion)
- Robin Chalas (chalas_r)
- Christophe Coevoet (stof)
+ - Wouter De Jong (wouterj)
- Jérémy DERUSSÉ (jderusse)
- Maxime Steinhausser (ogizanagi)
- Kévin Dunglas (dunglas)
- - Wouter De Jong (wouterj)
- Grégoire Pineau (lyrixx)
- Jordi Boggiano (seldaek)
- Victor Berchet (victor)
@@ -48,11 +48,11 @@ The Symfony Connect username in parenthesis allows to get more information
- Eriksen Costa (eriksencosta)
- Ener-Getick (energetick)
- Sarah Khalil (saro0h)
- - Pierre du Plessis (pierredup)
- Kevin Bond (kbond)
+ - Pierre du Plessis (pierredup)
+ - Valentin Udaltsov (vudaltsov)
- Iltar van der Berg (kjarli)
- Jonathan Wage (jwage)
- - Valentin Udaltsov (vudaltsov)
- Matthias Pigulla (mpdude)
- Vasilij Duško (staff)
- Diego Saint Esteben (dosten)
@@ -91,6 +91,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Issei Murasawa (issei_m)
- Eric Clemmons (ericclemmons)
- Charles Sarrazin (csarrazi)
+ - Antoine M (amakdessi)
- Vasilij Dusko
- Douglas Greenshields (shieldo)
- Graham Campbell (graham)
@@ -99,7 +100,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Deni
- Henrik Westphal (snc)
- Dariusz Górecki (canni)
- - Antoine M (amakdessi)
- Fran Moreno (franmomu)
- Dariusz Ruminski
- Jérôme Vasseur (jvasseur)
@@ -112,26 +112,27 @@ The Symfony Connect username in parenthesis allows to get more information
- Bart van den Burg (burgov)
- Jordan Alliot (jalliot)
- John Wards (johnwards)
+ - Alexander Schranz (alexander-schranz)
- Baptiste Clavié (talus)
- Antoine Hérault (herzult)
- Paráda József (paradajozsef)
- - Alexander Schranz (alexander-schranz)
- Arnaud Le Blanc (arnaud-lb)
- Przemysław Bogusz (przemyslaw-bogusz)
+ - Vincent Langlet (deviling)
- Maxime STEINHAUSSER
+ - Tomas Norkūnas (norkunas)
- Michal Piotrowski (eventhorizon)
- Tomáš Votruba (tomas_votruba)
- Massimiliano Arione (garak)
- Mathias Arlaud (mtarld)
- Tim Nagel (merk)
- - Vincent Langlet (deviling)
- Chris Wilkinson (thewilkybarkid)
- - Tomas Norkūnas (norkunas)
- Peter Kokot (maastermedia)
- Lars Strojny (lstrojny)
- Brice BERNARD (brikou)
- Ahmed TAILOULOUTE (ahmedtai)
- Gregor Harlan (gharlan)
+ - HypeMC (hypemc)
- marc.weistroff
- lenar
- Alexander Schwenn (xelaris)
@@ -144,29 +145,29 @@ The Symfony Connect username in parenthesis allows to get more information
- Jacob Dreesen (jdreesen)
- Malte Schlüter (maltemaltesich)
- Joel Wurtz (brouznouf)
+ - Théo FIDRY (theofidry)
- Florian Voutzinos (florianv)
- Teoh Han Hui (teohhanhui)
- Colin Frei
- Javier Spagnoletti (phansys)
- Joshua Thijssen
- - HypeMC (hypemc)
- Daniel Wehner (dawehner)
- Tugdual Saunier (tucksaun)
- excelwebzone
- Gordon Franke (gimler)
- Saif Eddin Gmati (azjezz)
+ - Alexandre Daubois (alexandre-daubois)
- Jesse Rushlow (geeshoe)
- Fabien Pennequin (fabienpennequin)
- - Théo FIDRY (theofidry)
- Olivier Dolbeau (odolbeau)
- - Alexandre Daubois (alexandre-daubois)
+ - Smaine Milianni (ismail1432)
+ - Richard van Laak (rvanlaak)
- Eric GELOEN (gelo)
- Matthieu Napoli (mnapoli)
- Jannik Zschiesche (apfelbox)
- Mathieu Santostefano (welcomattic)
- Robert Schönthal (digitalkaoz)
- Florian Lonqueu-Brochard (florianlb)
- - Richard van Laak (rvanlaak)
- Tigran Azatyan (tigranazatyan)
- YaFou
- Gary PEGEOT (gary-p)
@@ -183,10 +184,10 @@ The Symfony Connect username in parenthesis allows to get more information
- Hidenori Goto (hidenorigoto)
- Jan Rosier (rosier)
- Alessandro Chitolina (alekitto)
+ - Ruud Kamphuis (ruudk)
- Albert Casademont (acasademont)
- Arnaud Kleinpeter (nanocom)
- Guilherme Blanco (guilhermeblanco)
- - Smaine Milianni (ismail1432)
- SpacePossum
- Pablo Godel (pgodel)
- Andreas Braun
@@ -194,7 +195,6 @@ The Symfony Connect username in parenthesis allows to get more information
- François-Xavier de Guillebon (de-gui_f)
- Oleg Voronkovich
- hacfi (hifi)
- - Ruud Kamphuis (ruudk)
- Rafael Dohms (rdohms)
- George Mponos (gmponos)
- jwdeitch
@@ -215,6 +215,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Timo Bakx (timobakx)
- Marco Pivetta (ocramius)
- Vincent Touzet (vincenttouzet)
+ - Nate Wiebe (natewiebe13)
- Rouven Weßling (realityking)
- Jérôme Parmentier (lctrs)
- Ben Davies (bendavies)
@@ -248,6 +249,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Dmitrii Chekaliuk (lazyhammer)
- Clément JOBEILI (dator)
- Mathieu Lechat (mat_the_cat)
+ - Jeroen Noten (jeroennoten)
- Marek Štípek (maryo)
- Daniel Espendiller
- Possum
@@ -263,7 +265,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Hidde Wieringa (hiddewie)
- Antonio Pauletich (x-coder264)
- Andre Rømcke (andrerom)
- - Nate Wiebe (natewiebe13)
- Philippe Segatori
- Thibaut Cheymol (tcheymol)
- Sebastien Morel (plopix)
@@ -287,10 +288,10 @@ The Symfony Connect username in parenthesis allows to get more information
- François Pluchino (francoispluchino)
- Rokas Mikalkėnas (rokasm)
- bronze1man
- - Jeroen Noten (jeroennoten)
- sun (sun)
- Larry Garfield (crell)
- Edi Modrić (emodric)
+ - Gocha Ossinkine (ossinkine)
- Roman Martinuk (a2a4)
- Leo Feyer (leofeyer)
- Nikolay Labinskiy (e-moe)
@@ -314,8 +315,10 @@ The Symfony Connect username in parenthesis allows to get more information
- Dustin Whittle (dustinwhittle)
- jeff
- John Kary (johnkary)
+ - zairig imad (zairigimad)
- Justin Hileman (bobthecow)
- Blanchon Vincent (blanchonvincent)
+ - Maciej Malarz (malarzm)
- Michele Orselli (orso)
- Sven Paulus (subsven)
- Daniel STANCU
@@ -330,7 +333,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Bohan Yang (brentybh)
- Pascal Montoya
- Julien Brochet (mewt)
- - Gocha Ossinkine (ossinkine)
- Tristan Darricau (nicofuma)
- Victor Bocharsky (bocharsky_bw)
- Bozhidar Hristov (warxcell)
@@ -360,12 +362,10 @@ The Symfony Connect username in parenthesis allows to get more information
- Manuel Reinhard (sprain)
- Harm van Tilborg (hvt)
- Danny Berger (dpb587)
- - zairig imad (zairigimad)
- Antonio J. García Lagar (ajgarlag)
- Adam Prager (padam87)
- Judicaël RUFFIEUX (axanagor)
- Benoît Burnichon (bburnichon)
- - Maciej Malarz (malarzm)
- Roman Marintšenko (inori)
- Xavier Montaña Carreras (xmontana)
- Mickaël Andrieu (mickaelandrieu)
@@ -400,6 +400,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Bob den Otter (bopp)
- Thomas Schulz (king2500)
- Frank de Jonge (frenkynet)
+ - Artem Henvald (artemgenvald)
- Lescot Edouard (idetox)
- Nikita Konstantinov
- Wodor Wodorski
@@ -422,10 +423,12 @@ The Symfony Connect username in parenthesis allows to get more information
- Roumen Damianoff (roumen)
- Kim Hemsø Rasmussen (kimhemsoe)
- Oleg Andreyev
+ - Martin Herndl (herndlm)
- Pavel Kirpitsov (pavel-kirpichyov)
- Pascal Luna (skalpa)
- Wouter Van Hecke
- Iker Ibarguren (ikerib)
+ - Bob van de Vijver (bobvandevijver)
- Peter Kruithof (pkruithof)
- Michael Holm (hollo)
- Sylvain Fabre (sylfabre)
@@ -437,6 +440,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Gonzalo Vilaseca (gonzalovilaseca)
- Ben Hakim
- Haralan Dobrev (hkdobrev)
+ - Marco Petersen (ocrampete16)
- MatTheCat
- Vilius Grigaliūnas
- David Badura (davidbadura)
@@ -493,7 +497,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Oleksandr Barabolia (oleksandrbarabolia)
- Christopher Davis (chrisguitarguy)
- ivan
- - Artem Henvald (artemgenvald)
- Greg Anderson
- Tri Pham (phamuyentri)
- BoShurik
@@ -519,15 +522,14 @@ The Symfony Connect username in parenthesis allows to get more information
- Inal DJAFAR (inalgnu)
- Christian Gärtner (dagardner)
- Dmytro Borysovskyi (dmytr0)
- - Bob van de Vijver (bobvandevijver)
- Tomasz Kowalczyk (thunderer)
- Artur Eshenbrener
+ - Soner Sayakci
- Thomas Perez (scullwm)
- Felix Labrecque
- Yaroslav Kiliba
- Terje Bråten
- Renan Gonçalves (renan_saddam)
- - Marco Petersen (ocrampete16)
- Tarmo Leppänen (tarlepp)
- Martin Auswöger
- Robbert Klarenbeek (robbertkl)
@@ -536,6 +538,7 @@ The Symfony Connect username in parenthesis allows to get more information
- JhonnyL
- hossein zolfi (ocean)
- Clément Gautier (clementgautier)
+ - Koen Reiniers (koenre)
- Dāvis Zālītis (k0d3r1s)
- Sanpi
- Eduardo Gulias (egulias)
@@ -617,6 +620,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Valentin Jonovs (valentins-jonovs)
- Bastien DURAND (deamon)
- Jeanmonod David (jeanmonod)
+ - Christin Gruber (christingruber)
- Andrey Sevastianov
- Webnet team (webnet)
- Urinbayev Shakhobiddin (shokhaa)
@@ -666,6 +670,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Andrew M-Y (andr)
- Krasimir Bosilkov (kbosilkov)
- Marcin Michalski (marcinmichalski)
+ - Yoann RENARD (yrenard)
- Vitaliy Tverdokhlib (vitaliytv)
- Ariel Ferrandini (aferrandini)
- Niklas Keller
@@ -676,7 +681,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Tim Goudriaan (codedmonkey)
- Jonas Flodén (flojon)
- AnneKir
- - Soner Sayakci
- Tobias Weichart
- Miro Michalicka
- Marcin Sikoń (marphi)
@@ -692,7 +696,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Christian Wahler
- Giso Stallenberg (gisostallenberg)
- Gintautas Miselis
- - Koen Reiniers (koenre)
- Rob Bast
- Roberto Espinoza (respinoza)
- Pierre Rineau
@@ -725,10 +728,13 @@ The Symfony Connect username in parenthesis allows to get more information
- Jan van Thoor (janvt)
- Gladhon
- Joshua Nye
+ - Martin Kirilov (wucdbm)
- Nathan Dench (ndenc2)
+ - Thibault Richard (t-richard)
- Sebastian Bergmann
- Miroslav Sustek
- Pablo Díez (pablodip)
+ - SiD (plbsid)
- Michel Roca (mroca)
- Piotr Kugla (piku235)
- Kevin McBride
@@ -777,8 +783,10 @@ The Symfony Connect username in parenthesis allows to get more information
- Norbert Orzechowicz (norzechowicz)
- Denis Charrier (brucewouaigne)
- Matthijs van den Bos (matthijs)
+ - Simon Podlipsky (simpod)
- DemigodCode
- Jaik Dean (jaikdean)
+ - Pavel Popov (metaer)
- Lenard Palko
- arai
- Nils Adermann (naderman)
@@ -824,6 +832,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Jeremy Benoist
- Lenar Lõhmus
- Daniël Brekelmans (dbrekelmans)
+ - Simon Heimberg (simon_heimberg)
- Benjamin Laugueux (yzalis)
- Zach Badgett (zachbadgett)
- Aurélien Fredouelle
@@ -860,7 +869,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Jules Matsounga (hyoa)
- Quentin Dequippe (qdequippe)
- khoptynskyi
- - Christin Gruber (christingruber)
- Jean-Christophe Cuvelier [Artack]
- julien57
- Julien Montel (julienmgel)
@@ -914,6 +922,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Nahuel Cuesta (ncuesta)
- Chris Boden (cboden)
- Christophe Villeger (seragan)
+ - Hendrik Luup
- Julien Fredon
- Jacek Wilczyński (jacekwilczynski)
- Xavier Leune (xleune)
@@ -954,7 +963,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Mardari Dorel (dorumd)
- Daisuke Ohata
- Vincent Simonin
- - Yoann RENARD (yrenard)
- Alex Bogomazov (alebo)
- maxime.steinhausser
- Claus Due (namelesscoder)
@@ -987,7 +995,6 @@ The Symfony Connect username in parenthesis allows to get more information
- rtek
- Benjamin Dos Santos
- Jérémy Jarrié (gagnar)
- - Martin Herndl (herndlm)
- Tomas Javaisis
- Ivan Grigoriev
- Johann Saunier (prophet777)
@@ -1058,7 +1065,6 @@ The Symfony Connect username in parenthesis allows to get more information
- mohammadreza honarkhah
- develop
- flip111
- - Thibault Richard (t-richard)
- VJ
- RJ Garcia
- Adam Wójs (awojs)
@@ -1081,7 +1087,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Andrea Sprega (asprega)
- Alexander Volochnev (exelenz)
- Viktor Bajraktar (njutn95)
- - SiD (plbsid)
- Mbechezi Nawo
- Michael Piecko
- Toni Peric (tperic)
@@ -1144,7 +1149,6 @@ The Symfony Connect username in parenthesis allows to get more information
- michaelwilliams
- Romain
- Matěj Humpál
- - Martin Kirilov
- Pierre Grimaud (pgrimaud)
- Alexandre Parent
- 1emming
@@ -1182,6 +1186,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Krzysiek Łabuś
- Juraj Surman
- Camille Dejoye
+ - Fabien S (bafs)
- 1ma (jautenim)
- Douglas Hammond (wizhippo)
- Xavier Lacot (xavier)
@@ -1204,7 +1209,6 @@ The Symfony Connect username in parenthesis allows to get more information
- roromix
- Dmitry Pigin (dotty)
- Vincent Composieux (eko)
- - Simon Podlipsky (simpod)
- Jayson Xu (superjavason)
- Hubert Lenoir (hubert_lenoir)
- fago
@@ -1248,6 +1252,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Aleksandar Jakovljevic (ajakov)
- Laurent Bassin (lbassin)
- Hamza Makraz (makraz)
+ - Tomasz Ignatiuk
- andrey1s
- Abhoryo
- Fabian Vogler (fabian)
@@ -1269,11 +1274,13 @@ The Symfony Connect username in parenthesis allows to get more information
- Tony Malzhacker
- Pchol
- Mathieu MARCHOIS
+ - W0rma
- Cyril Quintin (cyqui)
- Cyrille Bourgois (cyrilleb)
- Gerard van Helden (drm)
- Johnny Peck (johnnypeck)
- Marcos Rezende (rezehnde)
+ - Roman Anasal
- Ivan Menshykov
- David Romaní
- Patrick Allaert
@@ -1344,7 +1351,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Harry Walter (haswalt)
- Johnson Page (jwpage)
- Ruben Gonzalez (rubenruateltek)
- - Simon Heimberg (simon_heimberg)
- Michael Roterman (wtfzdotnet)
- Arno Geurts
- Adán Lobato (adanlobato)
@@ -1412,6 +1418,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Antoine Bluchet (soyuka)
- Patrick Kaufmann
- Anton Dyshkant
+ - Paul Oms
- Reece Fowell (reecefowell)
- stefan.r
- Guillaume Gammelin
@@ -1558,6 +1565,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Maximilian Berghoff (electricmaxxx)
- nacho
- Piotr Antosik (antek88)
+ - Volker Killesreiter (ol0lll)
- Vedran Mihočinec (v-m-i)
- Sergey Novikov (s12v)
- creiner
@@ -1677,6 +1685,7 @@ The Symfony Connect username in parenthesis allows to get more information
- rchoquet
- gitlost
- Taras Girnyk
+ - Dmitry Derepko
- Jan Vernarsky
- Amine Yakoubi
- Eduardo García Sanz (coma)
@@ -1686,7 +1695,9 @@ The Symfony Connect username in parenthesis allows to get more information
- James Gilliland
- fduch (fduch)
- Juan Miguel Besada Vidal (soutlink)
+ - dlorek
- Stuart Fyfe
+ - Carl Casbolt (carlcasbolt)
- David de Boer (ddeboer)
- Eno Mullaraj (emullaraj)
- Nathan PAGE (nathix)
@@ -1695,6 +1706,7 @@ The Symfony Connect username in parenthesis allows to get more information
- arnaud (arnooo999)
- Gilles Doge (gido)
- Oscar Esteve (oesteve)
+ - Peter Potrowl
- abulford
- Philipp Kretzschmar
- antograssiot
@@ -1762,10 +1774,12 @@ The Symfony Connect username in parenthesis allows to get more information
- Christian Rishøj
- Patrick Berenschot
- SuRiKmAn
+ - rtek
- Jelte Steijaert (jelte)
- David Négrier (moufmouf)
- Quique Porta (quiqueporta)
- Artem Oliynyk (artemoliynyk)
+ - Ben Roberts (benr77)
- Andrea Quintino (dirk39)
- Tomasz Szymczyk (karion)
- Alex Vasilchenko
@@ -1896,7 +1910,6 @@ The Symfony Connect username in parenthesis allows to get more information
- Luis Galeas
- Bogdan Scordaliu
- Martin Pärtel
- - Fabien S (bafs)
- Daniel Rotter (danrot)
- Frédéric Bouchery (fbouchery)
- kylekatarnls (kylekatarnls)
@@ -1921,6 +1934,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Guillaume BRETOU (guiguiboy)
- Nikita Popov (nikic)
- Carsten Nielsen (phreaknerd)
+ - Michael Olšavský
- Jay Severson
- Benny Born
- Emirald Mateli
@@ -2049,6 +2063,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Antonio Peric-Mazar (antonioperic)
- César Suárez (csuarez)
- Bjorn Twachtmann (dotbjorn)
+ - Wahyu Kristianto (kristories)
- Tobias Genberg (lorceroth)
- Nicolas Badey (nico-b)
- Shane Preece (shane)
@@ -2112,6 +2127,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Joni Halme
- Matt Farmer
- catch
+ - aetxebeste
- siganushka
- Alexandre Segura
- Josef Cech
@@ -2192,6 +2208,7 @@ The Symfony Connect username in parenthesis allows to get more information
- David Stone
- jjanvier
- Julius Beckmann
+ - Ruben Jansen
- shreypuranik
- loru88
- Thibaut Salanon
@@ -2261,6 +2278,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Alessio Baglio (ioalessio)
- Johannes Müller (johmue)
- Jordi Llonch (jordillonch)
+ - Jordi Sala Morales (jsala)
- Mouad ZIANI (mouadziani)
- Nicholas Ruunu (nicholasruunu)
- Jeroen van den Nieuwenhuisen (nieuwenhuisen)
@@ -2275,8 +2293,8 @@ The Symfony Connect username in parenthesis allows to get more information
- alex
- Nicole Cordes
- Nicolas PHILIPPE
- - Roman Anasal
- Roman Orlov
+ - Simon Ackermann
- VolCh
- Alexey Popkov
- Gijs Kunze
@@ -2437,6 +2455,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Filipe Guerra
- Jean Ragouin
- Gerben Wijnja
+ - Emre YILMAZ
- Rowan Manning
- Per Modin
- David Windell
@@ -2521,6 +2540,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Bart Reunes (metalarend)
- Muriel (metalmumu)
- Michael Pohlers (mick_the_big)
+ - Misha Klomp (mishaklomp)
- mlpo (mlpo)
- Marek Šimeček (mssimi)
- Dmitriy Tkachenko (neka)
@@ -2598,6 +2618,7 @@ The Symfony Connect username in parenthesis allows to get more information
- temperatur
- misterx
- Cas
+ - Vincent Godé
- Dusan Kasan
- Michael Steininger
- Nardberjean
@@ -2628,6 +2649,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Michel Bardelmeijer
- Tomas Kmieliauskas
- Ikko Ashimine
+ - Brad Jones
- Billie Thompson
- lol768
- jamogon
@@ -2681,6 +2703,7 @@ The Symfony Connect username in parenthesis allows to get more information
- James Michael DuPont
- Kasperki
- Tammy D
+ - Rodolfo Ruiz
- Enrico
- Ryan Rud
- Ondrej Slinták
@@ -2701,6 +2724,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Markus Staab
- Pierre-Louis LAUNAY
- djama
+ - Benjamin Rosenberger
- Vladyslav Startsev
- Michael Gwynne
- Eduardo Conceição
@@ -2717,6 +2741,7 @@ The Symfony Connect username in parenthesis allows to get more information
- nsbx
- Shude
- Richard Hodgson
+ - Sven Fabricius
- Ondřej Führer
- Sema
- Thorsten Hallwas
@@ -2760,6 +2785,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Sam Anthony
- Christian Stocker
- Oussama Elgoumri
+ - Steve Marvell
- Dawid Nowak
- Lesnykh Ilia
- sabruss
@@ -2823,6 +2849,7 @@ The Symfony Connect username in parenthesis allows to get more information
- Gerry Vandermaesen (gerryvdm)
- Ghazy Ben Ahmed (ghazy)
- Arash Tabriziyan (ghost098)
+ - Greg Szczotka (greg606)
- ibasaw (ibasaw)
- Vladislav Krupenkin (ideea)
- Ilija Tovilo (ilijatovilo)
diff --git a/README.md b/README.md
index 52860457b2336..02417bc9835d2 100644
--- a/README.md
+++ b/README.md
@@ -57,8 +57,8 @@ If you discover a security vulnerability within Symfony, please follow our
About Us
--------
-Symfony development is sponsored by [SensioLabs][21], led by the
-[Symfony Core Team][22] and supported by [Symfony contributors][19].
+Symfony development is led by the [Symfony Core Team][22]
+and supported by [Symfony contributors][19].
[1]: https://symfony.com
[2]: https://symfony.com/projects
@@ -80,7 +80,6 @@ Symfony development is sponsored by [SensioLabs][21], led by the
[18]: https://symfony.com/doc/current/contributing/documentation/index.html
[19]: https://symfony.com/contributors
[20]: https://symfony.com/security
-[21]: https://sensiolabs.com
[22]: https://symfony.com/doc/current/contributing/code/core_team.html
[23]: https://github.com/symfony/symfony-demo
[24]: https://symfony.com/coc
diff --git a/psalm.xml b/psalm.xml
index 3f12f1331c272..015c0ed18b21b 100644
--- a/psalm.xml
+++ b/psalm.xml
@@ -17,4 +17,15 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php
index 1f7f6afe4cc0f..6c0c0b9bc721d 100644
--- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php
+++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php
@@ -166,7 +166,7 @@ public function getTypes(string $class, string $property, array $context = [])
case Type::BUILTIN_TYPE_ARRAY:
switch ($typeOfField) {
case Types::ARRAY:
- case Types::JSON_ARRAY:
+ case 'json_array':
return [new Type(Type::BUILTIN_TYPE_ARRAY, $nullable, null, true)];
case Types::SIMPLE_ARRAY:
@@ -280,7 +280,7 @@ private function getPhpType(string $doctrineType): ?string
case Types::ARRAY:
case Types::SIMPLE_ARRAY:
- case Types::JSON_ARRAY:
+ case 'json_array':
return Type::BUILTIN_TYPE_ARRAY;
}
diff --git a/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php b/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php
index 01dce37978c94..5b6b37525426a 100644
--- a/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php
+++ b/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php
@@ -13,6 +13,7 @@
use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Driver\Result as DriverResult;
+use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Result;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Types\Types;
@@ -57,7 +58,7 @@ public function loadTokenBySeries(string $series)
// the alias for lastUsed works around case insensitivity in PostgreSQL
$sql = 'SELECT class, username, value, lastUsed AS last_used FROM rememberme_token WHERE series=:series';
$paramValues = ['series' => $series];
- $paramTypes = ['series' => \PDO::PARAM_STR];
+ $paramTypes = ['series' => ParameterType::STRING];
$stmt = $this->conn->executeQuery($sql, $paramValues, $paramTypes);
$row = $stmt instanceof Result || $stmt instanceof DriverResult ? $stmt->fetchAssociative() : $stmt->fetch(\PDO::FETCH_ASSOC);
@@ -75,7 +76,7 @@ public function deleteTokenBySeries(string $series)
{
$sql = 'DELETE FROM rememberme_token WHERE series=:series';
$paramValues = ['series' => $series];
- $paramTypes = ['series' => \PDO::PARAM_STR];
+ $paramTypes = ['series' => ParameterType::STRING];
if (method_exists($this->conn, 'executeStatement')) {
$this->conn->executeStatement($sql, $paramValues, $paramTypes);
} else {
@@ -95,9 +96,9 @@ public function updateToken(string $series, string $tokenValue, \DateTime $lastU
'series' => $series,
];
$paramTypes = [
- 'value' => \PDO::PARAM_STR,
+ 'value' => ParameterType::STRING,
'lastUsed' => Types::DATETIME_MUTABLE,
- 'series' => \PDO::PARAM_STR,
+ 'series' => ParameterType::STRING,
];
if (method_exists($this->conn, 'executeStatement')) {
$updated = $this->conn->executeStatement($sql, $paramValues, $paramTypes);
@@ -124,10 +125,10 @@ public function createNewToken(PersistentTokenInterface $token)
'lastUsed' => $token->getLastUsed(),
];
$paramTypes = [
- 'class' => \PDO::PARAM_STR,
- 'username' => \PDO::PARAM_STR,
- 'series' => \PDO::PARAM_STR,
- 'value' => \PDO::PARAM_STR,
+ 'class' => ParameterType::STRING,
+ 'username' => ParameterType::STRING,
+ 'series' => ParameterType::STRING,
+ 'value' => ParameterType::STRING,
'lastUsed' => Types::DATETIME_MUTABLE,
];
if (method_exists($this->conn, 'executeStatement')) {
diff --git a/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php b/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php
index 9c31d6d7e76b4..35fc48ff1536f 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php
@@ -11,9 +11,9 @@
namespace Symfony\Bridge\Doctrine\Tests\DataCollector;
+use Doctrine\DBAL\Connection;
use Doctrine\DBAL\Logging\DebugStack;
-use Doctrine\DBAL\Platforms\MySqlPlatform;
-use Doctrine\DBAL\Version;
+use Doctrine\DBAL\Platforms\MySQLPlatform;
use Doctrine\Persistence\ManagerRegistry;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Doctrine\DataCollector\DoctrineDataCollector;
@@ -22,6 +22,9 @@
use Symfony\Component\VarDumper\Cloner\Data;
use Symfony\Component\VarDumper\Dumper\CliDumper;
+// Doctrine DBAL 2 compatibility
+class_exists(\Doctrine\DBAL\Platforms\MySqlPlatform::class);
+
class DoctrineDataCollectorTest extends TestCase
{
public function testCollectConnections()
@@ -93,6 +96,8 @@ public function testCollectQueries($param, $types, $expected, $explainable, bool
$dumper->setColors(false);
$collectedParam->dump($dumper);
$this->assertStringMatchesFormat($expected, print_r(stream_get_contents($out, -1, 0), true));
+ } elseif (\is_string($expected)) {
+ $this->assertStringMatchesFormat($expected, $collectedParam);
} else {
$this->assertEquals($expected, $collectedParam);
}
@@ -150,7 +155,7 @@ public function testReset()
/**
* @dataProvider paramProvider
*/
- public function testSerialization($param, $types, $expected, $explainable, bool $runnable = true)
+ public function testSerialization($param, array $types, $expected, $explainable, bool $runnable = true)
{
$queries = [
['sql' => 'SELECT * FROM table1 WHERE field1 = ?1', 'params' => [$param], 'types' => $types, 'executionMS' => 1],
@@ -167,6 +172,8 @@ public function testSerialization($param, $types, $expected, $explainable, bool
$dumper->setColors(false);
$collectedParam->dump($dumper);
$this->assertStringMatchesFormat($expected, print_r(stream_get_contents($out, -1, 0), true));
+ } elseif (\is_string($expected)) {
+ $this->assertStringMatchesFormat($expected, $collectedParam);
} else {
$this->assertEquals($expected, $collectedParam);
}
@@ -175,9 +182,9 @@ public function testSerialization($param, $types, $expected, $explainable, bool
$this->assertSame($runnable, $collectedQueries['default'][0]['runnable']);
}
- public function paramProvider()
+ public function paramProvider(): array
{
- $tests = [
+ return [
['some value', [], 'some value', true],
[1, [], 1, true],
[true, [], true, true],
@@ -207,30 +214,25 @@ public function paramProvider()
,
false,
],
- ];
-
- if (version_compare(Version::VERSION, '2.6', '>=')) {
- $tests[] = ['this is not a date', ['date'], "⚠ Could not convert PHP value 'this is not a date' of type 'string' to type 'date'. Expected one of the following types: null, DateTime", false, false];
- $tests[] = [
+ ['this is not a date', ['date'], "⚠ Could not convert PHP value 'this is not a date'%S to type %Sdate%S. Expected one of the following types: null, DateTime", false, false],
+ [
new \stdClass(),
['date'],
<<getMockBuilder(\Doctrine\DBAL\Connection::class)
+ $connection = $this->getMockBuilder(Connection::class)
->disableOriginalConstructor()
->getMock();
$connection->expects($this->any())
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php
index 63cba7387c4a1..90cf50684d5d9 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php
@@ -296,9 +296,9 @@ public function testLoadChoicesForValuesDoesNotLoadIfEmptyValues()
/**
* @group legacy
*/
- public function legacyTestLoadChoicesForValuesLoadsOnlyChoicesIfValueUseIdReader()
+ public function testLegacyLoadChoicesForValuesLoadsOnlyChoicesIfValueUseIdReader()
{
- $this->expectDeprecation('Not defining explicitly the IdReader as value callback when query can be optimized has been deprecated in 5.1. Don\'t pass the IdReader to "Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader" or define the choice_value instead.');
+ $this->expectDeprecation('Since symfony/doctrine-bridge 5.1: Not defining explicitly the IdReader as value callback when query can be optimized is deprecated. Don\'t pass the IdReader to "Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader" or define the "choice_value" option instead.');
$loader = new DoctrineChoiceLoader(
$this->om,
$this->class,
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php b/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php
index f99a48527c442..be63ef923dfbc 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php
@@ -103,9 +103,12 @@ public function testInvalidEntityManagerThrowsException()
public function testMiddlewareNoPingInNonWorkerContext()
{
- $this->connection->expects($this->never())
- ->method('ping')
- ->willReturn(false);
+ // This method has been removed in DBAL 3.0
+ if (method_exists(Connection::class, 'ping')) {
+ $this->connection->expects($this->never())
+ ->method('ping')
+ ->willReturn(false);
+ }
$this->connection->expects($this->never())
->method('close')
diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json
index 152ed0ea75da2..49957bd989e7b 100644
--- a/src/Symfony/Bridge/Doctrine/composer.json
+++ b/src/Symfony/Bridge/Doctrine/composer.json
@@ -52,6 +52,7 @@
},
"conflict": {
"doctrine/dbal": "<2.10",
+ "doctrine/orm": "<2.7.3",
"phpunit/phpunit": "<5.4.3",
"symfony/dependency-injection": "<4.4",
"symfony/form": "<5.1",
diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
index 32461976f04b8..c2a524c44f699 100644
--- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
+++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
@@ -142,7 +142,7 @@ public function handleError($type, $msg, $file, $line, $context = [])
$msg = $deprecation->getMessage();
- if (error_reporting() & $type) {
+ if (\E_DEPRECATED !== $type && (error_reporting() & $type)) {
$group = 'unsilenced';
} elseif ($deprecation->isLegacy()) {
$group = 'legacy';
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/AboutCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/AboutCommand.php
index 3e359a04cbc42..05e7c3c6767b4 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/AboutCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/AboutCommand.php
@@ -44,9 +44,6 @@ protected function configure()
The PHP section displays important configuration that could affect your application. The values might
be different between web and CLI.
-
-The Environment section displays the current environment variables managed by Symfony Dotenv. It will not
-be shown if no variables were found. The values might be different between web and CLI.
EOT
)
;
diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsDecryptToLocalCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsDecryptToLocalCommand.php
index bf737308c5450..0e07d88fa3eb7 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Command/SecretsDecryptToLocalCommand.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Command/SecretsDecryptToLocalCommand.php
@@ -91,9 +91,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int
foreach ($secrets as $k => $v) {
if (null === $v) {
- $io->error($this->vault->getLastMessage());
-
- return 1;
+ $io->error($this->vault->getLastMessage() ?? sprintf('Secret "%s" has been skipped as there was an error reading it.', $k));
+ continue;
}
$this->localVault->seal($k, $v);
diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
index 7f439bb572f87..c35dc91a52c58 100644
--- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
+++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php
@@ -122,6 +122,7 @@ public function build(ContainerBuilder $container)
$container->addCompilerPass(new RegisterControllerArgumentLocatorsPass());
$container->addCompilerPass(new RemoveEmptyControllerArgumentLocatorsPass(), PassConfig::TYPE_BEFORE_REMOVING);
$container->addCompilerPass(new RoutingResolverPass());
+ $container->addCompilerPass(new DataCollectorTranslatorPass());
$container->addCompilerPass(new ProfilerPass());
// must be registered before removing private services as some might be listeners/subscribers
// but as late as possible to get resolved parameters
@@ -141,7 +142,6 @@ public function build(ContainerBuilder $container)
$container->addCompilerPass(new FragmentRendererPass());
$this->addCompilerPassIfExists($container, SerializerPass::class);
$this->addCompilerPassIfExists($container, PropertyInfoPass::class);
- $container->addCompilerPass(new DataCollectorTranslatorPass());
$container->addCompilerPass(new ControllerArgumentValueResolverPass());
$container->addCompilerPass(new CachePoolPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 32);
$container->addCompilerPass(new CachePoolClearerPass(), PassConfig::TYPE_AFTER_REMOVING);
diff --git a/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php b/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php
index 8ded6a2ee4320..7d4475a7e21ca 100644
--- a/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php
+++ b/src/Symfony/Bundle/FrameworkBundle/KernelBrowser.php
@@ -128,11 +128,14 @@ public function loginUser(object $user, string $firewallContext = 'main'): self
$container = $this->getContainer();
$container->get('security.untracked_token_storage')->setToken($token);
- if (!$container->has('session') && !$container->has('session_factory')) {
+ if ($container->has('session.factory')) {
+ $session = $container->get('session.factory')->createSession();
+ } elseif ($container->has('session')) {
+ $session = $container->get('session');
+ } else {
return $this;
}
- $session = $container->get($container->has('session') ? 'session' : 'session_factory');
$session->set('_security_'.$firewallContext, serialize($token));
$session->save();
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.php
index 350a6b27d7dc6..b15b29270afd4 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer.php
@@ -73,5 +73,9 @@
->tag('kernel.event_subscriber')
->tag('kernel.reset', ['method' => 'reset'])
->deprecate('symfony/framework-bundle', '5.2', 'The "%service_id%" service is deprecated, use "mailer.message_logger_listener" instead.')
+
+ ->set('mailer.message_logger_listener', MessageLoggerListener::class)
+ ->tag('kernel.event_subscriber')
+ ->tag('kernel.reset', ['method' => 'reset'])
;
};
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer_debug.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer_debug.php
index 5bc56faad5a05..3fb6ce0a42d49 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer_debug.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/mailer_debug.php
@@ -24,9 +24,5 @@
'template' => '@WebProfiler/Collector/mailer.html.twig',
'id' => 'mailer',
])
-
- ->set('mailer.message_logger_listener', MessageLoggerListener::class)
- ->tag('kernel.event_subscriber')
- ->tag('kernel.reset', ['method' => 'reset'])
;
};
diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
index edcaca3a90018..bc46570744d16 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
+++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd
@@ -310,6 +310,7 @@
+
@@ -339,6 +340,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml
index 290ab50e7d8da..79361af57a61f 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflows.xml
@@ -8,6 +8,7 @@
+ draftSymfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest
@@ -42,6 +43,7 @@
+ startSymfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest
diff --git a/src/Symfony/Bundle/SecurityBundle/Security/FirewallAwareTrait.php b/src/Symfony/Bundle/SecurityBundle/Security/FirewallAwareTrait.php
index 70d9178f8ab19..d79d0b7a1df53 100644
--- a/src/Symfony/Bundle/SecurityBundle/Security/FirewallAwareTrait.php
+++ b/src/Symfony/Bundle/SecurityBundle/Security/FirewallAwareTrait.php
@@ -29,7 +29,7 @@ private function getForFirewall(): object
{
$serviceIdentifier = str_replace('FirewallAware', '', static::class);
if (null === $request = $this->requestStack->getCurrentRequest()) {
- throw new \LogicException('Cannot determine the correct '.$serviceIdentifier.' to use: there is no active Request and so, the firewall cannot be determined. Try using a specific '.$serviceIdentifier().' service.');
+ throw new \LogicException('Cannot determine the correct '.$serviceIdentifier.' to use: there is no active Request and so, the firewall cannot be determined. Try using a specific '.$serviceIdentifier.' service.');
}
$firewall = $this->firewallMap->getFirewallConfig($request);
diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Security/UserAuthenticatorTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Security/UserAuthenticatorTest.php
new file mode 100644
index 0000000000000..ecb9cd8e7e33d
--- /dev/null
+++ b/src/Symfony/Bundle/SecurityBundle/Tests/Security/UserAuthenticatorTest.php
@@ -0,0 +1,34 @@
+expectException(\LogicException::class);
+ $this->expectExceptionMessage('Cannot determine the correct Symfony\Bundle\SecurityBundle\Security\UserAuthenticator to use: there is no active Request and so, the firewall cannot be determined. Try using a specific Symfony\Bundle\SecurityBundle\Security\UserAuthenticator service.');
+
+ $userAuthenticator->authenticateUser($user, $authenticator, $request);
+ }
+}
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig
index 7792ea6730a0f..6dfd27bcbc67a 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig
+++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/config.html.twig
@@ -116,14 +116,14 @@
Symfony version
- {% if 'n/a' != collector.env %}
+ {% if 'n/a' is not same as(collector.env) %}
{{ collector.env }}Environment
{% endif %}
- {% if 'n/a' != collector.debug %}
+ {% if 'n/a' is not same as(collector.debug) %}
{{ collector.debug ? 'enabled' : 'disabled' }}Debug
diff --git a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
index 0cfd10ae86be8..efba9eb54a799 100644
--- a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php
@@ -116,7 +116,7 @@ public static function createSystemCache(string $namespace, int $defaultLifetime
return $opcache;
}
- $apcu = new ApcuAdapter($namespace, (int) $defaultLifetime / 5, $version);
+ $apcu = new ApcuAdapter($namespace, intdiv($defaultLifetime, 5), $version);
if (null !== $logger) {
$apcu->setLogger($logger);
}
diff --git a/src/Symfony/Component/Cache/Adapter/PdoAdapter.php b/src/Symfony/Component/Cache/Adapter/PdoAdapter.php
index 568490c2fce76..b54841f0c0fbc 100644
--- a/src/Symfony/Component/Cache/Adapter/PdoAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/PdoAdapter.php
@@ -17,7 +17,9 @@
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Exception;
use Doctrine\DBAL\Exception\TableNotFoundException;
+use Doctrine\DBAL\ParameterType;
use Doctrine\DBAL\Schema\Schema;
+use Doctrine\DBAL\Statement;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\Marshaller\DefaultMarshaller;
use Symfony\Component\Cache\Marshaller\MarshallerInterface;
@@ -191,19 +193,29 @@ public function prune()
$deleteSql .= " AND $this->idCol LIKE :namespace";
}
+ $connection = $this->getConnection();
+ $useDbalConstants = $connection instanceof Connection;
+
try {
- $delete = $this->getConnection()->prepare($deleteSql);
+ $delete = $connection->prepare($deleteSql);
} catch (TableNotFoundException $e) {
return true;
} catch (\PDOException $e) {
return true;
}
- $delete->bindValue(':time', time(), \PDO::PARAM_INT);
+ $delete->bindValue(':time', time(), $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
if ('' !== $this->namespace) {
- $delete->bindValue(':namespace', sprintf('%s%%', $this->namespace), \PDO::PARAM_STR);
+ $delete->bindValue(':namespace', sprintf('%s%%', $this->namespace), $useDbalConstants ? ParameterType::STRING : \PDO::PARAM_STR);
}
try {
+ // Doctrine DBAL ^2.13 || >= 3.1
+ if ($delete instanceof Statement && method_exists($delete, 'executeStatement')) {
+ $delete->executeStatement();
+
+ return true;
+ }
+
return $delete->execute();
} catch (TableNotFoundException $e) {
return true;
@@ -217,13 +229,16 @@ public function prune()
*/
protected function doFetch(array $ids)
{
+ $connection = $this->getConnection();
+ $useDbalConstants = $connection instanceof Connection;
+
$now = time();
$expired = [];
$sql = str_pad('', (\count($ids) << 1) - 1, '?,');
$sql = "SELECT $this->idCol, CASE WHEN $this->lifetimeCol IS NULL OR $this->lifetimeCol + $this->timeCol > ? THEN $this->dataCol ELSE NULL END FROM $this->table WHERE $this->idCol IN ($sql)";
- $stmt = $this->getConnection()->prepare($sql);
- $stmt->bindValue($i = 1, $now, \PDO::PARAM_INT);
+ $stmt = $connection->prepare($sql);
+ $stmt->bindValue($i = 1, $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
foreach ($ids as $id) {
$stmt->bindValue(++$i, $id);
}
@@ -247,8 +262,8 @@ protected function doFetch(array $ids)
if ($expired) {
$sql = str_pad('', (\count($expired) << 1) - 1, '?,');
$sql = "DELETE FROM $this->table WHERE $this->lifetimeCol + $this->timeCol <= ? AND $this->idCol IN ($sql)";
- $stmt = $this->getConnection()->prepare($sql);
- $stmt->bindValue($i = 1, $now, \PDO::PARAM_INT);
+ $stmt = $connection->prepare($sql);
+ $stmt->bindValue($i = 1, $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
foreach ($expired as $id) {
$stmt->bindValue(++$i, $id);
}
@@ -261,11 +276,14 @@ protected function doFetch(array $ids)
*/
protected function doHave(string $id)
{
+ $connection = $this->getConnection();
+ $useDbalConstants = $connection instanceof Connection;
+
$sql = "SELECT 1 FROM $this->table WHERE $this->idCol = :id AND ($this->lifetimeCol IS NULL OR $this->lifetimeCol + $this->timeCol > :time)";
- $stmt = $this->getConnection()->prepare($sql);
+ $stmt = $connection->prepare($sql);
$stmt->bindValue(':id', $id);
- $stmt->bindValue(':time', time(), \PDO::PARAM_INT);
+ $stmt->bindValue(':time', time(), $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
$result = $stmt->execute();
return (bool) (\is_object($result) ? $result->fetchOne() : $stmt->fetchColumn());
@@ -328,6 +346,8 @@ protected function doSave(array $values, int $lifetime)
}
$conn = $this->getConnection();
+ $useDbalConstants = $conn instanceof Connection;
+
$driver = $this->driver;
$insertSql = "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->lifetimeCol, $this->timeCol) VALUES (:id, :data, :lifetime, :time)";
@@ -379,25 +399,25 @@ protected function doSave(array $values, int $lifetime)
if ('sqlsrv' === $driver || 'oci' === $driver) {
$stmt->bindParam(1, $id);
$stmt->bindParam(2, $id);
- $stmt->bindParam(3, $data, \PDO::PARAM_LOB);
- $stmt->bindValue(4, $lifetime, \PDO::PARAM_INT);
- $stmt->bindValue(5, $now, \PDO::PARAM_INT);
- $stmt->bindParam(6, $data, \PDO::PARAM_LOB);
- $stmt->bindValue(7, $lifetime, \PDO::PARAM_INT);
- $stmt->bindValue(8, $now, \PDO::PARAM_INT);
+ $stmt->bindParam(3, $data, $useDbalConstants ? ParameterType::LARGE_OBJECT : \PDO::PARAM_LOB);
+ $stmt->bindValue(4, $lifetime, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
+ $stmt->bindValue(5, $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
+ $stmt->bindParam(6, $data, $useDbalConstants ? ParameterType::LARGE_OBJECT : \PDO::PARAM_LOB);
+ $stmt->bindValue(7, $lifetime, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
+ $stmt->bindValue(8, $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
} else {
$stmt->bindParam(':id', $id);
- $stmt->bindParam(':data', $data, \PDO::PARAM_LOB);
- $stmt->bindValue(':lifetime', $lifetime, \PDO::PARAM_INT);
- $stmt->bindValue(':time', $now, \PDO::PARAM_INT);
+ $stmt->bindParam(':data', $data, $useDbalConstants ? ParameterType::LARGE_OBJECT : \PDO::PARAM_LOB);
+ $stmt->bindValue(':lifetime', $lifetime, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
+ $stmt->bindValue(':time', $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
}
if (null === $driver) {
$insertStmt = $conn->prepare($insertSql);
$insertStmt->bindParam(':id', $id);
- $insertStmt->bindParam(':data', $data, \PDO::PARAM_LOB);
- $insertStmt->bindValue(':lifetime', $lifetime, \PDO::PARAM_INT);
- $insertStmt->bindValue(':time', $now, \PDO::PARAM_INT);
+ $insertStmt->bindParam(':data', $data, $useDbalConstants ? ParameterType::LARGE_OBJECT : \PDO::PARAM_LOB);
+ $insertStmt->bindValue(':lifetime', $lifetime, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
+ $insertStmt->bindValue(':time', $now, $useDbalConstants ? ParameterType::INTEGER : \PDO::PARAM_INT);
}
foreach ($values as $id => $data) {
diff --git a/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php
index 304d173737193..58456e6835061 100644
--- a/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php
+++ b/src/Symfony/Component/Cache/Adapter/RedisTagAwareAdapter.php
@@ -15,6 +15,7 @@
use Predis\Connection\Aggregate\PredisCluster;
use Predis\Connection\Aggregate\ReplicationInterface;
use Predis\Response\Status;
+use Symfony\Component\Cache\CacheItem;
use Symfony\Component\Cache\Exception\InvalidArgumentException;
use Symfony\Component\Cache\Exception\LogicException;
use Symfony\Component\Cache\Marshaller\DeflateMarshaller;
@@ -163,6 +164,12 @@ protected function doDeleteYieldTags(array $ids): iterable
});
foreach ($results as $id => $result) {
+ if ($result instanceof \RedisException) {
+ CacheItem::log($this->logger, 'Failed to delete key "{key}": '.$result->getMessage(), ['key' => substr($id, \strlen($this->namespace)), 'exception' => $result]);
+
+ continue;
+ }
+
try {
yield $id => !\is_string($result) || '' === $result ? [] : $this->marshaller->unmarshall($result);
} catch (\Exception $e) {
@@ -201,6 +208,8 @@ protected function doInvalidate(array $tagIds): bool
// gargage collect that set from the client side.
$lua = <<<'EOLUA'
+ redis.replicate_commands()
+
local cursor = '0'
local id = KEYS[1]
repeat
@@ -238,6 +247,8 @@ protected function doInvalidate(array $tagIds): bool
});
$lua = <<<'EOLUA'
+ redis.replicate_commands()
+
local id = KEYS[1]
local cursor = table.remove(ARGV)
redis.call('SREM', '{'..id..'}'..id, unpack(ARGV))
@@ -245,7 +256,17 @@ protected function doInvalidate(array $tagIds): bool
return redis.call('SSCAN', '{'..id..'}'..id, cursor, 'COUNT', 5000)
EOLUA;
- foreach ($results as $id => [$cursor, $ids]) {
+ $success = true;
+ foreach ($results as $id => $values) {
+ if ($values instanceof \RedisException) {
+ CacheItem::log($this->logger, 'Failed to invalidate key "{key}": '.$values->getMessage(), ['key' => substr($id, \strlen($this->namespace)), 'exception' => $values]);
+ $success = false;
+
+ continue;
+ }
+
+ [$cursor, $ids] = $values;
+
while ($ids || '0' !== $cursor) {
$this->doDelete($ids);
@@ -268,7 +289,7 @@ protected function doInvalidate(array $tagIds): bool
}
}
- return true;
+ return $success;
}
private function getRedisEvictionPolicy(): string
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
index bf0c89bb1d935..b67fb5cd0cc79 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php
@@ -227,7 +227,7 @@ public function testPrune()
$doSet('qux', 'qux-val', new \DateInterval('PT20S'));
sleep(30);
- $cache->prune();
+ $this->assertTrue($cache->prune());
$this->assertTrue($this->isPruned($cache, 'foo'));
$this->assertTrue($this->isPruned($cache, 'bar'));
$this->assertTrue($this->isPruned($cache, 'baz'));
@@ -238,27 +238,27 @@ public function testPrune()
$doSet('baz', 'baz-val', new \DateInterval('PT40S'));
$doSet('qux', 'qux-val', new \DateInterval('PT80S'));
- $cache->prune();
+ $this->assertTrue($cache->prune());
$this->assertFalse($this->isPruned($cache, 'foo'));
$this->assertFalse($this->isPruned($cache, 'bar'));
$this->assertFalse($this->isPruned($cache, 'baz'));
$this->assertFalse($this->isPruned($cache, 'qux'));
sleep(30);
- $cache->prune();
+ $this->assertTrue($cache->prune());
$this->assertFalse($this->isPruned($cache, 'foo'));
$this->assertTrue($this->isPruned($cache, 'bar'));
$this->assertFalse($this->isPruned($cache, 'baz'));
$this->assertFalse($this->isPruned($cache, 'qux'));
sleep(30);
- $cache->prune();
+ $this->assertTrue($cache->prune());
$this->assertFalse($this->isPruned($cache, 'foo'));
$this->assertTrue($this->isPruned($cache, 'baz'));
$this->assertFalse($this->isPruned($cache, 'qux'));
sleep(30);
- $cache->prune();
+ $this->assertTrue($cache->prune());
$this->assertFalse($this->isPruned($cache, 'foo'));
$this->assertTrue($this->isPruned($cache, 'qux'));
}
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
index b77568be593e6..ddfc5fd382143 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php
@@ -153,8 +153,10 @@ private function autowireCalls(\ReflectionClass $reflectionClass, bool $isRoot,
$this->decoratedClass = null;
$this->getPreviousValue = null;
- if ($isRoot && ($definition = $this->container->getDefinition($this->currentId)) && null !== ($this->decoratedId = $definition->innerServiceId) && $this->container->has($this->decoratedId)) {
- $this->decoratedClass = $this->container->findDefinition($this->decoratedId)->getClass();
+ if ($isRoot && ($definition = $this->container->getDefinition($this->currentId)) && ($decoratedDefinition = $definition->getDecoratedService()) && null !== ($innerId = $decoratedDefinition[0]) && $this->container->has($innerId)) {
+ // If the class references to itself and is decorated, provide the inner service id and class to not get a circular reference
+ $this->decoratedClass = $this->container->findDefinition($innerId)->getClass();
+ $this->decoratedId = $decoratedDefinition[1] ?? $this->currentId.'.inner';
}
foreach ($this->methodCalls as $i => $call) {
diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractServiceConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractServiceConfigurator.php
index f4f61ab46a8b2..96d6fd75a7764 100644
--- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractServiceConfigurator.php
+++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/AbstractServiceConfigurator.php
@@ -32,8 +32,8 @@ public function __destruct()
{
// default tags should be added last
foreach ($this->defaultTags as $name => $attributes) {
- foreach ($attributes as $attributes) {
- $this->definition->addTag($name, $attributes);
+ foreach ($attributes as $attribute) {
+ $this->definition->addTag($name, $attribute);
}
}
$this->defaultTags = [];
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php
index b61dc64fe8234..33e9adecfb4ea 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php
@@ -985,8 +985,8 @@ public function testAutowireDecorator()
->setAutowired(true)
;
- (new DecoratorServicePass())->process($container);
(new AutowirePass())->process($container);
+ (new DecoratorServicePass())->process($container);
$definition = $container->getDefinition(Decorator::class);
$this->assertSame(Decorator::class.'.inner', (string) $definition->getArgument(1));
@@ -1008,8 +1008,8 @@ public function testAutowireDecoratorChain()
->setAutowired(true)
;
- (new DecoratorServicePass())->process($container);
(new AutowirePass())->process($container);
+ (new DecoratorServicePass())->process($container);
$definition = $container->getDefinition(DecoratedDecorator::class);
$this->assertSame(DecoratedDecorator::class.'.inner', (string) $definition->getArgument(0));
@@ -1026,8 +1026,8 @@ public function testAutowireDecoratorRenamedId()
->setAutowired(true)
;
- (new DecoratorServicePass())->process($container);
(new AutowirePass())->process($container);
+ (new DecoratorServicePass())->process($container);
$definition = $container->getDefinition(Decorator::class);
$this->assertSame('renamed', (string) $definition->getArgument(1));
@@ -1044,12 +1044,11 @@ public function testDoNotAutowireDecoratorWhenSeveralArgumentOfTheType()
->setAutowired(true)
;
- (new DecoratorServicePass())->process($container);
try {
(new AutowirePass())->process($container);
$this->fail('AutowirePass should have thrown an exception');
} catch (AutowiringFailedException $e) {
- $this->assertSame('Cannot autowire service "Symfony\Component\DependencyInjection\Tests\Compiler\NonAutowirableDecorator": argument "$decorated1" of method "__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\DecoratorInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "Symfony\Component\DependencyInjection\Tests\Compiler\NonAutowirableDecorator", "Symfony\Component\DependencyInjection\Tests\Compiler\NonAutowirableDecorator.inner".', (string) $e->getMessage());
+ $this->assertSame('Cannot autowire service "Symfony\Component\DependencyInjection\Tests\Compiler\NonAutowirableDecorator": argument "$decorated1" of method "__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\DecoratorInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "Symfony\Component\DependencyInjection\Tests\Compiler\Decorated", "Symfony\Component\DependencyInjection\Tests\Compiler\NonAutowirableDecorator".', (string) $e->getMessage());
}
}
@@ -1106,4 +1105,23 @@ public function testArgumentWithTarget()
$this->assertSame(BarInterface::class.' $imageStorage', (string) $container->getDefinition('with_target')->getArgument(0));
}
+
+ public function testDecorationWithServiceAndAliasedInterface()
+ {
+ $container = new ContainerBuilder();
+
+ $container->register(DecoratorImpl::class, DecoratorImpl::class)
+ ->setAutowired(true)
+ ->setPublic(true);
+ $container->setAlias(DecoratorInterface::class, DecoratorImpl::class)->setPublic(true);
+ $container->register(DecoratedDecorator::class, DecoratedDecorator::class)
+ ->setAutowired(true)
+ ->setPublic(true)
+ ->setDecoratedService(DecoratorImpl::class);
+
+ $container->compile();
+
+ static::assertInstanceOf(DecoratedDecorator::class, $container->get(DecoratorInterface::class));
+ static::assertInstanceOf(DecoratedDecorator::class, $container->get(DecoratorImpl::class));
+ }
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php
index 3714936b4df2b..5bf9465a7a2dd 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/autowiring_classes.php
@@ -382,6 +382,10 @@ interface DecoratorInterface
{
}
+class DecoratorImpl implements DecoratorInterface
+{
+}
+
class Decorated implements DecoratorInterface
{
public function __construct($quz = null, \NonExistent $nonExistent = null, DecoratorInterface $decorated = null, array $foo = [])
diff --git a/src/Symfony/Component/Form/Resources/translations/validators.my.xlf b/src/Symfony/Component/Form/Resources/translations/validators.my.xlf
new file mode 100644
index 0000000000000..b0180c551172f
--- /dev/null
+++ b/src/Symfony/Component/Form/Resources/translations/validators.my.xlf
@@ -0,0 +1,139 @@
+
+
+
+
+
+ This form should not contain extra fields.
+ ဤ ဖောင်သည် field အပိုများ မပါ၀င်သင့်ပါ။
+
+
+ The uploaded file was too large. Please try to upload a smaller file.
+ Upload တင်သောဖိုင်သည်အလွန်ကြီးလွန်းသည်။ ကျေးဇူးပြု၍ သေးငယ်သည့်ဖိုင်ကိုတင်ရန်ကြိုးစားပါ။
+
+
+ The CSRF token is invalid. Please try to resubmit the form.
+ သင့်လျှော်သော် CSRF တိုကင် မဟုတ်ပါ။ ကျေးဇူးပြု၍ဖောင်ကိုပြန်တင်ပါ။
+
+
+ This value is not a valid HTML5 color.
+ ဤတန်ဖိုးသည် သင့်လျှော်သော် HTML5 အရောင်မဟုတ်ပါ။
+
+
+ Please enter a valid birthdate.
+ ကျေးဇူးပြု၍ မှန်ကန်သောမွေးနေ့ကိုထည့်ပါ။
+
+
+ The selected choice is invalid.
+ သင့် ရွေးချယ်မှုသည်မမှန်ကန်ပါ။
+
+
+ The collection is invalid.
+ ဤ collection သည်သင့်လျှော်သော် collection မဟုတ်ပါ။
+
+
+ Please select a valid color.
+ ကျေးဇူးပြု၍ မှန်ကန်သောအရောင်ကိုရွေးပါ။
+
+
+ Please select a valid country.
+ ကျေးဇူးပြု၍ မှန်ကန်သောနိုင်ငံကိုရွေးပါ။
+
+
+ Please select a valid currency.
+ ကျေးဇူးပြု၍ မှန်ကန်သောငွေကြေးကိုရွေးပါ။
+
+
+ Please choose a valid date interval.
+ ကျေးဇူးပြု၍ မှန်ကန်သောနေ ရက်စွဲကိုရွေးပါ။
+
+
+ Please enter a valid date and time.
+ ကျေးဇူးပြု၍ မှန်ကန်သောနေ ရက်စွဲနှင့်အချိန် ကိုထည့်ပါ။
+
+
+ Please enter a valid date.
+ ကျေးဇူးပြု၍ မှန်ကန်သောနေ ရက်စွဲကိုထည့်ပါ။
+
+
+ Please select a valid file.
+ ကျေးဇူးပြု၍ မှန်ကန်သောနေ ဖိုင်ကိုရွေးချယ်ပါ။
+
+
+ The hidden field is invalid.
+ မသင့် လျှော်သော် hidden field ဖြစ်နေသည်။
+
+
+ Please enter an integer.
+ ကျေးဇူးပြု၍ Integer တန်ဖိုးသာထည့်ပါ။
+
+
+ Please select a valid language.
+ ကျေးဇူးပြု၍ မှန်ကန်သော ဘာသာစကားကိုရွေးချယ်ပါ။
+
+
+ Please select a valid locale.
+ ကျေးဇူးပြု၍ မှန်ကန်သော locale ကိုရွေးချယ်ပါ။
+
+
+ Please enter a valid money amount.
+ ကျေးဇူးပြု၍ မှန်ကန်သော ပိုက်ဆံပမာဏ ကိုထည့်ပါ။
+
+
+ Please enter a number.
+ ကျေးဇူးပြု၍ မှန်ကန်သော နံပါတ် ကိုရွေးချယ်ပါ။
+
+
+ The password is invalid.
+ မှန်ကန်သောစကား၀ှက်မဟုတ်ပါ။
+
+
+ Please enter a percentage value.
+ ကျေးဇူးပြု၍ ရာခိုင်နှုန်းတန်ဖိုးထည့်ပါ။
+
+
+ The values do not match.
+ တန်ဖိုးများကိုက်ညီမှုမရှိပါ။
+
+
+ Please enter a valid time.
+ ကျေးဇူးပြု၍ မှန်ကန်သောအချိန်ကိုထည့်ပါ။
+
+
+ Please select a valid timezone.
+ ကျေးဇူးပြု၍ မှန်ကန်သောအချိန်ဇုန်ကိုရွေးပါ။
+
+
+ Please enter a valid URL.
+ ကျေးဇူးပြု၍ သင့်လျှော်သော် URL ကိုရွေးပါ။
+
+
+ Please enter a valid search term.
+ ကျေးဇူးပြု၍ သင့် လျှော်သော်ရှာဖွေမှု term များထည့်ပါ။
+
+
+ Please provide a valid phone number.
+ ကျေးဇူးပြု၍ သင့် လျှော်သော်ရှာဖွေမှု ဖုန်းနံပါတ်ထည့်ပါ။
+
+
+ The checkbox has an invalid value.
+ Checkbox တန်ဖိုးသည် မှန်ကန်မှုမရှိပါ။
+
+
+ Please enter a valid email address.
+ ကျေးဇူးပြု၍ မှန်ကန်သော် email လိပ်စာထည့်ပါ။
+
+
+ Please select a valid option.
+ ကျေးဇူးပြု၍ မှန်ကန်သော် ရွေးချယ်မှု ကိုရွေးပါ။
+
+
+ Please select a valid range.
+ ကျေးဇူးပြု၍ မှန်ကန်သော အပိုင်းအခြား ကိုရွေးပါ။
+
+
+ Please enter a valid week.
+ ကျေးဇူးပြု၍ မှန်ကန်သောရက်သတ္တပတ်ကိုထည့်ပါ။
+
+
+
+
diff --git a/src/Symfony/Component/Form/Tests/Util/StringUtilTest.php b/src/Symfony/Component/Form/Tests/Util/StringUtilTest.php
index 1d162250d1568..3058a2e25d84d 100644
--- a/src/Symfony/Component/Form/Tests/Util/StringUtilTest.php
+++ b/src/Symfony/Component/Form/Tests/Util/StringUtilTest.php
@@ -16,11 +16,20 @@
class StringUtilTest extends TestCase
{
- public function testTrim()
+ public function trimProvider()
{
- $data = ' Foo! ';
+ return [
+ [' Foo! ', 'Foo!'],
+ ["\u{1F92E}", "\u{1F92E}"], // unassigned character in PCRE versions of assertEquals('Foo!', StringUtil::trim($data));
+ /**
+ * @dataProvider trimProvider
+ */
+ public function testTrim($data, $expectedData)
+ {
+ $this->assertSame($expectedData, StringUtil::trim($data));
}
/**
diff --git a/src/Symfony/Component/Form/Util/StringUtil.php b/src/Symfony/Component/Form/Util/StringUtil.php
index 851baf0c19ecb..a33b506b157da 100644
--- a/src/Symfony/Component/Form/Util/StringUtil.php
+++ b/src/Symfony/Component/Form/Util/StringUtil.php
@@ -31,7 +31,7 @@ private function __construct()
*/
public static function trim(string $string)
{
- if (null !== $result = @preg_replace('/^[\pZ\pC]+|[\pZ\pC]+$/u', '', $string)) {
+ if (null !== $result = @preg_replace('/^[\pZ\p{Cc}\p{Cf}]+|[\pZ\p{Cc}\p{Cf}]+$/u', '', $string)) {
return $result;
}
diff --git a/src/Symfony/Component/HttpClient/Internal/ClientState.php b/src/Symfony/Component/HttpClient/Internal/ClientState.php
index c316e7b078920..52fe3c8c054c7 100644
--- a/src/Symfony/Component/HttpClient/Internal/ClientState.php
+++ b/src/Symfony/Component/HttpClient/Internal/ClientState.php
@@ -22,4 +22,5 @@ class ClientState
{
public $handlesActivity = [];
public $openHandles = [];
+ public $lastTimeout;
}
diff --git a/src/Symfony/Component/HttpClient/Response/AsyncResponse.php b/src/Symfony/Component/HttpClient/Response/AsyncResponse.php
index 1e64959df8e0b..06518f1a2cb3a 100644
--- a/src/Symfony/Component/HttpClient/Response/AsyncResponse.php
+++ b/src/Symfony/Component/HttpClient/Response/AsyncResponse.php
@@ -57,13 +57,13 @@ public function __construct(HttpClientInterface $client, string $method, string
}
$this->response = $client->request($method, $url, ['buffer' => false] + $options);
$this->passthru = $passthru;
- $this->initializer = static function (self $response) {
+ $this->initializer = static function (self $response, float $timeout = null) {
if (null === $response->shouldBuffer) {
return false;
}
while (true) {
- foreach (self::stream([$response]) as $chunk) {
+ foreach (self::stream([$response], $timeout) as $chunk) {
if ($chunk->isTimeout() && $response->passthru) {
foreach (self::passthru($response->client, $response, new ErrorChunk($response->offset, new TransportException($chunk->getError()))) as $chunk) {
if ($chunk->isFirst()) {
@@ -179,6 +179,7 @@ public function __destruct()
if ($this->initializer && null === $this->getInfo('error')) {
try {
+ self::initialize($this, -0.0);
$this->getHeaders(true);
} catch (HttpExceptionInterface $httpException) {
// no-op
diff --git a/src/Symfony/Component/HttpClient/Response/CommonResponseTrait.php b/src/Symfony/Component/HttpClient/Response/CommonResponseTrait.php
index f3c8e149f77f7..1dd8c1f071e04 100644
--- a/src/Symfony/Component/HttpClient/Response/CommonResponseTrait.php
+++ b/src/Symfony/Component/HttpClient/Response/CommonResponseTrait.php
@@ -145,15 +145,15 @@ public function __wakeup()
*/
abstract protected function close(): void;
- private static function initialize(self $response): void
+ private static function initialize(self $response, float $timeout = null): void
{
if (null !== $response->getInfo('error')) {
throw new TransportException($response->getInfo('error'));
}
try {
- if (($response->initializer)($response)) {
- foreach (self::stream([$response]) as $chunk) {
+ if (($response->initializer)($response, $timeout)) {
+ foreach (self::stream([$response], $timeout) as $chunk) {
if ($chunk->isFirst()) {
break;
}
diff --git a/src/Symfony/Component/HttpClient/Response/TransportResponseTrait.php b/src/Symfony/Component/HttpClient/Response/TransportResponseTrait.php
index 8c490bcd5b826..105b375d35615 100644
--- a/src/Symfony/Component/HttpClient/Response/TransportResponseTrait.php
+++ b/src/Symfony/Component/HttpClient/Response/TransportResponseTrait.php
@@ -138,7 +138,7 @@ private function doDestruct()
$this->shouldBuffer = true;
if ($this->initializer && null === $this->info['error']) {
- self::initialize($this);
+ self::initialize($this, -0.0);
$this->checkStatusCode();
}
}
@@ -159,6 +159,12 @@ public static function stream(iterable $responses, float $timeout = null): \Gene
$lastActivity = microtime(true);
$elapsedTimeout = 0;
+ if ($fromLastTimeout = 0.0 === $timeout && '-0' === (string) $timeout) {
+ $timeout = null;
+ } elseif ($fromLastTimeout = 0 > $timeout) {
+ $timeout = -$timeout;
+ }
+
while (true) {
$hasActivity = false;
$timeoutMax = 0;
@@ -172,15 +178,21 @@ public static function stream(iterable $responses, float $timeout = null): \Gene
foreach ($responses as $j => $response) {
$timeoutMax = $timeout ?? max($timeoutMax, $response->timeout);
$timeoutMin = min($timeoutMin, $response->timeout, 1);
+
+ if ($fromLastTimeout && null !== $multi->lastTimeout) {
+ $elapsedTimeout = microtime(true) - $multi->lastTimeout;
+ }
+
$chunk = false;
if (isset($multi->handlesActivity[$j])) {
- // no-op
+ $multi->lastTimeout = null;
} elseif (!isset($multi->openHandles[$j])) {
unset($responses[$j]);
continue;
} elseif ($elapsedTimeout >= $timeoutMax) {
$multi->handlesActivity[$j] = [new ErrorChunk($response->offset, sprintf('Idle timeout reached for "%s".', $response->getInfo('url')))];
+ $multi->lastTimeout ?? $multi->lastTimeout = $lastActivity;
} else {
continue;
}
diff --git a/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php b/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php
index 0c91fb65d1b4c..0dfca6d4a2f97 100644
--- a/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php
+++ b/src/Symfony/Component/HttpClient/Tests/AsyncDecoratorTraitTest.php
@@ -13,6 +13,7 @@
use Symfony\Component\HttpClient\AsyncDecoratorTrait;
use Symfony\Component\HttpClient\DecoratorTrait;
+use Symfony\Component\HttpClient\HttpClient;
use Symfony\Component\HttpClient\Response\AsyncContext;
use Symfony\Component\HttpClient\Response\AsyncResponse;
use Symfony\Contracts\HttpClient\ChunkInterface;
@@ -29,6 +30,10 @@ protected function getHttpClient(string $testCase, \Closure $chunkFilter = null,
$this->markTestSkipped("AsyncDecoratorTrait doesn't cache handles");
}
+ if ('testTimeoutOnDestruct' === $testCase) {
+ return HttpClient::create();
+ }
+
$chunkFilter = $chunkFilter ?? static function (ChunkInterface $chunk, AsyncContext $context) { yield $chunk; };
return new class($decoratedClient ?? parent::getHttpClient($testCase), $chunkFilter) implements HttpClientInterface {
@@ -49,6 +54,15 @@ public function request(string $method, string $url, array $options = []): Respo
};
}
+ public function testTimeoutOnDestruct()
+ {
+ if (HttpClient::create() instanceof NativeHttpClient) {
+ $this->markTestSkipped('NativeHttpClient doesn\'t support opening concurrent requests.');
+ }
+
+ HttpClientTestCase::testTimeoutOnDestruct();
+ }
+
public function testRetry404()
{
$client = $this->getHttpClient(__FUNCTION__, function (ChunkInterface $chunk, AsyncContext $context) {
diff --git a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php
index 7ad91fd6bf8b1..87a460741e334 100644
--- a/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php
+++ b/src/Symfony/Component/HttpClient/Tests/HttpClientTestCase.php
@@ -32,6 +32,15 @@ abstract class HttpClientTestCase extends BaseHttpClientTestCase
{
private static $vulcainStarted = false;
+ public function testTimeoutOnDestruct()
+ {
+ if (!method_exists(parent::class, 'testTimeoutOnDestruct')) {
+ $this->markTestSkipped('BaseHttpClientTestCase doesn\'t have testTimeoutOnDestruct().');
+ }
+
+ parent::testTimeoutOnDestruct();
+ }
+
public function testAcceptHeader()
{
$client = $this->getHttpClient(__FUNCTION__);
diff --git a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php
index fcb871b1bc360..6ddb663ac2273 100644
--- a/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php
+++ b/src/Symfony/Component/HttpClient/Tests/MockHttpClientTest.php
@@ -236,6 +236,10 @@ protected function getHttpClient(string $testCase): HttpClientInterface
$this->markTestSkipped('Real transport required');
break;
+ case 'testTimeoutOnDestruct':
+ $this->markTestSkipped('Real transport required');
+ break;
+
case 'testDestruct':
$this->markTestSkipped("MockHttpClient doesn't timeout on destruct");
break;
diff --git a/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php b/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php
index 819124f1745b4..8080a90d20682 100644
--- a/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php
+++ b/src/Symfony/Component/HttpClient/Tests/NativeHttpClientTest.php
@@ -26,6 +26,11 @@ public function testInformationalResponseStream()
$this->markTestSkipped('NativeHttpClient doesn\'t support informational status codes.');
}
+ public function testTimeoutOnDestruct()
+ {
+ $this->markTestSkipped('NativeHttpClient doesn\'t support opening concurrent requests.');
+ }
+
public function testHttp2PushVulcain()
{
$this->markTestSkipped('NativeHttpClient doesn\'t support HTTP/2.');
diff --git a/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php
index 4e95603fb81c4..169366d076b79 100644
--- a/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php
+++ b/src/Symfony/Component/HttpKernel/DataCollector/TimeDataCollector.php
@@ -45,7 +45,7 @@ public function collect(Request $request, Response $response, \Throwable $except
}
$this->data = [
- 'token' => $response->headers->get('X-Debug-Token'),
+ 'token' => $request->attributes->get('_stopwatch_token'),
'start_time' => $startTime * 1000,
'events' => [],
'stopwatch_installed' => class_exists(Stopwatch::class, false),
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index 21e7e8543254b..027eef0baacf9 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -75,11 +75,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
private static $freshCache = [];
- public const VERSION = '5.3.7';
- public const VERSION_ID = 50307;
+ public const VERSION = '5.3.8';
+ public const VERSION_ID = 50308;
public const MAJOR_VERSION = 5;
public const MINOR_VERSION = 3;
- public const RELEASE_VERSION = 7;
+ public const RELEASE_VERSION = 8;
public const EXTRA_VERSION = '';
public const END_OF_MAINTENANCE = '01/2022';
diff --git a/src/Symfony/Component/HttpKernel/Tests/CacheClearer/Psr6CacheClearerTest.php b/src/Symfony/Component/HttpKernel/Tests/CacheClearer/Psr6CacheClearerTest.php
index 0c6f1543acfdd..26b323f81051a 100644
--- a/src/Symfony/Component/HttpKernel/Tests/CacheClearer/Psr6CacheClearerTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/CacheClearer/Psr6CacheClearerTest.php
@@ -32,9 +32,11 @@ public function testClearPool()
$pool = $this->createMock(CacheItemPoolInterface::class);
$pool
->expects($this->once())
- ->method('clear');
+ ->method('clear')
+ ->willReturn(true)
+ ;
- (new Psr6CacheClearer(['pool' => $pool]))->clearPool('pool');
+ $this->assertTrue((new Psr6CacheClearer(['pool' => $pool]))->clearPool('pool'));
}
public function testClearPoolThrowsExceptionOnUnreferencedPool()
diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php
index 22ace783a3134..7dbc439d70b62 100644
--- a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RegisterControllerArgumentLocatorsPassTest.php
@@ -249,7 +249,8 @@ public function testNoExceptionOnNonExistentTypeHintOptionalArg()
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
- $this->assertSame(['foo::barAction', 'foo::fooAction'], array_keys($locator));
+
+ $this->assertEqualsCanonicalizing(['foo::barAction', 'foo::fooAction'], array_keys($locator));
}
public function testArgumentWithNoTypeHintIsOk()
@@ -396,7 +397,7 @@ public function testAlias()
$pass->process($container);
$locator = $container->getDefinition((string) $resolver->getArgument(0))->getArgument(0);
- $this->assertSame([RegisterTestController::class.'::fooAction', 'foo::fooAction'], array_keys($locator));
+ $this->assertEqualsCanonicalizing([RegisterTestController::class.'::fooAction', 'foo::fooAction'], array_keys($locator));
}
/**
diff --git a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php
index b5e55bdea9e97..b9dd84d592fa6 100644
--- a/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/DependencyInjection/RemoveEmptyControllerArgumentLocatorsPassTest.php
@@ -57,7 +57,7 @@ public function testProcess()
'Symfony\Component\HttpKernel\DependencyInjection\RemoveEmptyControllerArgumentLocatorsPass: Removing method "setTestCase" of service "c2" from controller candidates: the method is called at instantiation, thus cannot be an action.',
];
- $this->assertSame($expectedLog, $container->getCompiler()->getLog());
+ $this->assertEqualsCanonicalizing($expectedLog, $container->getCompiler()->getLog());
}
public function testInvoke()
diff --git a/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php b/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php
index 6bd52c5ba7054..6c1dc2f7c685e 100644
--- a/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php
+++ b/src/Symfony/Component/Intl/Tests/DateFormatter/AbstractIntlDateFormatterTest.php
@@ -58,6 +58,9 @@ public function testConstructorDefaultTimeZone()
);
}
+ /**
+ * @group legacy
+ */
public function testConstructorWithoutDateType()
{
$formatter = $this->getDateFormatter('en', null, IntlDateFormatter::SHORT, 'UTC', IntlDateFormatter::GREGORIAN);
@@ -65,6 +68,9 @@ public function testConstructorWithoutDateType()
$this->assertSame('EEEE, MMMM d, y \'at\' h:mm a', $formatter->getPattern());
}
+ /**
+ * @group legacy
+ */
public function testConstructorWithoutTimeType()
{
$formatter = $this->getDateFormatter('en', IntlDateFormatter::SHORT, null, 'UTC', IntlDateFormatter::GREGORIAN);
diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php
index 4fd0bd68877f9..3de499e9d1f03 100644
--- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php
+++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Connection.php
@@ -11,6 +11,7 @@
namespace Symfony\Component\Ldap\Adapter\ExtLdap;
+use LDAP\Connection as LDAPConnection;
use Symfony\Component\Ldap\Adapter\AbstractConnection;
use Symfony\Component\Ldap\Exception\AlreadyExistsException;
use Symfony\Component\Ldap\Exception\ConnectionException;
@@ -32,7 +33,7 @@ class Connection extends AbstractConnection
/** @var bool */
private $bound = false;
- /** @var resource */
+ /** @var resource|LDAPConnection */
private $connection;
/**
@@ -89,9 +90,7 @@ public function bind(string $dn = null, string $password = null)
}
/**
- * Returns a link resource.
- *
- * @return resource
+ * @return resource|LDAPConnection
*
* @internal
*/
@@ -165,7 +164,7 @@ private function connect()
private function disconnect()
{
- if ($this->connection && \is_resource($this->connection)) {
+ if ($this->connection) {
ldap_unbind($this->connection);
}
diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php
index 519357ad4c6a5..15b36e9477188 100644
--- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php
+++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/Query.php
@@ -11,6 +11,8 @@
namespace Symfony\Component\Ldap\Adapter\ExtLdap;
+use LDAP\Connection as LDAPConnection;
+use LDAP\Result;
use Symfony\Component\Ldap\Adapter\AbstractQuery;
use Symfony\Component\Ldap\Exception\LdapException;
use Symfony\Component\Ldap\Exception\NotBoundException;
@@ -27,7 +29,7 @@ class Query extends AbstractQuery
/** @var Connection */
protected $connection;
- /** @var resource[] */
+ /** @var resource[]|Result[] */
private $results;
/** @var array */
@@ -156,7 +158,7 @@ public function execute()
* Returns an LDAP search resource. If this query resulted in multiple searches, only the first
* page will be returned.
*
- * @return resource
+ * @return resource|Result
*
* @internal
*/
@@ -172,7 +174,7 @@ public function getResource(int $idx = 0)
/**
* Returns all LDAP search resources.
*
- * @return resource[]
+ * @return resource[]|Result[]
*
* @internal
*/
@@ -215,7 +217,7 @@ private function resetPagination()
/**
* Sets LDAP pagination controls.
*
- * @param resource $con
+ * @param resource|LDAPConnection $con
*/
private function controlPagedResult($con, int $pageSize, bool $critical, string $cookie): bool
{
@@ -239,8 +241,8 @@ private function controlPagedResult($con, int $pageSize, bool $critical, string
/**
* Retrieve LDAP pagination cookie.
*
- * @param resource $con
- * @param resource $result
+ * @param resource|LDAPConnection $con
+ * @param resource|Result $result
*/
private function controlPagedResultResponse($con, $result, string $cookie = ''): string
{
@@ -257,9 +259,9 @@ private function controlPagedResultResponse($con, $result, string $cookie = ''):
/**
* Calls actual LDAP search function with the prepared options and parameters.
*
- * @param resource $con
+ * @param resource|LDAPConnection $con
*
- * @return resource
+ * @return resource|Result
*/
private function callSearchFunction($con, string $func, int $sizeLimit)
{
diff --git a/src/Symfony/Component/Ldap/Security/LdapAuthenticator.php b/src/Symfony/Component/Ldap/Security/LdapAuthenticator.php
index 30928f62278cd..2bc3f5925b389 100644
--- a/src/Symfony/Component/Ldap/Security/LdapAuthenticator.php
+++ b/src/Symfony/Component/Ldap/Security/LdapAuthenticator.php
@@ -16,7 +16,10 @@
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\AuthenticatorInterface;
+use Symfony\Component\Security\Http\Authenticator\InteractiveAuthenticatorInterface;
use Symfony\Component\Security\Http\Authenticator\Passport\PassportInterface;
+use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
+use Symfony\Component\Security\Http\EntryPoint\Exception\NotAnEntryPointException;
/**
* This class decorates internal authenticators to add the LDAP integration.
@@ -29,7 +32,7 @@
*
* @final
*/
-class LdapAuthenticator implements AuthenticatorInterface
+class LdapAuthenticator implements AuthenticationEntryPointInterface, InteractiveAuthenticatorInterface
{
private $authenticator;
private $ldapServiceId;
@@ -75,4 +78,22 @@ public function onAuthenticationFailure(Request $request, AuthenticationExceptio
{
return $this->authenticator->onAuthenticationFailure($request, $exception);
}
+
+ public function start(Request $request, AuthenticationException $authException = null): Response
+ {
+ if (!$this->authenticator instanceof AuthenticationEntryPointInterface) {
+ throw new NotAnEntryPointException(sprintf('Decorated authenticator "%s" does not implement interface "%s".', get_debug_type($this->authenticator), AuthenticationEntryPointInterface::class));
+ }
+
+ return $this->authenticator->start($request, $authException);
+ }
+
+ public function isInteractive(): bool
+ {
+ if ($this->authenticator instanceof InteractiveAuthenticatorInterface) {
+ return $this->authenticator->isInteractive();
+ }
+
+ return false;
+ }
}
diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php
index 13be9a333289e..3176c923f10f3 100644
--- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php
+++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php
@@ -140,7 +140,11 @@ private function getDBALConnectionMock()
$schemaConfig->method('getMaxIdentifierLength')->willReturn(63);
$schemaConfig->method('getDefaultTableOptions')->willReturn([]);
$schemaManager->method('createSchemaConfig')->willReturn($schemaConfig);
- $driverConnection->method('getSchemaManager')->willReturn($schemaManager);
+ if (method_exists(DBALConnection::class, 'createSchemaManager')) {
+ $driverConnection->method('createSchemaManager')->willReturn($schemaManager);
+ } else {
+ $driverConnection->method('getSchemaManager')->willReturn($schemaManager);
+ }
return $driverConnection;
}
@@ -430,7 +434,11 @@ public function testSetupIndices(string $platformClass, array $expectedIndices)
$expectedTable->addIndex($indexColumns);
}
$schemaManager->method('createSchema')->willReturn($schema);
- $driverConnection->method('getSchemaManager')->willReturn($schemaManager);
+ if (method_exists(DBALConnection::class, 'createSchemaManager')) {
+ $driverConnection->method('createSchemaManager')->willReturn($schemaManager);
+ } else {
+ $driverConnection->method('getSchemaManager')->willReturn($schemaManager);
+ }
$platformMock = $this->createMock($platformClass);
$platformMock
diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineIntegrationTest.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineIntegrationTest.php
index e99bf76f7733b..2c3556fbd3d30 100644
--- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineIntegrationTest.php
+++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineIntegrationTest.php
@@ -14,6 +14,7 @@
use Doctrine\DBAL\Driver\Result as DriverResult;
use Doctrine\DBAL\DriverManager;
use Doctrine\DBAL\Result;
+use Doctrine\DBAL\Schema\AbstractSchemaManager;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Messenger\Bridge\Doctrine\Tests\Fixtures\DummyMessage;
use Symfony\Component\Messenger\Bridge\Doctrine\Transport\Connection;
@@ -175,7 +176,7 @@ public function testItRetrieveTheMessageThatIsOlderThanRedeliverTimeout()
public function testTheTransportIsSetupOnGet()
{
- $this->assertFalse($this->driverConnection->getSchemaManager()->tablesExist('messenger_messages'));
+ $this->assertFalse($this->createSchemaManager()->tablesExist('messenger_messages'));
$this->assertNull($this->connection->get());
$this->connection->send('the body', ['my' => 'header']);
@@ -187,4 +188,11 @@ private function formatDateTime(\DateTime $dateTime)
{
return $dateTime->format($this->driverConnection->getDatabasePlatform()->getDateTimeFormatString());
}
+
+ private function createSchemaManager(): AbstractSchemaManager
+ {
+ return method_exists($this->driverConnection, 'createSchemaManager')
+ ? $this->driverConnection->createSchemaManager()
+ : $this->driverConnection->getSchemaManager();
+ }
}
diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php
index 43974a53e1f06..b09b289c6b403 100644
--- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php
+++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php
@@ -20,6 +20,7 @@
use Doctrine\DBAL\Platforms\MySqlPlatform;
use Doctrine\DBAL\Query\QueryBuilder;
use Doctrine\DBAL\Result;
+use Doctrine\DBAL\Schema\AbstractSchemaManager;
use Doctrine\DBAL\Schema\Comparator;
use Doctrine\DBAL\Schema\Schema;
use Doctrine\DBAL\Schema\Synchronizer\SchemaSynchronizer;
@@ -386,7 +387,7 @@ protected function executeStatement(string $sql, array $parameters = [], array $
private function getSchema(): Schema
{
- $schema = new Schema([], [], $this->driverConnection->getSchemaManager()->createSchemaConfig());
+ $schema = new Schema([], [], $this->createSchemaManager()->createSchemaConfig());
$this->addTableToSchema($schema);
return $schema;
@@ -437,7 +438,7 @@ private function updateSchema(): void
}
$comparator = new Comparator();
- $schemaDiff = $comparator->compare($this->driverConnection->getSchemaManager()->createSchema(), $this->getSchema());
+ $schemaDiff = $comparator->compare($this->createSchemaManager()->createSchema(), $this->getSchema());
foreach ($schemaDiff->toSaveSql($this->driverConnection->getDatabasePlatform()) as $sql) {
if (method_exists($this->driverConnection, 'executeStatement')) {
@@ -447,6 +448,13 @@ private function updateSchema(): void
}
}
}
+
+ private function createSchemaManager(): AbstractSchemaManager
+ {
+ return method_exists($this->driverConnection, 'createSchemaManager')
+ ? $this->driverConnection->createSchemaManager()
+ : $this->driverConnection->getSchemaManager();
+ }
}
if (!class_exists(\Symfony\Component\Messenger\Transport\Doctrine\Connection::class, false)) {
diff --git a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/ConnectionTest.php b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/ConnectionTest.php
index 9223d5a833135..1754c83da008c 100644
--- a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/ConnectionTest.php
+++ b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/ConnectionTest.php
@@ -78,7 +78,7 @@ public function testFromDsnWithTls()
$redis->expects($this->once())
->method('connect')
->with('tls://127.0.0.1', 6379)
- ->willReturn(null);
+ ->willReturn(true);
Connection::fromDsn('redis://127.0.0.1?tls=1', [], $redis);
}
@@ -92,7 +92,7 @@ public function testFromDsnWithTlsOption()
$redis->expects($this->once())
->method('connect')
->with('tls://127.0.0.1', 6379)
- ->willReturn(null);
+ ->willReturn(true);
Connection::fromDsn('redis://127.0.0.1', ['tls' => true], $redis);
}
@@ -103,7 +103,7 @@ public function testFromDsnWithRedissScheme()
$redis->expects($this->once())
->method('connect')
->with('tls://127.0.0.1', 6379)
- ->willReturn(null);
+ ->willReturn(true);
Connection::fromDsn('rediss://127.0.0.1', [], $redis);
}
@@ -163,15 +163,26 @@ public function testKeepGettingPendingMessages()
$this->assertNotNull($connection->get());
}
- public function testAuth()
+ /**
+ * @param string|array $expected
+ *
+ * @dataProvider provideAuthDsn
+ */
+ public function testAuth($expected, string $dsn)
{
$redis = $this->createMock(\Redis::class);
$redis->expects($this->exactly(1))->method('auth')
- ->with('password')
+ ->with($expected)
->willReturn(true);
- Connection::fromDsn('redis://password@localhost/queue', [], $redis);
+ Connection::fromDsn($dsn, [], $redis);
+ }
+
+ public function provideAuthDsn(): \Generator
+ {
+ yield 'Password only' => ['password', 'redis://password@localhost/queue'];
+ yield 'User and password' => [['user', 'password'], 'redis://user:password@localhost/queue'];
}
public function testAuthFromOptions()
@@ -315,7 +326,7 @@ public function testMaxEntries()
$redis->expects($this->exactly(1))->method('xadd')
->with('queue', '*', ['message' => '{"body":"1","headers":[]}'], 20000, true)
- ->willReturn(1);
+ ->willReturn('1');
$connection = Connection::fromDsn('redis://localhost/queue?stream_max_entries=20000', [], $redis); // 1 = always
$connection->add('1', []);
@@ -355,7 +366,7 @@ public function testLastErrorGetsCleared()
{
$redis = $this->createMock(\Redis::class);
- $redis->expects($this->once())->method('xadd')->willReturn(0);
+ $redis->expects($this->once())->method('xadd')->willReturn('0');
$redis->expects($this->once())->method('xack')->willReturn(0);
$redis->method('getLastError')->willReturnOnConsecutiveCalls('xadd error', 'xack error');
diff --git a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisTransportFactoryTest.php b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisTransportFactoryTest.php
index 728fe67c78bc3..754e5ae07d6c7 100644
--- a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisTransportFactoryTest.php
+++ b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisTransportFactoryTest.php
@@ -27,6 +27,7 @@ public function testSupportsOnlyRedisTransports()
$factory = new RedisTransportFactory();
$this->assertTrue($factory->supports('redis://localhost', []));
+ $this->assertTrue($factory->supports('rediss://localhost', []));
$this->assertFalse($factory->supports('sqs://localhost', []));
$this->assertFalse($factory->supports('invalid-dsn', []));
}
diff --git a/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php
index 4515660c93784..7ffd04caa97f5 100644
--- a/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php
+++ b/src/Symfony/Component/Messenger/Bridge/Redis/Transport/Connection.php
@@ -111,7 +111,10 @@ public function __construct(array $configuration, array $connectionCredentials =
$this->claimInterval = $configuration['claim_interval'] ?? self::DEFAULT_OPTIONS['claim_interval'];
}
- private static function initializeRedis(\Redis $redis, string $host, int $port, ?string $auth, int $serializer, int $dbIndex): \Redis
+ /**
+ * @param string|string[]|null $auth
+ */
+ private static function initializeRedis(\Redis $redis, string $host, int $port, $auth, int $serializer, int $dbIndex): \Redis
{
$redis->connect($host, $port);
$redis->setOption(\Redis::OPT_SERIALIZER, $serializer);
@@ -127,7 +130,10 @@ private static function initializeRedis(\Redis $redis, string $host, int $port,
return $redis;
}
- private static function initializeRedisCluster(?\RedisCluster $redis, array $hosts, ?string $auth, int $serializer): \RedisCluster
+ /**
+ * @param string|string[]|null $auth
+ */
+ private static function initializeRedisCluster(?\RedisCluster $redis, array $hosts, $auth, int $serializer): \RedisCluster
{
if (null === $redis) {
$redis = new \RedisCluster(null, $hosts, 0.0, 0.0, false, $auth);
@@ -233,7 +239,8 @@ public static function fromDsn(string $dsn, array $redisOptions = [], $redis = n
$connectionCredentials = [
'host' => $parsedUrl['host'] ?? '127.0.0.1',
'port' => $parsedUrl['port'] ?? 6379,
- 'auth' => $redisOptions['auth'] ?? $parsedUrl['pass'] ?? $parsedUrl['user'] ?? null,
+ // See: https://github.com/phpredis/phpredis/#auth
+ 'auth' => $redisOptions['auth'] ?? (isset($parsedUrl['pass']) && isset($parsedUrl['user']) ? [$parsedUrl['user'], $parsedUrl['pass']] : $parsedUrl['pass'] ?? $parsedUrl['user'] ?? null),
];
$pathParts = explode('/', rtrim($parsedUrl['path'] ?? '', '/'));
diff --git a/src/Symfony/Component/Messenger/Bridge/Redis/Transport/RedisTransportFactory.php b/src/Symfony/Component/Messenger/Bridge/Redis/Transport/RedisTransportFactory.php
index 55deeb09e7fa8..88cead8a934f4 100644
--- a/src/Symfony/Component/Messenger/Bridge/Redis/Transport/RedisTransportFactory.php
+++ b/src/Symfony/Component/Messenger/Bridge/Redis/Transport/RedisTransportFactory.php
@@ -30,7 +30,7 @@ public function createTransport(string $dsn, array $options, SerializerInterface
public function supports(string $dsn, array $options): bool
{
- return 0 === strpos($dsn, 'redis://');
+ return 0 === strpos($dsn, 'redis://') || 0 === strpos($dsn, 'rediss://');
}
}
diff --git a/src/Symfony/Component/Mime/RawMessage.php b/src/Symfony/Component/Mime/RawMessage.php
index 66788d8ad526d..d2a311daebecf 100644
--- a/src/Symfony/Component/Mime/RawMessage.php
+++ b/src/Symfony/Component/Mime/RawMessage.php
@@ -33,8 +33,11 @@ public function toString(): string
if (\is_string($this->message)) {
return $this->message;
}
+ if ($this->message instanceof \Traversable) {
+ $this->message = iterator_to_array($this->message, false);
+ }
- return $this->message = implode('', iterator_to_array($this->message, false));
+ return $this->message = implode('', $this->message);
}
public function toIterable(): iterable
diff --git a/src/Symfony/Component/Mime/Tests/RawMessageTest.php b/src/Symfony/Component/Mime/Tests/RawMessageTest.php
index 26e7605baba2d..41503451bb1da 100644
--- a/src/Symfony/Component/Mime/Tests/RawMessageTest.php
+++ b/src/Symfony/Component/Mime/Tests/RawMessageTest.php
@@ -16,16 +16,12 @@
class RawMessageTest extends TestCase
{
- public function testToString()
+ /**
+ * @dataProvider provideMessages
+ */
+ public function testToString($messageParameter)
{
- $message = new RawMessage('string');
- $this->assertEquals('string', $message->toString());
- $this->assertEquals('string', implode('', iterator_to_array($message->toIterable())));
- // calling methods more than once work
- $this->assertEquals('string', $message->toString());
- $this->assertEquals('string', implode('', iterator_to_array($message->toIterable())));
-
- $message = new RawMessage(new \ArrayObject(['some', ' ', 'string']));
+ $message = new RawMessage($messageParameter);
$this->assertEquals('some string', $message->toString());
$this->assertEquals('some string', implode('', iterator_to_array($message->toIterable())));
// calling methods more than once work
@@ -33,6 +29,15 @@ public function testToString()
$this->assertEquals('some string', implode('', iterator_to_array($message->toIterable())));
}
+ public function provideMessages(): array
+ {
+ return [
+ 'string' => ['some string'],
+ 'traversable' => [new \ArrayObject(['some', ' ', 'string'])],
+ 'array' => [['some', ' ', 'string']],
+ ];
+ }
+
public function testSerialization()
{
$message = new RawMessage('string');
diff --git a/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php b/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php
index 2ad0848bf2049..526ad5eb6ac85 100644
--- a/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php
+++ b/src/Symfony/Component/Notifier/Bridge/Firebase/FirebaseTransport.php
@@ -96,7 +96,7 @@ protected function doSend(MessageInterface $message): SentMessage
$success = $response->toArray(false);
$sentMessage = new SentMessage($message, (string) $this);
- $sentMessage->setMessageId($success['results'][0]['message_id']);
+ $sentMessage->setMessageId($success['results'][0]['message_id'] ?? '');
return $sentMessage;
}
diff --git a/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatOptions.php b/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatOptions.php
index 77372cd5102c6..bc7c492fd684c 100644
--- a/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatOptions.php
+++ b/src/Symfony/Component/Notifier/Bridge/GoogleChat/GoogleChatOptions.php
@@ -11,7 +11,6 @@
namespace Symfony\Component\Notifier\Bridge\GoogleChat;
-use Symfony\Component\Notifier\Bridge\GoogleChat\Component\Card;
use Symfony\Component\Notifier\Message\ChatMessage;
use Symfony\Component\Notifier\Message\MessageOptionsInterface;
use Symfony\Component\Notifier\Notification\Notification;
diff --git a/src/Symfony/Component/PasswordHasher/README.md b/src/Symfony/Component/PasswordHasher/README.md
index 0bddd95d61e80..0878746fca38c 100644
--- a/src/Symfony/Component/PasswordHasher/README.md
+++ b/src/Symfony/Component/PasswordHasher/README.md
@@ -33,7 +33,7 @@ $passwordHasher->verify($hash, 'plain'); // returns true (valid)
Resources
---------
- * [Documentation](https://symfony.com/doc/current/password-hasher.html)
+ * [Documentation](https://symfony.com/doc/current/security.html#c-hashing-passwords)
* [Contributing](https://symfony.com/doc/current/contributing/index.html)
* [Report issues](https://github.com/symfony/symfony/issues) and
[send Pull Requests](https://github.com/symfony/symfony/pulls)
diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php
index 5ece2c17e87bb..583bd886911fe 100644
--- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php
+++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php
@@ -313,10 +313,8 @@ public function isWritable($objectOrArray, $propertyPath)
if (!$zval[self::VALUE] instanceof \ArrayAccess && !\is_array($zval[self::VALUE])) {
return false;
}
- } else {
- if (!$this->isPropertyWritable($zval[self::VALUE], $propertyPath->getElement($i))) {
- return false;
- }
+ } elseif (!\is_object($zval[self::VALUE]) || !$this->isPropertyWritable($zval[self::VALUE], $propertyPath->getElement($i))) {
+ return false;
}
if (\is_object($zval[self::VALUE])) {
@@ -663,10 +661,6 @@ private function getWriteInfo(string $class, string $property, $value): Property
*/
private function isPropertyWritable(object $object, string $property): bool
{
- if (!\is_object($object)) {
- return false;
- }
-
$mutatorForArray = $this->getWriteInfo(\get_class($object), $property, []);
if (PropertyWriteInfo::TYPE_NONE !== $mutatorForArray->getType() || ($object instanceof \stdClass && property_exists($object, $property))) {
diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorArrayAccessTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorArrayAccessTest.php
index 71e71a7838600..98d6eb57d5936 100644
--- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorArrayAccessTest.php
+++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorArrayAccessTest.php
@@ -38,6 +38,14 @@ public function getValidPropertyPaths()
];
}
+ public function getInvalidPropertyPaths()
+ {
+ return [
+ [$this->getContainer(['firstName' => 'Bernhard']), 'firstName', 'Bernhard'],
+ [$this->getContainer(['person' => $this->getContainer(['firstName' => 'Bernhard'])]), 'person.firstName', 'Bernhard'],
+ ];
+ }
+
/**
* @dataProvider getValidPropertyPaths
*/
@@ -83,4 +91,12 @@ public function testIsWritable($collection, $path)
{
$this->assertTrue($this->propertyAccessor->isWritable($collection, $path));
}
+
+ /**
+ * @dataProvider getInvalidPropertyPaths
+ */
+ public function testIsNotWritable($collection, $path)
+ {
+ $this->assertFalse($this->propertyAccessor->isWritable($collection, $path));
+ }
}
diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php
index 041502d18fe34..971e47c1ab256 100644
--- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php
+++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php
@@ -552,8 +552,8 @@ private function extractFromReflectionType(\ReflectionType $reflectionType, \Ref
$types = [];
$nullable = $reflectionType->allowsNull();
- foreach ($reflectionType instanceof \ReflectionUnionType ? $reflectionType->getTypes() : [$reflectionType] as $type) {
- $phpTypeOrClass = $reflectionType instanceof \ReflectionNamedType ? $reflectionType->getName() : (string) $type;
+ foreach (($reflectionType instanceof \ReflectionUnionType || $reflectionType instanceof \ReflectionIntersectionType) ? $reflectionType->getTypes() : [$reflectionType] as $type) {
+ $phpTypeOrClass = $type->getName();
if ('null' === $phpTypeOrClass || 'mixed' === $phpTypeOrClass || 'never' === $phpTypeOrClass) {
continue;
}
diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php
index 253b9032ba2cb..8ad3315834a8d 100644
--- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php
+++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php
@@ -280,11 +280,20 @@ public function php80TypesProvider()
}
/**
+ * @dataProvider php81TypesProvider
* @requires PHP 8.1
*/
- public function testExtractPhp81Type()
+ public function testExtractPhp81Type($property, array $type = null)
{
- $this->assertNull($this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php81Dummy', 'nothing', []));
+ $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php81Dummy', $property, []));
+ }
+
+ public function php81TypesProvider()
+ {
+ return [
+ ['nothing', null],
+ ['collection', [new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Traversable'), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'Countable')]],
+ ];
}
/**
diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php81Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php81Dummy.php
index b4e896a434524..1300c3e695f1f 100644
--- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php81Dummy.php
+++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php81Dummy.php
@@ -8,4 +8,8 @@ public function getNothing(): never
{
throw new \Exception('Oops');
}
+
+ public function getCollection(): \Traversable&\Countable
+ {
+ }
}
diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.ca.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.ca.xlf
index 5a8d0c7d84880..212ca70c922e3 100644
--- a/src/Symfony/Component/Security/Core/Resources/translations/security.ca.xlf
+++ b/src/Symfony/Component/Security/Core/Resources/translations/security.ca.xlf
@@ -70,6 +70,14 @@
Invalid or expired login link.Enllaç d'inici de sessió no vàlid o caducat.
+
+ Too many failed login attempts, please try again in %minutes% minute.
+ Massa intents d'inici de sessió fallits, torneu-ho a provar en %minutes% minut.
+
+
+ Too many failed login attempts, please try again in %minutes% minutes.
+ Massa intents d'inici de sessió fallits, torneu-ho a provar en %minutes% minuts.
+