Merge branch '4.4' into 5.0

* 4.4: (30 commits)
  [Security] Check UserInterface::getPassword is not null before calling needsRehash
  gracefully handle missing event dispatchers
  Fix TokenStorage::reset not called in stateless firewall
  [DotEnv] Remove `usePutEnv` property default value
  [HttpFoundation] get currently session.gc_maxlifetime if ttl doesnt exists
  Set up typo fix
  [DependencyInjection] Handle env var placeholders in CheckTypeDeclarationsPass
  [Cache] fix memory leak when using PhpArrayAdapter
  [Validator] Allow underscore character "_" in URL username and password
  [TwigBridge] Update bootstrap_4_layout.html.twig
  [FrameworkBundle][SodiumVault] Create secrets directory only when needed
  fix parsing negative octal numbers
  [SecurityBundle] Passwords are not encoded when algorithm set to \"true\"
  [DependencyInjection] Resolve expressions in CheckTypeDeclarationsPass
  [SecurityBundle] Properly escape regex in AddSessionDomainConstraintPass
  do not validate passwords when the hash is null
  [DI] fix resolving bindings for named TypedReference
  [Config] never try loading failed classes twice with ClassExistenceResource
  [Mailer] Fix SMTP Authentication when using STARTTLS
  [DI] Fix making the container path-independent when the app is in /app
  ...
This commit is contained in:
Nicolas Grekas 2019-12-07 17:40:37 +01:00
commit 1d1e29c8cd
38 changed files with 552 additions and 92 deletions

View File

@ -7,6 +7,46 @@ in 4.3 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.3.0...v4.3.1
* 4.3.9 (2019-12-01)
* bug #34649 more robust initialization from request (dbu)
* bug #34671 [Security] Fix clearing remember-me cookie after deauthentication (chalasr)
* bug #34711 Fix the translation commands when a template contains a syntax error (fabpot)
* bug #34560 [Config][ReflectionClassResource] Handle parameters with undefined constant as their default values (fancyweb)
* bug #34695 [Config] don't break on virtual stack frames in ClassExistenceResource (nicolas-grekas)
* bug #34716 [DependencyInjection] fix dumping number-like string parameters (xabbuh)
* bug #34558 [Console] Fix autocomplete multibyte input support (fancyweb)
* bug #34130 [Console] Fix commands description with numeric namespaces (fancyweb)
* bug #34677 [EventDispatcher] Better error reporting when arguments to dispatch() are swapped (rimas-kudelis)
* bug #33573 [TwigBridge] Add row_attr to all form themes (fancyweb)
* bug #34019 [Serializer] CsvEncoder::NO_HEADERS_KEY ignored when used in constructor (Dario Savella)
* bug #34083 [Form] Keep preferred_choices order for choice groups (vilius-g)
* bug #34091 [Debug] work around failing chdir() on Darwin (mary2501)
* bug #34305 [PhpUnitBridge] Read configuration CLI directive (ro0NL)
* bug #34490 [Serializer] Fix MetadataAwareNameConverter usage with string group (antograssiot)
* bug #34632 [Console] Fix trying to access array offset on value of type int (Tavafi)
* bug #34669 [HttpClient] turn exception into log when the request has no content-type (nicolas-grekas)
* bug #34636 [VarDumper] notice on potential undefined index (sylvainmetayer)
* bug #34668 [Cache] Make sure we get the correct number of values from redis::mget() (thePanz)
* bug #34569 [Workflow] Apply the same logic of precedence between the apply() and the buildTransitionBlockerList() method (lyrixx)
* bug #34533 [Monolog Bridge] Fixed accessing static property as non static. (Sander-Toonen)
* bug #34546 [Serializer] Add DateTimeZoneNormalizer into Dependency Injection (jewome62)
* bug #34547 [Messenger] Error when specified default bus is not among the configured (vudaltsov)
* bug #34551 [Security] SwitchUser is broken when the User Provider always returns a valid user (tucksaun)
* bug #34385 Avoid empty "If-Modified-Since" header in validation request (mpdude)
* bug #34458 [Validator] ConstraintValidatorTestCase: add missing return value to mocked validate method calls (ogizanagi)
* bug #34451 [DependencyInjection] Fix dumping multiple deprecated aliases (shyim)
* bug #34448 [Form] allow button names to start with uppercase letter (xabbuh)
* bug #34419 [Cache] Disable igbinary on PHP >= 7.4 (nicolas-grekas)
* bug #34366 [HttpFoundation] Allow redirecting to URLs that contain a semicolon (JayBizzle)
* bug #34397 [FrameworkBundle] Remove project dir from Translator cache vary scanned directories (fancyweb)
* bug #34408 [Cache] catch exceptions when using PDO directly (xabbuh)
* bug #34410 [HttpFoundation] Fix MySQL column type definition. (jbroutier)
* bug #34398 [Config] fix id-generation for GlobResource (nicolas-grekas)
* bug #34396 [Finder] Allow ssh2 stream wrapper for sftp (damienalexandre)
* bug #34383 [DI] Use reproducible entropy to generate env placeholders (nicolas-grekas)
* bug #34381 [WebProfilerBundle] Require symfony/twig-bundle (fancyweb)
* 4.3.8 (2019-11-13)
* bug #34344 [Console] Constant STDOUT might be undefined (nicolas-grekas)

View File

