diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index b863dea0cbf9a..0d234d8fe9b7f 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,6 @@ | Q | A | ------------- | --- -| Branch? | 4.4 for features / 3.4 or 4.3 for bug fixes +| Branch? | master for features / 3.4, 4.3, 4.4 or 5.0 for bug fixes | Bug fix? | yes/no | New feature? | yes/no | Deprecations? | yes/no @@ -16,6 +16,5 @@ Additionally (see https://symfony.com/roadmap): - Never break backward compatibility (see https://symfony.com/bc). - Bug fixes must be submitted against the lowest maintained branch where they apply (lowest branches are regularly merged to upper ones so they get the fixes too.) - - Features and deprecations must be submitted against branch 4.4. - - Legacy code removals go to the master branch. + - Features and deprecations must be submitted against branch master. --> diff --git a/CHANGELOG-3.4.md b/CHANGELOG-3.4.md index ba1027925d004..91a96c6e3b71c 100644 --- a/CHANGELOG-3.4.md +++ b/CHANGELOG-3.4.md @@ -7,6 +7,26 @@ in 3.4 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v3.4.0...v3.4.1 +* 3.4.36 (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 #34632 [Console] Fix trying to access array offset on value of type int (Tavafi) + * bug #34668 [Cache] Make sure we get the correct number of values from redis::mget() (thePanz) + * bug #34533 [Monolog Bridge] Fixed accessing static property as non static. (Sander-Toonen) + * 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 #34366 [HttpFoundation] Allow redirecting to URLs that contain a semicolon (JayBizzle) + * bug #34410 [HttpFoundation] Fix MySQL column type definition. (jbroutier) + * bug #34396 [Finder] Allow ssh2 stream wrapper for sftp (damienalexandre) + * bug #34381 [WebProfilerBundle] Require symfony/twig-bundle (fancyweb) + * 3.4.35 (2019-11-13) * bug #34344 [Console] Constant STDOUT might be undefined (nicolas-grekas) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index ccca55ab4bb11..9a6707977b3ec 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -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) diff --git a/README.md b/README.md index 5796b1acd7ceb..da9e6156c00d7 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@

-[Symfony][1] is a **PHP framework** for web applications and a set of reusable +[Symfony][1] is a **PHP framework** for web and console applications and a set of reusable **PHP components**. Symfony is used by thousands of web applications (including BlaBlaCar.com and Spotify.com) and most of the [popular PHP projects][2] (including Drupal and Magento). diff --git a/UPGRADE-4.0.md b/UPGRADE-4.0.md index 8d41f32658c58..f970041949e5b 100644 --- a/UPGRADE-4.0.md +++ b/UPGRADE-4.0.md @@ -26,8 +26,8 @@ file and directory structure of your application: Then, upgrade the contents of your console script and your front controller: -* `bin/console`: https://github.com/symfony/recipes/blob/master/symfony/console/3.3/bin/console -* `public/index.php`: https://github.com/symfony/recipes/blob/master/symfony/framework-bundle/3.3/public/index.php +* `bin/console`: https://github.com/symfony/recipes/blob/master/symfony/console/4.4/bin/console +* `public/index.php`: https://github.com/symfony/recipes/blob/master/symfony/framework-bundle/4.4/public/index.php Lastly, read the following article to add Symfony Flex to your application and upgrade the configuration files: https://symfony.com/doc/current/setup/flex.html diff --git a/composer.json b/composer.json index 42397d75b851d..9ad5e39ad2ca5 100644 --- a/composer.json +++ b/composer.json @@ -103,6 +103,7 @@ "phpdocumentor/reflection-docblock": "^3.0|^4.0" }, "conflict": { + "monolog/monolog": ">=2", "phpdocumentor/reflection-docblock": "<3.0||>=3.2.0,<3.2.2", "phpdocumentor/type-resolver": "<0.3.0", "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0" diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterMappingsPass.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterMappingsPass.php index 7ac1856114d7e..4e025dc194c93 100644 --- a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterMappingsPass.php +++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterMappingsPass.php @@ -222,10 +222,7 @@ private function getManagerName(ContainerBuilder $container) } } - throw new InvalidArgumentException(sprintf( - 'Could not find the manager name parameter in the container. Tried the following parameter names: "%s"', - implode('", "', $this->managerParameters) - )); + throw new InvalidArgumentException(sprintf('Could not find the manager name parameter in the container. Tried the following parameter names: "%s"', implode('", "', $this->managerParameters))); } /** diff --git a/src/Symfony/Bridge/Monolog/Handler/ChromePhpHandler.php b/src/Symfony/Bridge/Monolog/Handler/ChromePhpHandler.php index c27b0803e200e..c8e21b2f42622 100644 --- a/src/Symfony/Bridge/Monolog/Handler/ChromePhpHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/ChromePhpHandler.php @@ -39,7 +39,7 @@ public function onKernelResponse(FilterResponseEvent $event) } if (!preg_match(static::USER_AGENT_REGEX, $event->getRequest()->headers->get('User-Agent'))) { - $this->sendHeaders = false; + self::$sendHeaders = false; $this->headers = []; return; @@ -57,7 +57,7 @@ public function onKernelResponse(FilterResponseEvent $event) */ protected function sendHeader($header, $content) { - if (!$this->sendHeaders) { + if (!self::$sendHeaders) { return; } diff --git a/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php b/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php index 82d72983657ba..28932d9449d6a 100644 --- a/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Translation/TwigExtractorTest.php @@ -16,7 +16,6 @@ use Symfony\Bridge\Twig\Translation\TwigExtractor; use Symfony\Component\Translation\MessageCatalogue; use Twig\Environment; -use Twig\Error\Error; use Twig\Loader\ArrayLoader; class TwigExtractorTest extends TestCase @@ -78,23 +77,15 @@ public function getExtractData() /** * @dataProvider resourcesWithSyntaxErrorsProvider */ - public function testExtractSyntaxError($resources) + public function testExtractSyntaxError($resources, array $messages) { - $this->expectException('Twig\Error\Error'); $twig = new Environment($this->getMockBuilder('Twig\Loader\LoaderInterface')->getMock()); $twig->addExtension(new TranslationExtension($this->getMockBuilder('Symfony\Component\Translation\TranslatorInterface')->getMock())); $extractor = new TwigExtractor($twig); - - try { - $extractor->extract($resources, new MessageCatalogue('en')); - } catch (Error $e) { - $this->assertSame(\dirname(__DIR__).strtr('/Fixtures/extractor/syntax_error.twig', '/', \DIRECTORY_SEPARATOR), $e->getFile()); - $this->assertSame(1, $e->getLine()); - $this->assertSame('Unclosed "block".', $e->getMessage()); - - throw $e; - } + $catalogue = new MessageCatalogue('en'); + $extractor->extract($resources, $catalogue); + $this->assertSame($messages, $catalogue->all()); } /** @@ -103,9 +94,9 @@ public function testExtractSyntaxError($resources) public function resourcesWithSyntaxErrorsProvider() { return [ - [__DIR__.'/../Fixtures'], - [__DIR__.'/../Fixtures/extractor/syntax_error.twig'], - [new \SplFileInfo(__DIR__.'/../Fixtures/extractor/syntax_error.twig')], + [__DIR__.'/../Fixtures', ['messages' => ['Hi!' => 'Hi!']]], + [__DIR__.'/../Fixtures/extractor/syntax_error.twig', []], + [new \SplFileInfo(__DIR__.'/../Fixtures/extractor/syntax_error.twig'), []], ]; } diff --git a/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php b/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php index b7c787226656f..107d8cc4bff17 100644 --- a/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php +++ b/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php @@ -12,7 +12,6 @@ namespace Symfony\Bridge\Twig\Translation; use Symfony\Component\Finder\Finder; -use Symfony\Component\Finder\SplFileInfo; use Symfony\Component\Translation\Extractor\AbstractFileExtractor; use Symfony\Component\Translation\Extractor\ExtractorInterface; use Symfony\Component\Translation\MessageCatalogue; @@ -58,13 +57,7 @@ public function extract($resource, MessageCatalogue $catalogue) try { $this->extractTemplate(file_get_contents($file->getPathname()), $catalogue); } catch (Error $e) { - if ($file instanceof \SplFileInfo) { - $path = $file->getRealPath() ?: $file->getPathname(); - $name = $file instanceof SplFileInfo ? $file->getRelativePathname() : $path; - $e->setSourceContext(new Source('', $name, $path)); - } - - throw $e; + // ignore errors, these should be fixed by using the linter } } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php index ea5d0c7d0bffa..197db657f0015 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php @@ -166,7 +166,7 @@ protected function describeEventDispatcherListeners(EventDispatcherInterface $ev */ protected function describeCallable($callable, array $options = []) { - $this->writeData($this->getCallableData($callable, $options), $options); + $this->writeData($this->getCallableData($callable), $options); } /** @@ -321,7 +321,7 @@ private function getEventDispatcherListenersData(EventDispatcherInterface $event * * @return array */ - private function getCallableData($callable, array $options = []) + private function getCallableData($callable) { $data = []; diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php index 34de3d6701470..8d419c0edd8f0 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/RememberMeFactory.php @@ -81,7 +81,11 @@ public function create(ContainerBuilder $container, $id, $config, $userProvider, throw new \RuntimeException('Each "security.remember_me_aware" tag must have a provider attribute.'); } - $userProviders[] = new Reference($attribute['provider']); + // context listeners don't need a provider + if ('none' !== $attribute['provider']) { + $userProviders[] = new Reference($attribute['provider']); + } + $container ->getDefinition($serviceId) ->addMethodCall('setRememberMeServices', [new Reference($rememberMeServicesId)]) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 731ce42d39328..19e9beb1e37e6 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -374,6 +374,7 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a $listeners[] = new Reference('security.channel_listener'); $contextKey = null; + $contextListenerId = null; // Context serializer listener if (false === $firewall['stateless']) { $contextKey = $id; @@ -390,7 +391,7 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a } $this->logoutOnUserChangeByContextKey[$contextKey] = [$id, $logoutOnUserChange]; - $listeners[] = new Reference($this->createContextListener($container, $contextKey, $logoutOnUserChange)); + $listeners[] = new Reference($contextListenerId = $this->createContextListener($container, $contextKey, $logoutOnUserChange)); $sessionStrategyId = 'security.authentication.session_strategy'; } else { $this->statelessFirewallKeys[] = $id; @@ -463,7 +464,7 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a $configuredEntryPoint = isset($firewall['entry_point']) ? $firewall['entry_point'] : null; // Authentication listeners - list($authListeners, $defaultEntryPoint) = $this->createAuthenticationListeners($container, $id, $firewall, $authenticationProviders, $defaultProvider, $providerIds, $configuredEntryPoint); + list($authListeners, $defaultEntryPoint) = $this->createAuthenticationListeners($container, $id, $firewall, $authenticationProviders, $defaultProvider, $providerIds, $configuredEntryPoint, $contextListenerId); $config->replaceArgument(7, $configuredEntryPoint ?: $defaultEntryPoint); @@ -519,7 +520,7 @@ private function createContextListener($container, $contextKey, $logoutUserOnCha return $this->contextListeners[$contextKey] = $listenerId; } - private function createAuthenticationListeners($container, $id, $firewall, &$authenticationProviders, $defaultProvider = null, array $providerIds, $defaultEntryPoint) + private function createAuthenticationListeners($container, $id, $firewall, &$authenticationProviders, $defaultProvider = null, array $providerIds, $defaultEntryPoint, $contextListenerId = null) { $listeners = []; $hasListeners = false; @@ -537,6 +538,9 @@ private function createAuthenticationListeners($container, $id, $firewall, &$aut } elseif ('remember_me' === $key) { // RememberMeFactory will use the firewall secret when created $userProvider = null; + if ($contextListenerId) { + $container->getDefinition($contextListenerId)->addTag('security.remember_me_aware', ['id' => $id, 'provider' => 'none']); + } } else { $userProvider = $defaultProvider ?: $this->getFirstProvider($id, $key, $providerIds); } @@ -585,7 +589,7 @@ private function createEncoders($encoders, ContainerBuilder $container) { $encoderMap = []; foreach ($encoders as $class => $encoder) { - $encoderMap[$class] = $this->createEncoder($encoder, $container); + $encoderMap[$class] = $this->createEncoder($encoder); } $container @@ -594,7 +598,7 @@ private function createEncoders($encoders, ContainerBuilder $container) ; } - private function createEncoder($config, ContainerBuilder $container) + private function createEncoder($config) { // a custom encoder service if (isset($config['id'])) { diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php new file mode 100644 index 0000000000000..3a1046b0c4a17 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\SecurityBundle\Tests\Functional; + +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Security\Core\User\InMemoryUserProvider; +use Symfony\Component\Security\Core\User\User; +use Symfony\Component\Security\Core\User\UserInterface; +use Symfony\Component\Security\Core\User\UserProviderInterface; + +class ClearRememberMeTest extends AbstractWebTestCase +{ + public function testUserChangeClearsCookie() + { + $client = $this->createClient(['test_case' => 'ClearRememberMe', 'root_config' => 'config.yml']); + + $client->request('POST', '/login', [ + '_username' => 'johannes', + '_password' => 'test', + ]); + + $this->assertSame(302, $client->getResponse()->getStatusCode()); + $cookieJar = $client->getCookieJar(); + $this->assertNotNull($cookieJar->get('REMEMBERME')); + + $client->request('GET', '/foo'); + $this->assertSame(200, $client->getResponse()->getStatusCode()); + $this->assertNull($cookieJar->get('REMEMBERME')); + } +} + +class RememberMeFooController +{ + public function __invoke(UserInterface $user) + { + return new Response($user->getUsername()); + } +} + +class RememberMeUserProvider implements UserProviderInterface +{ + private $inner; + + public function __construct(InMemoryUserProvider $inner) + { + $this->inner = $inner; + } + + public function loadUserByUsername($username) + { + return $this->inner->loadUserByUsername($username); + } + + public function refreshUser(UserInterface $user) + { + $user = $this->inner->refreshUser($user); + + $alterUser = \Closure::bind(function (User $user) { $user->password = 'foo'; }, null, User::class); + $alterUser($user); + + return $user; + } + + public function supportsClass($class) + { + return $this->inner->supportsClass($class); + } +} diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserTest.php index 31f99da2a08f2..722bef0f78628 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/SwitchUserTest.php @@ -25,6 +25,10 @@ public function testSwitchUser($originalUser, $targetUser, $expectedUser, $expec $client->request('GET', '/profile?_switch_user='.$targetUser); + if ('user_does_not_exist' === $targetUser && 403 === $expectedStatus && 500 === $client->getResponse()->getStatusCode()) { + $expectedStatus = 500; // 403 is generated by Symfony >= 4.3.8 + } + $this->assertEquals($expectedStatus, $client->getResponse()->getStatusCode()); $this->assertEquals($expectedUser, $client->getProfile()->getCollector('security')->getUser()); } @@ -68,7 +72,7 @@ public function getTestParameters() return [ 'unauthorized_user_cannot_switch' => ['user_cannot_switch_1', 'user_cannot_switch_1', 'user_cannot_switch_1', 403], 'authorized_user_can_switch' => ['user_can_switch', 'user_cannot_switch_1', 'user_cannot_switch_1', 200], - 'authorized_user_cannot_switch_to_non_existent' => ['user_can_switch', 'user_does_not_exist', 'user_can_switch', 500], + 'authorized_user_cannot_switch_to_non_existent' => ['user_can_switch', 'user_does_not_exist', 'user_can_switch', 403], 'authorized_user_can_switch_to_himself' => ['user_can_switch', 'user_can_switch', 'user_can_switch', 200], ]; } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/ClearRememberMe/bundles.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/ClearRememberMe/bundles.php new file mode 100644 index 0000000000000..9a26fb163a77d --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/ClearRememberMe/bundles.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Bundle\FrameworkBundle\FrameworkBundle; +use Symfony\Bundle\SecurityBundle\SecurityBundle; + +return [ + new FrameworkBundle(), + new SecurityBundle(), +]; diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/ClearRememberMe/config.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/ClearRememberMe/config.yml new file mode 100644 index 0000000000000..e5cefd37df76d --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/ClearRememberMe/config.yml @@ -0,0 +1,32 @@ +imports: + - { resource: ./../config/framework.yml } + +security: + encoders: + Symfony\Component\Security\Core\User\User: plaintext + + providers: + in_memory: + memory: + users: + johannes: { password: test, roles: [ROLE_USER] } + + firewalls: + default: + form_login: + check_path: login + remember_me: true + remember_me: + always_remember_me: true + secret: key + anonymous: ~ + logout_on_user_change: true + + access_control: + - { path: ^/foo, roles: ROLE_USER } + +services: + Symfony\Bundle\SecurityBundle\Tests\Functional\RememberMeUserProvider: + public: true + decorates: security.user.provider.concrete.in_memory + arguments: ['@Symfony\Bundle\SecurityBundle\Tests\Functional\RememberMeUserProvider.inner'] diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/ClearRememberMe/routing.yml b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/ClearRememberMe/routing.yml new file mode 100644 index 0000000000000..08975bdcb3832 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/app/ClearRememberMe/routing.yml @@ -0,0 +1,7 @@ +login: + path: /login + +foo: + path: /foo + defaults: + _controller: Symfony\Bundle\SecurityBundle\Tests\Functional\RememberMeFooController diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 1f0e56e6eedde..1a8057b6fbd08 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -19,7 +19,7 @@ "php": "^5.5.9|>=7.0.8", "ext-xml": "*", "symfony/config": "~3.4|~4.0", - "symfony/security": "~3.4.15|~4.0.15|^4.1.4", + "symfony/security": "~3.4.36|~4.3.9|^4.4.1", "symfony/dependency-injection": "^3.4.3|^4.0.3", "symfony/http-kernel": "~3.4|~4.0", "symfony/polyfill-php70": "~1.0" diff --git a/src/Symfony/Bundle/WebProfilerBundle/composer.json b/src/Symfony/Bundle/WebProfilerBundle/composer.json index 241a5e350b414..c82ef0fe0093d 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/composer.json +++ b/src/Symfony/Bundle/WebProfilerBundle/composer.json @@ -20,7 +20,7 @@ "symfony/http-kernel": "~3.4.25|^4.2.6", "symfony/polyfill-php70": "~1.0", "symfony/routing": "~2.8|~3.0|~4.0", - "symfony/twig-bridge": "~2.8|~3.0|~4.0", + "symfony/twig-bundle": "~2.8|~3.0|~4.0", "symfony/var-dumper": "~3.3|~4.0", "twig/twig": "~1.34|~2.4" }, diff --git a/src/Symfony/Bundle/WebServerBundle/Command/ServerLogCommand.php b/src/Symfony/Bundle/WebServerBundle/Command/ServerLogCommand.php index 73c51cc8e09e4..5c9ce910ddf54 100644 --- a/src/Symfony/Bundle/WebServerBundle/Command/ServerLogCommand.php +++ b/src/Symfony/Bundle/WebServerBundle/Command/ServerLogCommand.php @@ -114,7 +114,7 @@ protected function execute(InputInterface $input, OutputInterface $output) continue; } - $this->displayLog($input, $output, $clientId, $record); + $this->displayLog($output, $clientId, $record); } } @@ -141,7 +141,7 @@ private function getLogs($socket) } } - private function displayLog(InputInterface $input, OutputInterface $output, $clientId, array $record) + private function displayLog(OutputInterface $output, $clientId, array $record) { if ($this->handler->isHandling($record)) { if (isset($record['log_id'])) { diff --git a/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php b/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php index 76673e0a03c7b..e03d37b94de41 100644 --- a/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php @@ -271,7 +271,7 @@ private function generateItems(array $keys) public static function throwOnRequiredClass($class) { $e = new \ReflectionException("Class $class does not exist"); - $trace = $e->getTrace(); + $trace = debug_backtrace(); $autoloadFrame = [ 'function' => 'spl_autoload_call', 'args' => [$class], diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php index 395a9b8051b4f..c4b12b64bb37b 100644 --- a/src/Symfony/Component/Cache/Traits/RedisTrait.php +++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php @@ -179,7 +179,13 @@ protected function doFetch(array $ids) } }); } else { - $values = array_combine($ids, $this->redis->mget($ids)); + $values = $this->redis->mget($ids); + + if (!\is_array($values) || \count($values) !== \count($ids)) { + return []; + } + + $values = array_combine($ids, $values); } foreach ($values as $id => $v) { diff --git a/src/Symfony/Component/Config/Resource/ClassExistenceResource.php b/src/Symfony/Component/Config/Resource/ClassExistenceResource.php index 1ba8e76248322..4e0d0d834e6ab 100644 --- a/src/Symfony/Component/Config/Resource/ClassExistenceResource.php +++ b/src/Symfony/Component/Config/Resource/ClassExistenceResource.php @@ -72,7 +72,7 @@ public function isFresh($timestamp) spl_autoload_register(__CLASS__.'::throwOnRequiredClass'); } $autoloadedClass = self::$autoloadedClass; - self::$autoloadedClass = $this->resource; + self::$autoloadedClass = ltrim($this->resource, '\\'); try { $exists = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false); @@ -161,7 +161,7 @@ public static function throwOnRequiredClass($class, \Exception $previous = null) throw $e; } - $trace = $e->getTrace(); + $trace = debug_backtrace(); $autoloadFrame = [ 'function' => 'spl_autoload_call', 'args' => [$class], @@ -191,15 +191,17 @@ public static function throwOnRequiredClass($class, \Exception $previous = null) } $props = [ - 'file' => $trace[$i]['file'], - 'line' => $trace[$i]['line'], + 'file' => isset($trace[$i]['file']) ? $trace[$i]['file'] : null, + 'line' => isset($trace[$i]['line']) ? $trace[$i]['line'] : null, 'trace' => \array_slice($trace, 1 + $i), ]; foreach ($props as $p => $v) { - $r = new \ReflectionProperty('Exception', $p); - $r->setAccessible(true); - $r->setValue($e, $v); + if (null !== $v) { + $r = new \ReflectionProperty('Exception', $p); + $r->setAccessible(true); + $r->setValue($e, $v); + } } } diff --git a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php index d5e6b829cfeca..4c8f89cd3f204 100644 --- a/src/Symfony/Component/Config/Resource/ReflectionClassResource.php +++ b/src/Symfony/Component/Config/Resource/ReflectionClassResource.php @@ -151,12 +151,56 @@ private function generateSignature(\ReflectionClass $class) } } else { foreach ($class->getMethods(\ReflectionMethod::IS_PUBLIC | \ReflectionMethod::IS_PROTECTED) as $m) { - yield preg_replace('/^ @@.*/m', '', $m); - $defaults = []; + $parametersWithUndefinedConstants = []; foreach ($m->getParameters() as $p) { - $defaults[$p->name] = $p->isDefaultValueAvailable() ? $p->getDefaultValue() : null; + if (!$p->isDefaultValueAvailable()) { + $defaults[$p->name] = null; + + continue; + } + + if (!$p->isDefaultValueConstant() || \defined($p->getDefaultValueConstantName())) { + $defaults[$p->name] = $p->getDefaultValue(); + + continue; + } + + $defaults[$p->name] = $p->getDefaultValueConstantName(); + $parametersWithUndefinedConstants[$p->name] = true; + } + + if (!$parametersWithUndefinedConstants) { + yield preg_replace('/^ @@.*/m', '', $m); + } else { + $stack = [ + $m->getDocComment(), + $m->getName(), + $m->isAbstract(), + $m->isFinal(), + $m->isStatic(), + $m->isPublic(), + $m->isPrivate(), + $m->isProtected(), + $m->returnsReference(), + \PHP_VERSION_ID >= 70000 && $m->hasReturnType() ? (\PHP_VERSION_ID >= 70100 ? $m->getReturnType()->getName() : (string) $m->getReturnType()) : '', + ]; + + foreach ($m->getParameters() as $p) { + if (!isset($parametersWithUndefinedConstants[$p->name])) { + $stack[] = (string) $p; + } else { + $stack[] = $p->isOptional(); + $stack[] = \PHP_VERSION_ID >= 70000 && $p->hasType() ? (\PHP_VERSION_ID >= 70100 ? $p->getType()->getName() : (string) $p->getType()) : ''; + $stack[] = $p->isPassedByReference(); + $stack[] = \PHP_VERSION_ID >= 50600 ? $p->isVariadic() : ''; + $stack[] = $p->getName(); + } + } + + yield implode(',', $stack); } + yield print_r($defaults, true); } } diff --git a/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php b/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php index 76cad1433bb20..74ed6b3edc2a9 100644 --- a/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php +++ b/src/Symfony/Component/Config/Tests/Resource/ReflectionClassResourceTest.php @@ -63,8 +63,12 @@ public function testIsFreshForDeletedResources() /** * @dataProvider provideHashedSignature */ - public function testHashedSignature($changeExpected, $changedLine, $changedCode) + public function testHashedSignature($changeExpected, $changedLine, $changedCode, $setContext = null) { + if ($setContext) { + $setContext(); + } + $code = <<<'EOPHP' /* 0*/ /* 1*/ class %s extends ErrorException @@ -82,7 +86,9 @@ public function testHashedSignature($changeExpected, $changedLine, $changedCode) /*13*/ protected function prot($a = []) {} /*14*/ /*15*/ private function priv() {} -/*16*/ } +/*16*/ +/*17*/ public function ccc($bar = A_CONSTANT_THAT_FOR_SURE_WILL_NEVER_BE_DEFINED_CCCCCC) {} +/*18*/ } EOPHP; static $expectedSignature, $generateSignature; @@ -97,7 +103,9 @@ public function testHashedSignature($changeExpected, $changedLine, $changedCode) } $code = explode("\n", $code); - $code[$changedLine] = $changedCode; + if (null !== $changedCode) { + $code[$changedLine] = $changedCode; + } eval(sprintf(implode("\n", $code), $class = 'Foo'.str_replace('.', '_', uniqid('', true)))); $signature = implode("\n", iterator_to_array($generateSignature(new \ReflectionClass($class)))); @@ -145,6 +153,10 @@ public function provideHashedSignature() yield [0, 7, 'protected int $prot;']; yield [0, 9, 'private string $priv;']; } + + yield [1, 17, 'public function ccc($bar = 187) {}']; + yield [1, 17, 'public function ccc($bar = ANOTHER_ONE_THAT_WILL_NEVER_BE_DEFINED_CCCCCCCCC) {}']; + yield [1, 17, null, static function () { \define('A_CONSTANT_THAT_FOR_SURE_WILL_NEVER_BE_DEFINED_CCCCCC', 'foo'); }]; } public function testEventSubscriber() diff --git a/src/Symfony/Component/Console/Descriptor/ApplicationDescription.php b/src/Symfony/Component/Console/Descriptor/ApplicationDescription.php index 442a569711c07..7e214712da6f3 100644 --- a/src/Symfony/Component/Console/Descriptor/ApplicationDescription.php +++ b/src/Symfony/Component/Console/Descriptor/ApplicationDescription.php @@ -129,23 +129,29 @@ private function sortCommands(array $commands) { $namespacedCommands = []; $globalCommands = []; + $sortedCommands = []; foreach ($commands as $name => $command) { $key = $this->application->extractNamespace($name, 1); - if (!$key) { - $globalCommands['_global'][$name] = $command; + if (\in_array($key, ['', self::GLOBAL_NAMESPACE], true)) { + $globalCommands[$name] = $command; } else { $namespacedCommands[$key][$name] = $command; } } - ksort($namespacedCommands); - $namespacedCommands = array_merge($globalCommands, $namespacedCommands); - foreach ($namespacedCommands as &$commandsSet) { - ksort($commandsSet); + if ($globalCommands) { + ksort($globalCommands); + $sortedCommands[self::GLOBAL_NAMESPACE] = $globalCommands; } - // unset reference to keep scope clear - unset($commandsSet); - return $namespacedCommands; + if ($namespacedCommands) { + ksort($namespacedCommands); + foreach ($namespacedCommands as $key => $commandsSet) { + ksort($commandsSet); + $sortedCommands[$key] = $commandsSet; + } + } + + return $sortedCommands; } } diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php index af4d0b9cca459..1f93c06451630 100644 --- a/src/Symfony/Component/Console/Helper/QuestionHelper.php +++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php @@ -264,7 +264,7 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu } elseif ("\177" === $c) { // Backspace Character if (0 === $numMatches && 0 !== $i) { --$i; - $fullChoice = substr($fullChoice, 0, -1); + $fullChoice = self::substr($fullChoice, 0, $i); // Move cursor backwards $output->write("\033[1D"); } @@ -278,7 +278,7 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu } // Pop the last character off the end of our string - $ret = substr($ret, 0, $i); + $ret = self::substr($ret, 0, $i); } elseif ("\033" === $c) { // Did we read an escape sequence? $c .= fread($inputStream, 2); @@ -304,7 +304,7 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu $remainingCharacters = substr($ret, \strlen(trim($this->mostRecentlyEnteredValue($fullChoice)))); $output->write($remainingCharacters); $fullChoice .= $remainingCharacters; - $i = \strlen($fullChoice); + $i = self::strlen($fullChoice); } if ("\n" === $c) { diff --git a/src/Symfony/Component/Console/Input/ArrayInput.php b/src/Symfony/Component/Console/Input/ArrayInput.php index a04b6b68ea0c8..b2ebc7c2258e2 100644 --- a/src/Symfony/Component/Console/Input/ArrayInput.php +++ b/src/Symfony/Component/Console/Input/ArrayInput.php @@ -39,8 +39,8 @@ public function __construct(array $parameters, InputDefinition $definition = nul */ public function getFirstArgument() { - foreach ($this->parameters as $key => $value) { - if ($key && '-' === $key[0]) { + foreach ($this->parameters as $param => $value) { + if ($param && \is_string($param) && '-' === $param[0]) { continue; } @@ -107,7 +107,7 @@ public function __toString() { $params = []; foreach ($this->parameters as $param => $val) { - if ($param && '-' === $param[0]) { + if ($param && \is_string($param) && '-' === $param[0]) { if (\is_array($val)) { foreach ($val as $v) { $params[] = $param.('' != $v ? '='.$this->escapeToken($v) : ''); diff --git a/src/Symfony/Component/Console/Tests/Descriptor/ApplicationDescriptionTest.php b/src/Symfony/Component/Console/Tests/Descriptor/ApplicationDescriptionTest.php new file mode 100644 index 0000000000000..33d5c3840f3e3 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Descriptor/ApplicationDescriptionTest.php @@ -0,0 +1,53 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Tests\Descriptor; + +use PHPUnit\Framework\TestCase; +use Symfony\Component\Console\Application; +use Symfony\Component\Console\Command\Command; +use Symfony\Component\Console\Descriptor\ApplicationDescription; + +final class ApplicationDescriptionTest extends TestCase +{ + /** + * @dataProvider getNamespacesProvider + */ + public function testGetNamespaces(array $expected, array $names) + { + $application = new TestApplication(); + foreach ($names as $name) { + $application->add(new Command($name)); + } + + $this->assertSame($expected, array_keys((new ApplicationDescription($application))->getNamespaces())); + } + + public function getNamespacesProvider() + { + return [ + [['_global'], ['foobar']], + [['a', 'b'], ['b:foo', 'a:foo', 'b:bar']], + [['_global', 'b', 'z', 22, 33], ['z:foo', '1', '33:foo', 'b:foo', '22:foo:bar']], + ]; + } +} + +final class TestApplication extends Application +{ + /** + * {@inheritdoc} + */ + protected function getDefaultCommands() + { + return []; + } +} diff --git a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php index 02cc6ce7e0249..d2afee42ffa26 100644 --- a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php @@ -175,19 +175,20 @@ public function testAskWithAutocomplete() // Acm // AcsTest // - // - // Test + // + // Test // // S // F00oo - $inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n\033[A\033[A\n\033[A\033[A\033[A\033[A\033[A\tTest\n\033[B\nS\177\177\033[B\033[B\nF00\177\177oo\t\n"); + // F⭐ + $inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n\033[A\033[A\033[A\n\033[A\033[A\033[A\033[A\033[A\033[A\033[A\tTest\n\033[B\nS\177\177\033[B\033[B\nF00\177\177oo\t\nF⭐\t\177\177⭐\t\n"); $dialog = new QuestionHelper(); $helperSet = new HelperSet([new FormatterHelper()]); $dialog->setHelperSet($helperSet); $question = new Question('Please select a bundle', 'FrameworkBundle'); - $question->setAutocompleterValues(['AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle']); + $question->setAutocompleterValues(['AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle', 'F⭐Y']); $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); $this->assertEquals('AsseticBundleTest', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); @@ -197,6 +198,7 @@ public function testAskWithAutocomplete() $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); $this->assertEquals('AsseticBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); $this->assertEquals('FooBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); + $this->assertEquals('F⭐Y', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); } public function testAskWithAutocompleteWithNonSequentialKeys() @@ -680,12 +682,13 @@ public function testLegacyAskWithAutocomplete() // Acm // AcsTest // - // - // Test + // + // Test // // S // F00oo - $inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n\033[A\033[A\n\033[A\033[A\033[A\033[A\033[A\tTest\n\033[B\nS\177\177\033[B\033[B\nF00\177\177oo\t\n"); + // F⭐⭐ + $inputStream = $this->getInputStream("Acm\nAc\177\177s\tTest\n\n\033[A\033[A\033[A\n\033[A\033[A\033[A\033[A\033[A\033[A\033[A\tTest\n\033[B\nS\177\177\033[B\033[B\nF00\177\177oo\t\nF⭐\t⭐\t\n"); $dialog = new QuestionHelper(); $dialog->setInputStream($inputStream); @@ -693,7 +696,7 @@ public function testLegacyAskWithAutocomplete() $dialog->setHelperSet($helperSet); $question = new Question('Please select a bundle', 'FrameworkBundle'); - $question->setAutocompleterValues(['AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle']); + $question->setAutocompleterValues(['AcmeDemoBundle', 'AsseticBundle', 'SecurityBundle', 'FooBundle', 'F⭐Y']); $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); $this->assertEquals('AsseticBundleTest', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); @@ -703,6 +706,7 @@ public function testLegacyAskWithAutocomplete() $this->assertEquals('AcmeDemoBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); $this->assertEquals('AsseticBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); $this->assertEquals('FooBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question)); + $this->assertEquals('F⭐Y', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); } /** diff --git a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php index cfc932843937f..eff421ec4e71f 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/XmlDumper.php @@ -304,6 +304,11 @@ private function convertParameters(array $parameters, $type, \DOMElement $parent if (\in_array($value, ['null', 'true', 'false'], true)) { $element->setAttribute('type', 'string'); } + + if (\is_string($value) && (is_numeric($value) || preg_match('/^0b[01]*$/', $value) || preg_match('/^0x[0-9a-f]++$/i', $value))) { + $element->setAttribute('type', 'string'); + } + $text = $this->document->createTextNode(self::phpToXml($value)); $element->appendChild($text); } diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index c4b9b69a03ca2..bd2902f85681a 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -278,7 +278,7 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults) $definition->setDeprecated(true, $deprecated[0]->nodeValue ?: null); } - $definition->setArguments($this->getArgumentsAsPhp($service, 'argument', $file, false, $definition instanceof ChildDefinition)); + $definition->setArguments($this->getArgumentsAsPhp($service, 'argument', $file, $definition instanceof ChildDefinition)); $definition->setProperties($this->getArgumentsAsPhp($service, 'property', $file)); if ($factories = $this->getChildren($service, 'factory')) { @@ -452,11 +452,10 @@ private function processAnonymousServices(\DOMDocument $xml, $file, $defaults) * * @param string $name * @param string $file - * @param bool $lowercase * * @return mixed */ - private function getArgumentsAsPhp(\DOMElement $node, $name, $file, $lowercase = true, $isChildDefinition = false) + private function getArgumentsAsPhp(\DOMElement $node, $name, $file, $isChildDefinition = false) { $arguments = []; foreach ($this->getChildren($node, $name) as $arg) { @@ -506,10 +505,10 @@ private function getArgumentsAsPhp(\DOMElement $node, $name, $file, $lowercase = $arguments[$key] = new Expression($arg->nodeValue); break; case 'collection': - $arguments[$key] = $this->getArgumentsAsPhp($arg, $name, $file, false); + $arguments[$key] = $this->getArgumentsAsPhp($arg, $name, $file); break; case 'iterator': - $arg = $this->getArgumentsAsPhp($arg, $name, $file, false); + $arg = $this->getArgumentsAsPhp($arg, $name, $file); try { $arguments[$key] = new IteratorArgument($arg); } catch (InvalidArgumentException $e) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php index fd526caa94264..bfd3d67238277 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveBindingsPassTest.php @@ -18,7 +18,6 @@ use Symfony\Component\DependencyInjection\Compiler\ResolveBindingsPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Definition; -use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Tests\Fixtures\CaseSensitiveClass; use Symfony\Component\DependencyInjection\Tests\Fixtures\NamedArgumentsDummy; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container8.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container8.php index 5b3c01c23cd52..edcd045eaabbb 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container8.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container8.php @@ -9,6 +9,17 @@ 'bar' => 'foo is %%foo bar', 'escape' => '@escapeme', 'values' => [true, false, null, 0, 1000.3, 'true', 'false', 'null'], + 'null string' => 'null', + 'string of digits' => '123', + 'string of digits prefixed with minus character' => '-123', + 'true string' => 'true', + 'false string' => 'false', + 'binary number string' => '0b0110', + 'numeric string' => '-1.2E2', + 'hexadecimal number string' => '0xFF', + 'float string' => '10100.1', + 'positive float string' => '+10100.1', + 'negative float string' => '-10100.1', ])); return $container; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services8.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services8.php index ce4815ef81975..e7a0214a10f53 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services8.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services8.php @@ -151,6 +151,17 @@ protected function getDefaultParameters() 6 => 'false', 7 => 'null', ], + 'null string' => 'null', + 'string of digits' => '123', + 'string of digits prefixed with minus character' => '-123', + 'true string' => 'true', + 'false string' => 'false', + 'binary number string' => '0b0110', + 'numeric string' => '-1.2E2', + 'hexadecimal number string' => '0xFF', + 'float string' => '10100.1', + 'positive float string' => '+10100.1', + 'negative float string' => '-10100.1', ]; } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services8.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services8.xml index d0f9015c5a547..4b07bbb7da50c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services8.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services8.xml @@ -18,6 +18,17 @@ false null + null + 123 + -123 + true + false + 0b0110 + -1.2E2 + 0xFF + 10100.1 + +10100.1 + -10100.1 diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services8.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services8.yml index 4e37bc9315c9b..002b1d4bcd3a8 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services8.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services8.yml @@ -4,6 +4,17 @@ parameters: bar: 'foo is %%foo bar' escape: '@@escapeme' values: [true, false, null, 0, 1000.3, 'true', 'false', 'null'] + null string: 'null' + string of digits: '123' + string of digits prefixed with minus character: '-123' + true string: 'true' + false string: 'false' + binary number string: '0b0110' + numeric string: '-1.2E2' + hexadecimal number string: '0xFF' + float string: '10100.1' + positive float string: '+10100.1' + negative float string: '-10100.1' services: service_container: diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 1d187848b3b39..cce3921853e5d 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -349,6 +349,9 @@ public function testParsesIteratorArgument() $lazyDefinition = $container->getDefinition('lazy_context'); $this->assertEquals([new IteratorArgument(['k1' => new Reference('foo.baz'), 'k2' => new Reference('service_container')]), new IteratorArgument([])], $lazyDefinition->getArguments(), '->load() parses lazy arguments'); + + $message = 'The "deprecated_service" service is deprecated. You should stop using it, as it will soon be removed.'; + $this->assertSame($message, $container->getDefinition('deprecated_service')->getDeprecationMessage('deprecated_service')); } public function testAutowire() @@ -717,4 +720,17 @@ public function testOverriddenDefaultsBindings() $this->assertSame('overridden', $container->get('bar')->quz); } + + /** + * @group legacy + * @expectedDeprecation The configuration key "factory" is unsupported for the service "foo" which is defined as an alias in %s. + * @expectedDeprecation The configuration key "parent" is unsupported for the service "foo" which is defined as an alias in %s. + */ + public function testAliasDefinitionContainsUnsupportedElements() + { + $container = new ContainerBuilder(); + $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml')); + $loader->load('legacy_invalid_alias_definition.yml'); + $this->assertTrue($container->has('foo')); + } } diff --git a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php index a5b7f6dceb51f..e9e7784a3af40 100644 --- a/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php +++ b/src/Symfony/Component/Filesystem/Tests/FilesystemTest.php @@ -801,7 +801,7 @@ public function testSymlink() $file = $this->workspace.\DIRECTORY_SEPARATOR.'file'; $link = $this->workspace.\DIRECTORY_SEPARATOR.'link'; - // $file does not exists right now: creating "broken" links is a wanted feature + // $file does not exist right now: creating "broken" links is a wanted feature $this->filesystem->symlink($file, $link); $this->assertTrue(is_link($link)); diff --git a/src/Symfony/Component/Finder/Finder.php b/src/Symfony/Component/Finder/Finder.php index 6624e840791fb..d2ea17d87a00f 100644 --- a/src/Symfony/Component/Finder/Finder.php +++ b/src/Symfony/Component/Finder/Finder.php @@ -736,7 +736,7 @@ private function searchInDirectory($dir) /** * Normalizes given directory names by removing trailing slashes. * - * Excluding: (s)ftp:// wrapper + * Excluding: (s)ftp:// or ssh2.(s)ftp:// wrapper * * @param string $dir * @@ -746,7 +746,7 @@ private function normalizeDir($dir) { $dir = rtrim($dir, '/'.\DIRECTORY_SEPARATOR); - if (preg_match('#^s?ftp://#', $dir)) { + if (preg_match('#^(ssh2\.)?s?ftp://#', $dir)) { $dir .= '/'; } diff --git a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php index f43114111b076..ea7ac846974bd 100644 --- a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php +++ b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php @@ -348,7 +348,7 @@ public static function trustXSendfileTypeHeader() } /** - * If this is set to true, the file will be unlinked after the request is send + * If this is set to true, the file will be unlinked after the request is sent * Note: If the X-Sendfile header is used, the deleteFileAfterSend setting will not be used. * * @param bool $shouldDelete diff --git a/src/Symfony/Component/HttpFoundation/RedirectResponse.php b/src/Symfony/Component/HttpFoundation/RedirectResponse.php index 4e3cb4f77b28b..a19efba3e3d5e 100644 --- a/src/Symfony/Component/HttpFoundation/RedirectResponse.php +++ b/src/Symfony/Component/HttpFoundation/RedirectResponse.php @@ -93,7 +93,7 @@ public function setTargetUrl($url) - + Redirecting to %1$s diff --git a/src/Symfony/Component/HttpFoundation/ServerBag.php b/src/Symfony/Component/HttpFoundation/ServerBag.php index 4c82b1774873f..f3b64023489ef 100644 --- a/src/Symfony/Component/HttpFoundation/ServerBag.php +++ b/src/Symfony/Component/HttpFoundation/ServerBag.php @@ -46,13 +46,13 @@ public function getHeaders() /* * php-cgi under Apache does not pass HTTP Basic user/pass to PHP by default * For this workaround to work, add these lines to your .htaccess file: - * RewriteCond %{HTTP:Authorization} ^(.+)$ - * RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + * RewriteCond %{HTTP:Authorization} .+ + * RewriteRule ^ - [E=HTTP_AUTHORIZATION:%0] * * A sample .htaccess file: * RewriteEngine On - * RewriteCond %{HTTP:Authorization} ^(.+)$ - * RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] + * RewriteCond %{HTTP:Authorization} .+ + * RewriteRule ^ - [E=HTTP_AUTHORIZATION:%0] * RewriteCond %{REQUEST_FILENAME} !-f * RewriteRule ^(.*)$ app.php [QSA,L] */ diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php index f9e5d1e8f04d8..c9d47b6ed7c27 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php @@ -218,7 +218,7 @@ public function createTable() // - trailing space removal // - case-insensitivity // - language processing like é == e - $sql = "CREATE TABLE $this->table ($this->idCol VARBINARY(128) NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol MEDIUMINT NOT NULL, $this->timeCol INTEGER UNSIGNED NOT NULL) COLLATE utf8_bin, ENGINE = InnoDB"; + $sql = "CREATE TABLE $this->table ($this->idCol VARBINARY(128) NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER UNSIGNED NOT NULL, $this->timeCol INTEGER UNSIGNED NOT NULL) COLLATE utf8_bin, ENGINE = InnoDB"; break; case 'sqlite': $sql = "CREATE TABLE $this->table ($this->idCol TEXT NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER NOT NULL, $this->timeCol INTEGER NOT NULL)"; diff --git a/src/Symfony/Component/HttpFoundation/Tests/RedirectResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/RedirectResponseTest.php index e1ff3bf2bdb98..2bbf5aa1aea5a 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RedirectResponseTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RedirectResponseTest.php @@ -20,10 +20,7 @@ public function testGenerateMetaRedirect() { $response = new RedirectResponse('foo.bar'); - $this->assertEquals(1, preg_match( - '##', - preg_replace(['/\s+/', '/\'/'], [' ', '"'], $response->getContent()) - )); + $this->assertRegExp('##', preg_replace('/\s+/', ' ', $response->getContent())); } public function testRedirectResponseConstructorNullUrl() diff --git a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php index addeca8bae143..dbe028065948d 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php @@ -352,7 +352,9 @@ protected function validate(Request $request, Response $entry, $catch = false) } // add our cached last-modified validator - $subRequest->headers->set('if_modified_since', $entry->headers->get('Last-Modified')); + if ($entry->headers->has('Last-Modified')) { + $subRequest->headers->set('if_modified_since', $entry->headers->get('Last-Modified')); + } // Add our cached etag validator to the environment. // We keep the etags from the client to handle the case when the client diff --git a/src/Symfony/Component/HttpKernel/HttpKernel.php b/src/Symfony/Component/HttpKernel/HttpKernel.php index bca2cd1688e8e..9769d5e802b2d 100644 --- a/src/Symfony/Component/HttpKernel/HttpKernel.php +++ b/src/Symfony/Component/HttpKernel/HttpKernel.php @@ -62,7 +62,7 @@ public function __construct(EventDispatcherInterface $dispatcher, ControllerReso */ public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true) { - $request->headers->set('X-Php-Ob-Level', ob_get_level()); + $request->headers->set('X-Php-Ob-Level', (string) ob_get_level()); try { return $this->handleRaw($request, $type); diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 05b11f3665c5c..434174d5b8635 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -67,11 +67,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '3.4.35'; - const VERSION_ID = 30435; + const VERSION = '3.4.36'; + const VERSION_ID = 30436; const MAJOR_VERSION = 3; const MINOR_VERSION = 4; - const RELEASE_VERSION = 35; + const RELEASE_VERSION = 36; const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '11/2020'; diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php index a50e09fb14f93..93d92eb11e7e3 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php @@ -859,6 +859,7 @@ public function testValidatesCachedResponsesUseSameHttpMethod() public function testValidatesCachedResponsesWithETagAndNoFreshnessInformation() { $this->setNextResponse(200, [], 'Hello World', function ($request, $response) { + $this->assertFalse($request->headers->has('If-Modified-Since')); $response->headers->set('Cache-Control', 'public'); $response->headers->set('ETag', '"12345"'); if ($response->getETag() == $request->headers->get('IF_NONE_MATCH')) { diff --git a/src/Symfony/Component/Ldap/Ldap.php b/src/Symfony/Component/Ldap/Ldap.php index dda47b5376bb1..fd4955ef5d791 100644 --- a/src/Symfony/Component/Ldap/Ldap.php +++ b/src/Symfony/Component/Ldap/Ldap.php @@ -73,11 +73,7 @@ public function escape($subject, $ignore = '', $flags = 0) public static function create($adapter, array $config = []) { if (!isset(self::$adapterMap[$adapter])) { - throw new DriverNotFoundException(sprintf( - 'Adapter "%s" not found. You should use one of: %s', - $adapter, - implode(', ', self::$adapterMap) - )); + throw new DriverNotFoundException(sprintf('Adapter "%s" not found. You should use one of: %s', $adapter, implode(', ', self::$adapterMap))); } $class = self::$adapterMap[$adapter]; diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 9aab91638cbd9..4297d3947ff53 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -260,13 +260,14 @@ private static function throwInvalidArgumentException($message, $trace, $i) return; } - if (isset($trace[$i]['file']) && __FILE__ === $trace[$i]['file'] && \array_key_exists(0, $trace[$i]['args'])) { + if (isset($trace[$i]['file']) && __FILE__ === $trace[$i]['file']) { $pos = strpos($message, $delim = 'must be of the type ') ?: (strpos($message, $delim = 'must be an instance of ') ?: strpos($message, $delim = 'must implement interface ')); $pos += \strlen($delim); - $type = $trace[$i]['args'][0]; - $type = \is_object($type) ? \get_class($type) : \gettype($type); + $j = strpos($message, ',', $pos); + $type = substr($message, 2 + $j, strpos($message, ' given', $j) - $j - 2); + $message = substr($message, $pos, $j - $pos); - throw new InvalidArgumentException(sprintf('Expected argument of type "%s", "%s" given', substr($message, $pos, strpos($message, ',', $pos) - $pos), $type)); + throw new InvalidArgumentException(sprintf('Expected argument of type "%s", "%s" given', $message, 'NULL' === $type ? 'null' : $type)); } } diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php index d7ee358e07a79..0eb4baacf222d 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php @@ -532,7 +532,7 @@ public function testThrowTypeError() public function testThrowTypeErrorWithNullArgument() { $this->expectException('Symfony\Component\PropertyAccess\Exception\InvalidArgumentException'); - $this->expectExceptionMessage('Expected argument of type "DateTime", "NULL" given'); + $this->expectExceptionMessage('Expected argument of type "DateTime", "null" given'); $object = new TypeHinted(); $this->propertyAccessor->setValue($object, 'date', null); diff --git a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php index 663ebcbefaaec..b8599b23ad759 100644 --- a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php +++ b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php @@ -80,9 +80,7 @@ public function match($pathinfo) throw new NoConfigurationException(); } - throw 0 < \count($this->allow) - ? new MethodNotAllowedException(array_unique($this->allow)) - : new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo)); + throw 0 < \count($this->allow) ? new MethodNotAllowedException(array_unique($this->allow)) : new ResourceNotFoundException(sprintf('No routes found for "%s".', $pathinfo)); } /** diff --git a/src/Symfony/Component/Routing/RequestContext.php b/src/Symfony/Component/Routing/RequestContext.php index 8ebad8e2538db..ed50cd70d835a 100644 --- a/src/Symfony/Component/Routing/RequestContext.php +++ b/src/Symfony/Component/Routing/RequestContext.php @@ -67,8 +67,8 @@ public function fromRequest(Request $request) $this->setMethod($request->getMethod()); $this->setHost($request->getHost()); $this->setScheme($request->getScheme()); - $this->setHttpPort($request->isSecure() ? $this->httpPort : $request->getPort()); - $this->setHttpsPort($request->isSecure() ? $request->getPort() : $this->httpsPort); + $this->setHttpPort($request->isSecure() || null === $request->getPort() ? $this->httpPort : $request->getPort()); + $this->setHttpsPort($request->isSecure() && null !== $request->getPort() ? $request->getPort() : $this->httpsPort); $this->setQueryString($request->server->get('QUERY_STRING', '')); return $this; diff --git a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php index c6b89793e66e7..ea9f51f9224ad 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php @@ -27,6 +27,7 @@ use Symfony\Component\Security\Core\Role\SwitchUserRole; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; +use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface; /** * ContextListener manages the SecurityContext persistence through a session. @@ -44,6 +45,7 @@ class ContextListener implements ListenerInterface private $registered; private $trustResolver; private $logoutOnUserChange = false; + private $rememberMeServices; /** * @param iterable|UserProviderInterface[] $userProviders @@ -103,6 +105,10 @@ public function handle(GetResponseEvent $event) if ($token instanceof TokenInterface) { $token = $this->refreshUser($token); + + if (!$token && $this->logoutOnUserChange && $this->rememberMeServices) { + $this->rememberMeServices->loginFail($request); + } } elseif (null !== $token) { if (null !== $this->logger) { $this->logger->warning('Expected a security token from the session, got something else.', ['key' => $this->sessionKey, 'received' => $token]); @@ -268,4 +274,9 @@ public static function handleUnserializeCallback($class) { throw new \UnexpectedValueException('Class not found: '.$class, 0x37313bc); } + + public function setRememberMeServices(RememberMeServicesInterface $rememberMeServices) + { + $this->rememberMeServices = $rememberMeServices; + } } diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php index 25915f212a4c0..acab7087cb92f 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php @@ -31,6 +31,7 @@ use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Core\User\UserProviderInterface; use Symfony\Component\Security\Http\Firewall\ContextListener; +use Symfony\Component\Security\Http\RememberMe\RememberMeServicesInterface; class ContextListenerTest extends TestCase { @@ -278,6 +279,19 @@ public function testIfTokenIsNotDeauthenticated() $this->assertSame($goodRefreshedUser, $tokenStorage->getToken()->getUser()); } + public function testRememberMeGetsCanceledIfTokenIsDeauthenticated() + { + $tokenStorage = new TokenStorage(); + $refreshedUser = new User('foobar', 'baz'); + + $rememberMeServices = $this->createMock(RememberMeServicesInterface::class); + $rememberMeServices->expects($this->once())->method('loginFail'); + + $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(), new SupportingUserProvider($refreshedUser)], null, true, $rememberMeServices); + + $this->assertNull($tokenStorage->getToken()); + } + public function testTryAllUserProvidersUntilASupportingUserProviderIsFound() { $tokenStorage = new TokenStorage(); @@ -347,7 +361,7 @@ protected function runSessionOnKernelResponse($newToken, $original = null) return $session; } - private function handleEventWithPreviousSession(TokenStorageInterface $tokenStorage, $userProviders, UserInterface $user = null, $logoutOnUserChange = false) + private function handleEventWithPreviousSession(TokenStorageInterface $tokenStorage, $userProviders, UserInterface $user = null, $logoutOnUserChange = false, RememberMeServicesInterface $rememberMeServices = null) { $user = $user ?: new User('foo', 'bar'); $session = new Session(new MockArraySessionStorage()); @@ -359,6 +373,10 @@ private function handleEventWithPreviousSession(TokenStorageInterface $tokenStor $listener = new ContextListener($tokenStorage, $userProviders, 'context_key'); $listener->setLogoutOnUserChange($logoutOnUserChange); + + if ($rememberMeServices) { + $listener->setRememberMeServices($rememberMeServices); + } $listener->handle(new GetResponseEvent($this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(), $request, HttpKernelInterface::MASTER_REQUEST)); } } diff --git a/src/Symfony/Component/Security/Http/Tests/FirewallTest.php b/src/Symfony/Component/Security/Http/Tests/FirewallTest.php index 774db6128f379..3114f2da17812 100644 --- a/src/Symfony/Component/Security/Http/Tests/FirewallTest.php +++ b/src/Symfony/Component/Security/Http/Tests/FirewallTest.php @@ -12,7 +12,6 @@ namespace Symfony\Component\Security\Http\Tests; use PHPUnit\Framework\TestCase; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Event\GetResponseEvent; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\Security\Http\Firewall; diff --git a/src/Symfony/Component/Serializer/Mapping/Factory/ClassResolverTrait.php b/src/Symfony/Component/Serializer/Mapping/Factory/ClassResolverTrait.php index 73c02a647c57e..5c58476383427 100644 --- a/src/Symfony/Component/Serializer/Mapping/Factory/ClassResolverTrait.php +++ b/src/Symfony/Component/Serializer/Mapping/Factory/ClassResolverTrait.php @@ -29,7 +29,7 @@ trait ClassResolverTrait * * @return string * - * @throws InvalidArgumentException If the class does not exists + * @throws InvalidArgumentException If the class does not exist */ private function getClass($value) { diff --git a/src/Symfony/Component/Translation/Dumper/XliffFileDumper.php b/src/Symfony/Component/Translation/Dumper/XliffFileDumper.php index cd867b0967908..f933be8b258df 100644 --- a/src/Symfony/Component/Translation/Dumper/XliffFileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/XliffFileDumper.php @@ -41,7 +41,7 @@ public function formatCatalogue(MessageCatalogue $messages, $domain, array $opti return $this->dumpXliff1($defaultLocale, $messages, $domain, $options); } if ('2.0' === $xliffVersion) { - return $this->dumpXliff2($defaultLocale, $messages, $domain, $options); + return $this->dumpXliff2($defaultLocale, $messages, $domain); } throw new InvalidArgumentException(sprintf('No support implemented for dumping XLIFF version "%s".', $xliffVersion)); @@ -129,7 +129,7 @@ private function dumpXliff1($defaultLocale, MessageCatalogue $messages, $domain, return $dom->saveXML(); } - private function dumpXliff2($defaultLocale, MessageCatalogue $messages, $domain, array $options = []) + private function dumpXliff2($defaultLocale, MessageCatalogue $messages, $domain) { $dom = new \DOMDocument('1.0', 'utf-8'); $dom->formatOutput = true; diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf index 5a391a2e6626e..21e2392c7d96c 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf @@ -362,6 +362,10 @@ This password has been leaked in a data breach, it must not be used. Please use another password. このパスワードは漏洩している為使用できません。 + + This value should be between {{ min }} and {{ max }}. + {{ min }}以上{{ max }}以下でなければなりません。 + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf index 6f5fd98ca192e..cb12a8a9daa4d 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf @@ -318,6 +318,54 @@ Error Napaka + + This is not a valid UUID. + To ni veljaven UUID. + + + This value should be a multiple of {{ compared_value }}. + Ta vrednost bi morala biti večkratnik od {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Ta poslovna identifikacijska koda (BIC) ni povezana z IBAN {{ iban }}. + + + This value should be valid JSON. + Ta vrednost bi morala biti veljaven JSON. + + + This collection should contain only unique elements. + Ta zbirka bi morala vsebovati samo edinstvene elemente. + + + This value should be positive. + Ta vrednost bi morala biti pozitivna. + + + This value should be either positive or zero. + Ta vrednost bi morala biti pozitivna ali enaka nič. + + + This value should be negative. + Ta vrednost bi morala biti negativna. + + + This value should be either negative or zero. + Ta vrednost bi morala biti negativna ali enaka nič. + + + This value is not a valid timezone. + Ta vrednost ni veljaven časovni pas. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + To geslo je ušlo pri kršitvi varnosti podatkov in ga ne smete uporabljati. Prosimo, uporabite drugo geslo. + + + This value should be between {{ min }} and {{ max }}. + Ta vrednost bi morala biti med {{ min }} in {{ max }}. + diff --git a/src/Symfony/Component/Validator/Test/ConstraintValidatorTestCase.php b/src/Symfony/Component/Validator/Test/ConstraintValidatorTestCase.php index 18705b7987efe..ed57d396ae00e 100644 --- a/src/Symfony/Component/Validator/Test/ConstraintValidatorTestCase.php +++ b/src/Symfony/Component/Validator/Test/ConstraintValidatorTestCase.php @@ -177,7 +177,8 @@ protected function expectValidateAt($i, $propertyPath, $value, $group) ->willReturn($validator); $validator->expects($this->at(2 * $i + 1)) ->method('validate') - ->with($value, $this->logicalOr(null, [], $this->isInstanceOf('\Symfony\Component\Validator\Constraints\Valid')), $group); + ->with($value, $this->logicalOr(null, [], $this->isInstanceOf('\Symfony\Component\Validator\Constraints\Valid')), $group) + ->willReturn($validator); } protected function expectValidateValueAt($i, $propertyPath, $value, $constraints, $group = null) @@ -189,7 +190,8 @@ protected function expectValidateValueAt($i, $propertyPath, $value, $constraints ->willReturn($contextualValidator); $contextualValidator->expects($this->at(2 * $i + 1)) ->method('validate') - ->with($value, $constraints, $group); + ->with($value, $constraints, $group) + ->willReturn($contextualValidator); } protected function assertNoViolation()