diff --git a/CHANGELOG-5.2.md b/CHANGELOG-5.2.md index 5e5f455254f7..112bd2968ddf 100644 --- a/CHANGELOG-5.2.md +++ b/CHANGELOG-5.2.md @@ -7,6 +7,42 @@ in 5.2 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v5.2.0...v5.2.1 +* 5.2.7 (2021-05-01) + + * bug #41008 [Security] Do not try to rehash null-passwords (tjveldhuizen) + * bug #40993 [Security] [Security/Core] fix checking for bcrypt (nicolas-grekas) + * bug #40923 [Yaml] expose references detected in inline notation structures (xabbuh) + * bug #40964 [HttpFoundation] Fixes for PHP 8.1 deprecations (jrmajor) + * bug #40919 [Mailer] use correct spelling when accessing the SMTP php.ini value (xabbuh) + * bug #40514 [Yaml] Allow tabs as separators between tokens (bertramakers) + * bug #40882 [Cache] phpredis: Added full TLS support for RedisCluster (jackthomasatl) + * bug #40872 [DependencyInjection] [AliasDeprecatedPublicServicesPass] Noop when the service is private (fancyweb) + * bug #40802 [FrameworkBundle] Fix array controller link in debug:router (fancyweb) + * bug #40793 [DoctrineBridge] Add support for a driver type "attribute" (beberlei) + * bug #40807 RequestMatcher issue when `_controller` is a closure (Plopix) + * bug #40811 [PropertyInfo] Use the right context for methods defined in traits (colinodell) + * bug #40791 [WebProfilerBundle] Use ControllerReference instead of URL in twig render() (Foxprodev) + * bug #40330 [SecurityBundle] Empty line starting with dash under "access_control" causes all rules to be skipped (monteiro) + * bug #40780 [Cache] Apply NullAdapter as Null Object (roukmoute) + * bug #40740 [Cache][FrameworkBundle] Fix logging for TagAwareAdapter (fancyweb) + * bug #40755 [Routing] Better inline requirements and defaults parsing (Foxprodev) + * bug #40754 [PhpUnitBridge] Fix phpunit symlink on Windows (johnstevenson) + * bug #40660 [Form] Fix 'invalid_message' use in multiple ChoiceType (alexandre-daubois) + * bug #40707 [Yaml] Fixed infinite loop when parser goes through an additional and invalid closing tag (alexandre-daubois) + * bug #40698 [Console] Add Helper::width() and Helper::length() (Nyholm, grasmash) + * bug #40679 [Debug][ErrorHandler] Avoid warning with Xdebug 3 with develop mode disabled (Jean85) + * bug #40702 [HttpClient] allow CurlHttpClient on Windows (n0rbyt3) + * bug #40503 [Yaml] fix parsing some block sequences (a1812) + * bug #40610 Fixed bugs found by psalm (Nyholm) + * bug #40603 [Config] Fixed support for nodes not extending BaseNode (Nyholm) + * bug #40658 [RateLimiter] Fix sleep value (jderusse) + * bug #40645 [FrameworkBundle] Dont store cache misses on warmup (Nyholm) + * bug #40629 [DependencyInjection] Fix "url" env var processor behavior when the url has no path (fancyweb) + * bug #40655 [Cache] skip storing failure-to-save as misses in ArrayAdapter (nicolas-grekas) + * bug #40522 [Serializer] Allow AbstractNormalizer to use null for non-optional nullable constructor parameters without default value (Pierre Rineau) + * bug #40595 add missing queue_name to find(id) in doctrine messenger transport (monteiro) + * bug #40619 [FrameworkBundle] dont access the container to configure http_cache (nicolas-grekas) + * 5.2.6 (2021-03-29) * bug #40598 [Form] error if the input string couldn't be parsed as a date (xabbuh) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 09e940bebd83..8a5518bb3390 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -33,10 +33,10 @@ The Symfony Connect username in parenthesis allows to get more information - Romain Neutron (romain) - Pascal Borreli (pborreli) - Joseph Bielawski (stloyd) + - Tobias Nyholm (tobias) - Karma Dordrak (drak) - Jules Pietri (heah) - Lukas Kahwe Smith (lsmith) - - Tobias Nyholm (tobias) - Martin Hasoň (hason) - Amrouche Hamza (simperfit) - Jeremy Mikola (jmikola) @@ -54,11 +54,11 @@ The Symfony Connect username in parenthesis allows to get more information - Matthias Pigulla (mpdude) - Diego Saint Esteben (dosten) - Valentin Udaltsov (vudaltsov) + - Kevin Bond (kbond) - Alexandre Salomé (alexandresalome) - William Durand (couac) - Grégoire Paris (greg0ire) - ornicar - - Kevin Bond (kbond) - Dany Maillard (maidmaid) - Francis Besset (francisbesset) - stealth35 ‏ (stealth35) @@ -184,6 +184,7 @@ The Symfony Connect username in parenthesis allows to get more information - Arman Hosseini (arman) - Niels Keurentjes (curry684) - Vyacheslav Pavlov + - Albert Casademont (acasademont) - George Mponos (gmponos) - Richard Shank (iampersistent) - Thomas Rabaix (rande) @@ -192,6 +193,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jérôme Parmentier (lctrs) - Ben Davies (bendavies) - Andreas Schempp (aschempp) + - Jan Rosier (rosier) - Clemens Tolboom - Helmer Aaviksoo - Hiromi Hishida (77web) @@ -200,7 +202,6 @@ The Symfony Connect username in parenthesis allows to get more information - Dawid Nowak - Maxime Helias (maxhelias) - Amal Raghav (kertz) - - Albert Casademont (acasademont) - Jonathan Ingram (jonathaningram) - Artur Kotyrba - Tyson Andre @@ -229,12 +230,12 @@ The Symfony Connect username in parenthesis allows to get more information - DQNEO - David Prévot - Andre Rømcke (andrerom) + - Marco Pivetta (ocramius) - Smaine Milianni (ismail1432) - mcfedr (mcfedr) - Christian Scheb - Ruben Gonzalez (rubenrua) - Benjamin Dulau (dbenjamin) - - Jan Rosier (rosier) - Mathieu Lemoine (lemoinem) - Remon van de Kamp (rpkamp) - Christian Schmidt @@ -270,6 +271,7 @@ The Symfony Connect username in parenthesis allows to get more information - jeff - John Kary (johnkary) - Tien Vo (tienvx) + - YaFou - Justin Hileman (bobthecow) - Blanchon Vincent (blanchonvincent) - Michele Orselli (orso) @@ -277,6 +279,7 @@ The Symfony Connect username in parenthesis allows to get more information - Baptiste Lafontaine (magnetik) - Maxime Veber (nek-) - Rui Marinho (ruimarinho) + - Jesse Rushlow (geeshoe) - Eugene Wissner - Andreas Möller (localheinz) - Edi Modrić (emodric) @@ -292,7 +295,6 @@ The Symfony Connect username in parenthesis allows to get more information - Mantis Development - Loïc Faugeron - dFayet - - Marco Pivetta (ocramius) - Antonio Pauletich (x-coder264) - Jeroen Spee (jeroens) - Rob Frawley 2nd (robfrawley) @@ -317,7 +319,6 @@ The Symfony Connect username in parenthesis allows to get more information - Alessandro Lai (jean85) - Adam Prager (padam87) - Benoît Burnichon (bburnichon) - - YaFou - Maciej Malarz (malarzm) - Roman Marintšenko (inori) - Xavier Montaña Carreras (xmontana) @@ -417,7 +418,6 @@ The Symfony Connect username in parenthesis allows to get more information - Aurelijus Valeiša (aurelijus) - Jan Decavele (jandc) - Gustavo Piltcher - - Jesse Rushlow (geeshoe) - Stepan Tanasiychuk (stfalcon) - Ivan Kurnosov - Tiago Ribeiro (fixe) @@ -442,6 +442,7 @@ The Symfony Connect username in parenthesis allows to get more information - Mark Challoner (markchalloner) - ivan - Karoly Gossler (connorhu) + - Nate Wiebe (natewiebe13) - Ahmed Raafat - Philippe Segatori - Gennady Telegin (gtelegin) @@ -470,6 +471,7 @@ The Symfony Connect username in parenthesis allows to get more information - Harm van Tilborg (hvt) - Malte Schlüter (maltemaltesich) - Thomas Perez (scullwm) + - Michał (bambucha15) - Felix Labrecque - Yaroslav Kiliba - Terje Bråten @@ -497,11 +499,13 @@ The Symfony Connect username in parenthesis allows to get more information - Grzegorz Zdanowski (kiler129) - Dimitri Gritsajuk (ottaviano) - Kirill chEbba Chebunin (chebba) + - Pol Dellaiera (drupol) - - Greg Thornton (xdissent) - Alex Bowers - Philipp Cordes - Costin Bereveanu (schniper) + - Bozhidar Hristov (warxcell) - Loïc Chardonnet (gnusat) - Marek Kalnik (marekkalnik) - Vyacheslav Salakhutdinov (megazoll) @@ -536,6 +540,7 @@ The Symfony Connect username in parenthesis allows to get more information - Miha Vrhovnik - Alessandro Desantis - hubert lecorche (hlecorche) + - fritzmg - Marc Morales Valldepérez (kuert) - Jean-Baptiste GOMOND (mjbgo) - Vadim Kharitonov (virtuozzz) @@ -559,7 +564,6 @@ The Symfony Connect username in parenthesis allows to get more information - Christopher Davis (chrisguitarguy) - Webnet team (webnet) - Ben Ramsey (ramsey) - - Nate Wiebe (natewiebe13) - Marcin Szepczynski (czepol) - Mohammad Emran Hasan (phpfour) - Dmitriy Mamontov (mamontovdmitriy) @@ -567,6 +571,7 @@ The Symfony Connect username in parenthesis allows to get more information - Niklas Fiekas - Markus Bachmann (baachi) - Kévin THERAGE (kevin_therage) + - Gunnstein Lye (glye) - Erkhembayar Gantulga (erheme318) - Greg Anderson - Islam93 @@ -588,6 +593,7 @@ The Symfony Connect username in parenthesis allows to get more information - DerManoMann - vagrant - Aurimas Niekis (gcds) + - Benjamin Cremer (bcremer) - EdgarPE - Bob van de Vijver (bobvandevijver) - Florian Pfitzer (marmelatze) @@ -609,6 +615,7 @@ The Symfony Connect username in parenthesis allows to get more information - Ariel Ferrandini (aferrandini) - Dirk Pahl (dirkaholic) - cedric lombardot (cedriclombardot) + - Dane Powell - Arkadius Stefanski (arkadius) - Tim Goudriaan (codedmonkey) - Jonas Flodén (flojon) @@ -641,7 +648,6 @@ The Symfony Connect username in parenthesis allows to get more information - Sam Fleming (sam_fleming) - Alex Bakhturin - Patrick Reimers (preimers) - - Pol Dellaiera (drupol) - insekticid - Alexander Obuhovich (aik099) - boombatower @@ -659,7 +665,6 @@ The Symfony Connect username in parenthesis allows to get more information - Nathan Dench (ndenc2) - Sebastian Bergmann - Miroslav Sustek - - Michał (bambucha15) - Pablo Díez (pablodip) - Kevin McBride - Sergio Santoro @@ -717,7 +722,6 @@ The Symfony Connect username in parenthesis allows to get more information - Jacek Jędrzejewski (jacek.jedrzejewski) - Stefan Kruppa - sasezaki - - Bozhidar Hristov (warxcell) - Dawid Pakuła (zulusx) - Florian Rey (nervo) - Rodrigo Borrego Bernabé (rodrigobb) @@ -743,7 +747,6 @@ The Symfony Connect username in parenthesis allows to get more information - Ned Schwartz - Ziumin - Jeremy Benoist - - fritzmg - Lenar Lõhmus - Benjamin Laugueux (yzalis) - Zach Badgett (zachbadgett) @@ -756,6 +759,7 @@ The Symfony Connect username in parenthesis allows to get more information - Geoffrey Tran (geoff) - Pablo Lozano (arkadis) - Jan Behrens + - Bernd Stellwag - Mantas Var (mvar) - Terje Bråten - Sebastian Krebs @@ -766,6 +770,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jean-Christophe Cuvelier [Artack] - Julien Montel (julienmgel) - Mátyás Somfai (smatyas) + - Urinbayev Shakhobiddin (shokhaa) - Bastien DURAND (deamon) - Simon DELICATA - Artem Henvald (artemgenvald) @@ -813,10 +818,8 @@ The Symfony Connect username in parenthesis allows to get more information - Hany el-Kerdany - Wang Jingyu - Åsmund Garfors - - Gunnstein Lye (glye) - Maxime Douailin - Jean Pasdeloup (pasdeloup) - - Benjamin Cremer (bcremer) - Javier López (loalf) - Reinier Kip - Jérôme Tamarelle (jtamarelle-prismamedia) @@ -834,6 +837,7 @@ The Symfony Connect username in parenthesis allows to get more information - zenmate - Michal Trojanowski - Lescot Edouard (idetox) + - Andrii Popov (andrii-popov) - David Fuhr - Rodrigo Aguilera - Mathias STRASSER (roukmoute) @@ -844,6 +848,7 @@ The Symfony Connect username in parenthesis allows to get more information - Mardari Dorel (dorumd) - Daisuke Ohata - Vincent Simonin + - Pierrick VIGNAND (pierrick) - Alex Bogomazov (alebo) - maxime.steinhausser - adev @@ -940,7 +945,9 @@ The Symfony Connect username in parenthesis allows to get more information - Andrew Berry - twifty - Indra Gunawan (guind) + - Roberto Nygaard - Peter Ward + - Matthew Grasmick - Davide Borsatto (davide.borsatto) - Gert de Pagter - Julien DIDIER (juliendidier) @@ -1032,6 +1039,7 @@ The Symfony Connect username in parenthesis allows to get more information - Vincent Composieux (eko) - Jayson Xu (superjavason) - Gijs van Lammeren + - DemigodCode - Hubert Lenoir (hubert_lenoir) - fago - Jan Prieser @@ -1167,18 +1175,19 @@ The Symfony Connect username in parenthesis allows to get more information - Dmitriy Derepko - Stéphane Delprat - Brian Freytag (brianfreytag) + - Elan Ruusamäe (glen) - Brunet Laurent (lbrunet) - Florent Viel (luxifer) - Mikhail Yurasov (mym) - LOUARDI Abdeltif (ouardisoft) - Robert Gruendler (pulse00) + - Sebastian Paczkowski (sebpacz) - Simon Terrien (sterrien) - Benoît Merlet (trompette) - Koen Kuipers - datibbaw - Thiago Cordeiro (thiagocordeiro) - Rootie - - Bernd Stellwag - Alireza Mirsepassi (alirezamirsepassi) - Daniel Alejandro Castro Arellano (lexcast) - sensio @@ -1258,6 +1267,7 @@ The Symfony Connect username in parenthesis allows to get more information - Fred Cox - luffy1727 - Luciano Mammino (loige) + - LHommet Nicolas (nicolaslh) - fabios - Sander Coolen (scoolen) - Amirreza Shafaat (amirrezashafaat) @@ -1288,6 +1298,7 @@ The Symfony Connect username in parenthesis allows to get more information - linh - Mario Blažek (marioblazek) - Jure (zamzung) + - Michael Nelson - Ashura - Hryhorii Hrebiniuk - Eric Krona @@ -1308,7 +1319,6 @@ The Symfony Connect username in parenthesis allows to get more information - boite - Silvio Ginter - MGDSoft - - Pierrick VIGNAND (pierrick) - Vadim Tyukov (vatson) - Arman - Gabi Udrescu @@ -1385,6 +1395,7 @@ The Symfony Connect username in parenthesis allows to get more information - Ken Marfilla (marfillaster) - benatespina (benatespina) - Denis Kop + - Cristoforo Cervino (cristoforocervino) - Jean-Guilhem Rouel (jean-gui) - jfcixmedia - Dominic Tubach @@ -1397,7 +1408,9 @@ The Symfony Connect username in parenthesis allows to get more information - Christian - Alexandru Patranescu - Denis Golubovskiy (bukashk0zzz) + - Arkadiusz Rzadkowolski (flies) - Sergii Smertin (nfx) + - Oksana Kozlova (oksanakozlova) - Quentin Moreau (sheitak) - Mikkel Paulson - Michał Strzelecki @@ -1427,6 +1440,7 @@ The Symfony Connect username in parenthesis allows to get more information - Atthaphon Urairat - Benoit Garret - Maximilian Ruta (deltachaos) + - Mickaël Isaert (misaert) - Jakub Sacha - Olaf Klischat - orlovv @@ -1453,6 +1467,7 @@ The Symfony Connect username in parenthesis allows to get more information - Benjamin Dos Santos - Einenlum - Jérémy Jarrié (gagnar) + - Martin Herndl (herndlm) - Jochen Bayer (jocl) - Tomas Javaisis - Patrick Carlo-Hickman @@ -1479,6 +1494,7 @@ The Symfony Connect username in parenthesis allows to get more information - peter - Jérémy Jourdin (jjk801) - BRAMILLE Sébastien (oktapodia) + - Loïc Ovigne (oviglo) - Artem Kolesnikov (tyomo4ka) - Gustavo Adrian - Jorrit Schippers (jorrit) @@ -1506,6 +1522,7 @@ The Symfony Connect username in parenthesis allows to get more information - Eno Mullaraj (emullaraj) - Nathan PAGE (nathix) - Ryan Rogers + - Marion Hurteau - Klaus Purer - Dmitrii Lozhkin - arnaud (arnooo999) @@ -1565,6 +1582,7 @@ The Symfony Connect username in parenthesis allows to get more information - Andrii Serdiuk (andreyserdjuk) - Clement Herreman (clemherreman) - Dan Ionut Dumitriu (danionut90) + - Floran Brutel (notFloran) (floran) - Vladislav Rastrusny (fractalizer) - Alexander Kurilo (kamazee) - Nyro (nyro) @@ -1577,6 +1595,7 @@ The Symfony Connect username in parenthesis allows to get more information - Dmitri Petmanson - heccjj - Alexandre Melard + - Stefano A. (stefano93) - Jay Klehr - Sergey Yuferev - Tobias Stöckler @@ -1587,9 +1606,11 @@ The Symfony Connect username in parenthesis allows to get more information - Mo Di (modi) - Pablo Schläpfer - Christian Rishøj + - Roromix - Patrick Berenschot - SuRiKmAn - Jelte Steijaert (jelte) + - Maxime AILLOUD (mailloud) - David Négrier (moufmouf) - Quique Porta (quiqueporta) - mohammadreza honarkhah @@ -1604,6 +1625,7 @@ The Symfony Connect username in parenthesis allows to get more information - ConneXNL - Aharon Perkel - matze + - Adam Wójs (awojs) - Justin Reherman (jreherman) - Rubén Calvo (rubencm) - Paweł Niedzielski (steveb) @@ -1618,6 +1640,7 @@ The Symfony Connect username in parenthesis allows to get more information - Artem Stepin (astepin) - Christian Flach (cmfcmf) - Cédric Girard (enk_) + - Junaid Farooq (junaidfarooq) - Lars Ambrosius Wallenborn (larsborn) - Oriol Mangas Abellan (oriolman) - Sebastian Göttschkes (sgoettschkes) @@ -1655,6 +1678,7 @@ The Symfony Connect username in parenthesis allows to get more information - Andrea Sprega (asprega) - Maks Rafalko (bornfree) - Karol Sójko (karolsojko) + - Viktor Bajraktar (njutn95) - sl_toto (sl_toto) - Walter Dal Mut (wdalmut) - abluchet @@ -1673,6 +1697,8 @@ The Symfony Connect username in parenthesis allows to get more information - Cédric Lahouste (rapotor) - Samuel Vogel (samuelvogel) - Osayawe Ogbemudia Terry (terdia) + - AndrolGenhald + - Damien Fa - Berat Doğan - Guillaume LECERF - Juanmi Rodriguez Cerón @@ -1705,6 +1731,7 @@ The Symfony Connect username in parenthesis allows to get more information - Alexander Pasichnick - Ilya Ch. (ilya0) - Luis Ramirez (luisdeimos) + - Ilia Sergunin (maranqz) - Daniel Richter (richtermeister) - ChrisC - JL @@ -1713,6 +1740,7 @@ The Symfony Connect username in parenthesis allows to get more information - Johan de Ruijter - Jason Desrosiers - m.chwedziak + - marbul - Andreas Frömer - Philip Frank - David Brooks @@ -1720,6 +1748,7 @@ The Symfony Connect username in parenthesis allows to get more information - Florian Caron (shalalalala) - Serhiy Lunak (slunak) - Giorgio Premi + - tamcy - Mikko Pesari - Aurélien Fontaine - ncou @@ -1804,6 +1833,8 @@ The Symfony Connect username in parenthesis allows to get more information - Peter Bouwdewijn - mlively - Wouter Diesveld + - Romain + - Matěj Humpál - Vincent Langlet - Amine Matmati - caalholm @@ -1913,6 +1944,7 @@ The Symfony Connect username in parenthesis allows to get more information - Biji (biji) - Alex Teterin (errogaht) - Gunnar Lium (gunnarlium) + - Marie Minasyan (marie.minassyan) - Tiago Garcia (tiagojsag) - Artiom - Jakub Simon @@ -1926,6 +1958,7 @@ The Symfony Connect username in parenthesis allows to get more information - Martin Eckhardt - natechicago - Camille Dejoye + - Alexis - Sergei Gorjunov - Jonathan Poston - Adrian Olek (adrianolek) @@ -2095,6 +2128,7 @@ The Symfony Connect username in parenthesis allows to get more information - Florent Olivaud - Eric Hertwig - JakeFr + - Oliver Klee - Niels Robin-Aubertin - Simon Sargeant - efeen @@ -2309,7 +2343,6 @@ The Symfony Connect username in parenthesis allows to get more information - Arjan Keeman - Erik van Wingerden - Valouleloup - - Dane Powell - Alexis MARQUIS - Gerrit Drost - Linnaea Von Lavia @@ -2322,6 +2355,7 @@ The Symfony Connect username in parenthesis allows to get more information - hainey - Juan M Martínez - Gilles Gauthier + - Benjamin Franzke - Pavinthan - Sylvain METAYER - ddebree @@ -2380,6 +2414,7 @@ The Symfony Connect username in parenthesis allows to get more information - Olivier Laviale (olvlvl) - Pierre Gasté (pierre_g) - Pablo Monterde Perez (plebs) + - Pierre-Olivier Vares (povares) - Jimmy Leger (redpanda) - Ronny López (ronnylt) - Dmitry (staratel) @@ -2505,6 +2540,7 @@ The Symfony Connect username in parenthesis allows to get more information - Paweł Tomulik - Eric J. Duran - Pavol Tuka + - stlrnz - Alexandru Bucur - Alexis Lefebvre - cmfcmf @@ -2558,6 +2594,7 @@ The Symfony Connect username in parenthesis allows to get more information - Jon Cave - Sébastien HOUZE - Abdulkadir N. A. + - Markus Klein - Adam Klvač - Bruno Nogueira Nascimento Wowk - Matthias Dötsch @@ -2570,7 +2607,6 @@ The Symfony Connect username in parenthesis allows to get more information - Ondřej Führer - Bogdan - Sema - - Elan Ruusamäe - Thorsten Hallwas - Marco Pfeiffer - Alex Nostadt @@ -2647,12 +2683,13 @@ The Symfony Connect username in parenthesis allows to get more information - Alex Olmos (alexolmos) - Antonio Mansilla (amansilla) - Robin Kanters (anddarerobin) - - Andrii Popov (andrii-popov) - Juan Ases García (ases) - Siragusa (asiragusa) - Daniel Basten (axhm3a) - Dude (b1rdex) + - Benedict Massolle (bemas) - Gerard Berengue Llobera (bere) + - Ronny (big-r) - Bernd Matzner (bmatzner) - Bram Tweedegolf (bram_tweedegolf) - Brandon Kelly (brandonkelly) @@ -2722,6 +2759,7 @@ The Symfony Connect username in parenthesis allows to get more information - Paul Andrieux (paulandrieux) - Paweł Szczepanek (pauluz) - Philippe Degeeter (pdegeeter) + - PLAZANET Pierre (pedrotroller) - Christian López Espínola (penyaskito) - Petr Jaroš (petajaros) - Philipp Hoffmann (philipphoffmann) diff --git a/README.md b/README.md index bddcd21f9776..d3f5b5588d75 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ Documentation * Read the [Getting Started guide][7] if you are new to Symfony. * Try the [Symfony Demo application][23] to learn Symfony in practice. +* Discover Symfony ecosystem in detail with [Symfony The Fast Track][26]. * Master Symfony with the [Guides and Tutorials][8], the [Components docs][9] and the [Best Practices][10] reference. @@ -74,3 +75,4 @@ Symfony development is sponsored by [SensioLabs][21], led by the [23]: https://github.com/symfony/symfony-demo [24]: https://symfony.com/coc [25]: https://symfony.com/doc/current/contributing/code_of_conduct/care_team.html +[26]: https://symfony.com/book diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php index 211992d14991..00652bb71612 100644 --- a/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php +++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php @@ -146,7 +146,7 @@ protected function getMappingDriverBundleConfigDefaults(array $bundleConfig, \Re } if (!$bundleConfig['dir']) { - if (\in_array($bundleConfig['type'], ['annotation', 'staticphp'])) { + if (\in_array($bundleConfig['type'], ['annotation', 'staticphp', 'attribute'])) { $bundleConfig['dir'] = $bundleDir.'/'.$this->getMappingObjectDefaultName(); } else { $bundleConfig['dir'] = $bundleDir.'/'.$this->getMappingResourceConfigDirectory(); @@ -186,6 +186,10 @@ protected function registerMappingDrivers(array $objectManager, ContainerBuilder $args[0] = array_merge(array_values($driverPaths), $args[0]); } $mappingDriverDef->setArguments($args); + } elseif ('attribute' === $driverType) { + $mappingDriverDef = new Definition($this->getMetadataDriverClass($driverType), [ + array_values($driverPaths), + ]); } elseif ('annotation' == $driverType) { $mappingDriverDef = new Definition($this->getMetadataDriverClass($driverType), [ new Reference($this->getObjectManagerElementName('metadata.annotation_reader')), @@ -227,8 +231,8 @@ protected function assertValidMappingConfiguration(array $mappingConfig, string throw new \InvalidArgumentException(sprintf('Specified non-existing directory "%s" as Doctrine mapping source.', $mappingConfig['dir'])); } - if (!\in_array($mappingConfig['type'], ['xml', 'yml', 'annotation', 'php', 'staticphp'])) { - throw new \InvalidArgumentException(sprintf('Can only configure "xml", "yml", "annotation", "php" or "staticphp" through the DoctrineBundle. Use your own bundle to configure other metadata drivers. You can register them by adding a new driver to the "%s" service definition.', $this->getObjectManagerElementName($objectManagerName.'_metadata_driver'))); + if (!\in_array($mappingConfig['type'], ['xml', 'yml', 'annotation', 'php', 'staticphp', 'attribute'])) { + throw new \InvalidArgumentException(sprintf('Can only configure "xml", "yml", "annotation", "php", "staticphp" or "attribute" through the DoctrineBundle. Use your own bundle to configure other metadata drivers. You can register them by adding a new driver to the "%s" service definition.', $this->getObjectManagerElementName($objectManagerName.'_metadata_driver'))); } } diff --git a/src/Symfony/Bridge/Monolog/Formatter/VarDumperFormatter.php b/src/Symfony/Bridge/Monolog/Formatter/VarDumperFormatter.php index 8fe52385cca1..54988766c3a2 100644 --- a/src/Symfony/Bridge/Monolog/Formatter/VarDumperFormatter.php +++ b/src/Symfony/Bridge/Monolog/Formatter/VarDumperFormatter.php @@ -23,7 +23,7 @@ class VarDumperFormatter implements FormatterInterface public function __construct(VarCloner $cloner = null) { - $this->cloner = $cloner ?: new VarCloner(); + $this->cloner = $cloner ?? new VarCloner(); } /** diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php index 077050688b3c..a28ee544787d 100644 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit.php @@ -158,8 +158,8 @@ } $COMPOSER = file_exists($COMPOSER = $oldPwd.'/composer.phar') - || ($COMPOSER = rtrim('\\' === \DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer.phar`) : `which composer.phar 2> /dev/null`)) - || ($COMPOSER = rtrim('\\' === \DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer`) : `which composer 2> /dev/null`)) + || ($COMPOSER = rtrim('\\' === \DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer.phar 2> NUL`) : `which composer.phar 2> /dev/null`)) + || ($COMPOSER = rtrim('\\' === \DIRECTORY_SEPARATOR ? preg_replace('/[\r\n].*/', '', `where.exe composer 2> NUL`) : `which composer 2> /dev/null`)) || file_exists($COMPOSER = rtrim('\\' === \DIRECTORY_SEPARATOR ? `git rev-parse --show-toplevel 2> NUL` : `git rev-parse --show-toplevel 2> /dev/null`).\DIRECTORY_SEPARATOR.'composer.phar') ? ('#!/usr/bin/env php' === file_get_contents($COMPOSER, false, null, 0, 18) ? $PHP : '').' '.escapeshellarg($COMPOSER) // detect shell wrappers by looking at the shebang : 'composer'; @@ -185,9 +185,9 @@ @mkdir($PHPUNIT_DIR, 0777, true); chdir($PHPUNIT_DIR); if (file_exists("$PHPUNIT_VERSION_DIR")) { - passthru(sprintf('\\' === \DIRECTORY_SEPARATOR ? 'rmdir /S /Q %s > NUL' : 'rm -rf %s', "$PHPUNIT_VERSION_DIR.old")); + passthru(sprintf('\\' === \DIRECTORY_SEPARATOR ? 'rmdir /S /Q %s 2> NUL' : 'rm -rf %s', escapeshellarg("$PHPUNIT_VERSION_DIR.old"))); rename("$PHPUNIT_VERSION_DIR", "$PHPUNIT_VERSION_DIR.old"); - passthru(sprintf('\\' === \DIRECTORY_SEPARATOR ? 'rmdir /S /Q %s' : 'rm -rf %s', "$PHPUNIT_VERSION_DIR.old")); + passthru(sprintf('\\' === \DIRECTORY_SEPARATOR ? 'rmdir /S /Q %s' : 'rm -rf %s', escapeshellarg("$PHPUNIT_VERSION_DIR.old"))); } $info = []; @@ -313,10 +313,15 @@ class_exists(\SymfonyExcludeListSimplePhpunit::class, false) && PHPUnit\Util\Bla // This is useful for static analytics tools such as PHPStan having to load PHPUnit's classes // and for other testing libraries such as Behat using PHPUnit's assertions. chdir($PHPUNIT_DIR); -if (file_exists('phpunit')) { - @unlink('phpunit'); +if ('\\' === \DIRECTORY_SEPARATOR) { + passthru('rmdir /S /Q phpunit 2> NUL'); + passthru(sprintf('mklink /j phpunit %s > NUL 2>&1', escapeshellarg($PHPUNIT_VERSION_DIR))); +} else { + if (file_exists('phpunit')) { + @unlink('phpunit'); + } + @symlink($PHPUNIT_VERSION_DIR, 'phpunit'); } -@symlink($PHPUNIT_VERSION_DIR, 'phpunit'); chdir($oldPwd); if ($PHPUNIT_VERSION < 8.0) { diff --git a/src/Symfony/Bridge/Twig/Command/LintCommand.php b/src/Symfony/Bridge/Twig/Command/LintCommand.php index 00c31def64b7..2e3befb5aa0e 100644 --- a/src/Symfony/Bridge/Twig/Command/LintCommand.php +++ b/src/Symfony/Bridge/Twig/Command/LintCommand.php @@ -219,7 +219,7 @@ private function displayJson(OutputInterface $output, array $filesInfo) return min($errors, 1); } - private function renderException(OutputInterface $output, string $template, Error $exception, string $file = null) + private function renderException(SymfonyStyle $output, string $template, Error $exception, string $file = null) { $line = $exception->getTemplateLine(); diff --git a/src/Symfony/Bridge/Twig/Extension/DumpExtension.php b/src/Symfony/Bridge/Twig/Extension/DumpExtension.php index 80fe82f9b8b2..46ad8eaf679c 100644 --- a/src/Symfony/Bridge/Twig/Extension/DumpExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/DumpExtension.php @@ -74,7 +74,7 @@ public function dump(Environment $env, array $context): ?string } $dump = fopen('php://memory', 'r+'); - $this->dumper = $this->dumper ?: new HtmlDumper(); + $this->dumper = $this->dumper ?? new HtmlDumper(); $this->dumper->setCharset($env->getCharset()); foreach ($vars as $value) { diff --git a/src/Symfony/Bridge/Twig/Mime/WrappedTemplatedEmail.php b/src/Symfony/Bridge/Twig/Mime/WrappedTemplatedEmail.php index 7b299e6347d6..f1726914b490 100644 --- a/src/Symfony/Bridge/Twig/Mime/WrappedTemplatedEmail.php +++ b/src/Symfony/Bridge/Twig/Mime/WrappedTemplatedEmail.php @@ -182,7 +182,7 @@ public function getBcc(): array */ public function setPriority(int $priority): self { - $this->message->setPriority($priority); + $this->message->priority($priority); return $this; } diff --git a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AnnotationsCacheWarmer.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AnnotationsCacheWarmer.php index 2169eecf8a62..ac7f016fe628 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AnnotationsCacheWarmer.php +++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/AnnotationsCacheWarmer.php @@ -15,6 +15,7 @@ use Doctrine\Common\Annotations\CachedReader; use Doctrine\Common\Annotations\Reader; use Symfony\Component\Cache\Adapter\ArrayAdapter; +use Symfony\Component\Cache\Adapter\PhpArrayAdapter; use Symfony\Component\Cache\DoctrineProvider; /** @@ -68,6 +69,17 @@ protected function doWarmUp(string $cacheDir, ArrayAdapter $arrayAdapter) return true; } + /** + * @return string[] A list of classes to preload on PHP 7.4+ + */ + protected function warmUpPhpArrayAdapter(PhpArrayAdapter $phpArrayAdapter, array $values) + { + // make sure we don't cache null values + $values = array_filter($values, function ($val) { return null !== $val; }); + + return parent::warmUpPhpArrayAdapter($phpArrayAdapter, $values); + } + private function readAllComponents(Reader $reader, string $class) { $reflectionClass = new \ReflectionClass($class); diff --git a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ValidatorCacheWarmer.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ValidatorCacheWarmer.php index 89e9c1872a3d..3c6d582c4320 100644 --- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ValidatorCacheWarmer.php +++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/ValidatorCacheWarmer.php @@ -74,7 +74,9 @@ protected function doWarmUp(string $cacheDir, ArrayAdapter $arrayAdapter) protected function warmUpPhpArrayAdapter(PhpArrayAdapter $phpArrayAdapter, array $values) { // make sure we don't cache null values - return parent::warmUpPhpArrayAdapter($phpArrayAdapter, array_filter($values)); + $values = array_filter($values, function ($val) { return null !== $val; }); + + return parent::warmUpPhpArrayAdapter($phpArrayAdapter, $values); } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php index dbd93818c7dd..3bb548057164 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/CacheClearCommand.php @@ -45,7 +45,7 @@ public function __construct(CacheClearerInterface $cacheClearer, Filesystem $fil parent::__construct(); $this->cacheClearer = $cacheClearer; - $this->filesystem = $filesystem ?: new Filesystem(); + $this->filesystem = $filesystem ?? new Filesystem(); } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index 33566f7f3eb7..adc524ce6202 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -554,6 +554,10 @@ private function formatControllerLink($controller, string $anchorText, callable $r = new \ReflectionFunction($controller); } } catch (\ReflectionException $e) { + if (\is_array($controller)) { + $controller = implode('::', $controller); + } + $id = $controller; $method = '__invoke'; diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index a0efab6b5ba6..a2d3cdf119f3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -40,9 +40,6 @@ /** * FrameworkExtension configuration structure. - * - * @author Jeremy Mikola - * @author Grégoire Pineau */ class Configuration implements ConfigurationInterface { diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 00892d884795..431e1dc4a6ec 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -166,12 +166,8 @@ use Symfony\Contracts\Translation\LocaleAwareInterface; /** - * FrameworkExtension. - * - * @author Fabien Potencier - * @author Jeremy Mikola - * @author Kévin Dunglas - * @author Grégoire Pineau + * Process the configuration and prepare the dependency injection container with + * parameters and services. */ class FrameworkExtension extends Extension { @@ -392,7 +388,7 @@ public function load(array $configs, ContainerBuilder $container) $propertyInfoEnabled = $this->isConfigEnabled($container, $config['property_info']); $this->registerValidationConfiguration($config['validation'], $container, $loader, $propertyInfoEnabled); - $this->registerHttpCacheConfiguration($config['http_cache'], $container); + $this->registerHttpCacheConfiguration($config['http_cache'], $container, $config['http_method_override']); $this->registerEsiConfiguration($config['esi'], $container, $loader); $this->registerSsiConfiguration($config['ssi'], $container, $loader); $this->registerFragmentsConfiguration($config['fragments'], $container, $loader); @@ -580,7 +576,7 @@ private function registerFormConfiguration(array $config, ContainerBuilder $cont } } - private function registerHttpCacheConfiguration(array $config, ContainerBuilder $container) + private function registerHttpCacheConfiguration(array $config, ContainerBuilder $container, bool $httpMethodOverride) { $options = $config; unset($options['enabled']); @@ -592,6 +588,13 @@ private function registerHttpCacheConfiguration(array $config, ContainerBuilder $container->getDefinition('http_cache') ->setPublic($config['enabled']) ->replaceArgument(3, $options); + + if ($httpMethodOverride) { + $container->getDefinition('http_cache') + ->addArgument((new Definition('void')) + ->setFactory([Request::class, 'enableHttpMethodParameterOverride']) + ); + } } private function registerEsiConfiguration(array $config, ContainerBuilder $container, PhpFileLoader $loader) @@ -1312,7 +1315,7 @@ private function registerValidationConfiguration(array $config, ContainerBuilder if (\array_key_exists('enable_annotations', $config) && $config['enable_annotations']) { if (!$this->annotationsConfigEnabled && \PHP_VERSION_ID < 80000) { - throw new \LogicException('"enable_annotations" on the validator cannot be set as Doctrine Annotations support is disabled.'); + throw new \LogicException('"enable_annotations" on the validator cannot be set as the PHP version is lower than 8 and Doctrine Annotations support is disabled. Consider upgrading PHP.'); } $validatorBuilder->addMethodCall('enableAnnotationMapping', [true]); @@ -1576,7 +1579,7 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder $serializerLoaders = []; if (isset($config['enable_annotations']) && $config['enable_annotations']) { if (\PHP_VERSION_ID < 80000 && !$this->annotationsConfigEnabled) { - throw new \LogicException('"enable_annotations" on the serializer cannot be set as Annotations support is disabled.'); + throw new \LogicException('"enable_annotations" on the serializer cannot be set as the PHP version is lower than 8 and Annotations support is disabled. Consider upgrading PHP.'); } $annotationLoader = new Definition( @@ -1968,6 +1971,12 @@ private function registerCacheConfiguration(array $config, ContainerBuilder $con ->setPublic($pool['public']) ; + if (method_exists(TagAwareAdapter::class, 'setLogger')) { + $container + ->getDefinition($name) + ->addMethodCall('setLogger', [new Reference('logger', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)]); + } + $pool['name'] = $tagAwareId = $name; $pool['public'] = false; $name = '.'.$name.'.inner'; diff --git a/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php b/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php index 45b2ca785603..35ea73c23577 100644 --- a/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php +++ b/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php @@ -18,7 +18,6 @@ use Symfony\Component\HttpKernel\HttpCache\Store; use Symfony\Component\HttpKernel\HttpCache\StoreInterface; use Symfony\Component\HttpKernel\HttpCache\SurrogateInterface; -use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\HttpKernel\KernelInterface; /** @@ -63,15 +62,6 @@ public function __construct(KernelInterface $kernel, $cache = null, SurrogateInt parent::__construct($kernel, $this->createStore(), $this->createSurrogate(), array_merge($this->options, $this->getOptions())); } - public function handle(Request $request, int $type = HttpKernelInterface::MASTER_REQUEST, bool $catch = true) - { - if ($this->kernel->getContainer()->getParameter('kernel.http_method_override')) { - Request::enableHttpMethodParameterOverride(); - } - - return parent::handle($request, $type, $catch); - } - /** * {@inheritdoc} */ diff --git a/src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php b/src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php index 52587cc7c756..08e15d18d6b2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php +++ b/src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php @@ -61,7 +61,7 @@ trait MicroKernelTrait * * $c->parameters()->set('halloween', 'lot of fun'); */ - //abstract protected function configureContainer(ContainerConfigurator $c): void; + //abstract protected function configureContainer(ContainerConfigurator $container): void; /** * {@inheritdoc} @@ -129,7 +129,7 @@ public function registerContainerConfiguration(LoaderInterface $loader) try { $configureContainer = new \ReflectionMethod($this, 'configureContainer'); } catch (\ReflectionException $e) { - throw new \LogicException(sprintf('"%s" uses "%s", but does not implement the required method "protected function configureContainer(ContainerConfigurator $c): void".', get_debug_type($this), MicroKernelTrait::class), 0, $e); + throw new \LogicException(sprintf('"%s" uses "%s", but does not implement the required method "protected function configureContainer(ContainerConfigurator $container): void".', get_debug_type($this), MicroKernelTrait::class), 0, $e); } $configuratorClass = $configureContainer->getNumberOfParameters() > 0 && ($type = $configureContainer->getParameters()[0]->getType()) instanceof \ReflectionNamedType && !$type->isBuiltin() ? $type->getName() : null; diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.php index c7838ff61536..0289a55c22c8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/messenger.php @@ -11,6 +11,7 @@ namespace Symfony\Component\DependencyInjection\Loader\Configurator; +use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\Messenger\Bridge\AmazonSqs\Transport\AmazonSqsTransportFactory; use Symfony\Component\Messenger\Bridge\Amqp\Transport\AmqpTransportFactory; use Symfony\Component\Messenger\Bridge\Beanstalkd\Transport\BeanstalkdTransportFactory; @@ -101,7 +102,7 @@ ]) // Discovery - ->set('messenger.receiver_locator') + ->set('messenger.receiver_locator', ServiceLocator::class) ->args([ [], ]) @@ -132,7 +133,7 @@ ->set('messenger.transport.beanstalkd.factory', BeanstalkdTransportFactory::class) // retry - ->set('messenger.retry_strategy_locator') + ->set('messenger.retry_strategy_locator', ServiceLocator::class) ->args([ [], ]) diff --git a/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php b/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php index b70437374ad2..23d194567959 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php +++ b/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php @@ -44,7 +44,7 @@ public function __construct(ContainerInterface $container, $resource, array $opt { $this->container = $container; $this->resource = $resource; - $this->context = $context ?: new RequestContext(); + $this->context = $context ?? new RequestContext(); $this->logger = $logger; $this->setOptions($options); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/AnnotationsCacheWarmerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/AnnotationsCacheWarmerTest.php index 905593b280f4..88538c374088 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/AnnotationsCacheWarmerTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/CacheWarmer/AnnotationsCacheWarmerTest.php @@ -8,6 +8,7 @@ use PHPUnit\Framework\MockObject\MockObject; use Symfony\Bundle\FrameworkBundle\CacheWarmer\AnnotationsCacheWarmer; use Symfony\Bundle\FrameworkBundle\Tests\TestCase; +use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\Cache\Adapter\NullAdapter; use Symfony\Component\Cache\Adapter\PhpArrayAdapter; use Symfony\Component\Cache\DoctrineProvider; @@ -120,6 +121,35 @@ public function testClassAutoloadExceptionWithUnrelatedException() spl_autoload_unregister($classLoader); } + public function testWarmupRemoveCacheMisses() + { + $cacheFile = tempnam($this->cacheDir, __FUNCTION__); + $warmer = $this->getMockBuilder(AnnotationsCacheWarmer::class) + ->setConstructorArgs([new AnnotationReader(), $cacheFile]) + ->setMethods(['doWarmUp']) + ->getMock(); + + $warmer->method('doWarmUp')->willReturnCallback(function ($cacheDir, ArrayAdapter $arrayAdapter) { + $arrayAdapter->getItem('foo_miss'); + + $item = $arrayAdapter->getItem('bar_hit'); + $item->set('data'); + $arrayAdapter->save($item); + + $item = $arrayAdapter->getItem('baz_hit_null'); + $item->set(null); + $arrayAdapter->save($item); + + return true; + }); + + $warmer->warmUp($this->cacheDir); + $data = include $cacheFile; + + $this->assertCount(1, $data[0]); + $this->assertTrue(isset($data[0]['bar_hit'])); + } + /** * @return MockObject|Reader */ diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php index 44e0c450f473..a060c13f930c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/cache.php @@ -35,6 +35,11 @@ 'redis://foo' => 'cache.adapter.redis', ], ], + 'cache.ccc' => [ + 'adapter' => 'cache.adapter.array', + 'default_lifetime' => 410, + 'tags' => true, + ], 'cache.redis_tag_aware.foo' => [ 'adapter' => 'cache.adapter.redis_tag_aware', ], diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml index 7f04adc965b8..2750715f6b7e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/cache.xml @@ -18,6 +18,7 @@ + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml index 91f4d25fff71..8c9e10b82ee6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/cache.yml @@ -25,6 +25,10 @@ framework: - cache.adapter.array - cache.adapter.filesystem - {name: cache.adapter.redis, provider: 'redis://foo'} + cache.ccc: + adapter: cache.adapter.array + default_lifetime: 410 + tags: true cache.redis_tag_aware.foo: adapter: cache.adapter.redis_tag_aware cache.redis_tag_aware.foo2: diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 5cae48bd6ecc..3796e2fd2f93 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -29,6 +29,7 @@ use Symfony\Component\Cache\Adapter\ProxyAdapter; use Symfony\Component\Cache\Adapter\RedisAdapter; use Symfony\Component\Cache\Adapter\RedisTagAwareAdapter; +use Symfony\Component\Cache\Adapter\TagAwareAdapter; use Symfony\Component\Cache\DependencyInjection\CachePoolPass; use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException; use Symfony\Component\DependencyInjection\ChildDefinition; @@ -1388,6 +1389,17 @@ public function testCachePoolServices() 12, ]; $this->assertEquals($expected, $chain->getArguments()); + + // Test "tags: true" wrapping logic + $tagAwareDefinition = $container->getDefinition('cache.ccc'); + $this->assertSame(TagAwareAdapter::class, $tagAwareDefinition->getClass()); + $this->assertCachePoolServiceDefinitionIsCreated($container, (string) $tagAwareDefinition->getArgument(0), 'cache.adapter.array', 410); + + if (method_exists(TagAwareAdapter::class, 'setLogger')) { + $this->assertEquals([ + ['setLogger', [new Reference('logger', ContainerInterface::IGNORE_ON_INVALID_REFERENCE)]], + ], $tagAwareDefinition->getMethodCalls()); + } } public function testRedisTagAwareAdapter() @@ -1786,6 +1798,9 @@ private function assertCachePoolServiceDefinitionIsCreated(ContainerBuilder $con case 'cache.adapter.redis': $this->assertSame(RedisAdapter::class, $parentDefinition->getClass()); break; + case 'cache.adapter.array': + $this->assertSame(ArrayAdapter::class, $parentDefinition->getClass()); + break; default: $this->fail('Unresolved adapter: '.$adapter); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Kernel/MicroKernelTraitTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Kernel/MicroKernelTraitTest.php index cc5573d43dc3..d5055f33259b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Kernel/MicroKernelTraitTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Kernel/MicroKernelTraitTest.php @@ -136,7 +136,7 @@ protected function configureRoutes(RoutingConfigurator $routes): void }; $this->expectException(\LogicException::class); - $this->expectExceptionMessage('"Symfony\Bundle\FrameworkBundle\Tests\Kernel\MinimalKernel@anonymous" uses "Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait", but does not implement the required method "protected function configureContainer(ContainerConfigurator $c): void".'); + $this->expectExceptionMessage('"Symfony\Bundle\FrameworkBundle\Tests\Kernel\MinimalKernel@anonymous" uses "Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait", but does not implement the required method "protected function configureContainer(ContainerConfigurator $container): void".'); $kernel->boot(); } diff --git a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php index 9bd7c005757b..16bad6df54c9 100644 --- a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php +++ b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php @@ -367,7 +367,7 @@ public function getAccessDecisionLog() /** * Returns the configuration of the current firewall context. * - * @return array|Data + * @return array|Data|null */ public function getFirewall() { diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 57a97749b47e..0b1be065df09 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -208,6 +208,12 @@ private function createAuthorization(array $config, ContainerBuilder $container) $attributes[] = $this->createExpression($container, $access['allow_if']); } + $emptyAccess = 0 === \count(array_filter($access)); + + if ($emptyAccess) { + throw new InvalidConfigurationException('One or more access control items are empty. Did you accidentally add lines only containing a "-" under "security.access_control"?'); + } + $container->getDefinition('security.access_map') ->addMethodCall('add', [$matcher, $attributes, $access['requires_channel']]); } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php index 3ffa6cb015bc..79f5d60f0908 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/SecurityExtensionTest.php @@ -432,6 +432,56 @@ public function testSwitchUserWithSeveralDefinedProvidersButNoFirewallRootProvid $this->assertEquals(new Reference('security.user.provider.concrete.second'), $container->getDefinition('security.authentication.switchuser_listener.foobar')->getArgument(1)); } + public function testInvalidAccessControlWithEmptyRow() + { + $container = $this->getRawContainer(); + + $container->loadFromExtension('security', [ + 'providers' => [ + 'default' => ['id' => 'foo'], + ], + 'firewalls' => [ + 'some_firewall' => [ + 'pattern' => '/.*', + 'http_basic' => [], + ], + ], + 'access_control' => [ + [], + ['path' => '/admin', 'roles' => 'ROLE_ADMIN'], + ], + ]); + + $this->expectException(InvalidConfigurationException::class); + $this->expectExceptionMessage('One or more access control items are empty. Did you accidentally add lines only containing a "-" under "security.access_control"?'); + $container->compile(); + } + + public function testValidAccessControlWithEmptyRow() + { + $container = $this->getRawContainer(); + + $container->loadFromExtension('security', [ + 'providers' => [ + 'default' => ['id' => 'foo'], + ], + 'firewalls' => [ + 'some_firewall' => [ + 'pattern' => '/.*', + 'http_basic' => [], + ], + ], + 'access_control' => [ + ['path' => '^/login'], + ['path' => '^/', 'roles' => 'ROLE_USER'], + ], + ]); + + $container->compile(); + + $this->assertTrue(true, 'extension throws an InvalidConfigurationException if there is one more more empty access control items'); + } + /** * @dataProvider provideEntryPointFirewalls */ diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/exception.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/exception.html.twig index 261d5cc2b187..1fe0f5d47072 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/exception.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/exception.html.twig @@ -3,7 +3,7 @@ {% block head %} {% if collector.hasexception %} {% endif %} @@ -31,7 +31,7 @@ {% else %}
- {{ render(path('_profiler_exception', { token: token })) }} + {{ render(controller('web_profiler.controller.exception_panel::body', { token: token })) }}
{% endif %} {% endblock %} diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/router.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/router.html.twig index 94faa719cd13..a1449c2b272b 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/router.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/router.html.twig @@ -10,5 +10,5 @@ {% endblock %} {% block panel %} - {{ render(path('_profiler_router', { token: token })) }} + {{ render(controller('web_profiler.controller.router::panelAction', { token: token })) }} {% endblock %} diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig index bbd525d095dd..1177954a9d43 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig @@ -108,7 +108,7 @@ {{ include('@WebProfiler/Icon/search.svg') }} Search - {{ render(path('_profiler_search_bar', request.query.all)) }} + {{ render(controller('web_profiler.controller.profiler::searchBarAction', request.query.all)) }} diff --git a/src/Symfony/Bundle/WebProfilerBundle/Twig/WebProfilerExtension.php b/src/Symfony/Bundle/WebProfilerBundle/Twig/WebProfilerExtension.php index a2c8d06c3c37..1f9d54bf71e6 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Twig/WebProfilerExtension.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Twig/WebProfilerExtension.php @@ -44,7 +44,7 @@ class WebProfilerExtension extends ProfilerExtension public function __construct(HtmlDumper $dumper = null) { - $this->dumper = $dumper ?: new HtmlDumper(); + $this->dumper = $dumper ?? new HtmlDumper(); $this->dumper->setOutput($this->output = fopen('php://memory', 'r+')); } diff --git a/src/Symfony/Component/Asset/Package.php b/src/Symfony/Component/Asset/Package.php index b3b1c0be2210..ad6044bd3ee1 100644 --- a/src/Symfony/Component/Asset/Package.php +++ b/src/Symfony/Component/Asset/Package.php @@ -29,7 +29,7 @@ class Package implements PackageInterface public function __construct(VersionStrategyInterface $versionStrategy, ContextInterface $context = null) { $this->versionStrategy = $versionStrategy; - $this->context = $context ?: new NullContext(); + $this->context = $context ?? new NullContext(); } /** diff --git a/src/Symfony/Component/BrowserKit/AbstractBrowser.php b/src/Symfony/Component/BrowserKit/AbstractBrowser.php index 43e0602acacb..b1f0a0abecf7 100644 --- a/src/Symfony/Component/BrowserKit/AbstractBrowser.php +++ b/src/Symfony/Component/BrowserKit/AbstractBrowser.php @@ -53,8 +53,8 @@ abstract class AbstractBrowser public function __construct(array $server = [], History $history = null, CookieJar $cookieJar = null) { $this->setServerParameters($server); - $this->history = $history ?: new History(); - $this->cookieJar = $cookieJar ?: new CookieJar(); + $this->history = $history ?? new History(); + $this->cookieJar = $cookieJar ?? new CookieJar(); } /** diff --git a/src/Symfony/Component/BrowserKit/Response.php b/src/Symfony/Component/BrowserKit/Response.php index f4c04c93eaa8..23b1a373aa83 100644 --- a/src/Symfony/Component/BrowserKit/Response.php +++ b/src/Symfony/Component/BrowserKit/Response.php @@ -84,7 +84,7 @@ public function getHeaders(): array /** * Gets a response header. * - * @return string|array The first header value if $first is true, an array of values otherwise + * @return string|array|null The first header value if $first is true, an array of values otherwise */ public function getHeader(string $header, bool $first = true) { diff --git a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php index 63761947e7e9..6f24ee018762 100644 --- a/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/ArrayAdapter.php @@ -356,6 +356,7 @@ private function freeze($value, $key) try { $serialized = serialize($value); } catch (\Exception $e) { + unset($this->values[$key]); $type = get_debug_type($value); $message = sprintf('Failed to save key "{key}" of type %s: %s', $type, $e->getMessage()); CacheItem::log($this->logger, $message, ['key' => $key, 'exception' => $e, 'cache-adapter' => get_debug_type($this)]); diff --git a/src/Symfony/Component/Cache/Adapter/NullAdapter.php b/src/Symfony/Component/Cache/Adapter/NullAdapter.php index 44778d787b08..fd85840556d6 100644 --- a/src/Symfony/Component/Cache/Adapter/NullAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/NullAdapter.php @@ -112,7 +112,7 @@ public function deleteItems(array $keys) */ public function save(CacheItemInterface $item) { - return false; + return true; } /** @@ -122,7 +122,7 @@ public function save(CacheItemInterface $item) */ public function saveDeferred(CacheItemInterface $item) { - return false; + return true; } /** @@ -132,7 +132,7 @@ public function saveDeferred(CacheItemInterface $item) */ public function commit() { - return false; + return true; } /** diff --git a/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php index 2ee3e367b936..549cbadb80e3 100644 --- a/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php @@ -13,6 +13,8 @@ use Psr\Cache\CacheItemInterface; use Psr\Cache\InvalidArgumentException; +use Psr\Log\LoggerAwareInterface; +use Psr\Log\LoggerAwareTrait; use Symfony\Component\Cache\CacheItem; use Symfony\Component\Cache\PruneableInterface; use Symfony\Component\Cache\ResettableInterface; @@ -23,11 +25,12 @@ /** * @author Nicolas Grekas */ -class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface, PruneableInterface, ResettableInterface +class TagAwareAdapter implements TagAwareAdapterInterface, TagAwareCacheInterface, PruneableInterface, ResettableInterface, LoggerAwareInterface { public const TAGS_PREFIX = "\0tags\0"; use ContractsTrait; + use LoggerAwareTrait; use ProxyTrait; private $deferred = []; diff --git a/src/Symfony/Component/Cache/LockRegistry.php b/src/Symfony/Component/Cache/LockRegistry.php index d8929bebd310..38c0a6cea7b1 100644 --- a/src/Symfony/Component/Cache/LockRegistry.php +++ b/src/Symfony/Component/Cache/LockRegistry.php @@ -82,7 +82,7 @@ public static function setFiles(array $files): array public static function compute(callable $callback, ItemInterface $item, bool &$save, CacheInterface $pool, \Closure $setMetadata = null, LoggerInterface $logger = null) { - $key = self::$files ? crc32($item->getKey()) % \count(self::$files) : -1; + $key = self::$files ? abs(crc32($item->getKey())) % \count(self::$files) : -1; if ($key < 0 || (self::$lockedFiles[$key] ?? false) || !$lock = self::open($key)) { return $callback($item, $save); diff --git a/src/Symfony/Component/Cache/Tests/Adapter/ArrayAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/ArrayAdapterTest.php index f23ca6b80664..1f74ff952eca 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/ArrayAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/ArrayAdapterTest.php @@ -47,6 +47,10 @@ public function testGetValuesHitAndMiss() // Miss (should be present as NULL in $values) $cache->getItem('bar'); + // Fail (should be missing from $values) + $item = $cache->getItem('buz'); + $cache->save($item->set(function() {})); + $values = $cache->getValues(); $this->assertCount(2, $values); diff --git a/src/Symfony/Component/Cache/Tests/Adapter/NullAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/NullAdapterTest.php index ae3de76dc135..3192dff99972 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/NullAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/NullAdapterTest.php @@ -113,7 +113,7 @@ public function testSave() $this->assertFalse($item->isHit()); $this->assertNull($item->get(), "Item's value must be null when isHit is false."); - $this->assertFalse($adapter->save($item)); + $this->assertTrue($adapter->save($item)); } public function testDeferredSave() @@ -124,7 +124,7 @@ public function testDeferredSave() $this->assertFalse($item->isHit()); $this->assertNull($item->get(), "Item's value must be null when isHit is false."); - $this->assertFalse($adapter->saveDeferred($item)); + $this->assertTrue($adapter->saveDeferred($item)); } public function testCommit() @@ -135,7 +135,7 @@ public function testCommit() $this->assertFalse($item->isHit()); $this->assertNull($item->get(), "Item's value must be null when isHit is false."); - $this->assertFalse($adapter->saveDeferred($item)); - $this->assertFalse($this->createCachePool()->commit()); + $this->assertTrue($adapter->saveDeferred($item)); + $this->assertTrue($this->createCachePool()->commit()); } } diff --git a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php index e96db881d079..9a45adaa36e2 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\MockObject\MockObject; use Psr\Cache\CacheItemInterface; use Psr\Cache\CacheItemPoolInterface; +use Psr\Log\LoggerInterface; use Symfony\Component\Cache\Adapter\AdapterInterface; use Symfony\Component\Cache\Adapter\ArrayAdapter; use Symfony\Component\Cache\Adapter\FilesystemAdapter; @@ -197,6 +198,20 @@ public function testGetItemReturnsCacheMissWhenPoolDoesNotHaveItemAndOnlyHasTags $this->assertFalse($item->isHit()); } + public function testLog() + { + $logger = $this->createMock(LoggerInterface::class); + $logger + ->expects($this->atLeastOnce()) + ->method($this->anything()); + + $cache = new TagAwareAdapter(new ArrayAdapter()); + $cache->setLogger($logger); + + // Computing will produce at least one log + $cache->get('foo', static function (): string { return 'ccc'; }); + } + /** * @return MockObject|PruneableCacheInterface */ diff --git a/src/Symfony/Component/Cache/Traits/RedisClusterNodeProxy.php b/src/Symfony/Component/Cache/Traits/RedisClusterNodeProxy.php new file mode 100644 index 000000000000..7818f0b8df9c --- /dev/null +++ b/src/Symfony/Component/Cache/Traits/RedisClusterNodeProxy.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Cache\Traits; + +/** + * This file acts as a wrapper to the \RedisCluster implementation so it can accept the same type of calls as + * individual \Redis objects. + * + * Calls are made to individual nodes via: RedisCluster->{method}($host, ...args)' + * according to https://github.com/phpredis/phpredis/blob/develop/cluster.markdown#directed-node-commands + * + * @author Jack Thomas + * + * @internal + */ +class RedisClusterNodeProxy +{ + private $host; + private $redis; + + /** + * @param \RedisCluster|RedisClusterProxy $redis + */ + public function __construct(array $host, $redis) + { + $this->host = $host; + $this->redis = $redis; + } + + public function __call(string $method, array $args) + { + return $this->redis->{$method}($this->host, ...$args); + } + + public function scan(&$iIterator, $strPattern = null, $iCount = null) + { + return $this->redis->scan($iIterator, $this->host, $strPattern, $iCount); + } +} diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php index 67f1042d0510..e33f75da173e 100644 --- a/src/Symfony/Component/Cache/Traits/RedisTrait.php +++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php @@ -42,6 +42,7 @@ trait RedisTrait 'redis_sentinel' => null, 'dbindex' => 0, 'failover' => 'none', + 'ssl' => null, // see https://php.net/context.ssl ]; private $redis; private $marshaller; @@ -188,7 +189,7 @@ public static function createConnection($dsn, array $options = []) } try { - @$redis->{$connect}($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout']); + @$redis->{$connect}($host, $port, $params['timeout'], (string) $params['persistent_id'], $params['retry_interval'], $params['read_timeout'], ['stream' => $params['ssl'] ?? null]); set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; }); $isConnected = $redis->isConnected(); @@ -251,7 +252,7 @@ public static function createConnection($dsn, array $options = []) } try { - $redis = new $class(null, $hosts, $params['timeout'], $params['read_timeout'], (bool) $params['persistent'], $params['auth'] ?? ''); + $redis = new $class(null, $hosts, $params['timeout'], $params['read_timeout'], (bool) $params['persistent'], $params['auth'] ?? '', $params['ssl'] ?? null); } catch (\RedisClusterException $e) { throw new InvalidArgumentException(sprintf('Redis connection "%s" failed: ', $dsn).$e->getMessage()); } @@ -300,7 +301,7 @@ public static function createConnection($dsn, array $options = []) } $params['exceptions'] = false; - $redis = new $class($hosts, array_diff_key($params, self::$defaultConnectionOptions)); + $redis = new $class($hosts, array_diff_key($params, array_diff_key(self::$defaultConnectionOptions, ['ssl' => null]))); if (isset($params['redis_sentinel'])) { $redis->getConnection()->setSentinelTimeout($params['timeout']); } @@ -547,8 +548,7 @@ private function getHosts(): array } elseif ($this->redis instanceof RedisClusterProxy || $this->redis instanceof \RedisCluster) { $hosts = []; foreach ($this->redis->_masters() as $host) { - $hosts[] = $h = new \Redis(); - $h->connect($host[0], $host[1]); + $hosts[] = new RedisClusterNodeProxy($host, $this->redis); } } diff --git a/src/Symfony/Component/Config/Definition/ArrayNode.php b/src/Symfony/Component/Config/Definition/ArrayNode.php index 2f8fa7525162..fb17f30338ee 100644 --- a/src/Symfony/Component/Config/Definition/ArrayNode.php +++ b/src/Symfony/Component/Config/Definition/ArrayNode.php @@ -68,7 +68,7 @@ protected function preNormalize($value) /** * Retrieves the children of this node. * - * @return array The children + * @return array */ public function getChildren() { diff --git a/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php b/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php index 6ac04a165106..0d9c91fea466 100644 --- a/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php +++ b/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php @@ -124,7 +124,9 @@ public function getNode(bool $forceRootNode = false) } $node = $this->createNode(); - $node->setAttributes($this->attributes); + if ($node instanceof BaseNode) { + $node->setAttributes($this->attributes); + } return $node; } diff --git a/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php b/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php index 13a18db3ae1c..f3c3c2109cd7 100644 --- a/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php +++ b/src/Symfony/Component/Config/Definition/Builder/TreeBuilder.php @@ -25,7 +25,7 @@ class TreeBuilder implements NodeParentInterface public function __construct(string $name, string $type = 'array', NodeBuilder $builder = null) { - $builder = $builder ?: new NodeBuilder(); + $builder = $builder ?? new NodeBuilder(); $this->root = $builder->node($name, $type)->setParent($this); } diff --git a/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php b/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php index a9589c53afe5..c4af75c12532 100644 --- a/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php +++ b/src/Symfony/Component/Config/Definition/Dumper/XmlReferenceDumper.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Config\Definition\Dumper; use Symfony\Component\Config\Definition\ArrayNode; +use Symfony\Component\Config\Definition\BaseNode; use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\Definition\EnumNode; use Symfony\Component\Config\Definition\NodeInterface; @@ -126,51 +127,53 @@ private function writeNode(NodeInterface $node, int $depth = 0, bool $root = fal // get attributes and elements foreach ($children as $child) { - if (!$child instanceof ArrayNode) { - // get attributes + if ($child instanceof ArrayNode) { + // get elements + $rootChildren[] = $child; - // metadata - $name = str_replace('_', '-', $child->getName()); - $value = '%%%%not_defined%%%%'; // use a string which isn't used in the normal world + continue; + } - // comments - $comments = []; - if ($info = $child->getInfo()) { - $comments[] = $info; - } + // get attributes - if ($example = $child->getExample()) { - $comments[] = 'Example: '.$example; - } + // metadata + $name = str_replace('_', '-', $child->getName()); + $value = '%%%%not_defined%%%%'; // use a string which isn't used in the normal world - if ($child->isRequired()) { - $comments[] = 'Required'; - } + // comments + $comments = []; + if ($child instanceof BaseNode && $info = $child->getInfo()) { + $comments[] = $info; + } - if ($child->isDeprecated()) { - $deprecation = $child->getDeprecation($child->getName(), $node->getPath()); - $comments[] = sprintf('Deprecated (%s)', ($deprecation['package'] || $deprecation['version'] ? "Since {$deprecation['package']} {$deprecation['version']}: " : '').$deprecation['message']); - } + if ($child instanceof BaseNode && $example = $child->getExample()) { + $comments[] = 'Example: '.$example; + } - if ($child instanceof EnumNode) { - $comments[] = 'One of '.implode('; ', array_map('json_encode', $child->getValues())); - } + if ($child->isRequired()) { + $comments[] = 'Required'; + } - if (\count($comments)) { - $rootAttributeComments[$name] = implode(";\n", $comments); - } + if ($child instanceof BaseNode && $child->isDeprecated()) { + $deprecation = $child->getDeprecation($child->getName(), $node->getPath()); + $comments[] = sprintf('Deprecated (%s)', ($deprecation['package'] || $deprecation['version'] ? "Since {$deprecation['package']} {$deprecation['version']}: " : '').$deprecation['message']); + } - // default values - if ($child->hasDefaultValue()) { - $value = $child->getDefaultValue(); - } + if ($child instanceof EnumNode) { + $comments[] = 'One of '.implode('; ', array_map('json_encode', $child->getValues())); + } - // append attribute - $rootAttributes[$name] = $value; - } else { - // get elements - $rootChildren[] = $child; + if (\count($comments)) { + $rootAttributeComments[$name] = implode(";\n", $comments); } + + // default values + if ($child->hasDefaultValue()) { + $value = $child->getDefaultValue(); + } + + // append attribute + $rootAttributes[$name] = $value; } } diff --git a/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php b/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php index 8f77076eb422..6fcfb71bd981 100644 --- a/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php +++ b/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Config\Definition\Dumper; use Symfony\Component\Config\Definition\ArrayNode; +use Symfony\Component\Config\Definition\BaseNode; use Symfony\Component\Config\Definition\ConfigurationInterface; use Symfony\Component\Config\Definition\EnumNode; use Symfony\Component\Config\Definition\NodeInterface; @@ -76,7 +77,10 @@ private function writeNode(NodeInterface $node, NodeInterface $parentNode = null $default = ''; $defaultArray = null; $children = null; - $example = $node->getExample(); + $example = null; + if ($node instanceof BaseNode) { + $example = $node->getExample(); + } // defaults if ($node instanceof ArrayNode) { @@ -123,7 +127,7 @@ private function writeNode(NodeInterface $node, NodeInterface $parentNode = null } // deprecated? - if ($node->isDeprecated()) { + if ($node instanceof BaseNode && $node->isDeprecated()) { $deprecation = $node->getDeprecation($node->getName(), $parentNode ? $parentNode->getPath() : $node->getPath()); $comments[] = sprintf('Deprecated (%s)', ($deprecation['package'] || $deprecation['version'] ? "Since {$deprecation['package']} {$deprecation['version']}: " : '').$deprecation['message']); } @@ -139,7 +143,7 @@ private function writeNode(NodeInterface $node, NodeInterface $parentNode = null $key = $prototypedArray ? '-' : $node->getName().':'; $text = rtrim(sprintf('%-21s%s %s', $key, $default, $comments), ' '); - if ($info = $node->getInfo()) { + if ($node instanceof BaseNode && $info = $node->getInfo()) { $this->writeLine(''); // indenting multi-line info $info = str_replace("\n", sprintf("\n%".($depth * 4).'s# ', ' '), $info); diff --git a/src/Symfony/Component/Config/Exception/LoaderLoadException.php b/src/Symfony/Component/Config/Exception/LoaderLoadException.php index 86886058668a..b31b2bc0075e 100644 --- a/src/Symfony/Component/Config/Exception/LoaderLoadException.php +++ b/src/Symfony/Component/Config/Exception/LoaderLoadException.php @@ -64,7 +64,7 @@ public function __construct(string $resource, string $sourceResource = null, ?in } elseif (null !== $type) { // maybe there is no loader for this specific type if ('annotation' === $type) { - $message .= ' Make sure annotations are installed and enabled.'; + $message .= ' Make sure to use PHP 8+ or that annotations are installed and enabled.'; } else { $message .= sprintf(' Make sure there is a loader supporting the "%s" type.', $type); } diff --git a/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php b/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php index 8e938a9d681a..8d84ae50babe 100644 --- a/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php @@ -57,6 +57,7 @@ private function getConfigurationAsString() node-with-a-looong-name="" enum-with-default="this" enum="" + custom-node="true" > diff --git a/src/Symfony/Component/Config/Tests/Definition/Dumper/YamlReferenceDumperTest.php b/src/Symfony/Component/Config/Tests/Definition/Dumper/YamlReferenceDumperTest.php index 73dc785542ca..f5935c6e0743 100644 --- a/src/Symfony/Component/Config/Tests/Definition/Dumper/YamlReferenceDumperTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/Dumper/YamlReferenceDumperTest.php @@ -137,6 +137,7 @@ enum: ~ # One of "this"; "that" # Prototype name: [] + custom_node: true EOL; } diff --git a/src/Symfony/Component/Config/Tests/Exception/LoaderLoadExceptionTest.php b/src/Symfony/Component/Config/Tests/Exception/LoaderLoadExceptionTest.php index 67c40edd2c33..3150c5a83c31 100644 --- a/src/Symfony/Component/Config/Tests/Exception/LoaderLoadExceptionTest.php +++ b/src/Symfony/Component/Config/Tests/Exception/LoaderLoadExceptionTest.php @@ -31,7 +31,7 @@ public function testMessageCannotLoadResourceWithType() public function testMessageCannotLoadResourceWithAnnotationType() { $exception = new LoaderLoadException('resource', null, 0, null, 'annotation'); - $this->assertEquals('Cannot load resource "resource". Make sure annotations are installed and enabled.', $exception->getMessage()); + $this->assertEquals('Cannot load resource "resource". Make sure to use PHP 8+ or that annotations are installed and enabled.', $exception->getMessage()); } public function testMessageCannotImportResourceFromSource() diff --git a/src/Symfony/Component/Config/Tests/Fixtures/Configuration/CustomNode.php b/src/Symfony/Component/Config/Tests/Fixtures/Configuration/CustomNode.php new file mode 100644 index 000000000000..1270eb6a6832 --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Fixtures/Configuration/CustomNode.php @@ -0,0 +1,49 @@ +end() ->end() ->end() + ->append(new CustomNodeDefinition('acme')) ->end() ; diff --git a/src/Symfony/Component/Console/Descriptor/Descriptor.php b/src/Symfony/Component/Console/Descriptor/Descriptor.php index 2834cd0aa66b..2ecc59e4e27e 100644 --- a/src/Symfony/Component/Console/Descriptor/Descriptor.php +++ b/src/Symfony/Component/Console/Descriptor/Descriptor.php @@ -69,36 +69,26 @@ protected function write(string $content, bool $decorated = false) /** * Describes an InputArgument instance. - * - * @return string|mixed */ abstract protected function describeInputArgument(InputArgument $argument, array $options = []); /** * Describes an InputOption instance. - * - * @return string|mixed */ abstract protected function describeInputOption(InputOption $option, array $options = []); /** * Describes an InputDefinition instance. - * - * @return string|mixed */ abstract protected function describeInputDefinition(InputDefinition $definition, array $options = []); /** * Describes a Command instance. - * - * @return string|mixed */ abstract protected function describeCommand(Command $command, array $options = []); /** * Describes an Application instance. - * - * @return string|mixed */ abstract protected function describeApplication(Application $application, array $options = []); } diff --git a/src/Symfony/Component/Console/Descriptor/TextDescriptor.php b/src/Symfony/Component/Console/Descriptor/TextDescriptor.php index 07aef2a31a56..ccfbd6d36dfe 100644 --- a/src/Symfony/Component/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Component/Console/Descriptor/TextDescriptor.php @@ -296,7 +296,7 @@ private function formatDefaultValue($default): string } /** - * @param (Command|string)[] $commands + * @param array $commands */ private function getColumnWidth(array $commands): int { diff --git a/src/Symfony/Component/Console/Formatter/OutputFormatterStyleStack.php b/src/Symfony/Component/Console/Formatter/OutputFormatterStyleStack.php index 33f7d5222a4c..fc48dc0e15e6 100644 --- a/src/Symfony/Component/Console/Formatter/OutputFormatterStyleStack.php +++ b/src/Symfony/Component/Console/Formatter/OutputFormatterStyleStack.php @@ -28,7 +28,7 @@ class OutputFormatterStyleStack implements ResetInterface public function __construct(OutputFormatterStyleInterface $emptyStyle = null) { - $this->emptyStyle = $emptyStyle ?: new OutputFormatterStyle(); + $this->emptyStyle = $emptyStyle ?? new OutputFormatterStyle(); $this->reset(); } diff --git a/src/Symfony/Component/Console/Helper/Helper.php b/src/Symfony/Component/Console/Helper/Helper.php index acec994db83c..e4f9ca907345 100644 --- a/src/Symfony/Component/Console/Helper/Helper.php +++ b/src/Symfony/Component/Console/Helper/Helper.php @@ -45,6 +45,17 @@ public function getHelperSet() * @return int The length of the string */ public static function strlen(?string $string) + { + return self::width($string); + } + + /** + * Returns the width of a string, using mb_strwidth if it is available. + * The width is how many characters positions the string will use. + * + * @internal in Symfony 5.2 + */ + public static function width(?string $string): int { $string ?? $string = ''; @@ -59,6 +70,27 @@ public static function strlen(?string $string) return mb_strwidth($string, $encoding); } + /** + * Returns the length of a string, using mb_strlen if it is available. + * The length is related to how many bytes the string will use. + * + * @internal in Symfony 5.2 + */ + public static function length(?string $string): int + { + $string ?? $string = ''; + + if (preg_match('//u', $string)) { + return (new UnicodeString($string))->length(); + } + + if (false === $encoding = mb_detect_encoding($string, null, true)) { + return \strlen($string); + } + + return mb_strlen($string, $encoding); + } + /** * Returns the subset of a string, using mb_substr if it is available. * @@ -123,13 +155,7 @@ public static function formatMemory(int $memory) public static function strlenWithoutDecoration(OutputFormatterInterface $formatter, ?string $string) { - $string = self::removeDecoration($formatter, $string); - - if (preg_match('//u', $string)) { - return (new UnicodeString($string))->width(true); - } - - return self::strlen($string); + return self::width(self::removeDecoration($formatter, $string)); } public static function removeDecoration(OutputFormatterInterface $formatter, ?string $string) diff --git a/src/Symfony/Component/Console/Helper/ProgressBar.php b/src/Symfony/Component/Console/Helper/ProgressBar.php index 61c471424ad4..fb90369257f1 100644 --- a/src/Symfony/Component/Console/Helper/ProgressBar.php +++ b/src/Symfony/Component/Console/Helper/ProgressBar.php @@ -513,7 +513,7 @@ private static function initPlaceholderFormatters(): array $completeBars = $bar->getBarOffset(); $display = str_repeat($bar->getBarCharacter(), $completeBars); if ($completeBars < $bar->getBarWidth()) { - $emptyBars = $bar->getBarWidth() - $completeBars - Helper::strlenWithoutDecoration($output->getFormatter(), $bar->getProgressCharacter()); + $emptyBars = $bar->getBarWidth() - $completeBars - Helper::length(Helper::removeDecoration($output->getFormatter(), $bar->getProgressCharacter())); $display .= $bar->getProgressCharacter().str_repeat($bar->getEmptyBarCharacter(), $emptyBars); } diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php index 5bf8186b8fbf..72880f6a69cc 100644 --- a/src/Symfony/Component/Console/Helper/QuestionHelper.php +++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php @@ -99,7 +99,7 @@ public static function disableStty() /** * Asks the question to the user. * - * @return bool|mixed|string|null + * @return mixed * * @throws RuntimeException In case the fallback is deactivated and the response cannot be hidden */ diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php index 04114540356f..ee969bcffb3e 100644 --- a/src/Symfony/Component/Console/Helper/Table.php +++ b/src/Symfony/Component/Console/Helper/Table.php @@ -511,7 +511,7 @@ private function renderCell(array $row, int $column, string $cellFormat): string return sprintf($style->getBorderFormat(), str_repeat($style->getBorderChars()[2], $width)); } - $width += Helper::strlen($cell) - Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell); + $width += Helper::length($cell) - Helper::length(Helper::removeDecoration($this->output->getFormatter(), $cell)); $content = sprintf($style->getCellRowContentFormat(), $cell); $padType = $style->getPadType(); diff --git a/src/Symfony/Component/Console/Input/InputOption.php b/src/Symfony/Component/Console/Input/InputOption.php index a8e956db55b1..5e48f88b81cb 100644 --- a/src/Symfony/Component/Console/Input/InputOption.php +++ b/src/Symfony/Component/Console/Input/InputOption.php @@ -21,9 +21,24 @@ */ class InputOption { + /** + * Do not accept input for the option (e.g. --yell). This is the default behavior of options. + */ public const VALUE_NONE = 1; + + /** + * A value must be passed when the option is used (e.g. --iterations=5 or -i5). + */ public const VALUE_REQUIRED = 2; + + /** + * The option may or may not have a value (e.g. --yell or --yell=loud). + */ public const VALUE_OPTIONAL = 4; + + /** + * The option accepts multiple values (e.g. --dir=/foo --dir=/bar). + */ public const VALUE_IS_ARRAY = 8; private $name; diff --git a/src/Symfony/Component/Console/Output/Output.php b/src/Symfony/Component/Console/Output/Output.php index ed13d58fc0d2..1b01472cdf9a 100644 --- a/src/Symfony/Component/Console/Output/Output.php +++ b/src/Symfony/Component/Console/Output/Output.php @@ -40,7 +40,7 @@ abstract class Output implements OutputInterface public function __construct(?int $verbosity = self::VERBOSITY_NORMAL, bool $decorated = false, OutputFormatterInterface $formatter = null) { $this->verbosity = null === $verbosity ? self::VERBOSITY_NORMAL : $verbosity; - $this->formatter = $formatter ?: new OutputFormatter(); + $this->formatter = $formatter ?? new OutputFormatter(); $this->formatter->setDecorated($decorated); } diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php index 8baf5a6d824c..71b6c7850ee0 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProgressBarTest.php @@ -899,6 +899,21 @@ public function testSetFormat() ); } + public function testUnicode() + { + $bar = new ProgressBar($output = $this->getOutputStream(), 10, 0); + ProgressBar::setFormatDefinition('test', '%current%/%max% [%bar%] %percent:3s%% %message% Fruitcake marzipan toffee. Cupcake gummi bears tart dessert ice cream chupa chups cupcake chocolate bar sesame snaps. Croissant halvah cookie jujubes powder macaroon. Fruitcake bear claw bonbon jelly beans oat cake pie muffin Fruitcake marzipan toffee.'); + $bar->setFormat('test'); + $bar->setProgressCharacter('💧'); + $bar->start(); + rewind($output->getStream()); + $this->assertStringContainsString( + ' 0/10 [💧] 0%', + stream_get_contents($output->getStream()) + ); + $bar->finish(); + } + /** * @dataProvider provideFormat */ diff --git a/src/Symfony/Component/CssSelector/Parser/Parser.php b/src/Symfony/Component/CssSelector/Parser/Parser.php index 63e883dcfa70..963efb013eef 100644 --- a/src/Symfony/Component/CssSelector/Parser/Parser.php +++ b/src/Symfony/Component/CssSelector/Parser/Parser.php @@ -31,7 +31,7 @@ class Parser implements ParserInterface public function __construct(Tokenizer $tokenizer = null) { - $this->tokenizer = $tokenizer ?: new Tokenizer(); + $this->tokenizer = $tokenizer ?? new Tokenizer(); } /** diff --git a/src/Symfony/Component/CssSelector/XPath/Translator.php b/src/Symfony/Component/CssSelector/XPath/Translator.php index d1b65187ecbd..13e1adacd583 100644 --- a/src/Symfony/Component/CssSelector/XPath/Translator.php +++ b/src/Symfony/Component/CssSelector/XPath/Translator.php @@ -50,7 +50,7 @@ class Translator implements TranslatorInterface public function __construct(ParserInterface $parser = null) { - $this->mainParser = $parser ?: new Parser(); + $this->mainParser = $parser ?? new Parser(); $this ->registerExtension(new Extension\NodeExtension()) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AliasDeprecatedPublicServicesPass.php b/src/Symfony/Component/DependencyInjection/Compiler/AliasDeprecatedPublicServicesPass.php index 802c40766212..a44767de3ab6 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AliasDeprecatedPublicServicesPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AliasDeprecatedPublicServicesPass.php @@ -54,7 +54,7 @@ public function process(ContainerBuilder $container) $definition = $container->getDefinition($id); if (!$definition->isPublic() || $definition->isPrivate()) { - throw new InvalidArgumentException(sprintf('The "%s" service is private: it cannot have the "%s" tag.', $id, $this->tagName)); + continue; } $container diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php index e2c98b6889fa..e12c9a597383 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckTypeDeclarationsPass.php @@ -78,7 +78,7 @@ public function __construct(bool $autoload = false, array $skippedIds = []) /** * {@inheritdoc} */ - protected function processValue($value, $isRoot = false) + protected function processValue($value, bool $isRoot = false) { if (isset($this->skippedIds[$this->currentId])) { return $value; diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php index 2654dceb6264..b4d40fbced69 100644 --- a/src/Symfony/Component/DependencyInjection/Container.php +++ b/src/Symfony/Component/DependencyInjection/Container.php @@ -64,7 +64,7 @@ class Container implements ContainerInterface, ResetInterface public function __construct(ParameterBagInterface $parameterBag = null) { - $this->parameterBag = $parameterBag ?: new EnvPlaceholderParameterBag(); + $this->parameterBag = $parameterBag ?? new EnvPlaceholderParameterBag(); } /** diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index 15d6d16adcd7..9e858b25ea81 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -357,7 +357,7 @@ public function getReflectionClass(?string $class, bool $throw = true): ?\Reflec if ($this->trackResources) { if (!$classReflector) { - $this->addResource($resource ?: new ClassExistenceResource($class, false)); + $this->addResource($resource ?? new ClassExistenceResource($class, false)); } elseif (!$classReflector->isInternal()) { $path = $classReflector->getFileName(); diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php index 7e71d0f661eb..b5a06f5b8f03 100644 --- a/src/Symfony/Component/DependencyInjection/Definition.php +++ b/src/Symfony/Component/DependencyInjection/Definition.php @@ -96,7 +96,7 @@ public function setChanges(array $changes) /** * Sets a factory. * - * @param string|array|Reference $factory A PHP function, reference or an array containing a class/Reference and a method to call + * @param string|array|Reference|null $factory A PHP function, reference or an array containing a class/Reference and a method to call * * @return $this */ diff --git a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php index a85fc64b04f8..39eb3d996711 100644 --- a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php +++ b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php @@ -255,8 +255,10 @@ public function getEnv(string $prefix, string $name, \Closure $getEnv) 'fragment' => null, ]; - // remove the '/' separator - $parsedEnv['path'] = '/' === $parsedEnv['path'] ? null : substr($parsedEnv['path'], 1); + if (null !== $parsedEnv['path']) { + // remove the '/' separator + $parsedEnv['path'] = '/' === $parsedEnv['path'] ? null : substr($parsedEnv['path'], 1); + } return $parsedEnv; } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AliasDeprecatedPublicServicesPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AliasDeprecatedPublicServicesPassTest.php index b1f13ddb29d5..d03ece235afc 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AliasDeprecatedPublicServicesPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AliasDeprecatedPublicServicesPassTest.php @@ -59,14 +59,13 @@ public function processWithMissingAttributeProvider() public function testProcessWithNonPublicService() { - $this->expectException(InvalidArgumentException::class); - $this->expectExceptionMessage('The "foo" service is private: it cannot have the "container.private" tag.'); - $container = new ContainerBuilder(); $container ->register('foo') ->addTag('container.private', ['package' => 'foo/bar', 'version' => '1.2']); (new AliasDeprecatedPublicServicesPass())->process($container); + + $this->assertTrue($container->hasDefinition('foo')); } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php index 9f059a80d989..2a6b445e7adf 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/IntegrationTest.php @@ -168,7 +168,7 @@ public function testCanDecorateServiceLocator() public function testYamlContainerCompiles($directory, $actualServiceId, $expectedServiceId, ContainerBuilder $mainContainer = null) { // allow a container to be passed in, which might have autoconfigure settings - $container = $mainContainer ?: new ContainerBuilder(); + $container = $mainContainer ?? new ContainerBuilder(); $container->setResourceTracking(false); $loader = new YamlFileLoader($container, new FileLocator(__DIR__.'/../Fixtures/yaml/integration/'.$directory)); $loader->load('main.yml'); diff --git a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php index ab5f24b2ecba..45a64e4f8e05 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/EnvVarProcessorTest.php @@ -610,4 +610,26 @@ public function testGetEnvInvalidPrefixWithDefault() return null; }); } + + /** + * @dataProvider provideGetEnvUrlPath + */ + public function testGetEnvUrlPath(?string $expected, string $url) + { + $this->assertSame($expected, (new EnvVarProcessor(new Container()))->getEnv('url', 'foo', static function () use ($url): string { + return $url; + })['path']); + } + + public function provideGetEnvUrlPath() + { + return [ + [null, 'https://symfony.com'], + [null, 'https://symfony.com/'], + ['/', 'https://symfony.com//'], + ['blog', 'https://symfony.com/blog'], + ['blog/', 'https://symfony.com/blog/'], + ['blog//', 'https://symfony.com/blog//'], + ]; + } } diff --git a/src/Symfony/Component/ErrorHandler/Error/FatalError.php b/src/Symfony/Component/ErrorHandler/Error/FatalError.php index 98490b5accc4..57fc690e26d6 100644 --- a/src/Symfony/Component/ErrorHandler/Error/FatalError.php +++ b/src/Symfony/Component/ErrorHandler/Error/FatalError.php @@ -33,8 +33,7 @@ public function __construct(string $message, int $code, array $error, int $trace } } } elseif (null !== $traceOffset) { - if (\function_exists('xdebug_get_function_stack')) { - $trace = xdebug_get_function_stack(); + if (\function_exists('xdebug_get_function_stack') && $trace = @xdebug_get_function_stack()) { if (0 < $traceOffset) { array_splice($trace, -$traceOffset); } diff --git a/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php b/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php index 03545e2ae03c..7c3bc7d395b5 100644 --- a/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php +++ b/src/Symfony/Component/ExpressionLanguage/ExpressionLanguage.php @@ -36,7 +36,7 @@ class ExpressionLanguage */ public function __construct(CacheItemPoolInterface $cache = null, array $providers = []) { - $this->cache = $cache ?: new ArrayAdapter(); + $this->cache = $cache ?? new ArrayAdapter(); $this->registerFunctions(); foreach ($providers as $provider) { $this->registerProvider($provider); diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index 35c568e71e7d..3498e7f9fb53 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -55,7 +55,7 @@ public function copy(string $originFile, string $targetFile, bool $overwriteNewe } // Stream context created to allow files overwrite when using FTP stream wrapper - disabled by default - if (false === $target = @fopen($targetFile, 'w', null, stream_context_create(['ftp' => ['overwrite' => true]]))) { + if (false === $target = @fopen($targetFile, 'w', false, stream_context_create(['ftp' => ['overwrite' => true]]))) { throw new IOException(sprintf('Failed to copy "%s" to "%s" because target file could not be opened for writing.', $originFile, $targetFile), 0, null, $originFile); } diff --git a/src/Symfony/Component/Form/Extension/Core/CoreExtension.php b/src/Symfony/Component/Form/Extension/Core/CoreExtension.php index 04e9dd45861f..9c19603df003 100644 --- a/src/Symfony/Component/Form/Extension/Core/CoreExtension.php +++ b/src/Symfony/Component/Form/Extension/Core/CoreExtension.php @@ -35,7 +35,7 @@ class CoreExtension extends AbstractExtension public function __construct(PropertyAccessorInterface $propertyAccessor = null, ChoiceListFactoryInterface $choiceListFactory = null, TranslatorInterface $translator = null) { $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor(); - $this->choiceListFactory = $choiceListFactory ?: new CachingFactoryDecorator(new PropertyAccessDecorator(new DefaultChoiceListFactory(), $this->propertyAccessor)); + $this->choiceListFactory = $choiceListFactory ?? new CachingFactoryDecorator(new PropertyAccessDecorator(new DefaultChoiceListFactory(), $this->propertyAccessor)); $this->translator = $translator; } diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php index 8cfc6eff2e93..e9896732f902 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToArrayTransformer.php @@ -42,7 +42,7 @@ public function __construct(string $inputTimezone = null, string $outputTimezone $this->fields = $fields; $this->pad = $pad; - $this->referenceDate = $referenceDate ?: new \DateTimeImmutable('1970-01-01 00:00:00'); + $this->referenceDate = $referenceDate ?? new \DateTimeImmutable('1970-01-01 00:00:00'); } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php index fc30dd57e3f0..e670ae9ac986 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php @@ -56,7 +56,7 @@ class ChoiceType extends AbstractType */ public function __construct(ChoiceListFactoryInterface $choiceListFactory = null, $translator = null) { - $this->choiceListFactory = $choiceListFactory ?: new CachingFactoryDecorator( + $this->choiceListFactory = $choiceListFactory ?? new CachingFactoryDecorator( new PropertyAccessDecorator( new DefaultChoiceListFactory() ) @@ -186,13 +186,14 @@ public function buildForm(FormBuilderInterface $builder, array $options) } if ($options['multiple']) { - $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) use (&$unknownValues) { + $messageTemplate = $options['invalid_message'] ?? 'The value {{ value }} is not valid.'; + + $builder->addEventListener(FormEvents::POST_SUBMIT, function (FormEvent $event) use (&$unknownValues, $messageTemplate) { // Throw exception if unknown values were submitted if (\count($unknownValues) > 0) { $form = $event->getForm(); - $clientDataAsString = is_scalar($form->getViewData()) ? (string) $form->getViewData() : \gettype($form->getViewData()); - $messageTemplate = 'The value {{ value }} is not valid.'; + $clientDataAsString = is_scalar($form->getViewData()) ? (string) $form->getViewData() : (\is_array($form->getViewData()) ? implode('", "', array_keys($unknownValues)) : \gettype($form->getViewData())); if (null !== $this->translator) { $message = $this->translator->trans($messageTemplate, ['{{ value }}' => $clientDataAsString], 'validators'); @@ -200,7 +201,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) $message = strtr($messageTemplate, ['{{ value }}' => $clientDataAsString]); } - $form->addError(new FormError($message, $messageTemplate, ['{{ value }}' => $clientDataAsString], null, new TransformationFailedException(sprintf('The choices "%s" do not exist in the choice list.', implode('", "', array_keys($unknownValues)))))); + $form->addError(new FormError($message, $messageTemplate, ['{{ value }}' => $clientDataAsString], null, new TransformationFailedException(sprintf('The choices "%s" do not exist in the choice list.', $clientDataAsString)))); } }); diff --git a/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php b/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php index d30bdef61e8e..37548ef55053 100644 --- a/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php +++ b/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php @@ -48,7 +48,7 @@ public function __construct(string $fieldName, CsrfTokenManagerInterface $tokenM $this->errorMessage = $errorMessage; $this->translator = $translator; $this->translationDomain = $translationDomain; - $this->serverParams = $serverParams ?: new ServerParams(); + $this->serverParams = $serverParams ?? new ServerParams(); } public function preSubmit(FormEvent $event) diff --git a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php index 47ce62feefe1..05503ff52977 100644 --- a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php +++ b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php @@ -32,7 +32,7 @@ class HttpFoundationRequestHandler implements RequestHandlerInterface public function __construct(ServerParams $serverParams = null) { - $this->serverParams = $serverParams ?: new ServerParams(); + $this->serverParams = $serverParams ?? new ServerParams(); } /** diff --git a/src/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php b/src/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php index 33b053b3a3e7..0d77f06ce3fd 100644 --- a/src/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php +++ b/src/Symfony/Component/Form/Extension/HttpFoundation/Type/FormTypeHttpFoundationExtension.php @@ -26,7 +26,7 @@ class FormTypeHttpFoundationExtension extends AbstractTypeExtension public function __construct(RequestHandlerInterface $requestHandler = null) { - $this->requestHandler = $requestHandler ?: new HttpFoundationRequestHandler(); + $this->requestHandler = $requestHandler ?? new HttpFoundationRequestHandler(); } /** diff --git a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php index 65e9d4e71abe..d14055f16cc3 100644 --- a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php +++ b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php @@ -203,7 +203,7 @@ public function validate($form, Constraint $formConstraint) /** * Returns the validation groups of the given form. * - * @return string|GroupSequence|(string|GroupSequence)[] The validation groups + * @return string|GroupSequence|array The validation groups */ private function getValidationGroups(FormInterface $form) { @@ -242,9 +242,9 @@ private function getValidationGroups(FormInterface $form) /** * Post-processes the validation groups option for a given form. * - * @param string|GroupSequence|(string|GroupSequence)[]|callable $groups The validation groups + * @param string|GroupSequence|array|callable $groups The validation groups * - * @return GroupSequence|(string|GroupSequence)[] The validation groups + * @return GroupSequence|array The validation groups */ private static function resolveValidationGroups($groups, FormInterface $form) { diff --git a/src/Symfony/Component/Form/FormFactoryBuilder.php b/src/Symfony/Component/Form/FormFactoryBuilder.php index a33613e2e57c..e10c947f6864 100644 --- a/src/Symfony/Component/Form/FormFactoryBuilder.php +++ b/src/Symfony/Component/Form/FormFactoryBuilder.php @@ -180,7 +180,7 @@ public function getFormFactory() $extensions[] = new PreloadedExtension($this->types, $this->typeExtensions, $typeGuesser); } - $registry = new FormRegistry($extensions, $this->resolvedTypeFactory ?: new ResolvedFormTypeFactory()); + $registry = new FormRegistry($extensions, $this->resolvedTypeFactory ?? new ResolvedFormTypeFactory()); return new FormFactory($registry); } diff --git a/src/Symfony/Component/Form/NativeRequestHandler.php b/src/Symfony/Component/Form/NativeRequestHandler.php index e65492466e73..6b18df44a165 100644 --- a/src/Symfony/Component/Form/NativeRequestHandler.php +++ b/src/Symfony/Component/Form/NativeRequestHandler.php @@ -36,7 +36,7 @@ class NativeRequestHandler implements RequestHandlerInterface public function __construct(ServerParams $params = null) { - $this->serverParams = $params ?: new ServerParams(); + $this->serverParams = $params ?? new ServerParams(); } /** diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index 7e68bb147bf3..e9141b860a93 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -26,6 +26,7 @@ abstract class AbstractLayoutTest extends FormIntegrationTestCase protected $csrfTokenManager; protected $testableFeatures = []; + private $defaultLocale; protected function setUp(): void { @@ -33,6 +34,7 @@ protected function setUp(): void $this->markTestSkipped('Extension intl is required.'); } + $this->defaultLocale = \Locale::getDefault(); \Locale::setDefault('en'); $this->csrfTokenManager = $this->createMock(CsrfTokenManagerInterface::class); @@ -50,6 +52,7 @@ protected function getExtensions() protected function tearDown(): void { $this->csrfTokenManager = null; + \Locale::setDefault($this->defaultLocale); parent::tearDown(); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php index e2aa4748d8cf..cde7cd531a89 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php @@ -23,6 +23,7 @@ class DateTimeToLocalizedStringTransformerTest extends TestCase protected $dateTime; protected $dateTimeWithoutSeconds; + private $defaultLocale; protected function setUp(): void { @@ -37,6 +38,7 @@ protected function setUp(): void // Since we test against "de_AT", we need the full implementation IntlTestHelper::requireFullIntl($this, '57.1'); + $this->defaultLocale = \Locale::getDefault(); \Locale::setDefault('de_AT'); $this->dateTime = new \DateTime('2010-02-03 04:05:06 UTC'); @@ -47,6 +49,7 @@ protected function tearDown(): void { $this->dateTime = null; $this->dateTimeWithoutSeconds = null; + \Locale::setDefault($this->defaultLocale); } public function dataProvider() diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php index 3ab3c2d50135..7f9d436679b3 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php @@ -19,15 +19,18 @@ class MoneyToLocalizedStringTransformerTest extends TestCase { private $previousLocale; + private $defaultLocale; protected function setUp(): void { $this->previousLocale = setlocale(\LC_ALL, '0'); + $this->defaultLocale = \Locale::getDefault(); } protected function tearDown(): void { setlocale(\LC_ALL, $this->previousLocale); + \Locale::setDefault($this->defaultLocale); } public function testTransform() diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php index b09665084dd6..53ad49af5f86 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php @@ -1849,6 +1849,32 @@ public function testAdjustFullNameForMultipleNonExpanded() $this->assertSame('name[]', $view->vars['full_name']); } + public function testInvalidMessageAwarenessForMultiple() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'multiple' => true, + 'expanded' => false, + 'choices' => $this->choices, + 'invalid_message' => 'You are not able to use value "{{ value }}"', + ]); + + $form->submit(['My invalid choice']); + $this->assertEquals("ERROR: You are not able to use value \"My invalid choice\"\n", (string) $form->getErrors(true)); + } + + public function testInvalidMessageAwarenessForMultipleWithoutScalarOrArrayViewData() + { + $form = $this->factory->create(static::TESTED_TYPE, null, [ + 'multiple' => true, + 'expanded' => false, + 'choices' => $this->choices, + 'invalid_message' => 'You are not able to use value "{{ value }}"', + ]); + + $form->submit(new \stdClass()); + $this->assertEquals("ERROR: You are not able to use value \"stdClass\"\n", (string) $form->getErrors(true)); + } + // https://github.com/symfony/symfony/issues/3298 public function testInitializeWithEmptyChoices() { diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php index 654827d0e8a8..ab1e5611f33d 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTimeTypeTest.php @@ -18,13 +18,20 @@ class DateTimeTypeTest extends BaseTypeTest { public const TESTED_TYPE = 'Symfony\Component\Form\Extension\Core\Type\DateTimeType'; + private $defaultLocale; + protected function setUp(): void { + $this->defaultLocale = \Locale::getDefault(); \Locale::setDefault('en'); - parent::setUp(); } + protected function tearDown(): void + { + \Locale::setDefault($this->defaultLocale); + } + public function testSubmitDateTime() { $form = $this->factory->create(static::TESTED_TYPE, null, [ diff --git a/src/Symfony/Component/HttpClient/HttpClient.php b/src/Symfony/Component/HttpClient/HttpClient.php index 606d043298be..79cee02a2368 100644 --- a/src/Symfony/Component/HttpClient/HttpClient.php +++ b/src/Symfony/Component/HttpClient/HttpClient.php @@ -50,7 +50,7 @@ public static function create(array $defaultOptions = [], int $maxHostConnection } if (\extension_loaded('curl')) { - if ('\\' !== \DIRECTORY_SEPARATOR || ini_get('curl.cainfo') || ini_get('openssl.cafile') || ini_get('openssl.capath')) { + if ('\\' !== \DIRECTORY_SEPARATOR || isset($defaultOptions['cafile']) || isset($defaultOptions['capath']) || ini_get('curl.cainfo') || ini_get('openssl.cafile') || ini_get('openssl.capath')) { return new CurlHttpClient($defaultOptions, $maxHostConnections, $maxPendingPushes); } diff --git a/src/Symfony/Component/HttpClient/RetryableHttpClient.php b/src/Symfony/Component/HttpClient/RetryableHttpClient.php index 2472683d180c..afab2f8d0388 100644 --- a/src/Symfony/Component/HttpClient/RetryableHttpClient.php +++ b/src/Symfony/Component/HttpClient/RetryableHttpClient.php @@ -43,7 +43,7 @@ public function __construct(HttpClientInterface $client, RetryStrategyInterface $this->client = $client; $this->strategy = $strategy ?? new GenericRetryStrategy(); $this->maxRetries = $maxRetries; - $this->logger = $logger ?: new NullLogger(); + $this->logger = $logger ?? new NullLogger(); } public function request(string $method, string $url, array $options = []): ResponseInterface diff --git a/src/Symfony/Component/HttpFoundation/HeaderBag.php b/src/Symfony/Component/HttpFoundation/HeaderBag.php index db0f4836512a..f9c02f2105f2 100644 --- a/src/Symfony/Component/HttpFoundation/HeaderBag.php +++ b/src/Symfony/Component/HttpFoundation/HeaderBag.php @@ -230,7 +230,7 @@ public function hasCacheControlDirective(string $key) /** * Returns a Cache-Control directive value by name. * - * @return mixed|null The directive value if defined, null otherwise + * @return mixed The directive value if defined, null otherwise */ public function getCacheControlDirective(string $key) { diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 919f44fd47ca..f8c6ce0ed817 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -306,7 +306,7 @@ public static function createFromGlobals() if ($_POST) { $request->request = new InputBag($_POST); - } elseif (0 === strpos($request->headers->get('CONTENT_TYPE'), 'application/x-www-form-urlencoded') + } elseif (0 === strpos($request->headers->get('CONTENT_TYPE', ''), 'application/x-www-form-urlencoded') && \in_array(strtoupper($request->server->get('REQUEST_METHOD', 'GET')), ['PUT', 'DELETE', 'PATCH']) ) { parse_str($request->getContent(), $data); @@ -699,7 +699,7 @@ public static function getHttpMethodParameterOverride() * flexibility in controllers, it is better to explicitly get request parameters from the appropriate * public property instead (attributes, query, request). * - * Order of precedence: PATH (routing placeholders or custom attributes), GET, BODY + * Order of precedence: PATH (routing placeholders or custom attributes), GET, POST * * @param mixed $default The default value if the parameter key does not exist * @@ -1405,7 +1405,7 @@ public function setRequestFormat(?string $format) */ public function getContentType() { - return $this->getFormat($this->headers->get('CONTENT_TYPE')); + return $this->getFormat($this->headers->get('CONTENT_TYPE', '')); } /** @@ -1600,7 +1600,7 @@ public function toArray() */ public function getETags() { - return preg_split('/\s*,\s*/', $this->headers->get('if_none_match'), null, \PREG_SPLIT_NO_EMPTY); + return preg_split('/\s*,\s*/', $this->headers->get('if_none_match', ''), -1, \PREG_SPLIT_NO_EMPTY); } /** @@ -1849,13 +1849,13 @@ protected function prepareRequestUri() */ protected function prepareBaseUrl() { - $filename = basename($this->server->get('SCRIPT_FILENAME')); + $filename = basename($this->server->get('SCRIPT_FILENAME', '')); - if (basename($this->server->get('SCRIPT_NAME')) === $filename) { + if (basename($this->server->get('SCRIPT_NAME', '')) === $filename) { $baseUrl = $this->server->get('SCRIPT_NAME'); - } elseif (basename($this->server->get('PHP_SELF')) === $filename) { + } elseif (basename($this->server->get('PHP_SELF', '')) === $filename) { $baseUrl = $this->server->get('PHP_SELF'); - } elseif (basename($this->server->get('ORIG_SCRIPT_NAME')) === $filename) { + } elseif (basename($this->server->get('ORIG_SCRIPT_NAME', '')) === $filename) { $baseUrl = $this->server->get('ORIG_SCRIPT_NAME'); // 1and1 shared hosting compatibility } else { // Backtrack up the script_filename to find the portion matching @@ -1895,7 +1895,7 @@ protected function prepareBaseUrl() $truncatedRequestUri = substr($requestUri, 0, $pos); } - $basename = basename($baseUrl); + $basename = basename($baseUrl ?? ''); if (empty($basename) || !strpos(rawurldecode($truncatedRequestUri), $basename)) { // no match whatsoever; set it blank return ''; @@ -2046,7 +2046,7 @@ private static function createRequestFromFactory(array $query = [], array $reque */ public function isFromTrustedProxy() { - return self::$trustedProxies && IpUtils::checkIp($this->server->get('REMOTE_ADDR'), self::$trustedProxies); + return self::$trustedProxies && IpUtils::checkIp($this->server->get('REMOTE_ADDR', ''), self::$trustedProxies); } private function getTrustedValues(int $type, string $ip = null): array diff --git a/src/Symfony/Component/HttpFoundation/RequestMatcher.php b/src/Symfony/Component/HttpFoundation/RequestMatcher.php index ab778ea585e7..f02db30b1d95 100644 --- a/src/Symfony/Component/HttpFoundation/RequestMatcher.php +++ b/src/Symfony/Component/HttpFoundation/RequestMatcher.php @@ -164,7 +164,11 @@ public function matches(Request $request) } foreach ($this->attributes as $key => $pattern) { - if (!preg_match('{'.$pattern.'}', $request->attributes->get($key))) { + $requestAttribute = $request->attributes->get($key); + if (!\is_string($requestAttribute)) { + return false; + } + if (!preg_match('{'.$pattern.'}', $requestAttribute)) { return false; } } diff --git a/src/Symfony/Component/HttpFoundation/Session/Session.php b/src/Symfony/Component/HttpFoundation/Session/Session.php index 4a8af4d50e70..e4e25356376e 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Session.php +++ b/src/Symfony/Component/HttpFoundation/Session/Session.php @@ -39,14 +39,14 @@ class Session implements SessionInterface, \IteratorAggregate, \Countable public function __construct(SessionStorageInterface $storage = null, AttributeBagInterface $attributes = null, FlashBagInterface $flashes = null, callable $usageReporter = null) { - $this->storage = $storage ?: new NativeSessionStorage(); + $this->storage = $storage ?? new NativeSessionStorage(); $this->usageReporter = $usageReporter; - $attributes = $attributes ?: new AttributeBag(); + $attributes = $attributes ?? new AttributeBag(); $this->attributeName = $attributes->getName(); $this->registerBag($attributes); - $flashes = $flashes ?: new FlashBag(); + $flashes = $flashes ?? new FlashBag(); $this->flashName = $flashes->getName(); $this->registerBag($flashes); } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php index b4c2e139b369..b3877afbf321 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php @@ -113,9 +113,8 @@ public function save() $this->data = $data; } - // this is needed for Silex, where the session object is re-used across requests - // in functional tests. In Symfony, the container is rebooted, so we don't have - // this issue + // this is needed when the session object is re-used across multiple requests + // in functional tests. $this->started = false; } diff --git a/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/cookie_raw_urlencode.php b/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/cookie_raw_urlencode.php index 00c022d95394..4b96ddab362f 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/cookie_raw_urlencode.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/cookie_raw_urlencode.php @@ -9,4 +9,4 @@ $r->headers->setCookie(new Cookie($str, $str, 0, '/', null, false, false, true, null)); $r->sendHeaders(); -setrawcookie($str, $str, 0, '/', null, false, false); +setrawcookie($str, $str, 0, '/', '', false, false); diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestMatcherTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestMatcherTest.php index 6fab4e712cf3..18e269693e1a 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestMatcherTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestMatcherTest.php @@ -164,6 +164,19 @@ public function testAttributes() $this->assertFalse($matcher->matches($request)); } + public function testAttributesWithClosure() + { + $matcher = new RequestMatcher(); + + $request = Request::create('/admin/foo'); + $request->attributes->set('_controller', function () { + return new Response('foo'); + }); + + $matcher->matchAttribute('_controller', 'babar'); + $this->assertFalse($matcher->matches($request)); + } + public function testIps() { $matcher = new RequestMatcher(); diff --git a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php index 4285ba76319b..05775abfb0cf 100644 --- a/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php +++ b/src/Symfony/Component/HttpKernel/Controller/ArgumentResolver.php @@ -36,7 +36,7 @@ final class ArgumentResolver implements ArgumentResolverInterface public function __construct(ArgumentMetadataFactoryInterface $argumentMetadataFactory = null, iterable $argumentValueResolvers = []) { - $this->argumentMetadataFactory = $argumentMetadataFactory ?: new ArgumentMetadataFactory(); + $this->argumentMetadataFactory = $argumentMetadataFactory ?? new ArgumentMetadataFactory(); $this->argumentValueResolvers = $argumentValueResolvers ?: self::getDefaultArgumentValueResolvers(); } diff --git a/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php b/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php index 4244f460145f..59c399f312e9 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php @@ -56,14 +56,13 @@ public function onKernelRequest(RequestEvent $event) return; } - $session = null; $request = $event->getRequest(); if (!$request->hasSession()) { $sess = null; $request->setSessionFactory(function () use (&$sess) { return $sess ?? $sess = $this->getSession(); }); } - $session = $session ?? ($this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : null); + $session = $this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : null; $this->sessionUsageStack[] = $session instanceof Session ? $session->getUsageIndex() : 0; } diff --git a/src/Symfony/Component/HttpKernel/HttpKernel.php b/src/Symfony/Component/HttpKernel/HttpKernel.php index 850331349bb8..f61c4e43d942 100644 --- a/src/Symfony/Component/HttpKernel/HttpKernel.php +++ b/src/Symfony/Component/HttpKernel/HttpKernel.php @@ -60,7 +60,7 @@ public function __construct(EventDispatcherInterface $dispatcher, ControllerReso { $this->dispatcher = $dispatcher; $this->resolver = $resolver; - $this->requestStack = $requestStack ?: new RequestStack(); + $this->requestStack = $requestStack ?? new RequestStack(); $this->argumentResolver = $argumentResolver; if (null === $this->argumentResolver) { diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 7549ae9b21ac..112f9f2bd8fd 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -74,11 +74,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private static $freshCache = []; - public const VERSION = '5.2.6'; - public const VERSION_ID = 50206; + public const VERSION = '5.2.7'; + public const VERSION_ID = 50207; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 2; - public const RELEASE_VERSION = 6; + public const RELEASE_VERSION = 7; public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '07/2021'; diff --git a/src/Symfony/Component/HttpKernel/README.md b/src/Symfony/Component/HttpKernel/README.md index abdaf513f9cd..0136784a72d8 100644 --- a/src/Symfony/Component/HttpKernel/README.md +++ b/src/Symfony/Component/HttpKernel/README.md @@ -3,8 +3,7 @@ HttpKernel Component The HttpKernel component provides a structured process for converting a Request into a Response by making use of the EventDispatcher component. It's flexible -enough to create a full-stack framework (Symfony), a micro-framework (Silex) or -an advanced CMS system (Drupal). +enough to create full-stack frameworks, micro-frameworks or advanced CMS systems like Drupal. Resources --------- diff --git a/src/Symfony/Component/HttpKernel/Resources/welcome.html.php b/src/Symfony/Component/HttpKernel/Resources/welcome.html.php index b8337dc737e4..b25f99b3d059 100644 --- a/src/Symfony/Component/HttpKernel/Resources/welcome.html.php +++ b/src/Symfony/Component/HttpKernel/Resources/welcome.html.php @@ -19,8 +19,9 @@ .wrapper { text-align: center; width: 100%; } .container { position: relative; background: radial-gradient(ellipse at bottom, 0%, hsl(, 20%, 13%) 100%); background-attachment: fixed; color: ; } .container:after { content: ""; position: absolute; height: 2px; width: 2px; top: -2px; left: 0; background: white; box-shadow: 778px 1019px 0 0 rgba(255, 255, 255, 0.826) , 1075px 1688px 0 0 rgba(255,255,255, 0.275) , 388px 1021px 0 0 rgba(255,255,255, 0.259) , 1238px 626px 0 0 rgba(255,255,255, 0.469) , 997px 904px 0 0 rgba(255,255,255, 0.925) , 921px 1345px 0 0 rgba(255,255,255, 0.698) , 337px 1236px 0 0 rgba(255,255,255, 0.838) , 460px 569px 0 0 rgba(255,255,255, 0.01) , 690px 1488px 0 0 rgba(255,255,255, 0.154) , 859px 926px 0 0 rgba(255,255,255, 0.515) , 1272px 791px 0 0 rgba(255,255,255, 1) , 238px 1256px 0 0 rgba(255,255,255, 0.633) , 1486px 897px 0 0 rgba(255,255,255, 0.88) , 667px 6px 0 0 rgba(255,255,255, 0.508) , 853px 504px 0 0 rgba(255,255,255, 0.248) , 1329px 1778px 0 0 rgba(255,255,255, 0.217) , 768px 1340px 0 0 rgba(255,255,255, 0.792) , 631px 1383px 0 0 rgba(255,255,255, 0.698) , 991px 1603px 0 0 rgba(255,255,255, 0.939) , 1778px 1767px 0 0 rgba(255,255,255, 0.784) , 285px 546px 0 0 rgba(255,255,255, 0.8) , 1224px 1333px 0 0 rgba(255,255,255, 0.676) , 1154px 397px 0 0 rgba(255,255,255, 0.974) , 1210px 1004px 0 0 rgba(255,255,255, 0.894) , 1632px 953px 0 0 rgba(255,255,255, 0.281) , 449px 1144px 0 0 rgba(255,255,255, 0.706) , 1426px 771px 0 0 rgba(255,255,255, 0.737) , 1438px 1634px 0 0 rgba(255,255,255, 0.984) , 806px 168px 0 0 rgba(255,255,255, 0.807) , 731px 1067px 0 0 rgba(255,255,255, 0.734) , 1731px 1785px 0 0 rgba(255,255,255, 0.528) , 23px 975px 0 0 rgba(255,255,255, 0.068) , 575px 1088px 0 0 rgba(255,255,255, 0.876) , 1205px 1668px 0 0 rgba(255,255,255, 0.601) , 18px 1457px 0 0 rgba(255,255,255, 0.176) , 252px 1163px 0 0 rgba(255,255,255, 0.416) , 1752px 1px 0 0 rgba(255,255,255, 0.374) , 382px 767px 0 0 rgba(255,255,255, 0.073) , 133px 1462px 0 0 rgba(255,255,255, 0.706) , 851px 1166px 0 0 rgba(255,255,255, 0.535) , 374px 921px 0 0 rgba(255,255,255, 0.548) , 554px 1598px 0 0 rgba(255,255,255, 0.062) , 314px 685px 0 0 rgba(255,255,255, 0.187) , 1443px 209px 0 0 rgba(255,255,255, 0.097) , 1774px 1625px 0 0 rgba(255,255,255, 0.32) , 58px 278px 0 0 rgba(255,255,255, 0.684) , 986px 338px 0 0 rgba(255,255,255, 0.272) , 718px 1357px 0 0 rgba(255,255,255, 0.317) , 722px 983px 0 0 rgba(255,255,255, 0.568) , 1124px 992px 0 0 rgba(255,255,255, 0.199) , 581px 619px 0 0 rgba(255,255,255, 0.44) , 1120px 285px 0 0 rgba(255,255,255, 0.425) , 702px 138px 0 0 rgba(255,255,255, 0.816) , 262px 767px 0 0 rgba(255,255,255, 0.92) , 1204px 38px 0 0 rgba(255,255,255, 0.197) , 1196px 410px 0 0 rgba(255,255,255, 0.453) , 707px 699px 0 0 rgba(255,255,255, 0.481) , 1590px 1488px 0 0 rgba(255,255,255, 0.559) , 879px 1763px 0 0 rgba(255,255,255, 0.241) , 106px 686px 0 0 rgba(255,255,255, 0.175) , 158px 569px 0 0 rgba(255,255,255, 0.549) , 711px 1219px 0 0 rgba(255,255,255, 0.476) , 1339px 53px 0 0 rgba(255,255,255, 0.275) , 1410px 172px 0 0 rgba(255,255,255, 0.449) , 1601px 1484px 0 0 rgba(255,255,255, 0.988) , 1328px 1752px 0 0 rgba(255,255,255, 0.827) , 1733px 1475px 0 0 rgba(255,255,255, 0.567) , 559px 742px 0 0 rgba(255,255,255, 0.423) , 772px 844px 0 0 rgba(255,255,255, 0.039) , 602px 520px 0 0 rgba(255,255,255, 0.284) , 1158px 1067px 0 0 rgba(255,255,255, 0.066) , 1562px 730px 0 0 rgba(255,255,255, 0.086) , 1792px 615px 0 0 rgba(255,255,255, 0.438) , 1085px 1191px 0 0 rgba(255,255,255, 0.157) , 1402px 1087px 0 0 rgba(255,255,255, 0.797) , 569px 1685px 0 0 rgba(255,255,255, 0.992) , 1608px 52px 0 0 rgba(255,255,255, 0.302) , 1697px 1246px 0 0 rgba(255,255,255, 0.295) , 899px 1490px 0 0 rgba(255,255,255, 0.73) , 993px 901px 0 0 rgba(255,255,255, 0.961) , 1193px 1023px 0 0 rgba(255,255,255, 0.671) , 1224px 176px 0 0 rgba(255,255,255, 0.786) , 721px 1308px 0 0 rgba(255,255,255, 0.691) , 1702px 730px 0 0 rgba(255,255,255, 0.841) , 1480px 1498px 0 0 rgba(255,255,255, 0.655) , 181px 1612px 0 0 rgba(255,255,255, 0.588) , 1776px 679px 0 0 rgba(255,255,255, 0.821) , 892px 706px 0 0 rgba(255,255,255, 0.056) , 859px 267px 0 0 rgba(255,255,255, 0.565) , 784px 1285px 0 0 rgba(255,255,255, 0.029) , 1561px 1198px 0 0 rgba(255,255,255, 0.315) , 205px 421px 0 0 rgba(255,255,255, 0.584) , 236px 406px 0 0 rgba(255,255,255, 0.166) , 1259px 689px 0 0 rgba(255,255,255, 0.321) , 448px 317px 0 0 rgba(255,255,255, 0.495) , 1318px 466px 0 0 rgba(255,255,255, 0.275) , 1053px 297px 0 0 rgba(255,255,255, 0.035) , 716px 538px 0 0 rgba(255,255,255, 0.764) , 381px 207px 0 0 rgba(255,255,255, 0.692) , 871px 1140px 0 0 rgba(255,255,255, 0.342) , 361px 53px 0 0 rgba(255,255,255, 0.984) , 1565px 1593px 0 0 rgba(255,255,255, 0.102) , 145px 277px 0 0 rgba(255,255,255, 0.866) , 220px 1503px 0 0 rgba(255,255,255, 0.936) , 1068px 1475px 0 0 rgba(255,255,255, 0.156) , 1548px 483px 0 0 rgba(255,255,255, 0.768) , 710px 103px 0 0 rgba(255,255,255, 0.809) , 1660px 921px 0 0 rgba(255,255,255, 0.952) , 462px 1252px 0 0 rgba(255,255,255, 0.825) , 1123px 1628px 0 0 rgba(255,255,255, 0.409) , 1274px 729px 0 0 rgba(255,255,255, 0.26) , 1739px 679px 0 0 rgba(255,255,255, 0.83) , 1550px 1518px 0 0 rgba(255,255,255, 0.25) , 1624px 346px 0 0 rgba(255,255,255, 0.557) , 1023px 579px 0 0 rgba(255,255,255, 0.854) , 217px 661px 0 0 rgba(255,255,255, 0.731) , 1504px 549px 0 0 rgba(255,255,255, 0.705) , 939px 5px 0 0 rgba(255,255,255, 0.389) , 284px 735px 0 0 rgba(255,255,255, 0.355) , 13px 1679px 0 0 rgba(255,255,255, 0.712) , 137px 1592px 0 0 rgba(255,255,255, 0.619) , 1113px 505px 0 0 rgba(255,255,255, 0.651) , 1584px 510px 0 0 rgba(255,255,255, 0.41) , 346px 913px 0 0 rgba(255,255,255, 0.09) , 198px 1490px 0 0 rgba(255,255,255, 0.103) , 447px 1128px 0 0 rgba(255,255,255, 0.314) , 1356px 324px 0 0 rgba(255,255,255, 0.324) , 648px 667px 0 0 rgba(255,255,255, 0.155) , 442px 260px 0 0 rgba(255,255,255, 0.22) , 210px 401px 0 0 rgba(255,255,255, 0.682) , 422px 1772px 0 0 rgba(255,255,255, 0.671) , 276px 349px 0 0 rgba(255,255,255, 0.683) , 131px 539px 0 0 rgba(255,255,255, 0.977) , 892px 94px 0 0 rgba(255,255,255, 0.081) , 1295px 222px 0 0 rgba(255,255,255, 0.961) , 5px 1727px 0 0 rgba(255,255,255, 0.311) , 714px 1148px 0 0 rgba(255,255,255, 0.846) , 1455px 1182px 0 0 rgba(255,255,255, 0.313) , 1370px 708px 0 0 rgba(255,255,255, 0.824) , 812px 433px 0 0 rgba(255,255,255, 0.75) , 1110px 558px 0 0 rgba(255,255,255, 0.709) , 1132px 1543px 0 0 rgba(255,255,255, 0.868) , 644px 610px 0 0 rgba(255,255,255, 0.166) , 269px 1481px 0 0 rgba(255,255,255, 0.889) , 1712px 590px 0 0 rgba(255,255,255, 0.139) , 1159px 599px 0 0 rgba(255,255,255, 0.992) , 1551px 209px 0 0 rgba(255,255,255, 0.033) , 1020px 1721px 0 0 rgba(255,255,255, 0.028) , 216px 373px 0 0 rgba(255,255,255, 0.665) , 877px 532px 0 0 rgba(255,255,255, 0.686) , 1326px 885px 0 0 rgba(255,255,255, 0.517) , 972px 1704px 0 0 rgba(255,255,255, 0.499) , 749px 181px 0 0 rgba(255,255,255, 0.712) , 1511px 1650px 0 0 rgba(255,255,255, 0.101) , 1432px 183px 0 0 rgba(255,255,255, 0.545) , 1541px 1338px 0 0 rgba(255,255,255, 0.71) , 513px 1406px 0 0 rgba(255,255,255, 0.17) , 1314px 1197px 0 0 rgba(255,255,255, 0.789) , 824px 1659px 0 0 rgba(255,255,255, 0.597) , 308px 298px 0 0 rgba(255,255,255, 0.917) , 1225px 659px 0 0 rgba(255,255,255, 0.229) , 1253px 257px 0 0 rgba(255,255,255, 0.631) , 1653px 185px 0 0 rgba(255,255,255, 0.113) , 336px 614px 0 0 rgba(255,255,255, 0.045) , 1093px 898px 0 0 rgba(255,255,255, 0.617) , 730px 5px 0 0 rgba(255,255,255, 0.11) , 785px 645px 0 0 rgba(255,255,255, 0.516) , 989px 678px 0 0 rgba(255,255,255, 0.917) , 1511px 1614px 0 0 rgba(255,255,255, 0.938) , 584px 1117px 0 0 rgba(255,255,255, 0.631) , 534px 1012px 0 0 rgba(255,255,255, 0.668) , 1325px 1778px 0 0 rgba(255,255,255, 0.293) , 1632px 754px 0 0 rgba(255,255,255, 0.26) , 78px 1258px 0 0 rgba(255,255,255, 0.52) , 779px 1691px 0 0 rgba(255,255,255, 0.878) , 253px 1706px 0 0 rgba(255,255,255, 0.75) , 1358px 245px 0 0 rgba(255,255,255, 0.027) , 361px 1629px 0 0 rgba(255,255,255, 0.238) , 1134px 232px 0 0 rgba(255,255,255, 0.387) , 1685px 777px 0 0 rgba(255,255,255, 0.156) , 515px 724px 0 0 rgba(255,255,255, 0.863) , 588px 1728px 0 0 rgba(255,255,255, 0.159) , 1132px 47px 0 0 rgba(255,255,255, 0.691) , 315px 1446px 0 0 rgba(255,255,255, 0.782) , 79px 233px 0 0 rgba(255,255,255, 0.317) , 1498px 1050px 0 0 rgba(255,255,255, 0.358) , 30px 1073px 0 0 rgba(255,255,255, 0.939) , 1637px 620px 0 0 rgba(255,255,255, 0.141) , 1736px 1683px 0 0 rgba(255,255,255, 0.682) , 1298px 1505px 0 0 rgba(255,255,255, 0.863) , 972px 85px 0 0 rgba(255,255,255, 0.941) , 349px 1356px 0 0 rgba(255,255,255, 0.672) , 1545px 1429px 0 0 rgba(255,255,255, 0.859) , 1076px 467px 0 0 rgba(255,255,255, 0.024) , 189px 1647px 0 0 rgba(255,255,255, 0.838) , 423px 1722px 0 0 rgba(255,255,255, 0.771) , 1691px 1719px 0 0 rgba(255,255,255, 0.676) , 1747px 658px 0 0 rgba(255,255,255, 0.255) , 149px 1492px 0 0 rgba(255,255,255, 0.911) , 1203px 1138px 0 0 rgba(255,255,255, 0.964) , 781px 1584px 0 0 rgba(255,255,255, 0.465) , 1609px 1595px 0 0 rgba(255,255,255, 0.688) , 447px 1655px 0 0 rgba(255,255,255, 0.166) , 914px 1153px 0 0 rgba(255,255,255, 0.085) , 600px 1058px 0 0 rgba(255,255,255, 0.821) , 804px 505px 0 0 rgba(255,255,255, 0.608) , 1506px 584px 0 0 rgba(255,255,255, 0.618) , 587px 1290px 0 0 rgba(255,255,255, 0.071) , 258px 600px 0 0 rgba(255,255,255, 0.243) , 328px 395px 0 0 rgba(255,255,255, 0.065) , 846px 783px 0 0 rgba(255,255,255, 0.995) , 1138px 1294px 0 0 rgba(255,255,255, 0.703) , 1668px 633px 0 0 rgba(255,255,255, 0.27) , 337px 103px 0 0 rgba(255,255,255, 0.202) , 132px 986px 0 0 rgba(255,255,255, 0.726) , 414px 757px 0 0 rgba(255,255,255, 0.752) , 8px 1311px 0 0 rgba(255,255,255, 0.307) , 1791px 910px 0 0 rgba(255,255,255, 0.346) , 844px 216px 0 0 rgba(255,255,255, 0.156) , 1547px 1723px 0 0 rgba(255,255,255, 0.73) , 1187px 398px 0 0 rgba(255,255,255, 0.698) , 1550px 1520px 0 0 rgba(255,255,255, 0.462) , 1346px 655px 0 0 rgba(255,255,255, 0.58) , 668px 770px 0 0 rgba(255,255,255, 0.422) , 1774px 1435px 0 0 rgba(255,255,255, 0.089) , 693px 1061px 0 0 rgba(255,255,255, 0.893) , 132px 1689px 0 0 rgba(255,255,255, 0.937) , 894px 1561px 0 0 rgba(255,255,255, 0.88) , 906px 1706px 0 0 rgba(255,255,255, 0.567) , 1140px 297px 0 0 rgba(255,255,255, 0.358) , 13px 1288px 0 0 rgba(255,255,255, 0.464) , 1744px 423px 0 0 rgba(255,255,255, 0.845) , 119px 1548px 0 0 rgba(255,255,255, 0.769) , 1249px 1321px 0 0 rgba(255,255,255, 0.29) , 123px 795px 0 0 rgba(255,255,255, 0.597) , 390px 1542px 0 0 rgba(255,255,255, 0.47) , 825px 667px 0 0 rgba(255,255,255, 0.049) , 1071px 875px 0 0 rgba(255,255,255, 0.06) , 1428px 1786px 0 0 rgba(255,255,255, 0.222) , 993px 696px 0 0 rgba(255,255,255, 0.399) , 1585px 247px 0 0 rgba(255,255,255, 0.094) , 1340px 1312px 0 0 rgba(255,255,255, 0.603) , 1640px 725px 0 0 rgba(255,255,255, 0.026) , 1161px 1397px 0 0 rgba(255,255,255, 0.222) , 966px 1132px 0 0 rgba(255,255,255, 0.69) , 1782px 1275px 0 0 rgba(255,255,255, 0.606) , 1117px 1533px 0 0 rgba(255,255,255, 0.248) , 1027px 959px 0 0 rgba(255,255,255, 0.46) , 459px 839px 0 0 rgba(255,255,255, 0.98) , 1192px 265px 0 0 rgba(255,255,255, 0.523) , 175px 501px 0 0 rgba(255,255,255, 0.371) , 626px 19px 0 0 rgba(255,255,255, 0.246) , 46px 1173px 0 0 rgba(255,255,255, 0.124) , 573px 925px 0 0 rgba(255,255,255, 0.621) , 1px 283px 0 0 rgba(255,255,255, 0.943) , 778px 1213px 0 0 rgba(255,255,255, 0.128) , 435px 593px 0 0 rgba(255,255,255, 0.378) , 32px 394px 0 0 rgba(255,255,255, 0.451) , 1019px 1055px 0 0 rgba(255,255,255, 0.685) , 1423px 1233px 0 0 rgba(255,255,255, 0.354) , 494px 841px 0 0 rgba(255,255,255, 0.322) , 667px 194px 0 0 rgba(255,255,255, 0.655) , 1671px 195px 0 0 rgba(255,255,255, 0.502) , 403px 1710px 0 0 rgba(255,255,255, 0.623) , 665px 1597px 0 0 rgba(255,255,255, 0.839) , 61px 1742px 0 0 rgba(255,255,255, 0.566) , 1490px 1654px 0 0 rgba(255,255,255, 0.646) , 1361px 1604px 0 0 rgba(255,255,255, 0.101) , 1191px 1023px 0 0 rgba(255,255,255, 0.881) , 550px 378px 0 0 rgba(255,255,255, 0.573) , 1332px 1234px 0 0 rgba(255,255,255, 0.922) , 760px 1205px 0 0 rgba(255,255,255, 0.992) , 1506px 1328px 0 0 rgba(255,255,255, 0.723) , 1126px 813px 0 0 rgba(255,255,255, 0.549) , 67px 240px 0 0 rgba(255,255,255, 0.901) , 125px 1301px 0 0 rgba(255,255,255, 0.464) , 643px 391px 0 0 rgba(255,255,255, 0.589) , 1114px 1756px 0 0 rgba(255,255,255, 0.321) , 1602px 699px 0 0 rgba(255,255,255, 0.274) , 510px 393px 0 0 rgba(255,255,255, 0.185) , 171px 1217px 0 0 rgba(255,255,255, 0.932) , 1202px 1362px 0 0 rgba(255,255,255, 0.726) , 1160px 1324px 0 0 rgba(255,255,255, 0.867) , 121px 319px 0 0 rgba(255,255,255, 0.992) , 1474px 835px 0 0 rgba(255,255,255, 0.89) , 357px 1213px 0 0 rgba(255,255,255, 0.91) , 783px 976px 0 0 rgba(255,255,255, 0.941) , 750px 1599px 0 0 rgba(255,255,255, 0.515) , 323px 450px 0 0 rgba(255,255,255, 0.966) , 1078px 282px 0 0 rgba(255,255,255, 0.947) , 1164px 46px 0 0 rgba(255,255,255, 0.296) , 1792px 705px 0 0 rgba(255,255,255, 0.485) , 880px 1287px 0 0 rgba(255,255,255, 0.894) , 60px 1402px 0 0 rgba(255,255,255, 0.816) , 752px 894px 0 0 rgba(255,255,255, 0.803) , 285px 1535px 0 0 rgba(255,255,255, 0.93) , 1528px 401px 0 0 rgba(255,255,255, 0.727) , 651px 1767px 0 0 rgba(255,255,255, 0.146) , 1498px 1190px 0 0 rgba(255,255,255, 0.042) , 394px 1786px 0 0 rgba(255,255,255, 0.159) , 1318px 9px 0 0 rgba(255,255,255, 0.575) , 1699px 1675px 0 0 rgba(255,255,255, 0.511) , 82px 986px 0 0 rgba(255,255,255, 0.906) , 940px 970px 0 0 rgba(255,255,255, 0.562) , 1624px 259px 0 0 rgba(255,255,255, 0.537) , 1782px 222px 0 0 rgba(255,255,255, 0.259) , 1572px 1725px 0 0 rgba(255,255,255, 0.716) , 1080px 1557px 0 0 rgba(255,255,255, 0.245) , 1727px 648px 0 0 rgba(255,255,255, 0.471) , 899px 231px 0 0 rgba(255,255,255, 0.445) , 1061px 1074px 0 0 rgba(255,255,255, 0.079) , 556px 478px 0 0 rgba(255,255,255, 0.524) , 343px 359px 0 0 rgba(255,255,255, 0.162) , 711px 1254px 0 0 rgba(255,255,255, 0.323) , 1335px 242px 0 0 rgba(255,255,255, 0.936) , 933px 39px 0 0 rgba(255,255,255, 0.784) , 1629px 908px 0 0 rgba(255,255,255, 0.289) , 1800px 229px 0 0 rgba(255,255,255, 0.399) , 1589px 926px 0 0 rgba(255,255,255, 0.709) , 976px 694px 0 0 rgba(255,255,255, 0.855) , 1163px 1240px 0 0 rgba(255,255,255, 0.754) , 1662px 1784px 0 0 rgba(255,255,255, 0.088) , 656px 1388px 0 0 rgba(255,255,255, 0.688) , 1190px 1100px 0 0 rgba(255,255,255, 0.769) , 33px 392px 0 0 rgba(255,255,255, 0.301) , 56px 1405px 0 0 rgba(255,255,255, 0.969) , 1491px 118px 0 0 rgba(255,255,255, 0.991) , 1216px 997px 0 0 rgba(255,255,255, 0.727) , 1617px 712px 0 0 rgba(255,255,255, 0.45) , 163px 553px 0 0 rgba(255,255,255, 0.977) , 103px 140px 0 0 rgba(255,255,255, 0.916) , 1099px 1404px 0 0 rgba(255,255,255, 0.167) , 1423px 587px 0 0 rgba(255,255,255, 0.792) , 1797px 309px 0 0 rgba(255,255,255, 0.526) , 381px 141px 0 0 rgba(255,255,255, 0.005) , 1214px 802px 0 0 rgba(255,255,255, 0.887) , 211px 829px 0 0 rgba(255,255,255, 0.72) , 1103px 1507px 0 0 rgba(255,255,255, 0.642) , 244px 1231px 0 0 rgba(255,255,255, 0.184) , 118px 1747px 0 0 rgba(255,255,255, 0.475) , 183px 1293px 0 0 rgba(255,255,255, 0.148) , 911px 1362px 0 0 rgba(255,255,255, 0.073) , 817px 457px 0 0 rgba(255,255,255, 0.459) , 756px 18px 0 0 rgba(255,255,255, 0.544) , 481px 1118px 0 0 rgba(255,255,255, 0.878) , 380px 138px 0 0 rgba(255,255,255, 0.132) , 320px 646px 0 0 rgba(255,255,255, 0.04) , 1724px 1716px 0 0 rgba(255,255,255, 0.381) , 978px 1269px 0 0 rgba(255,255,255, 0.431) , 1530px 255px 0 0 rgba(255,255,255, 0.31) , 664px 204px 0 0 rgba(255,255,255, 0.913) , 474px 703px 0 0 rgba(255,255,255, 0.832) , 1722px 1204px 0 0 rgba(255,255,255, 0.356) , 1453px 821px 0 0 rgba(255,255,255, 0.195) , 730px 1468px 0 0 rgba(255,255,255, 0.696) , 928px 1610px 0 0 rgba(255,255,255, 0.894) , 1036px 304px 0 0 rgba(255,255,255, 0.696) , 1590px 172px 0 0 rgba(255,255,255, 0.729) , 249px 1590px 0 0 rgba(255,255,255, 0.277) , 357px 81px 0 0 rgba(255,255,255, 0.526) , 726px 1261px 0 0 rgba(255,255,255, 0.149) , 643px 946px 0 0 rgba(255,255,255, 0.005) , 1263px 995px 0 0 rgba(255,255,255, 0.124) , 1564px 1107px 0 0 rgba(255,255,255, 0.789) , 388px 83px 0 0 rgba(255,255,255, 0.498) , 715px 681px 0 0 rgba(255,255,255, 0.655) , 1618px 1624px 0 0 rgba(255,255,255, 0.63) , 1423px 1576px 0 0 rgba(255,255,255, 0.52) , 564px 1786px 0 0 rgba(255,255,255, 0.482) , 1066px 735px 0 0 rgba(255,255,255, 0.276) , 714px 1179px 0 0 rgba(255,255,255, 0.395) , 967px 1006px 0 0 rgba(255,255,255, 0.923) , 1136px 1790px 0 0 rgba(255,255,255, 0.801) , 215px 1690px 0 0 rgba(255,255,255, 0.957) , 1500px 1338px 0 0 rgba(255,255,255, 0.541) , 1679px 1065px 0 0 rgba(255,255,255, 0.925) , 426px 1489px 0 0 rgba(255,255,255, 0.193) , 1273px 853px 0 0 rgba(255,255,255, 0.317) , 665px 1189px 0 0 rgba(255,255,255, 0.512) , 520px 552px 0 0 rgba(255,255,255, 0.925) , 253px 438px 0 0 rgba(255,255,255, 0.588) , 369px 1354px 0 0 rgba(255,255,255, 0.889) , 749px 205px 0 0 rgba(255,255,255, 0.243) , 820px 145px 0 0 rgba(255,255,255, 0.207) , 1739px 228px 0 0 rgba(255,255,255, 0.267) , 392px 495px 0 0 rgba(255,255,255, 0.504) , 721px 1044px 0 0 rgba(255,255,255, 0.823) , 833px 912px 0 0 rgba(255,255,255, 0.222) , 865px 1499px 0 0 rgba(255,255,255, 0.003) , 313px 756px 0 0 rgba(255,255,255, 0.727) , 439px 1187px 0 0 rgba(255,255,255, 0.572) , 6px 1238px 0 0 rgba(255,255,255, 0.676) , 1567px 11px 0 0 rgba(255,255,255, 0.701) , 1216px 757px 0 0 rgba(255,255,255, 0.87) , 916px 588px 0 0 rgba(255,255,255, 0.565) , 831px 215px 0 0 rgba(255,255,255, 0.597) , 1289px 697px 0 0 rgba(255,255,255, 0.964) , 307px 34px 0 0 rgba(255,255,255, 0.462) , 3px 1685px 0 0 rgba(255,255,255, 0.464) , 1115px 1421px 0 0 rgba(255,255,255, 0.303) , 1451px 473px 0 0 rgba(255,255,255, 0.142) , 1374px 1205px 0 0 rgba(255,255,255, 0.086) , 1564px 317px 0 0 rgba(255,255,255, 0.773) , 304px 1127px 0 0 rgba(255,255,255, 0.653) , 446px 214px 0 0 rgba(255,255,255, 0.135) , 1541px 459px 0 0 rgba(255,255,255, 0.725) , 1387px 880px 0 0 rgba(255,255,255, 0.157) , 1172px 224px 0 0 rgba(255,255,255, 0.088) , 1420px 637px 0 0 rgba(255,255,255, 0.916) , 1385px 932px 0 0 rgba(255,255,255, 0.225) , 174px 1472px 0 0 rgba(255,255,255, 0.649) , 252px 750px 0 0 rgba(255,255,255, 0.277) , 825px 1042px 0 0 rgba(255,255,255, 0.707) , 840px 703px 0 0 rgba(255,255,255, 0.948) , 1478px 1800px 0 0 rgba(255,255,255, 0.151) , 95px 1303px 0 0 rgba(255,255,255, 0.332) , 1198px 740px 0 0 rgba(255,255,255, 0.443) , 141px 312px 0 0 rgba(255,255,255, 0.04) , 291px 729px 0 0 rgba(255,255,255, 0.284) , 1209px 1506px 0 0 rgba(255,255,255, 0.741) , 1188px 307px 0 0 rgba(255,255,255, 0.141) , 958px 41px 0 0 rgba(255,255,255, 0.858) , 1311px 1484px 0 0 rgba(255,255,255, 0.097) , 846px 1153px 0 0 rgba(255,255,255, 0.862) , 1238px 1376px 0 0 rgba(255,255,255, 0.071) , 1499px 342px 0 0 rgba(255,255,255, 0.719) , 640px 833px 0 0 rgba(255,255,255, 0.966) , 712px 545px 0 0 rgba(255,255,255, 0.194) , 1655px 1542px 0 0 rgba(255,255,255, 0.82) , 616px 353px 0 0 rgba(255,255,255, 0.871) , 1591px 1631px 0 0 rgba(255,255,255, 0.61) , 1664px 591px 0 0 rgba(255,255,255, 0.35) , 934px 454px 0 0 rgba(255,255,255, 0.58) , 1175px 477px 0 0 rgba(255,255,255, 0.966) , 299px 914px 0 0 rgba(255,255,255, 0.839) , 534px 243px 0 0 rgba(255,255,255, 0.194) , 773px 1135px 0 0 rgba(255,255,255, 0.42) , 1696px 1472px 0 0 rgba(255,255,255, 0.552) , 125px 523px 0 0 rgba(255,255,255, 0.591) , 1195px 382px 0 0 rgba(255,255,255, 0.904) , 1609px 1374px 0 0 rgba(255,255,255, 0.579) , 843px 82px 0 0 rgba(255,255,255, 0.072) , 1604px 451px 0 0 rgba(255,255,255, 0.545) , 1322px 190px 0 0 rgba(255,255,255, 0.034) , 528px 228px 0 0 rgba(255,255,255, 0.146) , 1470px 1169px 0 0 rgba(255,255,255, 0.912) , 502px 1350px 0 0 rgba(255,255,255, 0.594) , 1031px 298px 0 0 rgba(255,255,255, 0.368) , 1100px 1427px 0 0 rgba(255,255,255, 0.79) , 979px 1105px 0 0 rgba(255,255,255, 0.973) , 643px 1184px 0 0 rgba(255,255,255, 0.813) , 1636px 1701px 0 0 rgba(255,255,255, 0.013) , 1004px 245px 0 0 rgba(255,255,255, 0.412) , 680px 740px 0 0 rgba(255,255,255, 0.967) , 1599px 562px 0 0 rgba(255,255,255, 0.66) , 256px 1617px 0 0 rgba(255,255,255, 0.463) , 314px 1092px 0 0 rgba(255,255,255, 0.734) , 870px 900px 0 0 rgba(255,255,255, 0.512) , 530px 60px 0 0 rgba(255,255,255, 0.198) , 1786px 896px 0 0 rgba(255,255,255, 0.392) , 636px 212px 0 0 rgba(255,255,255, 0.997) , 672px 540px 0 0 rgba(255,255,255, 0.632) , 1118px 1649px 0 0 rgba(255,255,255, 0.377) , 433px 647px 0 0 rgba(255,255,255, 0.902) , 1200px 1737px 0 0 rgba(255,255,255, 0.262) , 1258px 143px 0 0 rgba(255,255,255, 0.729) , 1603px 1364px 0 0 rgba(255,255,255, 0.192) , 66px 1756px 0 0 rgba(255,255,255, 0.681) , 946px 263px 0 0 rgba(255,255,255, 0.105) , 1216px 1082px 0 0 rgba(255,255,255, 0.287) , 6px 1143px 0 0 rgba(255,255,255, 0.017) , 1631px 126px 0 0 rgba(255,255,255, 0.449) , 357px 1565px 0 0 rgba(255,255,255, 0.163) , 1752px 261px 0 0 rgba(255,255,255, 0.423) , 1247px 1631px 0 0 rgba(255,255,255, 0.312) , 320px 671px 0 0 rgba(255,255,255, 0.695) , 1375px 596px 0 0 rgba(255,255,255, 0.856) , 1456px 1340px 0 0 rgba(255,255,255, 0.564) , 447px 1044px 0 0 rgba(255,255,255, 0.623) , 1732px 447px 0 0 rgba(255,255,255, 0.216) , 174px 1509px 0 0 rgba(255,255,255, 0.398) , 16px 861px 0 0 rgba(255,255,255, 0.904) , 878px 1296px 0 0 rgba(255,255,255, 0.205) , 1725px 1483px 0 0 rgba(255,255,255, 0.704) , 255px 48px 0 0 rgba(255,255,255, 0.7) , 610px 1669px 0 0 rgba(255,255,255, 0.865) , 1044px 1251px 0 0 rgba(255,255,255, 0.98) , 884px 862px 0 0 rgba(255,255,255, 0.198) , 986px 545px 0 0 rgba(255,255,255, 0.379) , 1620px 217px 0 0 rgba(255,255,255, 0.159) , 383px 1763px 0 0 rgba(255,255,255, 0.518) , 595px 974px 0 0 rgba(255,255,255, 0.347) , 359px 14px 0 0 rgba(255,255,255, 0.863) , 95px 1385px 0 0 rgba(255,255,255, 0.011) , 411px 1030px 0 0 rgba(255,255,255, 0.038) , 345px 789px 0 0 rgba(255,255,255, 0.771) , 421px 460px 0 0 rgba(255,255,255, 0.133) , 972px 1160px 0 0 rgba(255,255,255, 0.342) , 597px 1061px 0 0 rgba(255,255,255, 0.781) , 1017px 1092px 0 0 rgba(255,255,255, 0.437); } - .warning { background: ; display: flex; align-content: center; padding: 10px; text-align: left; justify-content: center; } - .warning svg { height: 48px; width: 48px; margin-right: 10px; } + .warning { background: ; display: flex; align-items: center; padding: 10px; text-align: left; justify-content: center; } + .warning svg { flex-shrink: 0; height: 32px; width: 32px; margin-right: 10px; } + .warning p { line-height: 1.4; margin: 0; } .container svg.wave { position: absolute; bottom: -2px; left: 0; z-index: 1; } .container .logo { margin-bottom: 1em; } .container .logo svg { fill: hsl(, 20%, 26%); } @@ -45,9 +46,6 @@ @keyframes fade-in { 0% { opacity: 0; } 100% { opacity: 1; } } .sf-toolbar { opacity: 0; -webkit-animation: fade-in 1s .2s forwards; animation: fade-in 1s .2s forwards; z-index: 99999; } - body { font-size: 20px; } - .warning { text-align: center; } - .warning svg { height: 32px; width: 32px; } .resources .row { margin-left: 50px; margin-right: 50px; } .resource { padding: 0 30px; } @@ -59,13 +57,19 @@ .resource h2 { font-size: 22px; } .resource a { font-size: 16px; margin-top: 0; } } + @media (min-width: 992px) { + body { font-size: 20px; } + .warning { text-align: center; } + }
- You're seeing this page because you haven't configured any homepage URL and debug mode is enabled. +

+ You're seeing this page because you haven't configured any homepage URL and debug mode is enabled. +

diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/TestSessionListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/TestSessionListenerTest.php index 2ec6581694c8..70629a8fb8d8 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/TestSessionListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/TestSessionListenerTest.php @@ -158,7 +158,7 @@ public function testDoesNotThrowIfRequestDoesNotHaveASession() private function filterResponse(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, Response $response = null) { $request->setSession($this->session); - $response = $response ?: new Response(); + $response = $response ?? new Response(); $kernel = $this->createMock(HttpKernelInterface::class); $event = new ResponseEvent($kernel, $request, $type, $response); diff --git a/src/Symfony/Component/Intl/Tests/ResourceBundleTestCase.php b/src/Symfony/Component/Intl/Tests/ResourceBundleTestCase.php index 5b0096aab642..2f13602f7e5c 100644 --- a/src/Symfony/Component/Intl/Tests/ResourceBundleTestCase.php +++ b/src/Symfony/Component/Intl/Tests/ResourceBundleTestCase.php @@ -725,13 +725,20 @@ abstract class ResourceBundleTestCase extends TestCase ]; private static $rootLocales; + private $defaultLocale; protected function setUp(): void { + $this->defaultLocale = \Locale::getDefault(); Locale::setDefault('en'); Locale::setDefaultFallback('en'); } + protected function tearDown(): void + { + \Locale::setDefault($this->defaultLocale); + } + public function provideLocales() { return array_map( diff --git a/src/Symfony/Component/Mailer/Bridge/Mailjet/.gitattributes b/src/Symfony/Component/Mailer/Bridge/Mailjet/.gitattributes new file mode 100644 index 000000000000..84c7add058fb --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailjet/.gitattributes @@ -0,0 +1,4 @@ +/Tests export-ignore +/phpunit.xml.dist export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore diff --git a/src/Symfony/Component/Mailer/Bridge/Mailjet/.gitignore b/src/Symfony/Component/Mailer/Bridge/Mailjet/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Mailer/Bridge/Mailjet/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Mailer/EventListener/EnvelopeListener.php b/src/Symfony/Component/Mailer/EventListener/EnvelopeListener.php index 570a9e39551f..b439b2f0bf41 100644 --- a/src/Symfony/Component/Mailer/EventListener/EnvelopeListener.php +++ b/src/Symfony/Component/Mailer/EventListener/EnvelopeListener.php @@ -27,8 +27,8 @@ class EnvelopeListener implements EventSubscriberInterface private $recipients; /** - * @param Address|string $sender - * @param (Address|string)[] $recipients + * @param Address|string $sender + * @param array $recipients */ public function __construct($sender = null, array $recipients = null) { diff --git a/src/Symfony/Component/Mailer/Tests/Transport/NativeTransportFactoryTest.php b/src/Symfony/Component/Mailer/Tests/Transport/NativeTransportFactoryTest.php index 630113dbdc22..35f48ea4ccda 100644 --- a/src/Symfony/Component/Mailer/Tests/Transport/NativeTransportFactoryTest.php +++ b/src/Symfony/Component/Mailer/Tests/Transport/NativeTransportFactoryTest.php @@ -111,7 +111,7 @@ public function testCreate(string $dsn, string $sendmailPath, string $smtp, stri { self::$fakeConfiguration = [ 'sendmail_path' => $sendmailPath, - 'smtp' => $smtp, + 'SMTP' => $smtp, 'smtp_port' => $smtpPort, ]; diff --git a/src/Symfony/Component/Mailer/Tests/Transport/Smtp/Stream/SocketStreamTest.php b/src/Symfony/Component/Mailer/Tests/Transport/Smtp/Stream/SocketStreamTest.php index e4ca6aa45eca..f06160d00955 100644 --- a/src/Symfony/Component/Mailer/Tests/Transport/Smtp/Stream/SocketStreamTest.php +++ b/src/Symfony/Component/Mailer/Tests/Transport/Smtp/Stream/SocketStreamTest.php @@ -20,7 +20,7 @@ class SocketStreamTest extends TestCase public function testSocketErrorNoConnection() { $this->expectException(TransportException::class); - $this->expectExceptionMessageMatches('/Connection refused|unable to connect/'); + $this->expectExceptionMessageMatches('/Connection refused|unable to connect/i'); $s = new SocketStream(); $s->setTimeout(0.1); $s->setPort(9999); diff --git a/src/Symfony/Component/Mailer/Transport/AbstractTransport.php b/src/Symfony/Component/Mailer/Transport/AbstractTransport.php index 0bee2bdb2bbe..73f23b27b373 100644 --- a/src/Symfony/Component/Mailer/Transport/AbstractTransport.php +++ b/src/Symfony/Component/Mailer/Transport/AbstractTransport.php @@ -35,7 +35,7 @@ abstract class AbstractTransport implements TransportInterface public function __construct(EventDispatcherInterface $dispatcher = null, LoggerInterface $logger = null) { $this->dispatcher = class_exists(Event::class) ? LegacyEventDispatcherProxy::decorate($dispatcher) : $dispatcher; - $this->logger = $logger ?: new NullLogger(); + $this->logger = $logger ?? new NullLogger(); } /** diff --git a/src/Symfony/Component/Mailer/Transport/NativeTransportFactory.php b/src/Symfony/Component/Mailer/Transport/NativeTransportFactory.php index 358200b09081..8afa53cc43ae 100644 --- a/src/Symfony/Component/Mailer/Transport/NativeTransportFactory.php +++ b/src/Symfony/Component/Mailer/Transport/NativeTransportFactory.php @@ -39,7 +39,7 @@ public function create(Dsn $dsn): TransportInterface // Only for windows hosts; at this point non-windows // host have already thrown an exception or returned a transport - $host = ini_get('smtp'); + $host = ini_get('SMTP'); $port = (int) ini_get('smtp_port'); if (!$host || !$port) { diff --git a/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php index 9456fd09bd4c..2e1448f39a89 100644 --- a/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php +++ b/src/Symfony/Component/Mailer/Transport/Smtp/SmtpTransport.php @@ -44,7 +44,7 @@ public function __construct(AbstractStream $stream = null, EventDispatcherInterf { parent::__construct($dispatcher, $logger); - $this->stream = $stream ?: new SocketStream(); + $this->stream = $stream ?? new SocketStream(); } public function getStream(): AbstractStream diff --git a/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Tests/Transport/AmazonSqsTransportTest.php b/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Tests/Transport/AmazonSqsTransportTest.php index 62f596f40fe8..e7f55226ccc0 100644 --- a/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Tests/Transport/AmazonSqsTransportTest.php +++ b/src/Symfony/Component/Messenger/Bridge/AmazonSqs/Tests/Transport/AmazonSqsTransportTest.php @@ -60,8 +60,8 @@ public function testTransportIsAMessageCountAware() private function getTransport(SerializerInterface $serializer = null, Connection $connection = null) { - $serializer = $serializer ?: $this->createMock(SerializerInterface::class); - $connection = $connection ?: $this->createMock(Connection::class); + $serializer = $serializer ?? $this->createMock(SerializerInterface::class); + $connection = $connection ?? $this->createMock(Connection::class); return new AmazonSqsTransport($connection, $serializer); } diff --git a/src/Symfony/Component/Messenger/Bridge/Amqp/Tests/Transport/AmqpTransportTest.php b/src/Symfony/Component/Messenger/Bridge/Amqp/Tests/Transport/AmqpTransportTest.php index a5fc89eb9013..0223a0396c01 100644 --- a/src/Symfony/Component/Messenger/Bridge/Amqp/Tests/Transport/AmqpTransportTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Amqp/Tests/Transport/AmqpTransportTest.php @@ -54,8 +54,8 @@ public function testReceivesMessages() private function getTransport(SerializerInterface $serializer = null, Connection $connection = null): AmqpTransport { - $serializer = $serializer ?: $this->createMock(SerializerInterface::class); - $connection = $connection ?: $this->createMock(Connection::class); + $serializer = $serializer ?? $this->createMock(SerializerInterface::class); + $connection = $connection ?? $this->createMock(Connection::class); return new AmqpTransport($connection, $serializer); } diff --git a/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php index 5c7e76291060..5b2138891507 100644 --- a/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/Amqp/Transport/Connection.php @@ -114,7 +114,7 @@ public function __construct(array $connectionOptions, array $exchangeOptions, ar ], $connectionOptions); $this->exchangeOptions = $exchangeOptions; $this->queuesOptions = $queuesOptions; - $this->amqpFactory = $amqpFactory ?: new AmqpFactory(); + $this->amqpFactory = $amqpFactory ?? new AmqpFactory(); } /** diff --git a/src/Symfony/Component/Messenger/Bridge/Beanstalkd/Tests/Transport/BeanstalkdTransportTest.php b/src/Symfony/Component/Messenger/Bridge/Beanstalkd/Tests/Transport/BeanstalkdTransportTest.php index 0bf4005cd757..5671163982b5 100644 --- a/src/Symfony/Component/Messenger/Bridge/Beanstalkd/Tests/Transport/BeanstalkdTransportTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Beanstalkd/Tests/Transport/BeanstalkdTransportTest.php @@ -52,8 +52,8 @@ public function testReceivesMessages() private function getTransport(SerializerInterface $serializer = null, Connection $connection = null): BeanstalkdTransport { - $serializer = $serializer ?: $this->createMock(SerializerInterface::class); - $connection = $connection ?: $this->createMock(Connection::class); + $serializer = $serializer ?? $this->createMock(SerializerInterface::class); + $connection = $connection ?? $this->createMock(Connection::class); return new BeanstalkdTransport($connection, $serializer); } diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php index 378727ebda52..cb0d3e79bd66 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php @@ -287,6 +287,7 @@ public function testFind() ->willReturn($queryBuilder); $queryBuilder ->method('where') + ->with('m.id = ? and m.queue_name = ?') ->willReturn($queryBuilder); $queryBuilder ->method('getSQL') diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineTransportTest.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineTransportTest.php index d28a9280876d..751390503234 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineTransportTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineTransportTest.php @@ -71,8 +71,8 @@ public function testConfigureSchema() private function getTransport(SerializerInterface $serializer = null, Connection $connection = null): DoctrineTransport { - $serializer = $serializer ?: $this->createMock(SerializerInterface::class); - $connection = $connection ?: $this->createMock(Connection::class); + $serializer = $serializer ?? $this->createMock(SerializerInterface::class); + $connection = $connection ?? $this->createMock(Connection::class); return new DoctrineTransport($connection, $serializer); } diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php index daf95b5fbbce..b7c99a23bf52 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php @@ -278,9 +278,9 @@ public function findAll(int $limit = null): array public function find($id): ?array { $queryBuilder = $this->createQueryBuilder() - ->where('m.id = ?'); + ->where('m.id = ? and m.queue_name = ?'); - $stmt = $this->executeQuery($queryBuilder->getSQL(), [$id]); + $stmt = $this->executeQuery($queryBuilder->getSQL(), [$id, $this->configuration['queue_name']]); $data = $stmt instanceof Result || $stmt instanceof DriverResult ? $stmt->fetchAssociative() : $stmt->fetch(); return false === $data ? null : $this->decodeEnvelopeHeaders($data); diff --git a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisTransportTest.php b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisTransportTest.php index 892c072af815..19528de19e76 100644 --- a/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisTransportTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Redis/Tests/Transport/RedisTransportTest.php @@ -52,8 +52,8 @@ public function testReceivesMessages() private function getTransport(SerializerInterface $serializer = null, Connection $connection = null): RedisTransport { - $serializer = $serializer ?: $this->createMock(SerializerInterface::class); - $connection = $connection ?: $this->createMock(Connection::class); + $serializer = $serializer ?? $this->createMock(SerializerInterface::class); + $connection = $connection ?? $this->createMock(Connection::class); return new RedisTransport($connection, $serializer); } diff --git a/src/Symfony/Component/Messenger/Command/AbstractFailedMessagesCommand.php b/src/Symfony/Component/Messenger/Command/AbstractFailedMessagesCommand.php index 77a6700500ee..783d24f1d4ab 100644 --- a/src/Symfony/Component/Messenger/Command/AbstractFailedMessagesCommand.php +++ b/src/Symfony/Component/Messenger/Command/AbstractFailedMessagesCommand.php @@ -52,7 +52,7 @@ protected function getReceiverName(): string } /** - * @return mixed|null + * @return mixed */ protected function getMessageId(Envelope $envelope) { diff --git a/src/Symfony/Component/Mime/Address.php b/src/Symfony/Component/Mime/Address.php index f317e218e11e..373d4236f815 100644 --- a/src/Symfony/Component/Mime/Address.php +++ b/src/Symfony/Component/Mime/Address.php @@ -114,7 +114,7 @@ public static function create($address): self } /** - * @param (Address|string)[] $addresses + * @param array $addresses * * @return Address[] */ diff --git a/src/Symfony/Component/Mime/Header/Headers.php b/src/Symfony/Component/Mime/Header/Headers.php index b8d8da64f071..32e4d41b3a80 100644 --- a/src/Symfony/Component/Mime/Header/Headers.php +++ b/src/Symfony/Component/Mime/Header/Headers.php @@ -75,7 +75,7 @@ public function getMaxLineLength(): int } /** - * @param (Address|string)[] $addresses + * @param array $addresses * * @return $this */ diff --git a/src/Symfony/Component/Mime/Part/DataPart.php b/src/Symfony/Component/Mime/Part/DataPart.php index 0da9230c29a8..bbe8eca10b32 100644 --- a/src/Symfony/Component/Mime/Part/DataPart.php +++ b/src/Symfony/Component/Mime/Part/DataPart.php @@ -46,8 +46,6 @@ public function __construct($body, string $filename = null, string $contentType public static function fromPath(string $path, string $name = null, string $contentType = null): self { - // FIXME: if file is not readable, exception? - if (null === $contentType) { $ext = strtolower(substr($path, strrpos($path, '.') + 1)); if (null === self::$mimeTypes) { diff --git a/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php b/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php index f53dea4e9934..ff6df818f4ba 100644 --- a/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php +++ b/src/Symfony/Component/Mime/Part/Multipart/FormDataPart.php @@ -26,7 +26,7 @@ final class FormDataPart extends AbstractMultipartPart private $fields = []; /** - * @param (string|array|DataPart)[] $fields + * @param array $fields */ public function __construct(array $fields = []) { diff --git a/src/Symfony/Component/Notifier/Bridge/Discord/.gitignore b/src/Symfony/Component/Notifier/Bridge/Discord/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Discord/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/Discord/Tests/DiscordTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Discord/Tests/DiscordTransportTest.php index 70dd0f46eaac..37aac4471cfc 100644 --- a/src/Symfony/Component/Notifier/Bridge/Discord/Tests/DiscordTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Discord/Tests/DiscordTransportTest.php @@ -30,7 +30,7 @@ final class DiscordTransportTest extends TransportTestCase */ public function createTransport(?HttpClientInterface $client = null): TransportInterface { - return (new DiscordTransport('testToken', 'testWebhookId', $client ?: $this->createMock(HttpClientInterface::class)))->setHost('host.test'); + return (new DiscordTransport('testToken', 'testWebhookId', $client ?? $this->createMock(HttpClientInterface::class)))->setHost('host.test'); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/Esendex/.gitattributes b/src/Symfony/Component/Notifier/Bridge/Esendex/.gitattributes new file mode 100644 index 000000000000..84c7add058fb --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Esendex/.gitattributes @@ -0,0 +1,4 @@ +/Tests export-ignore +/phpunit.xml.dist export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore diff --git a/src/Symfony/Component/Notifier/Bridge/Esendex/.gitignore b/src/Symfony/Component/Notifier/Bridge/Esendex/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Esendex/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/Esendex/Tests/EsendexTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Esendex/Tests/EsendexTransportTest.php index 4076ad49884a..6e3518a7dc45 100644 --- a/src/Symfony/Component/Notifier/Bridge/Esendex/Tests/EsendexTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Esendex/Tests/EsendexTransportTest.php @@ -29,7 +29,7 @@ final class EsendexTransportTest extends TransportTestCase */ public function createTransport(?HttpClientInterface $client = null): TransportInterface { - return (new EsendexTransport('testToken', 'testAccountReference', 'testFrom', $client ?: $this->createMock(HttpClientInterface::class)))->setHost('host.test'); + return (new EsendexTransport('testToken', 'testAccountReference', 'testFrom', $client ?? $this->createMock(HttpClientInterface::class)))->setHost('host.test'); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/Firebase/.gitignore b/src/Symfony/Component/Notifier/Bridge/Firebase/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Firebase/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/Firebase/Tests/FirebaseTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Firebase/Tests/FirebaseTransportTest.php index 23845284b38e..61fad8bad8ea 100644 --- a/src/Symfony/Component/Notifier/Bridge/Firebase/Tests/FirebaseTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Firebase/Tests/FirebaseTransportTest.php @@ -29,7 +29,7 @@ final class FirebaseTransportTest extends TransportTestCase */ public function createTransport(?HttpClientInterface $client = null): TransportInterface { - return new FirebaseTransport('username:password', $client ?: $this->createMock(HttpClientInterface::class)); + return new FirebaseTransport('username:password', $client ?? $this->createMock(HttpClientInterface::class)); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/FreeMobile/.gitignore b/src/Symfony/Component/Notifier/Bridge/FreeMobile/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/FreeMobile/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/FreeMobile/Tests/FreeMobileTransportTest.php b/src/Symfony/Component/Notifier/Bridge/FreeMobile/Tests/FreeMobileTransportTest.php index 739672a90390..394b37e23a9b 100644 --- a/src/Symfony/Component/Notifier/Bridge/FreeMobile/Tests/FreeMobileTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/FreeMobile/Tests/FreeMobileTransportTest.php @@ -26,7 +26,7 @@ final class FreeMobileTransportTest extends TransportTestCase */ public function createTransport(?HttpClientInterface $client = null): TransportInterface { - return new FreeMobileTransport('login', 'pass', '0611223344', $client ?: $this->createMock(HttpClientInterface::class)); + return new FreeMobileTransport('login', 'pass', '0611223344', $client ?? $this->createMock(HttpClientInterface::class)); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/GoogleChat/.gitignore b/src/Symfony/Component/Notifier/Bridge/GoogleChat/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/GoogleChat/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportTest.php b/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportTest.php index 9fd6a7c7d3bb..3bde37fb40b4 100644 --- a/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/GoogleChat/Tests/GoogleChatTransportTest.php @@ -33,7 +33,7 @@ final class GoogleChatTransportTest extends TestCase */ public function createTransport(?HttpClientInterface $client = null): TransportInterface { - return new GoogleChatTransport('My-Space', 'theAccessKey', 'theAccessToken=', $client ?: $this->createMock(HttpClientInterface::class)); + return new GoogleChatTransport('My-Space', 'theAccessKey', 'theAccessToken=', $client ?? $this->createMock(HttpClientInterface::class)); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/Infobip/.gitignore b/src/Symfony/Component/Notifier/Bridge/Infobip/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Infobip/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/Infobip/Tests/InfobipTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Infobip/Tests/InfobipTransportTest.php index 98c40c73d9fe..8d5838ace22d 100644 --- a/src/Symfony/Component/Notifier/Bridge/Infobip/Tests/InfobipTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Infobip/Tests/InfobipTransportTest.php @@ -26,7 +26,7 @@ final class InfobipTransportTest extends TransportTestCase */ public function createTransport(?HttpClientInterface $client = null): TransportInterface { - return (new InfobipTransport('authtoken', '0611223344', $client ?: $this->createMock(HttpClientInterface::class)))->setHost('host.test'); + return (new InfobipTransport('authtoken', '0611223344', $client ?? $this->createMock(HttpClientInterface::class)))->setHost('host.test'); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/LinkedIn/.gitattributes b/src/Symfony/Component/Notifier/Bridge/LinkedIn/.gitattributes new file mode 100644 index 000000000000..84c7add058fb --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/LinkedIn/.gitattributes @@ -0,0 +1,4 @@ +/Tests export-ignore +/phpunit.xml.dist export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore diff --git a/src/Symfony/Component/Notifier/Bridge/LinkedIn/.gitignore b/src/Symfony/Component/Notifier/Bridge/LinkedIn/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/LinkedIn/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/LinkedIn/Tests/LinkedInTransportTest.php b/src/Symfony/Component/Notifier/Bridge/LinkedIn/Tests/LinkedInTransportTest.php index f3bbcadaa654..65b11c1445f8 100644 --- a/src/Symfony/Component/Notifier/Bridge/LinkedIn/Tests/LinkedInTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/LinkedIn/Tests/LinkedInTransportTest.php @@ -23,7 +23,7 @@ final class LinkedInTransportTest extends TransportTestCase */ public function createTransport(?HttpClientInterface $client = null): TransportInterface { - return (new LinkedInTransport('AuthToken', 'AccountId', $client ?: $this->createMock(HttpClientInterface::class)))->setHost('host.test'); + return (new LinkedInTransport('AuthToken', 'AccountId', $client ?? $this->createMock(HttpClientInterface::class)))->setHost('host.test'); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/Mattermost/.gitignore b/src/Symfony/Component/Notifier/Bridge/Mattermost/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Mattermost/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/Mattermost/Tests/MattermostTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Mattermost/Tests/MattermostTransportTest.php index 53f91afd46cb..7d2af7de0431 100644 --- a/src/Symfony/Component/Notifier/Bridge/Mattermost/Tests/MattermostTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Mattermost/Tests/MattermostTransportTest.php @@ -29,7 +29,7 @@ final class MattermostTransportTest extends TransportTestCase */ public function createTransport(?HttpClientInterface $client = null): TransportInterface { - return (new MattermostTransport('testAccessToken', 'testChannel', $client ?: $this->createMock(HttpClientInterface::class)))->setHost('host.test'); + return (new MattermostTransport('testAccessToken', 'testChannel', $client ?? $this->createMock(HttpClientInterface::class)))->setHost('host.test'); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/Mobyt/.gitignore b/src/Symfony/Component/Notifier/Bridge/Mobyt/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Mobyt/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/Mobyt/Tests/MobytTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Mobyt/Tests/MobytTransportTest.php index 906ecebcf4ce..4ec0598166fa 100644 --- a/src/Symfony/Component/Notifier/Bridge/Mobyt/Tests/MobytTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Mobyt/Tests/MobytTransportTest.php @@ -30,7 +30,7 @@ final class MobytTransportTest extends TransportTestCase */ public function createTransport(?HttpClientInterface $client = null, string $messageType = MobytOptions::MESSAGE_TYPE_QUALITY_LOW): TransportInterface { - return (new MobytTransport('accountSid', 'authToken', 'from', $messageType, $client ?: $this->createMock(HttpClientInterface::class)))->setHost('host.test'); + return (new MobytTransport('accountSid', 'authToken', 'from', $messageType, $client ?? $this->createMock(HttpClientInterface::class)))->setHost('host.test'); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/Nexmo/.gitignore b/src/Symfony/Component/Notifier/Bridge/Nexmo/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Nexmo/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/Nexmo/Tests/NexmoTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Nexmo/Tests/NexmoTransportTest.php index e8389d2ac919..d179efb6225e 100644 --- a/src/Symfony/Component/Notifier/Bridge/Nexmo/Tests/NexmoTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Nexmo/Tests/NexmoTransportTest.php @@ -26,7 +26,7 @@ final class NexmoTransportTest extends TransportTestCase */ public function createTransport(?HttpClientInterface $client = null): TransportInterface { - return new NexmoTransport('apiKey', 'apiSecret', 'sender', $client ?: $this->createMock(HttpClientInterface::class)); + return new NexmoTransport('apiKey', 'apiSecret', 'sender', $client ?? $this->createMock(HttpClientInterface::class)); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/OvhCloud/.gitignore b/src/Symfony/Component/Notifier/Bridge/OvhCloud/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/OvhCloud/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/OvhCloud/Tests/OvhCloudTransportTest.php b/src/Symfony/Component/Notifier/Bridge/OvhCloud/Tests/OvhCloudTransportTest.php index 4e1c5b84dc79..52099efca62e 100644 --- a/src/Symfony/Component/Notifier/Bridge/OvhCloud/Tests/OvhCloudTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/OvhCloud/Tests/OvhCloudTransportTest.php @@ -28,7 +28,7 @@ final class OvhCloudTransportTest extends TransportTestCase */ public function createTransport(?HttpClientInterface $client = null): TransportInterface { - return new OvhCloudTransport('applicationKey', 'applicationSecret', 'consumerKey', 'serviceName', $client ?: $this->createMock(HttpClientInterface::class)); + return new OvhCloudTransport('applicationKey', 'applicationSecret', 'consumerKey', 'serviceName', $client ?? $this->createMock(HttpClientInterface::class)); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/RocketChat/.gitignore b/src/Symfony/Component/Notifier/Bridge/RocketChat/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/RocketChat/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/RocketChat/Tests/RocketChatTransportTest.php b/src/Symfony/Component/Notifier/Bridge/RocketChat/Tests/RocketChatTransportTest.php index 71133404c1d4..e29db766cfca 100644 --- a/src/Symfony/Component/Notifier/Bridge/RocketChat/Tests/RocketChatTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/RocketChat/Tests/RocketChatTransportTest.php @@ -29,7 +29,7 @@ final class RocketChatTransportTest extends TransportTestCase */ public function createTransport(?HttpClientInterface $client = null, string $channel = null): TransportInterface { - return new RocketChatTransport('testAccessToken', $channel, $client ?: $this->createMock(HttpClientInterface::class)); + return new RocketChatTransport('testAccessToken', $channel, $client ?? $this->createMock(HttpClientInterface::class)); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/Sendinblue/.gitignore b/src/Symfony/Component/Notifier/Bridge/Sendinblue/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Sendinblue/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/Sendinblue/Tests/SendinblueTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Sendinblue/Tests/SendinblueTransportTest.php index f784b0810508..71eb02153949 100644 --- a/src/Symfony/Component/Notifier/Bridge/Sendinblue/Tests/SendinblueTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Sendinblue/Tests/SendinblueTransportTest.php @@ -29,7 +29,7 @@ final class SendinblueTransportTest extends TransportTestCase */ public function createTransport(?HttpClientInterface $client = null): TransportInterface { - return (new SendinblueTransport('api-key', '0611223344', $client ?: $this->createMock(HttpClientInterface::class)))->setHost('host.test'); + return (new SendinblueTransport('api-key', '0611223344', $client ?? $this->createMock(HttpClientInterface::class)))->setHost('host.test'); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/Sinch/.gitignore b/src/Symfony/Component/Notifier/Bridge/Sinch/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Sinch/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/Sinch/Tests/SinchTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Sinch/Tests/SinchTransportTest.php index 03eb9eb6c521..c630ae61284a 100644 --- a/src/Symfony/Component/Notifier/Bridge/Sinch/Tests/SinchTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Sinch/Tests/SinchTransportTest.php @@ -26,7 +26,7 @@ final class SinchTransportTest extends TransportTestCase */ public function createTransport(?HttpClientInterface $client = null): TransportInterface { - return new SinchTransport('accountSid', 'authToken', 'sender', $client ?: $this->createMock(HttpClientInterface::class)); + return new SinchTransport('accountSid', 'authToken', 'sender', $client ?? $this->createMock(HttpClientInterface::class)); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/Slack/.gitignore b/src/Symfony/Component/Notifier/Bridge/Slack/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Slack/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/Slack/Tests/SlackTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Slack/Tests/SlackTransportTest.php index 3b7a3c6f8ff6..c75768ad6a05 100644 --- a/src/Symfony/Component/Notifier/Bridge/Slack/Tests/SlackTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Slack/Tests/SlackTransportTest.php @@ -33,7 +33,7 @@ final class SlackTransportTest extends TransportTestCase */ public function createTransport(?HttpClientInterface $client = null, string $channel = null): TransportInterface { - return new SlackTransport('testToken', $channel, $client ?: $this->createMock(HttpClientInterface::class)); + return new SlackTransport('testToken', $channel, $client ?? $this->createMock(HttpClientInterface::class)); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/Smsapi/.gitignore b/src/Symfony/Component/Notifier/Bridge/Smsapi/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Smsapi/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportTest.php index 24d6730fe446..9e77b82e387f 100644 --- a/src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Smsapi/Tests/SmsapiTransportTest.php @@ -26,7 +26,7 @@ final class SmsapiTransportTest extends TransportTestCase */ public function createTransport(?HttpClientInterface $client = null): TransportInterface { - return (new SmsapiTransport('testToken', 'testFrom', $client ?: $this->createMock(HttpClientInterface::class)))->setHost('test.host'); + return (new SmsapiTransport('testToken', 'testFrom', $client ?? $this->createMock(HttpClientInterface::class)))->setHost('test.host'); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/Telegram/.gitignore b/src/Symfony/Component/Notifier/Bridge/Telegram/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Telegram/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/Telegram/Tests/TelegramTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Telegram/Tests/TelegramTransportTest.php index eeed3b5024c9..fb65e7e2b3c9 100644 --- a/src/Symfony/Component/Notifier/Bridge/Telegram/Tests/TelegramTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Telegram/Tests/TelegramTransportTest.php @@ -30,7 +30,7 @@ final class TelegramTransportTest extends TransportTestCase */ public function createTransport(?HttpClientInterface $client = null, string $channel = null): TransportInterface { - return new TelegramTransport('token', $channel, $client ?: $this->createMock(HttpClientInterface::class)); + return new TelegramTransport('token', $channel, $client ?? $this->createMock(HttpClientInterface::class)); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/Twilio/.gitignore b/src/Symfony/Component/Notifier/Bridge/Twilio/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Twilio/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/Twilio/Tests/TwilioTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Twilio/Tests/TwilioTransportTest.php index 9dd3cda88703..b49807923ff6 100644 --- a/src/Symfony/Component/Notifier/Bridge/Twilio/Tests/TwilioTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Twilio/Tests/TwilioTransportTest.php @@ -26,7 +26,7 @@ final class TwilioTransportTest extends TransportTestCase */ public function createTransport(?HttpClientInterface $client = null): TransportInterface { - return new TwilioTransport('accountSid', 'authToken', 'from', $client ?: $this->createMock(HttpClientInterface::class)); + return new TwilioTransport('accountSid', 'authToken', 'from', $client ?? $this->createMock(HttpClientInterface::class)); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Notifier/Bridge/Zulip/.gitignore b/src/Symfony/Component/Notifier/Bridge/Zulip/.gitignore new file mode 100644 index 000000000000..c49a5d8df5c6 --- /dev/null +++ b/src/Symfony/Component/Notifier/Bridge/Zulip/.gitignore @@ -0,0 +1,3 @@ +vendor/ +composer.lock +phpunit.xml diff --git a/src/Symfony/Component/Notifier/Bridge/Zulip/Tests/ZulipTransportTest.php b/src/Symfony/Component/Notifier/Bridge/Zulip/Tests/ZulipTransportTest.php index 422a04d118b9..d5eed5edc86c 100644 --- a/src/Symfony/Component/Notifier/Bridge/Zulip/Tests/ZulipTransportTest.php +++ b/src/Symfony/Component/Notifier/Bridge/Zulip/Tests/ZulipTransportTest.php @@ -26,7 +26,7 @@ final class ZulipTransportTest extends TransportTestCase */ public function createTransport(?HttpClientInterface $client = null): TransportInterface { - return (new ZulipTransport('testEmail', 'testToken', 'testChannel', $client ?: $this->createMock(HttpClientInterface::class)))->setHost('test.host'); + return (new ZulipTransport('testEmail', 'testToken', 'testChannel', $client ?? $this->createMock(HttpClientInterface::class)))->setHost('test.host'); } public function toStringProvider(): iterable diff --git a/src/Symfony/Component/Process/Process.php b/src/Symfony/Component/Process/Process.php index 49192eeb4063..877f16cd3def 100644 --- a/src/Symfony/Component/Process/Process.php +++ b/src/Symfony/Component/Process/Process.php @@ -133,7 +133,7 @@ class Process implements \IteratorAggregate * @param array $command The command to run and its arguments listed as separate entries * @param string|null $cwd The working directory or null to use the working dir of the current PHP process * @param array|null $env The environment variables or null to use the same environment as the current PHP process - * @param mixed|null $input The input as stream resource, scalar or \Traversable, or null for no input + * @param mixed $input The input as stream resource, scalar or \Traversable, or null for no input * @param int|float|null $timeout The timeout in seconds or null to disable * * @throws LogicException When proc_open is not installed @@ -180,7 +180,7 @@ public function __construct(array $command, string $cwd = null, array $env = nul * @param string $command The command line to pass to the shell of the OS * @param string|null $cwd The working directory or null to use the working dir of the current PHP process * @param array|null $env The environment variables or null to use the same environment as the current PHP process - * @param mixed|null $input The input as stream resource, scalar or \Traversable, or null for no input + * @param mixed $input The input as stream resource, scalar or \Traversable, or null for no input * @param int|float|null $timeout The timeout in seconds or null to disable * * @return static diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php index f8b62b5e917f..8a73c37a2d81 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php @@ -326,7 +326,17 @@ private function getDocBlockFromMethod(string $class, string $ucFirstProperty, i } try { - return [$this->docBlockFactory->create($reflectionMethod, $this->createFromReflector($reflectionMethod->getDeclaringClass())), $prefix]; + $reflector = $reflectionMethod->getDeclaringClass(); + + foreach ($reflector->getTraits() as $trait) { + if ($trait->hasMethod($methodName)) { + $reflector = $trait; + + break; + } + } + + return [$this->docBlockFactory->create($reflectionMethod, $this->createFromReflector($reflector)), $prefix]; } catch (\InvalidArgumentException $e) { return null; } catch (\RuntimeException $e) { diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php index 6ad50ca89702..3acadc6484be 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php @@ -344,6 +344,23 @@ public function propertiesDefinedByTraitsProvider(): array ]; } + /** + * @dataProvider methodsDefinedByTraitsProvider + */ + public function testMethodsDefinedByTraits(string $property, Type $type) + { + $this->assertEquals([$type], $this->extractor->getTypes(DummyUsingTrait::class, $property)); + } + + public function methodsDefinedByTraitsProvider(): array + { + return [ + ['methodInTraitPrimitiveType', new Type(Type::BUILTIN_TYPE_STRING)], + ['methodInTraitObjectSameNamespace', new Type(Type::BUILTIN_TYPE_OBJECT, false, DummyUsedInTrait::class)], + ['methodInTraitObjectDifferentNamespace', new Type(Type::BUILTIN_TYPE_OBJECT, false, Dummy::class)], + ]; + } + /** * @dataProvider propertiesStaticTypeProvider */ diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/TraitUsage/DummyTrait.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/TraitUsage/DummyTrait.php index 6284ebf10567..0599d979c295 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/TraitUsage/DummyTrait.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/TraitUsage/DummyTrait.php @@ -29,4 +29,28 @@ trait DummyTrait * @var Dummy */ private $propertyInTraitObjectDifferentNamespace; + + /** + * @return string + */ + public function getMethodInTraitPrimitiveType() + { + return 'value'; + } + + /** + * @return DummyUsedInTrait + */ + public function getMethodInTraitObjectSameNamespace() + { + return new DummyUsedInTrait(); + } + + /** + * @return Dummy + */ + public function getMethodInTraitObjectDifferentNamespace() + { + return new Dummy(); + } } diff --git a/src/Symfony/Component/RateLimiter/RateLimit.php b/src/Symfony/Component/RateLimiter/RateLimit.php index 64c706b6e656..8aef2652a331 100644 --- a/src/Symfony/Component/RateLimiter/RateLimit.php +++ b/src/Symfony/Component/RateLimiter/RateLimit.php @@ -67,6 +67,11 @@ public function getLimit(): int public function wait(): void { - sleep(($this->retryAfter->getTimestamp() - time()) * 1e6); + $delta = $this->retryAfter->getTimestamp() - time(); + if ($delta <= 0) { + return; + } + + sleep($delta); } } diff --git a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php index 9951625be93d..355b4f486c8b 100644 --- a/src/Symfony/Component/Routing/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/Routing/Loader/XmlFileLoader.php @@ -358,7 +358,7 @@ private function parseDefaultsConfig(\DOMElement $element, string $path) /** * Recursively parses the value of a "default" element. * - * @return array|bool|float|int|string The parsed value + * @return array|bool|float|int|string|null The parsed value * * @throws \InvalidArgumentException when the XML is invalid */ diff --git a/src/Symfony/Component/Routing/Route.php b/src/Symfony/Component/Routing/Route.php index ce52a5696f53..d52ed4240a8e 100644 --- a/src/Symfony/Component/Routing/Route.php +++ b/src/Symfony/Component/Routing/Route.php @@ -539,15 +539,15 @@ private function extractInlineDefaultsAndRequirements(string $pattern): string return $pattern; } - return preg_replace_callback('#\{(!?\w++)(<.*?>)?(\?[^\}]*+)?\}#', function ($m) { - if (isset($m[3][0])) { - $this->setDefault($m[1], '?' !== $m[3] ? substr($m[3], 1) : null); + return preg_replace_callback('#\{(!?)(\w++)(<.*?>)?(\?[^\}]*+)?\}#', function ($m) { + if (isset($m[4][0])) { + $this->setDefault($m[2], '?' !== $m[4] ? substr($m[4], 1) : null); } - if (isset($m[2][0])) { - $this->setRequirement($m[1], substr($m[2], 1, -1)); + if (isset($m[3][0])) { + $this->setRequirement($m[2], substr($m[3], 1, -1)); } - return '{'.$m[1].'}'; + return '{'.$m[1].$m[2].'}'; }, $pattern); } diff --git a/src/Symfony/Component/Routing/Router.php b/src/Symfony/Component/Routing/Router.php index b5360c4b741d..60740370fdb5 100644 --- a/src/Symfony/Component/Routing/Router.php +++ b/src/Symfony/Component/Routing/Router.php @@ -102,7 +102,7 @@ public function __construct(LoaderInterface $loader, $resource, array $options = $this->loader = $loader; $this->resource = $resource; $this->logger = $logger; - $this->context = $context ?: new RequestContext(); + $this->context = $context ?? new RequestContext(); $this->setOptions($options); $this->defaultLocale = $defaultLocale; } diff --git a/src/Symfony/Component/Routing/Tests/Matcher/CompiledRedirectableUrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/CompiledRedirectableUrlMatcherTest.php index 45618ba0d7fd..faf5f181a2aa 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/CompiledRedirectableUrlMatcherTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/CompiledRedirectableUrlMatcherTest.php @@ -25,7 +25,7 @@ protected function getUrlMatcher(RouteCollection $routes, RequestContext $contex $compiledRoutes = $dumper->getCompiledRoutes(); return $this->getMockBuilder(TestCompiledRedirectableUrlMatcher::class) - ->setConstructorArgs([$compiledRoutes, $context ?: new RequestContext()]) + ->setConstructorArgs([$compiledRoutes, $context ?? new RequestContext()]) ->setMethods(['redirect']) ->getMock(); } diff --git a/src/Symfony/Component/Routing/Tests/Matcher/CompiledUrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/CompiledUrlMatcherTest.php index 0a93f5ee7531..c8cd40cc2643 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/CompiledUrlMatcherTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/CompiledUrlMatcherTest.php @@ -22,6 +22,6 @@ protected function getUrlMatcher(RouteCollection $routes, RequestContext $contex { $dumper = new CompiledUrlMatcherDumper($routes); - return new CompiledUrlMatcher($dumper->getCompiledRoutes(), $context ?: new RequestContext()); + return new CompiledUrlMatcher($dumper->getCompiledRoutes(), $context ?? new RequestContext()); } } diff --git a/src/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php index e7e49a212bd4..97073c48e309 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/RedirectableUrlMatcherTest.php @@ -211,6 +211,6 @@ public function testTrailingRequirementWithDefault_A() protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null) { - return $this->getMockForAbstractClass(RedirectableUrlMatcher::class, [$routes, $context ?: new RequestContext()]); + return $this->getMockForAbstractClass(RedirectableUrlMatcher::class, [$routes, $context ?? new RequestContext()]); } } diff --git a/src/Symfony/Component/Routing/Tests/Matcher/TraceableUrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/TraceableUrlMatcherTest.php index b31f99e0c496..b33e93caa1a8 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/TraceableUrlMatcherTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/TraceableUrlMatcherTest.php @@ -121,6 +121,6 @@ public function testRoutesWithConditions() protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null) { - return new TraceableUrlMatcher($routes, $context ?: new RequestContext()); + return new TraceableUrlMatcher($routes, $context ?? new RequestContext()); } } diff --git a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php index 7297a887731d..fa98fbc557ad 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php @@ -943,6 +943,6 @@ public function testRestrictiveTrailingRequirementWithStaticRouteAfter() protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null) { - return new UrlMatcher($routes, $context ?: new RequestContext()); + return new UrlMatcher($routes, $context ?? new RequestContext()); } } diff --git a/src/Symfony/Component/Routing/Tests/RouteTest.php b/src/Symfony/Component/Routing/Tests/RouteTest.php index 5dc12c8759a2..63ae8d952ad6 100644 --- a/src/Symfony/Component/Routing/Tests/RouteTest.php +++ b/src/Symfony/Component/Routing/Tests/RouteTest.php @@ -50,6 +50,14 @@ public function testPath() $this->assertEquals($route, $route->setPath(''), '->setPath() implements a fluent interface'); $route->setPath('//path'); $this->assertEquals('/path', $route->getPath(), '->setPath() does not allow two slashes "//" at the beginning of the path as it would be confused with a network path when generating the path from the route'); + $route->setPath('/path/{!foo}'); + $this->assertEquals('/path/{!foo}', $route->getPath(), '->setPath() keeps ! to pass important params'); + $route->setPath('/path/{bar<\w++>}'); + $this->assertEquals('/path/{bar}', $route->getPath(), '->setPath() removes inline requirements'); + $route->setPath('/path/{foo?value}'); + $this->assertEquals('/path/{foo}', $route->getPath(), '->setPath() removes inline defaults'); + $route->setPath('/path/{!bar<\d+>?value}'); + $this->assertEquals('/path/{!bar}', $route->getPath(), '->setPath() removes all inline settings'); } public function testOptions() @@ -221,17 +229,20 @@ public function testInlineDefaultAndRequirement() $this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', null), new Route('/foo/{bar?}')); $this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', 'baz'), new Route('/foo/{bar?baz}')); $this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', 'baz'), new Route('/foo/{bar?baz}')); - $this->assertEquals((new Route('/foo/{!bar}'))->setDefault('!bar', 'baz'), new Route('/foo/{!bar?baz}')); + $this->assertEquals((new Route('/foo/{!bar}'))->setDefault('bar', 'baz'), new Route('/foo/{!bar?baz}')); $this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', 'baz'), new Route('/foo/{bar?}', ['bar' => 'baz'])); $this->assertEquals((new Route('/foo/{bar}'))->setRequirement('bar', '.*'), new Route('/foo/{bar<.*>}')); $this->assertEquals((new Route('/foo/{bar}'))->setRequirement('bar', '>'), new Route('/foo/{bar<>>}')); $this->assertEquals((new Route('/foo/{bar}'))->setRequirement('bar', '\d+'), new Route('/foo/{bar<.*>}', [], ['bar' => '\d+'])); $this->assertEquals((new Route('/foo/{bar}'))->setRequirement('bar', '[a-z]{2}'), new Route('/foo/{bar<[a-z]{2}>}')); + $this->assertEquals((new Route('/foo/{!bar}'))->setRequirement('bar', '\d+'), new Route('/foo/{!bar<\d+>}')); $this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', null)->setRequirement('bar', '.*'), new Route('/foo/{bar<.*>?}')); $this->assertEquals((new Route('/foo/{bar}'))->setDefault('bar', '<>')->setRequirement('bar', '>'), new Route('/foo/{bar<>>?<>}')); + $this->assertEquals((new Route('/{foo}/{!bar}'))->setDefaults(['bar' => '<>', 'foo' => '\\'])->setRequirements(['bar' => '\\', 'foo' => '.']), new Route('/{foo<.>?\}/{!bar<\>?<>}')); + $this->assertEquals((new Route('/'))->setHost('{bar}')->setDefault('bar', null), (new Route('/'))->setHost('{bar?}')); $this->assertEquals((new Route('/'))->setHost('{bar}')->setDefault('bar', 'baz'), (new Route('/'))->setHost('{bar?baz}')); $this->assertEquals((new Route('/'))->setHost('{bar}')->setDefault('bar', 'baz'), (new Route('/'))->setHost('{bar?baz}')); diff --git a/src/Symfony/Component/Routing/composer.json b/src/Symfony/Component/Routing/composer.json index 164dbb2bfdc9..8db1bef646dd 100644 --- a/src/Symfony/Component/Routing/composer.json +++ b/src/Symfony/Component/Routing/composer.json @@ -38,8 +38,7 @@ "symfony/http-foundation": "For using a Symfony Request object", "symfony/config": "For using the all-in-one router or any loader", "symfony/yaml": "For using the YAML loader", - "symfony/expression-language": "For using expression matching", - "doctrine/annotations": "For using the annotation loader" + "symfony/expression-language": "For using expression matching" }, "autoload": { "psr-4": { "Symfony\\Component\\Routing\\": "" }, diff --git a/src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php index 83b7f3f1e89b..5748dd5cdfe0 100644 --- a/src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php +++ b/src/Symfony/Component/Security/Core/Encoder/NativePasswordEncoder.php @@ -51,11 +51,11 @@ public function __construct(int $opsLimit = null, int $memLimit = null, int $cos $algos = [1 => \PASSWORD_BCRYPT, '2y' => \PASSWORD_BCRYPT]; if (\defined('PASSWORD_ARGON2I')) { - $this->algo = $algos[2] = $algos['argon2i'] = (string) \PASSWORD_ARGON2I; + $this->algo = $algos[2] = $algos['argon2i'] = \PASSWORD_ARGON2I; } if (\defined('PASSWORD_ARGON2ID')) { - $this->algo = $algos[3] = $algos['argon2id'] = (string) \PASSWORD_ARGON2ID; + $this->algo = $algos[3] = $algos['argon2id'] = \PASSWORD_ARGON2ID; } if (null !== $algo) { @@ -75,7 +75,7 @@ public function __construct(int $opsLimit = null, int $memLimit = null, int $cos */ public function encodePassword(string $raw, ?string $salt): string { - if (\strlen($raw) > self::MAX_PASSWORD_LENGTH || ((string) \PASSWORD_BCRYPT === $this->algo && 72 < \strlen($raw))) { + if (\strlen($raw) > self::MAX_PASSWORD_LENGTH || (\PASSWORD_BCRYPT === $this->algo && 72 < \strlen($raw))) { throw new BadCredentialsException('Invalid password.'); } diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.en.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.en.xlf index d274ea9527fa..e7bc7c7082f6 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.en.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.en.xlf @@ -70,6 +70,14 @@ Invalid or expired login link. Invalid or expired login link. + + Too many failed login attempts, please try again in %minutes% minute. + Too many failed login attempts, please try again in %minutes% minute. + + + Too many failed login attempts, please try again in %minutes% minutes. + Too many failed login attempts, please try again in %minutes% minutes. + diff --git a/src/Symfony/Component/Security/Core/Resources/translations/security.fr.xlf b/src/Symfony/Component/Security/Core/Resources/translations/security.fr.xlf index 72ad86d6d7e5..38fec553b016 100644 --- a/src/Symfony/Component/Security/Core/Resources/translations/security.fr.xlf +++ b/src/Symfony/Component/Security/Core/Resources/translations/security.fr.xlf @@ -70,6 +70,14 @@ Invalid or expired login link. Lien de connexion invalide ou expiré. + + Too many failed login attempts, please try again in %minutes% minute. + Plusieurs tentatives de connexion ont échoué, veuillez réessayer dans %minutes% minute. + + + Too many failed login attempts, please try again in %minutes% minutes. + Plusieurs tentatives de connexion ont échoué, veuillez réessayer dans %minutes% minutes. + diff --git a/src/Symfony/Component/Security/Csrf/CsrfTokenManager.php b/src/Symfony/Component/Security/Csrf/CsrfTokenManager.php index da28302b78f3..89defe75343a 100644 --- a/src/Symfony/Component/Security/Csrf/CsrfTokenManager.php +++ b/src/Symfony/Component/Security/Csrf/CsrfTokenManager.php @@ -39,8 +39,8 @@ class CsrfTokenManager implements CsrfTokenManagerInterface */ public function __construct(TokenGeneratorInterface $generator = null, TokenStorageInterface $storage = null, $namespace = null) { - $this->generator = $generator ?: new UriSafeTokenGenerator(); - $this->storage = $storage ?: new NativeSessionTokenStorage(); + $this->generator = $generator ?? new UriSafeTokenGenerator(); + $this->storage = $storage ?? new NativeSessionTokenStorage(); $superGlobalNamespaceGenerator = function () { return !empty($_SERVER['HTTPS']) && 'off' !== strtolower($_SERVER['HTTPS']) ? 'https-' : ''; diff --git a/src/Symfony/Component/Security/Http/Authenticator/Passport/Badge/UserBadge.php b/src/Symfony/Component/Security/Http/Authenticator/Passport/Badge/UserBadge.php index 10856e4bfe87..11ef37b2cfb3 100644 --- a/src/Symfony/Component/Security/Http/Authenticator/Passport/Badge/UserBadge.php +++ b/src/Symfony/Component/Security/Http/Authenticator/Passport/Badge/UserBadge.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Security\Http\Authenticator\Passport\Badge; +use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Http\EventListener\UserProviderListener; @@ -55,6 +56,9 @@ public function getUserIdentifier(): string return $this->userIdentifier; } + /** + * @throws AuthenticationException when the user cannot be found + */ public function getUser(): UserInterface { if (null === $this->user) { diff --git a/src/Symfony/Component/Security/Http/Authenticator/Passport/Passport.php b/src/Symfony/Component/Security/Http/Authenticator/Passport/Passport.php index d9b23cd3a79d..553f75caeab2 100644 --- a/src/Symfony/Component/Security/Http/Authenticator/Passport/Passport.php +++ b/src/Symfony/Component/Security/Http/Authenticator/Passport/Passport.php @@ -55,6 +55,9 @@ public function __construct($userBadge, CredentialsInterface $credentials, array } } + /** + * {@inheritdoc} + */ public function getUser(): UserInterface { if (null === $this->user) { diff --git a/src/Symfony/Component/Security/Http/Authenticator/Passport/UserPassportInterface.php b/src/Symfony/Component/Security/Http/Authenticator/Passport/UserPassportInterface.php index 2d8b57f22b8b..e78a73338334 100644 --- a/src/Symfony/Component/Security/Http/Authenticator/Passport/UserPassportInterface.php +++ b/src/Symfony/Component/Security/Http/Authenticator/Passport/UserPassportInterface.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Security\Http\Authenticator\Passport; +use Symfony\Component\Security\Core\Exception\AuthenticationException; use Symfony\Component\Security\Core\User\UserInterface; /** @@ -22,5 +23,8 @@ */ interface UserPassportInterface extends PassportInterface { + /** + * @throws AuthenticationException when the user cannot be found + */ public function getUser(): UserInterface; } diff --git a/src/Symfony/Component/Security/Http/EventListener/PasswordMigratingListener.php b/src/Symfony/Component/Security/Http/EventListener/PasswordMigratingListener.php index 81d4c0483861..6b23a2367aa6 100644 --- a/src/Symfony/Component/Security/Http/EventListener/PasswordMigratingListener.php +++ b/src/Symfony/Component/Security/Http/EventListener/PasswordMigratingListener.php @@ -50,6 +50,10 @@ public function onLoginSuccess(LoginSuccessEvent $event): void } $user = $passport->getUser(); + if (null === $user->getPassword()) { + return; + } + $passwordEncoder = $this->encoderFactory->getEncoder($user); if (!$passwordEncoder->needsRehash($user->getPassword())) { return; diff --git a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php index 66b54d325b11..3f870cf8e6f8 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php @@ -69,7 +69,7 @@ public function __construct(TokenStorageInterface $tokenStorage, iterable $userP $this->logger = $logger; $this->dispatcher = class_exists(Event::class) ? LegacyEventDispatcherProxy::decorate($dispatcher) : $dispatcher; - $this->trustResolver = $trustResolver ?: new AuthenticationTrustResolver(AnonymousToken::class, RememberMeToken::class); + $this->trustResolver = $trustResolver ?? new AuthenticationTrustResolver(AnonymousToken::class, RememberMeToken::class); $this->sessionTrackerEnabler = $sessionTrackerEnabler; } diff --git a/src/Symfony/Component/Security/Http/LoginLink/ExpiredLoginLinkStorage.php b/src/Symfony/Component/Security/Http/LoginLink/ExpiredLoginLinkStorage.php index 8e3b4ba7db77..1a7dbd68fba2 100644 --- a/src/Symfony/Component/Security/Http/LoginLink/ExpiredLoginLinkStorage.php +++ b/src/Symfony/Component/Security/Http/LoginLink/ExpiredLoginLinkStorage.php @@ -14,6 +14,8 @@ use Psr\Cache\CacheItemPoolInterface; /** + * @experimental in 5.2 + * * @final */ class ExpiredLoginLinkStorage diff --git a/src/Symfony/Component/Security/Http/Tests/EventListener/PasswordMigratingListenerTest.php b/src/Symfony/Component/Security/Http/Tests/EventListener/PasswordMigratingListenerTest.php index 285472f03713..2d925fa220dc 100644 --- a/src/Symfony/Component/Security/Http/Tests/EventListener/PasswordMigratingListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/EventListener/PasswordMigratingListenerTest.php @@ -108,6 +108,16 @@ public function testUpgradeWithoutUpgrader() $this->listener->onLoginSuccess($event); } + public function testUserWithoutPassword() + { + $this->user = new User('test', null); + + $this->encoderFactory->expects($this->never())->method('getEncoder'); + + $event = $this->createEvent(new SelfValidatingPassport(new UserBadge('test', function () { return $this->user; }), [new PasswordUpgradeBadge('pa$$word')])); + $this->listener->onLoginSuccess($event); + } + private function createPasswordUpgrader() { return $this->createMock(MigratingUserProvider::class); diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php index c2980c293ab0..016c429e4c23 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php @@ -417,7 +417,7 @@ protected function runSessionOnKernelResponse($newToken, $original = null) private function handleEventWithPreviousSession($userProviders, UserInterface $user = null, RememberMeServicesInterface $rememberMeServices = null) { - $tokenUser = $user ?: new User('foo', 'bar'); + $tokenUser = $user ?? new User('foo', 'bar'); $session = new Session(new MockArraySessionStorage()); $session->set('_security_context_key', serialize(new UsernamePasswordToken($tokenUser, '', 'context_key', ['ROLE_USER']))); diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php index 3c6020b27d62..b6c437a0333b 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php @@ -184,7 +184,7 @@ public function getAccessDeniedExceptionProvider() private function createEntryPoint(Response $response = null) { $entryPoint = $this->createMock(AuthenticationEntryPointInterface::class); - $entryPoint->expects($this->once())->method('start')->willReturn($response ?: new Response('OK')); + $entryPoint->expects($this->once())->method('start')->willReturn($response ?? new Response('OK')); return $entryPoint; } @@ -209,9 +209,9 @@ private function createEvent(\Exception $exception, $kernel = null) private function createExceptionListener(TokenStorageInterface $tokenStorage = null, AuthenticationTrustResolverInterface $trustResolver = null, HttpUtils $httpUtils = null, AuthenticationEntryPointInterface $authenticationEntryPoint = null, $errorPage = null, AccessDeniedHandlerInterface $accessDeniedHandler = null) { return new ExceptionListener( - $tokenStorage ?: $this->createMock(TokenStorageInterface::class), - $trustResolver ?: $this->createMock(AuthenticationTrustResolverInterface::class), - $httpUtils ?: $this->createMock(HttpUtils::class), + $tokenStorage ?? $this->createMock(TokenStorageInterface::class), + $trustResolver ?? $this->createMock(AuthenticationTrustResolverInterface::class), + $httpUtils ?? $this->createMock(HttpUtils::class), 'key', $authenticationEntryPoint, $errorPage, diff --git a/src/Symfony/Component/Serializer/Encoder/JsonEncoder.php b/src/Symfony/Component/Serializer/Encoder/JsonEncoder.php index 386fab92072f..cf4a89ca1ab5 100644 --- a/src/Symfony/Component/Serializer/Encoder/JsonEncoder.php +++ b/src/Symfony/Component/Serializer/Encoder/JsonEncoder.php @@ -25,8 +25,8 @@ class JsonEncoder implements EncoderInterface, DecoderInterface public function __construct(JsonEncode $encodingImpl = null, JsonDecode $decodingImpl = null) { - $this->encodingImpl = $encodingImpl ?: new JsonEncode(); - $this->decodingImpl = $decodingImpl ?: new JsonDecode([JsonDecode::ASSOCIATIVE => true]); + $this->encodingImpl = $encodingImpl ?? new JsonEncode(); + $this->decodingImpl = $decodingImpl ?? new JsonDecode([JsonDecode::ASSOCIATIVE => true]); } /** diff --git a/src/Symfony/Component/Serializer/Encoder/YamlEncoder.php b/src/Symfony/Component/Serializer/Encoder/YamlEncoder.php index a969b9594d94..c688c228330d 100644 --- a/src/Symfony/Component/Serializer/Encoder/YamlEncoder.php +++ b/src/Symfony/Component/Serializer/Encoder/YamlEncoder.php @@ -46,8 +46,8 @@ public function __construct(Dumper $dumper = null, Parser $parser = null, array throw new RuntimeException('The YamlEncoder class requires the "Yaml" component. Install "symfony/yaml" to use it.'); } - $this->dumper = $dumper ?: new Dumper(); - $this->parser = $parser ?: new Parser(); + $this->dumper = $dumper ?? new Dumper(); + $this->parser = $parser ?? new Parser(); $this->defaultContext = array_merge($this->defaultContext, $defaultContext); } diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index 4a03ab851a3a..6c62e39c4ae7 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -390,6 +390,8 @@ protected function instantiateObject(array &$data, string $class, array &$contex $params[] = $this->defaultContext[self::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class][$key]; } elseif ($constructorParameter->isDefaultValueAvailable()) { $params[] = $constructorParameter->getDefaultValue(); + } elseif ($constructorParameter->hasType() && $constructorParameter->getType()->allowsNull()) { + $params[] = null; } else { throw new MissingConstructorArgumentsException(sprintf('Cannot create an instance of "%s" from serialized data because its constructor requires parameter "%s" to be present.', $class, $constructorParameter->name)); } diff --git a/src/Symfony/Component/Serializer/Normalizer/CustomNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/CustomNormalizer.php index 6bf6339372d5..44ad1771b624 100644 --- a/src/Symfony/Component/Serializer/Normalizer/CustomNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/CustomNormalizer.php @@ -35,7 +35,7 @@ public function normalize($object, string $format = null, array $context = []) */ public function denormalize($data, string $type, string $format = null, array $context = []) { - $object = $this->extractObjectToPopulate($type, $context) ?: new $type(); + $object = $this->extractObjectToPopulate($type, $context) ?? new $type(); $object->denormalize($this->serializer, $data, $format, $context); return $object; diff --git a/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php index 02cb11f44b3c..aacce5092428 100644 --- a/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/GetSetMethodNormalizer.php @@ -61,7 +61,7 @@ public function hasCacheableSupportsMethod(): bool } /** - * Checks if the given class has any get{Property} method. + * Checks if the given class has any getter method. */ private function supports(string $class): bool { @@ -77,7 +77,7 @@ private function supports(string $class): bool } /** - * Checks if a method's name is get.* or is.*, and can be called without parameters. + * Checks if a method's name matches /^(get|is|has).+$/ and can be called non-statically without parameters. */ private function isGetMethod(\ReflectionMethod $method): bool { diff --git a/src/Symfony/Component/Serializer/Serializer.php b/src/Symfony/Component/Serializer/Serializer.php index 6414caf90047..686e831a7336 100644 --- a/src/Symfony/Component/Serializer/Serializer.php +++ b/src/Symfony/Component/Serializer/Serializer.php @@ -69,8 +69,8 @@ class Serializer implements SerializerInterface, ContextAwareNormalizerInterface private $normalizerCache = []; /** - * @param (NormalizerInterface|DenormalizerInterface)[] $normalizers - * @param (EncoderInterface|DecoderInterface)[] $encoders + * @param array $normalizers + * @param array $encoders */ public function __construct(array $normalizers = [], array $encoders = []) { diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/NullableOptionalConstructorArgumentDummy.php b/src/Symfony/Component/Serializer/Tests/Fixtures/NullableOptionalConstructorArgumentDummy.php new file mode 100644 index 000000000000..45b65adbc319 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/NullableOptionalConstructorArgumentDummy.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +class NullableOptionalConstructorArgumentDummy +{ + private $foo; + + public function __construct(?\stdClass $foo) + { + $this->foo = $foo; + } + + public function setFoo($foo) + { + $this->foo = 'this setter should not be called when using the constructor argument'; + } + + public function getFoo() + { + return $this->foo; + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php index d65e1f10d0fc..ddd4040ae3c8 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractNormalizerTest.php @@ -19,6 +19,7 @@ use Symfony\Component\Serializer\Tests\Fixtures\Annotations\IgnoreDummy; use Symfony\Component\Serializer\Tests\Fixtures\Dummy; use Symfony\Component\Serializer\Tests\Fixtures\NullableConstructorArgumentDummy; +use Symfony\Component\Serializer\Tests\Fixtures\NullableOptionalConstructorArgumentDummy; use Symfony\Component\Serializer\Tests\Fixtures\StaticConstructorDummy; use Symfony\Component\Serializer\Tests\Fixtures\StaticConstructorNormalizer; use Symfony\Component\Serializer\Tests\Fixtures\VariadicConstructorTypedArgsDummy; @@ -125,6 +126,22 @@ public function testObjectWithStaticConstructor() } public function testObjectWithNullableConstructorArgument() + { + $normalizer = new ObjectNormalizer(); + $dummy = $normalizer->denormalize(['foo' => null], NullableOptionalConstructorArgumentDummy::class); + + $this->assertNull($dummy->getFoo()); + } + + public function testObjectWithNullableConstructorArgumentWithoutInput() + { + $normalizer = new ObjectNormalizer(); + $dummy = $normalizer->denormalize([], NullableOptionalConstructorArgumentDummy::class); + + $this->assertNull($dummy->getFoo()); + } + + public function testObjectWithNullableNonOptionalConstructorArgument() { $normalizer = new ObjectNormalizer(); $dummy = $normalizer->denormalize(['foo' => null], NullableConstructorArgumentDummy::class); @@ -132,6 +149,14 @@ public function testObjectWithNullableConstructorArgument() $this->assertNull($dummy->getFoo()); } + public function testObjectWithNullableNonOptionalConstructorArgumentWithoutInput() + { + $normalizer = new ObjectNormalizer(); + $dummy = $normalizer->denormalize([], NullableConstructorArgumentDummy::class); + + $this->assertNull($dummy->getFoo()); + } + /** * @dataProvider getNormalizer */ diff --git a/src/Symfony/Component/Serializer/composer.json b/src/Symfony/Component/Serializer/composer.json index be930136ddfb..85ff9bfe9d89 100644 --- a/src/Symfony/Component/Serializer/composer.json +++ b/src/Symfony/Component/Serializer/composer.json @@ -55,8 +55,6 @@ "symfony/config": "For using the XML mapping loader.", "symfony/property-access": "For using the ObjectNormalizer.", "symfony/mime": "For using a MIME type guesser within the DataUriNormalizer.", - "doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.", - "doctrine/cache": "For using the default cached annotation reader and metadata cache.", "symfony/var-exporter": "For using the metadata compiler." }, "autoload": { diff --git a/src/Symfony/Component/Stopwatch/CHANGELOG.md b/src/Symfony/Component/Stopwatch/CHANGELOG.md index 14b7dc6dd5ef..e047001f0e4c 100644 --- a/src/Symfony/Component/Stopwatch/CHANGELOG.md +++ b/src/Symfony/Component/Stopwatch/CHANGELOG.md @@ -1,6 +1,11 @@ CHANGELOG ========= +5.2 +--- + +* Add `name` argument to the `StopWatchEvent` constructor, accessible via a new `StopwatchEvent::getName()` + 5.0.0 ----- diff --git a/src/Symfony/Component/Translation/PluralizationRules.php b/src/Symfony/Component/Translation/PluralizationRules.php deleted file mode 100644 index 2a46ce094f43..000000000000 --- a/src/Symfony/Component/Translation/PluralizationRules.php +++ /dev/null @@ -1,220 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Translation; - -/** - * Returns the plural rules for a given locale. - * - * @author Fabien Potencier - * - * @deprecated since Symfony 4.2, use IdentityTranslator instead - */ -class PluralizationRules -{ - private static $rules = []; - - /** - * Returns the plural position to use for the given locale and number. - * - * @param float $number The number - * @param string $locale The locale - * - * @return int The plural position - */ - public static function get($number, $locale/*, bool $triggerDeprecation = true*/) - { - $number = abs($number); - - if (3 > \func_num_args() || func_get_arg(2)) { - @trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.2.', __CLASS__), \E_USER_DEPRECATED); - } - - if ('pt_BR' === $locale) { - // temporary set a locale for brazilian - $locale = 'xbr'; - } - - if (\strlen($locale) > 3) { - $locale = substr($locale, 0, -\strlen(strrchr($locale, '_'))); - } - - if (isset(self::$rules[$locale])) { - $return = self::$rules[$locale]($number); - - if (!\is_int($return) || $return < 0) { - return 0; - } - - return $return; - } - - /* - * The plural rules are derived from code of the Zend Framework (2010-09-25), - * which is subject to the new BSD license (http://framework.zend.com/license/new-bsd). - * Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com) - */ - switch ($locale) { - case 'az': - case 'bo': - case 'dz': - case 'id': - case 'ja': - case 'jv': - case 'ka': - case 'km': - case 'kn': - case 'ko': - case 'ms': - case 'th': - case 'tr': - case 'vi': - case 'zh': - return 0; - - case 'af': - case 'bn': - case 'bg': - case 'ca': - case 'da': - case 'de': - case 'el': - case 'en': - case 'eo': - case 'es': - case 'et': - case 'eu': - case 'fa': - case 'fi': - case 'fo': - case 'fur': - case 'fy': - case 'gl': - case 'gu': - case 'ha': - case 'he': - case 'hu': - case 'is': - case 'it': - case 'ku': - case 'lb': - case 'ml': - case 'mn': - case 'mr': - case 'nah': - case 'nb': - case 'ne': - case 'nl': - case 'nn': - case 'no': - case 'oc': - case 'om': - case 'or': - case 'pa': - case 'pap': - case 'ps': - case 'pt': - case 'so': - case 'sq': - case 'sv': - case 'sw': - case 'ta': - case 'te': - case 'tk': - case 'ur': - case 'zu': - return (1 == $number) ? 0 : 1; - - case 'am': - case 'bh': - case 'fil': - case 'fr': - case 'gun': - case 'hi': - case 'hy': - case 'ln': - case 'mg': - case 'nso': - case 'xbr': - case 'ti': - case 'wa': - return ($number < 2) ? 0 : 1; - - case 'be': - case 'bs': - case 'hr': - case 'ru': - case 'sh': - case 'sr': - case 'uk': - return ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2); - - case 'cs': - case 'sk': - return (1 == $number) ? 0 : ((($number >= 2) && ($number <= 4)) ? 1 : 2); - - case 'ga': - return (1 == $number) ? 0 : ((2 == $number) ? 1 : 2); - - case 'lt': - return ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2); - - case 'sl': - return (1 == $number % 100) ? 0 : ((2 == $number % 100) ? 1 : (((3 == $number % 100) || (4 == $number % 100)) ? 2 : 3)); - - case 'mk': - return (1 == $number % 10) ? 0 : 1; - - case 'mt': - return (1 == $number) ? 0 : (((0 == $number) || (($number % 100 > 1) && ($number % 100 < 11))) ? 1 : ((($number % 100 > 10) && ($number % 100 < 20)) ? 2 : 3)); - - case 'lv': - return (0 == $number) ? 0 : (((1 == $number % 10) && (11 != $number % 100)) ? 1 : 2); - - case 'pl': - return (1 == $number) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 12) || ($number % 100 > 14))) ? 1 : 2); - - case 'cy': - return (1 == $number) ? 0 : ((2 == $number) ? 1 : (((8 == $number) || (11 == $number)) ? 2 : 3)); - - case 'ro': - return (1 == $number) ? 0 : (((0 == $number) || (($number % 100 > 0) && ($number % 100 < 20))) ? 1 : 2); - - case 'ar': - return (0 == $number) ? 0 : ((1 == $number) ? 1 : ((2 == $number) ? 2 : ((($number % 100 >= 3) && ($number % 100 <= 10)) ? 3 : ((($number % 100 >= 11) && ($number % 100 <= 99)) ? 4 : 5)))); - - default: - return 0; - } - } - - /** - * Overrides the default plural rule for a given locale. - * - * @param callable $rule A PHP callable - * @param string $locale The locale - */ - public static function set(callable $rule, $locale) - { - @trigger_error(sprintf('The "%s" class is deprecated since Symfony 4.2.', __CLASS__), \E_USER_DEPRECATED); - - if ('pt_BR' === $locale) { - // temporary set a locale for brazilian - $locale = 'xbr'; - } - - if (\strlen($locale) > 3) { - $locale = substr($locale, 0, -\strlen(strrchr($locale, '_'))); - } - - self::$rules[$locale] = $rule; - } -} diff --git a/src/Symfony/Component/Validator/Constraints/IsbnValidator.php b/src/Symfony/Component/Validator/Constraints/IsbnValidator.php index e8e54eb6369b..78671004984b 100644 --- a/src/Symfony/Component/Validator/Constraints/IsbnValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IsbnValidator.php @@ -163,8 +163,7 @@ protected function validateIsbn13($isbn) } for ($i = 1; $i < 12; $i += 2) { - $checkSum += $isbn[$i] - * 3; + $checkSum += $isbn[$i] * 3; } return 0 === $checkSum % 10 ? true : Isbn::CHECKSUM_FAILED_ERROR; diff --git a/src/Symfony/Component/Validator/Constraints/IssnValidator.php b/src/Symfony/Component/Validator/Constraints/IssnValidator.php index 8766b077ba3b..aa83201cdabc 100644 --- a/src/Symfony/Component/Validator/Constraints/IssnValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IssnValidator.php @@ -114,10 +114,7 @@ public function validate($value, Constraint $constraint) } // Calculate a checksum. "X" equals 10. - $checkSum = 'X' === $canonical[7] - || 'x' === $canonical[7] - ? 10 - : $canonical[7]; + $checkSum = 'X' === $canonical[7] || 'x' === $canonical[7] ? 10 : $canonical[7]; for ($i = 0; $i < 7; ++$i) { // Multiply the first digit by 8, the second by 7, etc. diff --git a/src/Symfony/Component/Validator/Constraints/Regex.php b/src/Symfony/Component/Validator/Constraints/Regex.php index 35a1806039e3..72f691461637 100644 --- a/src/Symfony/Component/Validator/Constraints/Regex.php +++ b/src/Symfony/Component/Validator/Constraints/Regex.php @@ -89,9 +89,6 @@ public function getRequiredOptions() * Example: /^[a-z]+$/ would be converted to [a-z]+ * However, if options are specified, it cannot be converted. * - * Pattern is also ignored if match=false since the pattern should - * then be reversed before application. - * * @see http://dev.w3.org/html5/spec/single-page.html#the-pattern-attribute * * @return string|null diff --git a/src/Symfony/Component/Validator/Mapping/ClassMetadata.php b/src/Symfony/Component/Validator/Mapping/ClassMetadata.php index 7aa90fe492c0..7d6dc97b42db 100644 --- a/src/Symfony/Component/Validator/Mapping/ClassMetadata.php +++ b/src/Symfony/Component/Validator/Mapping/ClassMetadata.php @@ -264,7 +264,7 @@ public function addPropertyConstraints(string $property, array $constraints) * Adds a constraint to the getter of the given property. * * The name of the getter is assumed to be the name of the property with an - * uppercased first letter and either the prefix "get" or "is". + * uppercased first letter and the prefix "get", "is" or "has". * * @return $this */ diff --git a/src/Symfony/Component/Validator/Mapping/GetterMetadata.php b/src/Symfony/Component/Validator/Mapping/GetterMetadata.php index c840d975dfed..0be3329342b2 100644 --- a/src/Symfony/Component/Validator/Mapping/GetterMetadata.php +++ b/src/Symfony/Component/Validator/Mapping/GetterMetadata.php @@ -18,7 +18,7 @@ * method. * * A property getter is any method that is equal to the property's name, - * prefixed with either "get" or "is". That method will be used to access the + * prefixed with "get", "is" or "has". That method will be used to access the * property's value. * * The getter will be invoked by reflection, so the access of private and diff --git a/src/Symfony/Component/Validator/Validator/ContextualValidatorInterface.php b/src/Symfony/Component/Validator/Validator/ContextualValidatorInterface.php index 68cd36eac98b..0a6afadf10c3 100644 --- a/src/Symfony/Component/Validator/Validator/ContextualValidatorInterface.php +++ b/src/Symfony/Component/Validator/Validator/ContextualValidatorInterface.php @@ -40,9 +40,9 @@ public function atPath(string $path); * If no constraint is passed, the constraint * {@link \Symfony\Component\Validator\Constraints\Valid} is assumed. * - * @param mixed $value The value to validate - * @param Constraint|Constraint[] $constraints The constraint(s) to validate against - * @param string|GroupSequence|(string|GroupSequence)[]|null $groups The validation groups to validate. If none is given, "Default" is assumed + * @param mixed $value The value to validate + * @param Constraint|Constraint[] $constraints The constraint(s) to validate against + * @param string|GroupSequence|array|null $groups The validation groups to validate. If none is given, "Default" is assumed * * @return $this */ @@ -52,9 +52,9 @@ public function validate($value, $constraints = null, $groups = null); * Validates a property of an object against the constraints specified * for this property. * - * @param object $object The object - * @param string $propertyName The name of the validated property - * @param string|GroupSequence|(string|GroupSequence)[]|null $groups The validation groups to validate. If none is given, "Default" is assumed + * @param object $object The object + * @param string $propertyName The name of the validated property + * @param string|GroupSequence|array|null $groups The validation groups to validate. If none is given, "Default" is assumed * * @return $this */ @@ -64,10 +64,10 @@ public function validateProperty($object, string $propertyName, $groups = null); * Validates a value against the constraints specified for an object's * property. * - * @param object|string $objectOrClass The object or its class name - * @param string $propertyName The name of the property - * @param mixed $value The value to validate against the property's constraints - * @param string|GroupSequence|(string|GroupSequence)[]|null $groups The validation groups to validate. If none is given, "Default" is assumed + * @param object|string $objectOrClass The object or its class name + * @param string $propertyName The name of the property + * @param mixed $value The value to validate against the property's constraints + * @param string|GroupSequence|array|null $groups The validation groups to validate. If none is given, "Default" is assumed * * @return $this */ diff --git a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php index 7920a07c8d9f..f9dc81a23e8c 100644 --- a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php +++ b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php @@ -271,9 +271,9 @@ public function getViolations() /** * Normalizes the given group or list of groups to an array. * - * @param string|GroupSequence|(string|GroupSequence)[] $groups The groups to normalize + * @param string|GroupSequence|array $groups The groups to normalize * - * @return (string|GroupSequence)[] A group array + * @return array A group array */ protected function normalizeGroups($groups) { diff --git a/src/Symfony/Component/Validator/Validator/ValidatorInterface.php b/src/Symfony/Component/Validator/Validator/ValidatorInterface.php index 23356638be80..f1d76df5336c 100644 --- a/src/Symfony/Component/Validator/Validator/ValidatorInterface.php +++ b/src/Symfony/Component/Validator/Validator/ValidatorInterface.php @@ -30,9 +30,9 @@ interface ValidatorInterface extends MetadataFactoryInterface * If no constraint is passed, the constraint * {@link \Symfony\Component\Validator\Constraints\Valid} is assumed. * - * @param mixed $value The value to validate - * @param Constraint|Constraint[] $constraints The constraint(s) to validate against - * @param string|GroupSequence|(string|GroupSequence)[]|null $groups The validation groups to validate. If none is given, "Default" is assumed + * @param mixed $value The value to validate + * @param Constraint|Constraint[] $constraints The constraint(s) to validate against + * @param string|GroupSequence|array|null $groups The validation groups to validate. If none is given, "Default" is assumed * * @return ConstraintViolationListInterface A list of constraint violations * If the list is empty, validation @@ -44,9 +44,9 @@ public function validate($value, $constraints = null, $groups = null); * Validates a property of an object against the constraints specified * for this property. * - * @param object $object The object - * @param string $propertyName The name of the validated property - * @param string|GroupSequence|(string|GroupSequence)[]|null $groups The validation groups to validate. If none is given, "Default" is assumed + * @param object $object The object + * @param string $propertyName The name of the validated property + * @param string|GroupSequence|array|null $groups The validation groups to validate. If none is given, "Default" is assumed * * @return ConstraintViolationListInterface A list of constraint violations * If the list is empty, validation @@ -58,10 +58,10 @@ public function validateProperty($object, string $propertyName, $groups = null); * Validates a value against the constraints specified for an object's * property. * - * @param object|string $objectOrClass The object or its class name - * @param string $propertyName The name of the property - * @param mixed $value The value to validate against the property's constraints - * @param string|GroupSequence|(string|GroupSequence)[]|null $groups The validation groups to validate. If none is given, "Default" is assumed + * @param object|string $objectOrClass The object or its class name + * @param string $propertyName The name of the property + * @param mixed $value The value to validate against the property's constraints + * @param string|GroupSequence|array|null $groups The validation groups to validate. If none is given, "Default" is assumed * * @return ConstraintViolationListInterface A list of constraint violations * If the list is empty, validation diff --git a/src/Symfony/Component/Validator/ValidatorBuilder.php b/src/Symfony/Component/Validator/ValidatorBuilder.php index 336c4f7be25e..8b363b553904 100644 --- a/src/Symfony/Component/Validator/ValidatorBuilder.php +++ b/src/Symfony/Component/Validator/ValidatorBuilder.php @@ -407,7 +407,7 @@ public function getValidator() $metadataFactory = new LazyLoadingMetadataFactory($loader, $this->mappingCache); } - $validatorFactory = $this->validatorFactory ?: new ConstraintValidatorFactory(); + $validatorFactory = $this->validatorFactory ?? new ConstraintValidatorFactory(); $translator = $this->translator; if (null === $translator) { diff --git a/src/Symfony/Component/Validator/composer.json b/src/Symfony/Component/Validator/composer.json index acf7f485f0ef..054b1e27be84 100644 --- a/src/Symfony/Component/Validator/composer.json +++ b/src/Symfony/Component/Validator/composer.json @@ -56,8 +56,6 @@ }, "suggest": { "psr/cache-implementation": "For using the mapping cache.", - "doctrine/annotations": "For using the annotation mapping. You will also need doctrine/cache.", - "doctrine/cache": "For using the default cached annotation reader.", "symfony/http-foundation": "", "symfony/intl": "", "symfony/translation": "For translating validation errors.", diff --git a/src/Symfony/Component/VarDumper/Command/ServerDumpCommand.php b/src/Symfony/Component/VarDumper/Command/ServerDumpCommand.php index 3ec8353aff6f..b66301b52d21 100644 --- a/src/Symfony/Component/VarDumper/Command/ServerDumpCommand.php +++ b/src/Symfony/Component/VarDumper/Command/ServerDumpCommand.php @@ -95,5 +95,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->server->listen(function (Data $data, array $context, int $clientId) use ($descriptor, $io) { $descriptor->describe($io, $data, $context, $clientId); }); + + return 0; } } diff --git a/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php b/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php index b47296321677..d9f55eb46c84 100644 --- a/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Cloner/VarClonerTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\VarDumper\Cloner\VarCloner; use Symfony\Component\VarDumper\Tests\Fixtures\Php74; +use Symfony\Component\VarDumper\Tests\Fixtures\Php81Enums; /** * @author Nicolas Grekas @@ -428,7 +429,7 @@ public function testCaster() [attr] => Array ( [file] => %a%eVarClonerTest.php - [line] => 21 + [line] => 22 ) ) @@ -526,6 +527,108 @@ public function testPhp74() ) +EOTXT; + $this->assertStringMatchesFormat($expected, print_r($clone, true)); + } + + /** + * @requires PHP 8.1 + */ + public function testPhp81Enums() + { + $data = new Php81Enums(); + + $cloner = new VarCloner(); + $clone = $cloner->cloneVar($data); + + $expected = <<<'EOTXT' +Symfony\Component\VarDumper\Cloner\Data Object +( + [data:Symfony\Component\VarDumper\Cloner\Data:private] => Array + ( + [0] => Array + ( + [0] => Symfony\Component\VarDumper\Cloner\Stub Object + ( + [type] => 4 + [class] => Symfony\Component\VarDumper\Tests\Fixtures\Php81Enums + [value] => + [cut] => 0 + [handle] => %i + [refCount] => 0 + [position] => 1 + [attr] => Array + ( + [file] => %s + [line] => 5 + ) + + ) + + ) + + [1] => Array + ( + [e1] => Symfony\Component\VarDumper\Cloner\Stub Object + ( + [type] => 4 + [class] => Symfony\Component\VarDumper\Tests\Fixtures\UnitEnumFixture + [value] => + [cut] => 0 + [handle] => %i + [refCount] => 0 + [position] => 2 + [attr] => Array + ( + [file] => %s + [line] => 5 + ) + + ) + + [e2] => Symfony\Component\VarDumper\Cloner\Stub Object + ( + [type] => 4 + [class] => Symfony\Component\VarDumper\Tests\Fixtures\BackedEnumFixture + [value] => + [cut] => 0 + [handle] => %i + [refCount] => 0 + [position] => 3 + [attr] => Array + ( + [file] => %s + [line] => 5 + ) + + ) + + ) + + [2] => Array + ( + [name] => Hearts + ) + + [3] => Array + ( + [name] => Diamonds + [value] => D + ) + + ) + + [position:Symfony\Component\VarDumper\Cloner\Data:private] => 0 + [key:Symfony\Component\VarDumper\Cloner\Data:private] => 0 + [maxDepth:Symfony\Component\VarDumper\Cloner\Data:private] => 20 + [maxItemsPerDepth:Symfony\Component\VarDumper\Cloner\Data:private] => -1 + [useRefHandles:Symfony\Component\VarDumper\Cloner\Data:private] => -1 + [context:Symfony\Component\VarDumper\Cloner\Data:private] => Array + ( + ) + +) + EOTXT; $this->assertStringMatchesFormat($expected, print_r($clone, true)); } diff --git a/src/Symfony/Component/VarDumper/Tests/Fixtures/BackedEnumFixture.php b/src/Symfony/Component/VarDumper/Tests/Fixtures/BackedEnumFixture.php new file mode 100644 index 000000000000..79c31431d0bf --- /dev/null +++ b/src/Symfony/Component/VarDumper/Tests/Fixtures/BackedEnumFixture.php @@ -0,0 +1,10 @@ +e1 = UnitEnumFixture::Hearts; + $this->e2 = BackedEnumFixture::Diamonds; + } +} diff --git a/src/Symfony/Component/VarDumper/Tests/Fixtures/UnitEnumFixture.php b/src/Symfony/Component/VarDumper/Tests/Fixtures/UnitEnumFixture.php new file mode 100644 index 000000000000..4a054b640f76 --- /dev/null +++ b/src/Symfony/Component/VarDumper/Tests/Fixtures/UnitEnumFixture.php @@ -0,0 +1,10 @@ +__serialize())) { - throw new \Typerror($class.'::__serialize() must return an array'); + throw new \TypeError($class.'::__serialize() must return an array'); } goto prepare_value; diff --git a/src/Symfony/Component/Workflow/Definition.php b/src/Symfony/Component/Workflow/Definition.php index 210e7569579b..123353861601 100644 --- a/src/Symfony/Component/Workflow/Definition.php +++ b/src/Symfony/Component/Workflow/Definition.php @@ -44,7 +44,7 @@ public function __construct(array $places, array $transitions, $initialPlaces = $this->setInitialPlaces($initialPlaces); - $this->metadataStore = $metadataStore ?: new InMemoryMetadataStore(); + $this->metadataStore = $metadataStore ?? new InMemoryMetadataStore(); } /** diff --git a/src/Symfony/Component/Workflow/Metadata/InMemoryMetadataStore.php b/src/Symfony/Component/Workflow/Metadata/InMemoryMetadataStore.php index 5e8b9c4f78ec..a1553885b34d 100644 --- a/src/Symfony/Component/Workflow/Metadata/InMemoryMetadataStore.php +++ b/src/Symfony/Component/Workflow/Metadata/InMemoryMetadataStore.php @@ -28,7 +28,7 @@ public function __construct(array $workflowMetadata = [], array $placesMetadata { $this->workflowMetadata = $workflowMetadata; $this->placesMetadata = $placesMetadata; - $this->transitionsMetadata = $transitionsMetadata ?: new \SplObjectStorage(); + $this->transitionsMetadata = $transitionsMetadata ?? new \SplObjectStorage(); } public function getWorkflowMetadata(): array diff --git a/src/Symfony/Component/Workflow/StateMachine.php b/src/Symfony/Component/Workflow/StateMachine.php index aa4f024b9064..7bd912b34a6c 100644 --- a/src/Symfony/Component/Workflow/StateMachine.php +++ b/src/Symfony/Component/Workflow/StateMachine.php @@ -22,6 +22,6 @@ class StateMachine extends Workflow { public function __construct(Definition $definition, MarkingStoreInterface $markingStore = null, EventDispatcherInterface $dispatcher = null, string $name = 'unnamed') { - parent::__construct($definition, $markingStore ?: new MethodMarkingStore(true), $dispatcher, $name); + parent::__construct($definition, $markingStore ?? new MethodMarkingStore(true), $dispatcher, $name); } } diff --git a/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php b/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php index 4d6741a2ea1c..bc6ec0d8a1b0 100644 --- a/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php +++ b/src/Symfony/Component/Workflow/Tests/EventListener/GuardListenerTest.php @@ -136,7 +136,7 @@ public function testGuardExpressionBlocks() private function createEvent(Transition $transition = null) { $subject = new Subject(); - $transition = $transition ?: new Transition('name', 'from', 'to'); + $transition = $transition ?? new Transition('name', 'from', 'to'); $workflow = $this->createMock(WorkflowInterface::class); diff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.php index 00abecd4f153..5b45c1f7c77c 100644 --- a/src/Symfony/Component/Workflow/Workflow.php +++ b/src/Symfony/Component/Workflow/Workflow.php @@ -70,7 +70,7 @@ class Workflow implements WorkflowInterface public function __construct(Definition $definition, MarkingStoreInterface $markingStore = null, EventDispatcherInterface $dispatcher = null, string $name = 'unnamed', array $eventsToDispatch = null) { $this->definition = $definition; - $this->markingStore = $markingStore ?: new MethodMarkingStore(); + $this->markingStore = $markingStore ?? new MethodMarkingStore(); $this->dispatcher = $dispatcher; $this->name = $name; $this->eventsToDispatch = $eventsToDispatch; diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index fe10287877f3..70f4c35c44a9 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -58,7 +58,7 @@ public static function initialize(int $flags, int $parsedLineNumber = null, stri * * @throws ParseException */ - public static function parse(string $value = null, int $flags = 0, array $references = []) + public static function parse(string $value = null, int $flags = 0, array &$references = []) { self::initialize($flags); @@ -267,7 +267,7 @@ private static function dumpNull(int $flags): string * * @throws ParseException When malformed inline YAML string is parsed */ - public static function parseScalar(string $scalar, int $flags = 0, array $delimiters = null, int &$i = 0, bool $evaluate = true, array $references = []) + public static function parseScalar(string $scalar, int $flags = 0, array $delimiters = null, int &$i = 0, bool $evaluate = true, array &$references = []) { if (\in_array($scalar[$i], ['"', "'"], true)) { // quoted scalar @@ -343,7 +343,7 @@ private static function parseQuotedScalar(string $scalar, int &$i): string * * @throws ParseException When malformed inline YAML string is parsed */ - private static function parseSequence(string $sequence, int $flags, int &$i = 0, array $references = []): array + private static function parseSequence(string $sequence, int $flags, int &$i = 0, array &$references = []): array { $output = []; $len = \strlen($sequence); @@ -385,6 +385,11 @@ private static function parseSequence(string $sequence, int $flags, int &$i = 0, } } + if (\is_string($value) && '' !== $value && '&' === $value[0] && Parser::preg_match(Parser::REFERENCE_PATTERN, $value, $matches)) { + $references[$matches['ref']] = $matches['value']; + $value = $matches['value']; + } + --$i; } @@ -407,7 +412,7 @@ private static function parseSequence(string $sequence, int $flags, int &$i = 0, * * @throws ParseException When malformed inline YAML string is parsed */ - private static function parseMapping(string $mapping, int $flags, int &$i = 0, array $references = []) + private static function parseMapping(string $mapping, int $flags, int &$i = 0, array &$references = []) { $output = []; $len = \strlen($mapping); @@ -433,14 +438,14 @@ private static function parseMapping(string $mapping, int $flags, int &$i = 0, a // key $offsetBeforeKeyParsing = $i; $isKeyQuoted = \in_array($mapping[$i], ['"', "'"], true); - $key = self::parseScalar($mapping, $flags, [':', ' '], $i, false, []); + $key = self::parseScalar($mapping, $flags, [':', ' '], $i, false); if ($offsetBeforeKeyParsing === $i) { throw new ParseException('Missing mapping key.', self::$parsedLineNumber + 1, $mapping); } if ('!php/const' === $key) { - $key .= ' '.self::parseScalar($mapping, $flags, [':'], $i, false, []); + $key .= ' '.self::parseScalar($mapping, $flags, [':'], $i, false); $key = self::evaluateScalar($key, $flags); } @@ -522,6 +527,11 @@ private static function parseMapping(string $mapping, int $flags, int &$i = 0, a if ('<<' === $key) { $output += $value; } elseif ($allowOverwrite || !isset($output[$key])) { + if (\is_string($value) && '' !== $value && '&' === $value[0] && Parser::preg_match(Parser::REFERENCE_PATTERN, $value, $matches)) { + $references[$matches['ref']] = $matches['value']; + $value = $matches['value']; + } + if (null !== $tag) { $output[$key] = new TaggedValue($tag, $value); } else { @@ -548,7 +558,7 @@ private static function parseMapping(string $mapping, int $flags, int &$i = 0, a * * @throws ParseException when object parsing support was disabled and the parser detected a PHP object or when a reference could not be resolved */ - private static function evaluateScalar(string $scalar, int $flags, array $references = []) + private static function evaluateScalar(string $scalar, int $flags, array &$references = []) { $scalar = trim($scalar); diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index 8a76b4880bbe..39485f21aaaa 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -25,6 +25,7 @@ class Parser { public const TAG_PATTERN = '(?P![\w!.\/:-]+)'; public const BLOCK_SCALAR_HEADER_PATTERN = '(?P\||>)(?P\+|\-|\d+|\+\d+|\-\d+|\d+\+|\d+\-)?(?P +#.*)?'; + public const REFERENCE_PATTERN = '#^&(?P[^ ]++) *+(?P.*)#u'; private $filename; private $offset = 0; @@ -161,7 +162,7 @@ private function doParse(string $value, int $flags) } $context = 'sequence'; - if (isset($values['value']) && '&' === $values['value'][0] && self::preg_match('#^&(?P[^ ]+) *(?P.*)#u', $values['value'], $matches)) { + if (isset($values['value']) && '&' === $values['value'][0] && self::preg_match(self::REFERENCE_PATTERN, $values['value'], $matches)) { $isRef = $matches['ref']; $this->refsBeingParsed[] = $isRef; $values['value'] = $matches['value']; @@ -172,7 +173,16 @@ private function doParse(string $value, int $flags) } // array - if (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) { + if (isset($values['value']) && 0 === strpos(ltrim($values['value'], ' '), '-')) { + // Inline first child + $currentLineNumber = $this->getRealCurrentLineNb(); + + $sequenceIndentation = \strlen($values['leadspaces']) + 1; + $sequenceYaml = substr($this->currentLine, $sequenceIndentation); + $sequenceYaml .= "\n".$this->getNextEmbedBlock($sequenceIndentation, true); + + $data[] = $this->parseBlock($currentLineNumber, rtrim($sequenceYaml), $flags); + } elseif (!isset($values['value']) || '' == trim($values['value'], ' ') || 0 === strpos(ltrim($values['value'], ' '), '#')) { $data[] = $this->parseBlock($this->getRealCurrentLineNb() + 1, $this->getNextEmbedBlock(null, true) ?? '', $flags); } elseif (null !== $subTag = $this->getLineTag(ltrim($values['value'], ' '), $flags)) { $data[] = new TaggedValue( @@ -203,7 +213,7 @@ private function doParse(string $value, int $flags) array_pop($this->refsBeingParsed); } } elseif ( - self::preg_match('#^(?P(?:![^\s]++\s++)?(?:'.Inline::REGEX_QUOTED_STRING.'|(?:!?!php/const:)?[^ \'"\[\{!].*?)) *\:( ++(?P.+))?$#u', rtrim($this->currentLine), $values) + self::preg_match('#^(?P(?:![^\s]++\s++)?(?:'.Inline::REGEX_QUOTED_STRING.'|(?:!?!php/const:)?[^ \'"\[\{!].*?)) *\:(( |\t)++(?P.+))?$#u', rtrim($this->currentLine), $values) && (false === strpos($values['key'], ' #') || \in_array($values['key'][0], ['"', "'"])) ) { if ($context && 'sequence' == $context) { @@ -221,7 +231,7 @@ private function doParse(string $value, int $flags) } if (!\is_string($key) && !\is_int($key)) { - throw new ParseException(sprintf('%s keys are not supported. Quote your evaluable mapping keys instead.', is_numeric($key) ? 'Numeric' : 'Non-string'), $this->getRealCurrentLineNb() + 1, $this->currentLine); + throw new ParseException((is_numeric($key) ? 'Numeric' : 'Non-string').' keys are not supported. Quote your evaluable mapping keys instead.', $this->getRealCurrentLineNb() + 1, $this->currentLine); } // Convert float keys to strings, to avoid being converted to integers by PHP @@ -236,7 +246,7 @@ private function doParse(string $value, int $flags) $refName = substr(rtrim($values['value']), 1); if (!\array_key_exists($refName, $this->refs)) { if (false !== $pos = array_search($refName, $this->refsBeingParsed, true)) { - throw new ParseException(sprintf('Circular reference [%s, %s] detected for reference "%s".', implode(', ', \array_slice($this->refsBeingParsed, $pos)), $refName, $refName), $this->currentLineNb + 1, $this->currentLine, $this->filename); + throw new ParseException(sprintf('Circular reference [%s] detected for reference "%s".', implode(', ', array_merge(\array_slice($this->refsBeingParsed, $pos), [$refName])), $refName), $this->currentLineNb + 1, $this->currentLine, $this->filename); } throw new ParseException(sprintf('Reference "%s" does not exist.', $refName), $this->getRealCurrentLineNb() + 1, $this->currentLine, $this->filename); @@ -290,7 +300,7 @@ private function doParse(string $value, int $flags) $data += $parsed; // array union } } - } elseif ('<<' !== $key && isset($values['value']) && '&' === $values['value'][0] && self::preg_match('#^&(?P[^ ]++) *+(?P.*)#u', $values['value'], $matches)) { + } elseif ('<<' !== $key && isset($values['value']) && '&' === $values['value'][0] && self::preg_match(self::REFERENCE_PATTERN, $values['value'], $matches)) { $isRef = $matches['ref']; $this->refsBeingParsed[] = $isRef; $values['value'] = $matches['value']; @@ -612,6 +622,7 @@ private function getNextEmbedBlock(int $indentation = null, bool $inSequence = f } $data = []; + if ($this->getCurrentLineIndentation() >= $newIndent) { $data[] = substr($this->currentLine, $newIndent); } elseif ($this->isCurrentLineEmpty() || $this->isCurrentLineComment()) { @@ -722,7 +733,7 @@ private function parseValue(string $value, int $flags, string $context) if (!\array_key_exists($value, $this->refs)) { if (false !== $pos = array_search($value, $this->refsBeingParsed, true)) { - throw new ParseException(sprintf('Circular reference [%s, %s] detected for reference "%s".', implode(', ', \array_slice($this->refsBeingParsed, $pos)), $value, $value), $this->currentLineNb + 1, $this->currentLine, $this->filename); + throw new ParseException(sprintf('Circular reference [%s] detected for reference "%s".', implode(', ', array_merge(\array_slice($this->refsBeingParsed, $pos), [$value])), $value), $this->currentLineNb + 1, $this->currentLine, $this->filename); } throw new ParseException(sprintf('Reference "%s" does not exist.', $value), $this->currentLineNb + 1, $this->currentLine, $this->filename); @@ -1215,7 +1226,7 @@ private function lexInlineQuotedString(int &$cursor = 0): string } } while ($this->moveToNextLine()); - throw new ParseException('Malformed inline YAML string'); + throw new ParseException('Malformed inline YAML string.'); } private function lexUnquotedString(int &$cursor): string @@ -1223,6 +1234,10 @@ private function lexUnquotedString(int &$cursor): string $offset = $cursor; $cursor += strcspn($this->currentLine, '[]{},: ', $cursor); + if ($cursor === $offset) { + throw new ParseException('Malformed unquoted YAML string.'); + } + return substr($this->currentLine, $offset, $cursor - $offset); } @@ -1282,7 +1297,7 @@ private function lexInlineStructure(int &$cursor, string $closingTag): string } } while ($this->moveToNextLine()); - throw new ParseException('Malformed inline YAML string'); + throw new ParseException('Malformed inline YAML string.'); } private function consumeWhitespaces(int &$cursor): bool diff --git a/src/Symfony/Component/Yaml/Tests/Fixtures/YtsBasicTests.yml b/src/Symfony/Component/Yaml/Tests/Fixtures/YtsBasicTests.yml index 1a08d8ea9fdd..621e224490da 100644 --- a/src/Symfony/Component/Yaml/Tests/Fixtures/YtsBasicTests.yml +++ b/src/Symfony/Component/Yaml/Tests/Fixtures/YtsBasicTests.yml @@ -200,3 +200,37 @@ php: | 'age' => 38 ] ] +--- +test: Inline first element in sequence blocks 1 +yaml: | + - - s1_i1 + - s1_i2 + - s2 +php: | + [ + [ + "s1_i1", + "s1_i2" + ], + "s2" + ] +--- +test: Inline first element in sequence blocks 2 +yaml: | + - - s1_i1 + - - s1_i1_1 + - s1_i1_2 + - s1_i2 + - s2 +php: | + [ + [ + "s1_i1", + [ + "s1_i1_1", + "s1_i1_2", + ], + "s1_i2" + ], + "s2" + ] diff --git a/src/Symfony/Component/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php index e680d9d166c5..e6e61981900e 100644 --- a/src/Symfony/Component/Yaml/Tests/InlineTest.php +++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php @@ -190,7 +190,8 @@ public function testParseScalarWithCorrectlyQuotedStringShouldReturnString() */ public function testParseReferences($yaml, $expected) { - $this->assertSame($expected, Inline::parse($yaml, 0, ['var' => 'var-value'])); + $references = ['var' => 'var-value']; + $this->assertSame($expected, Inline::parse($yaml, 0, $references)); } public function getDataForParseReferences() @@ -214,7 +215,8 @@ public function testParseMapReferenceInSequence() 'b' => 'Clark', 'c' => 'Brian', ]; - $this->assertSame([$foo], Inline::parse('[*foo]', 0, ['foo' => $foo])); + $references = ['foo' => $foo]; + $this->assertSame([$foo], Inline::parse('[*foo]', 0, $references)); } public function testParseUnquotedAsterisk() diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index 3822ce7d0c62..50ed706f1ae4 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -52,26 +52,67 @@ public function getNonStringMappingKeysData() return $this->loadTestsFromFixtureFiles('nonStringKeys.yml'); } - public function testTabsInYaml() + /** + * @dataProvider invalidIndentation + */ + public function testTabsAsIndentationInYaml(string $given, string $expectedMessage) { - // test tabs in YAML - $yamls = [ - "foo:\n bar", - "foo:\n bar", - "foo:\n bar", - "foo:\n bar", + $this->expectException(ParseException::class); + $this->expectExceptionMessage($expectedMessage); + $this->parser->parse($given); + } + + public function invalidIndentation(): array + { + return [ + [ + "foo:\n\tbar", + "A YAML file cannot contain tabs as indentation at line 2 (near \"\tbar\").", + ], + [ + "foo:\n \tbar", + "A YAML file cannot contain tabs as indentation at line 2 (near \"\tbar\").", + ], + [ + "foo:\n\t bar", + "A YAML file cannot contain tabs as indentation at line 2 (near \"\t bar\").", + ], + [ + "foo:\n \t bar", + "A YAML file cannot contain tabs as indentation at line 2 (near \"\t bar\").", + ], ]; + } - foreach ($yamls as $yaml) { - try { - $this->parser->parse($yaml); + /** + * @dataProvider validTokenSeparators + */ + public function testValidTokenSeparation(string $given, array $expected) + { + $actual = $this->parser->parse($given); + $this->assertEquals($expected, $actual); + } - $this->fail('YAML files must not contain tabs'); - } catch (\Exception $e) { - $this->assertInstanceOf(\Exception::class, $e, 'YAML files must not contain tabs'); - $this->assertEquals('A YAML file cannot contain tabs as indentation at line 2 (near "'.strpbrk($yaml, "\t").'").', $e->getMessage(), 'YAML files must not contain tabs'); - } - } + public function validTokenSeparators(): array + { + return [ + [ + 'foo: bar', + ['foo' => 'bar'], + ], + [ + "foo:\tbar", + ['foo' => 'bar'], + ], + [ + "foo: \tbar", + ['foo' => 'bar'], + ], + [ + "foo:\t bar", + ['foo' => 'bar'], + ], + ]; } public function testEndOfTheDocumentMarker() @@ -1031,6 +1072,10 @@ public function testReferenceResolvingInInlineStrings() 'map' => ['key' => 'var-value'], 'list_in_map' => ['key' => ['var-value']], 'map_in_map' => ['foo' => ['bar' => 'var-value']], + 'foo' => ['bar' => 'baz'], + 'bar' => ['foo' => 'baz'], + 'baz' => ['foo'], + 'foobar' => ['foo'], ], Yaml::parse(<<<'EOF' var: &var var-value scalar: *var @@ -1041,6 +1086,10 @@ public function testReferenceResolvingInInlineStrings() map: { key: *var } list_in_map: { key: [*var] } map_in_map: { foo: { bar: *var } } +foo: { bar: &baz baz } +bar: { foo: *baz } +baz: [ &foo foo ] +foobar: [ *foo ] EOF )); } @@ -2675,6 +2724,25 @@ public function testParseValueWithNegativeModifiers() ); } + public function testThrowExceptionIfInvalidAdditionalClosingTagOccurs() + { + $yaml = '{ + "object": { + "array": [ + "a", + "b", + "c" + ] + ], + } + }'; + + $this->expectException(ParseException::class); + $this->expectExceptionMessage('Malformed unquoted YAML string at line 8 (near " ],").'); + + $this->parser->parse($yaml); + } + public function testWhitespaceAtEndOfLine() { $yaml = "\nfoo:\n arguments: [ '@bar' ] \n"; diff --git a/src/Symfony/Contracts/HttpClient/ResponseInterface.php b/src/Symfony/Contracts/HttpClient/ResponseInterface.php index fd5b635cd55e..df7148816e3e 100644 --- a/src/Symfony/Contracts/HttpClient/ResponseInterface.php +++ b/src/Symfony/Contracts/HttpClient/ResponseInterface.php @@ -95,15 +95,15 @@ public function cancel(): void; * - response_headers (array) - an array modelled after the special $http_response_header variable * - start_time (float) - the time when the request was sent or 0.0 when it's pending * - url (string) - the last effective URL of the request - * - user_data (mixed|null) - the value of the "user_data" request option, null if not set + * - user_data (mixed) - the value of the "user_data" request option, null if not set * * When the "capture_peer_cert_chain" option is true, the "peer_certificate_chain" * attribute SHOULD list the peer certificates as an array of OpenSSL X.509 resources. * * Other info SHOULD be named after curl_getinfo()'s associative return value. * - * @return array|mixed|null An array of all available info, or one of them when $type is - * provided, or null when an unsupported type is requested + * @return mixed An array of all available info, or one of them when $type is + * provided, or null when an unsupported type is requested */ public function getInfo(string $type = null); } diff --git a/src/Symfony/Contracts/Service/ServiceSubscriberTrait.php b/src/Symfony/Contracts/Service/ServiceSubscriberTrait.php index 81b2bae8a449..243e10328f1b 100644 --- a/src/Symfony/Contracts/Service/ServiceSubscriberTrait.php +++ b/src/Symfony/Contracts/Service/ServiceSubscriberTrait.php @@ -43,7 +43,7 @@ public static function getSubscribedServices(): array } if (self::class === $method->getDeclaringClass()->name && ($returnType = $method->getReturnType()) && !$returnType->isBuiltin()) { - $services[self::class.'::'.$method->name] = '?'.($returnType instanceof \ReflectionNamedType ? $returnType->getName() : $type); + $services[self::class.'::'.$method->name] = '?'.($returnType instanceof \ReflectionNamedType ? $returnType->getName() : $returnType); } } diff --git a/src/Symfony/Contracts/Translation/Test/TranslatorTest.php b/src/Symfony/Contracts/Translation/Test/TranslatorTest.php index facd9b56e129..aa1f9dd872bd 100644 --- a/src/Symfony/Contracts/Translation/Test/TranslatorTest.php +++ b/src/Symfony/Contracts/Translation/Test/TranslatorTest.php @@ -30,6 +30,18 @@ */ class TranslatorTest extends TestCase { + private $defaultLocale; + + protected function setUp(): void + { + $this->defaultLocale = \Locale::getDefault(); + } + + protected function tearDown(): void + { + \Locale::setDefault($this->defaultLocale); + } + public function getTranslator() { return new class() implements TranslatorInterface {