@ -19,8 +19,8 @@ Symfony is the result of the work of many people who made the code better
- Jakub Zalas (jakubzalas)
- Javier Eguiluz (javier.eguiluz)
- Roland Franssen (ro0)
- Johannes S (johannes)
- Grégoire Pineau (lyrixx)
- Johannes S (johannes)
- Kris Wallsmith (kriswallsmith)
- Yonel Ceruto (yonelceruto)
- Hugo Hamon (hhamon)
@ -36,13 +36,13 @@ Symfony is the result of the work of many people who made the code better
- Martin Hasoň (hason)
- Hamza Amrouche (simperfit)
- Jeremy Mikola (jmikola)
- Jean-François Simon (jfsimon)
- Jules Pietri (heah)
- Jean-François Simon (jfsimon)
- Benjamin Eberlei (beberlei)
- Igor Wiedler (igorw)
- Jérémy DERUSSÉ (jderusse)
- Eriksen Costa (eriksencosta)
- Thomas Calvet (fancyweb)
- Eriksen Costa (eriksencosta)
- Guilhem Niot (energetick)
- Sarah Khalil (saro0h)
- Tobias Nyholm (tobias)
@ -57,15 +57,15 @@ Symfony is the result of the work of many people who made the code better
- Francis Besset (francisbesset)
- stealth35 (stealth35)
- Alexander Mols (asm89)
- Konstantin Myakshin (koc)
- Matthias Pigulla (mpdude)
- Konstantin Myakshin (koc)
- Bulat Shakirzyanov (avalanche123)
- Valentin Udaltsov (vudaltsov)
- Grégoire Paris (greg0ire)
- Saša Stamenković (umpirsky)
- Peter Rehm (rpet)
- Kevin Bond (kbond)
- Henrik Bjørnskov (henrikbjorn)
- Valentin Udaltsov (vudaltsov)
- Miha Vrhovnik
- Diego Saint Esteben (dii3g0)
- Gábor Egyed (1ed)
@ -91,11 +91,11 @@ Symfony is the result of the work of many people who made the code better
- Henrik Westphal (snc)
- Dariusz Górecki (canni)
- David Buchmann (dbu)
- Graham Campbell (graham)
- Dariusz Ruminski
- Lee McDermott
- Brandon Turner
- Luis Cordova (cordoval)
- Graham Campbell (graham)
- Daniel Holmes (dholmes)
- Toni Uebernickel (havvg)
- Bart van den Burg (burgov)
@ -109,20 +109,21 @@ Symfony is the result of the work of many people who made the code better
- Maxime STEINHAUSSER
- Michal Piotrowski (eventhorizon)
- Tim Nagel (merk)
- Baptiste Clavié (talus)
- Chris Wilkinson (thewilkybarkid)
- Brice BERNARD (brikou)
- Baptiste Clavié (talus)
- marc.weistroff
- Tomáš Votruba (tomas_votruba)
- Peter Kokot (maastermedia)
- Jérôme Vasseur (jvasseur)
- lenar
- Alexander Schwenn (xelaris)
- Włodzimierz Gajda (gajdaw)
- Sebastiaan Stok (sstok)
- Adrien Brault (adrienbrault)
- Peter Kokot (maastermedia)
- Jacob Dreesen (jdreesen)
- Florian Voutzinos (florianv)
- Teoh Han Hui (teohhanhui)
- Colin Frei
- Oskar Stark (oskarstark)
- Javier Spagnoletti (phansys)
@ -131,13 +132,12 @@ Symfony is the result of the work of many people who made the code better
- Daniel Wehner (dawehner)
- excelwebzone
- Gordon Franke (gimler)
- Teoh Han Hui (teohhanhui)
- Tugdual Saunier (tucksaun)
- Fabien Pennequin (fabienpennequin)
- Théo FIDRY (theofidry)
- Eric GELOEN (gelo)
- Joel Wurtz (brouznouf)
- Lars Strojny (lstrojny)
- Tugdual Saunier (tucksaun)
- Jannik Zschiesche (apfelbox)
- Robert Schönthal (digitalkaoz)
- Gregor Harlan (gharlan)
@ -209,6 +209,7 @@ Symfony is the result of the work of many people who made the code better
- Mario A. Alvarez Garcia (nomack84)
- Dennis Benkert (denderello)
- DQNEO
- Andre Rømcke (andrerom)
- mcfedr (mcfedr)
- Ben Davies (bendavies)
- Gary PEGEOT (gary-p)
@ -233,7 +234,6 @@ Symfony is the result of the work of many people who made the code better
- Pierre Minnieur (pminnieur)
- fivestar
- Dominique Bongiraud
- Andre Rømcke (andrerom)
- Jeremy Livingston (jeremylivingston)
- Michael Lee (zerustech)
- Matthieu Auger (matthieuauger)
@ -249,6 +249,7 @@ Symfony is the result of the work of many people who made the code better
- Michele Orselli (orso)
- Sven Paulus (subsven)
- Maxime Veber (nek-)
- Anthony GRASSIOT (antograssiot)
- Rui Marinho (ruimarinho)
- Eugene Wissner
- Pascal Montoya
@ -257,8 +258,10 @@ Symfony is the result of the work of many people who made the code better
- Tristan Darricau (nicofuma)
- Victor Bocharsky (bocharsky_bw)
- Marcel Beerta (mazen)
- Maxime Helias (maxhelias)
- Pavel Batanov (scaytrase)
- Mantis Development
- David Prévot
- Loïc Faugeron
- Hidde Wieringa (hiddewie)
- dFayet
@ -285,7 +288,6 @@ Symfony is the result of the work of many people who made the code better
- Xavier Montaña Carreras (xmontana)
- Rémon van de Kamp (rpkamp)
- Mickaël Andrieu (mickaelandrieu)
- Anthony GRASSIOT (antograssiot)
- Xavier Perez
- Arjen Brouwer (arjenjb)
- Katsuhiro OGAWA
@ -311,13 +313,12 @@ Symfony is the result of the work of many people who made the code better
- Smaine Milianni (ismail1432)
- Chekote
- François Pluchino (francoispluchino)
- Christopher Hertel (chertel)
- Antoine Makdessi (amakdessi)
- Thomas Adam
- Jhonny Lidfors (jhonne)
- Diego Agulló (aeoris)
- jdhoek
- Maxime Helias (maxhelias)
- David Prévot
- Bob den Otter (bopp)
- Thomas Schulz (king2500)
- Frank de Jonge (frenkynet)
@ -342,6 +343,7 @@ Symfony is the result of the work of many people who made the code better
- Arjen van der Meijden
- Mathieu Lechat
- Marc Weistroff (futurecat)
- Damien Alexandre (damienalexandre)
- Simon Mönch (sm)
- Christian Schmidt
- Patrick Landolt (scube)
@ -349,6 +351,7 @@ Symfony is the result of the work of many people who made the code better
- David Badura (davidbadura)
- Chad Sikorra (chadsikorra)
- Chris Smith (cs278)
- Thomas Bisignani (toma)
- Florian Klein (docteurklein)
- Manuel Kiessling (manuelkiessling)
- Atsuhiro KUBO (iteman)
@ -407,18 +410,17 @@ Symfony is the result of the work of many people who made the code better
- Tomasz Kowalczyk (thunderer)
- Artur Eshenbrener
- Timo Bakx (timobakx)
- Damien Alexandre (damienalexandre)
- Thomas Perez (scullwm)
- Saif Eddin Gmati (azjezz)
- Felix Labrecque
- Yaroslav Kiliba
- Terje Bråten
- Tien Vo (tienvx)
- Robbert Klarenbeek (robbertkl)
- Eric Masoero (eric-masoero)
- JhonnyL
- hossein zolfi (ocean)
- Clément Gautier (clementgautier)
- Thomas Bisignani (toma)
- Dāvis Zālītis (k0d3r1s)
- Sanpi
- Eduardo Gulias (egulias)
@ -429,6 +431,7 @@ Symfony is the result of the work of many people who made the code better
- Grzegorz (Greg) Zdanowski (kiler129)
- Iker Ibarguren (ikerib)
- Kirill chEbba Chebunin (chebba)
- Rokas Mikalkėnas (rokasm)
- Greg Thornton (xdissent)
- Martin Hujer (martinhujer)
- Alex Bowers
@ -443,7 +446,6 @@ Symfony is the result of the work of many people who made the code better
- Michele Locati
- Pavel Volokitin (pvolok)
- Valentine Boineau (valentineboineau)
- Christopher Hertel (chertel)
- Arthur de Moulins (4rthem)
- Matthias Althaus (althaus)
- Nicolas Dewez (nicolas_dewez)
@ -476,6 +478,7 @@ Symfony is the result of the work of many people who made the code better
- Oscar Cubo Medina (ocubom)
- Karel Souffriau
- Christophe L. (christophelau)
- Sander Toonen (xatoo)
- Anthon Pang (robocoder)
- Michael Käfer (michael_kaefer)
- Sébastien Santoro (dereckson)
@ -502,6 +505,7 @@ Symfony is the result of the work of many people who made the code better
- Olivier Dolbeau (odolbeau)
- Jan Rosier (rosier)
- Alessandro Lai (jean85)
- Desjardins Jérôme (jewome62)
- Arturs Vonda
- Josip Kruslin
- Matthew Smeets
@ -529,7 +533,6 @@ Symfony is the result of the work of many people who made the code better
- Gonzalo Vilaseca (gonzalovilaseca)
- Tarmo Leppänen (tarlepp)
- Marcin Sikoń (marphi)
- Tien Vo (tienvx)
- Denis Brumann (dbrumann)
- Dominik Zogg (dominik.zogg)
- Marek Pietrzak
@ -540,6 +543,7 @@ Symfony is the result of the work of many people who made the code better
- Gintautas Miselis
- Rob Bast
- Roberto Espinoza (respinoza)
- Emanuele Panzeri (thepanz)
- Soufian EZ-ZANTAR (soezz)
- Zander Baldwin
- Gocha Ossinkine (ossinkine)
@ -603,7 +607,6 @@ Symfony is the result of the work of many people who made the code better
- Adam Szaraniec (mimol)
- Dariusz Ruminski
- Erik Trapman (eriktrapman)
- Rokas Mikalkėnas (rokasm)
- De Cock Xavier (xdecock)
- Almog Baku (almogbaku)
- Karoly Gossler (connorhu)
@ -648,11 +651,11 @@ Symfony is the result of the work of many people who made the code better
- Jeremy Benoist
- fritzmg
- Lenar Lõhmus
- Sander Toonen (xatoo)
- Benjamin Laugueux (yzalis)
- Zach Badgett (zachbadgett)
- Aurélien Fredouelle
- Pavel Campr (pcampr)
- Andrii Dembitskyi
- Johnny Robeson (johnny)
- Marko Kaznovac (kaznovac)
- Disquedur
@ -694,7 +697,6 @@ Symfony is the result of the work of many people who made the code better
- Sinan Eldem
- Alexandre Dupuy (satchette)
- Malte Blättermann
- Desjardins Jérôme (jewome62)
- Simeon Kolev (simeon_kolev9)
- Joost van Driel (j92)
- Jonas Elfering
@ -762,11 +764,12 @@ Symfony is the result of the work of many people who made the code better
- Giso Stallenberg (gisostallenberg)
- Michael Devery (mickadoo)
- Antoine Corcy
- Ahmed Ashraf (ahmedash95)
- Sascha Grossenbacher
- Emanuele Panzeri (thepanz)
- Szijarto Tamas
- Robin Lehrmann (robinlehrmann)
- Catalin Dan
- Soner Sayakci
- Jaroslav Kuba
- Kristijan Kanalas
- Stephan Vock
@ -825,11 +828,13 @@ Symfony is the result of the work of many people who made the code better
- Markus Fasselt (digilist)
- Julien DIDIER (juliendidier)
- Dominik Ritter (dritter)
- Dimitri Gritsajuk (ottaviano)
- Sebastian Grodzicki (sgrodzicki)
- Jeroen van den Enden (stoefke)
- Pascal Helfenstein
- Baldur Rensch (brensch)
- Pierre Rineau
- Vilius Grigaliūnas
- Vladyslav Petrovych
- Alex Xandra Albert Sim
- Carson Full
@ -946,6 +951,7 @@ Symfony is the result of the work of many people who made the code better
- Patrick Allaert
- Gustavo Falco (gfalco)
- Matt Robinson (inanimatt)
- Kristof Van Cauwenbergh (kristofvc)
- Aleksey Podskrebyshev
- Calin Mihai Pristavu
- David Marín Carreño (davefx)
@ -984,6 +990,7 @@ Symfony is the result of the work of many people who made the code better
- Thomas Landauer
- 243083df
- Thibault Duplessis
- Rimas Kudelis
- Marc Abramowitz
- Martijn Evers
- Tony Tran
@ -996,12 +1003,12 @@ Symfony is the result of the work of many people who made the code better
- Johnson Page (jwpage)
- Ruben Gonzalez (rubenruateltek)
- Michael Roterman (wtfzdotnet)
- Andrii Dembitskyi
- Arno Geurts
- Adán Lobato (adanlobato)
- Ian Jenkins (jenkoian)
- Marcos Gómez Vilches (markitosgv)
- Matthew Davis (mdavis1982)
- Markus S. (staabm)
- Maks
- Antoine LA
- den
@ -1187,7 +1194,6 @@ Symfony is the result of the work of many people who made the code better
- Sergii Smertin (nfx)
- Mikkel Paulson
- Michał Strzelecki
- Soner Sayakci
- hugofonseca (fonsecas72)
- Marc Duboc (icemad)
- Matthias Krauser (mkrauser)
@ -1241,6 +1247,7 @@ Symfony is the result of the work of many people who made the code better
- Jeremy Bush
- wizhippo
- Thomason, James
- Dario Savella
- Gordienko Vladislav
- marie
- Viacheslav Sychov
@ -1291,6 +1298,7 @@ Symfony is the result of the work of many people who made the code better
- Oxan van Leeuwen
- pkowalczyk
- Soner Sayakci
- Koen Reiniers (koenre)
- Max Voloshin (maxvoloshin)
- Nicolas Fabre (nfabre)
- Raul Rodriguez (raul782)
@ -1306,6 +1314,8 @@ Symfony is the result of the work of many people who made the code better
- Felicitus
- Krzysztof Przybyszewski
- alexpozzi
- Vladimir
- Jorge Vahldick (jvahldick)
- Frederic Godfrin
- Paul Matthews
- Jakub Kisielewski
@ -1752,7 +1762,6 @@ Symfony is the result of the work of many people who made the code better
- downace
- Aarón Nieves Fernández
- Mike Meier
- Vilius Grigaliūnas
- Kirill Saksin
- Koalabaerchen
- michalmarcinkowski
@ -1765,6 +1774,7 @@ Symfony is the result of the work of many people who made the code better
- efeen
- Nicolas Pion
- Muhammed Akbulut
- Roy-Orbison
- Aaron Somi
- Michał Dąbrowski (defrag)
- Konstantin Grachev (grachevko)
@ -1802,12 +1812,14 @@ Symfony is the result of the work of many people who made the code better
- Alexander Li (aweelex)
- Bram Van der Sype (brammm)
- Guile (guile)
- Mark Beech (jaybizzle)
- Julien Moulin (lizjulien)
- Raito Akehanareru (raito)
- Mauro Foti (skler)
- Yannick Warnier (ywarnier)
- Kevin Decherf
- Jason Woods
- Maria Grazia Patteri
- klemens
- dened
- Dmitry Korotovsky
@ -1823,6 +1835,7 @@ Symfony is the result of the work of many people who made the code better
- Sören Bernstein
- devel
- taiiiraaa
- Ali Tavafi
- Trevor Suarez
- gedrox
- Bohan Yang
@ -1959,6 +1972,7 @@ Symfony is the result of the work of many people who made the code better
- Juan M Martínez
- Gilles Gauthier
- Pavinthan
- Sylvain METAYER
- ddebree
- Kuba Werłos
- Gyula Szucs
@ -2015,6 +2029,7 @@ Symfony is the result of the work of many people who made the code better
- Marcin Szepczynski (szepczynski)
- Cyrille Jouineau (tuxosaurus)
- Vladimir Chernyshev (volch)
- Wim Godden (wimg)
- Yorkie Chadwick (yorkie76)
- GuillaumeVerdon
- Philipp Keck
@ -2026,6 +2041,7 @@ Symfony is the result of the work of many people who made the code better
- Taylan Kasap
- Michael Orlitzky
- Nicolas A. Bérard-Nault
- Quentin Favrie
- Saem Ghani
- Stefan Oderbolz
- Curtis
@ -2051,12 +2067,10 @@ Symfony is the result of the work of many people who made the code better
- Jeffrey Moelands (jeffreymoelands)
- Hugo Alliaume (kocal)
- Simon CONSTANS (kosssi)
- Kristof Van Cauwenbergh (kristofvc)
- Dennis Langen (nijusan)
- Paulius Jarmalavičius (pjarmalavicius)
- Ramon Henrique Ornelas (ramonornela)
- Ricardo de Vries (ricknox)
- Markus S. (staabm)
- Thomas Dutrion (theocrite)
- Till Klampaeckel (till)
- Tobias Weinert (tweini)
@ -2074,6 +2088,7 @@ Symfony is the result of the work of many people who made the code better
- Cas
- Dusan Kasan
- Michael Steininger
- Nardberjean
- Karolis
- Myke79
- Brian Debuire
@ -2145,7 +2160,6 @@ Symfony is the result of the work of many people who made the code better
- Daniel STANCU
- Ryan Rud
- Ondrej Slinták
- Rimas Kudelis
- vlechemin
- Brian Corrigan
- Ladislav Tánczos
@ -2263,6 +2277,7 @@ Symfony is the result of the work of many people who made the code better
- Sebastian Landwehr (dword123)
- Adel ELHAIBA (eadel)
- Damián Nohales (eagleoneraptor)
- Jordane VASPARD (elementaire)
- Elliot Anderson (elliot)
- Fabien D. (fabd)
- Carsten Eilers (fnc)
@ -2277,6 +2292,7 @@ Symfony is the result of the work of many people who made the code better
- Peter Orosz (ill_logical)
- Imangazaliev Muhammad (imangazaliev)
- j0k (j0k)
- Jeremie Broutier (jbroutier)
- joris de wit (jdewit)
- Jérémy CROMBEZ (jeremy)
- Jose Manuel Gonzalez (jgonzalez)
@ -2293,6 +2309,7 @@ Symfony is the result of the work of many people who made the code better
- samuel laulhau (lalop)
- Laurent Bachelier (laurentb)
- Luís Cobucci (lcobucci)
- Jérémy (libertjeremy)
- Mehdi Achour (machour)
- Matthieu Mota (matthieumota)
- Matthieu Moquet (mattketmo)
@ -2300,12 +2317,12 @@ Symfony is the result of the work of many people who made the code better
- Michal Čihař (mcihar)
- Matt Drollette (mdrollette)
- Adam Monsen (meonkeys)
- Hugo Monteiro (monteiro)
- Ala Eddine Khefifi (nayzo)
- emilienbouard (neime)
- Nicholas Byfleet (nickbyfleet)
- Marco Petersen (ocrampete16)
- ollie harridge (ollietb)
- Dimitri Gritsajuk (ottaviano)
- Paul Andrieux (paulandrieux)
- Paulo Ribeiro (paulo)
- Paweł Szczepanek (pauluz)
@ -2333,6 +2350,7 @@ Symfony is the result of the work of many people who made the code better
- Julien Sanchez (sumbobyboys)
- Guillermo Gisinger (t3chn0r)
- Markus Tacker (tacker)
- Thiago Cordeiro (thiagocordeiro)
- Tom Newby (tomnewbyau)
- Andrew Clark (tqt_andrew_clark)
- David Lumaye (tux1124)
@ -2341,6 +2359,7 @@ Symfony is the result of the work of many people who made the code better
- Moritz Kraft (userfriendly)
- Víctor Mateo (victormateo)
- Vincent (vincent1870)
- Vincent MOULENE (vints24)
- David Herrmann (vworldat)
- Eugene Babushkin (warl)
- Wouter Sioen (wouter_sioen)
@ -2365,6 +2384,7 @@ Symfony is the result of the work of many people who made the code better
- damaya
- Kevin Weber
- Ben Scott
- Alexandru Năstase
- Dionysis Arvanitis
- Sergey Fedotov
- Konstantin Scheumann
@ -2378,6 +2398,7 @@ Symfony is the result of the work of many people who made the code better
- Zander Baldwin
- Philipp Scheit
- max
- Alexander Bauer (abauer)
- Ahmad Mayahi (ahmadmayahi)
- Mohamed Karnichi (amiral)
- Andrew Carter (andrewcarteruk)

