diff --git a/.travis.yml b/.travis.yml index 99595ca5f89b3..8574ad92a0f98 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: php -dist: trusty +dist: xenial git: depth: 2 @@ -24,9 +24,10 @@ matrix: include: - php: 5.5 env: php_extra="5.6 7.0 7.1 7.2" + dist: trusty - php: 7.3 env: deps=high - - php: 7.4snapshot + - php: 7.4 env: deps=low fast_finish: true diff --git a/CHANGELOG-3.4.md b/CHANGELOG-3.4.md index 91a96c6e3b71c..f68d58c658948 100644 --- a/CHANGELOG-3.4.md +++ b/CHANGELOG-3.4.md @@ -7,6 +7,53 @@ in 3.4 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v3.4.0...v3.4.1 +* 3.4.37 (2020-01-21) + + * bug #35065 [Security] Use supportsClass in addition to UnsupportedUserException (linaori) + * bug #35343 [Security] Fix RememberMe with null password (jderusse) + * bug #35318 [Yaml] fix PHP const mapping keys using the inline notation (xabbuh) + * bug #35304 [HttpKernel] Fix that no-cache MUST revalidate with the origin (mpdude) + * bug #35299 Avoid `stale-if-error` in FrameworkBundle's HttpCache if kernel.debug = true (mpdude) + * bug #35151 [DI] deferred exceptions in ResolveParameterPlaceHoldersPass (Islam93) + * bug #35254 [PHPUnit-Bridge] Fail-fast in simple-phpunit if one of the passthru() commands fails (mpdude) + * bug #34643 [Dotenv] Fixed infinite loop with missing quote followed by quoted value (naitsirch) + * bug #35239 [Security\Http] Prevent canceled remember-me cookie from being accepted (chalasr) + * bug #35267 [Debug] fix ClassNotFoundFatalErrorHandler (nicolas-grekas) + * bug #35193 [TwigBridge] button_widget now has its title attr translated even if its label = null or false (stephen-lewis) + * bug #35219 [PhpUnitBridge] When using phpenv + phpenv-composer plugin, composer executable is wrapped into a bash script (oleg-andreyev) + * bug #35170 [FrameworkBundle][TranslationUpdateCommand] Do not output positive feedback on stderr (fancyweb) + * bug #35134 [PropertyInfo] Fix BC issue in phpDoc Reflection library (jaapio) + * bug #35125 [Translator] fix performance issue in MessageCatalogue and catalogue operations (ArtemBrovko) + * bug #35103 [Translation] Use `locale_parse` for computing fallback locales (alanpoulain) + * bug #35094 [Console] Fix filtering out identical alternatives when there is a command loader (fancyweb) + * bug #35039 [DI] skip looking for config class when the extension class is anonymous (nicolas-grekas) + * bug #35049 [ProxyManager] fix generating proxies for root-namespaced classes (nicolas-grekas) + * bug #35022 [Dotenv] FIX missing getenv (mccullagh) + * bug #35010 [VarDumper] ignore failing __debugInfo() (nicolas-grekas) + * bug #35000 [Console][SymfonyQuestionHelper] Handle multibytes question choices keys and custom prompt (fancyweb) + * bug #29839 [Validator] fix comparisons with null values at property paths (xabbuh) + * bug #34900 [DoctrineBridge] Fixed submitting invalid ids when using queries with limit (HeahDude) + * bug #34791 [Serializer] Skip uninitialized (PHP 7.4) properties in PropertyNormalizer and ObjectNormalizer (vudaltsov) + * bug #34915 [FrameworkBundle] Fix invalid Windows path normalization in TemplateNameParser (mvorisek) + * bug #34981 stop using deprecated Doctrine persistence classes (xabbuh) + * bug #34904 [Validator][ConstraintValidator] Safe fail on invalid timezones (fancyweb) + * bug #34918 [Translation] fix memoryleak in PhpFileLoader (nicolas-grekas) + * bug #34438 [HttpFoundation] Use `Cache-Control: must-revalidate` only if explicit lifetime has been given (mpdude) + * bug #34449 [Yaml] Implement multiline string as scalar block for tagged values (natepage) + * bug #34601 [MonologBridge] Fix debug processor datetime type (mRoca) + * bug #34842 [ExpressionLanguage] Process division by zero (tigr1991) + * bug #34902 [PropertyAccess] forward caught exception (xabbuh) + * bug #34888 [TwigBundle] add tags before processing them (xabbuh) + * bug #34762 [Config] never try loading failed classes twice with ClassExistenceResource (nicolas-grekas) + * bug #34839 [Cache] fix memory leak when using PhpArrayAdapter (nicolas-grekas) + * bug #34812 [Yaml] fix parsing negative octal numbers (xabbuh) + * bug #34788 [SecurityBundle] Properly escape regex in AddSessionDomainConstraintPass (fancyweb) + * bug #34755 [FrameworkBundle] resolve service locators in `debug:*` commands (nicolas-grekas) + * bug #34832 [Validator] Allow underscore character "_" in URL username and password (romainneutron) + * bug #34738 [SecurityBundle] Passwords are not encoded when algorithm set to "true" (nieuwenhuisen) + * bug #34779 [Security] do not validate passwords when the hash is null (xabbuh) + * bug #34757 [DI] Fix making the container path-independent when the app is in /app (nicolas-grekas) + * 3.4.36 (2019-12-01) * bug #34649 more robust initialization from request (dbu) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 9a6707977b3ec..aea14fb7e6c5d 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -16,8 +16,8 @@ Symfony is the result of the work of many people who made the code better - Victor Berchet (victor) - Maxime Steinhausser (ogizanagi) - Ryan Weaver (weaverryan) - - Jakub Zalas (jakubzalas) - Javier Eguiluz (javier.eguiluz) + - Jakub Zalas (jakubzalas) - Roland Franssen (ro0) - Grégoire Pineau (lyrixx) - Johannes S (johannes) @@ -32,16 +32,16 @@ Symfony is the result of the work of many people who made the code better - Joseph Bielawski (stloyd) - Alexander M. Turek (derrabus) - Karma Dordrak (drak) + - Thomas Calvet (fancyweb) - Lukas Kahwe Smith (lsmith) - Martin Hasoň (hason) - Hamza Amrouche (simperfit) - Jeremy Mikola (jmikola) - Jules Pietri (heah) - Jean-François Simon (jfsimon) + - Jérémy DERUSSÉ (jderusse) - Benjamin Eberlei (beberlei) - Igor Wiedler (igorw) - - Jérémy DERUSSÉ (jderusse) - - Thomas Calvet (fancyweb) - Eriksen Costa (eriksencosta) - Guilhem Niot (energetick) - Sarah Khalil (saro0h) @@ -51,13 +51,13 @@ Symfony is the result of the work of many people who made the code better - Diego Saint Esteben (dosten) - Alexandre Salomé (alexandresalome) - William Durand (couac) - - ornicar + - Matthias Pigulla (mpdude) - Pierre du Plessis (pierredup) + - ornicar - Dany Maillard (maidmaid) - Francis Besset (francisbesset) - stealth35 ‏ (stealth35) - Alexander Mols (asm89) - - Matthias Pigulla (mpdude) - Konstantin Myakshin (koc) - Bulat Shakirzyanov (avalanche123) - Valentin Udaltsov (vudaltsov) @@ -81,12 +81,12 @@ Symfony is the result of the work of many people who made the code better - Andrej Hudec (pulzarraider) - Michel Weimerskirch (mweimerskirch) - Issei Murasawa (issei_m) + - Jan Schädlich (jschaedl) - Eric Clemmons (ericclemmons) - Charles Sarrazin (csarrazi) - - Jan Schädlich (jschaedl) - Christian Raue - - Arnout Boks (aboks) - Douglas Greenshields (shieldo) + - Arnout Boks (aboks) - Deni - Henrik Westphal (snc) - Dariusz Górecki (canni) @@ -130,9 +130,9 @@ Symfony is the result of the work of many people who made the code better - Joshua Thijssen - Alex Pott - Daniel Wehner (dawehner) + - Tugdual Saunier (tucksaun) - excelwebzone - Gordon Franke (gimler) - - Tugdual Saunier (tucksaun) - Fabien Pennequin (fabienpennequin) - Théo FIDRY (theofidry) - Eric GELOEN (gelo) @@ -154,6 +154,7 @@ Symfony is the result of the work of many people who made the code better - Daniel Gomes (danielcsgomes) - Hidenori Goto (hidenorigoto) - Andréia Bohner (andreia) + - Yanick Witschi (toflar) - Julien Falque (julienfalque) - Arnaud Kleinpeter (nanocom) - Guilherme Blanco (guilhermeblanco) @@ -168,7 +169,6 @@ Symfony is the result of the work of many people who made the code better - jwdeitch - Mikael Pajunen - Alessandro Chitolina (alekitto) - - Yanick Witschi (toflar) - Niels Keurentjes (curry684) - Vyacheslav Pavlov - Richard van Laak (rvanlaak) @@ -177,8 +177,10 @@ Symfony is the result of the work of many people who made the code better - Vincent Touzet (vincenttouzet) - jeremyFreeAgent (jeremyfreeagent) - Rouven Weßling (realityking) + - Jérôme Parmentier (lctrs) - Clemens Tolboom - Helmer Aaviksoo + - Arman Hosseini (arman) - Hiromi Hishida (77web) - Matthieu Ouellette-Vachon (maoueh) - Michał Pipa (michal.pipa) @@ -190,11 +192,11 @@ Symfony is the result of the work of many people who made the code better - Tyson Andre - GDIBass - Samuel NELA (snela) - - Jérôme Parmentier (lctrs) + - Ben Davies (bendavies) + - Andreas Schempp (aschempp) - James Halsall (jaitsu) - Matthieu Napoli (mnapoli) - Florent Mata (fmata) - - Arman Hosseini - Warnar Boekkooi (boekkooi) - Dmitrii Chekaliuk (lazyhammer) - Clément JOBEILI (dator) @@ -211,7 +213,6 @@ Symfony is the result of the work of many people who made the code better - DQNEO - Andre Rømcke (andrerom) - mcfedr (mcfedr) - - Ben Davies (bendavies) - Gary PEGEOT (gary-p) - Ruben Gonzalez (rubenrua) - Benjamin Dulau (dbenjamin) @@ -221,6 +222,7 @@ Symfony is the result of the work of many people who made the code better - Andreas Hucks (meandmymonkey) - Tom Van Looy (tvlooy) - Noel Guilbert (noel) + - Anthony GRASSIOT (antograssiot) - Stadly - Stepan Anchugov (kix) - bronze1man @@ -243,21 +245,24 @@ Symfony is the result of the work of many people who made the code better - Dustin Whittle (dustinwhittle) - jeff - John Kary (johnkary) - - Andreas Schempp (aschempp) + - Jan Rosier (rosier) - Justin Hileman (bobthecow) - Blanchon Vincent (blanchonvincent) - Michele Orselli (orso) - Sven Paulus (subsven) - Maxime Veber (nek-) - - Anthony GRASSIOT (antograssiot) - Rui Marinho (ruimarinho) - Eugene Wissner + - Edi Modrić (emodric) - Pascal Montoya - Julien Brochet (mewt) - Leo Feyer - Tristan Darricau (nicofuma) - Victor Bocharsky (bocharsky_bw) + - Tomas Norkūnas (norkunas) - Marcel Beerta (mazen) + - Ruud Kamphuis (ruudk) + - Antoine Makdessi (amakdessi) - Maxime Helias (maxhelias) - Pavel Batanov (scaytrase) - Mantis Development @@ -271,6 +276,7 @@ Symfony is the result of the work of many people who made the code better - Lorenz Schori - Sébastien Lavoie (lavoiesl) - Dariusz + - Dmitrii Poddubnyi (karser) - Michael Babker (mbabker) - Francois Zaninotto - Alexander Kotynia (olden) @@ -279,11 +285,13 @@ Symfony is the result of the work of many people who made the code better - Marcos Sánchez - Elnur Abdurrakhimov (elnur) - Manuel Reinhard (sprain) + - Tien Vo (tienvx) - Danny Berger (dpb587) - Antonio J. García Lagar (ajgarlag) - Adam Prager (padam87) - Przemysław Bogusz (przemyslaw-bogusz) - Benoît Burnichon (bburnichon) + - Maciej Malarz (malarzm) - Roman Marintšenko (inori) - Xavier Montaña Carreras (xmontana) - Rémon van de Kamp (rpkamp) @@ -299,14 +307,12 @@ Symfony is the result of the work of many people who made the code better - Jordan Samouh (jordansamouh) - Baptiste Lafontaine (magnetik) - Jakub Kucharovic (jkucharovic) - - Edi Modrić (emodric) - Uwe Jäger (uwej711) - Eugene Leonovich (rybakit) - Filippo Tessarotto - Joseph Rouff (rouffj) - Félix Labrecque (woodspire) - GordonsLondon - - Tomas Norkūnas (norkunas) - Quynh Xuan Nguyen (xuanquynh) - Jan Sorgalla (jsor) - Ray @@ -314,7 +320,6 @@ Symfony is the result of the work of many people who made the code better - Chekote - François Pluchino (francoispluchino) - Christopher Hertel (chertel) - - Antoine Makdessi (amakdessi) - Thomas Adam - Jhonny Lidfors (jhonne) - Diego Agulló (aeoris) @@ -335,7 +340,6 @@ Symfony is the result of the work of many people who made the code better - Zan Baldwin (zanderbaldwin) - Roumen Damianoff (roumen) - Kim Hemsø Rasmussen (kimhemsoe) - - Dmitrii Poddubnyi (karser) - Pascal Luna (skalpa) - Wouter Van Hecke - Peter Kruithof (pkruithof) @@ -348,6 +352,7 @@ Symfony is the result of the work of many people who made the code better - Christian Schmidt - Patrick Landolt (scube) - MatTheCat + - Loick Piera (pyrech) - David Badura (davidbadura) - Chad Sikorra (chadsikorra) - Chris Smith (cs278) @@ -368,7 +373,6 @@ Symfony is the result of the work of many people who made the code better - Jerzy Zawadzki (jzawadzki) - Wouter J - Ismael Ambrosi (iambrosi) - - Ruud Kamphuis (ruudk) - Emmanuel BORGES (eborges78) - Aurelijus Valeiša (aurelijus) - Jan Decavele (jandc) @@ -390,6 +394,7 @@ Symfony is the result of the work of many people who made the code better - Thierry Thuon (lepiaf) - Ricard Clau (ricardclau) - Mark Challoner (markchalloner) + - Philippe Segatori - Gennady Telegin (gtelegin) - Erin Millard - Artur Melo (restless) @@ -398,12 +403,12 @@ Symfony is the result of the work of many people who made the code better - Thomas Royer (cydonia7) - Nicolas LEFEVRE (nicoweb) - alquerci + - Olivier Dolbeau (odolbeau) - Mateusz Sip (mateusz_sip) - Francesco Levorato - Vitaliy Zakharov (zakharovvi) - Tobias Sjösten (tobiassjosten) - Gyula Sallai (salla) - - Maciej Malarz (malarzm) - Inal DJAFAR (inalgnu) - Christian Gärtner (dagardner) - Dmytro Borysovskyi (dmytr0) @@ -415,13 +420,14 @@ Symfony is the result of the work of many people who made the code better - Felix Labrecque - Yaroslav Kiliba - Terje Bråten - - Tien Vo (tienvx) - Robbert Klarenbeek (robbertkl) - Eric Masoero (eric-masoero) - JhonnyL - hossein zolfi (ocean) - Clément Gautier (clementgautier) + - Bastien Jaillot (bastnic) - Dāvis Zālītis (k0d3r1s) + - Emanuele Panzeri (thepanz) - Sanpi - Eduardo Gulias (egulias) - giulio de donato (liuggio) @@ -437,6 +443,7 @@ Symfony is the result of the work of many people who made the code better - Alex Bowers - Philipp Cordes - Costin Bereveanu (schniper) + - Vilius Grigaliūnas - Loïc Chardonnet (gnusat) - Marek Kalnik (marekkalnik) - Vyacheslav Salakhutdinov (megazoll) @@ -446,9 +453,11 @@ Symfony is the result of the work of many people who made the code better - Michele Locati - Pavel Volokitin (pvolok) - Valentine Boineau (valentineboineau) + - Benjamin Leveque (benji07) - Arthur de Moulins (4rthem) - Matthias Althaus (althaus) - Nicolas Dewez (nicolas_dewez) + - Saif Eddin G - Endre Fejes - Tobias Naumann (tna) - Daniel Beyer @@ -461,7 +470,6 @@ Symfony is the result of the work of many people who made the code better - Lee Rowlands - Krzysztof Piasecki (krzysztek) - Maximilian Reichel (phramz) - - Loick Piera (pyrech) - Alain Hippolyte (aloneh) - Grenier Kévin (mcsky_biig) - Karoly Negyesi (chx) @@ -484,6 +492,7 @@ Symfony is the result of the work of many people who made the code better - Sébastien Santoro (dereckson) - Brian King - Michel Salib (michelsalib) + - Chris Tanaskoski - geoffrey - Steffen Roßkamp - Alexandru Furculita (afurculita) @@ -494,6 +503,7 @@ Symfony is the result of the work of many people who made the code better - Christopher Davis (chrisguitarguy) - Webnet team (webnet) - Farhad Safarov + - Jeroen Spee (jeroens) - Jan Schumann - Niklas Fiekas - Markus Bachmann (baachi) @@ -502,8 +512,7 @@ Symfony is the result of the work of many people who made the code better - Mihai Stancu - Ivan Nikolaev (destillat) - Gildas Quéméner (gquemener) - - Olivier Dolbeau (odolbeau) - - Jan Rosier (rosier) + - Oleg Andreyev - Alessandro Lai (jean85) - Desjardins Jérôme (jewome62) - Arturs Vonda @@ -543,7 +552,7 @@ Symfony is the result of the work of many people who made the code better - Gintautas Miselis - Rob Bast - Roberto Espinoza (respinoza) - - Emanuele Panzeri (thepanz) + - Alan Poulain - Soufian EZ-ZANTAR (soezz) - Zander Baldwin - Gocha Ossinkine (ossinkine) @@ -602,7 +611,6 @@ Symfony is the result of the work of many people who made the code better - Jakub Škvára (jskvara) - Andrew Udvare (audvare) - alexpods - - Saif Eddin G - Johann Pardanaud - Adam Szaraniec (mimol) - Dariusz Ruminski @@ -620,7 +628,6 @@ Symfony is the result of the work of many people who made the code better - Nils Adermann (naderman) - Gábor Fási - DUPUCH (bdupuch) - - Benjamin Leveque (benji07) - Nate (frickenate) - Timothée Barray (tyx) - jhonnyL @@ -661,20 +668,22 @@ Symfony is the result of the work of many people who made the code better - Disquedur - Michiel Boeckaert (milio) - Geoffrey Tran (geoff) + - Pablo Lozano (arkadis) - Kyle - Jan Behrens - Mantas Var (mvar) - - Chris Tanaskoski - Terje Bråten - Sebastian Krebs - Piotr Stankowski - Baptiste Leduc (bleduc) - Julien Maulny + - Sebastien Morel (plopix) - Jean-Christophe Cuvelier [Artack] - Julien Montel (julienmgel) - - Philippe Segatori - Simon DELICATA + - Artem Henvald (artemgenvald) - Dmitry Simushev + - Joe Bennett (kralos) - alcaeus - Fred Cox - vitaliytv @@ -690,7 +699,6 @@ Symfony is the result of the work of many people who made the code better - Kyle Evans (kevans91) - Charles-Henri Bruyand - Max Rath (drak3) - - Oleg Andreyev - Stéphane Escandell (sescandell) - Konstantin S. M. Möllers (ksmmoellers) - James Johnston @@ -754,6 +762,7 @@ Symfony is the result of the work of many people who made the code better - M. Vondano - Quentin de Longraye (quentinus95) - Chris Heng (gigablah) + - Islam93 - Shaun Simmons (simshaun) - Richard Bradley - Ulumuddin Yunus (joenoez) @@ -766,6 +775,7 @@ Symfony is the result of the work of many people who made the code better - Antoine Corcy - Ahmed Ashraf (ahmedash95) - Sascha Grossenbacher + - Alexander Menshchikov (zmey_kk) - Szijarto Tamas - Robin Lehrmann (robinlehrmann) - Catalin Dan @@ -818,7 +828,6 @@ Symfony is the result of the work of many people who made the code better - Michael Piecko - Toni Peric (tperic) - yclian - - Alan Poulain - Aleksey Prilipko - Andrew Berry - twifty @@ -830,11 +839,11 @@ Symfony is the result of the work of many people who made the code better - Dominik Ritter (dritter) - Dimitri Gritsajuk (ottaviano) - Sebastian Grodzicki (sgrodzicki) + - Mohamed Gamal - Jeroen van den Enden (stoefke) - Pascal Helfenstein - Baldur Rensch (brensch) - Pierre Rineau - - Vilius Grigaliūnas - Vladyslav Petrovych - Alex Xandra Albert Sim - Carson Full @@ -843,6 +852,7 @@ Symfony is the result of the work of many people who made the code better - Yuen-Chi Lian - Tarjei Huse (tarjei) - Besnik Br + - Toni Rudolf (toooni) - Jose Gonzalez - Jonathan (jls-esokia) - Oleksii Zhurbytskyi @@ -851,6 +861,7 @@ Symfony is the result of the work of many people who made the code better - Claudio Zizza - Dave Marshall (davedevelopment) - Jakub Kulhan (jakubkulhan) + - Shaharia Azam - avorobiev - Grégoire Penverne (gpenverne) - Venu @@ -896,6 +907,7 @@ Symfony is the result of the work of many people who made the code better - Franco Traversaro (belinde) - Francis Turmel (fturmel) - Nikita Nefedov (nikita2206) + - Alex Bacart - cgonzalez - Ben - Vincent Composieux (eko) @@ -919,6 +931,7 @@ Symfony is the result of the work of many people who made the code better - Reen Lokum - Andreas Möller (localheinz) - Martin Parsiegla (spea) + - Ivan - Quentin Schuler - Pierre Vanliefland (pvanliefland) - Roy Klutman (royklutman) @@ -969,6 +982,7 @@ Symfony is the result of the work of many people who made the code better - Derek ROTH - Ben Johnson - mweimerskirch + - Lctrs - Dmytro Boiko (eagle) - Shin Ohno (ganchiku) - Geert De Deckere (geertdd) @@ -1009,6 +1023,7 @@ Symfony is the result of the work of many people who made the code better - Marcos Gómez Vilches (markitosgv) - Matthew Davis (mdavis1982) - Markus S. (staabm) + - Guilliam Xavier - Maks - Antoine LA - den @@ -1030,14 +1045,12 @@ Symfony is the result of the work of many people who made the code better - Benoît Merlet (trompette) - Koen Kuipers - datibbaw - - Pablo Lozano (arkadis) - Erik Saunier (snickers) - Rootie - Daniel Alejandro Castro Arellano (lexcast) - sensio - Thomas Jarrand - Antoine Bluchet (soyuka) - - Sebastien Morel (plopix) - Patrick Kaufmann - Anton Dyshkant - Reece Fowell (reecefowell) @@ -1152,6 +1165,7 @@ Symfony is the result of the work of many people who made the code better - AKeeman (akeeman) - Mert Simsek (mrtsmsk0) - Lin Clark + - Meneses (c77men) - Jeremy David (jeremy.david) - Jordi Rejas - Troy McCabe @@ -1185,6 +1199,7 @@ Symfony is the result of the work of many people who made the code better - HypeMC - jfcixmedia - Dominic Tubach + - Nicolas Philippe (nikophil) - Nikita Konstantinov - Martijn Evers - Vitaliy Ryaboy (vitaliy) @@ -1241,7 +1256,9 @@ Symfony is the result of the work of many people who made the code better - e-ivanov - Michał (bambucha15) - Einenlum + - Jérémy Jarrié (gagnar) - Jochen Bayer (jocl) + - Michel Roca (mroca) - Patrick Carlo-Hickman - Bruno MATEU - Jeremy Bush @@ -1274,14 +1291,17 @@ Symfony is the result of the work of many people who made the code better - rchoquet - gitlost - Taras Girnyk + - Rémi Leclerc - Jan Vernarsky - Amine Yakoubi - Eduardo García Sanz (coma) - Sergio (deverad) - James Gilliland - fduch (fduch) + - Stuart Fyfe - David de Boer (ddeboer) - Eno Mullaraj (emullaraj) + - Nathan PAGE (nathix) - Ryan Rogers - Klaus Purer - arnaud (arnooo999) @@ -1404,6 +1424,7 @@ Symfony is the result of the work of many people who made the code better - Walter Dal Mut (wdalmut) - abluchet - Ruud Arentsen + - Ahmed Raafat - Harald Tollefsen - Matthieu - Albin Kerouaton @@ -1431,6 +1452,7 @@ Symfony is the result of the work of many people who made the code better - Constantine Shtompel - Jules Lamur - Renato Mendes Figueiredo + - Benjamin RICHARD - pdommelen - Eric Stern - ShiraNai7 @@ -1453,8 +1475,9 @@ Symfony is the result of the work of many people who made the code better - m.chwedziak - Andreas Frömer - Philip Frank + - David Brooks - Lance McNearney - - Jeroen Spee (jeroens) + - Guillaume Verstraete - Giorgio Premi - ncou - Ian Carroll @@ -1466,7 +1489,6 @@ Symfony is the result of the work of many people who made the code better - Tom Corrigan (tomcorrigan) - Luis Galeas - Martin Pärtel - - Bastien Jaillot (bastnic) - Daniel Rotter (danrot) - Frédéric Bouchery (fbouchery) - Patrick Daley (padrig) @@ -1475,7 +1497,6 @@ Symfony is the result of the work of many people who made the code better - WedgeSama - Felds Liscia - Chihiro Adachi (chihiro-adachi) - - Alex Bacart - Raphaëll Roussel - Tadcka - Beth Binkovitz @@ -1504,6 +1525,7 @@ Symfony is the result of the work of many people who made the code better - Mathieu Morlon - Daniel Tschinder - Arnaud CHASSEUX + - tuqqu - Wojciech Gorczyca - Rafał Muszyński (rafmus90) - Sébastien Decrême (sebdec) @@ -1563,8 +1585,10 @@ Symfony is the result of the work of many people who made the code better - Patrik Gmitter (patie) - Peter Schultz - Jonathan Gough + - Benhssaein Youssef - Benjamin Bender - Jared Farrish + - Trevor North - karl.rixon - raplider - Konrad Mohrfeldt @@ -1636,6 +1660,7 @@ Symfony is the result of the work of many people who made the code better - Francisco Facioni (fran6co) - Stanislav Gamayunov (happyproff) - Iwan van Staveren (istaveren) + - Alexander McCullagh (mccullagh) - Povilas S. (povilas) - Laurent Negre (raulnet) - Evrard Boulou @@ -1772,6 +1797,7 @@ Symfony is the result of the work of many people who made the code better - JakeFr - Simon Sargeant - efeen + - Jan Christoph Beyer - Nicolas Pion - Muhammed Akbulut - Roy-Orbison @@ -1785,6 +1811,7 @@ Symfony is the result of the work of many people who made the code better - Johannes Müller (johmue) - Jordi Llonch (jordillonch) - Nicholas Ruunu (nicholasruunu) + - Jeroen van den Nieuwenhuisen (nieuwenhuisen) - Cyril Pascal (paxal) - Cédric Dugat (ph3nol) - Philip Dahlstrøm (phidah) @@ -1825,10 +1852,10 @@ Symfony is the result of the work of many people who made the code better - Dmitry Korotovsky - mcorteel - Michael van Tricht - - Ivan - ReScO - Tim Strehle - Sam Ward + - Michael Voříšek - Walther Lalk - Adam - Ivo @@ -1840,7 +1867,6 @@ Symfony is the result of the work of many people who made the code better - gedrox - Bohan Yang - Alan Bondarchuk - - Joe Bennett - dropfen - Andrey Chernykh - Edvinas Klovas @@ -1858,6 +1884,7 @@ Symfony is the result of the work of many people who made the code better - thib92 - Rudolf Ratusiński - Bertalan Attila + - Rafael Tovar - Amin Hosseini (aminh) - AmsTaFF (amstaff) - Simon Müller (boscho) @@ -1872,10 +1899,13 @@ Symfony is the result of the work of many people who made the code better - Jan Marek (janmarek) - Mark de Haan (markdehaan) - Dan Patrick (mdpatrick) + - naitsirch (naitsirch) - Geoffrey Monte (numerogeek) + - Martijn Boers (plebian) - Pedro Magalhães (pmmaga) - Rares Vlaseanu (raresvla) - tante kinast (tante) + - Stephen Lewis (tehanomalousone) - Ahmed Hannachi (tiecoders) - Vincent LEFORT (vlefort) - Walid BOUGHDIRI (walidboughdiri) @@ -1982,7 +2012,6 @@ Symfony is the result of the work of many people who made the code better - Klaas Naaijkens - Daniel González Cerviño - Rafał - - Lctrs - Achilles Kaloeridis (achilles) - Adria Lopez (adlpz) - Aaron Scherer (aequasi) @@ -1993,8 +2022,10 @@ Symfony is the result of the work of many people who made the code better - Masao Maeda (brtriver) - Darius Leskauskas (darles) - david perez (davidpv) + - Daniël Brekelmans (dbrekelmans) - David Joos (djoos) - Denis Klementjev (dklementjev) + - Dominik Pesch (dombn) - Dominik Hajduk (dominikalp) - Tomáš Polívka (draczris) - Dennis Smink (dsmink) @@ -2005,6 +2036,7 @@ Symfony is the result of the work of many people who made the code better - Gusakov Nikita (hell0w0rd) - Yannick Ihmels (ihmels) - Osman Üngür (import) + - Jaap van Otterdijk (jaapio) - Javier Núñez Berrocoso (javiernuber) - Jelle Bekker (jbekker) - Giovanni Albero (johntree) @@ -2021,6 +2053,7 @@ Symfony is the result of the work of many people who made the code better - Marek Šimeček (mssimi) - Dmitriy Tkachenko (neka) - Cayetano Soriano Gallego (neoshadybeat) + - Artem (nexim) - Olivier Laviale (olvlvl) - Ondrej Machulda (ondram) - Pierre Gasté (pierre_g) @@ -2036,6 +2069,7 @@ Symfony is the result of the work of many people who made the code better - Angel Fernando Quiroz Campos - Ondrej Mirtes - akimsko + - Stefan Kruppa - Youpie - srsbiz - Taylan Kasap @@ -2075,6 +2109,7 @@ Symfony is the result of the work of many people who made the code better - Till Klampaeckel (till) - Tobias Weinert (tweini) - Ulf Reimers (ureimers) + - Morten Wulff (wulff) - Wotre - goohib - Tom Counsell @@ -2095,7 +2130,6 @@ Symfony is the result of the work of many people who made the code better - Benjamin Morel - Eric Grimois - Piers Warmers - - Guilliam Xavier - Sylvain Lorinet - klyk50 - Andreas Lutro @@ -2235,10 +2269,12 @@ Symfony is the result of the work of many people who made the code better - Oussama Elgoumri - Dawid Nowak - Lesnykh Ilia + - sabruss - darnel - Karolis Daužickas - Nicolas - Sergio Santoro + - Dmitriy Derepko - tirnanog06 - phc - Дмитрий Пацура @@ -2283,6 +2319,7 @@ Symfony is the result of the work of many people who made the code better - Carsten Eilers (fnc) - Sorin Gitlan (forapathy) - Yohan Giarelli (frequence-web) + - Jesse Rushlow (geeshoe) - Gerry Vandermaesen (gerryvdm) - Ghazy Ben Ahmed (ghazy) - Arash Tabriziyan (ghost098) @@ -2317,6 +2354,7 @@ Symfony is the result of the work of many people who made the code better - Michal Čihař (mcihar) - Matt Drollette (mdrollette) - Adam Monsen (meonkeys) + - diego aguiar (mollokhan) - Hugo Monteiro (monteiro) - Ala Eddine Khefifi (nayzo) - emilienbouard (neime) @@ -2332,6 +2370,7 @@ Symfony is the result of the work of many people who made the code better - Philipp Hoffmann (philipphoffmann) - Alex Carol (picard89) - Daniel Perez Pinazo (pitiflautico) + - Igor Tarasov (polosatus) - Phil Taylor (prazgod) - Maxim Pustynnikov (pustynnikov) - Ralf Kuehnel (ralfkuehnel) @@ -2365,7 +2404,6 @@ Symfony is the result of the work of many people who made the code better - Wouter Sioen (wouter_sioen) - Xavier Amado (xamado) - Jesper Søndergaard Pedersen (zerrvox) - - Alexander Menshchikov (zmey_kk) - Florent Cailhol - szymek - Ryan Linnit @@ -2377,6 +2415,7 @@ Symfony is the result of the work of many people who made the code better - MaPePeR - Andreas Streichardt - Alexandre Segura + - Vivien - Pascal Hofmann - david-binda - smokeybear87 @@ -2389,6 +2428,7 @@ Symfony is the result of the work of many people who made the code better - Sergey Fedotov - Konstantin Scheumann - Michael + - Nate Wiebe - fh-github@fholzhauer.de - AbdElKader Bouadjadja - DSeemiller @@ -2400,6 +2440,7 @@ Symfony is the result of the work of many people who made the code better - max - Alexander Bauer (abauer) - Ahmad Mayahi (ahmadmayahi) + - Alireza Mirsepassi (alirezamirsepassi) - Mohamed Karnichi (amiral) - Andrew Carter (andrewcarteruk) - Adam Elsodaney (archfizz) diff --git a/LICENSE b/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/link b/link index 7b7512f0c9d1f..9f42fe951247c 100755 --- a/link +++ b/link @@ -23,11 +23,14 @@ use Symfony\Component\Filesystem\Filesystem; * @author Kévin Dunglas */ +$copy = false !== $k = array_search('--copy', $argv, true); +$copy && array_splice($argv, $k, 1); $pathToProject = $argv[1] ?? getcwd(); if (!is_dir("$pathToProject/vendor/symfony")) { - echo 'Link dependencies to components to a local clone of the main symfony/symfony GitHub repository.'.PHP_EOL.PHP_EOL; - echo "Usage: $argv[0] /path/to/the/project".PHP_EOL.PHP_EOL; + echo 'Link (or copy) dependencies to components to a local clone of the main symfony/symfony GitHub repository.'.PHP_EOL.PHP_EOL; + echo "Usage: $argv[0] /path/to/the/project".PHP_EOL; + echo ' Use `--copy` to copy dependencies instead of symlink'.PHP_EOL.PHP_EOL; echo "The directory \"$pathToProject\" does not exist or the dependencies are not installed, did you forget to run \"composer install\" in your project?".PHP_EOL; exit(1); } @@ -48,7 +51,7 @@ foreach ($directories as $dir) { foreach (glob("$pathToProject/vendor/symfony/*", GLOB_ONLYDIR | GLOB_NOSORT) as $dir) { $package = 'symfony/'.basename($dir); - if (is_link($dir)) { + if (!$copy && is_link($dir)) { echo "\"$package\" is already a symlink, skipping.".PHP_EOL; continue; } @@ -57,11 +60,17 @@ foreach (glob("$pathToProject/vendor/symfony/*", GLOB_ONLYDIR | GLOB_NOSORT) as continue; } - $sfDir = '\\' === DIRECTORY_SEPARATOR ? $sfPackages[$package] : $filesystem->makePathRelative($sfPackages[$package], dirname(realpath($dir))); + $sfDir = ('\\' === DIRECTORY_SEPARATOR || $copy) ? $sfPackages[$package] : $filesystem->makePathRelative($sfPackages[$package], dirname(realpath($dir))); $filesystem->remove($dir); - $filesystem->symlink($sfDir, $dir); - echo "\"$package\" has been linked to \"$sfPackages[$package]\".".PHP_EOL; + + if ($copy) { + $filesystem->mirror($sfDir, $dir); + echo "\"$package\" has been copied from \"$sfPackages[$package]\".".PHP_EOL; + } else { + $filesystem->symlink($sfDir, $dir); + echo "\"$package\" has been linked to \"$sfPackages[$package]\".".PHP_EOL; + } } foreach (glob("$pathToProject/var/cache/*", GLOB_NOSORT) as $cacheDir) { diff --git a/phpunit b/phpunit index b07ca07d06a20..200a9c28b4c34 100755 --- a/phpunit +++ b/phpunit @@ -21,4 +21,14 @@ if (!getenv('SYMFONY_PATCH_TYPE_DECLARATIONS')) { putenv('SYMFONY_PATCH_TYPE_DECLARATIONS=deprecations=1'); } putenv('SYMFONY_PHPUNIT_DIR='.__DIR__.'/.phpunit'); + +if (!getenv('SYMFONY_DEPRECATIONS_HELPER')) { + foreach ($_SERVER['argv'] as $v) { + if (false !== strpos($v, 'Bridge/Doctrine')) { + putenv('SYMFONY_DEPRECATIONS_HELPER=max[indirect]=7'); + break; + } + } +} + require __DIR__.'/vendor/symfony/phpunit-bridge/bin/simple-phpunit'; diff --git a/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php b/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php index 9bf22357df895..db8163e4c8b43 100644 --- a/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php +++ b/src/Symfony/Bridge/Doctrine/CacheWarmer/ProxyCacheWarmer.php @@ -11,7 +11,8 @@ namespace Symfony\Bridge\Doctrine\CacheWarmer; -use Doctrine\Common\Persistence\ManagerRegistry; +use Doctrine\Common\Persistence\ManagerRegistry as LegacyManagerRegistry; +use Doctrine\Persistence\ManagerRegistry; use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerInterface; /** @@ -26,7 +27,10 @@ class ProxyCacheWarmer implements CacheWarmerInterface { private $registry; - public function __construct(ManagerRegistry $registry) + /** + * @param ManagerRegistry|LegacyManagerRegistry $registry + */ + public function __construct($registry) { $this->registry = $registry; } diff --git a/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php b/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php index 937b36f5163c8..ba3887b83bf0d 100644 --- a/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php +++ b/src/Symfony/Bridge/Doctrine/DataCollector/DoctrineDataCollector.php @@ -11,10 +11,11 @@ namespace Symfony\Bridge\Doctrine\DataCollector; -use Doctrine\Common\Persistence\ManagerRegistry; +use Doctrine\Common\Persistence\ManagerRegistry as LegacyManagerRegistry; use Doctrine\DBAL\Logging\DebugStack; use Doctrine\DBAL\Types\ConversionException; use Doctrine\DBAL\Types\Type; +use Doctrine\Persistence\ManagerRegistry; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\DataCollector\DataCollector; @@ -35,7 +36,10 @@ class DoctrineDataCollector extends DataCollector */ private $loggers = []; - public function __construct(ManagerRegistry $registry) + /** + * @param ManagerRegistry|LegacyManagerRegistry $registry + */ + public function __construct($registry) { $this->registry = $registry; $this->connections = $registry->getConnectionNames(); diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php index d8dfab3b2b505..8dab9c8a3e071 100644 --- a/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php +++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php @@ -239,11 +239,7 @@ protected function assertValidMappingConfiguration(array $mappingConfig, $object } 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') - )); + 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'))); } } diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterMappingsPass.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterMappingsPass.php index 4e025dc194c93..16ca723223cdc 100644 --- a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterMappingsPass.php +++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterMappingsPass.php @@ -143,7 +143,7 @@ public function process(ContainerBuilder $container) $mappingDriverDef = $this->getDriver($container); $chainDriverDefService = $this->getChainDriverServiceName($container); - // Definition for a Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain + // Definition for a Doctrine\Persistence\Mapping\Driver\MappingDriverChain $chainDriverDef = $container->getDefinition($chainDriverDefService); foreach ($this->namespaces as $namespace) { $chainDriverDef->addMethodCall('addDriver', [$mappingDriverDef, $namespace]); diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php index 89df8931c75aa..244d6331e4685 100644 --- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php +++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/DoctrineChoiceLoader.php @@ -11,7 +11,8 @@ namespace Symfony\Bridge\Doctrine\Form\ChoiceList; -use Doctrine\Common\Persistence\ObjectManager; +use Doctrine\Common\Persistence\ObjectManager as LegacyObjectManager; +use Doctrine\Persistence\ObjectManager; use Symfony\Component\Form\ChoiceList\ArrayChoiceList; use Symfony\Component\Form\ChoiceList\ChoiceListInterface; use Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface; @@ -41,11 +42,11 @@ class DoctrineChoiceLoader implements ChoiceLoaderInterface * passed which optimizes the object loading for one of the Doctrine * mapper implementations. * - * @param ObjectManager $manager The object manager - * @param string $class The class name of the loaded objects - * @param IdReader $idReader The reader for the object IDs - * @param EntityLoaderInterface|null $objectLoader The objects loader - * @param ChoiceListFactoryInterface $factory The factory for creating the loaded choice list + * @param ObjectManager|LegacyObjectManager $manager The object manager + * @param string $class The class name of the loaded objects + * @param IdReader $idReader The reader for the object IDs + * @param EntityLoaderInterface|null $objectLoader The objects loader + * @param ChoiceListFactoryInterface $factory The factory for creating the loaded choice list */ public function __construct($manager, $class, $idReader = null, $objectLoader = null, $factory = null) { diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php index 4812e6dfcd53f..50f8742881db4 100644 --- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php +++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php @@ -11,8 +11,10 @@ namespace Symfony\Bridge\Doctrine\Form\ChoiceList; -use Doctrine\Common\Persistence\Mapping\ClassMetadata; -use Doctrine\Common\Persistence\ObjectManager; +use Doctrine\Common\Persistence\Mapping\ClassMetadata as LegacyClassMetadata; +use Doctrine\Common\Persistence\ObjectManager as LegacyObjectManager; +use Doctrine\Persistence\Mapping\ClassMetadata; +use Doctrine\Persistence\ObjectManager; use Symfony\Component\Form\Exception\RuntimeException; /** @@ -35,7 +37,11 @@ class IdReader */ private $associationIdReader; - public function __construct(ObjectManager $om, ClassMetadata $classMetadata) + /** + * @param ObjectManager|LegacyObjectManager $om + * @param ClassMetadata|LegacyClassMetadata $classMetadata + */ + public function __construct($om, $classMetadata) { $ids = $classMetadata->getIdentifierFieldNames(); $idType = $classMetadata->getTypeOfField(current($ids)); diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php index 96f5e2f5f1868..875b08dae95e0 100644 --- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php +++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/ORMQueryBuilderLoader.php @@ -55,6 +55,21 @@ public function getEntities() */ public function getEntitiesByIds($identifier, array $values) { + if (null !== $this->queryBuilder->getMaxResults() || null !== $this->queryBuilder->getFirstResult()) { + // an offset or a limit would apply on results including the where clause with submitted id values + // that could make invalid choices valid + $choices = []; + $metadata = $this->queryBuilder->getEntityManager()->getClassMetadata(current($this->queryBuilder->getRootEntities())); + + foreach ($this->getEntities() as $entity) { + if (\in_array(current($metadata->getIdentifierValues($entity)), $values, true)) { + $choices[] = $entity; + } + } + + return $choices; + } + $qb = clone $this->queryBuilder; $alias = current($qb->getRootAliases()); $parameter = 'ORMQueryBuilderLoader_getEntitiesByIds_'.$identifier; diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmExtension.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmExtension.php index 891754a1da08f..90aca67a49fb6 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmExtension.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmExtension.php @@ -11,7 +11,8 @@ namespace Symfony\Bridge\Doctrine\Form; -use Doctrine\Common\Persistence\ManagerRegistry; +use Doctrine\Common\Persistence\ManagerRegistry as LegacyManagerRegistry; +use Doctrine\Persistence\ManagerRegistry; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractExtension; @@ -19,7 +20,10 @@ class DoctrineOrmExtension extends AbstractExtension { protected $registry; - public function __construct(ManagerRegistry $registry) + /** + * @param ManagerRegistry|LegacyManagerRegistry $registry + */ + public function __construct($registry) { $this->registry = $registry; } diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php index 1df396d367d84..ff4b54d24bdcc 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php @@ -11,12 +11,14 @@ namespace Symfony\Bridge\Doctrine\Form; -use Doctrine\Common\Persistence\ManagerRegistry; -use Doctrine\Common\Persistence\Mapping\MappingException; +use Doctrine\Common\Persistence\ManagerRegistry as LegacyManagerRegistry; +use Doctrine\Common\Persistence\Mapping\MappingException as LegacyCommonMappingException; use Doctrine\Common\Util\ClassUtils; use Doctrine\DBAL\Types\Type; use Doctrine\ORM\Mapping\ClassMetadataInfo; use Doctrine\ORM\Mapping\MappingException as LegacyMappingException; +use Doctrine\Persistence\ManagerRegistry; +use Doctrine\Persistence\Mapping\MappingException; use Symfony\Component\Form\FormTypeGuesserInterface; use Symfony\Component\Form\Guess\Guess; use Symfony\Component\Form\Guess\TypeGuess; @@ -28,7 +30,10 @@ class DoctrineOrmTypeGuesser implements FormTypeGuesserInterface private $cache = []; - public function __construct(ManagerRegistry $registry) + /** + * @param ManagerRegistry|LegacyManagerRegistry $registry + */ + public function __construct($registry) { $this->registry = $registry; } @@ -173,6 +178,8 @@ protected function getMetadata($class) return $this->cache[$class] = [$em->getClassMetadata($class), $name]; } catch (MappingException $e) { // not an entity or mapped super class + } catch (LegacyCommonMappingException $e) { + // not an entity or mapped super class } catch (LegacyMappingException $e) { // not an entity or mapped super class, using Doctrine ORM 2.2 } diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php index 60caab8ba68fa..1aeecf4388425 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php @@ -11,8 +11,10 @@ namespace Symfony\Bridge\Doctrine\Form\Type; -use Doctrine\Common\Persistence\ManagerRegistry; -use Doctrine\Common\Persistence\ObjectManager; +use Doctrine\Common\Persistence\ManagerRegistry as LegacyManagerRegistry; +use Doctrine\Common\Persistence\ObjectManager as LegacyObjectManager; +use Doctrine\Persistence\ManagerRegistry; +use Doctrine\Persistence\ObjectManager; use Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader; use Symfony\Bridge\Doctrine\Form\ChoiceList\EntityLoaderInterface; use Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader; @@ -99,7 +101,10 @@ public function getQueryBuilderPartsForCachingHash($queryBuilder) return false; } - public function __construct(ManagerRegistry $registry) + /** + * @param ManagerRegistry|LegacyManagerRegistry $registry + */ + public function __construct($registry) { $this->registry = $registry; } @@ -194,9 +199,8 @@ public function configureOptions(OptionsResolver $resolver) }; $emNormalizer = function (Options $options, $em) { - /* @var ManagerRegistry $registry */ if (null !== $em) { - if ($em instanceof ObjectManager) { + if ($em instanceof ObjectManager || $em instanceof LegacyObjectManager) { return $em; } @@ -262,7 +266,7 @@ public function configureOptions(OptionsResolver $resolver) $resolver->setNormalizer('query_builder', $queryBuilderNormalizer); $resolver->setNormalizer('id_reader', $idReaderNormalizer); - $resolver->setAllowedTypes('em', ['null', 'string', 'Doctrine\Common\Persistence\ObjectManager']); + $resolver->setAllowedTypes('em', ['null', 'string', ObjectManager::class, LegacyObjectManager::class]); } /** @@ -273,7 +277,7 @@ public function configureOptions(OptionsResolver $resolver) * * @return EntityLoaderInterface */ - abstract public function getLoader(ObjectManager $manager, $queryBuilder, $class); + abstract public function getLoader(LegacyObjectManager $manager, $queryBuilder, $class); public function getParent() { diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/EntityType.php b/src/Symfony/Bridge/Doctrine/Form/Type/EntityType.php index 2226da9512488..7d6d017e58f5f 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/EntityType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/EntityType.php @@ -11,7 +11,7 @@ namespace Symfony\Bridge\Doctrine\Form\Type; -use Doctrine\Common\Persistence\ObjectManager; +use Doctrine\Common\Persistence\ObjectManager as LegacyObjectManager; use Doctrine\ORM\Query\Parameter; use Doctrine\ORM\QueryBuilder; use Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader; @@ -51,7 +51,7 @@ public function configureOptions(OptionsResolver $resolver) * * @return ORMQueryBuilderLoader */ - public function getLoader(ObjectManager $manager, $queryBuilder, $class) + public function getLoader(LegacyObjectManager $manager, $queryBuilder, $class) { return new ORMQueryBuilderLoader($queryBuilder); } diff --git a/src/Symfony/Bridge/Doctrine/LICENSE b/src/Symfony/Bridge/Doctrine/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Bridge/Doctrine/LICENSE +++ b/src/Symfony/Bridge/Doctrine/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bridge/Doctrine/ManagerRegistry.php b/src/Symfony/Bridge/Doctrine/ManagerRegistry.php index e3fcbb4a21394..852aa3898a26c 100644 --- a/src/Symfony/Bridge/Doctrine/ManagerRegistry.php +++ b/src/Symfony/Bridge/Doctrine/ManagerRegistry.php @@ -11,18 +11,33 @@ namespace Symfony\Bridge\Doctrine; -use Doctrine\Common\Persistence\AbstractManagerRegistry; +use Doctrine\Common\Persistence\AbstractManagerRegistry as LegacyAbstractManagerRegistry; +use Doctrine\Persistence\AbstractManagerRegistry; use ProxyManager\Proxy\LazyLoadingInterface; use Symfony\Component\DependencyInjection\Container; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerInterface as SymfonyContainerInterface; +if (class_exists(AbstractManagerRegistry::class)) { + abstract class ManagerRegistry extends AbstractManagerRegistry implements ContainerAwareInterface + { + use ManagerRegistryTrait; + } +} else { + abstract class ManagerRegistry extends LegacyAbstractManagerRegistry implements ContainerAwareInterface + { + use ManagerRegistryTrait; + } +} + /** * References Doctrine connections and entity/document managers. * * @author Lukas Kahwe Smith + * + * @internal */ -abstract class ManagerRegistry extends AbstractManagerRegistry implements ContainerAwareInterface +trait ManagerRegistryTrait { /** * @var Container diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index 1107146ff0cb8..1902adc0269a4 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -11,11 +11,13 @@ namespace Symfony\Bridge\Doctrine\PropertyInfo; -use Doctrine\Common\Persistence\Mapping\ClassMetadataFactory; -use Doctrine\Common\Persistence\Mapping\MappingException; +use Doctrine\Common\Persistence\Mapping\ClassMetadataFactory as LegacyClassMetadataFactory; +use Doctrine\Common\Persistence\Mapping\MappingException as LegacyMappingException; use Doctrine\DBAL\Types\Type as DBALType; use Doctrine\ORM\Mapping\ClassMetadataInfo; use Doctrine\ORM\Mapping\MappingException as OrmMappingException; +use Doctrine\Persistence\Mapping\ClassMetadataFactory; +use Doctrine\Persistence\Mapping\MappingException; use Symfony\Component\PropertyInfo\PropertyListExtractorInterface; use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface; use Symfony\Component\PropertyInfo\Type; @@ -29,7 +31,10 @@ class DoctrineExtractor implements PropertyListExtractorInterface, PropertyTypeE { private $classMetadataFactory; - public function __construct(ClassMetadataFactory $classMetadataFactory) + /** + * @param ClassMetadataFactory|LegacyClassMetadataFactory $classMetadataFactory + */ + public function __construct($classMetadataFactory) { $this->classMetadataFactory = $classMetadataFactory; } @@ -45,6 +50,8 @@ public function getProperties($class, array $context = []) return null; } catch (OrmMappingException $exception) { return null; + } catch (LegacyMappingException $exception) { + return null; } $properties = array_merge($metadata->getFieldNames(), $metadata->getAssociationNames()); @@ -71,6 +78,8 @@ public function getTypes($class, $property, array $context = []) return null; } catch (OrmMappingException $exception) { return null; + } catch (LegacyMappingException $exception) { + return null; } if ($metadata->hasAssociation($property)) { diff --git a/src/Symfony/Bridge/Doctrine/RegistryInterface.php b/src/Symfony/Bridge/Doctrine/RegistryInterface.php index 6928f8afd4f9c..e5b0c6f573ab9 100644 --- a/src/Symfony/Bridge/Doctrine/RegistryInterface.php +++ b/src/Symfony/Bridge/Doctrine/RegistryInterface.php @@ -11,7 +11,7 @@ namespace Symfony\Bridge\Doctrine; -use Doctrine\Common\Persistence\ManagerRegistry as ManagerRegistryInterface; +use Doctrine\Common\Persistence\ManagerRegistry as LegacyManagerRegistry; use Doctrine\ORM\EntityManager; /** @@ -19,7 +19,7 @@ * * @author Fabien Potencier */ -interface RegistryInterface extends ManagerRegistryInterface +interface RegistryInterface extends LegacyManagerRegistry { /** * Gets the default entity manager name. diff --git a/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php b/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php index 7c630b4e98399..94b7480930a5e 100644 --- a/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php +++ b/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php @@ -11,7 +11,8 @@ namespace Symfony\Bridge\Doctrine\Security\User; -use Doctrine\Common\Persistence\ManagerRegistry; +use Doctrine\Common\Persistence\ManagerRegistry as LegacyManagerRegistry; +use Doctrine\Persistence\ManagerRegistry; use Symfony\Component\Security\Core\Exception\UnsupportedUserException; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; use Symfony\Component\Security\Core\User\UserInterface; @@ -33,7 +34,10 @@ class EntityUserProvider implements UserProviderInterface private $class; private $property; - public function __construct(ManagerRegistry $registry, $classOrAlias, $property = null, $managerName = null) + /** + * @param ManagerRegistry|LegacyManagerRegistry $registry + */ + public function __construct($registry, $classOrAlias, $property = null, $managerName = null) { $this->registry = $registry; $this->managerName = $managerName; @@ -83,11 +87,7 @@ public function refreshUser(UserInterface $user) // That's the case when the user has been changed by a form with // validation errors. if (!$id = $this->getClassMetadata()->getIdentifierValues($user)) { - throw new \InvalidArgumentException('You cannot refresh a user '. - 'from the EntityUserProvider that does not contain an identifier. '. - 'The user object has to be serialized with its own identifier '. - 'mapped by Doctrine.' - ); + throw new \InvalidArgumentException('You cannot refresh a user from the EntityUserProvider that does not contain an identifier. The user object has to be serialized with its own identifier mapped by Doctrine.'); } $refreshedUser = $repository->find($id); diff --git a/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php b/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php index e7df3702ebf1f..8eed972fc2a99 100644 --- a/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php +++ b/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php @@ -11,10 +11,11 @@ namespace Symfony\Bridge\Doctrine\Test; -use Doctrine\Common\Persistence\ObjectRepository; +use Doctrine\Common\Persistence\ObjectRepository as LegacyObjectRepository; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Repository\RepositoryFactory; +use Doctrine\Persistence\ObjectRepository; /** * @author Andreas Braun @@ -28,6 +29,8 @@ final class TestRepositoryFactory implements RepositoryFactory /** * {@inheritdoc} + * + * @return ObjectRepository|LegacyObjectRepository */ public function getRepository(EntityManagerInterface $entityManager, $entityName) { @@ -40,7 +43,7 @@ public function getRepository(EntityManagerInterface $entityManager, $entityName return $this->repositoryList[$repositoryHash] = $this->createRepository($entityManager, $entityName); } - public function setRepository(EntityManagerInterface $entityManager, $entityName, ObjectRepository $repository) + public function setRepository(EntityManagerInterface $entityManager, $entityName, LegacyObjectRepository $repository) { $repositoryHash = $this->getRepositoryHash($entityManager, $entityName); @@ -48,7 +51,7 @@ public function setRepository(EntityManagerInterface $entityManager, $entityName } /** - * @return ObjectRepository + * @return ObjectRepository|LegacyObjectRepository */ private function createRepository(EntityManagerInterface $entityManager, $entityName) { diff --git a/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php b/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php index a789b7a9793fc..bd60c8cc40c1b 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorTest.php @@ -11,8 +11,10 @@ namespace Symfony\Bridge\Doctrine\Tests\DataCollector; +use Doctrine\Common\Persistence\ManagerRegistry as LegacyManagerRegistry; use Doctrine\DBAL\Platforms\MySqlPlatform; use Doctrine\DBAL\Version; +use Doctrine\Persistence\ManagerRegistry; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Doctrine\DataCollector\DoctrineDataCollector; use Symfony\Component\HttpFoundation\Request; @@ -180,7 +182,7 @@ private function createCollector($queries) ->method('getDatabasePlatform') ->willReturn(new MySqlPlatform()); - $registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')->getMock(); + $registry = $this->getMockBuilder(interface_exists(ManagerRegistry::class) ? ManagerRegistry::class : LegacyManagerRegistry::class)->getMock(); $registry ->expects($this->any()) ->method('getConnectionNames') diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/ContainerAwareFixture.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/ContainerAwareFixture.php index 6c3f880eaacf9..7d183351cefe9 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/ContainerAwareFixture.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/ContainerAwareFixture.php @@ -12,7 +12,7 @@ namespace Symfony\Bridge\Doctrine\Tests\Fixtures; use Doctrine\Common\DataFixtures\FixtureInterface; -use Doctrine\Common\Persistence\ObjectManager; +use Doctrine\Common\Persistence\ObjectManager as LegacyObjectManager; use Symfony\Component\DependencyInjection\ContainerAwareInterface; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -25,7 +25,7 @@ public function setContainer(ContainerInterface $container = null) $this->container = $container; } - public function load(ObjectManager $manager) + public function load(LegacyObjectManager $manager) { } } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php index 05657d6e523b3..4428489a8b0df 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/DoctrineChoiceLoaderTest.php @@ -11,9 +11,11 @@ namespace Symfony\Bridge\Doctrine\Tests\Form\ChoiceList; -use Doctrine\Common\Persistence\ObjectManager; -use Doctrine\Common\Persistence\ObjectRepository; +use Doctrine\Common\Persistence\ObjectManager as LegacyObjectManager; +use Doctrine\Common\Persistence\ObjectRepository as LegacyObjectRepository; use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\Persistence\ObjectManager; +use Doctrine\Persistence\ObjectRepository; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Doctrine\Form\ChoiceList\DoctrineChoiceLoader; @@ -75,8 +77,8 @@ class DoctrineChoiceLoaderTest extends TestCase protected function setUp() { $this->factory = $this->getMockBuilder('Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface')->getMock(); - $this->om = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectManager')->getMock(); - $this->repository = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectRepository')->getMock(); + $this->om = $this->getMockBuilder(interface_exists(ObjectManager::class) ? ObjectManager::class : LegacyObjectManager::class)->getMock(); + $this->repository = $this->getMockBuilder(interface_exists(ObjectRepository::class) ? ObjectRepository::class : LegacyObjectRepository::class)->getMock(); $this->class = 'stdClass'; $this->idReader = $this->getMockBuilder('Symfony\Bridge\Doctrine\Form\ChoiceList\IdReader') ->disableOriginalConstructor() diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php index d2e101b4cdc58..226f94e9934cf 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php @@ -11,7 +11,11 @@ namespace Symfony\Bridge\Doctrine\Tests\Form; -use Doctrine\Common\Persistence\Mapping\ClassMetadata; +use Doctrine\Common\Persistence\ManagerRegistry as LegacyManagerRegistry; +use Doctrine\Common\Persistence\ObjectManager as LegacyObjectManager; +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\Persistence\ManagerRegistry; +use Doctrine\Persistence\ObjectManager; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Doctrine\Form\DoctrineOrmTypeGuesser; use Symfony\Component\Form\Guess\Guess; @@ -83,10 +87,10 @@ public function requiredProvider() private function getGuesser(ClassMetadata $classMetadata) { - $em = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectManager')->getMock(); + $em = $this->getMockBuilder(interface_exists(ObjectManager::class) ? ObjectManager::class : LegacyObjectManager::class)->getMock(); $em->expects($this->once())->method('getClassMetaData')->with('TestEntity')->willReturn($classMetadata); - $registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')->getMock(); + $registry = $this->getMockBuilder(interface_exists(ManagerRegistry::class) ? ManagerRegistry::class : LegacyManagerRegistry::class)->getMock(); $registry->expects($this->once())->method('getManagers')->willReturn([$em]); return new DoctrineOrmTypeGuesser($registry); diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypePerformanceTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypePerformanceTest.php index 5dc184fb91009..c23edb3784682 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypePerformanceTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypePerformanceTest.php @@ -11,7 +11,9 @@ namespace Symfony\Bridge\Doctrine\Tests\Form\Type; +use Doctrine\Common\Persistence\ManagerRegistry as LegacyManagerRegistry; use Doctrine\ORM\Tools\SchemaTool; +use Doctrine\Persistence\ManagerRegistry; use Symfony\Bridge\Doctrine\Form\DoctrineOrmExtension; use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper; use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity; @@ -34,7 +36,7 @@ class EntityTypePerformanceTest extends FormPerformanceTestCase protected function getExtensions() { - $manager = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')->getMock(); + $manager = $this->getMockBuilder(interface_exists(ManagerRegistry::class) ? ManagerRegistry::class : LegacyManagerRegistry::class)->getMock(); $manager->expects($this->any()) ->method('getManager') diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php index 147be98b90ce1..bc12de5d427e9 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php @@ -12,10 +12,11 @@ namespace Symfony\Bridge\Doctrine\Tests\Form\Type; use Doctrine\Common\Collections\ArrayCollection; -use Doctrine\Common\Persistence\ManagerRegistry; +use Doctrine\Common\Persistence\ManagerRegistry as LegacyManagerRegistry; use Doctrine\ORM\EntityManager; use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Tools\SchemaTool; +use Doctrine\Persistence\ManagerRegistry; use PHPUnit\Framework\MockObject\MockObject; use Symfony\Bridge\Doctrine\Form\DoctrineOrmExtension; use Symfony\Bridge\Doctrine\Form\DoctrineOrmTypeGuesser; @@ -955,6 +956,31 @@ public function testDisallowChoicesThatAreNotIncludedQueryBuilderSingleIdentifie $this->assertNull($field->getData()); } + public function testDisallowChoicesThatAreNotIncludedQueryBuilderSingleIdentifierWithLimit() + { + $entity1 = new SingleIntIdEntity(1, 'Foo'); + $entity2 = new SingleIntIdEntity(2, 'Bar'); + $entity3 = new SingleIntIdEntity(3, 'Baz'); + + $this->persist([$entity1, $entity2, $entity3]); + + $repository = $this->em->getRepository(self::SINGLE_IDENT_CLASS); + + $field = $this->factory->createNamed('name', static::TESTED_TYPE, null, [ + 'em' => 'default', + 'class' => self::SINGLE_IDENT_CLASS, + 'query_builder' => $repository->createQueryBuilder('e') + ->where('e.id IN (1, 2, 3)') + ->setMaxResults(1), + 'choice_label' => 'name', + ]); + + $field->submit('3'); + + $this->assertFalse($field->isSynchronized()); + $this->assertNull($field->getData()); + } + public function testDisallowChoicesThatAreNotIncludedQueryBuilderSingleAssocIdentifier() { $innerEntity1 = new SingleIntIdNoToStringEntity(1, 'InFoo'); @@ -1228,7 +1254,7 @@ public function testLoaderCachingWithParameters() protected function createRegistryMock($name, $em) { - $registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')->getMock(); + $registry = $this->getMockBuilder(interface_exists(ManagerRegistry::class) ? ManagerRegistry::class : LegacyManagerRegistry::class)->getMock(); $registry->expects($this->any()) ->method('getManager') ->with($this->equalTo($name)) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php index 36bb326eceb33..8916f8fb929e0 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php @@ -11,7 +11,11 @@ namespace Symfony\Bridge\Doctrine\Tests\Security\User; +use Doctrine\Common\Persistence\ManagerRegistry as LegacyManagerRegistry; +use Doctrine\Common\Persistence\ObjectManager as LegacyObjectManager; use Doctrine\ORM\Tools\SchemaTool; +use Doctrine\Persistence\ManagerRegistry; +use Doctrine\Persistence\ObjectManager; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Doctrine\Security\User\EntityUserProvider; use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper; @@ -178,7 +182,7 @@ public function testLoadUserByUserNameShouldDeclineInvalidInterface() private function getManager($em, $name = null) { - $manager = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')->getMock(); + $manager = $this->getMockBuilder(interface_exists(ManagerRegistry::class) ? ManagerRegistry::class : LegacyManagerRegistry::class)->getMock(); $manager->expects($this->any()) ->method('getManager') ->with($this->equalTo($name)) @@ -189,7 +193,7 @@ private function getManager($em, $name = null) private function getObjectManager($repository) { - $em = $this->getMockBuilder('\Doctrine\Common\Persistence\ObjectManager') + $em = $this->getMockBuilder(interface_exists(ObjectManager::class) ? ObjectManager::class : LegacyObjectManager::class) ->setMethods(['getClassMetadata', 'getRepository']) ->getMockForAbstractClass(); $em->expects($this->any()) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php index ff29b1f284c4e..77d15999905ba 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php @@ -12,11 +12,16 @@ namespace Symfony\Bridge\Doctrine\Tests\Validator\Constraints; use Doctrine\Common\Collections\ArrayCollection; -use Doctrine\Common\Persistence\ManagerRegistry; -use Doctrine\Common\Persistence\ObjectManager; -use Doctrine\Common\Persistence\ObjectRepository; +use Doctrine\Common\Persistence\ManagerRegistry as LegacyManagerRegistry; +use Doctrine\Common\Persistence\Mapping\ClassMetadata as LegacyClassMetadata; +use Doctrine\Common\Persistence\ObjectManager as LegacyObjectManager; +use Doctrine\Common\Persistence\ObjectRepository as LegacyObjectRepository; use Doctrine\DBAL\Types\Type; use Doctrine\ORM\Tools\SchemaTool; +use Doctrine\Persistence\ManagerRegistry; +use Doctrine\Persistence\Mapping\ClassMetadata; +use Doctrine\Persistence\ObjectManager; +use Doctrine\Persistence\ObjectRepository; use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper; use Symfony\Bridge\Doctrine\Test\TestRepositoryFactory; use Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity; @@ -76,9 +81,9 @@ protected function setUp() parent::setUp(); } - protected function createRegistryMock(ObjectManager $em = null) + protected function createRegistryMock($em = null) { - $registry = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')->getMock(); + $registry = $this->getMockBuilder(interface_exists(ManagerRegistry::class) ? ManagerRegistry::class : LegacyManagerRegistry::class)->getMock(); $registry->expects($this->any()) ->method('getManager') ->with($this->equalTo(self::EM_NAME)) @@ -89,7 +94,7 @@ protected function createRegistryMock(ObjectManager $em = null) protected function createRepositoryMock() { - $repository = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectRepository') + $repository = $this->getMockBuilder(interface_exists(ObjectRepository::class) ? ObjectRepository::class : LegacyObjectRepository::class) ->setMethods(['findByCustom', 'find', 'findAll', 'findOneBy', 'findBy', 'getClassName']) ->getMock() ; @@ -99,7 +104,7 @@ protected function createRepositoryMock() protected function createEntityManagerMock($repositoryMock) { - $em = $this->getMockBuilder('Doctrine\Common\Persistence\ObjectManager') + $em = $this->getMockBuilder(interface_exists(ObjectManager::class) ? ObjectManager::class : LegacyObjectManager::class) ->getMock() ; $em->expects($this->any()) @@ -107,7 +112,7 @@ protected function createEntityManagerMock($repositoryMock) ->willReturn($repositoryMock) ; - $classMetadata = $this->getMockBuilder('Doctrine\Common\Persistence\Mapping\ClassMetadata')->getMock(); + $classMetadata = $this->getMockBuilder(interface_exists(ClassMetadata::class) ? ClassMetadata::class : LegacyClassMetadata::class)->getMock(); $classMetadata ->expects($this->any()) ->method('hasField') @@ -141,7 +146,7 @@ protected function createValidator() return new UniqueEntityValidator($this->registry); } - private function createSchema(ObjectManager $em) + private function createSchema($em) { $schemaTool = new SchemaTool($em); $schemaTool->createSchema([ diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php index 312b84a71abc8..e6f8c311852bd 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php +++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php @@ -11,9 +11,8 @@ namespace Symfony\Bridge\Doctrine\Validator\Constraints; -use Doctrine\Common\Persistence\ManagerRegistry; -use Doctrine\Common\Persistence\Mapping\ClassMetadata; -use Doctrine\Common\Persistence\ObjectManager; +use Doctrine\Common\Persistence\ManagerRegistry as LegacyManagerRegistry; +use Doctrine\Persistence\ManagerRegistry; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; @@ -28,7 +27,10 @@ class UniqueEntityValidator extends ConstraintValidator { private $registry; - public function __construct(ManagerRegistry $registry) + /** + * @param ManagerRegistry|LegacyManagerRegistry $registry + */ + public function __construct($registry) { $this->registry = $registry; } @@ -42,7 +44,7 @@ public function __construct(ManagerRegistry $registry) public function validate($entity, Constraint $constraint) { if (!$constraint instanceof UniqueEntity) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\UniqueEntity'); + throw new UnexpectedTypeException($constraint, UniqueEntity::class); } if (!\is_array($constraint->fields) && !\is_string($constraint->fields)) { @@ -78,7 +80,6 @@ public function validate($entity, Constraint $constraint) } $class = $em->getClassMetadata(\get_class($entity)); - /* @var $class \Doctrine\Common\Persistence\Mapping\ClassMetadata */ $criteria = []; $hasNullValue = false; @@ -179,7 +180,7 @@ public function validate($entity, Constraint $constraint) ->addViolation(); } - private function formatWithIdentifiers(ObjectManager $em, ClassMetadata $class, $value) + private function formatWithIdentifiers($em, $class, $value) { if (!\is_object($value) || $value instanceof \DateTimeInterface) { return $this->formatValue($value, self::PRETTY_DATE); diff --git a/src/Symfony/Bridge/Doctrine/Validator/DoctrineInitializer.php b/src/Symfony/Bridge/Doctrine/Validator/DoctrineInitializer.php index 010c051581e70..b337be5b1c852 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/DoctrineInitializer.php +++ b/src/Symfony/Bridge/Doctrine/Validator/DoctrineInitializer.php @@ -11,7 +11,8 @@ namespace Symfony\Bridge\Doctrine\Validator; -use Doctrine\Common\Persistence\ManagerRegistry; +use Doctrine\Common\Persistence\ManagerRegistry as LegacyManagerRegistry; +use Doctrine\Persistence\ManagerRegistry; use Symfony\Component\Validator\ObjectInitializerInterface; /** @@ -23,7 +24,10 @@ class DoctrineInitializer implements ObjectInitializerInterface { protected $registry; - public function __construct(ManagerRegistry $registry) + /** + * @param ManagerRegistry|LegacyManagerRegistry $registry + */ + public function __construct($registry) { $this->registry = $registry; } diff --git a/src/Symfony/Bridge/Monolog/LICENSE b/src/Symfony/Bridge/Monolog/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Bridge/Monolog/LICENSE +++ b/src/Symfony/Bridge/Monolog/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php b/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php index 3950268fb2023..2d4529f296fc8 100644 --- a/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php +++ b/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php @@ -22,7 +22,7 @@ class DebugProcessor implements DebugLoggerInterface public function __invoke(array $record) { $this->records[] = [ - 'timestamp' => $record['datetime']->getTimestamp(), + 'timestamp' => $record['datetime'] instanceof \DateTimeInterface ? $record['datetime']->getTimestamp() : strtotime($record['datetime']), 'message' => $record['message'], 'priority' => $record['level'], 'priorityName' => $record['level_name'], diff --git a/src/Symfony/Bridge/Monolog/Tests/Processor/DebugProcessorTest.php b/src/Symfony/Bridge/Monolog/Tests/Processor/DebugProcessorTest.php new file mode 100644 index 0000000000000..d9fcccafcbf9b --- /dev/null +++ b/src/Symfony/Bridge/Monolog/Tests/Processor/DebugProcessorTest.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Tests\Processor; + +use Monolog\Logger; +use PHPUnit\Framework\TestCase; +use Symfony\Bridge\Monolog\Processor\DebugProcessor; + +class DebugProcessorTest extends TestCase +{ + /** + * @dataProvider providerDatetimeFormatTests + */ + public function testDatetimeFormat(array $record, $expectedTimestamp) + { + $processor = new DebugProcessor(); + $processor($record); + + $records = $processor->getLogs(); + self::assertCount(1, $records); + self::assertSame($expectedTimestamp, $records[0]['timestamp']); + } + + /** + * @return array + */ + public function providerDatetimeFormatTests() + { + $record = $this->getRecord(); + + return [ + [array_merge($record, ['datetime' => new \DateTime('2019-01-01T00:01:00+00:00')]), 1546300860], + [array_merge($record, ['datetime' => '2019-01-01T00:01:00+00:00']), 1546300860], + [array_merge($record, ['datetime' => 'foo']), false], + ]; + } + + /** + * @return array + */ + private function getRecord() + { + return [ + 'message' => 'test', + 'context' => [], + 'level' => Logger::DEBUG, + 'level_name' => Logger::getLevelName(Logger::DEBUG), + 'channel' => 'test', + 'datetime' => new \DateTime(), + ]; + } +} diff --git a/src/Symfony/Bridge/PhpUnit/LICENSE b/src/Symfony/Bridge/PhpUnit/LICENSE index cf8b3ebe87145..684fbf94df83c 100644 --- a/src/Symfony/Bridge/PhpUnit/LICENSE +++ b/src/Symfony/Bridge/PhpUnit/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2014-2019 Fabien Potencier +Copyright (c) 2014-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php index 4591f67ed51b8..54c15b67ceedf 100644 --- a/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php +++ b/src/Symfony/Bridge/PhpUnit/Legacy/SymfonyTestsListenerTrait.php @@ -37,7 +37,6 @@ class SymfonyTestsListenerTrait private $gatheredDeprecations = array(); private $previousErrorHandler; private $testsWithWarnings; - private $reportUselessTests; private $error; private $runsInSeparateProcess = false; @@ -198,10 +197,6 @@ public function addSkippedTest($test, \Exception $e, $time) public function startTest($test) { if (-2 < $this->state && ($test instanceof \PHPUnit\Framework\TestCase || $test instanceof TestCase)) { - if (null !== $test->getTestResultObject()) { - $this->reportUselessTests = $test->getTestResultObject()->isStrictAboutTestsThatDoNotTestAnything(); - } - // This event is triggered before the test is re-run in isolation if ($this->willBeIsolated($test)) { $this->runsInSeparateProcess = tempnam(sys_get_temp_dir(), 'deprec'); @@ -267,11 +262,6 @@ public function endTest($test, $time) $classGroups = $Test::getGroups($className); $groups = $Test::getGroups($className, $test->getName(false)); - if (null !== $this->reportUselessTests) { - $test->getTestResultObject()->beStrictAboutTestsThatDoNotTestAnything($this->reportUselessTests); - $this->reportUselessTests = null; - } - if ($errored = null !== $this->error) { $test->getTestResultObject()->addError($test, $this->error, 0); $this->error = null; diff --git a/src/Symfony/Bridge/PhpUnit/Tests/ExpectedDeprecationAnnotationTest.php b/src/Symfony/Bridge/PhpUnit/Tests/ExpectedDeprecationAnnotationTest.php new file mode 100644 index 0000000000000..259c99162a831 --- /dev/null +++ b/src/Symfony/Bridge/PhpUnit/Tests/ExpectedDeprecationAnnotationTest.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\PhpUnit\Tests; + +use PHPUnit\Framework\TestCase; + +final class ExpectedDeprecationAnnotationTest extends TestCase +{ + /** + * Do not remove this test in the next major versions. + * + * @group legacy + * + * @expectedDeprecation foo + */ + public function testOne() + { + @trigger_error('foo', E_USER_DEPRECATED); + } + + /** + * Do not remove this test in the next major versions. + * + * @group legacy + * + * @expectedDeprecation foo + * @expectedDeprecation bar + */ + public function testMany() + { + @trigger_error('foo', E_USER_DEPRECATED); + @trigger_error('bar', E_USER_DEPRECATED); + } +} diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index 262fdd9dea603..11a40d55b6d32 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -15,6 +15,14 @@ error_reporting(-1); +$passthruOrFail = function ($command) { + passthru($command, $status); + + if ($status) { + exit($status); + } +}; + if (PHP_VERSION_ID >= 70200) { // PHPUnit 6 is required for PHP 7.2+ $PHPUNIT_VERSION = getenv('SYMFONY_PHPUNIT_VERSION') ?: '6.5'; @@ -60,7 +68,7 @@ foreach ($defaultEnvs as $envName => $envValue) { $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`)) - ? $PHP.' '.escapeshellarg($COMPOSER) + ? (file_get_contents($COMPOSER, false, null, 0, 18) === '#!/usr/bin/env php' ? $PHP : '').' '.escapeshellarg($COMPOSER) // detect shell wrappers by looking at the shebang : 'composer'; if (false === $SYMFONY_PHPUNIT_REMOVE = getenv('SYMFONY_PHPUNIT_REMOVE')) { @@ -77,25 +85,25 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__ rename("phpunit-$PHPUNIT_VERSION", "phpunit-$PHPUNIT_VERSION.old"); passthru(sprintf('\\' === DIRECTORY_SEPARATOR ? 'rmdir /S /Q %s': 'rm -rf %s', "phpunit-$PHPUNIT_VERSION.old")); } - passthru("$COMPOSER create-project --no-install --prefer-dist --no-scripts --no-plugins --no-progress --ansi phpunit/phpunit phpunit-$PHPUNIT_VERSION \"$PHPUNIT_VERSION.*\""); + $passthruOrFail("$COMPOSER create-project --no-install --prefer-dist --no-scripts --no-plugins --no-progress --ansi phpunit/phpunit phpunit-$PHPUNIT_VERSION \"$PHPUNIT_VERSION.*\""); @copy("phpunit-$PHPUNIT_VERSION/phpunit.xsd", 'phpunit.xsd'); chdir("phpunit-$PHPUNIT_VERSION"); if ($SYMFONY_PHPUNIT_REMOVE) { - passthru("$COMPOSER remove --no-update ".$SYMFONY_PHPUNIT_REMOVE); + $passthruOrFail("$COMPOSER remove --no-update ".$SYMFONY_PHPUNIT_REMOVE); } if (5.1 <= $PHPUNIT_VERSION && $PHPUNIT_VERSION < 5.4) { - passthru("$COMPOSER require --no-update phpunit/phpunit-mock-objects \"~3.1.0\""); + $passthruOrFail("$COMPOSER require --no-update phpunit/phpunit-mock-objects \"~3.1.0\""); } - passthru("$COMPOSER config --unset platform"); + $passthruOrFail("$COMPOSER config --unset platform.php"); if (file_exists($path = $root.'/vendor/symfony/phpunit-bridge')) { - passthru("$COMPOSER require --no-update symfony/phpunit-bridge \"*@dev\""); - passthru("$COMPOSER config repositories.phpunit-bridge path ".escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $path))); + $passthruOrFail("$COMPOSER require --no-update symfony/phpunit-bridge \"*@dev\""); + $passthruOrFail("$COMPOSER config repositories.phpunit-bridge path ".escapeshellarg(str_replace('/', DIRECTORY_SEPARATOR, $path))); if ('\\' === DIRECTORY_SEPARATOR) { file_put_contents('composer.json', preg_replace('/^( {8})"phpunit-bridge": \{$/m', "$0\n$1 ".'"options": {"symlink": false},', file_get_contents('composer.json'))); } } else { - passthru("$COMPOSER require --no-update symfony/phpunit-bridge \"*\""); + $passthruOrFail("$COMPOSER require --no-update symfony/phpunit-bridge \"*\""); } $prevRoot = getenv('COMPOSER_ROOT_VERSION'); putenv("COMPOSER_ROOT_VERSION=$PHPUNIT_VERSION.99"); diff --git a/src/Symfony/Bridge/ProxyManager/LICENSE b/src/Symfony/Bridge/ProxyManager/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Bridge/ProxyManager/LICENSE +++ b/src/Symfony/Bridge/ProxyManager/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php index 1a5c68c04a227..549b154f623f2 100644 --- a/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php +++ b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php @@ -97,6 +97,7 @@ public function getProxyFactoryCode(Definition $definition, $id, $factoryCode = public function getProxyCode(Definition $definition) { $code = $this->classGenerator->generate($this->generateProxyClass($definition)); + $code = preg_replace('/^(class [^ ]++ extends )([^\\\\])/', '$1\\\\$2', $code); $code = preg_replace( '/(\$this->initializer[0-9a-f]++) && \1->__invoke\(\$this->(valueHolder[0-9a-f]++), (.*?), \1\);/', diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_structure.txt b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_structure.txt index 574041b89bbb4..906fff68f7bbe 100644 --- a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_structure.txt +++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_structure.txt @@ -21,5 +21,5 @@ class LazyServiceProjectServiceContainer extends Container } } -class stdClass_%s extends %SstdClass implements \ProxyManager\%s +class stdClass_%s extends \stdClass implements \ProxyManager\%s {%a}%A diff --git a/src/Symfony/Bridge/Twig/LICENSE b/src/Symfony/Bridge/Twig/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Bridge/Twig/LICENSE +++ b/src/Symfony/Bridge/Twig/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index ad4477cba5dea..cee716eb47b33 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -222,13 +222,11 @@ '%name%': name, '%id%': id, }) %} - {%- elseif label is same as(false) -%} - {% set translation_domain = false %} - {%- else -%} + {%- elseif label is not same as(false) -%} {% set label = name|humanize %} {%- endif -%} {%- endif -%} - + {%- endblock button_widget -%} {%- block submit_widget -%} diff --git a/src/Symfony/Bundle/DebugBundle/LICENSE b/src/Symfony/Bundle/DebugBundle/LICENSE index cf8b3ebe87145..684fbf94df83c 100644 --- a/src/Symfony/Bundle/DebugBundle/LICENSE +++ b/src/Symfony/Bundle/DebugBundle/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2014-2019 Fabien Potencier +Copyright (c) 2014-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php index 2143e885c7caa..edbb526f0c707 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ContainerDebugCommand.php @@ -20,6 +20,7 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Console\Style\SymfonyStyle; +use Symfony\Component\DependencyInjection\Compiler\ServiceLocatorTagPass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; @@ -198,6 +199,8 @@ protected function getContainerBuilder() $container->compile(); } else { (new XmlFileLoader($container = new ContainerBuilder(), new FileLocator()))->load($kernel->getContainer()->getParameter('debug.container.dump')); + $locatorPass = new ServiceLocatorTagPass(); + $locatorPass->process($container); } return $this->containerBuilder = $container; diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php index 7375450d5d219..fcf145cc4603f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php @@ -200,12 +200,12 @@ protected function execute(InputInterface $input, OutputInterface $output) } } - $errorIo->title('Translation Messages Extractor and Dumper'); - $errorIo->comment(sprintf('Generating "%s" translation files for "%s"', $input->getArgument('locale'), $currentName)); + $io->title('Translation Messages Extractor and Dumper'); + $io->comment(sprintf('Generating "%s" translation files for "%s"', $input->getArgument('locale'), $currentName)); // load any messages from templates $extractedCatalogue = new MessageCatalogue($input->getArgument('locale')); - $errorIo->comment('Parsing templates...'); + $io->comment('Parsing templates...'); $prefix = $input->getOption('prefix'); // @deprecated since version 3.4, to be removed in 4.0 along with the --no-prefix option if ($input->getOption('no-prefix')) { @@ -221,7 +221,7 @@ protected function execute(InputInterface $input, OutputInterface $output) // load any existing messages from the translation files $currentCatalogue = new MessageCatalogue($input->getArgument('locale')); - $errorIo->comment('Loading translation files...'); + $io->comment('Loading translation files...'); foreach ($transPaths as $path) { if (is_dir($path)) { $this->reader->read($path, $currentCatalogue); @@ -274,7 +274,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } if ('xlf' == $input->getOption('output-format')) { - $errorIo->comment('Xliff output version is 1.2'); + $io->comment('Xliff output version is 1.2'); } $resultMessage = sprintf('%d message%s successfully extracted', $extractedMessagesCount, $extractedMessagesCount > 1 ? 's were' : ' was'); @@ -286,7 +286,7 @@ protected function execute(InputInterface $input, OutputInterface $output) // save the files if (true === $input->getOption('force')) { - $errorIo->comment('Writing files...'); + $io->comment('Writing files...'); $bundleTransPath = false; foreach ($transPaths as $path) { @@ -306,7 +306,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } } - $errorIo->success($resultMessage.'.'); + $io->success($resultMessage.'.'); return null; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php b/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php index 2d0944e19e1ed..106ecc87d724f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/AbstractController.php @@ -11,7 +11,8 @@ namespace Symfony\Bundle\FrameworkBundle\Controller; -use Doctrine\Common\Persistence\ManagerRegistry; +use Doctrine\Common\Persistence\ManagerRegistry as LegacyManagerRegistry; +use Doctrine\Persistence\ManagerRegistry; use Psr\Container\ContainerInterface; use Symfony\Component\DependencyInjection\ServiceSubscriberInterface; use Symfony\Component\Form\FormFactoryInterface; @@ -63,7 +64,7 @@ public static function getSubscribedServices() 'security.authorization_checker' => '?'.AuthorizationCheckerInterface::class, 'templating' => '?'.EngineInterface::class, 'twig' => '?'.Environment::class, - 'doctrine' => '?'.ManagerRegistry::class, + 'doctrine' => '?'.(interface_exists(ManagerRegistry::class) ? ManagerRegistry::class : LegacyManagerRegistry::class), 'form.factory' => '?'.FormFactoryInterface::class, 'security.token_storage' => '?'.TokenStorageInterface::class, 'security.csrf.token_manager' => '?'.CsrfTokenManagerInterface::class, diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php index cb339cd15ea4c..9d5640750af84 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php @@ -11,7 +11,8 @@ namespace Symfony\Bundle\FrameworkBundle\Controller; -use Doctrine\Common\Persistence\ManagerRegistry; +use Doctrine\Common\Persistence\ManagerRegistry as LegacyManagerRegistry; +use Doctrine\Persistence\ManagerRegistry; use Psr\Container\ContainerInterface; use Symfony\Component\Form\Extension\Core\Type\FormType; use Symfony\Component\Form\FormBuilderInterface; @@ -26,6 +27,7 @@ use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException; +use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Csrf\CsrfToken; /** @@ -413,7 +415,7 @@ protected function createFormBuilder($data = null, array $options = []) /** * Shortcut to return the Doctrine Registry service. * - * @return ManagerRegistry + * @return ManagerRegistry|LegacyManagerRegistry * * @throws \LogicException If DoctrineBundle is not available * @@ -431,7 +433,7 @@ protected function getDoctrine() /** * Get a user from the Security Token Storage. * - * @return object|null + * @return UserInterface|object|null * * @throws \LogicException If SecurityBundle is not available * diff --git a/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php b/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php index 6d79c6a90e29e..c5220f350ca86 100644 --- a/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php +++ b/src/Symfony/Bundle/FrameworkBundle/HttpCache/HttpCache.php @@ -37,7 +37,14 @@ public function __construct(KernelInterface $kernel, $cacheDir = null) $this->kernel = $kernel; $this->cacheDir = $cacheDir; - parent::__construct($kernel, $this->createStore(), $this->createSurrogate(), array_merge(['debug' => $kernel->isDebug()], $this->getOptions())); + $isDebug = $kernel->isDebug(); + $options = ['debug' => $isDebug]; + + if ($isDebug) { + $options['stale_if_error'] = 0; + } + + parent::__construct($kernel, $this->createStore(), $this->createSurrogate(), array_merge($options, $this->getOptions())); } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/LICENSE b/src/Symfony/Bundle/FrameworkBundle/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/LICENSE +++ b/src/Symfony/Bundle/FrameworkBundle/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php b/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php index 22dbe3c972890..ccfd3b5b3d495 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php +++ b/src/Symfony/Bundle/FrameworkBundle/Templating/TemplateNameParser.php @@ -44,7 +44,7 @@ public function parse($name) } // normalize name - $name = str_replace(':/', ':', preg_replace('#/{2,}#', '/', str_replace('\\', '/', $name))); + $name = preg_replace('#/{2,}#', '/', str_replace('\\', '/', $name)); if (false !== strpos($name, '..')) { throw new \RuntimeException(sprintf('Template name "%s" contains invalid characters.', $name)); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php index c039345653fd2..f71c4c8cae2ee 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/ControllerTraitTest.php @@ -11,6 +11,8 @@ namespace Symfony\Bundle\FrameworkBundle\Tests\Controller; +use Doctrine\Common\Persistence\ManagerRegistry as LegacyManagerRegistry; +use Doctrine\Persistence\ManagerRegistry; use Symfony\Bundle\FrameworkBundle\Controller\ControllerTrait; use Symfony\Bundle\FrameworkBundle\Tests\TestCase; use Symfony\Component\DependencyInjection\Container; @@ -513,7 +515,7 @@ public function testCreateFormBuilder() public function testGetDoctrine() { - $doctrine = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')->getMock(); + $doctrine = $this->getMockBuilder(interface_exists(ManagerRegistry::class) ? ManagerRegistry::class : LegacyManagerRegistry::class)->getMock(); $container = new Container(); $container->set('doctrine', $doctrine); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/TemplateNameParserTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/TemplateNameParserTest.php index b9cb308592c53..0b1d6f376f0e9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/TemplateNameParserTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/TemplateNameParserTest.php @@ -98,8 +98,8 @@ public function provideAbsolutePaths() { return [ ['/path/to/section/index.html.php', '/path/to/section/index.html.php', '/path/to/section/index.html.php', new BaseTemplateReference('/path/to/section/index.html.php', 'php')], - ['C:\\path\\to\\section\\name.html.php', 'C:path/to/section/name.html.php', 'C:path/to/section/name.html.php', new BaseTemplateReference('C:path/to/section/name.html.php', 'php')], - ['C:\\path\\to\\section\\name:foo.html.php', 'C:path/to/section/name:foo.html.php', 'C:path/to/section/name:foo.html.php', new BaseTemplateReference('C:path/to/section/name:foo.html.php', 'php')], + ['C:\\path\\to\\section\\name.html.php', 'C:/path/to/section/name.html.php', 'C:/path/to/section/name.html.php', new BaseTemplateReference('C:/path/to/section/name.html.php', 'php')], + ['C:\\path\\to\\section\\name:foo.html.php', 'C:/path/to/section/name:foo.html.php', 'C:/path/to/section/name:foo.html.php', new BaseTemplateReference('C:/path/to/section/name:foo.html.php', 'php')], ['\\path\\to\\section\\name.html.php', '/path/to/section/name.html.php', '/path/to/section/name.html.php', new BaseTemplateReference('/path/to/section/name.html.php', 'php')], ['/path/to/section/name.php', '/path/to/section/name.php', '/path/to/section/name.php', new BaseTemplateReference('/path/to/section/name.php', 'php')], ]; diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSessionDomainConstraintPass.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSessionDomainConstraintPass.php index 27098f8b19336..7fd323a5f21f7 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSessionDomainConstraintPass.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Compiler/AddSessionDomainConstraintPass.php @@ -31,7 +31,7 @@ public function process(ContainerBuilder $container) } $sessionOptions = $container->getParameter('session.storage.options'); - $domainRegexp = empty($sessionOptions['cookie_domain']) ? '%s' : sprintf('(?:%%s|(?:.+\.)?%s)', preg_quote(trim($sessionOptions['cookie_domain'], '.'))); + $domainRegexp = empty($sessionOptions['cookie_domain']) ? '%%s' : sprintf('(?:%%%%s|(?:.+\.)?%s)', preg_quote(trim($sessionOptions['cookie_domain'], '.'))); $domainRegexp = (empty($sessionOptions['cookie_secure']) ? 'https?://' : 'https://').$domainRegexp; $container->findDefinition('security.http_utils')->addArgument(sprintf('{^%s$}i', $domainRegexp)); diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index 4868dbe82f380..251c7bb6a905b 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -421,7 +421,13 @@ private function addEncodersSection(ArrayNodeDefinition $rootNode) ->performNoDeepMerging() ->beforeNormalization()->ifString()->then(function ($v) { return ['algorithm' => $v]; })->end() ->children() - ->scalarNode('algorithm')->cannotBeEmpty()->end() + ->scalarNode('algorithm') + ->cannotBeEmpty() + ->validate() + ->ifTrue(function ($v) { return !\is_string($v); }) + ->thenInvalid('You must provide a string value.') + ->end() + ->end() ->scalarNode('hash_algorithm')->info('Name of hashing algorithm for PBKDF2 (i.e. sha256, sha512, etc..) See hash_algos() for a list of supported algorithms.')->defaultValue('sha512')->end() ->scalarNode('key_length')->defaultValue(40)->end() ->booleanNode('ignore_case')->defaultFalse()->end() diff --git a/src/Symfony/Bundle/SecurityBundle/LICENSE b/src/Symfony/Bundle/SecurityBundle/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Bundle/SecurityBundle/LICENSE +++ b/src/Symfony/Bundle/SecurityBundle/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bundle/SecurityBundle/Security/FirewallMap.php b/src/Symfony/Bundle/SecurityBundle/Security/FirewallMap.php index 3bb16b26c765a..9e20f4e527c39 100644 --- a/src/Symfony/Bundle/SecurityBundle/Security/FirewallMap.php +++ b/src/Symfony/Bundle/SecurityBundle/Security/FirewallMap.php @@ -107,13 +107,11 @@ class _FirewallMap { private $container; private $map; - private $contexts; public function __construct(ContainerInterface $container, $map) { $this->container = $container; $this->map = $map; - $this->contexts = new \SplObjectStorage(); } public function getListeners(Request $request) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php index 3a1046b0c4a17..51f56c220d33c 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/ClearRememberMeTest.php @@ -33,7 +33,7 @@ public function testUserChangeClearsCookie() $this->assertNotNull($cookieJar->get('REMEMBERME')); $client->request('GET', '/foo'); - $this->assertSame(200, $client->getResponse()->getStatusCode()); + $this->assertRedirect($client->getResponse(), '/login'); $this->assertNull($cookieJar->get('REMEMBERME')); } } diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 1a8057b6fbd08..f0e35c7f3d7e8 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -19,7 +19,7 @@ "php": "^5.5.9|>=7.0.8", "ext-xml": "*", "symfony/config": "~3.4|~4.0", - "symfony/security": "~3.4.36|~4.3.9|^4.4.1", + "symfony/security": "~3.4.37|~4.3.10|^4.4.3", "symfony/dependency-injection": "^3.4.3|^4.0.3", "symfony/http-kernel": "~3.4|~4.0", "symfony/polyfill-php70": "~1.0" diff --git a/src/Symfony/Bundle/TwigBundle/LICENSE b/src/Symfony/Bundle/TwigBundle/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Bundle/TwigBundle/LICENSE +++ b/src/Symfony/Bundle/TwigBundle/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bundle/TwigBundle/TwigBundle.php b/src/Symfony/Bundle/TwigBundle/TwigBundle.php index bd766c15219e7..5a353833eb27c 100644 --- a/src/Symfony/Bundle/TwigBundle/TwigBundle.php +++ b/src/Symfony/Bundle/TwigBundle/TwigBundle.php @@ -32,7 +32,8 @@ public function build(ContainerBuilder $container) { parent::build($container); - $container->addCompilerPass(new ExtensionPass()); + // ExtensionPass must be run before the FragmentRendererPass as it adds tags that are processed later + $container->addCompilerPass(new ExtensionPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 10); $container->addCompilerPass(new TwigEnvironmentPass()); $container->addCompilerPass(new TwigLoaderPass()); $container->addCompilerPass(new ExceptionListenerPass()); diff --git a/src/Symfony/Bundle/WebProfilerBundle/LICENSE b/src/Symfony/Bundle/WebProfilerBundle/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/LICENSE +++ b/src/Symfony/Bundle/WebProfilerBundle/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/info.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/info.html.twig index 0227532e1208a..43404393ec360 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/info.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/info.html.twig @@ -4,7 +4,7 @@ 'no_token' : { status: 'error', title: (token|default('') == 'latest') ? 'There are no profiles' : 'Token not found', - message: (token|default('') == 'latest') ? 'No profiles found in the database.' : 'Token "' ~ token|default('') ~ '" was not found in the database.' + message: (token|default('') == 'latest') ? 'No profiles found.' : 'Token "' ~ token|default('') ~ '" not found.' } } %} diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php index c55c67e537a02..78edaac89e5f2 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/Controller/ProfilerControllerTest.php @@ -11,19 +11,110 @@ namespace Symfony\Bundle\WebProfilerBundle\Tests\Controller; -use PHPUnit\Framework\TestCase; +use Symfony\Bundle\FrameworkBundle\Client; +use Symfony\Bundle\FrameworkBundle\Test\WebTestCase; use Symfony\Bundle\WebProfilerBundle\Controller\ProfilerController; use Symfony\Bundle\WebProfilerBundle\Csp\ContentSecurityPolicyHandler; +use Symfony\Bundle\WebProfilerBundle\Tests\Functional\WebProfilerBundleKernel; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Profiler\Profile; -class ProfilerControllerTest extends TestCase +class ProfilerControllerTest extends WebTestCase { + public function testHomeActionWithProfilerDisabled() + { + $this->expectException(NotFoundHttpException::class); + $this->expectExceptionMessage('The profiler must be enabled.'); + + $urlGenerator = $this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGeneratorInterface')->getMock(); + $twig = $this->getMockBuilder('Twig\Environment')->disableOriginalConstructor()->getMock(); + + $controller = new ProfilerController($urlGenerator, null, $twig, []); + $controller->homeAction(); + } + + public function testHomeActionRedirect() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + + $client->request('GET', '/_profiler/'); + + $this->assertSame(302, $client->getResponse()->getStatusCode()); + $this->assertSame('/_profiler/empty/search/results?limit=10', $client->getResponse()->getTargetUrl()); + } + + public function testPanelActionWithLatestTokenWhenNoTokensExist() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + + $client->request('GET', '/_profiler/latest'); + + $this->assertStringContainsString('No profiles found.', $client->getResponse()->getContent()); + } + + public function testPanelActionWithLatestToken() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + + $client->request('GET', '/'); + $client->request('GET', '/_profiler/latest'); + + $this->assertStringContainsString('kernel:homepageController', $client->getResponse()->getContent()); + } + + public function testPanelActionWithoutValidToken() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + + $client->request('GET', '/_profiler/this-token-does-not-exist'); + + $this->assertStringContainsString('Token "this-token-does-not-exist" not found.', $client->getResponse()->getContent()); + } + + public function testPanelActionWithWrongPanel() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + + $client->request('GET', '/'); + $client->request('GET', '/_profiler/latest?panel=this-panel-does-not-exist'); + + $this->assertSame(404, $client->getResponse()->getStatusCode()); + } + + public function testPanelActionWithValidPanelAndToken() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + + $client->request('GET', '/'); + $crawler = $client->request('GET', '/_profiler/latest?panel=router'); + + $this->assertSame('_', $crawler->filter('.metrics .metric .value')->eq(0)->text()); + $this->assertSame('12', $crawler->filter('.metrics .metric .value')->eq(1)->text()); + } + + public function testToolbarActionWithProfilerDisabled() + { + $this->expectException(NotFoundHttpException::class); + $this->expectExceptionMessage('The profiler must be enabled.'); + + $urlGenerator = $this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGeneratorInterface')->getMock(); + $twig = $this->getMockBuilder('Twig\Environment')->disableOriginalConstructor()->getMock(); + + $controller = new ProfilerController($urlGenerator, null, $twig, []); + $controller->toolbarAction(Request::create('/_wdt/foo-token'), null); + } + /** * @dataProvider getEmptyTokenCases */ - public function testEmptyToken($token) + public function testToolbarActionWithEmptyToken($token) { $urlGenerator = $this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGeneratorInterface')->getMock(); $twig = $this->getMockBuilder('Twig\Environment')->disableOriginalConstructor()->getMock(); @@ -111,10 +202,36 @@ public function testReturns404onTokenNotFound($withCsp) $this->assertEquals(404, $response->getStatusCode()); } + public function testSearchBarActionWithProfilerDisabled() + { + $this->expectException(NotFoundHttpException::class); + $this->expectExceptionMessage('The profiler must be enabled.'); + + $urlGenerator = $this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGeneratorInterface')->getMock(); + $twig = $this->getMockBuilder('Twig\Environment')->disableOriginalConstructor()->getMock(); + + $controller = new ProfilerController($urlGenerator, null, $twig, []); + $controller->searchBarAction(Request::create('/_profiler/search_bar')); + } + + public function testSearchBarActionDefaultPage() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + + $crawler = $client->request('GET', '/_profiler/search_bar'); + + $this->assertSame(200, $client->getResponse()->getStatusCode()); + + foreach (['ip', 'status_code', 'url', 'token', 'start', 'end'] as $searchCriteria) { + $this->assertSame('', $crawler->filter(sprintf('form input[name="%s"]', $searchCriteria))->text()); + } + } + /** * @dataProvider provideCspVariants */ - public function testSearchResult($withCsp) + public function testSearchResultsAction($withCsp) { $twig = $this->getMockBuilder('Twig\Environment')->disableOriginalConstructor()->getMock(); $profiler = $this @@ -177,6 +294,67 @@ public function testSearchResult($withCsp) $this->assertEquals(200, $response->getStatusCode()); } + public function testSearchActionWithProfilerDisabled() + { + $this->expectException(NotFoundHttpException::class); + $this->expectExceptionMessage('The profiler must be enabled.'); + + $urlGenerator = $this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGeneratorInterface')->getMock(); + $twig = $this->getMockBuilder('Twig\Environment')->disableOriginalConstructor()->getMock(); + + $controller = new ProfilerController($urlGenerator, null, $twig, []); + $controller->searchBarAction(Request::create('/_profiler/search')); + } + + public function testSearchActionWithToken() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + + $client->request('GET', '/'); + $token = $client->getResponse()->headers->get('x-debug-token'); + $client->request('GET', '/_profiler/search?token='.$token); + + $this->assertSame(302, $client->getResponse()->getStatusCode()); + $this->assertSame('/_profiler/'.$token, $client->getResponse()->getTargetUrl()); + } + + public function testSearchActionWithoutToken() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + $client->followRedirects(); + + $client->request('GET', '/'); + $token = $client->getResponse()->headers->get('x-debug-token'); + $client->request('GET', '/_profiler/search?ip=&method=GET&status_code=&url=&token=&start=&end=&limit=10'); + + $this->assertStringContainsString('results found', $client->getResponse()->getContent()); + $this->assertStringContainsString(sprintf('%s', $token, $token), $client->getResponse()->getContent()); + } + + public function testPhpinfoActionWithProfilerDisabled() + { + $this->expectException(NotFoundHttpException::class); + $this->expectExceptionMessage('The profiler must be enabled.'); + + $urlGenerator = $this->getMockBuilder('Symfony\Component\Routing\Generator\UrlGeneratorInterface')->getMock(); + $twig = $this->getMockBuilder('Twig\Environment')->disableOriginalConstructor()->getMock(); + + $controller = new ProfilerController($urlGenerator, null, $twig, []); + $controller->phpinfoAction(Request::create('/_profiler/phpinfo')); + } + + public function testPhpinfoAction() + { + $kernel = new WebProfilerBundleKernel(); + $client = new Client($kernel); + + $client->request('GET', '/_profiler/phpinfo'); + + $this->assertStringContainsString('PHP License', $client->getResponse()->getContent()); + } + public function provideCspVariants() { return [ diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/Functional/WebProfilerBundleKernel.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/Functional/WebProfilerBundleKernel.php new file mode 100644 index 0000000000000..5470ca7dc6858 --- /dev/null +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/Functional/WebProfilerBundleKernel.php @@ -0,0 +1,80 @@ +name) { + $this->name = parent::getName().substr(md5(__CLASS__), -16); + } + + return $this->name; + } + + public function registerBundles() + { + return [ + new FrameworkBundle(), + new TwigBundle(), + new WebProfilerBundle(), + ]; + } + + protected function configureRoutes(RouteCollectionBuilder $routes) + { + $routes->import(__DIR__.'/../../Resources/config/routing/profiler.xml', '/_profiler'); + $routes->import(__DIR__.'/../../Resources/config/routing/wdt.xml', '/_wdt'); + $routes->add('/', 'kernel:homepageController'); + } + + protected function configureContainer(ContainerBuilder $containerBuilder, LoaderInterface $loader) + { + $containerBuilder->loadFromExtension('framework', [ + 'secret' => 'foo-secret', + 'profiler' => ['only_exceptions' => false], + 'session' => ['storage_id' => 'session.storage.mock_file'], + ]); + + $containerBuilder->loadFromExtension('web_profiler', [ + 'toolbar' => true, + 'intercept_redirects' => false, + ]); + } + + public function getCacheDir() + { + return sys_get_temp_dir().'/cache-'.spl_object_hash($this); + } + + public function getLogDir() + { + return sys_get_temp_dir().'/log-'.spl_object_hash($this); + } + + public function homepageController() + { + return new Response('Homepage Controller.'); + } +} diff --git a/src/Symfony/Bundle/WebProfilerBundle/composer.json b/src/Symfony/Bundle/WebProfilerBundle/composer.json index c82ef0fe0093d..6f254c67cc482 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/composer.json +++ b/src/Symfony/Bundle/WebProfilerBundle/composer.json @@ -17,21 +17,22 @@ ], "require": { "php": "^5.5.9|>=7.0.8", + "symfony/config": "~3.4|~4.0", "symfony/http-kernel": "~3.4.25|^4.2.6", "symfony/polyfill-php70": "~1.0", - "symfony/routing": "~2.8|~3.0|~4.0", - "symfony/twig-bundle": "~2.8|~3.0|~4.0", + "symfony/routing": "~3.4.7|~4.0", + "symfony/twig-bundle": "~3.4|~4.0", "symfony/var-dumper": "~3.3|~4.0", "twig/twig": "~1.34|~2.4" }, "require-dev": { - "symfony/config": "~3.4|~4.0", - "symfony/console": "~2.8|~3.0|~4.0", - "symfony/dependency-injection": "~3.4|~4.0", - "symfony/stopwatch": "~2.8|~3.0|~4.0" + "symfony/browser-kit": "~3.4|~4.0", + "symfony/console": "~3.4|~4.0", + "symfony/css-selector": "~3.4|~4.0", + "symfony/framework-bundle": "~3.4|~4.0", + "symfony/stopwatch": "~3.4|~4.0" }, "conflict": { - "symfony/config": "<3.4", "symfony/dependency-injection": "<3.4", "symfony/event-dispatcher": "<3.3.1", "symfony/var-dumper": "<3.3" diff --git a/src/Symfony/Bundle/WebServerBundle/LICENSE b/src/Symfony/Bundle/WebServerBundle/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Bundle/WebServerBundle/LICENSE +++ b/src/Symfony/Bundle/WebServerBundle/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Asset/LICENSE b/src/Symfony/Component/Asset/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Asset/LICENSE +++ b/src/Symfony/Component/Asset/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/BrowserKit/LICENSE b/src/Symfony/Component/BrowserKit/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/BrowserKit/LICENSE +++ b/src/Symfony/Component/BrowserKit/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php b/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php index e03d37b94de41..6df00d1d33712 100644 --- a/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php @@ -61,14 +61,13 @@ static function ($key, $value, $isHit) { * fallback pool with this adapter only if the current PHP version is supported. * * @param string $file The PHP file were values are cached - * @param CacheItemPoolInterface $fallbackPool Fallback for old PHP versions or opcache disabled + * @param CacheItemPoolInterface $fallbackPool A pool to fallback on when an item is not hit * * @return CacheItemPoolInterface */ public static function create($file, CacheItemPoolInterface $fallbackPool) { - // Shared memory is available in PHP 7.0+ with OPCache enabled and in HHVM - if ((\PHP_VERSION_ID >= 70000 && filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN)) || \defined('HHVM_VERSION')) { + if (\PHP_VERSION_ID >= 70000) { if (!$fallbackPool instanceof AdapterInterface) { $fallbackPool = new ProxyAdapter($fallbackPool); } diff --git a/src/Symfony/Component/Cache/LICENSE b/src/Symfony/Component/Cache/LICENSE index 3c464ca94359b..a7ec70801827a 100644 --- a/src/Symfony/Component/Cache/LICENSE +++ b/src/Symfony/Component/Cache/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2016-2019 Fabien Potencier +Copyright (c) 2016-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Cache/Simple/PhpArrayCache.php b/src/Symfony/Component/Cache/Simple/PhpArrayCache.php index 607555e93b660..5ded7ee741ec7 100644 --- a/src/Symfony/Component/Cache/Simple/PhpArrayCache.php +++ b/src/Symfony/Component/Cache/Simple/PhpArrayCache.php @@ -44,14 +44,14 @@ public function __construct($file, CacheInterface $fallbackPool) * stores arrays in its latest versions. This factory method decorates the given * fallback pool with this adapter only if the current PHP version is supported. * - * @param string $file The PHP file were values are cached + * @param string $file The PHP file were values are cached + * @param CacheInterface $fallbackPool A pool to fallback on when an item is not hit * * @return CacheInterface */ public static function create($file, CacheInterface $fallbackPool) { - // Shared memory is available in PHP 7.0+ with OPCache enabled and in HHVM - if ((\PHP_VERSION_ID >= 70000 && filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN)) || \defined('HHVM_VERSION')) { + if (\PHP_VERSION_ID >= 70000) { return new static($file, $fallbackPool); } diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php index 751f758cc2c0b..f88a7187394ab 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterTest.php @@ -62,6 +62,8 @@ public static function setUpBeforeClass() protected function tearDown() { + $this->createCachePool()->clear(); + if (file_exists(sys_get_temp_dir().'/symfony-cache')) { FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache'); } diff --git a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterWithFallbackTest.php b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterWithFallbackTest.php index 4bdd7580fc557..0bfd5c3947bf4 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterWithFallbackTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/PhpArrayAdapterWithFallbackTest.php @@ -37,6 +37,8 @@ public static function setUpBeforeClass() protected function tearDown() { + $this->createCachePool()->clear(); + if (file_exists(sys_get_temp_dir().'/symfony-cache')) { FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache'); } diff --git a/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheTest.php b/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheTest.php index c18f714429614..bcd7dea55391b 100644 --- a/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheTest.php +++ b/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheTest.php @@ -56,6 +56,8 @@ public static function setUpBeforeClass() protected function tearDown() { + $this->createSimpleCache()->clear(); + if (file_exists(sys_get_temp_dir().'/symfony-cache')) { FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache'); } diff --git a/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php b/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php index eba749cece224..b08c16043c200 100644 --- a/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php +++ b/src/Symfony/Component/Cache/Tests/Simple/PhpArrayCacheWithFallbackTest.php @@ -43,6 +43,8 @@ public static function setUpBeforeClass() protected function tearDown() { + $this->createSimpleCache()->clear(); + if (file_exists(sys_get_temp_dir().'/symfony-cache')) { FilesystemAdapterTest::rmdir(sys_get_temp_dir().'/symfony-cache'); } diff --git a/src/Symfony/Component/Cache/Traits/PhpArrayTrait.php b/src/Symfony/Component/Cache/Traits/PhpArrayTrait.php index ea996a217cf13..2400486f80557 100644 --- a/src/Symfony/Component/Cache/Traits/PhpArrayTrait.php +++ b/src/Symfony/Component/Cache/Traits/PhpArrayTrait.php @@ -28,6 +28,8 @@ trait PhpArrayTrait private $values; private $zendDetectUnicode; + private static $valuesCache = []; + /** * Store an array of cached values. * @@ -107,6 +109,7 @@ public function warmUp(array $values) unset($serialized, $unserialized, $value, $dump); @rename($tmpFile, $this->file); + unset(self::$valuesCache[$this->file]); $this->initialize(); } @@ -119,6 +122,7 @@ public function clear() $this->values = []; $cleared = @unlink($this->file) || !file_exists($this->file); + unset(self::$valuesCache[$this->file]); return $this->pool->clear() && $cleared; } @@ -128,11 +132,17 @@ public function clear() */ private function initialize() { + if (isset(self::$valuesCache[$this->file])) { + $this->values = self::$valuesCache[$this->file]; + + return; + } + if ($this->zendDetectUnicode) { $zmb = ini_set('zend.detect_unicode', 0); } try { - $this->values = file_exists($this->file) ? (include $this->file ?: []) : []; + $this->values = self::$valuesCache[$this->file] = file_exists($this->file) ? (include $this->file ?: []) : []; } finally { if ($this->zendDetectUnicode) { ini_set('zend.detect_unicode', $zmb); diff --git a/src/Symfony/Component/ClassLoader/LICENSE b/src/Symfony/Component/ClassLoader/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/ClassLoader/LICENSE +++ b/src/Symfony/Component/ClassLoader/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/ClassLoader/README.md b/src/Symfony/Component/ClassLoader/README.md index d61992b6a80e7..96d1e9fe5a5ce 100644 --- a/src/Symfony/Component/ClassLoader/README.md +++ b/src/Symfony/Component/ClassLoader/README.md @@ -7,7 +7,7 @@ their locations for performance. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/class_loader/index.html) + * [Documentation](https://symfony.com/doc/current/components/class_loader.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php b/src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php index 63c0d696b4fa0..2809cb6c6f601 100644 --- a/src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php +++ b/src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php @@ -24,13 +24,13 @@ class NodeBuilder implements NodeParentInterface public function __construct() { $this->nodeMapping = [ - 'variable' => __NAMESPACE__.'\\VariableNodeDefinition', - 'scalar' => __NAMESPACE__.'\\ScalarNodeDefinition', - 'boolean' => __NAMESPACE__.'\\BooleanNodeDefinition', - 'integer' => __NAMESPACE__.'\\IntegerNodeDefinition', - 'float' => __NAMESPACE__.'\\FloatNodeDefinition', - 'array' => __NAMESPACE__.'\\ArrayNodeDefinition', - 'enum' => __NAMESPACE__.'\\EnumNodeDefinition', + 'variable' => VariableNodeDefinition::class, + 'scalar' => ScalarNodeDefinition::class, + 'boolean' => BooleanNodeDefinition::class, + 'integer' => IntegerNodeDefinition::class, + 'float' => FloatNodeDefinition::class, + 'array' => ArrayNodeDefinition::class, + 'enum' => EnumNodeDefinition::class, ]; } diff --git a/src/Symfony/Component/Config/LICENSE b/src/Symfony/Component/Config/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Config/LICENSE +++ b/src/Symfony/Component/Config/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Config/README.md b/src/Symfony/Component/Config/README.md index bf400da196b22..0bbde55230a21 100644 --- a/src/Symfony/Component/Config/README.md +++ b/src/Symfony/Component/Config/README.md @@ -8,7 +8,7 @@ may be (YAML, XML, INI files, or for instance a database). Resources --------- - * [Documentation](https://symfony.com/doc/current/components/config/index.html) + * [Documentation](https://symfony.com/doc/current/components/config.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Config/Resource/ClassExistenceResource.php b/src/Symfony/Component/Config/Resource/ClassExistenceResource.php index 4e0d0d834e6ab..685da72850e55 100644 --- a/src/Symfony/Component/Config/Resource/ClassExistenceResource.php +++ b/src/Symfony/Component/Config/Resource/ClassExistenceResource.php @@ -36,7 +36,7 @@ public function __construct($resource, $exists = null) { $this->resource = $resource; if (null !== $exists) { - $this->exists = (bool) $exists; + $this->exists = [(bool) $exists, null]; } } @@ -65,9 +65,13 @@ public function isFresh($timestamp) { $loaded = class_exists($this->resource, false) || interface_exists($this->resource, false) || trait_exists($this->resource, false); - if (null !== $exists = &self::$existsCache[(int) (0 >= $timestamp)][$this->resource]) { - $exists = $exists || $loaded; - } elseif (!$exists = $loaded) { + if (null !== $exists = &self::$existsCache[$this->resource]) { + if ($loaded) { + $exists = [true, null]; + } elseif (0 >= $timestamp && !$exists[0] && null !== $exists[1]) { + throw new \ReflectionException($exists[1]); + } + } elseif ([false, null] === $exists = [$loaded, null]) { if (!self::$autoloadLevel++) { spl_autoload_register(__CLASS__.'::throwOnRequiredClass'); } @@ -75,16 +79,19 @@ public function isFresh($timestamp) self::$autoloadedClass = ltrim($this->resource, '\\'); try { - $exists = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false); + $exists[0] = class_exists($this->resource) || interface_exists($this->resource, false) || trait_exists($this->resource, false); } catch (\Exception $e) { + $exists[1] = $e->getMessage(); + try { self::throwOnRequiredClass($this->resource, $e); } catch (\ReflectionException $e) { if (0 >= $timestamp) { - unset(self::$existsCache[1][$this->resource]); throw $e; } } + } catch (\Throwable $e) { + $exists[1] = $e->getMessage(); } finally { self::$autoloadedClass = $autoloadedClass; if (!--self::$autoloadLevel) { @@ -97,7 +104,7 @@ public function isFresh($timestamp) $this->exists = $exists; } - return $this->exists xor !$exists; + return $this->exists[0] xor !$exists[0]; } /** @@ -118,6 +125,10 @@ public function serialize() public function unserialize($serialized) { list($this->resource, $this->exists) = unserialize($serialized); + + if (\is_bool($this->exists)) { + $this->exists = [$this->exists, null]; + } } /** @@ -155,7 +166,17 @@ public static function throwOnRequiredClass($class, \Exception $previous = null) throw $previous; } - $e = new \ReflectionException(sprintf('Class "%s" not found while loading "%s".', $class, self::$autoloadedClass), 0, $previous); + $message = sprintf('Class "%s" not found.', $class); + + if (self::$autoloadedClass !== $class) { + $message = substr_replace($message, sprintf(' while loading "%s"', self::$autoloadedClass), -1, 0); + } + + if (null !== $previous) { + $message = $previous->getMessage(); + } + + $e = new \ReflectionException($message, 0, $previous); if (null !== $previous) { throw $e; diff --git a/src/Symfony/Component/Config/Tests/Definition/Builder/NodeBuilderTest.php b/src/Symfony/Component/Config/Tests/Definition/Builder/NodeBuilderTest.php index 5cc7cfea4f492..46518c659afbd 100644 --- a/src/Symfony/Component/Config/Tests/Definition/Builder/NodeBuilderTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/Builder/NodeBuilderTest.php @@ -35,7 +35,7 @@ public function testThrowsAnExceptionWhenTheNodeClassIsNotFound() public function testAddingANewNodeType() { - $class = __NAMESPACE__.'\\SomeNodeDefinition'; + $class = SomeNodeDefinition::class; $builder = new BaseNodeBuilder(); $node = $builder @@ -47,7 +47,7 @@ public function testAddingANewNodeType() public function testOverridingAnExistingNodeType() { - $class = __NAMESPACE__.'\\SomeNodeDefinition'; + $class = SomeNodeDefinition::class; $builder = new BaseNodeBuilder(); $node = $builder @@ -66,7 +66,7 @@ public function testNodeTypesAreNotCaseSensitive() $this->assertInstanceOf(\get_class($node1), $node2); - $builder->setNodeClass('CuStOm', __NAMESPACE__.'\\SomeNodeDefinition'); + $builder->setNodeClass('CuStOm', SomeNodeDefinition::class); $node1 = $builder->node('', 'CUSTOM'); $node2 = $builder->node('', 'custom'); diff --git a/src/Symfony/Component/Config/Tests/Fixtures/BadFileName.php b/src/Symfony/Component/Config/Tests/Fixtures/BadFileName.php new file mode 100644 index 0000000000000..0f79bdd523a7f --- /dev/null +++ b/src/Symfony/Component/Config/Tests/Fixtures/BadFileName.php @@ -0,0 +1,9 @@ +isFresh(0); } + public function testBadFileName() + { + $this->expectException('ReflectionException'); + $this->expectExceptionMessage('Mismatch between file name and class name.'); + + $res = new ClassExistenceResource(BadFileName::class, false); + $res->isFresh(0); + } + + public function testBadFileNameBis() + { + $this->expectException('ReflectionException'); + $this->expectExceptionMessage('Mismatch between file name and class name.'); + + $res = new ClassExistenceResource(BadFileName::class, false); + $res->isFresh(0); + } + public function testConditionalClass() { $res = new ClassExistenceResource(ConditionalClass::class, false); diff --git a/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php b/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php index 4653c8d7c776c..d1a47a8ea3376 100644 --- a/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php +++ b/src/Symfony/Component/Config/Tests/Util/XmlUtilsTest.php @@ -48,7 +48,7 @@ public function testLoadFile() $this->assertStringContainsString('XSD file or callable', $e->getMessage()); } - $mock = $this->getMockBuilder(__NAMESPACE__.'\Validator')->getMock(); + $mock = $this->getMockBuilder(Validator::class)->getMock(); $mock->expects($this->exactly(2))->method('validate')->will($this->onConsecutiveCalls(false, true)); try { @@ -68,7 +68,7 @@ public function testParseWithInvalidValidatorCallable() $this->expectExceptionMessage('The XML is not valid'); $fixtures = __DIR__.'/../Fixtures/Util/'; - $mock = $this->getMockBuilder(__NAMESPACE__.'\Validator')->getMock(); + $mock = $this->getMockBuilder(Validator::class)->getMock(); $mock->expects($this->once())->method('validate')->willReturn(false); XmlUtils::parse(file_get_contents($fixtures.'valid.xml'), [$mock, 'validate']); diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index d181e41e80c46..1463967ffae08 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -645,8 +645,13 @@ public function find($name) // filter out aliases for commands which are already on the list if (\count($commands) > 1) { $commandList = $this->commandLoader ? array_merge(array_flip($this->commandLoader->getNames()), $this->commands) : $this->commands; - $commands = array_unique(array_filter($commands, function ($nameOrAlias) use ($commandList, $commands, &$aliases) { - $commandName = $commandList[$nameOrAlias] instanceof Command ? $commandList[$nameOrAlias]->getName() : $nameOrAlias; + $commands = array_unique(array_filter($commands, function ($nameOrAlias) use (&$commandList, $commands, &$aliases) { + if (!$commandList[$nameOrAlias] instanceof Command) { + $commandList[$nameOrAlias] = $this->commandLoader->get($nameOrAlias); + } + + $commandName = $commandList[$nameOrAlias]->getName(); + $aliases[$nameOrAlias] = $commandName; return $commandName === $nameOrAlias || !\in_array($commandName, $commands); @@ -662,10 +667,6 @@ public function find($name) $maxLen = max(Helper::strlen($abbrev), $maxLen); } $abbrevs = array_map(function ($cmd) use ($commandList, $usableWidth, $maxLen) { - if (!$commandList[$cmd] instanceof Command) { - $commandList[$cmd] = $this->commandLoader->get($cmd); - } - if ($commandList[$cmd]->isHidden()) { return false; } diff --git a/src/Symfony/Component/Console/Helper/FormatterHelper.php b/src/Symfony/Component/Console/Helper/FormatterHelper.php index 4ad63856dcd5c..d6eccee8e85ac 100644 --- a/src/Symfony/Component/Console/Helper/FormatterHelper.php +++ b/src/Symfony/Component/Console/Helper/FormatterHelper.php @@ -54,12 +54,12 @@ public function formatBlock($messages, $style, $large = false) foreach ($messages as $message) { $message = OutputFormatter::escape($message); $lines[] = sprintf($large ? ' %s ' : ' %s ', $message); - $len = max($this->strlen($message) + ($large ? 4 : 2), $len); + $len = max(self::strlen($message) + ($large ? 4 : 2), $len); } $messages = $large ? [str_repeat(' ', $len)] : []; for ($i = 0; isset($lines[$i]); ++$i) { - $messages[] = $lines[$i].str_repeat(' ', $len - $this->strlen($lines[$i])); + $messages[] = $lines[$i].str_repeat(' ', $len - self::strlen($lines[$i])); } if ($large) { $messages[] = str_repeat(' ', $len); @@ -83,17 +83,13 @@ public function formatBlock($messages, $style, $large = false) */ public function truncate($message, $length, $suffix = '...') { - $computedLength = $length - $this->strlen($suffix); + $computedLength = $length - self::strlen($suffix); - if ($computedLength > $this->strlen($message)) { + if ($computedLength > self::strlen($message)) { return $message; } - if (false === $encoding = mb_detect_encoding($message, null, true)) { - return substr($message, 0, $length).$suffix; - } - - return mb_substr($message, 0, $length, $encoding).$suffix; + return self::substr($message, 0, $length).$suffix; } /** diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php index 1f93c06451630..93e221d36a563 100644 --- a/src/Symfony/Component/Console/Helper/QuestionHelper.php +++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php @@ -198,15 +198,9 @@ protected function writePrompt(OutputInterface $output, Question $question) $message = $question->getQuestion(); if ($question instanceof ChoiceQuestion) { - $maxWidth = max(array_map([$this, 'strlen'], array_keys($question->getChoices()))); - - $messages = (array) $question->getQuestion(); - foreach ($question->getChoices() as $key => $value) { - $width = $maxWidth - $this->strlen($key); - $messages[] = ' ['.$key.str_repeat(' ', $width).'] '.$value; - } - - $output->writeln($messages); + $output->writeln(array_merge([ + $question->getQuestion(), + ], $this->formatChoiceQuestionChoices($question, 'info'))); $message = $question->getPrompt(); } @@ -214,6 +208,26 @@ protected function writePrompt(OutputInterface $output, Question $question) $output->write($message); } + /** + * @param string $tag + * + * @return string[] + */ + protected function formatChoiceQuestionChoices(ChoiceQuestion $question, $tag) + { + $messages = []; + + $maxWidth = max(array_map('self::strlen', array_keys($choices = $question->getChoices()))); + + foreach ($choices as $key => $value) { + $padding = str_repeat(' ', $maxWidth - self::strlen($key)); + + $messages[] = sprintf(" [<$tag>%s$padding] %s", $key, $value); + } + + return $messages; + } + /** * Outputs an error message. */ diff --git a/src/Symfony/Component/Console/Helper/SymfonyQuestionHelper.php b/src/Symfony/Component/Console/Helper/SymfonyQuestionHelper.php index 5937741a2c69e..7cd050fee133c 100644 --- a/src/Symfony/Component/Console/Helper/SymfonyQuestionHelper.php +++ b/src/Symfony/Component/Console/Helper/SymfonyQuestionHelper.php @@ -96,15 +96,15 @@ protected function writePrompt(OutputInterface $output, Question $question) $output->writeln($text); + $prompt = ' > '; + if ($question instanceof ChoiceQuestion) { - $width = max(array_map('strlen', array_keys($question->getChoices()))); + $output->writeln($this->formatChoiceQuestionChoices($question, 'comment')); - foreach ($question->getChoices() as $key => $value) { - $output->writeln(sprintf(" [%-${width}s] %s", $key, $value)); - } + $prompt = $question->getPrompt(); } - $output->write(' > '); + $output->write($prompt); } /** diff --git a/src/Symfony/Component/Console/LICENSE b/src/Symfony/Component/Console/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Console/LICENSE +++ b/src/Symfony/Component/Console/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Console/README.md b/src/Symfony/Component/Console/README.md index 664a37c0ee7be..3e2fc605e5bfd 100644 --- a/src/Symfony/Component/Console/README.md +++ b/src/Symfony/Component/Console/README.md @@ -7,7 +7,7 @@ interfaces. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/console/index.html) + * [Documentation](https://symfony.com/doc/current/components/console.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index 1ef2ed3d78d7a..559c42599fbdd 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -558,7 +558,7 @@ public function testFindAlternativeCommands() $this->assertRegExp(sprintf('/Command "%s" is not defined./', $commandName), $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternatives'); $this->assertRegExp('/afoobar1/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternative : "afoobar1"'); $this->assertRegExp('/foo:bar1/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, with alternative : "foo:bar1"'); - $this->assertNotRegExp('/foo:bar(?>!1)/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, without "foo:bar" alternative'); + $this->assertNotRegExp('/foo:bar(?!1)/', $e->getMessage(), '->find() throws a CommandNotFoundException if command does not exist, without "foo:bar" alternative'); } } @@ -568,6 +568,9 @@ public function testFindAlternativeCommandsWithAnAlias() $fooCommand->setAliases(['foo2']); $application = new Application(); + $application->setCommandLoader(new FactoryCommandLoader([ + 'foo3' => static function () use ($fooCommand) { return $fooCommand; }, + ])); $application->add($fooCommand); $result = $application->find('foo'); diff --git a/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php index cbf3b957b3913..467f38b6d45c8 100644 --- a/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php @@ -130,6 +130,49 @@ public function testAskThrowsExceptionOnMissingInput() $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), new Question('What\'s your name?')); } + public function testChoiceQuestionPadding() + { + $choiceQuestion = new ChoiceQuestion('qqq', [ + 'foo' => 'foo', + 'żółw' => 'bar', + 'łabądź' => 'baz', + ]); + + (new SymfonyQuestionHelper())->ask( + $this->createStreamableInputInterfaceMock($this->getInputStream("foo\n")), + $output = $this->createOutputInterface(), + $choiceQuestion + ); + + $this->assertOutputContains(<< +EOT + , $output, true); + } + + public function testChoiceQuestionCustomPrompt() + { + $choiceQuestion = new ChoiceQuestion('qqq', ['foo']); + $choiceQuestion->setPrompt(' >ccc> '); + + (new SymfonyQuestionHelper())->ask( + $this->createStreamableInputInterfaceMock($this->getInputStream("foo\n")), + $output = $this->createOutputInterface(), + $choiceQuestion + ); + + $this->assertOutputContains(<<ccc> +EOT + , $output, true); + } + protected function getInputStream($input) { $stream = fopen('php://memory', 'r+', false); @@ -157,10 +200,15 @@ protected function createInputInterfaceMock($interactive = true) return $mock; } - private function assertOutputContains($expected, StreamOutput $output) + private function assertOutputContains($expected, StreamOutput $output, $normalize = false) { rewind($output->getStream()); $stream = stream_get_contents($output->getStream()); + + if ($normalize) { + $stream = str_replace(PHP_EOL, "\n", $stream); + } + $this->assertStringContainsString($expected, $stream); } } diff --git a/src/Symfony/Component/CssSelector/LICENSE b/src/Symfony/Component/CssSelector/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/CssSelector/LICENSE +++ b/src/Symfony/Component/CssSelector/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Debug/LICENSE b/src/Symfony/Component/Debug/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Debug/LICENSE +++ b/src/Symfony/Component/Debug/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Debug/README.md b/src/Symfony/Component/Debug/README.md index a1d16175c1a1f..38bc800c587b3 100644 --- a/src/Symfony/Component/Debug/README.md +++ b/src/Symfony/Component/Debug/README.md @@ -6,7 +6,7 @@ The Debug component provides tools to ease debugging PHP code. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/debug/index.html) + * [Documentation](https://symfony.com/doc/current/components/debug.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php b/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php index 0388acba029ba..86ecf16df02c8 100644 --- a/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php +++ b/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php @@ -64,14 +64,14 @@ public function testThrowingClass() $this->expectException('Exception'); $this->expectExceptionMessage('boo'); try { - class_exists(__NAMESPACE__.'\Fixtures\Throwing'); + class_exists(Fixtures\Throwing::class); $this->fail('Exception expected'); } catch (\Exception $e) { $this->assertSame('boo', $e->getMessage()); } // the second call also should throw - class_exists(__NAMESPACE__.'\Fixtures\Throwing'); + class_exists(Fixtures\Throwing::class); } public function testUnsilencing() @@ -90,7 +90,7 @@ public function testUnsilencing() // See below: this will fail with parse error // but this should not be @-silenced. - @class_exists(__NAMESPACE__.'\TestingUnsilencing', true); + @class_exists(TestingUnsilencing::class, true); $output = ob_get_clean(); @@ -141,7 +141,7 @@ public function testNameCaseMismatch() { $this->expectException('RuntimeException'); $this->expectExceptionMessage('Case mismatch between loaded and declared class names'); - class_exists(__NAMESPACE__.'\TestingCaseMismatch', true); + class_exists(TestingCaseMismatch::class, true); } public function testFileCaseMismatch() @@ -152,7 +152,7 @@ public function testFileCaseMismatch() $this->markTestSkipped('Can only be run on case insensitive filesystems'); } - class_exists(__NAMESPACE__.'\Fixtures\CaseMismatch', true); + class_exists(Fixtures\CaseMismatch::class, true); } public function testPsr4CaseMismatch() @@ -174,7 +174,7 @@ public function testNotPsr0Bis() public function testClassAlias() { - $this->assertTrue(class_exists(__NAMESPACE__.'\Fixtures\ClassAlias', true)); + $this->assertTrue(class_exists(Fixtures\ClassAlias::class, true)); } /** @@ -216,7 +216,7 @@ public function testInterfaceExtendsDeprecatedInterface() $e = error_reporting(0); trigger_error('', E_USER_NOTICE); - class_exists('Test\\'.__NAMESPACE__.'\\NonDeprecatedInterfaceClass', true); + class_exists('Test\\'.NonDeprecatedInterfaceClass::class, true); error_reporting($e); restore_error_handler(); @@ -264,7 +264,7 @@ public function testReservedForPhp7() $e = error_reporting(0); trigger_error('', E_USER_NOTICE); - class_exists('Test\\'.__NAMESPACE__.'\\Float', true); + class_exists('Test\\'.Float::class, true); error_reporting($e); restore_error_handler(); @@ -289,7 +289,7 @@ public function testExtendedFinalClass() require __DIR__.'/Fixtures/FinalClasses.php'; $i = 1; - while (class_exists($finalClass = __NAMESPACE__.'\\Fixtures\\FinalClass'.$i++, false)) { + while (class_exists($finalClass = Fixtures\FinalClass::class.$i++, false)) { spl_autoload_call($finalClass); class_exists('Test\\'.__NAMESPACE__.'\\Extends'.substr($finalClass, strrpos($finalClass, '\\') + 1), true); } @@ -315,7 +315,7 @@ public function testExtendedFinalMethod() set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; }); $e = error_reporting(E_USER_DEPRECATED); - class_exists(__NAMESPACE__.'\\Fixtures\\ExtendedFinalMethod', true); + class_exists(Fixtures\ExtendedFinalMethod::class, true); error_reporting($e); restore_error_handler(); @@ -334,7 +334,7 @@ public function testExtendedDeprecatedMethodDoesntTriggerAnyNotice() $e = error_reporting(0); trigger_error('', E_USER_NOTICE); - class_exists('Test\\'.__NAMESPACE__.'\\ExtendsAnnotatedClass', true); + class_exists('Test\\'.ExtendsAnnotatedClass::class, true); error_reporting($e); restore_error_handler(); @@ -351,7 +351,7 @@ public function testInternalsUse() set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; }); $e = error_reporting(E_USER_DEPRECATED); - class_exists('Test\\'.__NAMESPACE__.'\\ExtendsInternals', true); + class_exists('Test\\'.ExtendsInternals::class, true); error_reporting($e); restore_error_handler(); @@ -370,7 +370,7 @@ public function testUseTraitWithInternalMethod() set_error_handler(function ($type, $msg) use (&$deprecations) { $deprecations[] = $msg; }); $e = error_reporting(E_USER_DEPRECATED); - class_exists('Test\\'.__NAMESPACE__.'\\UseTraitWithInternalMethod', true); + class_exists('Test\\'.UseTraitWithInternalMethod::class, true); error_reporting($e); restore_error_handler(); @@ -380,7 +380,7 @@ class_exists('Test\\'.__NAMESPACE__.'\\UseTraitWithInternalMethod', true); public function testEvaluatedCode() { - $this->assertTrue(class_exists(__NAMESPACE__.'\Fixtures\DefinitionInEvaluatedCode', true)); + $this->assertTrue(class_exists(Fixtures\DefinitionInEvaluatedCode::class, true)); } } @@ -399,11 +399,11 @@ public function findFile($class) { $fixtureDir = __DIR__.\DIRECTORY_SEPARATOR.'Fixtures'.\DIRECTORY_SEPARATOR; - if (__NAMESPACE__.'\TestingUnsilencing' === $class) { + if (TestingUnsilencing::class === $class) { eval('-- parse error --'); - } elseif (__NAMESPACE__.'\TestingStacking' === $class) { + } elseif (TestingStacking::class === $class) { eval('namespace '.__NAMESPACE__.'; class TestingStacking { function foo() {} }'); - } elseif (__NAMESPACE__.'\TestingCaseMismatch' === $class) { + } elseif (TestingCaseMismatch::class === $class) { eval('namespace '.__NAMESPACE__.'; class TestingCaseMisMatch {}'); } elseif (__NAMESPACE__.'\Fixtures\Psr4CaseMismatch' === $class) { return $fixtureDir.'psr4'.\DIRECTORY_SEPARATOR.'Psr4CaseMismatch.php'; @@ -413,30 +413,30 @@ public function findFile($class) return $fixtureDir.'notPsr0Bis.php'; } elseif ('Symfony\Bridge\Debug\Tests\Fixtures\ExtendsDeprecatedParent' === $class) { eval('namespace Symfony\Bridge\Debug\Tests\Fixtures; class ExtendsDeprecatedParent extends \\'.__NAMESPACE__.'\Fixtures\DeprecatedClass {}'); - } elseif ('Test\\'.__NAMESPACE__.'\DeprecatedParentClass' === $class) { + } elseif ('Test\\'.DeprecatedParentClass::class === $class) { eval('namespace Test\\'.__NAMESPACE__.'; class DeprecatedParentClass extends \\'.__NAMESPACE__.'\Fixtures\DeprecatedClass {}'); - } elseif ('Test\\'.__NAMESPACE__.'\DeprecatedInterfaceClass' === $class) { + } elseif ('Test\\'.DeprecatedInterfaceClass::class === $class) { eval('namespace Test\\'.__NAMESPACE__.'; class DeprecatedInterfaceClass implements \\'.__NAMESPACE__.'\Fixtures\DeprecatedInterface {}'); - } elseif ('Test\\'.__NAMESPACE__.'\NonDeprecatedInterfaceClass' === $class) { + } elseif ('Test\\'.NonDeprecatedInterfaceClass::class === $class) { eval('namespace Test\\'.__NAMESPACE__.'; class NonDeprecatedInterfaceClass implements \\'.__NAMESPACE__.'\Fixtures\NonDeprecatedInterface {}'); - } elseif ('Test\\'.__NAMESPACE__.'\Float' === $class) { + } elseif ('Test\\'.Float::class === $class) { eval('namespace Test\\'.__NAMESPACE__.'; class Float {}'); - } elseif (0 === strpos($class, 'Test\\'.__NAMESPACE__.'\ExtendsFinalClass')) { + } elseif (0 === strpos($class, 'Test\\'.ExtendsFinalClass::class)) { $classShortName = substr($class, strrpos($class, '\\') + 1); eval('namespace Test\\'.__NAMESPACE__.'; class '.$classShortName.' extends \\'.__NAMESPACE__.'\Fixtures\\'.substr($classShortName, 7).' {}'); - } elseif ('Test\\'.__NAMESPACE__.'\ExtendsAnnotatedClass' === $class) { + } elseif ('Test\\'.ExtendsAnnotatedClass::class === $class) { eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsAnnotatedClass extends \\'.__NAMESPACE__.'\Fixtures\AnnotatedClass { public function deprecatedMethod() { } }'); - } elseif ('Test\\'.__NAMESPACE__.'\ExtendsInternals' === $class) { + } elseif ('Test\\'.ExtendsInternals::class === $class) { eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsInternals extends ExtendsInternalsParent { use \\'.__NAMESPACE__.'\Fixtures\InternalTrait; public function internalMethod() { } }'); - } elseif ('Test\\'.__NAMESPACE__.'\ExtendsInternalsParent' === $class) { + } elseif ('Test\\'.ExtendsInternalsParent::class === $class) { eval('namespace Test\\'.__NAMESPACE__.'; class ExtendsInternalsParent extends \\'.__NAMESPACE__.'\Fixtures\InternalClass implements \\'.__NAMESPACE__.'\Fixtures\InternalInterface { }'); - } elseif ('Test\\'.__NAMESPACE__.'\UseTraitWithInternalMethod' === $class) { + } elseif ('Test\\'.UseTraitWithInternalMethod::class === $class) { eval('namespace Test\\'.__NAMESPACE__.'; class UseTraitWithInternalMethod { use \\'.__NAMESPACE__.'\Fixtures\TraitWithInternalMethod; }'); } diff --git a/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php b/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php index 0290b05bad484..3d163eec7775f 100644 --- a/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php +++ b/src/Symfony/Component/Debug/Tests/Exception/FlattenExceptionTest.php @@ -199,6 +199,10 @@ public function flattenDataProvider() public function testArguments() { + if (\PHP_VERSION_ID >= 70400) { + $this->markTestSkipped('PHP 7.4 removes arguments from exception traces.'); + } + $dh = opendir(__DIR__); $fh = tmpfile(); @@ -261,6 +265,10 @@ function () {}, public function testRecursionInArguments() { + if (\PHP_VERSION_ID >= 70400) { + $this->markTestSkipped('PHP 7.4 removes arguments from exception traces.'); + } + $a = null; $a = ['foo', [2, &$a]]; $exception = $this->createException($a); @@ -272,6 +280,10 @@ public function testRecursionInArguments() public function testTooBigArray() { + if (\PHP_VERSION_ID >= 70400) { + $this->markTestSkipped('PHP 7.4 removes arguments from exception traces.'); + } + $a = []; for ($i = 0; $i < 20; ++$i) { for ($j = 0; $j < 50; ++$j) { diff --git a/src/Symfony/Component/Debug/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php b/src/Symfony/Component/Debug/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php index 9a56b3b4ec8fc..f3564762013fc 100644 --- a/src/Symfony/Component/Debug/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php +++ b/src/Symfony/Component/Debug/Tests/FatalErrorHandler/ClassNotFoundFatalErrorHandlerTest.php @@ -29,6 +29,10 @@ public static function setUpBeforeClass() // get class loaders wrapped by DebugClassLoader if ($function[0] instanceof DebugClassLoader) { $function = $function[0]->getClassLoader(); + + if (!\is_array($function)) { + continue; + } } if ($function[0] instanceof ComposerClassLoader) { diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php index 0e9005415a30b..4b6d277fe9979 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckDefinitionValidityPass.php @@ -49,21 +49,10 @@ public function process(ContainerBuilder $container) } if (class_exists($id) || interface_exists($id, false)) { if (0 === strpos($id, '\\') && 1 < substr_count($id, '\\')) { - throw new RuntimeException(sprintf( - 'The definition for "%s" has no class attribute, and appears to reference a class or interface. ' - .'Please specify the class attribute explicitly or remove the leading backslash by renaming ' - .'the service to "%s" to get rid of this error.', - $id, substr($id, 1) - )); + throw new RuntimeException(sprintf('The definition for "%s" has no class attribute, and appears to reference a class or interface. Please specify the class attribute explicitly or remove the leading backslash by renaming the service to "%s" to get rid of this error.', $id, substr($id, 1))); } - throw new RuntimeException(sprintf( - 'The definition for "%s" has no class attribute, and appears to reference a ' - .'class or interface in the global namespace. Leaving out the "class" attribute ' - .'is only allowed for namespaced classes. Please specify the class attribute ' - .'explicitly to get rid of this error.', - $id - )); + throw new RuntimeException(sprintf('The definition for "%s" has no class attribute, and appears to reference a class or interface in the global namespace. Leaving out the "class" attribute is only allowed for namespaced classes. Please specify the class attribute explicitly to get rid of this error.', $id)); } throw new RuntimeException(sprintf('The definition for "%s" has no class. If you intend to inject this service dynamically at runtime, please mark it as synthetic=true. If this is an abstract definition solely used by child definitions, please add abstract=true, otherwise specify a class to get rid of this error.', $id)); diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php index 323faad57f9a0..bf8d75e6df280 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php @@ -53,7 +53,7 @@ public function __construct() new ServiceLocatorTagPass(), new RegisterServiceSubscribersPass(), new DecoratorServicePass(), - new ResolveParameterPlaceHoldersPass(false), + new ResolveParameterPlaceHoldersPass(false, false), new ResolveFactoryClassPass(), new FactoryReturnTypePass($resolveClassPass), new CheckDefinitionValidityPass(), diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveInstanceofConditionalsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveInstanceofConditionalsPass.php index 69e3796df0c4f..6268ed9ed048c 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveInstanceofConditionalsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveInstanceofConditionalsPass.php @@ -64,9 +64,10 @@ private function processDefinition(ContainerBuilder $container, $id, Definition $definition->setInstanceofConditionals([]); $parent = $shared = null; $instanceofTags = []; + $reflectionClass = null; foreach ($conditionals as $interface => $instanceofDefs) { - if ($interface !== $class && (!$container->getReflectionClass($class, false))) { + if ($interface !== $class && !(null === $reflectionClass ? $reflectionClass = ($container->getReflectionClass($class, false) ?: false) : $reflectionClass)) { continue; } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveParameterPlaceHoldersPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveParameterPlaceHoldersPass.php index 8c942b524ea3b..32eb6a3a76f3e 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveParameterPlaceHoldersPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveParameterPlaceHoldersPass.php @@ -24,10 +24,12 @@ class ResolveParameterPlaceHoldersPass extends AbstractRecursivePass { private $bag; private $resolveArrays; + private $throwOnResolveException; - public function __construct($resolveArrays = true) + public function __construct($resolveArrays = true, $throwOnResolveException = true) { $this->resolveArrays = $resolveArrays; + $this->throwOnResolveException = $throwOnResolveException; } /** @@ -61,7 +63,16 @@ public function process(ContainerBuilder $container) protected function processValue($value, $isRoot = false) { if (\is_string($value)) { - $v = $this->bag->resolveValue($value); + try { + $v = $this->bag->resolveValue($value); + } catch (ParameterNotFoundException $e) { + if ($this->throwOnResolveException) { + throw $e; + } + + $v = null; + $this->container->getDefinition($this->currentId)->addError($e->getMessage()); + } return $this->resolveArrays || !$v || !\is_array($v) ? $v : $value; } diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 7596b9953bda4..4dd4475cbe4cf 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -173,14 +173,14 @@ public function dump(array $options = []) if (!empty($options['file']) && is_dir($dir = \dirname($options['file']))) { // Build a regexp where the first root dirs are mandatory, // but every other sub-dir is optional up to the full path in $dir - // Mandate at least 2 root dirs and not more that 5 optional dirs. + // Mandate at least 1 root dir and not more than 5 optional dirs. $dir = explode(\DIRECTORY_SEPARATOR, realpath($dir)); $i = \count($dir); - if (3 <= $i) { + if (2 + (int) ('\\' === \DIRECTORY_SEPARATOR) <= $i) { $regex = ''; - $lastOptionalDir = $i > 8 ? $i - 5 : 3; + $lastOptionalDir = $i > 8 ? $i - 5 : (2 + (int) ('\\' === \DIRECTORY_SEPARATOR)); $this->targetDirMaxMatches = $i - $lastOptionalDir; while (--$i >= $lastOptionalDir) { diff --git a/src/Symfony/Component/DependencyInjection/Extension/Extension.php b/src/Symfony/Component/DependencyInjection/Extension/Extension.php index 7df483064f11d..8acb8ee31d48f 100644 --- a/src/Symfony/Component/DependencyInjection/Extension/Extension.php +++ b/src/Symfony/Component/DependencyInjection/Extension/Extension.php @@ -80,6 +80,11 @@ public function getAlias() public function getConfiguration(array $config, ContainerBuilder $container) { $class = \get_class($this); + + if (false !== strpos($class, "\0")) { + return null; // ignore anonymous classes + } + $class = substr_replace($class, '\Configuration', strrpos($class, '\\')); $class = $container->getReflectionClass($class); $constructor = $class ? $class->getConstructor() : null; diff --git a/src/Symfony/Component/DependencyInjection/LICENSE b/src/Symfony/Component/DependencyInjection/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/DependencyInjection/LICENSE +++ b/src/Symfony/Component/DependencyInjection/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php index 3b4b2a4830f91..828d4071dab35 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php +++ b/src/Symfony/Component/DependencyInjection/Loader/Configurator/ContainerConfigurator.php @@ -45,13 +45,7 @@ final public function extension($namespace, array $config) { if (!$this->container->hasExtension($namespace)) { $extensions = array_filter(array_map(function ($ext) { return $ext->getAlias(); }, $this->container->getExtensions())); - throw new InvalidArgumentException(sprintf( - 'There is no extension able to load the configuration for "%s" (in %s). Looked for namespace "%s", found %s', - $namespace, - $this->file, - $namespace, - $extensions ? sprintf('"%s"', implode('", "', $extensions)) : 'none' - )); + throw new InvalidArgumentException(sprintf('There is no extension able to load the configuration for "%s" (in %s). Looked for namespace "%s", found %s', $namespace, $this->file, $namespace, $extensions ? sprintf('"%s"', implode('", "', $extensions)) : 'none')); } $this->container->loadFromExtension($namespace, static::processValue($config)); diff --git a/src/Symfony/Component/DependencyInjection/README.md b/src/Symfony/Component/DependencyInjection/README.md index 932647f94a903..cb2d4a11c5886 100644 --- a/src/Symfony/Component/DependencyInjection/README.md +++ b/src/Symfony/Component/DependencyInjection/README.md @@ -7,7 +7,7 @@ way objects are constructed in your application. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/dependency_injection/index.html) + * [Documentation](https://symfony.com/doc/current/components/dependency_injection.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index c5bcc660a5e48..a32a6c9735026 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -37,7 +37,7 @@ public function testProcess() $container = new ContainerBuilder(); $container->register(Foo::class); - $barDefinition = $container->register('bar', __NAMESPACE__.'\Bar'); + $barDefinition = $container->register('bar', Bar::class); $barDefinition->setAutowired(true); (new ResolveClassPass())->process($container); @@ -75,7 +75,7 @@ public function testProcessAutowireParent() $container = new ContainerBuilder(); $container->register(B::class); - $cDefinition = $container->register('c', __NAMESPACE__.'\C'); + $cDefinition = $container->register('c', C::class); $cDefinition->setAutowired(true); (new ResolveClassPass())->process($container); @@ -97,7 +97,7 @@ public function testProcessLegacyAutowireWithAvailableInterface() $container->setAlias(AInterface::class, B::class); $container->register(B::class); - $cDefinition = $container->register('c', __NAMESPACE__.'\C'); + $cDefinition = $container->register('c', C::class); $cDefinition->setAutowired(true); (new ResolveClassPass())->process($container); @@ -118,7 +118,7 @@ public function testProcessAutowireInterface() $container = new ContainerBuilder(); $container->register(F::class); - $gDefinition = $container->register('g', __NAMESPACE__.'\G'); + $gDefinition = $container->register('g', G::class); $gDefinition->setAutowired(true); (new ResolveClassPass())->process($container); @@ -134,9 +134,9 @@ public function testCompleteExistingDefinition() { $container = new ContainerBuilder(); - $container->register('b', __NAMESPACE__.'\B'); + $container->register('b', B::class); $container->register(DInterface::class, F::class); - $hDefinition = $container->register('h', __NAMESPACE__.'\H')->addArgument(new Reference('b')); + $hDefinition = $container->register('h', H::class)->addArgument(new Reference('b')); $hDefinition->setAutowired(true); (new ResolveClassPass())->process($container); @@ -153,7 +153,7 @@ public function testCompleteExistingDefinitionWithNotDefinedArguments() $container->register(B::class); $container->register(DInterface::class, F::class); - $hDefinition = $container->register('h', __NAMESPACE__.'\H')->addArgument('')->addArgument(''); + $hDefinition = $container->register('h', H::class)->addArgument('')->addArgument(''); $hDefinition->setAutowired(true); (new ResolveClassPass())->process($container); @@ -171,10 +171,10 @@ public function testExceptionsAreStored() { $container = new ContainerBuilder(); - $container->register('c1', __NAMESPACE__.'\CollisionA'); - $container->register('c2', __NAMESPACE__.'\CollisionB'); - $container->register('c3', __NAMESPACE__.'\CollisionB'); - $aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired'); + $container->register('c1', CollisionA::class); + $container->register('c2', CollisionB::class); + $container->register('c3', CollisionB::class); + $aDefinition = $container->register('a', CannotBeAutowired::class); $aDefinition->setAutowired(true); $pass = new AutowirePass(false); @@ -188,7 +188,7 @@ public function testPrivateConstructorThrowsAutowireException() $this->expectExceptionMessage('Invalid service "private_service": constructor of class "Symfony\Component\DependencyInjection\Tests\Compiler\PrivateConstructor" must be public.'); $container = new ContainerBuilder(); - $container->autowire('private_service', __NAMESPACE__.'\PrivateConstructor'); + $container->autowire('private_service', PrivateConstructor::class); $pass = new AutowirePass(true); $pass->process($container); @@ -200,10 +200,10 @@ public function testTypeCollision() $this->expectExceptionMessage('Cannot autowire service "a": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\CannotBeAutowired::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists. You should maybe alias this interface to one of these existing services: "c1", "c2", "c3".'); $container = new ContainerBuilder(); - $container->register('c1', __NAMESPACE__.'\CollisionA'); - $container->register('c2', __NAMESPACE__.'\CollisionB'); - $container->register('c3', __NAMESPACE__.'\CollisionB'); - $aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired'); + $container->register('c1', CollisionA::class); + $container->register('c2', CollisionB::class); + $container->register('c3', CollisionB::class); + $aDefinition = $container->register('a', CannotBeAutowired::class); $aDefinition->setAutowired(true); $pass = new AutowirePass(); @@ -216,9 +216,9 @@ public function testTypeNotGuessable() $this->expectExceptionMessage('Cannot autowire service "a": argument "$k" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotGuessableArgument::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\Foo" but no such service exists. You should maybe alias this class to one of these existing services: "a1", "a2".'); $container = new ContainerBuilder(); - $container->register('a1', __NAMESPACE__.'\Foo'); - $container->register('a2', __NAMESPACE__.'\Foo'); - $aDefinition = $container->register('a', __NAMESPACE__.'\NotGuessableArgument'); + $container->register('a1', Foo::class); + $container->register('a2', Foo::class); + $aDefinition = $container->register('a', NotGuessableArgument::class); $aDefinition->setAutowired(true); $pass = new AutowirePass(); @@ -231,9 +231,9 @@ public function testTypeNotGuessableWithSubclass() $this->expectExceptionMessage('Cannot autowire service "a": argument "$k" of method "Symfony\Component\DependencyInjection\Tests\Compiler\NotGuessableArgumentForSubclass::__construct()" references class "Symfony\Component\DependencyInjection\Tests\Compiler\A" but no such service exists. You should maybe alias this class to one of these existing services: "a1", "a2".'); $container = new ContainerBuilder(); - $container->register('a1', __NAMESPACE__.'\B'); - $container->register('a2', __NAMESPACE__.'\B'); - $aDefinition = $container->register('a', __NAMESPACE__.'\NotGuessableArgumentForSubclass'); + $container->register('a1', B::class); + $container->register('a2', B::class); + $aDefinition = $container->register('a', NotGuessableArgumentForSubclass::class); $aDefinition->setAutowired(true); $pass = new AutowirePass(); @@ -246,7 +246,7 @@ public function testTypeNotGuessableNoServicesFound() $this->expectExceptionMessage('Cannot autowire service "a": argument "$collision" of method "Symfony\Component\DependencyInjection\Tests\Compiler\CannotBeAutowired::__construct()" references interface "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" but no such service exists.'); $container = new ContainerBuilder(); - $aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired'); + $aDefinition = $container->register('a', CannotBeAutowired::class); $aDefinition->setAutowired(true); $pass = new AutowirePass(); @@ -257,10 +257,10 @@ public function testTypeNotGuessableWithTypeSet() { $container = new ContainerBuilder(); - $container->register('a1', __NAMESPACE__.'\Foo'); - $container->register('a2', __NAMESPACE__.'\Foo'); + $container->register('a1', Foo::class); + $container->register('a2', Foo::class); $container->register(Foo::class, Foo::class); - $aDefinition = $container->register('a', __NAMESPACE__.'\NotGuessableArgument'); + $aDefinition = $container->register('a', NotGuessableArgument::class); $aDefinition->setAutowired(true); $pass = new AutowirePass(); @@ -274,10 +274,10 @@ public function testWithTypeSet() { $container = new ContainerBuilder(); - $container->register('c1', __NAMESPACE__.'\CollisionA'); - $container->register('c2', __NAMESPACE__.'\CollisionB'); + $container->register('c1', CollisionA::class); + $container->register('c2', CollisionB::class); $container->setAlias(CollisionInterface::class, 'c2'); - $aDefinition = $container->register('a', __NAMESPACE__.'\CannotBeAutowired'); + $aDefinition = $container->register('a', CannotBeAutowired::class); $aDefinition->setAutowired(true); $pass = new AutowirePass(); @@ -296,7 +296,7 @@ public function testCreateDefinition() { $container = new ContainerBuilder(); - $coopTilleulsDefinition = $container->register('coop_tilleuls', __NAMESPACE__.'\LesTilleuls'); + $coopTilleulsDefinition = $container->register('coop_tilleuls', LesTilleuls::class); $coopTilleulsDefinition->setAutowired(true); $pass = new AutowirePass(); @@ -307,13 +307,13 @@ public function testCreateDefinition() $this->assertEquals('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas', $container->getDefinition('coop_tilleuls')->getArgument(1)); $dunglasDefinition = $container->getDefinition('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Dunglas'); - $this->assertEquals(__NAMESPACE__.'\Dunglas', $dunglasDefinition->getClass()); + $this->assertEquals(Dunglas::class, $dunglasDefinition->getClass()); $this->assertFalse($dunglasDefinition->isPublic()); $this->assertCount(1, $dunglasDefinition->getArguments()); $this->assertEquals('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Lille', $dunglasDefinition->getArgument(0)); $lilleDefinition = $container->getDefinition('autowired.Symfony\Component\DependencyInjection\Tests\Compiler\Lille'); - $this->assertEquals(__NAMESPACE__.'\Lille', $lilleDefinition->getClass()); + $this->assertEquals(Lille::class, $lilleDefinition->getClass()); } public function testResolveParameter() @@ -337,7 +337,7 @@ public function testOptionalParameter() $container->register(A::class); $container->register(Foo::class); - $optDefinition = $container->register('opt', __NAMESPACE__.'\OptionalParameter'); + $optDefinition = $container->register('opt', OptionalParameter::class); $optDefinition->setAutowired(true); (new ResolveClassPass())->process($container); @@ -354,7 +354,7 @@ public function testDontTriggerAutowiring() $container = new ContainerBuilder(); $container->register(Foo::class); - $container->register('bar', __NAMESPACE__.'\Bar'); + $container->register('bar', Bar::class); (new ResolveClassPass())->process($container); (new AutowirePass())->process($container); @@ -368,7 +368,7 @@ public function testClassNotFoundThrowsException() $this->expectExceptionMessage('Cannot autowire service "a": argument "$r" of method "Symfony\Component\DependencyInjection\Tests\Compiler\BadTypeHintedArgument::__construct()" has type "Symfony\Component\DependencyInjection\Tests\Compiler\NotARealClass" but this class was not found.'); $container = new ContainerBuilder(); - $aDefinition = $container->register('a', __NAMESPACE__.'\BadTypeHintedArgument'); + $aDefinition = $container->register('a', BadTypeHintedArgument::class); $aDefinition->setAutowired(true); $container->register(Dunglas::class, Dunglas::class); @@ -384,7 +384,7 @@ public function testParentClassNotFoundThrowsException() $container = new ContainerBuilder(); - $aDefinition = $container->register('a', __NAMESPACE__.'\BadParentTypeHintedArgument'); + $aDefinition = $container->register('a', BadParentTypeHintedArgument::class); $aDefinition->setAutowired(true); $container->register(Dunglas::class, Dunglas::class); @@ -404,8 +404,8 @@ public function testDontUseAbstractServices() $container = new ContainerBuilder(); $container->register(Foo::class)->setAbstract(true); - $container->register('foo', __NAMESPACE__.'\Foo'); - $container->register('bar', __NAMESPACE__.'\Bar')->setAutowired(true); + $container->register('foo', Foo::class); + $container->register('bar', Bar::class)->setAutowired(true); (new ResolveClassPass())->process($container); (new AutowirePass())->process($container); @@ -418,7 +418,7 @@ public function testSomeSpecificArgumentsAreSet() $container->register('foo', Foo::class); $container->register(A::class); $container->register(Dunglas::class); - $container->register('multiple', __NAMESPACE__.'\MultipleArguments') + $container->register('multiple', MultipleArguments::class) ->setAutowired(true) // set the 2nd (index 1) argument only: autowire the first and third // args are: A, Foo, Dunglas @@ -450,7 +450,7 @@ public function testScalarArgsCannotBeAutowired() $container->register(A::class); $container->register(Dunglas::class); - $container->register('arg_no_type_hint', __NAMESPACE__.'\MultipleArguments') + $container->register('arg_no_type_hint', MultipleArguments::class) ->setArguments([1 => 'foo']) ->setAutowired(true); @@ -466,7 +466,7 @@ public function testNoTypeArgsCannotBeAutowired() $container->register(A::class); $container->register(Dunglas::class); - $container->register('arg_no_type_hint', __NAMESPACE__.'\MultipleArguments') + $container->register('arg_no_type_hint', MultipleArguments::class) ->setAutowired(true); (new ResolveClassPass())->process($container); @@ -479,7 +479,7 @@ public function testOptionalScalarNotReallyOptionalUsesDefaultValue() $container->register(A::class); $container->register(Lille::class); - $definition = $container->register('not_really_optional_scalar', __NAMESPACE__.'\MultipleArgumentsOptionalScalarNotReallyOptional') + $definition = $container->register('not_really_optional_scalar', MultipleArgumentsOptionalScalarNotReallyOptional::class) ->setAutowired(true); (new ResolveClassPass())->process($container); @@ -494,7 +494,7 @@ public function testOptionalScalarArgsDontMessUpOrder() $container->register(A::class); $container->register(Lille::class); - $container->register('with_optional_scalar', __NAMESPACE__.'\MultipleArgumentsOptionalScalar') + $container->register('with_optional_scalar', MultipleArgumentsOptionalScalar::class) ->setAutowired(true); (new ResolveClassPass())->process($container); @@ -518,7 +518,7 @@ public function testOptionalScalarArgsNotPassedIfLast() $container->register(A::class); $container->register(Lille::class); - $container->register('with_optional_scalar_last', __NAMESPACE__.'\MultipleArgumentsOptionalScalarLast') + $container->register('with_optional_scalar_last', MultipleArgumentsOptionalScalarLast::class) ->setAutowired(true); (new ResolveClassPass())->process($container); @@ -659,7 +659,7 @@ public function testTypedReference() public function testCreateResourceForClass($className, $isEqual) { $startingResource = AutowirePass::createResourceForClass( - new \ReflectionClass(__NAMESPACE__.'\ClassForResource') + new \ReflectionClass(ClassForResource::class) ); $newResource = AutowirePass::createResourceForClass( new \ReflectionClass(__NAMESPACE__.'\\'.$className) @@ -690,9 +690,9 @@ public function testIgnoreServiceWithClassNotExisting() { $container = new ContainerBuilder(); - $container->register('class_not_exist', __NAMESPACE__.'\OptionalServiceClass'); + $container->register('class_not_exist', OptionalServiceClass::class); - $barDefinition = $container->register('bar', __NAMESPACE__.'\Bar'); + $barDefinition = $container->register('bar', Bar::class); $barDefinition->setAutowired(true); $container->register(Foo::class, Foo::class); @@ -750,8 +750,8 @@ public function testProcessDoesNotTriggerDeprecations() { $container = new ContainerBuilder(); $container->register('deprecated', 'Symfony\Component\DependencyInjection\Tests\Fixtures\DeprecatedClass')->setDeprecated(true); - $container->register('foo', __NAMESPACE__.'\Foo'); - $container->register('bar', __NAMESPACE__.'\Bar')->setAutowired(true); + $container->register('foo', Foo::class); + $container->register('bar', Bar::class)->setAutowired(true); $pass = new AutowirePass(); $pass->process($container); @@ -767,7 +767,7 @@ public function testEmptyStringIsKept() $container->register(A::class); $container->register(Lille::class); - $container->register('foo', __NAMESPACE__.'\MultipleArgumentsOptionalScalar') + $container->register('foo', MultipleArgumentsOptionalScalar::class) ->setAutowired(true) ->setArguments(['', '']); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveParameterPlaceHoldersPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveParameterPlaceHoldersPassTest.php index 5aa6471751f24..06399614392e5 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveParameterPlaceHoldersPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveParameterPlaceHoldersPassTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\DependencyInjection\Compiler\ResolveParameterPlaceHoldersPass; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Exception\ParameterNotFoundException; class ResolveParameterPlaceHoldersPassTest extends TestCase { @@ -71,6 +72,31 @@ public function testBindingsShouldBeResolved() $this->assertSame($this->container->getParameterBag()->resolveValue('%env(BAZ)%'), $boundValue); } + public function testParameterNotFoundExceptionsIsThrown() + { + $this->expectException(ParameterNotFoundException::class); + $this->expectExceptionMessage('The service "baz_service_id" has a dependency on a non-existent parameter "non_existent_param".'); + + $containerBuilder = new ContainerBuilder(); + $definition = $containerBuilder->register('baz_service_id'); + $definition->setArgument(0, '%non_existent_param%'); + + $pass = new ResolveParameterPlaceHoldersPass(); + $pass->process($containerBuilder); + } + + public function testParameterNotFoundExceptionsIsNotThrown() + { + $containerBuilder = new ContainerBuilder(); + $definition = $containerBuilder->register('baz_service_id'); + $definition->setArgument(0, '%non_existent_param%'); + + $pass = new ResolveParameterPlaceHoldersPass(true, false); + $pass->process($containerBuilder); + + $this->assertCount(1, $definition->getErrors()); + } + private function createContainerBuilder() { $containerBuilder = new ContainerBuilder(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Config/AutowireServiceResourceTest.php b/src/Symfony/Component/DependencyInjection/Tests/Config/AutowireServiceResourceTest.php index 153e0807ef862..990a9ad6639b3 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Config/AutowireServiceResourceTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Config/AutowireServiceResourceTest.php @@ -34,7 +34,7 @@ protected function setUp() $this->time = time(); touch($this->file, $this->time); - $this->class = __NAMESPACE__.'\Foo'; + $this->class = Foo::class; $this->resource = new AutowireServiceResource( $this->class, $this->file, @@ -83,7 +83,7 @@ public function testIsNotFreshChangedResource() public function testIsFreshSameConstructorArgs() { $oldResource = AutowirePass::createResourceForClass( - new \ReflectionClass(__NAMESPACE__.'\Foo') + new \ReflectionClass(Foo::class) ); // test with a stale file *but* the resource will not be changed diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index f2666ef9629b3..53d62a58d214f 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -1238,7 +1238,7 @@ public function testAutowiring() $container = new ContainerBuilder(); $container->register(A::class)->setPublic(true); - $bDefinition = $container->register('b', __NAMESPACE__.'\B'); + $bDefinition = $container->register('b', B::class); $bDefinition->setAutowired(true); $bDefinition->setPublic(true); diff --git a/src/Symfony/Component/DomCrawler/LICENSE b/src/Symfony/Component/DomCrawler/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/DomCrawler/LICENSE +++ b/src/Symfony/Component/DomCrawler/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Dotenv/Dotenv.php b/src/Symfony/Component/Dotenv/Dotenv.php index c2475f204a8bb..63424e165d477 100644 --- a/src/Symfony/Component/Dotenv/Dotenv.php +++ b/src/Symfony/Component/Dotenv/Dotenv.php @@ -203,7 +203,10 @@ private function lexValue() $this->cursor += 1 + $len; } elseif ('"' === $this->data[$this->cursor]) { $value = ''; - ++$this->cursor; + + if (++$this->cursor === $this->end) { + throw $this->createFormatException('Missing quote to end the value'); + } while ('"' !== $this->data[$this->cursor] || ('\\' === $this->data[$this->cursor - 1] && '\\' !== $this->data[$this->cursor - 2])) { $value .= $this->data[$this->cursor]; @@ -387,7 +390,7 @@ private function resolveVariables($value, array $loadedVars) } elseif (isset($this->values[$name])) { $value = $this->values[$name]; } else { - $value = ''; + $value = (string) getenv($name); } if (!$matches['opening_brace'] && isset($matches['closing_brace'])) { diff --git a/src/Symfony/Component/Dotenv/LICENSE b/src/Symfony/Component/Dotenv/LICENSE index 3c464ca94359b..a7ec70801827a 100644 --- a/src/Symfony/Component/Dotenv/LICENSE +++ b/src/Symfony/Component/Dotenv/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2016-2019 Fabien Potencier +Copyright (c) 2016-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php index 1e493f24bdb5b..fa53029c67dea 100644 --- a/src/Symfony/Component/Dotenv/Tests/DotenvTest.php +++ b/src/Symfony/Component/Dotenv/Tests/DotenvTest.php @@ -40,6 +40,7 @@ public function getEnvDataWithFormatErrors() ['FOO', "Missing = in the environment variable declaration in \".env\" at line 1.\n...FOO...\n ^ line 1 offset 3"], ['FOO="foo', "Missing quote to end the value in \".env\" at line 1.\n...FOO=\"foo...\n ^ line 1 offset 8"], ['FOO=\'foo', "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo...\n ^ line 1 offset 8"], + ["FOO=\"foo\nBAR=\"bar\"", "Missing quote to end the value in \".env\" at line 1.\n...FOO=\"foo\\nBAR=\"bar\"...\n ^ line 1 offset 18"], ['FOO=\'foo'."\n", "Missing quote to end the value in \".env\" at line 1.\n...FOO='foo\\n...\n ^ line 1 offset 9"], ['export FOO', "Unable to unset an environment variable in \".env\" at line 1.\n...export FOO...\n ^ line 1 offset 10"], ['FOO=${FOO', "Unclosed braces on variable expansion in \".env\" at line 1.\n...FOO=\${FOO...\n ^ line 1 offset 9"], @@ -314,4 +315,18 @@ public function testGetVariablesValueFromEnvFirst() $this->assertSame('foo2_prod', $values['TEST2']); } } + + public function testGetVariablesValueFromGetenv() + { + putenv('Foo=Bar'); + + $dotenv = new Dotenv(true); + + try { + $values = $dotenv->parse('Foo=${Foo}'); + $this->assertSame('Bar', $values['Foo']); + } finally { + putenv('Foo'); + } + } } diff --git a/src/Symfony/Component/EventDispatcher/LICENSE b/src/Symfony/Component/EventDispatcher/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/EventDispatcher/LICENSE +++ b/src/Symfony/Component/EventDispatcher/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/EventDispatcher/README.md b/src/Symfony/Component/EventDispatcher/README.md index 185c3fecf8fee..e0d38eed017f8 100644 --- a/src/Symfony/Component/EventDispatcher/README.md +++ b/src/Symfony/Component/EventDispatcher/README.md @@ -8,7 +8,7 @@ them. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/event_dispatcher/index.html) + * [Documentation](https://symfony.com/doc/current/components/event_dispatcher.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/ExpressionLanguage/LICENSE b/src/Symfony/Component/ExpressionLanguage/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/ExpressionLanguage/LICENSE +++ b/src/Symfony/Component/ExpressionLanguage/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/ExpressionLanguage/Node/BinaryNode.php b/src/Symfony/Component/ExpressionLanguage/Node/BinaryNode.php index 92378102beda8..bbfe393d0d12a 100644 --- a/src/Symfony/Component/ExpressionLanguage/Node/BinaryNode.php +++ b/src/Symfony/Component/ExpressionLanguage/Node/BinaryNode.php @@ -147,8 +147,16 @@ public function evaluate($functions, $values) case '*': return $left * $right; case '/': + if (0 == $right) { + throw new \DivisionByZeroError('Division by zero'); + } + return $left / $right; case '%': + if (0 == $right) { + throw new \DivisionByZeroError('Modulo by zero'); + } + return $left % $right; case 'matches': return preg_match($right, $left); diff --git a/src/Symfony/Component/ExpressionLanguage/composer.json b/src/Symfony/Component/ExpressionLanguage/composer.json index 5f662ffd38b23..ee441851343ed 100644 --- a/src/Symfony/Component/ExpressionLanguage/composer.json +++ b/src/Symfony/Component/ExpressionLanguage/composer.json @@ -17,7 +17,8 @@ ], "require": { "php": "^5.5.9|>=7.0.8", - "symfony/cache": "~3.1|~4.0" + "symfony/cache": "~3.1|~4.0", + "symfony/polyfill-php70": "~1.6" }, "autoload": { "psr-4": { "Symfony\\Component\\ExpressionLanguage\\": "" }, diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index cd456c7848b3d..7d7301c3a199f 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -211,7 +211,7 @@ public function chmod($files, $mode, $umask = 0000, $recursive = false) * Change the owner of an array of files or directories. * * @param string|iterable $files A filename, an array of files, or a \Traversable instance to change owner - * @param string $user The new owner user name + * @param string|int $user A user name or number * @param bool $recursive Whether change the owner recursively or not * * @throws IOException When the change fails @@ -238,7 +238,7 @@ public function chown($files, $user, $recursive = false) * Change the group of an array of files or directories. * * @param string|iterable $files A filename, an array of files, or a \Traversable instance to change group - * @param string $group The group name + * @param string|int $group A group name or number * @param bool $recursive Whether change the group recursively or not * * @throws IOException When the change fails diff --git a/src/Symfony/Component/Filesystem/LICENSE b/src/Symfony/Component/Filesystem/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Filesystem/LICENSE +++ b/src/Symfony/Component/Filesystem/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Filesystem/README.md b/src/Symfony/Component/Filesystem/README.md index 877ab3543f32d..cb03d43c15dd2 100644 --- a/src/Symfony/Component/Filesystem/README.md +++ b/src/Symfony/Component/Filesystem/README.md @@ -6,7 +6,7 @@ The Filesystem component provides basic utilities for the filesystem. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/filesystem/index.html) + * [Documentation](https://symfony.com/doc/current/components/filesystem.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Finder/LICENSE b/src/Symfony/Component/Finder/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Finder/LICENSE +++ b/src/Symfony/Component/Finder/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Form/Extension/Core/Type/BirthdayType.php b/src/Symfony/Component/Form/Extension/Core/Type/BirthdayType.php index acb8d02b8c5a9..a4e8b8d41c0e6 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/BirthdayType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/BirthdayType.php @@ -31,7 +31,7 @@ public function configureOptions(OptionsResolver $resolver) */ public function getParent() { - return __NAMESPACE__.'\DateType'; + return DateType::class; } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php index e29896fa61857..aec61a2b4d80a 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php @@ -391,12 +391,12 @@ private function addSubForm(FormBuilderInterface $builder, $name, ChoiceView $ch ]; if ($options['multiple']) { - $choiceType = __NAMESPACE__.'\CheckboxType'; + $choiceType = CheckboxType::class; // The user can check 0 or more checkboxes. If required // is true, they are required to check all of them. $choiceOpts['required'] = false; } else { - $choiceType = __NAMESPACE__.'\RadioType'; + $choiceType = RadioType::class; } $builder->add($name, $choiceType, $choiceOpts); diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php b/src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php index fc36cca6da937..b441f08ce6fc4 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/CollectionType.php @@ -94,7 +94,7 @@ public function configureOptions(OptionsResolver $resolver) 'prototype' => true, 'prototype_data' => null, 'prototype_name' => '__name__', - 'entry_type' => __NAMESPACE__.'\TextType', + 'entry_type' => TextType::class, 'entry_options' => [], 'delete_empty' => false, ]); diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php index c5b6b0dcf9127..eab178ede0025 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php @@ -55,7 +55,7 @@ public function configureOptions(OptionsResolver $resolver) */ public function getParent() { - return __NAMESPACE__.'\ChoiceType'; + return ChoiceType::class; } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php b/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php index 638c2e1a62adb..31c66f105917d 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php @@ -55,7 +55,7 @@ public function configureOptions(OptionsResolver $resolver) */ public function getParent() { - return __NAMESPACE__.'\ChoiceType'; + return ChoiceType::class; } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php index 04b0221fdc632..f766037946170 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/DateTimeType.php @@ -158,8 +158,8 @@ public function buildForm(FormBuilderInterface $builder, array $options) 'time' => $timeParts, ]), ])) - ->add('date', __NAMESPACE__.'\DateType', $dateOptions) - ->add('time', __NAMESPACE__.'\TimeType', $timeOptions) + ->add('date', DateType::class, $dateOptions) + ->add('time', TimeType::class, $timeOptions) ; } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/EmailType.php b/src/Symfony/Component/Form/Extension/Core/Type/EmailType.php index 2434778c760c4..1bc1019ab9f26 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/EmailType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/EmailType.php @@ -20,7 +20,7 @@ class EmailType extends AbstractType */ public function getParent() { - return __NAMESPACE__.'\TextType'; + return TextType::class; } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php b/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php index e23bc954794dd..ecce8a7a3af09 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php @@ -55,7 +55,7 @@ public function configureOptions(OptionsResolver $resolver) */ public function getParent() { - return __NAMESPACE__.'\ChoiceType'; + return ChoiceType::class; } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php index 21225b032d800..d53f217988c6f 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php @@ -55,7 +55,7 @@ public function configureOptions(OptionsResolver $resolver) */ public function getParent() { - return __NAMESPACE__.'\ChoiceType'; + return ChoiceType::class; } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/PasswordType.php b/src/Symfony/Component/Form/Extension/Core/Type/PasswordType.php index 5a5b2605a4222..a11708084feb7 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/PasswordType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/PasswordType.php @@ -44,7 +44,7 @@ public function configureOptions(OptionsResolver $resolver) */ public function getParent() { - return __NAMESPACE__.'\TextType'; + return TextType::class; } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/RadioType.php b/src/Symfony/Component/Form/Extension/Core/Type/RadioType.php index 7c0e8608478bc..471075b9a6bbc 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/RadioType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/RadioType.php @@ -20,7 +20,7 @@ class RadioType extends AbstractType */ public function getParent() { - return __NAMESPACE__.'\CheckboxType'; + return CheckboxType::class; } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/RangeType.php b/src/Symfony/Component/Form/Extension/Core/Type/RangeType.php index a69633c540407..36ecdb96da4ee 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/RangeType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/RangeType.php @@ -20,7 +20,7 @@ class RangeType extends AbstractType */ public function getParent() { - return __NAMESPACE__.'\TextType'; + return TextType::class; } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/RepeatedType.php b/src/Symfony/Component/Form/Extension/Core/Type/RepeatedType.php index 5f9ee5329cc09..ffb7520a582b6 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/RepeatedType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/RepeatedType.php @@ -47,7 +47,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) public function configureOptions(OptionsResolver $resolver) { $resolver->setDefaults([ - 'type' => __NAMESPACE__.'\TextType', + 'type' => TextType::class, 'options' => [], 'first_options' => [], 'second_options' => [], diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ResetType.php b/src/Symfony/Component/Form/Extension/Core/Type/ResetType.php index 16978ec5f1433..ce8013d1b09dc 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/ResetType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/ResetType.php @@ -26,7 +26,7 @@ class ResetType extends AbstractType implements ButtonTypeInterface */ public function getParent() { - return __NAMESPACE__.'\ButtonType'; + return ButtonType::class; } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/SearchType.php b/src/Symfony/Component/Form/Extension/Core/Type/SearchType.php index 4766ad094cd8f..c817a26d025b6 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/SearchType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/SearchType.php @@ -20,7 +20,7 @@ class SearchType extends AbstractType */ public function getParent() { - return __NAMESPACE__.'\TextType'; + return TextType::class; } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/SubmitType.php b/src/Symfony/Component/Form/Extension/Core/Type/SubmitType.php index 38666325f374a..78ed618c843d1 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/SubmitType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/SubmitType.php @@ -33,7 +33,7 @@ public function buildView(FormView $view, FormInterface $form, array $options) */ public function getParent() { - return __NAMESPACE__.'\ButtonType'; + return ButtonType::class; } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TextareaType.php b/src/Symfony/Component/Form/Extension/Core/Type/TextareaType.php index e4127f932cfc6..7db19d8aedc65 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/TextareaType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/TextareaType.php @@ -30,7 +30,7 @@ public function buildView(FormView $view, FormInterface $form, array $options) */ public function getParent() { - return __NAMESPACE__.'\TextType'; + return TextType::class; } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php b/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php index dfbe2b1800b96..9f92557052e1a 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/TimezoneType.php @@ -77,7 +77,7 @@ public function configureOptions(OptionsResolver $resolver) */ public function getParent() { - return __NAMESPACE__.'\ChoiceType'; + return ChoiceType::class; } /** diff --git a/src/Symfony/Component/Form/Extension/Core/Type/UrlType.php b/src/Symfony/Component/Form/Extension/Core/Type/UrlType.php index 39b9d2d20828c..b0392a9849b03 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/UrlType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/UrlType.php @@ -56,7 +56,7 @@ public function configureOptions(OptionsResolver $resolver) */ public function getParent() { - return __NAMESPACE__.'\TextType'; + return TextType::class; } /** diff --git a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php index 9e167c82155c9..07ecabdad1346 100644 --- a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php +++ b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php @@ -30,7 +30,7 @@ class FormValidator extends ConstraintValidator public function validate($form, Constraint $formConstraint) { if (!$formConstraint instanceof Form) { - throw new UnexpectedTypeException($formConstraint, __NAMESPACE__.'\Form'); + throw new UnexpectedTypeException($formConstraint, Form::class); } if (!$form instanceof FormInterface) { diff --git a/src/Symfony/Component/Form/LICENSE b/src/Symfony/Component/Form/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Form/LICENSE +++ b/src/Symfony/Component/Form/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Form/README.md b/src/Symfony/Component/Form/README.md index 3fe6f8bbf3206..5519cd00058dd 100644 --- a/src/Symfony/Component/Form/README.md +++ b/src/Symfony/Component/Form/README.md @@ -6,7 +6,7 @@ The Form component allows you to easily create, process and reuse HTML forms. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/form/index.html) + * [Documentation](https://symfony.com/doc/current/components/form.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php index e024ac3338a94..e19620e790f7c 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php @@ -133,7 +133,10 @@ public function testDontValidateIfParentWithoutValidConstraint() $parent->add($form); $form->setData($object); + $parent->submit([]); + $this->assertTrue($form->isSubmitted()); + $this->assertTrue($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); @@ -188,10 +191,15 @@ public function testDontValidateIfNoValidationGroups() 'validation_groups' => [], ]) ->setData($object) + ->setCompound(true) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $form->setData($object); + $form->submit([]); + $this->assertTrue($form->isSubmitted()); + $this->assertTrue($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); @@ -214,6 +222,8 @@ public function testDontValidateConstraintsIfNoValidationGroups() // Launch transformer $form->submit('foo'); + $this->assertTrue($form->isSubmitted()); + $this->assertTrue($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); @@ -236,6 +246,8 @@ public function testDontValidateChildConstraintsIfCallableNoValidationGroups() $form->add($child); $form->submit([]); + $this->assertTrue($form->isSubmitted()); + $this->assertTrue($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); @@ -264,6 +276,8 @@ function () { throw new TransformationFailedException(); } // Launch transformer $form->submit('foo'); + $this->assertTrue($form->isSubmitted()); + $this->assertFalse($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); @@ -299,6 +313,8 @@ function () { throw new TransformationFailedException(); } // Launch transformer $form->submit('foo'); + $this->assertTrue($form->isSubmitted()); + $this->assertFalse($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); @@ -369,6 +385,8 @@ function () { throw new TransformationFailedException(); } // Launch transformer $form->submit(['child' => 'foo']); + $this->assertTrue($form->isSubmitted()); + $this->assertFalse($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); @@ -574,7 +592,10 @@ public function testDontWalkScalars() $form = $this->getBuilder() ->setData('scalar') ->getForm(); + $form->submit('foo'); + $this->assertTrue($form->isSubmitted()); + $this->assertTrue($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); @@ -592,6 +613,8 @@ public function testViolationIfExtraData() $form->submit(['foo' => 'bar']); + $this->assertTrue($form->isSubmitted()); + $this->assertTrue($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); @@ -613,6 +636,8 @@ public function testViolationFormatIfMultipleExtraFields() $form->submit(['foo' => 'bar', 'baz' => 'qux', 'quux' => 'quuz']); + $this->assertTrue($form->isSubmitted()); + $this->assertTrue($form->isSynchronized()); $this->expectNoValidate(); $this->validator->validate($form, new Form()); diff --git a/src/Symfony/Component/Form/Tests/Fixtures/FooSubType.php b/src/Symfony/Component/Form/Tests/Fixtures/FooSubType.php index e4a4f3612e19d..61aa451236d7f 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/FooSubType.php +++ b/src/Symfony/Component/Form/Tests/Fixtures/FooSubType.php @@ -17,6 +17,6 @@ class FooSubType extends AbstractType { public function getParent() { - return __NAMESPACE__.'\FooType'; + return FooType::class; } } diff --git a/src/Symfony/Component/Form/Tests/Fixtures/FooTypeBarExtension.php b/src/Symfony/Component/Form/Tests/Fixtures/FooTypeBarExtension.php index 7eda15546cd5f..8cd34ebb239ed 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/FooTypeBarExtension.php +++ b/src/Symfony/Component/Form/Tests/Fixtures/FooTypeBarExtension.php @@ -30,6 +30,6 @@ public function getAllowedOptionValues() public function getExtendedType() { - return __NAMESPACE__.'\FooType'; + return FooType::class; } } diff --git a/src/Symfony/Component/Form/Tests/Fixtures/FooTypeBazExtension.php b/src/Symfony/Component/Form/Tests/Fixtures/FooTypeBazExtension.php index 646d41f7ffe00..658f574bfc484 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/FooTypeBazExtension.php +++ b/src/Symfony/Component/Form/Tests/Fixtures/FooTypeBazExtension.php @@ -23,6 +23,6 @@ public function buildForm(FormBuilderInterface $builder, array $options) public function getExtendedType() { - return __NAMESPACE__.'\FooType'; + return FooType::class; } } diff --git a/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php b/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php index 19b15e0c9fae9..da8bdbbfafd3a 100644 --- a/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php +++ b/src/Symfony/Component/Form/Tests/ResolvedFormTypeTest.php @@ -350,12 +350,12 @@ public function testBlockPrefixDefaultsToFQCNIfNoName($typeClass, $blockPrefix) public function provideTypeClassBlockPrefixTuples() { return [ - [__NAMESPACE__.'\Fixtures\FooType', 'foo'], - [__NAMESPACE__.'\Fixtures\Foo', 'foo'], - [__NAMESPACE__.'\Fixtures\Type', 'type'], - [__NAMESPACE__.'\Fixtures\FooBarHTMLType', 'foo_bar_html'], + [Fixtures\FooType::class, 'foo'], + [Fixtures\Foo::class, 'foo'], + [Fixtures\Type::class, 'type'], + [Fixtures\FooBarHTMLType::class, 'foo_bar_html'], [__NAMESPACE__.'\Fixtures\Foo1Bar2Type', 'foo1_bar2'], - [__NAMESPACE__.'\Fixtures\FBooType', 'f_boo'], + [Fixtures\FBooType::class, 'f_boo'], ]; } diff --git a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php index ea7ac846974bd..c2f66d6952ab2 100644 --- a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php +++ b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php @@ -217,7 +217,7 @@ public function prepare(Request $request) } if ('x-accel-redirect' === strtolower($type)) { // Do X-Accel-Mapping substitutions. - // @link http://wiki.nginx.org/X-accel#X-Accel-Redirect + // @link https://www.nginx.com/resources/wiki/start/topics/examples/x-accel/#x-accel-redirect foreach (explode(',', $request->headers->get('X-Accel-Mapping', '')) as $mapping) { $mapping = explode('=', $mapping, 2); diff --git a/src/Symfony/Component/HttpFoundation/LICENSE b/src/Symfony/Component/HttpFoundation/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/HttpFoundation/LICENSE +++ b/src/Symfony/Component/HttpFoundation/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/HttpFoundation/README.md b/src/Symfony/Component/HttpFoundation/README.md index 8907f0b967896..ac98f9b80ad5d 100644 --- a/src/Symfony/Component/HttpFoundation/README.md +++ b/src/Symfony/Component/HttpFoundation/README.md @@ -7,7 +7,7 @@ specification. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/http_foundation/index.html) + * [Documentation](https://symfony.com/doc/current/components/http_foundation.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php b/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php index 1dc8dc2c5f651..e11b98a10f65b 100644 --- a/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php +++ b/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php @@ -309,13 +309,13 @@ public function makeDisposition($disposition, $filename, $filenameFallback = '') */ protected function computeCacheControlValue() { - if (!$this->cacheControl && !$this->has('ETag') && !$this->has('Last-Modified') && !$this->has('Expires')) { - return 'no-cache, private'; - } - if (!$this->cacheControl) { + if ($this->has('Last-Modified') || $this->has('Expires')) { + return 'private, must-revalidate'; // allows for heuristic expiration (RFC 7234 Section 4.2.2) in the case of "Last-Modified" + } + // conservative by default - return 'private, must-revalidate'; + return 'no-cache, private'; } $header = $this->getCacheControlHeader(); diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php index c9d47b6ed7c27..653ca6917bbc1 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php @@ -218,7 +218,7 @@ public function createTable() // - trailing space removal // - case-insensitivity // - language processing like é == e - $sql = "CREATE TABLE $this->table ($this->idCol VARBINARY(128) NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER UNSIGNED NOT NULL, $this->timeCol INTEGER UNSIGNED NOT NULL) COLLATE utf8_bin, ENGINE = InnoDB"; + $sql = "CREATE TABLE $this->table ($this->idCol VARBINARY(128) NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER UNSIGNED NOT NULL, $this->timeCol INTEGER UNSIGNED NOT NULL) COLLATE utf8mb4_bin, ENGINE = InnoDB"; break; case 'sqlite': $sql = "CREATE TABLE $this->table ($this->idCol TEXT NOT NULL PRIMARY KEY, $this->dataCol BLOB NOT NULL, $this->lifetimeCol INTEGER NOT NULL, $this->timeCol INTEGER NOT NULL)"; diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php index 4c5873728a19d..df7da3c72f046 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php @@ -375,13 +375,11 @@ public function setOptions(array $options) * ini_set('session.save_path', '/tmp'); * * or pass in a \SessionHandler instance which configures session.save_handler in the - * constructor, for a template see NativeFileSessionHandler or use handlers in - * composer package drak/native-session + * constructor, for a template see NativeFileSessionHandler. * * @see https://php.net/session-set-save-handler * @see https://php.net/sessionhandlerinterface * @see https://php.net/sessionhandler - * @see https://github.com/zikula/NativeSession * * @param \SessionHandlerInterface|null $saveHandler * diff --git a/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php index d85f6e112fd12..4e3a6c82b5513 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php @@ -51,9 +51,9 @@ public function testCacheControlHeader() $this->assertTrue($bag->hasCacheControlDirective('public')); $bag = new ResponseHeaderBag(['ETag' => 'abcde']); - $this->assertEquals('private, must-revalidate', $bag->get('Cache-Control')); + $this->assertEquals('no-cache, private', $bag->get('Cache-Control')); $this->assertTrue($bag->hasCacheControlDirective('private')); - $this->assertTrue($bag->hasCacheControlDirective('must-revalidate')); + $this->assertTrue($bag->hasCacheControlDirective('no-cache')); $this->assertFalse($bag->hasCacheControlDirective('max-age')); $bag = new ResponseHeaderBag(['Expires' => 'Wed, 16 Feb 2011 14:17:43 GMT']); diff --git a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php index dbe028065948d..da60e74642cb4 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php @@ -323,6 +323,10 @@ protected function lookup(Request $request, $catch = false) return $this->validate($request, $entry, $catch); } + if ($entry->headers->hasCacheControlDirective('no-cache')) { + return $this->validate($request, $entry, $catch); + } + $this->record($request, 'fresh'); $entry->headers->set('Age', $entry->getAge()); diff --git a/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php b/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php index 3bdf0f5199891..aee689e1cea3d 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php @@ -110,8 +110,6 @@ public function update(Response $response) $response->headers->set('Age', $this->age); if ($this->isNotCacheableResponseEmbedded) { - $response->setExpires($response->getDate()); - if ($this->flagDirectives['no-store']) { $response->headers->set('Cache-Control', 'no-cache, no-store, must-revalidate'); } else { diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 434174d5b8635..463b49174fbf3 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -67,11 +67,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '3.4.36'; - const VERSION_ID = 30436; + const VERSION = '3.4.37'; + const VERSION_ID = 30437; const MAJOR_VERSION = 3; const MINOR_VERSION = 4; - const RELEASE_VERSION = 36; + const RELEASE_VERSION = 37; const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '11/2020'; diff --git a/src/Symfony/Component/HttpKernel/LICENSE b/src/Symfony/Component/HttpKernel/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/HttpKernel/LICENSE +++ b/src/Symfony/Component/HttpKernel/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/HttpKernel/README.md b/src/Symfony/Component/HttpKernel/README.md index cc5e74b6bca3b..abdaf513f9cde 100644 --- a/src/Symfony/Component/HttpKernel/README.md +++ b/src/Symfony/Component/HttpKernel/README.md @@ -9,7 +9,7 @@ an advanced CMS system (Drupal). Resources --------- - * [Documentation](https://symfony.com/doc/current/components/http_kernel/index.html) + * [Documentation](https://symfony.com/doc/current/components/http_kernel.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/HttpKernel/Tests/Controller/ContainerControllerResolverTest.php b/src/Symfony/Component/HttpKernel/Tests/Controller/ContainerControllerResolverTest.php index 1f8ddb83143f4..bdb2a00f4be5a 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Controller/ContainerControllerResolverTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Controller/ContainerControllerResolverTest.php @@ -71,7 +71,7 @@ public function testGetControllerInvokableService() public function testGetControllerInvokableServiceWithClassNameAsName() { $invokableController = new InvokableController('bar'); - $className = __NAMESPACE__.'\InvokableController'; + $className = InvokableController::class; $container = $this->createMockContainer(); $container->expects($this->once()) diff --git a/src/Symfony/Component/HttpKernel/Tests/ControllerMetadata/ArgumentMetadataFactoryTest.php b/src/Symfony/Component/HttpKernel/Tests/ControllerMetadata/ArgumentMetadataFactoryTest.php index 1c0c4648a0f2a..e5c62a87caf74 100644 --- a/src/Symfony/Component/HttpKernel/Tests/ControllerMetadata/ArgumentMetadataFactoryTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/ControllerMetadata/ArgumentMetadataFactoryTest.php @@ -48,7 +48,7 @@ public function testSignature2() $this->assertEquals([ new ArgumentMetadata('foo', self::class, false, true, null, true), - new ArgumentMetadata('bar', __NAMESPACE__.'\FakeClassThatDoesNotExist', false, true, null, true), + new ArgumentMetadata('bar', FakeClassThatDoesNotExist::class, false, true, null, true), new ArgumentMetadata('baz', 'Fake\ImportedAndFake', false, true, null, true), ], $arguments); } @@ -58,7 +58,7 @@ public function testSignature3() $arguments = $this->factory->createArgumentMetadata([$this, 'signature3']); $this->assertEquals([ - new ArgumentMetadata('bar', __NAMESPACE__.'\FakeClassThatDoesNotExist', false, false, null), + new ArgumentMetadata('bar', FakeClassThatDoesNotExist::class, false, false, null), new ArgumentMetadata('baz', 'Fake\ImportedAndFake', false, false, null), ], $arguments); } diff --git a/src/Symfony/Component/HttpKernel/Tests/DataCollector/RequestDataCollectorTest.php b/src/Symfony/Component/HttpKernel/Tests/DataCollector/RequestDataCollectorTest.php index 5e97267da5423..9b6264be3920c 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DataCollector/RequestDataCollectorTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DataCollector/RequestDataCollectorTest.php @@ -99,7 +99,7 @@ public function provideControllerCallables() '"Regular" callable', [$this, 'testControllerInspection'], [ - 'class' => __NAMESPACE__.'\RequestDataCollectorTest', + 'class' => RequestDataCollectorTest::class, 'method' => 'testControllerInspection', 'file' => __FILE__, 'line' => $r1->getStartLine(), diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php index 93d92eb11e7e3..ef201de6cf15f 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php @@ -443,6 +443,22 @@ public function testCachesResponsesWithExplicitNoCacheDirective() $this->assertTrue($this->response->headers->has('Age')); } + public function testRevalidatesResponsesWithNoCacheDirectiveEvenIfFresh() + { + $this->setNextResponse(200, ['Cache-Control' => 'public, no-cache, max-age=10', 'ETag' => 'some-etag'], 'OK'); + $this->request('GET', '/'); // warm the cache + + sleep(5); + + $this->setNextResponse(304, ['Cache-Control' => 'public, no-cache, max-age=10', 'ETag' => 'some-etag']); + $this->request('GET', '/'); + + $this->assertHttpKernelIsCalled(); // no-cache -> MUST have revalidated at origin + $this->assertTraceContains('valid'); + $this->assertEquals('OK', $this->response->getContent()); + $this->assertEquals(0, $this->response->getAge()); + } + public function testCachesResponsesWithAnExpirationHeader() { $time = \DateTime::createFromFormat('U', time() + 5); @@ -1242,7 +1258,6 @@ public function testEsiCacheForceValidation() $this->request('GET', '/', [], [], true); $this->assertEquals('Hello World! My name is Bobby.', $this->response->getContent()); $this->assertNull($this->response->getTtl()); - $this->assertTrue($this->response->mustRevalidate()); $this->assertTrue($this->response->headers->hasCacheControlDirective('private')); $this->assertTrue($this->response->headers->hasCacheControlDirective('no-cache')); } @@ -1273,7 +1288,6 @@ public function testEsiCacheForceValidationForHeadRequests() // This can neither be cached nor revalidated, so it should be private/no cache $this->assertEmpty($this->response->getContent()); $this->assertNull($this->response->getTtl()); - $this->assertTrue($this->response->mustRevalidate()); $this->assertTrue($this->response->headers->hasCacheControlDirective('private')); $this->assertTrue($this->response->headers->hasCacheControlDirective('no-cache')); } diff --git a/src/Symfony/Component/Inflector/LICENSE b/src/Symfony/Component/Inflector/LICENSE index f03153cc4a232..2749b15672205 100644 --- a/src/Symfony/Component/Inflector/LICENSE +++ b/src/Symfony/Component/Inflector/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2012-2019 Fabien Potencier +Copyright (c) 2012-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Intl/LICENSE b/src/Symfony/Component/Intl/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Intl/LICENSE +++ b/src/Symfony/Component/Intl/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Ldap/LICENSE b/src/Symfony/Component/Ldap/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Ldap/LICENSE +++ b/src/Symfony/Component/Ldap/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Lock/LICENSE b/src/Symfony/Component/Lock/LICENSE index 3c464ca94359b..a7ec70801827a 100644 --- a/src/Symfony/Component/Lock/LICENSE +++ b/src/Symfony/Component/Lock/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2016-2019 Fabien Potencier +Copyright (c) 2016-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/OptionsResolver/LICENSE b/src/Symfony/Component/OptionsResolver/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/OptionsResolver/LICENSE +++ b/src/Symfony/Component/OptionsResolver/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Process/LICENSE b/src/Symfony/Component/Process/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Process/LICENSE +++ b/src/Symfony/Component/Process/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/PropertyAccess/LICENSE b/src/Symfony/Component/PropertyAccess/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/PropertyAccess/LICENSE +++ b/src/Symfony/Component/PropertyAccess/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 4297d3947ff53..7aff347134273 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -229,7 +229,7 @@ public function setValue(&$objectOrArray, $propertyPath, $value) $value = $zval[self::VALUE]; } } catch (\TypeError $e) { - self::throwInvalidArgumentException($e->getMessage(), $e->getTrace(), 0); + self::throwInvalidArgumentException($e->getMessage(), $e->getTrace(), 0, $e); // It wasn't thrown in this class so rethrow it throw $e; @@ -253,7 +253,7 @@ public static function handleError($type, $message, $file, $line, $context = []) return null !== self::$previousErrorHandler && false !== \call_user_func(self::$previousErrorHandler, $type, $message, $file, $line, $context); } - private static function throwInvalidArgumentException($message, $trace, $i) + private static function throwInvalidArgumentException($message, $trace, $i, $previous = null) { // the type mismatch is not caused by invalid arguments (but e.g. by an incompatible return type hint of the writer method) if (0 !== strpos($message, 'Argument ')) { @@ -267,7 +267,7 @@ private static function throwInvalidArgumentException($message, $trace, $i) $type = substr($message, 2 + $j, strpos($message, ' given', $j) - $j - 2); $message = substr($message, $pos, $j - $pos); - throw new InvalidArgumentException(sprintf('Expected argument of type "%s", "%s" given', $message, 'NULL' === $type ? 'null' : $type)); + throw new InvalidArgumentException(sprintf('Expected argument of type "%s", "%s" given', $message, 'NULL' === $type ? 'null' : $type), 0, $previous); } } diff --git a/src/Symfony/Component/PropertyAccess/README.md b/src/Symfony/Component/PropertyAccess/README.md index 1959fd9e93492..891528d29cb94 100644 --- a/src/Symfony/Component/PropertyAccess/README.md +++ b/src/Symfony/Component/PropertyAccess/README.md @@ -7,7 +7,7 @@ object or array using a simple string notation. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/property_access/index.html) + * [Documentation](https://symfony.com/doc/current/components/property_access.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php index 76b6c43400791..787bf4b5d2d09 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php @@ -212,6 +212,8 @@ private function getDocBlockFromProperty($class, $property) return $this->docBlockFactory->create($reflectionProperty, $this->contextFactory->createFromReflector($reflectionProperty->getDeclaringClass())); } catch (\InvalidArgumentException $e) { return null; + } catch (\RuntimeException $e) { + return null; } } @@ -257,6 +259,8 @@ private function getDocBlockFromMethod($class, $ucFirstProperty, $type) return [$this->docBlockFactory->create($reflectionMethod, $this->contextFactory->createFromReflector($reflectionMethod)), $prefix]; } catch (\InvalidArgumentException $e) { return null; + } catch (\RuntimeException $e) { + return null; } } } diff --git a/src/Symfony/Component/PropertyInfo/LICENSE b/src/Symfony/Component/PropertyInfo/LICENSE index 4cd8bdd3007da..5612f967a232e 100644 --- a/src/Symfony/Component/PropertyInfo/LICENSE +++ b/src/Symfony/Component/PropertyInfo/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2015-2019 Fabien Potencier +Copyright (c) 2015-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Routing/LICENSE b/src/Symfony/Component/Routing/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Routing/LICENSE +++ b/src/Symfony/Component/Routing/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Routing/README.md b/src/Symfony/Component/Routing/README.md index 88fb1fde5a7bd..a16d9d7fcbbbb 100644 --- a/src/Symfony/Component/Routing/README.md +++ b/src/Symfony/Component/Routing/README.md @@ -6,7 +6,7 @@ The Routing component maps an HTTP request to a set of configuration variables. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/routing/index.html) + * [Documentation](https://symfony.com/doc/current/components/routing.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php index 9d846d5f26179..1d90434424137 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php +++ b/src/Symfony/Component/Security/Core/Authentication/Provider/DaoAuthenticationProvider.php @@ -61,7 +61,7 @@ protected function checkAuthentication(UserInterface $user, UsernamePasswordToke throw new BadCredentialsException('The presented password cannot be empty.'); } - if (!$this->encoderFactory->getEncoder($user)->isPasswordValid($user->getPassword(), $presentedPassword, $user->getSalt())) { + if (null === $user->getPassword() || !$this->encoderFactory->getEncoder($user)->isPasswordValid($user->getPassword(), $presentedPassword, $user->getSalt())) { throw new BadCredentialsException('The presented password is invalid.'); } } diff --git a/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php b/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php index 82e7cd459f2f0..aefd111b296aa 100644 --- a/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php +++ b/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php @@ -86,17 +86,13 @@ private function decideAffirmative(TokenInterface $token, array $attributes, $ob $deny = 0; foreach ($this->voters as $voter) { $result = $this->vote($voter, $token, $object, $attributes); - switch ($result) { - case VoterInterface::ACCESS_GRANTED: - return true; - case VoterInterface::ACCESS_DENIED: - ++$deny; - - break; + if (VoterInterface::ACCESS_GRANTED === $result) { + return true; + } - default: - break; + if (VoterInterface::ACCESS_DENIED === $result) { + ++$deny; } } @@ -128,16 +124,10 @@ private function decideConsensus(TokenInterface $token, array $attributes, $obje foreach ($this->voters as $voter) { $result = $this->vote($voter, $token, $object, $attributes); - switch ($result) { - case VoterInterface::ACCESS_GRANTED: - ++$grant; - - break; - - case VoterInterface::ACCESS_DENIED: - ++$deny; - - break; + if (VoterInterface::ACCESS_GRANTED === $result) { + ++$grant; + } elseif (VoterInterface::ACCESS_DENIED === $result) { + ++$deny; } } @@ -169,17 +159,12 @@ private function decideUnanimous(TokenInterface $token, array $attributes, $obje foreach ($attributes as $attribute) { $result = $this->vote($voter, $token, $object, [$attribute]); - switch ($result) { - case VoterInterface::ACCESS_GRANTED: - ++$grant; - - break; - - case VoterInterface::ACCESS_DENIED: - return false; + if (VoterInterface::ACCESS_DENIED === $result) { + return false; + } - default: - break; + if (VoterInterface::ACCESS_GRANTED === $result) { + ++$grant; } } } diff --git a/src/Symfony/Component/Security/Core/Encoder/UserPasswordEncoder.php b/src/Symfony/Component/Security/Core/Encoder/UserPasswordEncoder.php index 3efc8c6d48bb5..479a5731c2547 100644 --- a/src/Symfony/Component/Security/Core/Encoder/UserPasswordEncoder.php +++ b/src/Symfony/Component/Security/Core/Encoder/UserPasswordEncoder.php @@ -42,6 +42,10 @@ public function encodePassword(UserInterface $user, $plainPassword) */ public function isPasswordValid(UserInterface $user, $raw) { + if (null === $user->getPassword()) { + return false; + } + $encoder = $this->encoderFactory->getEncoder($user); return $encoder->isPasswordValid($user->getPassword(), $raw, $user->getSalt()); diff --git a/src/Symfony/Component/Security/Core/LICENSE b/src/Symfony/Component/Security/Core/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Security/Core/LICENSE +++ b/src/Symfony/Component/Security/Core/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Security/Core/README.md b/src/Symfony/Component/Security/Core/README.md index ede185bd3b3f5..70476d9e7f2b2 100644 --- a/src/Symfony/Component/Security/Core/README.md +++ b/src/Symfony/Component/Security/Core/README.md @@ -9,7 +9,7 @@ the Java Spring framework. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/security/index.html) + * [Documentation](https://symfony.com/doc/current/components/security.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php index bb0576fb4c1a2..7f46b1bcae3d5 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/DaoAuthenticationProviderTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Security\Core\Authentication\Provider\DaoAuthenticationProvider; use Symfony\Component\Security\Core\Encoder\PlaintextPasswordEncoder; use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; +use Symfony\Component\Security\Core\User\User; class DaoAuthenticationProviderTest extends TestCase { @@ -151,7 +152,7 @@ public function testCheckAuthenticationWhenCredentialsAre0() $method->invoke( $provider, - $this->getMockBuilder('Symfony\\Component\\Security\\Core\\User\\UserInterface')->getMock(), + new User('username', 'password'), $token ); } @@ -175,7 +176,7 @@ public function testCheckAuthenticationWhenCredentialsAreNotValid() ->willReturn('foo') ; - $method->invoke($provider, $this->getMockBuilder('Symfony\\Component\\Security\\Core\\User\\UserInterface')->getMock(), $token); + $method->invoke($provider, new User('username', 'password'), $token); } public function testCheckAuthenticationDoesNotReauthenticateWhenPasswordHasChanged() @@ -247,7 +248,7 @@ public function testCheckAuthentication() ->willReturn('foo') ; - $method->invoke($provider, $this->getMockBuilder('Symfony\\Component\\Security\\Core\\User\\UserInterface')->getMock(), $token); + $method->invoke($provider, new User('username', 'password'), $token); } protected function getSupportedToken() diff --git a/src/Symfony/Component/Security/Core/Tests/User/ChainUserProviderTest.php b/src/Symfony/Component/Security/Core/Tests/User/ChainUserProviderTest.php index 1592bcd2fe8e8..cf4909dfe8829 100644 --- a/src/Symfony/Component/Security/Core/Tests/User/ChainUserProviderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/User/ChainUserProviderTest.php @@ -68,24 +68,49 @@ public function testRefreshUser() $provider1 = $this->getProvider(); $provider1 ->expects($this->once()) - ->method('refreshUser') - ->willThrowException(new UnsupportedUserException('unsupported')) + ->method('supportsClass') + ->willReturn(false) ; $provider2 = $this->getProvider(); + $provider2 + ->expects($this->once()) + ->method('supportsClass') + ->willReturn(true) + ; + $provider2 + ->expects($this->once()) + ->method('refreshUser') + ->willThrowException(new UnsupportedUserException('unsupported')) + ; + + $provider3 = $this->getProvider(); + $provider3 + ->expects($this->once()) + ->method('supportsClass') + ->willReturn(true) + ; + + $provider3 ->expects($this->once()) ->method('refreshUser') ->willReturn($account = $this->getAccount()) ; - $provider = new ChainUserProvider([$provider1, $provider2]); + $provider = new ChainUserProvider([$provider1, $provider2, $provider3]); $this->assertSame($account, $provider->refreshUser($this->getAccount())); } public function testRefreshUserAgain() { $provider1 = $this->getProvider(); + $provider1 + ->expects($this->once()) + ->method('supportsClass') + ->willReturn(true) + ; + $provider1 ->expects($this->once()) ->method('refreshUser') @@ -93,6 +118,12 @@ public function testRefreshUserAgain() ; $provider2 = $this->getProvider(); + $provider2 + ->expects($this->once()) + ->method('supportsClass') + ->willReturn(true) + ; + $provider2 ->expects($this->once()) ->method('refreshUser') @@ -107,6 +138,12 @@ public function testRefreshUserThrowsUnsupportedUserException() { $this->expectException('Symfony\Component\Security\Core\Exception\UnsupportedUserException'); $provider1 = $this->getProvider(); + $provider1 + ->expects($this->once()) + ->method('supportsClass') + ->willReturn(true) + ; + $provider1 ->expects($this->once()) ->method('refreshUser') @@ -114,6 +151,12 @@ public function testRefreshUserThrowsUnsupportedUserException() ; $provider2 = $this->getProvider(); + $provider2 + ->expects($this->once()) + ->method('supportsClass') + ->willReturn(true) + ; + $provider2 ->expects($this->once()) ->method('refreshUser') @@ -171,6 +214,12 @@ public function testSupportsClassWhenNotSupported() public function testAcceptsTraversable() { $provider1 = $this->getProvider(); + $provider1 + ->expects($this->once()) + ->method('supportsClass') + ->willReturn(true) + ; + $provider1 ->expects($this->once()) ->method('refreshUser') @@ -178,6 +227,12 @@ public function testAcceptsTraversable() ; $provider2 = $this->getProvider(); + $provider2 + ->expects($this->once()) + ->method('supportsClass') + ->willReturn(true) + ; + $provider2 ->expects($this->once()) ->method('refreshUser') diff --git a/src/Symfony/Component/Security/Core/User/ChainUserProvider.php b/src/Symfony/Component/Security/Core/User/ChainUserProvider.php index 02ce08464d218..5ea8150a3017e 100644 --- a/src/Symfony/Component/Security/Core/User/ChainUserProvider.php +++ b/src/Symfony/Component/Security/Core/User/ChainUserProvider.php @@ -73,6 +73,10 @@ public function refreshUser(UserInterface $user) foreach ($this->providers as $provider) { try { + if (!$provider->supportsClass(\get_class($user))) { + continue; + } + return $provider->refreshUser($user); } catch (UnsupportedUserException $e) { // try next one diff --git a/src/Symfony/Component/Security/Core/Validator/Constraints/UserPasswordValidator.php b/src/Symfony/Component/Security/Core/Validator/Constraints/UserPasswordValidator.php index 41559a3adcd17..24b032484fa1a 100644 --- a/src/Symfony/Component/Security/Core/Validator/Constraints/UserPasswordValidator.php +++ b/src/Symfony/Component/Security/Core/Validator/Constraints/UserPasswordValidator.php @@ -36,7 +36,7 @@ public function __construct(TokenStorageInterface $tokenStorage, EncoderFactoryI public function validate($password, Constraint $constraint) { if (!$constraint instanceof UserPassword) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\UserPassword'); + throw new UnexpectedTypeException($constraint, UserPassword::class); } if (null === $password || '' === $password) { @@ -53,7 +53,7 @@ public function validate($password, Constraint $constraint) $encoder = $this->encoderFactory->getEncoder($user); - if (!$encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt())) { + if (null === $user->getPassword() || !$encoder->isPasswordValid($user->getPassword(), $password, $user->getSalt())) { $this->context->addViolation($constraint->message); } } diff --git a/src/Symfony/Component/Security/Csrf/LICENSE b/src/Symfony/Component/Security/Csrf/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Security/Csrf/LICENSE +++ b/src/Symfony/Component/Security/Csrf/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Security/Csrf/README.md b/src/Symfony/Component/Security/Csrf/README.md index aff72a0c32240..15b9ace238fb9 100644 --- a/src/Symfony/Component/Security/Csrf/README.md +++ b/src/Symfony/Component/Security/Csrf/README.md @@ -7,7 +7,7 @@ The Security CSRF (cross-site request forgery) component provides a class Resources --------- - * [Documentation](https://symfony.com/doc/current/components/security/index.html) + * [Documentation](https://symfony.com/doc/current/components/security.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Security/Guard/LICENSE b/src/Symfony/Component/Security/Guard/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Security/Guard/LICENSE +++ b/src/Symfony/Component/Security/Guard/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Security/Guard/README.md b/src/Symfony/Component/Security/Guard/README.md index ce706223901b3..40083a48d7682 100644 --- a/src/Symfony/Component/Security/Guard/README.md +++ b/src/Symfony/Component/Security/Guard/README.md @@ -8,7 +8,7 @@ total control. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/security/index.html) + * [Documentation](https://symfony.com/doc/current/components/security.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php index ea9f51f9224ad..6a05ee5175cb1 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php @@ -168,12 +168,17 @@ protected function refreshUser(TokenInterface $token) $userNotFoundByProvider = false; $userDeauthenticated = false; + $userClass = \get_class($user); foreach ($this->userProviders as $provider) { if (!$provider instanceof UserProviderInterface) { throw new \InvalidArgumentException(sprintf('User provider "%s" must implement "%s".', \get_class($provider), UserProviderInterface::class)); } + if (!$provider->supportsClass($userClass)) { + continue; + } + try { $refreshedUser = $provider->refreshUser($user); $newToken = clone $token; @@ -233,7 +238,7 @@ protected function refreshUser(TokenInterface $token) return null; } - throw new \RuntimeException(sprintf('There is no user provider for user "%s".', \get_class($user))); + throw new \RuntimeException(sprintf('There is no user provider for user "%s".', $userClass)); } private function safelyUnserialize($serializedToken) diff --git a/src/Symfony/Component/Security/Http/LICENSE b/src/Symfony/Component/Security/Http/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Security/Http/LICENSE +++ b/src/Symfony/Component/Security/Http/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Security/Http/README.md b/src/Symfony/Component/Security/Http/README.md index 5be2111830116..dbac8c659c112 100644 --- a/src/Symfony/Component/Security/Http/README.md +++ b/src/Symfony/Component/Security/Http/README.md @@ -9,7 +9,7 @@ the Java Spring framework. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/security/index.html) + * [Documentation](https://symfony.com/doc/current/components/security.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php index 8dacdafb574d1..bf69f3012b6ba 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php +++ b/src/Symfony/Component/Security/Http/RememberMe/AbstractRememberMeServices.php @@ -99,6 +99,10 @@ public function getSecret() */ final public function autoLogin(Request $request) { + if (($cookie = $request->attributes->get(self::COOKIE_ATTR_NAME)) && null === $cookie->getValue()) { + return null; + } + if (null === $cookie = $request->cookies->get($this->options['name'])) { return null; } diff --git a/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php b/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php index afa12e4f03d20..3df2ced6223fa 100644 --- a/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php +++ b/src/Symfony/Component/Security/Http/RememberMe/TokenBasedRememberMeServices.php @@ -89,10 +89,10 @@ protected function onLoginSuccess(Request $request, Response $response, TokenInt /** * Generates the cookie value. * - * @param string $class - * @param string $username The username - * @param int $expires The Unix timestamp when the cookie expires - * @param string $password The encoded password + * @param string $class + * @param string $username The username + * @param int $expires The Unix timestamp when the cookie expires + * @param string|null $password The encoded password * * @return string */ @@ -111,10 +111,10 @@ protected function generateCookieValue($class, $username, $expires, $password) /** * Generates a hash for the cookie to ensure it is not being tampered with. * - * @param string $class - * @param string $username The username - * @param int $expires The Unix timestamp when the cookie expires - * @param string $password The encoded password + * @param string $class + * @param string $username The username + * @param int $expires The Unix timestamp when the cookie expires + * @param string|null $password The encoded password * * @return string */ diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php index acab7087cb92f..74c459604cc8c 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ContextListenerTest.php @@ -256,7 +256,7 @@ public function testIfTokenIsDeauthenticatedTriggersDeprecations() { $tokenStorage = new TokenStorage(); $refreshedUser = new User('foobar', 'baz'); - $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(), new SupportingUserProvider($refreshedUser)]); + $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(true), new NotSupportingUserProvider(false), new SupportingUserProvider($refreshedUser)]); $this->assertSame($refreshedUser, $tokenStorage->getToken()->getUser()); } @@ -265,7 +265,7 @@ public function testIfTokenIsDeauthenticated() { $tokenStorage = new TokenStorage(); $refreshedUser = new User('foobar', 'baz'); - $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(), new SupportingUserProvider($refreshedUser)], null, true); + $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(true), new NotSupportingUserProvider(false), new SupportingUserProvider($refreshedUser)], null, true); $this->assertNull($tokenStorage->getToken()); } @@ -287,7 +287,7 @@ public function testRememberMeGetsCanceledIfTokenIsDeauthenticated() $rememberMeServices = $this->createMock(RememberMeServicesInterface::class); $rememberMeServices->expects($this->once())->method('loginFail'); - $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(), new SupportingUserProvider($refreshedUser)], null, true, $rememberMeServices); + $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(true), new NotSupportingUserProvider(false), new SupportingUserProvider($refreshedUser)], null, true, $rememberMeServices); $this->assertNull($tokenStorage->getToken()); } @@ -296,7 +296,7 @@ public function testTryAllUserProvidersUntilASupportingUserProviderIsFound() { $tokenStorage = new TokenStorage(); $refreshedUser = new User('foobar', 'baz'); - $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(), new SupportingUserProvider($refreshedUser)], $refreshedUser); + $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(true), new NotSupportingUserProvider(false), new SupportingUserProvider($refreshedUser)], $refreshedUser); $this->assertSame($refreshedUser, $tokenStorage->getToken()->getUser()); } @@ -313,7 +313,7 @@ public function testNextSupportingUserProviderIsTriedIfPreviousSupportingUserPro public function testTokenIsSetToNullIfNoUserWasLoadedByTheRegisteredUserProviders() { $tokenStorage = new TokenStorage(); - $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(), new SupportingUserProvider()]); + $this->handleEventWithPreviousSession($tokenStorage, [new NotSupportingUserProvider(true), new NotSupportingUserProvider(false), new SupportingUserProvider()]); $this->assertNull($tokenStorage->getToken()); } @@ -321,14 +321,14 @@ public function testTokenIsSetToNullIfNoUserWasLoadedByTheRegisteredUserProvider public function testRuntimeExceptionIsThrownIfNoSupportingUserProviderWasRegistered() { $this->expectException('RuntimeException'); - $this->handleEventWithPreviousSession(new TokenStorage(), [new NotSupportingUserProvider(), new NotSupportingUserProvider()]); + $this->handleEventWithPreviousSession(new TokenStorage(), [new NotSupportingUserProvider(false), new NotSupportingUserProvider(true)]); } public function testAcceptsProvidersAsTraversable() { $tokenStorage = new TokenStorage(); $refreshedUser = new User('foobar', 'baz'); - $this->handleEventWithPreviousSession($tokenStorage, new \ArrayObject([new NotSupportingUserProvider(), new SupportingUserProvider($refreshedUser)]), $refreshedUser); + $this->handleEventWithPreviousSession($tokenStorage, new \ArrayObject([new NotSupportingUserProvider(true), new NotSupportingUserProvider(false), new SupportingUserProvider($refreshedUser)]), $refreshedUser); $this->assertSame($refreshedUser, $tokenStorage->getToken()->getUser()); } @@ -383,6 +383,14 @@ private function handleEventWithPreviousSession(TokenStorageInterface $tokenStor class NotSupportingUserProvider implements UserProviderInterface { + /** @var bool */ + private $throwsUnsupportedException; + + public function __construct($throwsUnsupportedException) + { + $this->throwsUnsupportedException = $throwsUnsupportedException; + } + public function loadUserByUsername($username) { throw new UsernameNotFoundException(); @@ -390,7 +398,11 @@ public function loadUserByUsername($username) public function refreshUser(UserInterface $user) { - throw new UnsupportedUserException(); + if ($this->throwsUnsupportedException) { + throw new UnsupportedUserException(); + } + + return $user; } public function supportsClass($class) diff --git a/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php b/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php index 8dc2042f12c09..cf70ed4cb1618 100644 --- a/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php +++ b/src/Symfony/Component/Security/Http/Tests/RememberMe/AbstractRememberMeServicesTest.php @@ -39,6 +39,17 @@ public function testAutoLoginReturnsNullWhenNoCookie() $this->assertNull($service->autoLogin(new Request())); } + public function testAutoLoginReturnsNullAfterLoginFail() + { + $service = $this->getService(null, ['name' => 'foo', 'path' => null, 'domain' => null]); + + $request = new Request(); + $request->cookies->set('foo', 'foo'); + + $service->loginFail($request); + $this->assertNull($service->autoLogin($request)); + } + /** * @group legacy */ diff --git a/src/Symfony/Component/Security/LICENSE b/src/Symfony/Component/Security/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Security/LICENSE +++ b/src/Symfony/Component/Security/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Security/README.md b/src/Symfony/Component/Security/README.md index f55f8a10eab98..d98dcd9ed2cc1 100644 --- a/src/Symfony/Component/Security/README.md +++ b/src/Symfony/Component/Security/README.md @@ -11,7 +11,7 @@ roles. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/security/index.html) + * [Documentation](https://symfony.com/doc/current/components/security.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Serializer/LICENSE b/src/Symfony/Component/Serializer/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Serializer/LICENSE +++ b/src/Symfony/Component/Serializer/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php index 39c31f00f1590..d9d5a586e123a 100644 --- a/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php @@ -101,13 +101,7 @@ public function denormalize($data, $type, $format = null, array $context = []) $dateTimeErrors = \DateTime::class === $type ? \DateTime::getLastErrors() : \DateTimeImmutable::getLastErrors(); - throw new NotNormalizableValueException(sprintf( - 'Parsing datetime string "%s" using format "%s" resulted in %d errors:'."\n".'%s', - $data, - $dateTimeFormat, - $dateTimeErrors['error_count'], - implode("\n", $this->formatDateTimeErrors($dateTimeErrors['errors'])) - )); + throw new NotNormalizableValueException(sprintf('Parsing datetime string "%s" using format "%s" resulted in %d errors:'."\n".'%s', $data, $dateTimeFormat, $dateTimeErrors['error_count'], implode("\n", $this->formatDateTimeErrors($dateTimeErrors['errors'])))); } try { diff --git a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php index c1b3dd260e243..5c2cd7af1cc00 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php @@ -83,8 +83,14 @@ protected function extractAttributes($object, $format = null, array $context = [ } } + $checkPropertyInitialization = \PHP_VERSION_ID >= 70400; + // properties foreach ($reflClass->getProperties(\ReflectionProperty::IS_PUBLIC) as $reflProperty) { + if ($checkPropertyInitialization && !$reflProperty->isInitialized($object)) { + continue; + } + if ($reflProperty->isStatic() || !$this->isAllowedAttribute($object, $reflProperty->name, $format, $context)) { continue; } diff --git a/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php index 46faa1e7e9dfd..be6634b493204 100644 --- a/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/PropertyNormalizer.php @@ -99,9 +99,20 @@ protected function extractAttributes($object, $format = null, array $context = [ { $reflectionObject = new \ReflectionObject($object); $attributes = []; + $checkPropertyInitialization = \PHP_VERSION_ID >= 70400; do { foreach ($reflectionObject->getProperties() as $property) { + if ($checkPropertyInitialization) { + if (!$property->isPublic()) { + $property->setAccessible(true); + } + + if (!$property->isInitialized($object)) { + continue; + } + } + if (!$this->isAllowedAttribute($reflectionObject->getName(), $property->name, $format, $context)) { continue; } diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/Php74Dummy.php b/src/Symfony/Component/Serializer/Tests/Fixtures/Php74Dummy.php new file mode 100644 index 0000000000000..e8cebd9b45e95 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/Php74Dummy.php @@ -0,0 +1,22 @@ + + * + * 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; + +/** + * @author Valentin Udaltsov + */ +final class Php74Dummy +{ + public string $uninitializedProperty; + + public string $initializedProperty = 'defaultValue'; +} diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php index 4895526c45c0a..d5d7cace362e4 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php @@ -29,7 +29,7 @@ class AbstractObjectNormalizerTest extends TestCase public function testDenormalize() { $normalizer = new AbstractObjectNormalizerDummy(); - $normalizedData = $normalizer->denormalize(['foo' => 'foo', 'bar' => 'bar', 'baz' => 'baz'], __NAMESPACE__.'\Dummy'); + $normalizedData = $normalizer->denormalize(['foo' => 'foo', 'bar' => 'bar', 'baz' => 'baz'], Dummy::class); $this->assertSame('foo', $normalizedData->foo); $this->assertNull($normalizedData->bar); @@ -39,12 +39,12 @@ public function testDenormalize() public function testInstantiateObjectDenormalizer() { $data = ['foo' => 'foo', 'bar' => 'bar', 'baz' => 'baz']; - $class = __NAMESPACE__.'\Dummy'; + $class = Dummy::class; $context = []; $normalizer = new AbstractObjectNormalizerDummy(); - $this->assertInstanceOf(__NAMESPACE__.'\Dummy', $normalizer->instantiateObject($data, $class, $context, new \ReflectionClass($class), [])); + $this->assertInstanceOf(Dummy::class, $normalizer->instantiateObject($data, $class, $context, new \ReflectionClass($class), [])); } public function testDenormalizeWithExtraAttributes() @@ -55,7 +55,7 @@ public function testDenormalizeWithExtraAttributes() $normalizer = new AbstractObjectNormalizerDummy($factory); $normalizer->denormalize( ['fooFoo' => 'foo', 'fooBar' => 'bar'], - __NAMESPACE__.'\Dummy', + Dummy::class, 'any', ['allow_extra_attributes' => false] ); diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ArrayDenormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ArrayDenormalizerTest.php index 27bd361d3acb3..825ebd20b6f77 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/ArrayDenormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ArrayDenormalizerTest.php @@ -68,7 +68,7 @@ public function testSupportsValidArray() { $this->serializer->expects($this->once()) ->method('supportsDenormalization') - ->with($this->anything(), __NAMESPACE__.'\ArrayDummy', $this->anything()) + ->with($this->anything(), ArrayDummy::class, $this->anything()) ->willReturn(true); $this->assertTrue( @@ -104,7 +104,7 @@ public function testSupportsNoArray() $this->assertFalse( $this->denormalizer->supportsDenormalization( ['foo' => 'one', 'bar' => 'two'], - __NAMESPACE__.'\ArrayDummy' + ArrayDummy::class ) ); } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php index 13a244e72eb1c..43536e8144149 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/GetSetMethodNormalizerTest.php @@ -38,7 +38,7 @@ class GetSetMethodNormalizerTest extends TestCase protected function setUp() { - $this->serializer = $this->getMockBuilder(__NAMESPACE__.'\SerializerNormalizer')->getMock(); + $this->serializer = $this->getMockBuilder(SerializerNormalizer::class)->getMock(); $this->normalizer = new GetSetMethodNormalizer(); $this->normalizer->setSerializer($this->serializer); } @@ -83,7 +83,7 @@ public function testDenormalize() { $obj = $this->normalizer->denormalize( ['foo' => 'foo', 'bar' => 'bar', 'baz' => true, 'fooBar' => 'foobar'], - __NAMESPACE__.'\GetSetDummy', + GetSetDummy::class, 'any' ); $this->assertEquals('foo', $obj->getFoo()); @@ -114,21 +114,21 @@ public function testDenormalizeWithObject() $data->foo = 'foo'; $data->bar = 'bar'; $data->fooBar = 'foobar'; - $obj = $this->normalizer->denormalize($data, __NAMESPACE__.'\GetSetDummy', 'any'); + $obj = $this->normalizer->denormalize($data, GetSetDummy::class, 'any'); $this->assertEquals('foo', $obj->getFoo()); $this->assertEquals('bar', $obj->getBar()); } public function testDenormalizeNull() { - $this->assertEquals(new GetSetDummy(), $this->normalizer->denormalize(null, __NAMESPACE__.'\GetSetDummy')); + $this->assertEquals(new GetSetDummy(), $this->normalizer->denormalize(null, GetSetDummy::class)); } public function testConstructorDenormalize() { $obj = $this->normalizer->denormalize( ['foo' => 'foo', 'bar' => 'bar', 'baz' => true, 'fooBar' => 'foobar'], - __NAMESPACE__.'\GetConstructorDummy', 'any'); + GetConstructorDummy::class, 'any'); $this->assertEquals('foo', $obj->getFoo()); $this->assertEquals('bar', $obj->getBar()); $this->assertTrue($obj->isBaz()); @@ -138,7 +138,7 @@ public function testConstructorDenormalizeWithNullArgument() { $obj = $this->normalizer->denormalize( ['foo' => 'foo', 'bar' => null, 'baz' => true], - __NAMESPACE__.'\GetConstructorDummy', 'any'); + GetConstructorDummy::class, 'any'); $this->assertEquals('foo', $obj->getFoo()); $this->assertNull($obj->getBar()); $this->assertTrue($obj->isBaz()); @@ -148,7 +148,7 @@ public function testConstructorDenormalizeWithMissingOptionalArgument() { $obj = $this->normalizer->denormalize( ['foo' => 'test', 'baz' => [1, 2, 3]], - __NAMESPACE__.'\GetConstructorOptionalArgsDummy', 'any'); + GetConstructorOptionalArgsDummy::class, 'any'); $this->assertEquals('test', $obj->getFoo()); $this->assertEquals([], $obj->getBar()); $this->assertEquals([1, 2, 3], $obj->getBaz()); @@ -158,7 +158,7 @@ public function testConstructorDenormalizeWithOptionalDefaultArgument() { $obj = $this->normalizer->denormalize( ['bar' => 'test'], - __NAMESPACE__.'\GetConstructorArgsWithDefaultValueDummy', 'any'); + GetConstructorArgsWithDefaultValueDummy::class, 'any'); $this->assertEquals([], $obj->getFoo()); $this->assertEquals('test', $obj->getBar()); } @@ -192,14 +192,14 @@ public function testConstructorWithObjectDenormalize() $data->bar = 'bar'; $data->baz = true; $data->fooBar = 'foobar'; - $obj = $this->normalizer->denormalize($data, __NAMESPACE__.'\GetConstructorDummy', 'any'); + $obj = $this->normalizer->denormalize($data, GetConstructorDummy::class, 'any'); $this->assertEquals('foo', $obj->getFoo()); $this->assertEquals('bar', $obj->getBar()); } public function testConstructorWArgWithPrivateMutator() { - $obj = $this->normalizer->denormalize(['foo' => 'bar'], __NAMESPACE__.'\ObjectConstructorArgsWithPrivateMutatorDummy', 'any'); + $obj = $this->normalizer->denormalize(['foo' => 'bar'], ObjectConstructorArgsWithPrivateMutatorDummy::class, 'any'); $this->assertEquals('bar', $obj->getFoo()); } @@ -466,7 +466,7 @@ public function testObjectToPopulate() $obj = $this->normalizer->denormalize( ['bar' => 'bar'], - __NAMESPACE__.'\GetSetDummy', + GetSetDummy::class, null, [GetSetMethodNormalizer::OBJECT_TO_POPULATE => $dummy] ); @@ -480,13 +480,13 @@ public function testDenormalizeNonExistingAttribute() { $this->assertEquals( new GetSetDummy(), - $this->normalizer->denormalize(['non_existing' => true], __NAMESPACE__.'\GetSetDummy') + $this->normalizer->denormalize(['non_existing' => true], GetSetDummy::class) ); } public function testDenormalizeShouldNotSetStaticAttribute() { - $obj = $this->normalizer->denormalize(['staticObject' => true], __NAMESPACE__.'\GetSetDummy'); + $obj = $this->normalizer->denormalize(['staticObject' => true], GetSetDummy::class); $this->assertEquals(new GetSetDummy(), $obj); $this->assertNull(GetSetDummy::getStaticObject()); @@ -504,7 +504,7 @@ public function testNoStaticGetSetSupport() public function testPrivateSetter() { - $obj = $this->normalizer->denormalize(['foo' => 'foobar'], __NAMESPACE__.'\ObjectWithPrivateSetterDummy'); + $obj = $this->normalizer->denormalize(['foo' => 'foobar'], ObjectWithPrivateSetterDummy::class); $this->assertEquals('bar', $obj->getFoo()); } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php index 765db4c82bbae..62082e0cd2883 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php @@ -28,6 +28,7 @@ use Symfony\Component\Serializer\Tests\Fixtures\CircularReferenceDummy; use Symfony\Component\Serializer\Tests\Fixtures\GroupDummy; use Symfony\Component\Serializer\Tests\Fixtures\MaxDepthDummy; +use Symfony\Component\Serializer\Tests\Fixtures\Php74Dummy; use Symfony\Component\Serializer\Tests\Fixtures\SiblingHolder; /** @@ -46,7 +47,7 @@ class ObjectNormalizerTest extends TestCase protected function setUp() { - $this->serializer = $this->getMockBuilder(__NAMESPACE__.'\ObjectSerializerNormalizer')->getMock(); + $this->serializer = $this->getMockBuilder(ObjectSerializerNormalizer::class)->getMock(); $this->normalizer = new ObjectNormalizer(); $this->normalizer->setSerializer($this->serializer); } @@ -81,11 +82,23 @@ public function testNormalize() ); } + /** + * @requires PHP 7.4 + */ + public function testNormalizeObjectWithUninitializedProperties() + { + $obj = new Php74Dummy(); + $this->assertEquals( + ['initializedProperty' => 'defaultValue'], + $this->normalizer->normalize($obj, 'any') + ); + } + public function testDenormalize() { $obj = $this->normalizer->denormalize( ['foo' => 'foo', 'bar' => 'bar', 'baz' => true, 'fooBar' => 'foobar'], - __NAMESPACE__.'\ObjectDummy', + ObjectDummy::class, 'any' ); $this->assertEquals('foo', $obj->getFoo()); @@ -99,21 +112,21 @@ public function testDenormalizeWithObject() $data->foo = 'foo'; $data->bar = 'bar'; $data->fooBar = 'foobar'; - $obj = $this->normalizer->denormalize($data, __NAMESPACE__.'\ObjectDummy', 'any'); + $obj = $this->normalizer->denormalize($data, ObjectDummy::class, 'any'); $this->assertEquals('foo', $obj->getFoo()); $this->assertEquals('bar', $obj->bar); } public function testDenormalizeNull() { - $this->assertEquals(new ObjectDummy(), $this->normalizer->denormalize(null, __NAMESPACE__.'\ObjectDummy')); + $this->assertEquals(new ObjectDummy(), $this->normalizer->denormalize(null, ObjectDummy::class)); } public function testConstructorDenormalize() { $obj = $this->normalizer->denormalize( ['foo' => 'foo', 'bar' => 'bar', 'baz' => true, 'fooBar' => 'foobar'], - __NAMESPACE__.'\ObjectConstructorDummy', 'any'); + ObjectConstructorDummy::class, 'any'); $this->assertEquals('foo', $obj->getFoo()); $this->assertEquals('bar', $obj->bar); $this->assertTrue($obj->isBaz()); @@ -123,7 +136,7 @@ public function testConstructorDenormalizeWithNullArgument() { $obj = $this->normalizer->denormalize( ['foo' => 'foo', 'bar' => null, 'baz' => true], - __NAMESPACE__.'\ObjectConstructorDummy', 'any'); + ObjectConstructorDummy::class, 'any'); $this->assertEquals('foo', $obj->getFoo()); $this->assertNull($obj->bar); $this->assertTrue($obj->isBaz()); @@ -133,7 +146,7 @@ public function testConstructorDenormalizeWithMissingOptionalArgument() { $obj = $this->normalizer->denormalize( ['foo' => 'test', 'baz' => [1, 2, 3]], - __NAMESPACE__.'\ObjectConstructorOptionalArgsDummy', 'any'); + ObjectConstructorOptionalArgsDummy::class, 'any'); $this->assertEquals('test', $obj->getFoo()); $this->assertEquals([], $obj->bar); $this->assertEquals([1, 2, 3], $obj->getBaz()); @@ -143,7 +156,7 @@ public function testConstructorDenormalizeWithOptionalDefaultArgument() { $obj = $this->normalizer->denormalize( ['bar' => 'test'], - __NAMESPACE__.'\ObjectConstructorArgsWithDefaultValueDummy', 'any'); + ObjectConstructorArgsWithDefaultValueDummy::class, 'any'); $this->assertEquals([], $obj->getFoo()); $this->assertEquals('test', $obj->getBar()); } @@ -155,7 +168,7 @@ public function testConstructorWithObjectDenormalize() $data->bar = 'bar'; $data->baz = true; $data->fooBar = 'foobar'; - $obj = $this->normalizer->denormalize($data, __NAMESPACE__.'\ObjectConstructorDummy', 'any'); + $obj = $this->normalizer->denormalize($data, ObjectConstructorDummy::class, 'any'); $this->assertEquals('foo', $obj->getFoo()); $this->assertEquals('bar', $obj->bar); } @@ -397,7 +410,7 @@ public function testIgnoredAttributesDenormalize() $this->assertEquals( $obj, - $this->normalizer->denormalize(['fooBar' => 'fooBar', 'foo' => 'foo', 'baz' => 'baz'], __NAMESPACE__.'\ObjectDummy') + $this->normalizer->denormalize(['fooBar' => 'fooBar', 'foo' => 'foo', 'baz' => 'baz'], ObjectDummy::class) ); } @@ -521,7 +534,7 @@ public function testDenormalizeNonExistingAttribute() { $this->assertEquals( new ObjectDummy(), - $this->normalizer->denormalize(['non_existing' => true], __NAMESPACE__.'\ObjectDummy') + $this->normalizer->denormalize(['non_existing' => true], ObjectDummy::class) ); } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php index 4b138fca7ba98..d0e31ab4df783 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/PropertyNormalizerTest.php @@ -22,6 +22,7 @@ use Symfony\Component\Serializer\Tests\Fixtures\GroupDummy; use Symfony\Component\Serializer\Tests\Fixtures\GroupDummyChild; use Symfony\Component\Serializer\Tests\Fixtures\MaxDepthDummy; +use Symfony\Component\Serializer\Tests\Fixtures\Php74Dummy; use Symfony\Component\Serializer\Tests\Fixtures\PropertyCircularReferenceDummy; use Symfony\Component\Serializer\Tests\Fixtures\PropertySiblingHolder; @@ -55,11 +56,23 @@ public function testNormalize() ); } + /** + * @requires PHP 7.4 + */ + public function testNormalizeObjectWithUninitializedProperties() + { + $obj = new Php74Dummy(); + $this->assertEquals( + ['initializedProperty' => 'defaultValue'], + $this->normalizer->normalize($obj, 'any') + ); + } + public function testDenormalize() { $obj = $this->normalizer->denormalize( ['foo' => 'foo', 'bar' => 'bar'], - __NAMESPACE__.'\PropertyDummy', + PropertyDummy::class, 'any' ); $this->assertEquals('foo', $obj->foo); @@ -98,7 +111,7 @@ public function testConstructorDenormalize() { $obj = $this->normalizer->denormalize( ['foo' => 'foo', 'bar' => 'bar'], - __NAMESPACE__.'\PropertyConstructorDummy', + PropertyConstructorDummy::class, 'any' ); $this->assertEquals('foo', $obj->getFoo()); @@ -109,7 +122,7 @@ public function testConstructorDenormalizeWithNullArgument() { $obj = $this->normalizer->denormalize( ['foo' => null, 'bar' => 'bar'], - __NAMESPACE__.'\PropertyConstructorDummy', ' + PropertyConstructorDummy::class, ' any' ); $this->assertNull($obj->getFoo()); @@ -363,13 +376,13 @@ public function testDenormalizeNonExistingAttribute() { $this->assertEquals( new PropertyDummy(), - $this->normalizer->denormalize(['non_existing' => true], __NAMESPACE__.'\PropertyDummy') + $this->normalizer->denormalize(['non_existing' => true], PropertyDummy::class) ); } public function testDenormalizeShouldIgnoreStaticProperty() { - $obj = $this->normalizer->denormalize(['outOfScope' => true], __NAMESPACE__.'\PropertyDummy'); + $obj = $this->normalizer->denormalize(['outOfScope' => true], PropertyDummy::class); $this->assertEquals(new PropertyDummy(), $obj); $this->assertEquals('out_of_scope', PropertyDummy::$outOfScope); diff --git a/src/Symfony/Component/Stopwatch/LICENSE b/src/Symfony/Component/Stopwatch/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Stopwatch/LICENSE +++ b/src/Symfony/Component/Stopwatch/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Templating/LICENSE b/src/Symfony/Component/Templating/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Templating/LICENSE +++ b/src/Symfony/Component/Templating/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Templating/README.md b/src/Symfony/Component/Templating/README.md index 58e2a0a5c6b83..2b8ecad873964 100644 --- a/src/Symfony/Component/Templating/README.md +++ b/src/Symfony/Component/Templating/README.md @@ -12,7 +12,7 @@ layouts. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/templating/index.html) + * [Documentation](https://symfony.com/doc/current/components/templating.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Translation/DataCollector/TranslationDataCollector.php b/src/Symfony/Component/Translation/DataCollector/TranslationDataCollector.php index fc713463a0bc3..5b96a22f35001 100644 --- a/src/Symfony/Component/Translation/DataCollector/TranslationDataCollector.php +++ b/src/Symfony/Component/Translation/DataCollector/TranslationDataCollector.php @@ -16,6 +16,7 @@ use Symfony\Component\HttpKernel\DataCollector\DataCollector; use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface; use Symfony\Component\Translation\DataCollectorTranslator; +use Symfony\Component\VarDumper\Cloner\Data; /** * @author Abdellatif Ait boudad diff --git a/src/Symfony/Component/Translation/LICENSE b/src/Symfony/Component/Translation/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Translation/LICENSE +++ b/src/Symfony/Component/Translation/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Translation/Loader/PhpFileLoader.php b/src/Symfony/Component/Translation/Loader/PhpFileLoader.php index a0050e8db1e19..0991c3d3a28c6 100644 --- a/src/Symfony/Component/Translation/Loader/PhpFileLoader.php +++ b/src/Symfony/Component/Translation/Loader/PhpFileLoader.php @@ -18,11 +18,25 @@ */ class PhpFileLoader extends FileLoader { + private static $cache = []; + /** * {@inheritdoc} */ protected function loadResource($resource) { - return require $resource; + if ([] === self::$cache && \function_exists('opcache_invalidate') && filter_var(ini_get('opcache.enable'), FILTER_VALIDATE_BOOLEAN) && (!\in_array(\PHP_SAPI, ['cli', 'phpdbg'], true) || filter_var(ini_get('opcache.enable_cli'), FILTER_VALIDATE_BOOLEAN))) { + self::$cache = null; + } + + if (null === self::$cache) { + return require $resource; + } + + if (isset(self::$cache[$resource])) { + return self::$cache[$resource]; + } + + return self::$cache[$resource] = require $resource; } } diff --git a/src/Symfony/Component/Translation/MessageCatalogue.php b/src/Symfony/Component/Translation/MessageCatalogue.php index 9b59c87d2f919..cc4a0bfaba9d3 100644 --- a/src/Symfony/Component/Translation/MessageCatalogue.php +++ b/src/Symfony/Component/Translation/MessageCatalogue.php @@ -130,7 +130,9 @@ public function add($messages, $domain = 'messages') if (!isset($this->messages[$domain])) { $this->messages[$domain] = $messages; } else { - $this->messages[$domain] = array_replace($this->messages[$domain], $messages); + foreach ($messages as $id => $message) { + $this->messages[$domain][$id] = $message; + } } } diff --git a/src/Symfony/Component/Translation/README.md b/src/Symfony/Component/Translation/README.md index 46f3d1f2f25e6..e80a70cad033e 100644 --- a/src/Symfony/Component/Translation/README.md +++ b/src/Symfony/Component/Translation/README.md @@ -6,7 +6,7 @@ The Translation component provides tools to internationalize your application. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/translation/index.html) + * [Documentation](https://symfony.com/doc/current/components/translation.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Translation/Tests/TranslatorTest.php b/src/Symfony/Component/Translation/Tests/TranslatorTest.php index 77af7de33efea..68122b2915970 100644 --- a/src/Symfony/Component/Translation/Tests/TranslatorTest.php +++ b/src/Symfony/Component/Translation/Tests/TranslatorTest.php @@ -234,15 +234,38 @@ public function testTransWithFallbackLocaleFile($format, $loader) $this->assertEquals('bar', $translator->trans('foo', [], 'resources')); } - public function testTransWithFallbackLocaleBis() + /** + * @dataProvider getFallbackLocales + */ + public function testTransWithFallbackLocaleBis($expectedLocale, $locale) { - $translator = new Translator('en_US'); + $translator = new Translator($locale); $translator->addLoader('array', new ArrayLoader()); - $translator->addResource('array', ['foo' => 'foofoo'], 'en_US'); - $translator->addResource('array', ['bar' => 'foobar'], 'en'); + $translator->addResource('array', ['foo' => 'foofoo'], $locale); + $translator->addResource('array', ['bar' => 'foobar'], $expectedLocale); $this->assertEquals('foobar', $translator->trans('bar')); } + public function getFallbackLocales() + { + $locales = [ + ['en', 'en_US'], + ['en', 'en-US'], + ['sl_Latn_IT', 'sl_Latn_IT_nedis'], + ['sl_Latn', 'sl_Latn_IT'], + ]; + + if (\function_exists('locale_parse')) { + $locales[] = ['sl_Latn_IT', 'sl-Latn-IT-nedis']; + $locales[] = ['sl_Latn', 'sl-Latn-IT']; + } else { + $locales[] = ['sl-Latn-IT', 'sl-Latn-IT-nedis']; + $locales[] = ['sl-Latn', 'sl-Latn-IT']; + } + + return $locales; + } + public function testTransWithFallbackLocaleTer() { $translator = new Translator('fr_FR'); diff --git a/src/Symfony/Component/Translation/Translator.php b/src/Symfony/Component/Translation/Translator.php index e72d20a86f512..1bda62d1b11af 100644 --- a/src/Symfony/Component/Translation/Translator.php +++ b/src/Symfony/Component/Translation/Translator.php @@ -412,8 +412,19 @@ protected function computeFallbackLocales($locale) $locales[] = $fallback; } - if (false !== strrchr($locale, '_')) { + if (\function_exists('locale_parse')) { + $localeSubTags = locale_parse($locale); + if (1 < \count($localeSubTags)) { + array_pop($localeSubTags); + $fallback = locale_compose($localeSubTags); + if (false !== $fallback) { + array_unshift($locales, $fallback); + } + } + } elseif (false !== strrchr($locale, '_')) { array_unshift($locales, substr($locale, 0, -\strlen(strrchr($locale, '_')))); + } elseif (false !== strrchr($locale, '-')) { + array_unshift($locales, substr($locale, 0, -\strlen(strrchr($locale, '-')))); } return array_unique($locales); diff --git a/src/Symfony/Component/Validator/ConstraintValidator.php b/src/Symfony/Component/Validator/ConstraintValidator.php index 93cca2ea74a5e..458351fe2ee00 100644 --- a/src/Symfony/Component/Validator/ConstraintValidator.php +++ b/src/Symfony/Component/Validator/ConstraintValidator.php @@ -87,19 +87,12 @@ protected function formatValue($value, $format = 0) { if (($format & self::PRETTY_DATE) && $value instanceof \DateTimeInterface) { if (class_exists('IntlDateFormatter')) { - $locale = \Locale::getDefault(); - $formatter = new \IntlDateFormatter($locale, \IntlDateFormatter::MEDIUM, \IntlDateFormatter::SHORT, $value->getTimezone()); - - // neither the native nor the stub IntlDateFormatter support - // DateTimeImmutable as of yet - if (!$value instanceof \DateTime) { - $value = new \DateTime( - $value->format('Y-m-d H:i:s.u e'), - $value->getTimezone() - ); - } - - return $formatter->format($value); + $formatter = new \IntlDateFormatter(\Locale::getDefault(), \IntlDateFormatter::MEDIUM, \IntlDateFormatter::SHORT, 'UTC'); + + return $formatter->format(new \DateTime( + $value->format('Y-m-d H:i:s.u'), + new \DateTimeZone('UTC') + )); } return $value->format('Y-m-d H:i:s'); diff --git a/src/Symfony/Component/Validator/Constraints/AbstractComparisonValidator.php b/src/Symfony/Component/Validator/Constraints/AbstractComparisonValidator.php index cd96bc9df75f8..f04db3cc2d1b9 100644 --- a/src/Symfony/Component/Validator/Constraints/AbstractComparisonValidator.php +++ b/src/Symfony/Component/Validator/Constraints/AbstractComparisonValidator.php @@ -40,7 +40,7 @@ public function __construct(PropertyAccessorInterface $propertyAccessor = null) public function validate($value, Constraint $constraint) { if (!$constraint instanceof AbstractComparison) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\AbstractComparison'); + throw new UnexpectedTypeException($constraint, AbstractComparison::class); } if (null === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/AllValidator.php b/src/Symfony/Component/Validator/Constraints/AllValidator.php index 97de37058f650..cd539104ad97f 100644 --- a/src/Symfony/Component/Validator/Constraints/AllValidator.php +++ b/src/Symfony/Component/Validator/Constraints/AllValidator.php @@ -26,7 +26,7 @@ class AllValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof All) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\All'); + throw new UnexpectedTypeException($constraint, All::class); } if (null === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/BicValidator.php b/src/Symfony/Component/Validator/Constraints/BicValidator.php index fc363461587e5..fe6e83a203def 100644 --- a/src/Symfony/Component/Validator/Constraints/BicValidator.php +++ b/src/Symfony/Component/Validator/Constraints/BicValidator.php @@ -28,7 +28,7 @@ class BicValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Bic) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Bic'); + throw new UnexpectedTypeException($constraint, Bic::class); } if (null === $value || '' === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/BlankValidator.php b/src/Symfony/Component/Validator/Constraints/BlankValidator.php index ca999b5aa3961..3fd7fcc9fe1c6 100644 --- a/src/Symfony/Component/Validator/Constraints/BlankValidator.php +++ b/src/Symfony/Component/Validator/Constraints/BlankValidator.php @@ -26,7 +26,7 @@ class BlankValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Blank) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Blank'); + throw new UnexpectedTypeException($constraint, Blank::class); } if ('' !== $value && null !== $value) { diff --git a/src/Symfony/Component/Validator/Constraints/CallbackValidator.php b/src/Symfony/Component/Validator/Constraints/CallbackValidator.php index a66840eae1338..5b51869ab1246 100644 --- a/src/Symfony/Component/Validator/Constraints/CallbackValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CallbackValidator.php @@ -29,7 +29,7 @@ class CallbackValidator extends ConstraintValidator public function validate($object, Constraint $constraint) { if (!$constraint instanceof Callback) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Callback'); + throw new UnexpectedTypeException($constraint, Callback::class); } $method = $constraint->callback; diff --git a/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php b/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php index d39c87319a594..a4cb9f5c1fb7a 100644 --- a/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php @@ -91,7 +91,7 @@ class CardSchemeValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof CardScheme) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\CardScheme'); + throw new UnexpectedTypeException($constraint, CardScheme::class); } if (null === $value || '' === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php b/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php index 00577ef462518..9ec0fc6703586 100644 --- a/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php +++ b/src/Symfony/Component/Validator/Constraints/ChoiceValidator.php @@ -31,7 +31,7 @@ class ChoiceValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Choice) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Choice'); + throw new UnexpectedTypeException($constraint, Choice::class); } if (!\is_array($constraint->choices) && !$constraint->callback) { diff --git a/src/Symfony/Component/Validator/Constraints/CollectionValidator.php b/src/Symfony/Component/Validator/Constraints/CollectionValidator.php index 3b67e40a5c3d4..f8859b48eb5ef 100644 --- a/src/Symfony/Component/Validator/Constraints/CollectionValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CollectionValidator.php @@ -26,7 +26,7 @@ class CollectionValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Collection) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Collection'); + throw new UnexpectedTypeException($constraint, Collection::class); } if (null === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/CountValidator.php b/src/Symfony/Component/Validator/Constraints/CountValidator.php index 01f82a346600b..a81419bae6cd9 100644 --- a/src/Symfony/Component/Validator/Constraints/CountValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CountValidator.php @@ -26,7 +26,7 @@ class CountValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Count) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Count'); + throw new UnexpectedTypeException($constraint, Count::class); } if (null === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/CountryValidator.php b/src/Symfony/Component/Validator/Constraints/CountryValidator.php index 46585da8b9697..8116495f2e8ae 100644 --- a/src/Symfony/Component/Validator/Constraints/CountryValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CountryValidator.php @@ -29,7 +29,7 @@ class CountryValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Country) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Country'); + throw new UnexpectedTypeException($constraint, Country::class); } if (null === $value || '' === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/CurrencyValidator.php b/src/Symfony/Component/Validator/Constraints/CurrencyValidator.php index 42fa8cfa45682..de9d12cb1964d 100644 --- a/src/Symfony/Component/Validator/Constraints/CurrencyValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CurrencyValidator.php @@ -30,7 +30,7 @@ class CurrencyValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Currency) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Currency'); + throw new UnexpectedTypeException($constraint, Currency::class); } if (null === $value || '' === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php b/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php index a632a34e43784..bad043f20e6ea 100644 --- a/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php +++ b/src/Symfony/Component/Validator/Constraints/DateTimeValidator.php @@ -31,7 +31,7 @@ class DateTimeValidator extends DateValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof DateTime) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\DateTime'); + throw new UnexpectedTypeException($constraint, DateTime::class); } if (null === $value || '' === $value || $value instanceof \DateTimeInterface) { diff --git a/src/Symfony/Component/Validator/Constraints/DateValidator.php b/src/Symfony/Component/Validator/Constraints/DateValidator.php index a1492c54c9a03..c1c3bc9f8991f 100644 --- a/src/Symfony/Component/Validator/Constraints/DateValidator.php +++ b/src/Symfony/Component/Validator/Constraints/DateValidator.php @@ -44,7 +44,7 @@ public static function checkDate($year, $month, $day) public function validate($value, Constraint $constraint) { if (!$constraint instanceof Date) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Date'); + throw new UnexpectedTypeException($constraint, Date::class); } if (null === $value || '' === $value || $value instanceof \DateTimeInterface) { diff --git a/src/Symfony/Component/Validator/Constraints/EmailValidator.php b/src/Symfony/Component/Validator/Constraints/EmailValidator.php index 8fb4b886727af..1eb6a98bb89f2 100644 --- a/src/Symfony/Component/Validator/Constraints/EmailValidator.php +++ b/src/Symfony/Component/Validator/Constraints/EmailValidator.php @@ -39,7 +39,7 @@ public function __construct($strict = false) public function validate($value, Constraint $constraint) { if (!$constraint instanceof Email) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Email'); + throw new UnexpectedTypeException($constraint, Email::class); } if (null === $value || '' === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php b/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php index a4dfadbfc03ba..7ef552dd4045f 100644 --- a/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php +++ b/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php @@ -36,7 +36,7 @@ public function __construct($propertyAccessor = null, ExpressionLanguage $expres public function validate($value, Constraint $constraint) { if (!$constraint instanceof Expression) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Expression'); + throw new UnexpectedTypeException($constraint, Expression::class); } $variables = []; diff --git a/src/Symfony/Component/Validator/Constraints/FileValidator.php b/src/Symfony/Component/Validator/Constraints/FileValidator.php index 0a58cd2d687a0..199d7676a6bbb 100644 --- a/src/Symfony/Component/Validator/Constraints/FileValidator.php +++ b/src/Symfony/Component/Validator/Constraints/FileValidator.php @@ -41,7 +41,7 @@ class FileValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof File) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\File'); + throw new UnexpectedTypeException($constraint, File::class); } if (null === $value || '' === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/GreaterThanOrEqualValidator.php b/src/Symfony/Component/Validator/Constraints/GreaterThanOrEqualValidator.php index e196e688f3476..290408ac0cc3f 100644 --- a/src/Symfony/Component/Validator/Constraints/GreaterThanOrEqualValidator.php +++ b/src/Symfony/Component/Validator/Constraints/GreaterThanOrEqualValidator.php @@ -24,7 +24,7 @@ class GreaterThanOrEqualValidator extends AbstractComparisonValidator */ protected function compareValues($value1, $value2) { - return $value1 >= $value2; + return null === $value2 || $value1 >= $value2; } /** diff --git a/src/Symfony/Component/Validator/Constraints/GreaterThanValidator.php b/src/Symfony/Component/Validator/Constraints/GreaterThanValidator.php index 9029e8fc46a80..062503ab3f426 100644 --- a/src/Symfony/Component/Validator/Constraints/GreaterThanValidator.php +++ b/src/Symfony/Component/Validator/Constraints/GreaterThanValidator.php @@ -24,7 +24,7 @@ class GreaterThanValidator extends AbstractComparisonValidator */ protected function compareValues($value1, $value2) { - return $value1 > $value2; + return null === $value2 || $value1 > $value2; } /** diff --git a/src/Symfony/Component/Validator/Constraints/IbanValidator.php b/src/Symfony/Component/Validator/Constraints/IbanValidator.php index 3dcedb47dc1ea..d4f8455bb7827 100644 --- a/src/Symfony/Component/Validator/Constraints/IbanValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IbanValidator.php @@ -142,7 +142,7 @@ class IbanValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Iban) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Iban'); + throw new UnexpectedTypeException($constraint, Iban::class); } if (null === $value || '' === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/ImageValidator.php b/src/Symfony/Component/Validator/Constraints/ImageValidator.php index 4b6a6f3b20c6a..7ca0cd32b3a43 100644 --- a/src/Symfony/Component/Validator/Constraints/ImageValidator.php +++ b/src/Symfony/Component/Validator/Constraints/ImageValidator.php @@ -31,7 +31,7 @@ class ImageValidator extends FileValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Image) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Image'); + throw new UnexpectedTypeException($constraint, Image::class); } $violations = \count($this->context->getViolations()); diff --git a/src/Symfony/Component/Validator/Constraints/IpValidator.php b/src/Symfony/Component/Validator/Constraints/IpValidator.php index 5c687b900fdbb..b978d1daaece4 100644 --- a/src/Symfony/Component/Validator/Constraints/IpValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IpValidator.php @@ -29,7 +29,7 @@ class IpValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Ip) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Ip'); + throw new UnexpectedTypeException($constraint, Ip::class); } if (null === $value || '' === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/IsFalseValidator.php b/src/Symfony/Component/Validator/Constraints/IsFalseValidator.php index 95245fb97bd9d..79c42348fec68 100644 --- a/src/Symfony/Component/Validator/Constraints/IsFalseValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IsFalseValidator.php @@ -26,7 +26,7 @@ class IsFalseValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof IsFalse) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\IsFalse'); + throw new UnexpectedTypeException($constraint, IsFalse::class); } if (null === $value || false === $value || 0 === $value || '0' === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/IsNullValidator.php b/src/Symfony/Component/Validator/Constraints/IsNullValidator.php index 01b9d1e40a05e..b6e78170f92de 100644 --- a/src/Symfony/Component/Validator/Constraints/IsNullValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IsNullValidator.php @@ -26,7 +26,7 @@ class IsNullValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof IsNull) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\IsNull'); + throw new UnexpectedTypeException($constraint, IsNull::class); } if (null !== $value) { diff --git a/src/Symfony/Component/Validator/Constraints/IsTrueValidator.php b/src/Symfony/Component/Validator/Constraints/IsTrueValidator.php index 89aa337d2c054..6088f6d7a7a64 100644 --- a/src/Symfony/Component/Validator/Constraints/IsTrueValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IsTrueValidator.php @@ -26,7 +26,7 @@ class IsTrueValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof IsTrue) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\IsTrue'); + throw new UnexpectedTypeException($constraint, IsTrue::class); } if (null === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/IsbnValidator.php b/src/Symfony/Component/Validator/Constraints/IsbnValidator.php index 9f0d1fa1a35a1..5810c4df69a5c 100644 --- a/src/Symfony/Component/Validator/Constraints/IsbnValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IsbnValidator.php @@ -32,7 +32,7 @@ class IsbnValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Isbn) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Isbn'); + throw new UnexpectedTypeException($constraint, Isbn::class); } if (null === $value || '' === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/IssnValidator.php b/src/Symfony/Component/Validator/Constraints/IssnValidator.php index 41da39ebd87bc..50818d7bacf1f 100644 --- a/src/Symfony/Component/Validator/Constraints/IssnValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IssnValidator.php @@ -31,7 +31,7 @@ class IssnValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Issn) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Issn'); + throw new UnexpectedTypeException($constraint, Issn::class); } if (null === $value || '' === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/LanguageValidator.php b/src/Symfony/Component/Validator/Constraints/LanguageValidator.php index 1722034720c60..971e3c795f256 100644 --- a/src/Symfony/Component/Validator/Constraints/LanguageValidator.php +++ b/src/Symfony/Component/Validator/Constraints/LanguageValidator.php @@ -29,7 +29,7 @@ class LanguageValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Language) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Language'); + throw new UnexpectedTypeException($constraint, Language::class); } if (null === $value || '' === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/LengthValidator.php b/src/Symfony/Component/Validator/Constraints/LengthValidator.php index d8cb09ccb65f8..01955ed035710 100644 --- a/src/Symfony/Component/Validator/Constraints/LengthValidator.php +++ b/src/Symfony/Component/Validator/Constraints/LengthValidator.php @@ -26,7 +26,7 @@ class LengthValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Length) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Length'); + throw new UnexpectedTypeException($constraint, Length::class); } if (null === $value || '' === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/LessThanOrEqualValidator.php b/src/Symfony/Component/Validator/Constraints/LessThanOrEqualValidator.php index 54281eef5a673..f7f4c8be5f326 100644 --- a/src/Symfony/Component/Validator/Constraints/LessThanOrEqualValidator.php +++ b/src/Symfony/Component/Validator/Constraints/LessThanOrEqualValidator.php @@ -24,7 +24,7 @@ class LessThanOrEqualValidator extends AbstractComparisonValidator */ protected function compareValues($value1, $value2) { - return $value1 <= $value2; + return null === $value2 || $value1 <= $value2; } /** diff --git a/src/Symfony/Component/Validator/Constraints/LessThanValidator.php b/src/Symfony/Component/Validator/Constraints/LessThanValidator.php index ef7535fc99143..64e107547ac83 100644 --- a/src/Symfony/Component/Validator/Constraints/LessThanValidator.php +++ b/src/Symfony/Component/Validator/Constraints/LessThanValidator.php @@ -24,7 +24,7 @@ class LessThanValidator extends AbstractComparisonValidator */ protected function compareValues($value1, $value2) { - return $value1 < $value2; + return null === $value2 || $value1 < $value2; } /** diff --git a/src/Symfony/Component/Validator/Constraints/LocaleValidator.php b/src/Symfony/Component/Validator/Constraints/LocaleValidator.php index 40d63970e25a6..29c569c288e03 100644 --- a/src/Symfony/Component/Validator/Constraints/LocaleValidator.php +++ b/src/Symfony/Component/Validator/Constraints/LocaleValidator.php @@ -29,7 +29,7 @@ class LocaleValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Locale) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Locale'); + throw new UnexpectedTypeException($constraint, Locale::class); } if (null === $value || '' === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/LuhnValidator.php b/src/Symfony/Component/Validator/Constraints/LuhnValidator.php index 89ebfdcc5c54d..2f652b3f6b62d 100644 --- a/src/Symfony/Component/Validator/Constraints/LuhnValidator.php +++ b/src/Symfony/Component/Validator/Constraints/LuhnValidator.php @@ -39,7 +39,7 @@ class LuhnValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Luhn) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Luhn'); + throw new UnexpectedTypeException($constraint, Luhn::class); } if (null === $value || '' === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/NotBlankValidator.php b/src/Symfony/Component/Validator/Constraints/NotBlankValidator.php index 1d6c5bc983a37..f862da1ec14f8 100644 --- a/src/Symfony/Component/Validator/Constraints/NotBlankValidator.php +++ b/src/Symfony/Component/Validator/Constraints/NotBlankValidator.php @@ -26,7 +26,7 @@ class NotBlankValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof NotBlank) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\NotBlank'); + throw new UnexpectedTypeException($constraint, NotBlank::class); } if (false === $value || (empty($value) && '0' != $value)) { diff --git a/src/Symfony/Component/Validator/Constraints/NotNullValidator.php b/src/Symfony/Component/Validator/Constraints/NotNullValidator.php index d6f620713e6a6..d02fcc43988a6 100644 --- a/src/Symfony/Component/Validator/Constraints/NotNullValidator.php +++ b/src/Symfony/Component/Validator/Constraints/NotNullValidator.php @@ -26,7 +26,7 @@ class NotNullValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof NotNull) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\NotNull'); + throw new UnexpectedTypeException($constraint, NotNull::class); } if (null === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/RangeValidator.php b/src/Symfony/Component/Validator/Constraints/RangeValidator.php index ea7d2778088c3..43394601d7279 100644 --- a/src/Symfony/Component/Validator/Constraints/RangeValidator.php +++ b/src/Symfony/Component/Validator/Constraints/RangeValidator.php @@ -27,7 +27,7 @@ class RangeValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Range) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Range'); + throw new UnexpectedTypeException($constraint, Range::class); } if (null === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/RegexValidator.php b/src/Symfony/Component/Validator/Constraints/RegexValidator.php index c6b70feb7f0e1..62829ec5d083c 100644 --- a/src/Symfony/Component/Validator/Constraints/RegexValidator.php +++ b/src/Symfony/Component/Validator/Constraints/RegexValidator.php @@ -29,7 +29,7 @@ class RegexValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Regex) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Regex'); + throw new UnexpectedTypeException($constraint, Regex::class); } if (null === $value || '' === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/TimeValidator.php b/src/Symfony/Component/Validator/Constraints/TimeValidator.php index b1ee40c53051b..1c59d9e5e567a 100644 --- a/src/Symfony/Component/Validator/Constraints/TimeValidator.php +++ b/src/Symfony/Component/Validator/Constraints/TimeValidator.php @@ -44,7 +44,7 @@ public static function checkTime($hour, $minute, $second) public function validate($value, Constraint $constraint) { if (!$constraint instanceof Time) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Time'); + throw new UnexpectedTypeException($constraint, Time::class); } if (null === $value || '' === $value || $value instanceof \DateTimeInterface) { diff --git a/src/Symfony/Component/Validator/Constraints/TypeValidator.php b/src/Symfony/Component/Validator/Constraints/TypeValidator.php index 206836d3617fc..ecd7cd8cf7e37 100644 --- a/src/Symfony/Component/Validator/Constraints/TypeValidator.php +++ b/src/Symfony/Component/Validator/Constraints/TypeValidator.php @@ -26,7 +26,7 @@ class TypeValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Type) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Type'); + throw new UnexpectedTypeException($constraint, Type::class); } if (null === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/UrlValidator.php b/src/Symfony/Component/Validator/Constraints/UrlValidator.php index b77701dd7ecec..72affdf7b646c 100644 --- a/src/Symfony/Component/Validator/Constraints/UrlValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UrlValidator.php @@ -23,7 +23,7 @@ class UrlValidator extends ConstraintValidator { const PATTERN = '~^ (%s):// # protocol - (([\.\pL\pN-]+:)?([\.\pL\pN-]+)@)? # basic auth + (([\_\.\pL\pN-]+:)?([\_\.\pL\pN-]+)@)? # basic auth ( ([\pL\pN\pS\-\_\.])+(\.?([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?) # a domain name | # or @@ -45,7 +45,7 @@ class UrlValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Url) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Url'); + throw new UnexpectedTypeException($constraint, Url::class); } if (null === $value || '' === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/UuidValidator.php b/src/Symfony/Component/Validator/Constraints/UuidValidator.php index 26de4614f324f..a1f5e7fb52372 100644 --- a/src/Symfony/Component/Validator/Constraints/UuidValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UuidValidator.php @@ -67,7 +67,7 @@ class UuidValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Uuid) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Uuid'); + throw new UnexpectedTypeException($constraint, Uuid::class); } if (null === $value || '' === $value) { diff --git a/src/Symfony/Component/Validator/Constraints/ValidValidator.php b/src/Symfony/Component/Validator/Constraints/ValidValidator.php index 695ec822540ed..85eabb80ae8e2 100644 --- a/src/Symfony/Component/Validator/Constraints/ValidValidator.php +++ b/src/Symfony/Component/Validator/Constraints/ValidValidator.php @@ -23,7 +23,7 @@ class ValidValidator extends ConstraintValidator public function validate($value, Constraint $constraint) { if (!$constraint instanceof Valid) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Valid'); + throw new UnexpectedTypeException($constraint, Valid::class); } if (null === $value) { diff --git a/src/Symfony/Component/Validator/LICENSE b/src/Symfony/Component/Validator/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Validator/LICENSE +++ b/src/Symfony/Component/Validator/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf index 12f26fdc88688..79dab63d7de58 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf @@ -334,6 +334,38 @@ This value should be valid JSON. هذه القيمة يجب أن تكون صالحة ل JSON. + + This collection should contain only unique elements. + يجب أن تحتوي هذه المجموعة علي عناصر فريدة فقط. + + + This value should be positive. + يجب أن تكون هذه القيمة موجبة. + + + This value should be either positive or zero. + يجب أن تكون هذه القيمة إما موجبة او صفر. + + + This value should be negative. + يجب أن تكون هذه القيمة سالبة. + + + This value should be either negative or zero. + يجب أن تكون هذه القيمة إما سالبة او صفر. + + + This value is not a valid timezone. + هذه القيمة ليست منطقة زمنية صحيحة. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + تم تسريب كلمة المرور هذه في خرق للبيانات، ويجب عدم استخدامها. يرجي استخدام كلمة مرور أخري. + + + This value should be between {{ min }} and {{ max }}. + يجب أن تكون هذه القيمة بين {{ min }} و {{ max }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf index 018dd1233ac61..20dff43c6d904 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf @@ -24,11 +24,11 @@ You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. - Morate odabrati bar {{ limit }} mogućnost.|Morate odabrati bar {{ limit }} mogućnosti. + Morate odabrati bar {{ limit }} mogućnost.|Morate odabrati bar {{ limit }} mogućnosti.|Morate odabrati bar {{ limit }} mogućnosti. You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. - Morate odabrati najviše {{ limit }} mogućnost.|Morate odabrati najviše {{ limit }} mogućnosti. + Morate odabrati najviše {{ limit }} mogućnost.|Morate odabrati najviše {{ limit }} mogućnosti.|Morate odabrati najviše {{ limit }} mogućnosti. One or more of the given values is invalid. @@ -76,7 +76,7 @@ This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. - Vrednost je predugačka. Trebalo bi da ima {{ limit }} karakter ili manje.|Vrednost je predugačka. Trebalo bi da ima {{ limit }} karaktera ili manje. + Vrednost je predugačka. Trebalo bi da ima {{ limit }} karakter ili manje.|Vrednost je predugačka. Trebalo bi da ima {{ limit }} karaktera ili manje.|Vrednost je predugačka. Trebalo bi da ima {{ limit }} karaktera ili manje. This value should be {{ limit }} or more. @@ -84,7 +84,7 @@ This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. - Vrednost je prekratka. Trebalo bi da ima {{ limit }} karakter ili više.|Vrednost je prekratka. Trebalo bi da ima {{ limit }} karaktera ili više. + Vrednost je prekratka. Trebalo bi da ima {{ limit }} karakter ili više.|Vrednost je prekratka. Trebalo bi da ima {{ limit }} karaktera ili više.|Vrednost je prekratka. Trebalo bi da ima {{ limit }} karaktera ili više. This value should not be blank. @@ -180,7 +180,7 @@ This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. - Vrednost bi trebalo da ima tačno {{ limit }} karakter.|Vrednost bi trebalo da ima tačno {{ limit }} karaktera. + Vrednost bi trebalo da ima tačno {{ limit }} karakter.|Vrednost bi trebalo da ima tačno {{ limit }} karaktera.|Vrednost bi trebalo da ima tačno {{ limit }} karaktera. The file was only partially uploaded. @@ -204,15 +204,15 @@ This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. - Ova kolekcija bi trebalo da sadrži {{ limit }} ili više elemenata.|Ova kolekcija bi trebalo da sadrži {{ limit }} ili više elemenata. + Ova kolekcija bi trebalo da sadrži {{ limit }} ili više elemenata.|Ova kolekcija bi trebalo da sadrži {{ limit }} ili više elemenata.|Ova kolekcija bi trebalo da sadrži {{ limit }} ili više elemenata. This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. - Ova kolekcija bi trebalo da sadrži {{ limit }} ili manje elemenata.|Ova kolekcija bi trebalo da sadrži {{ limit }} ili manje elemenata. + Ova kolekcija bi trebalo da sadrži {{ limit }} ili manje elemenata.|Ova kolekcija bi trebalo da sadrži {{ limit }} ili manje elemenata.|Ova kolekcija bi trebalo da sadrži {{ limit }} ili manje elemenata. This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. - Ova kolekcija bi trebalo da sadrži tačno {{ limit }} element.|Ova kolekcija bi trebalo da sadrži tačno {{ limit }} elemenata. + Ova kolekcija bi trebalo da sadrži tačno {{ limit }} element.|Ova kolekcija bi trebalo da sadrži tačno {{ limit }} elementa.|Ova kolekcija bi trebalo da sadrži tačno {{ limit }} elemenata. Invalid card number. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf index d9d5f2f622b43..7cef875f5812e 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.zh_TW.xlf @@ -278,6 +278,94 @@ This value should not be identical to {{ compared_value_type }} {{ compared_value }}. 該值不應與 {{ compared_value_type }} {{ compared_value }} 相同。 + + The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. + 圖像格式過大 ({{ ratio }})。 最大允許尺寸 {{ max_ratio }}。 + + + The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. + 圖像格式過小 ({{ ratio }})。最小尺寸 {{ min_ratio }}。 + + + The image is square ({{ width }}x{{ height }}px). Square images are not allowed. + 方形圖像 ({{ width }}x{{ height }}px)。不接受方形圖像。 + + + The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + 紀念冊布局圖像 ({{ width }}x{{ height }}px)。 不接受紀念冊布局圖像。 + + + The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + 書籍布局圖像 ({{ width }}x{{ height }}px)。不接受圖像書籍布局。 + + + An empty file is not allowed. + 不接受空白文件。 + + + The host could not be resolved. + 未找到服務器。 + + + This value does not match the expected {{ charset }} charset. + 該數值不符合預期 {{ charset }} 符號編碼。 + + + This is not a valid Business Identifier Code (BIC). + 無效企業識別碼 (BIC)。 + + + Error. + 錯誤。 + + + This is not a valid UUID. + 無效的通用唯壹標識符 (UUID)。 + + + This value should be a multiple of {{ compared_value }}. + 該值必須是倍數 {{ compared_value }}。 + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + 該企業識別碼 (BIC) 與銀行賬戶國際編號不壹致 (IBAN) {{ iban }}。 + + + This value should be valid JSON. + 該數值必須序列化為JSON格式。 + + + This collection should contain only unique elements. + 該集合應僅包含唯壹元素。 + + + This value should be positive. + 數值應為正數。 + + + This value should be either positive or zero. + 數值應或未正數,或為零。 + + + This value should be negative. + 數值應為負數。 + + + This value should be either negative or zero. + 數值應或未負數,或為零。 + + + This value is not a valid timezone. + 無效時區。 + + + This password has been leaked in a data breach, it must not be used. Please use another password. + 依據您的密碼,發生數據泄露,請勿使用改密碼。請更換密碼。 + + + This value should be between {{ min }} and {{ max }}. + 該數值應在 {{ min }} 和 {{ max }} 之間。 + diff --git a/src/Symfony/Component/Validator/Tests/ConstraintValidatorTest.php b/src/Symfony/Component/Validator/Tests/ConstraintValidatorTest.php index 96af6f13eb4e7..6ca3eab41fd6e 100644 --- a/src/Symfony/Component/Validator/Tests/ConstraintValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/ConstraintValidatorTest.php @@ -27,6 +27,9 @@ public function testFormatValue($expected, $value, $format = 0) public function formatValueProvider() { + $defaultTimezone = date_default_timezone_get(); + date_default_timezone_set('Europe/Moscow'); // GMT+3 + $data = [ ['true', true], ['false', false], @@ -36,10 +39,15 @@ public function formatValueProvider() ['array', []], ['object', $toString = new TestToStringObject()], ['ccc', $toString, ConstraintValidator::OBJECT_TO_STRING], - ['object', $dateTime = (new \DateTimeImmutable('@0'))->setTimezone(new \DateTimeZone('UTC'))], - [class_exists(\IntlDateFormatter::class) ? 'Jan 1, 1970, 12:00 AM' : '1970-01-01 00:00:00', $dateTime, ConstraintValidator::PRETTY_DATE], + ['object', $dateTime = new \DateTimeImmutable('1971-02-02T08:00:00UTC')], + [class_exists(\IntlDateFormatter::class) ? 'Oct 4, 2019, 11:02 AM' : '2019-10-04 11:02:03', new \DateTimeImmutable('2019-10-04T11:02:03+09:00'), ConstraintValidator::PRETTY_DATE], + [class_exists(\IntlDateFormatter::class) ? 'Feb 2, 1971, 8:00 AM' : '1971-02-02 08:00:00', $dateTime, ConstraintValidator::PRETTY_DATE], + [class_exists(\IntlDateFormatter::class) ? 'Jan 1, 1970, 6:00 AM' : '1970-01-01 06:00:00', new \DateTimeImmutable('1970-01-01T06:00:00Z'), ConstraintValidator::PRETTY_DATE], + [class_exists(\IntlDateFormatter::class) ? 'Jan 1, 1970, 3:00 PM' : '1970-01-01 15:00:00', (new \DateTimeImmutable('1970-01-01T23:00:00'))->setTimezone(new \DateTimeZone('America/New_York')), ConstraintValidator::PRETTY_DATE], ]; + date_default_timezone_set($defaultTimezone); + return $data; } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/AbstractComparisonValidatorTestCase.php b/src/Symfony/Component/Validator/Tests/Constraints/AbstractComparisonValidatorTestCase.php index b02e57cfa2358..3e8a9dcd7b829 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/AbstractComparisonValidatorTestCase.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/AbstractComparisonValidatorTestCase.php @@ -53,10 +53,7 @@ protected static function addPhp5Dot5Comparisons(array $comparisons) foreach ($comparison as $i => $value) { if ($value instanceof \DateTime) { - $comparison[$i] = new \DateTimeImmutable( - $value->format('Y-m-d H:i:s.u e'), - $value->getTimezone() - ); + $comparison[$i] = new \DateTimeImmutable($value->format('Y-m-d H:i:s.u e')); $add = true; } elseif ('DateTime' === $value) { $comparison[$i] = 'DateTimeImmutable'; @@ -237,6 +234,31 @@ public function throwsOnInvalidStringDatesProvider() ]; } + /** + * @dataProvider provideComparisonsToNullValueAtPropertyPath + */ + public function testCompareWithNullValueAtPropertyAt($dirtyValue, $dirtyValueAsString, $isValid) + { + $constraint = $this->createConstraint(['propertyPath' => 'value']); + $constraint->message = 'Constraint Message'; + + $object = new ComparisonTest_Class(null); + $this->setObject($object); + + $this->validator->validate($dirtyValue, $constraint); + + if ($isValid) { + $this->assertNoViolation(); + } else { + $this->buildViolation('Constraint Message') + ->setParameter('{{ value }}', $dirtyValueAsString) + ->setParameter('{{ compared_value }}', 'null') + ->setParameter('{{ compared_value_type }}', 'NULL') + ->setCode($this->getErrorCode()) + ->assertRaised(); + } + } + /** * @return array */ @@ -258,6 +280,8 @@ public function provideAllInvalidComparisons() */ abstract public function provideInvalidComparisons(); + abstract public function provideComparisonsToNullValueAtPropertyPath(); + /** * @param array|null $options Options for the constraint * diff --git a/src/Symfony/Component/Validator/Tests/Constraints/EqualToValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/EqualToValidatorTest.php index c1eb2f93ad754..880dbd7795c2e 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/EqualToValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/EqualToValidatorTest.php @@ -75,4 +75,11 @@ public function provideInvalidComparisons() [new ComparisonTest_Class(4), '4', new ComparisonTest_Class(5), '5', __NAMESPACE__.'\ComparisonTest_Class'], ]; } + + public function provideComparisonsToNullValueAtPropertyPath() + { + return [ + [5, '5', false], + ]; + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanOrEqualValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanOrEqualValidatorTest.php index d8d8eab8bdeee..043c02e7a72d4 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanOrEqualValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanOrEqualValidatorTest.php @@ -78,4 +78,11 @@ public function provideInvalidComparisons() ['b', '"b"', 'c', '"c"', 'string'], ]; } + + public function provideComparisonsToNullValueAtPropertyPath() + { + return [ + [5, '5', true], + ]; + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanValidatorTest.php index e678496c41e68..119c162edb5e2 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/GreaterThanValidatorTest.php @@ -80,4 +80,11 @@ public function provideInvalidComparisons() ['22', '"22"', '22', '"22"', 'string'], ]; } + + public function provideComparisonsToNullValueAtPropertyPath() + { + return [ + [5, '5', true], + ]; + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/IdenticalToValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/IdenticalToValidatorTest.php index c96ac16a91930..1d3662f49ae45 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/IdenticalToValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/IdenticalToValidatorTest.php @@ -93,4 +93,11 @@ public function provideInvalidComparisons() [new ComparisonTest_Class(4), '4', new ComparisonTest_Class(5), '5', __NAMESPACE__.'\ComparisonTest_Class'], ]; } + + public function provideComparisonsToNullValueAtPropertyPath() + { + return [ + [5, '5', false], + ]; + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/LessThanOrEqualValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/LessThanOrEqualValidatorTest.php index b77deff6163d6..9311706e7df38 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/LessThanOrEqualValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/LessThanOrEqualValidatorTest.php @@ -81,4 +81,11 @@ public function provideInvalidComparisons() ['c', '"c"', 'b', '"b"', 'string'], ]; } + + public function provideComparisonsToNullValueAtPropertyPath() + { + return [ + [5, '5', true], + ]; + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/LessThanValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/LessThanValidatorTest.php index 7d209ed5d4719..c40389440df50 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/LessThanValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/LessThanValidatorTest.php @@ -79,4 +79,11 @@ public function provideInvalidComparisons() ['333', '"333"', '22', '"22"', 'string'], ]; } + + public function provideComparisonsToNullValueAtPropertyPath() + { + return [ + [5, '5', true], + ]; + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/NotEqualToValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/NotEqualToValidatorTest.php index 810f7a175f104..8577159583def 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/NotEqualToValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/NotEqualToValidatorTest.php @@ -75,4 +75,11 @@ public function provideInvalidComparisons() [new ComparisonTest_Class(5), '5', new ComparisonTest_Class(5), '5', __NAMESPACE__.'\ComparisonTest_Class'], ]; } + + public function provideComparisonsToNullValueAtPropertyPath() + { + return [ + [5, '5', true], + ]; + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/NotIdenticalToValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/NotIdenticalToValidatorTest.php index 0cb9ec543114c..f14c5bd0dce8a 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/NotIdenticalToValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/NotIdenticalToValidatorTest.php @@ -93,4 +93,11 @@ public function provideInvalidComparisons() return $comparisons; } + + public function provideComparisonsToNullValueAtPropertyPath() + { + return [ + [5, '5', true], + ]; + } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php index f04dd44bc961d..0357172680c61 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UrlValidatorTest.php @@ -117,9 +117,11 @@ public function getValidUrls() ['http://☎.com/'], ['http://username:password@symfony.com'], ['http://user.name:password@symfony.com'], + ['http://user_name:pass_word@symfony.com'], ['http://username:pass.word@symfony.com'], ['http://user.name:pass.word@symfony.com'], ['http://user-name@symfony.com'], + ['http://user_name@symfony.com'], ['http://symfony.com?'], ['http://symfony.com?query=1'], ['http://symfony.com/?query=1'], diff --git a/src/Symfony/Component/Validator/Tests/Mapping/Loader/StaticMethodLoaderTest.php b/src/Symfony/Component/Validator/Tests/Mapping/Loader/StaticMethodLoaderTest.php index 069ccd322929e..c5c3b4e1966d2 100644 --- a/src/Symfony/Component/Validator/Tests/Mapping/Loader/StaticMethodLoaderTest.php +++ b/src/Symfony/Component/Validator/Tests/Mapping/Loader/StaticMethodLoaderTest.php @@ -33,7 +33,7 @@ protected function tearDown() public function testLoadClassMetadataReturnsTrueIfSuccessful() { $loader = new StaticMethodLoader('loadMetadata'); - $metadata = new ClassMetadata(__NAMESPACE__.'\StaticLoaderEntity'); + $metadata = new ClassMetadata(StaticLoaderEntity::class); $this->assertTrue($loader->loadClassMetadata($metadata)); } @@ -49,7 +49,7 @@ public function testLoadClassMetadataReturnsFalseIfNotSuccessful() public function testLoadClassMetadata() { $loader = new StaticMethodLoader('loadMetadata'); - $metadata = new ClassMetadata(__NAMESPACE__.'\StaticLoaderEntity'); + $metadata = new ClassMetadata(StaticLoaderEntity::class); $loader->loadClassMetadata($metadata); @@ -59,12 +59,12 @@ public function testLoadClassMetadata() public function testLoadClassMetadataDoesNotRepeatLoadWithParentClasses() { $loader = new StaticMethodLoader('loadMetadata'); - $metadata = new ClassMetadata(__NAMESPACE__.'\StaticLoaderDocument'); + $metadata = new ClassMetadata(StaticLoaderDocument::class); $loader->loadClassMetadata($metadata); $this->assertCount(0, $metadata->getConstraints()); $loader = new StaticMethodLoader('loadMetadata'); - $metadata = new ClassMetadata(__NAMESPACE__.'\BaseStaticLoaderDocument'); + $metadata = new ClassMetadata(BaseStaticLoaderDocument::class); $loader->loadClassMetadata($metadata); $this->assertCount(1, $metadata->getConstraints()); } @@ -72,7 +72,7 @@ public function testLoadClassMetadataDoesNotRepeatLoadWithParentClasses() public function testLoadClassMetadataIgnoresInterfaces() { $loader = new StaticMethodLoader('loadMetadata'); - $metadata = new ClassMetadata(__NAMESPACE__.'\StaticLoaderInterface'); + $metadata = new ClassMetadata(StaticLoaderInterface::class); $loader->loadClassMetadata($metadata); @@ -82,7 +82,7 @@ public function testLoadClassMetadataIgnoresInterfaces() public function testLoadClassMetadataInAbstractClasses() { $loader = new StaticMethodLoader('loadMetadata'); - $metadata = new ClassMetadata(__NAMESPACE__.'\AbstractStaticLoader'); + $metadata = new ClassMetadata(AbstractStaticLoader::class); $loader->loadClassMetadata($metadata); @@ -95,7 +95,7 @@ public function testLoadClassMetadataIgnoresAbstractMethods() // strict standards error error_reporting(0); - $metadata = new ClassMetadata(__NAMESPACE__.'\AbstractStaticMethodLoader'); + $metadata = new ClassMetadata(AbstractStaticMethodLoader::class); $loader = new StaticMethodLoader('loadMetadata'); $loader->loadClassMetadata($metadata); diff --git a/src/Symfony/Component/VarDumper/Caster/Caster.php b/src/Symfony/Component/VarDumper/Caster/Caster.php index c1f38eb4a81e4..c279249a4d660 100644 --- a/src/Symfony/Component/VarDumper/Caster/Caster.php +++ b/src/Symfony/Component/VarDumper/Caster/Caster.php @@ -54,6 +54,15 @@ public static function castObject($obj, $class, $hasDebugInfo = false) $class = $class->name; } + if ($hasDebugInfo) { + try { + $debugInfo = $obj->__debugInfo(); + } catch (\Exception $e) { + // ignore failing __debugInfo() + $hasDebugInfo = false; + } + } + $a = $obj instanceof \Closure ? [] : (array) $obj; if ($obj instanceof \__PHP_Incomplete_Class) { @@ -89,7 +98,7 @@ public static function castObject($obj, $class, $hasDebugInfo = false) } } - if ($hasDebugInfo && \is_array($debugInfo = $obj->__debugInfo())) { + if ($hasDebugInfo && \is_array($debugInfo)) { foreach ($debugInfo as $k => $v) { if (!isset($k[0]) || "\0" !== $k[0]) { $k = self::PREFIX_VIRTUAL.$k; diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index 10d78b244a67b..aed1a67a1ea1e 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -45,6 +45,7 @@ abstract class AbstractCloner implements ClonerInterface 'Doctrine\Common\Proxy\Proxy' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castCommonProxy'], 'Doctrine\ORM\Proxy\Proxy' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castOrmProxy'], 'Doctrine\ORM\PersistentCollection' => ['Symfony\Component\VarDumper\Caster\DoctrineCaster', 'castPersistentCollection'], + 'Doctrine\Persistence\ObjectManager' => ['Symfony\Component\VarDumper\Caster\StubCaster', 'cutInternals'], 'DOMException' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castException'], 'DOMStringList' => ['Symfony\Component\VarDumper\Caster\DOMCaster', 'castLength'], diff --git a/src/Symfony/Component/VarDumper/LICENSE b/src/Symfony/Component/VarDumper/LICENSE index cf8b3ebe87145..684fbf94df83c 100644 --- a/src/Symfony/Component/VarDumper/LICENSE +++ b/src/Symfony/Component/VarDumper/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2014-2019 Fabien Potencier +Copyright (c) 2014-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php index 37e14966f4f67..a0c6dc2355202 100644 --- a/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php @@ -129,7 +129,7 @@ class: "Symfony\Component\VarDumper\Tests\Caster\ReflectionCasterTest" public function testReflectionParameter() { - $var = new \ReflectionParameter(__NAMESPACE__.'\reflectionParameterFixture', 0); + $var = new \ReflectionParameter(reflectionParameterFixture::class, 0); $this->assertDumpMatchesFormat( <<<'EOTXT' diff --git a/src/Symfony/Component/WebLink/LICENSE b/src/Symfony/Component/WebLink/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/WebLink/LICENSE +++ b/src/Symfony/Component/WebLink/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Workflow/LICENSE b/src/Symfony/Component/Workflow/LICENSE index cf8b3ebe87145..684fbf94df83c 100644 --- a/src/Symfony/Component/Workflow/LICENSE +++ b/src/Symfony/Component/Workflow/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2014-2019 Fabien Potencier +Copyright (c) 2014-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Yaml/Dumper.php b/src/Symfony/Component/Yaml/Dumper.php index a496dcc88ec2f..641dcd7f5419c 100644 --- a/src/Symfony/Component/Yaml/Dumper.php +++ b/src/Symfony/Component/Yaml/Dumper.php @@ -105,7 +105,7 @@ public function dump($input, $inline = 0, $indent = 0, $flags = 0) $blockIndentationIndicator = (' ' === substr($value, 0, 1)) ? (string) $this->indentation : ''; $output .= sprintf("%s%s%s |%s\n", $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', '', $blockIndentationIndicator); - foreach (preg_split('/\n|\r\n/', $value) as $row) { + foreach (explode("\n", $value) as $row) { $output .= sprintf("%s%s%s\n", $prefix, str_repeat(' ', $this->indentation), $row); } @@ -115,6 +115,19 @@ public function dump($input, $inline = 0, $indent = 0, $flags = 0) if ($value instanceof TaggedValue) { $output .= sprintf('%s%s !%s', $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', $value->getTag()); + if ($inline >= 1 && Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && \is_string($value->getValue()) && false !== strpos($value->getValue(), "\n") && false === strpos($value->getValue(), "\r\n")) { + // If the first line starts with a space character, the spec requires a blockIndicationIndicator + // http://www.yaml.org/spec/1.2/spec.html#id2793979 + $blockIndentationIndicator = (' ' === substr($value->getValue(), 0, 1)) ? (string) $this->indentation : ''; + $output .= sprintf(" |%s\n", $blockIndentationIndicator); + + foreach (explode("\n", $value->getValue()) as $row) { + $output .= sprintf("%s%s%s\n", $prefix, str_repeat(' ', $this->indentation), $row); + } + + continue; + } + if ($inline - 1 <= 0 || null === $value->getValue() || is_scalar($value->getValue())) { $output .= ' '.$this->dump($value->getValue(), $inline - 1, 0, $flags)."\n"; } else { diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index 7d3218a35e187..73aba3cb8b0dc 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -504,6 +504,11 @@ private static function parseMapping($mapping, $flags, &$i = 0, $references = [] $isKeyQuoted = \in_array($mapping[$i], ['"', "'"], true); $key = self::parseScalar($mapping, $flags, [':', ' '], $i, false, [], true); + if ('!php/const' === $key) { + $key .= self::parseScalar($mapping, $flags, [':', ' '], $i, false, [], true); + $key = self::evaluateScalar($key, $flags); + } + if (':' !== $key && false === $i = strpos($mapping, ':', $i)) { break; } @@ -735,11 +740,11 @@ private static function evaluateScalar($scalar, $flags, $references = []) // Optimize for returning strings. // no break case '+' === $scalar[0] || '-' === $scalar[0] || '.' === $scalar[0] || is_numeric($scalar[0]): + if (Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar)) { + $scalar = str_replace('_', '', (string) $scalar); + } + switch (true) { - case Parser::preg_match('{^[+-]?[0-9][0-9_]*$}', $scalar): - $scalar = str_replace('_', '', (string) $scalar); - // omitting the break / return as integers are handled in the next case - // no break case ctype_digit($scalar): $raw = $scalar; $cast = (int) $scalar; @@ -749,7 +754,7 @@ private static function evaluateScalar($scalar, $flags, $references = []) $raw = $scalar; $cast = (int) $scalar; - return '0' == $scalar[1] ? octdec($scalar) : (((string) $raw === (string) $cast) ? $cast : $raw); + return '0' == $scalar[1] ? -octdec(substr($scalar, 1)) : (($raw === (string) $cast) ? $cast : $raw); case is_numeric($scalar): case Parser::preg_match(self::getHexRegex(), $scalar): $scalar = str_replace('_', '', $scalar); diff --git a/src/Symfony/Component/Yaml/LICENSE b/src/Symfony/Component/Yaml/LICENSE index a677f43763ca4..9e936ec0448b8 100644 --- a/src/Symfony/Component/Yaml/LICENSE +++ b/src/Symfony/Component/Yaml/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2004-2019 Fabien Potencier +Copyright (c) 2004-2020 Fabien Potencier Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/src/Symfony/Component/Yaml/README.md b/src/Symfony/Component/Yaml/README.md index 0d324881ce5e4..b914e7836c7a5 100644 --- a/src/Symfony/Component/Yaml/README.md +++ b/src/Symfony/Component/Yaml/README.md @@ -6,7 +6,7 @@ The Yaml component loads and dumps YAML files. Resources --------- - * [Documentation](https://symfony.com/doc/current/components/yaml/index.html) + * [Documentation](https://symfony.com/doc/current/components/yaml.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/Yaml/Tests/DumperTest.php b/src/Symfony/Component/Yaml/Tests/DumperTest.php index 1a1ef25a5a4bc..231cf9a838fc7 100644 --- a/src/Symfony/Component/Yaml/Tests/DumperTest.php +++ b/src/Symfony/Component/Yaml/Tests/DumperTest.php @@ -553,6 +553,39 @@ public function testDumpingNotInlinedNullTaggedValue() $this->assertSame($expected, $this->dumper->dump($data, 2)); } + public function testDumpingMultiLineStringAsScalarBlockTaggedValue() + { + $data = [ + 'foo' => new TaggedValue('bar', "foo\nline with trailing spaces:\n \nbar\ninteger like line:\n123456789\nempty line:\n\nbaz"), + ]; + $expected = <<assertSame($expected, $this->dumper->dump($data, 2, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK)); + } + + public function testDumpingInlinedMultiLineIfRnBreakLineInTaggedValue() + { + $data = [ + 'data' => [ + 'foo' => new TaggedValue('bar', "foo\r\nline with trailing spaces:\n \nbar\ninteger like line:\n123456789\nempty line:\n\nbaz"), + ], + ]; + + $this->assertSame(file_get_contents(__DIR__.'/Fixtures/multiple_lines_as_literal_block_for_tagged_values.yml'), $this->dumper->dump($data, 2, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK)); + } + public function testDumpMultiLineStringAsScalarBlock() { $data = [ diff --git a/src/Symfony/Component/Yaml/Tests/Fixtures/multiple_lines_as_literal_block_for_tagged_values.yml b/src/Symfony/Component/Yaml/Tests/Fixtures/multiple_lines_as_literal_block_for_tagged_values.yml new file mode 100644 index 0000000000000..f8c9112fd52a5 --- /dev/null +++ b/src/Symfony/Component/Yaml/Tests/Fixtures/multiple_lines_as_literal_block_for_tagged_values.yml @@ -0,0 +1,2 @@ +data: + foo: !bar "foo\r\nline with trailing spaces:\n \nbar\ninteger like line:\n123456789\nempty line:\n\nbaz" diff --git a/src/Symfony/Component/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php index 014a12a706723..54372d69505bc 100644 --- a/src/Symfony/Component/Yaml/Tests/InlineTest.php +++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php @@ -58,6 +58,7 @@ public function getTestsForParsePhpConstants() ['!php/const PHP_INT_MAX', PHP_INT_MAX], ['[!php/const PHP_INT_MAX]', [PHP_INT_MAX]], ['{ foo: !php/const PHP_INT_MAX }', ['foo' => PHP_INT_MAX]], + ['{ !php/const PHP_INT_MAX: foo }', [PHP_INT_MAX => 'foo']], ['!php/const NULL', null], ]; } @@ -93,6 +94,7 @@ public function getTestsForParseLegacyPhpConstants() ['!php/const:PHP_INT_MAX', PHP_INT_MAX], ['[!php/const:PHP_INT_MAX]', [PHP_INT_MAX]], ['{ foo: !php/const:PHP_INT_MAX }', ['foo' => PHP_INT_MAX]], + ['{ !php/const:PHP_INT_MAX: foo }', [PHP_INT_MAX => 'foo']], ['!php/const:NULL', null], ]; } @@ -781,4 +783,20 @@ public function testUnfinishedInlineMap() $this->expectExceptionMessage('Unexpected end of line, expected one of ",}" at line 1 (near "{abc: \'def\'").'); Inline::parse("{abc: 'def'"); } + + /** + * @dataProvider getTestsForOctalNumbers + */ + public function testParseOctalNumbers($expected, $yaml) + { + self::assertSame($expected, Inline::parse($yaml)); + } + + public function getTestsForOctalNumbers() + { + return [ + 'positive octal number' => [28, '034'], + 'negative octal number' => [-28, '-034'], + ]; + } }