21
link
View File

@ -23,11 +23,14 @@ use Symfony\Component\Filesystem\Filesystem;
* @author Kévin Dunglas <dunglas@gmail.com>
*/
$copy = false !== $k = array_search('--copy', $argv, true);
$copy && array_splice($argv, $k, 1);
$pathToProject = $argv[1] ?? getcwd();
if (!is_dir("$pathToProject/vendor/symfony")) {
echo 'Link dependencies to components to a local clone of the main symfony/symfony GitHub repository.'.PHP_EOL.PHP_EOL;
echo "Usage: $argv[0] /path/to/the/project".PHP_EOL.PHP_EOL;
echo 'Link (or copy) dependencies to components to a local clone of the main symfony/symfony GitHub repository.'.PHP_EOL.PHP_EOL;
echo "Usage: $argv[0] /path/to/the/project".PHP_EOL;
echo ' Use `--copy` to copy dependencies instead of symlink'.PHP_EOL.PHP_EOL;
echo "The directory \"$pathToProject\" does not exist or the dependencies are not installed, did you forget to run \"composer install\" in your project?".PHP_EOL;
exit(1);
}
@ -50,7 +53,7 @@ foreach ($directories as $dir) {
foreach (glob("$pathToProject/vendor/symfony/*", GLOB_ONLYDIR | GLOB_NOSORT) as $dir) {
$package = 'symfony/'.basename($dir);
if (is_link($dir)) {
if (!$copy && is_link($dir)) {
echo "\"$package\" is already a symlink, skipping.".PHP_EOL;
continue;
}
@ -59,11 +62,17 @@ foreach (glob("$pathToProject/vendor/symfony/*", GLOB_ONLYDIR | GLOB_NOSORT) as
continue;
}
$sfDir = '\\' === DIRECTORY_SEPARATOR ? $sfPackages[$package] : $filesystem->makePathRelative($sfPackages[$package], dirname(realpath($dir)));
$sfDir = ('\\' === DIRECTORY_SEPARATOR || $copy) ? $sfPackages[$package] : $filesystem->makePathRelative($sfPackages[$package], dirname(realpath($dir)));
$filesystem->remove($dir);
$filesystem->symlink($sfDir, $dir);
echo "\"$package\" has been linked to \"$sfPackages[$package]\".".PHP_EOL;
if ($copy) {
$filesystem->mirror($sfDir, $dir);
echo "\"$package\" has been copied from \"$sfPackages[$package]\".".PHP_EOL;
} else {
$filesystem->symlink($sfDir, $dir);
echo "\"$package\" has been linked to \"$sfPackages[$package]\".".PHP_EOL;
}
}
foreach (glob("$pathToProject/var/cache/*", GLOB_NOSORT) as $cacheDir) {

View File

@ -0,0 +1,110 @@
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Symfony\Bridge\Monolog\Tests\Handler;
use Monolog\Formatter\JsonFormatter;
use Monolog\Logger;
use Monolog\Processor\ProcessIdProcessor;
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\Monolog\Formatter\VarDumperFormatter;
use Symfony\Bridge\Monolog\Handler\ServerLogHandler;
use Symfony\Component\VarDumper\Cloner\Data;
/**
* Tests the ServerLogHandler.
*/
class ServerLogHandlerTest extends TestCase
{
public function testFormatter()
{
$handler = new ServerLogHandler('tcp://127.0.0.1:9999');
$this->assertInstanceOf(VarDumperFormatter::class, $handler->getFormatter());
$formatter = new JsonFormatter();
$handler->setFormatter($formatter);
$this->assertSame($formatter, $handler->getFormatter());
}
public function testIsHandling()
{
$handler = new ServerLogHandler('tcp://127.0.0.1:9999', Logger::INFO);
$this->assertFalse($handler->isHandling(['level' => Logger::DEBUG]), '->isHandling returns false when no output is set');
}
public function testGetFormatter()
{
$handler = new ServerLogHandler('tcp://127.0.0.1:9999');
$this->assertInstanceOf(VarDumperFormatter::class, $handler->getFormatter(),
'-getFormatter returns VarDumperFormatter by default'
);
}
public function testWritingAndFormatting()
{
$host = 'tcp://127.0.0.1:9999';
$handler = new ServerLogHandler($host, Logger::INFO, false);
$handler->pushProcessor(new ProcessIdProcessor());
$infoRecord = [
'message' => 'My info message',
'context' => [],
'level' => Logger::INFO,
'level_name' => Logger::getLevelName(Logger::INFO),
'channel' => 'app',
'datetime' => new \DateTime('2013-05-29 16:21:54'),
'extra' => [],
];
$socket = stream_socket_server($host, $errno, $errstr);
$this->assertIsResource($socket, sprintf('Server start failed on "%s": %s %s.', $host, $errstr, $errno));
$this->assertTrue($handler->handle($infoRecord), 'The handler finished handling the log as bubble is false.');
$sockets = [(int) $socket => $socket];
$write = [];
for ($i = 0; $i < 10; ++$i) {
$read = $sockets;
stream_select($read, $write, $write, null);
foreach ($read as $stream) {
if ($socket === $stream) {
$stream = stream_socket_accept($socket);
$sockets[(int) $stream] = $stream;
} elseif (feof($stream)) {
unset($sockets[(int) $stream]);
fclose($stream);
} else {
$message = fgets($stream);
fclose($stream);
$record = unserialize(base64_decode($message));
$this->assertIsArray($record);
$this->assertArrayHasKey('message', $record);
$this->assertEquals('My info message', $record['message']);
$this->assertArrayHasKey('extra', $record);
$this->assertInstanceOf(Data::class, $record['extra']);
$extra = $record['extra']->getValue(true);
$this->assertIsArray($extra);
$this->assertArrayHasKey('process_id', $extra);
$this->assertSame(getmypid(), $extra['process_id']);
return;
}
}
usleep(100000);
}
$this->fail('Fail to read message from server');
}
}

View File

@ -242,7 +242,7 @@
{% block checkbox_radio_label -%}
{#- Do not display the label if widget is not defined in order to prevent double label rendering -#}
{%- if widget is defined -%}
{% set is_parent_custom = parent_label_class is defined and ('checkbox-custom' in parent_label_class or 'radio-custom' in parent_label_class) %}
{% set is_parent_custom = parent_label_class is defined and ('checkbox-custom' in parent_label_class or 'radio-custom' in parent_label_class or 'switch-custom' in parent_label_class) %}
{% set is_custom = label_attr.class is defined and ('checkbox-custom' in label_attr.class or 'radio-custom' in label_attr.class or 'switch-custom' in label_attr.class) %}
{%- if is_parent_custom or is_custom -%}
{%- set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' custom-control-label')|trim}) -%}

View File

@ -21,6 +21,7 @@ use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
@ -228,6 +229,8 @@ EOF
$container->compile();
} else {
(new XmlFileLoader($container = new ContainerBuilder(), new FileLocator()))->load($kernel->getContainer()->getParameter('debug.container.dump'));
$locatorPass = new ServiceLocatorTagPass();
$locatorPass->process($container);
}
return $this->containerBuilder = $container;

View File

@ -25,6 +25,7 @@ class SodiumVault extends AbstractVault implements EnvVarLoaderInterface
private $encryptionKey;
private $decryptionKey;
private $pathPrefix;
private $secretsDir;
/**
* @param string|object|null $decryptionKey A string or a stringable object that defines the private key to use to decrypt the vault
@ -36,12 +37,9 @@ class SodiumVault extends AbstractVault implements EnvVarLoaderInterface
throw new \TypeError(sprintf('Decryption key should be a string or an object that implements the __toString() method, %s given.', \gettype($decryptionKey)));
}
if (!is_dir($secretsDir) && !@mkdir($secretsDir, 0777, true) && !is_dir($secretsDir)) {
throw new \RuntimeException(sprintf('Unable to create the secrets directory (%s)', $secretsDir));
}
$this->pathPrefix = rtrim(strtr($secretsDir, '/', \DIRECTORY_SEPARATOR), \DIRECTORY_SEPARATOR).\DIRECTORY_SEPARATOR.basename($secretsDir).'.';
$this->decryptionKey = $decryptionKey;
$this->secretsDir = $secretsDir;
}
public function generateKeys(bool $override = false): bool
@ -203,9 +201,20 @@ class SodiumVault extends AbstractVault implements EnvVarLoaderInterface
$data = str_replace('%', '\x', rawurlencode($data));
$data = sprintf("<?php // %s on %s\n\nreturn \"%s\";\n", $name, date('r'), $data);
$this->createSecretsDir();
if (false === file_put_contents($this->pathPrefix.$file.'.php', $data, LOCK_EX)) {
$e = error_get_last();
throw new \ErrorException($e['message'] ?? 'Failed to write secrets data.', 0, $e['type'] ?? E_USER_WARNING);
}
}
private function createSecretsDir(): void
{
if ($this->secretsDir && !is_dir($this->secretsDir) && !@mkdir($this->secretsDir, 0777, true) && !is_dir($this->secretsDir)) {
throw new \RuntimeException(sprintf('Unable to create the secrets directory (%s)', $this->secretsDir));
}
$this->secretsDir = null;
}
}

View File

@ -31,7 +31,7 @@ class AddSessionDomainConstraintPass implements CompilerPassInterface
}
$sessionOptions = $container->getParameter('session.storage.options');
$domainRegexp = empty($sessionOptions['cookie_domain']) ? '%s' : sprintf('(?:%%s|(?:.+\.)?%s)', preg_quote(trim($sessionOptions['cookie_domain'], '.')));
$domainRegexp = empty($sessionOptions['cookie_domain']) ? '%%s' : sprintf('(?:%%%%s|(?:.+\.)?%s)', preg_quote(trim($sessionOptions['cookie_domain'], '.')));
if ('auto' === ($sessionOptions['cookie_secure'] ?? null)) {
$secureDomainRegexp = sprintf('{^https://%s$}i', $domainRegexp);

View File

@ -43,6 +43,7 @@ class RegisterTokenUsageTrackingPass implements CompilerPassInterface
if (!$container->has('session')) {
$container->setAlias('security.token_storage', 'security.untracked_token_storage')->setPublic(true);
$container->getDefinition('security.untracked_token_storage')->addTag('kernel.reset', ['method' => 'reset']);
} elseif ($container->hasDefinition('security.context_listener')) {
$container->getDefinition('security.context_listener')
->setArgument(6, [new Reference('security.token_storage'), 'enableUsageTracking']);

View File

@ -362,7 +362,13 @@ class MainConfiguration implements ConfigurationInterface
->performNoDeepMerging()
->beforeNormalization()->ifString()->then(function ($v) { return ['algorithm' => $v]; })->end()
->children()
->scalarNode('algorithm')->cannotBeEmpty()->end()
->scalarNode('algorithm')
->cannotBeEmpty()
->validate()
->ifTrue(function ($v) { return !\is_string($v); })
->thenInvalid('You must provide a string value.')
->end()
->end()
->arrayNode('migrate_from')
->prototype('scalar')->end()
->beforeNormalization()->castToArray()->end()

View File

@ -39,6 +39,8 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
private $values;
private $createCacheItem;
private static $valuesCache = [];
/**
* @param string $file The PHP file were values are cached
* @param AdapterInterface $fallbackPool A pool to fallback on when an item is not hit
@ -65,22 +67,17 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
* This adapter takes advantage of how PHP stores arrays in its latest versions.
*
* @param string $file The PHP file were values are cached
* @param CacheItemPoolInterface $fallbackPool Fallback when opcache is disabled
* @param CacheItemPoolInterface $fallbackPool A pool to fallback on when an item is not hit
*
* @return CacheItemPoolInterface
*/
public static function create(string $file, CacheItemPoolInterface $fallbackPool)
{
// Shared memory is available in PHP 7.0+ with OPCache enabled
if (filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN)) {
if (!$fallbackPool instanceof AdapterInterface) {
$fallbackPool = new ProxyAdapter($fallbackPool);
}
return new static($file, $fallbackPool);
if (!$fallbackPool instanceof AdapterInterface) {
$fallbackPool = new ProxyAdapter($fallbackPool);
}
return $fallbackPool;
return new static($file, $fallbackPool);
}
/**
@ -281,6 +278,7 @@ class PhpArrayAdapter implements AdapterInterface, CacheInterface, PruneableInte
$this->keys = $this->values = [];
$cleared = @unlink($this->file) || !file_exists($this->file);
unset(self::$valuesCache[$this->file]);
if ($this->pool instanceof AdapterInterface) {
return $this->pool->clear($prefix) && $cleared;
@ -375,6 +373,7 @@ EOF;
unset($serialized, $value, $dump);
@rename($tmpFile, $this->file);
unset(self::$valuesCache[$this->file]);
$this->initialize();
}
@ -384,12 +383,15 @@ EOF;
*/
private function initialize()
{
if (!file_exists($this->file)) {
if (isset(self::$valuesCache[$this->file])) {
$values = self::$valuesCache[$this->file];
} elseif (!file_exists($this->file)) {
$this->keys = $this->values = [];
return;
} else {
$values = self::$valuesCache[$this->file] = (include $this->file) ?: [[], []];
}
$values = (include $this->file) ?: [[], []];
if (2 !== \count($values) || !isset($values[0], $values[1])) {
$this->keys = $this->values = [];

View File

@ -66,6 +66,8 @@ class PhpArrayAdapterTest extends AdapterTestCase
protected function tearDown(): void
{
$this->createCachePool()->clear();
if (file_exists(sys_get_temp_dir().'/symfony-cache')) {
FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache');
}

View File

@ -38,6 +38,8 @@ class PhpArrayAdapterWithFallbackTest extends AdapterTestCase
protected function tearDown(): void
{
$this->createCachePool()->clear();
if (file_exists(sys_get_temp_dir().'/symfony-cache')) {
FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache');
}

View File

@ -37,7 +37,9 @@ class ClassExistenceResource implements SelfCheckingResourceInterface
public function __construct(string $resource, bool $exists = null)
{
$this->resource = $resource;
$this->exists = $exists;
if (null !== $exists) {
$this->exists = [(bool) $exists, null];
}
}
/**
@ -65,9 +67,13 @@ class ClassExistenceResource implements SelfCheckingResourceInterface
{
$loaded = class_exists($this->resource, false) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
if (null !== $exists = &self::$existsCache[(int) (0 >= $timestamp)][$this->resource]) {
$exists = $exists || $loaded;
} elseif (!$exists = $loaded) {
if (null !== $exists = &self::$existsCache[$this->resource]) {
if ($loaded) {
$exists = [true, null];
} elseif (0 >= $timestamp && !$exists[0] && null !== $exists[1]) {
throw new \ReflectionException($exists[1]);
}
} elseif ([false, null] === $exists = [$loaded, null]) {
if (!self::$autoloadLevel++) {
spl_autoload_register(__CLASS__.'::throwOnRequiredClass');
}
@ -75,16 +81,19 @@ class ClassExistenceResource implements SelfCheckingResourceInterface
self::$autoloadedClass = ltrim($this->resource, '\\');
try {
$exists = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
$exists[0] = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false);
} catch (\Exception $e) {
$exists[1] = $e->getMessage();
try {
self::throwOnRequiredClass($this->resource, $e);
} catch (\ReflectionException $e) {
if (0 >= $timestamp) {
unset(self::$existsCache[1][$this->resource]);
throw $e;
}
}
} catch (\Throwable $e) {
$exists[1] = $e->getMessage();
} finally {
self::$autoloadedClass = $autoloadedClass;
if (!--self::$autoloadLevel) {
@ -97,7 +106,7 @@ class ClassExistenceResource implements SelfCheckingResourceInterface
$this->exists = $exists;
}
return $this->exists xor !$exists;
return $this->exists[0] xor !$exists[0];
}
/**
@ -112,6 +121,16 @@ class ClassExistenceResource implements SelfCheckingResourceInterface
return ['resource', 'exists'];
}
/**
* @internal
*/
public function __wakeup()
{
if (\is_bool($this->exists)) {
$this->exists = [$this->exists, null];
}
}
/**
* Throws a reflection exception when the passed class does not exist but is required.
*
@ -147,7 +166,17 @@ class ClassExistenceResource implements SelfCheckingResourceInterface
throw $previous;
}
$e = new \ReflectionException(sprintf('Class "%s" not found while loading "%s".', $class, self::$autoloadedClass), 0, $previous);
$message = sprintf('Class "%s" not found.', $class);
if (self::$autoloadedClass !== $class) {
$message = substr_replace($message, sprintf(' while loading "%s"', self::$autoloadedClass), -1, 0);
}
if (null !== $previous) {
$message = $previous->getMessage();
}
$e = new \ReflectionException($message, 0, $previous);
if (null !== $previous) {
throw $e;

View File

@ -0,0 +1,9 @@
<?php
namespace Symfony\Component\Config\Tests\Fixtures;
class FileNameMismatchOnPurpose
{
}
throw new \RuntimeException('Mismatch between file name and class name.');

View File

@ -13,6 +13,7 @@ namespace Symfony\Component\Config\Tests\Resource;
use PHPUnit\Framework\TestCase;
use Symfony\Component\Config\Resource\ClassExistenceResource;
use Symfony\Component\Config\Tests\Fixtures\BadFileName;
use Symfony\Component\Config\Tests\Fixtures\BadParent;
use Symfony\Component\Config\Tests\Fixtures\Resource\ConditionalClass;
@ -90,6 +91,24 @@ EOF
$res->isFresh(0);
}
public function testBadFileName()
{
$this->expectException('ReflectionException');
$this->expectExceptionMessage('Mismatch between file name and class name.');
$res = new ClassExistenceResource(BadFileName::class, false);
$res->isFresh(0);
}
public function testBadFileNameBis()
{
$this->expectException('ReflectionException');
$this->expectExceptionMessage('Mismatch between file name and class name.');
$res = new ClassExistenceResource(BadFileName::class, false);
$res->isFresh(0);
}
public function testConditionalClass()
{
$res = new ClassExistenceResource(ConditionalClass::class, false);

View File

@ -14,12 +14,16 @@ namespace Symfony\Component\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Exception\EnvNotFoundException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\InvalidParameterTypeException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\ExpressionLanguage;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\ExpressionLanguage\Expression;
/**
* Checks whether injected parameters are compatible with type declarations.
@ -39,6 +43,8 @@ final class CheckTypeDeclarationsPass extends AbstractRecursivePass
private $autoload;
private $expressionLanguage;
/**
* @param bool $autoload Whether services who's class in not loaded should be checked or not.
* Defaults to false to save loading code during compilation.
@ -100,19 +106,21 @@ final class CheckTypeDeclarationsPass extends AbstractRecursivePass
$reflectionParameters = $reflectionFunction->getParameters();
$checksCount = min($reflectionFunction->getNumberOfParameters(), \count($values));
$envPlaceholderUniquePrefix = $this->container->getParameterBag() instanceof EnvPlaceholderParameterBag ? $this->container->getParameterBag()->getEnvPlaceholderUniquePrefix() : null;
for ($i = 0; $i < $checksCount; ++$i) {
if (!$reflectionParameters[$i]->hasType() || $reflectionParameters[$i]->isVariadic()) {
continue;
}
$this->checkType($checkedDefinition, $values[$i], $reflectionParameters[$i]);
$this->checkType($checkedDefinition, $values[$i], $reflectionParameters[$i], $envPlaceholderUniquePrefix);
}
if ($reflectionFunction->isVariadic() && ($lastParameter = end($reflectionParameters))->hasType()) {
$variadicParameters = \array_slice($values, $lastParameter->getPosition());
foreach ($variadicParameters as $variadicParameter) {
$this->checkType($checkedDefinition, $variadicParameter, $lastParameter);
$this->checkType($checkedDefinition, $variadicParameter, $lastParameter, $envPlaceholderUniquePrefix);
}
}
}
@ -120,7 +128,7 @@ final class CheckTypeDeclarationsPass extends AbstractRecursivePass
/**
* @throws InvalidParameterTypeException When a parameter is not compatible with the declared type
*/
private function checkType(Definition $checkedDefinition, $value, \ReflectionParameter $parameter): void
private function checkType(Definition $checkedDefinition, $value, \ReflectionParameter $parameter, ?string $envPlaceholderUniquePrefix): void
{
$type = $parameter->getType()->getName();
@ -172,8 +180,24 @@ final class CheckTypeDeclarationsPass extends AbstractRecursivePass
if ($value instanceof Parameter) {
$value = $this->container->getParameter($value);
} elseif (\is_string($value) && '%' === ($value[0] ?? '') && preg_match('/^%([^%]+)%$/', $value, $match)) {
$value = $this->container->getParameter($match[1]);
} elseif ($value instanceof Expression) {
$value = $this->getExpressionLanguage()->evaluate($value, ['container' => $this->container]);
} elseif (\is_string($value)) {
if ('%' === ($value[0] ?? '') && preg_match('/^%([^%]+)%$/', $value, $match)) {
// Only array parameters are not inlined when dumped.
$value = [];
} elseif ($envPlaceholderUniquePrefix && false !== strpos($value, 'env_')) {
// If the value is an env placeholder that is either mixed with a string or with another env placeholder, then its resolved value will always be a string, so we don't need to resolve it.
// We don't need to change the value because it is already a string.
if ('' === preg_replace('/'.$envPlaceholderUniquePrefix.'_\w+_[a-f0-9]{32}/U', '', $value, -1, $c) && 1 === $c) {
try {
$value = $this->container->resolveEnvPlaceholders($value, true);
} catch (EnvNotFoundException | RuntimeException $e) {
// If an env placeholder cannot be resolved, we skip the validation.
return;
}
}
}
}
if (null === $value && $parameter->allowsNull()) {
@ -202,4 +226,13 @@ final class CheckTypeDeclarationsPass extends AbstractRecursivePass
throw new InvalidParameterTypeException($this->currentId, \is_object($value) ? \get_class($value) : \gettype($value), $parameter);
}
}
private function getExpressionLanguage(): ExpressionLanguage
{
if (null === $this->expressionLanguage) {
$this->expressionLanguage = new ExpressionLanguage(null, $this->container->getExpressionLanguageProviders());
}
return $this->expressionLanguage;
}
}

View File

@ -96,6 +96,11 @@ class ResolveBindingsPass extends AbstractRecursivePass
if ($value instanceof TypedReference && $value->getType() === (string) $value) {
// Already checked
$bindings = $this->container->getDefinition($this->currentId)->getBindings();
$name = $value->getName();
if (isset($name, $bindings[$name = $value.' $'.$name])) {
return $this->getBindingValue($bindings[$name]);
}
if (isset($bindings[$value->getType()])) {
return $this->getBindingValue($bindings[$value->getType()]);

View File

@ -203,14 +203,14 @@ class PhpDumper extends Dumper
if (!empty($options['file']) && is_dir($dir = \dirname($options['file']))) {
// Build a regexp where the first root dirs are mandatory,
// but every other sub-dir is optional up to the full path in $dir
// Mandate at least 2 root dirs and not more that 5 optional dirs.
// Mandate at least 1 root dir and not more than 5 optional dirs.
$dir = explode(\DIRECTORY_SEPARATOR, realpath($dir));
$i = \count($dir);
if (3 <= $i) {
if (2 + (int) ('\\' === \DIRECTORY_SEPARATOR) <= $i) {
$regex = '';
$lastOptionalDir = $i > 8 ? $i - 5 : 3;
$lastOptionalDir = $i > 8 ? $i - 5 : (2 + (int) ('\\' === \DIRECTORY_SEPARATOR));
$this->targetDirMaxMatches = $i - $lastOptionalDir;
while (--$i >= $lastOptionalDir) {

View File

@ -14,8 +14,10 @@ namespace Symfony\Component\DependencyInjection\Tests\Compiler;
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\Argument\IteratorArgument;
use Symfony\Component\DependencyInjection\Compiler\CheckTypeDeclarationsPass;
use Symfony\Component\DependencyInjection\Compiler\ResolveParameterPlaceHoldersPass;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\ParameterBag\EnvPlaceholderParameterBag;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Bar;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\BarMethodCall;
@ -23,6 +25,7 @@ use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPa
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\BarOptionalArgumentNotNull;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\Foo;
use Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\FooObject;
use Symfony\Component\ExpressionLanguage\Expression;
/**
* @author Nicolas Grekas <p@tchwork.com>
@ -569,4 +572,101 @@ class CheckTypeDeclarationsPassTest extends TestCase
$this->assertInstanceOf(\stdClass::class, $container->get('bar')->foo);
}
public function testProcessResolveArrayParameters()
{
$container = new ContainerBuilder();
$container->setParameter('ccc', ['foobar']);
$container
->register('foobar', BarMethodCall::class)
->addMethodCall('setArray', ['%ccc%']);
(new CheckTypeDeclarationsPass(true))->process($container);
$this->addToAssertionCount(1);
}
public function testProcessResolveExpressions()
{
$container = new ContainerBuilder();
$container->setParameter('ccc', ['array']);
$container
->register('foobar', BarMethodCall::class)
->addMethodCall('setArray', [new Expression("parameter('ccc')")]);
(new CheckTypeDeclarationsPass(true))->process($container);
$this->addToAssertionCount(1);
}
public function testProcessHandleMixedEnvPlaceholder()
{
$this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid definition for service "foobar": argument 1 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\BarMethodCall::setArray" accepts "array", "string" passed.');
$container = new ContainerBuilder(new EnvPlaceholderParameterBag([
'ccc' => '%env(FOO)%',
]));
$container
->register('foobar', BarMethodCall::class)
->addMethodCall('setArray', ['foo%ccc%']);
(new CheckTypeDeclarationsPass(true))->process($container);
}
public function testProcessHandleMultipleEnvPlaceholder()
{
$this->expectException(\Symfony\Component\DependencyInjection\Exception\InvalidArgumentException::class);
$this->expectExceptionMessage('Invalid definition for service "foobar": argument 1 of "Symfony\Component\DependencyInjection\Tests\Fixtures\CheckTypeDeclarationsPass\BarMethodCall::setArray" accepts "array", "string" passed.');
$container = new ContainerBuilder(new EnvPlaceholderParameterBag([
'ccc' => '%env(FOO)%',
'fcy' => '%env(int:BAR)%',
]));
$container
->register('foobar', BarMethodCall::class)
->addMethodCall('setArray', ['%ccc%%fcy%']);
(new CheckTypeDeclarationsPass(true))->process($container);
}
public function testProcessHandleExistingEnvPlaceholder()
{
putenv('ARRAY={"foo":"bar"}');
$container = new ContainerBuilder(new EnvPlaceholderParameterBag([
'ccc' => '%env(json:ARRAY)%',
]));
$container
->register('foobar', BarMethodCall::class)
->addMethodCall('setArray', ['%ccc%']);
(new ResolveParameterPlaceHoldersPass())->process($container);
(new CheckTypeDeclarationsPass(true))->process($container);
$this->addToAssertionCount(1);
putenv('ARRAY=');
}
public function testProcessHandleNotFoundEnvPlaceholder()
{
$container = new ContainerBuilder(new EnvPlaceholderParameterBag([
'ccc' => '%env(json:ARRAY)%',
]));
$container
->register('foobar', BarMethodCall::class)
->addMethodCall('setArray', ['%ccc%']);
(new ResolveParameterPlaceHoldersPass())->process($container);
(new CheckTypeDeclarationsPass(true))->process($container);
$this->addToAssertionCount(1);
}
}

View File

@ -84,7 +84,10 @@ class ResolveBindingsPassTest extends TestCase
{
$container = new ContainerBuilder();
$bindings = [CaseSensitiveClass::class => new BoundArgument(new Reference('foo'))];
$bindings = [
CaseSensitiveClass::class => new BoundArgument(new Reference('foo')),
CaseSensitiveClass::class.' $c' => new BoundArgument(new Reference('bar')),
];
// Explicit service id
$definition1 = $container->register('def1', NamedArgumentsDummy::class);
@ -95,11 +98,16 @@ class ResolveBindingsPassTest extends TestCase
$definition2->addArgument(new TypedReference(CaseSensitiveClass::class, CaseSensitiveClass::class));
$definition2->setBindings($bindings);
$definition3 = $container->register('def3', NamedArgumentsDummy::class);
$definition3->addArgument(new TypedReference(CaseSensitiveClass::class, CaseSensitiveClass::class, ContainerBuilder::EXCEPTION_ON_INVALID_REFERENCE, 'c'));
$definition3->setBindings($bindings);
$pass = new ResolveBindingsPass();
$pass->process($container);
$this->assertEquals([$typedRef], $container->getDefinition('def1')->getArguments());
$this->assertEquals([new Reference('foo')], $container->getDefinition('def2')->getArguments());
$this->assertEquals([new Reference('bar')], $container->getDefinition('def3')->getArguments());
}
public function testScalarSetter()

View File

@ -35,7 +35,7 @@ final class Dotenv
private $data;
private $end;
private $values;
private $usePutenv = true;
private $usePutenv;
/**
* @var bool If `putenv()` should be used to define environment variables or not.

View File

@ -63,7 +63,7 @@ class RedisSessionHandler extends AbstractSessionHandler
$this->redis = $redis;
$this->prefix = $options['prefix'] ?? 'sf_s';
$this->ttl = $options['ttl'] ?? (int) ini_get('session.gc_maxlifetime');
$this->ttl = $options['ttl'] ?? null;
}
/**
@ -79,7 +79,7 @@ class RedisSessionHandler extends AbstractSessionHandler
*/
protected function doWrite(string $sessionId, string $data): bool
{
$result = $this->redis->setEx($this->prefix.$sessionId, $this->ttl, $data);
$result = $this->redis->setEx($this->prefix.$sessionId, (int) ($this->ttl ?? ini_get('session.gc_maxlifetime')), $data);
return $result && !$result instanceof ErrorInterface;
}
@ -115,6 +115,6 @@ class RedisSessionHandler extends AbstractSessionHandler
*/
public function updateTimestamp($sessionId, $data)
{
return (bool) $this->redis->expire($this->prefix.$sessionId, $this->ttl);
return (bool) $this->redis->expire($this->prefix.$sessionId, (int) ($this->ttl ?? ini_get('session.gc_maxlifetime')));
}
}

View File

@ -115,6 +115,7 @@ class EsmtpTransport extends SmtpTransport
try {
$response = $this->executeCommand(sprintf("EHLO %s\r\n", $this->getLocalDomain()), [250]);
$capabilities = $this->getCapabilities($response);
} catch (TransportExceptionInterface $e) {
parent::doHeloCommand();

View File

@ -59,7 +59,7 @@ EOF
$io = new SymfonyStyle($input, $output);
$transportNames = $this->transportNames;
// do we want to setup only one transport?
// do we want to set up only one transport?
if ($transport = $input->getArgument('transport')) {
if (!$this->transportLocator->has($transport)) {
throw new \RuntimeException(sprintf('The "%s" transport does not exist.', $transport));
@ -71,7 +71,7 @@ EOF
$transport = $this->transportLocator->get($transportName);
if ($transport instanceof SetupableTransportInterface) {
$transport->setup();
$io->success(sprintf('The "%s" transport was setup successfully.', $transportName));
$io->success(sprintf('The "%s" transport was set up successfully.', $transportName));
} else {
$io->note(sprintf('The "%s" transport does not support setup.', $transportName));
}

View File

@ -35,7 +35,13 @@ class SendMessageMiddleware implements MiddlewareInterface
public function __construct(SendersLocatorInterface $sendersLocator, EventDispatcherInterface $eventDispatcher = null)
{
$this->sendersLocator = $sendersLocator;
$this->eventDispatcher = LegacyEventDispatcherProxy::decorate($eventDispatcher);
if (null !== $eventDispatcher && class_exists(LegacyEventDispatcherProxy::class)) {
$this->eventDispatcher = LegacyEventDispatcherProxy::decorate($eventDispatcher);
} else {
$this->eventDispatcher = $eventDispatcher;
}
$this->logger = new NullLogger();
}

View File

@ -42,7 +42,7 @@ class SetupTransportsCommandTest extends TestCase
$tester->execute([]);
$display = $tester->getDisplay();
$this->assertStringContainsString('The "amqp" transport was setup successfully.', $display);
$this->assertStringContainsString('The "amqp" transport was set up successfully.', $display);
$this->assertStringContainsString('The "other_transport" transport does not support setup.', $display);
}
@ -66,7 +66,7 @@ class SetupTransportsCommandTest extends TestCase
$tester->execute(['transport' => 'amqp']);
$display = $tester->getDisplay();
$this->assertStringContainsString('The "amqp" transport was setup successfully.', $display);
$this->assertStringContainsString('The "amqp" transport was set up successfully.', $display);
}
public function testReceiverNameArgumentNotFound()

View File

@ -322,7 +322,7 @@ class Connection
}
} catch (\AMQPQueueException $e) {
if (404 === $e->getCode() && $this->shouldSetup()) {
// If we get a 404 for the queue, it means we need to setup the exchange & queue.
// If we get a 404 for the queue, it means we need to set up the exchange & queue.
$this->setupExchangeAndQueues();
return $this->get();

View File

@ -47,8 +47,13 @@ class Worker
{
$this->receivers = $receivers;
$this->bus = $bus;
$this->eventDispatcher = LegacyEventDispatcherProxy::decorate($eventDispatcher);
$this->logger = $logger;
if (null !== $eventDispatcher && class_exists(LegacyEventDispatcherProxy::class)) {
$this->eventDispatcher = LegacyEventDispatcherProxy::decorate($eventDispatcher);
} else {
$this->eventDispatcher = $eventDispatcher;
}
}
/**

View File

@ -55,6 +55,10 @@ class DaoAuthenticationProvider extends UserAuthenticationProvider
throw new BadCredentialsException('The presented password cannot be empty.');
}
if (null === $user->getPassword()) {
throw new BadCredentialsException('The presented password is invalid.');
}
$encoder = $this->encoderFactory->getEncoder($user);
if (!$encoder->isPasswordValid($user->getPassword(), $presentedPassword, $user->getSalt())) {

View File

@ -42,6 +42,10 @@ class UserPasswordEncoder implements UserPasswordEncoderInterface
*/
public function isPasswordValid(UserInterface $user, string $raw)
{
if (null === $user->getPassword()) {
return false;
}
$encoder = $this->encoderFactory->getEncoder($user);
return $encoder->isPasswordValid($user->getPassword(), $raw, $user->getSalt());
@ -52,6 +56,10 @@ class UserPasswordEncoder implements UserPasswordEncoderInterface
*/
public function needsRehash(UserInterface $user): bool
{
if (null === $user->getPassword()) {
return false;
}
$encoder = $this->encoderFactory->getEncoder($user);
return $encoder->needsRehash($user->getPassword());

View File

@ -147,7 +147,11 @@ class DaoAuthenticationProviderTest extends TestCase
->willReturn('0')
;
$method->invoke($provider, new TestUser(), $token);
$method->invoke(
$provider,
new User('username', 'password'),
$token
);
}
public function testCheckAuthenticationWhenCredentialsAreNotValid()
@ -169,7 +173,7 @@ class DaoAuthenticationProviderTest extends TestCase
->willReturn('foo')
;
$method->invoke($provider, new TestUser(), $token);
$method->invoke($provider, new User('username', 'password'), $token);
}
public function testCheckAuthenticationDoesNotReauthenticateWhenPasswordHasChanged()
@ -241,7 +245,7 @@ class DaoAuthenticationProviderTest extends TestCase
->willReturn('foo')
;
$method->invoke($provider, new TestUser(), $token);
$method->invoke($provider, new User('username', 'password'), $token);
}
public function testPasswordUpgrades()

View File

@ -53,7 +53,7 @@ class UserPasswordValidator extends ConstraintValidator
$encoder = $this->encoderFactory->getEncoder($user);
if (!$encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt())) {
if (null === $user->getPassword() || !$encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt())) {
$this->context->addViolation($constraint->message);
}
}

View File

@ -66,7 +66,13 @@ class ContextListener extends AbstractListener
$this->userProviders = $userProviders;
$this->sessionKey = '_security_'.$contextKey;
$this->logger = $logger;
$this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher);
if (null !== $dispatcher && class_exists(LegacyEventDispatcherProxy::class)) {
$this->dispatcher = LegacyEventDispatcherProxy::decorate($dispatcher);
} else {
$this->dispatcher = $dispatcher;
}
$this->trustResolver = $trustResolver ?: new AuthenticationTrustResolver(AnonymousToken::class, RememberMeToken::class);
$this->sessionTrackerEnabler = $sessionTrackerEnabler;
}

View File

@ -23,7 +23,7 @@ class UrlValidator extends ConstraintValidator
{
const PATTERN = '~^
(%s):// # protocol
(([\.\pL\pN-]+:)?([\.\pL\pN-]+)@)? # basic auth
(([\_\.\pL\pN-]+:)?([\_\.\pL\pN-]+)@)? # basic auth
(
([\pL\pN\pS\-\_\.])+(\.?([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?) # a domain name
| # or

View File

@ -148,9 +148,11 @@ class UrlValidatorTest extends ConstraintValidatorTestCase
['http://☎.com/'],
['http://username:password@symfony.com'],
['http://user.name:password@symfony.com'],
['http://user_name:pass_word@symfony.com'],
['http://username:pass.word@symfony.com'],
['http://user.name:pass.word@symfony.com'],
['http://user-name@symfony.com'],
['http://user_name@symfony.com'],
['http://symfony.com?'],
['http://symfony.com?query=1'],
['http://symfony.com/?query=1'],

View File

@ -617,11 +617,11 @@ class Inline
// Optimize for returning strings.
// no break
case '+' === $scalar[0] || '-' === $scalar[0] || '.' === $scalar[0] || is_numeric($scalar[0]):
if (Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar)) {
$scalar = str_replace('_', '', (string) $scalar);
}
switch (true) {
case Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar):
$scalar = str_replace('_', '', (string) $scalar);
// omitting the break / return as integers are handled in the next case
// no break
case ctype_digit($scalar):
$raw = $scalar;
$cast = (int) $scalar;
@ -631,7 +631,7 @@ class Inline
$raw = $scalar;
$cast = (int) $scalar;
return '0' == $scalar[1] ? octdec($scalar) : (((string) $raw === (string) $cast) ? $cast : $raw);
return '0' == $scalar[1] ? -octdec(substr($scalar, 1)) : (($raw === (string) $cast) ? $cast : $raw);
case is_numeric($scalar):
case Parser::preg_match(self::getHexRegex(), $scalar):
$scalar = str_replace('_', '', $scalar);

View File

@ -720,4 +720,20 @@ class InlineTest extends TestCase
$this->expectExceptionMessage("Unexpected end of line, expected one of \",}\n\" at line 1 (near \"{abc: 'def'\").");
Inline::parse("{abc: 'def'");
}
/**
* @dataProvider getTestsForOctalNumbers
*/
public function testParseOctalNumbers($expected, $yaml)
{
self::assertSame($expected, Inline::parse($yaml));
}
public function getTestsForOctalNumbers()
{
return [
'positive octal number' => [28, '034'],
'negative octal number' => [-28, '-034'],
];
}
}