diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 415464c40b9a8..0bef18db33536 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -25,3 +25,5 @@
/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ValidateWorkflowsPass.php @lyrixx
/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/WorkflowGuardListenerPass.php @lyrixx
/src/Symfony/Component/Workflow/* @lyrixx
+# Yaml
+/src/Symfony/Component/Yaml/* @xabbuh
diff --git a/.travis.yml b/.travis.yml
index c23169a9b4d9e..d4c5156a6d2a5 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -149,7 +149,7 @@ before_install:
tfold ext.apcu tpecl apcu-5.1.6 apcu.so $INI
tfold ext.libsodium tpecl libsodium sodium.so $INI
- tfold ext.mongodb tpecl mongodb-1.4.0RC1 mongodb.so $INI
+ tfold ext.mongodb tpecl mongodb-1.5.0 mongodb.so $INI
tfold ext.amqp tpecl amqp-1.9.3 amqp.so $INI
fi
diff --git a/CHANGELOG-4.0.md b/CHANGELOG-4.0.md
index 7131036ba4fa8..72d24bf39e62d 100644
--- a/CHANGELOG-4.0.md
+++ b/CHANGELOG-4.0.md
@@ -7,6 +7,46 @@ in 4.0 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.0.0...v4.0.1
+* 4.0.12 (2018-06-25)
+
+ * bug #27626 [TwigBundle][DX] Only add the Twig WebLinkExtension if the WebLink component is enabled (thewilkybarkid)
+ * bug #27701 [SecurityBundle] Dont throw if "security.http_utils" is not found (nicolas-grekas)
+ * bug #27690 [DI] Resolve env placeholder in logs (ro0NL)
+ * bug #26534 allow_extra_attributes does not throw an exception as documented (deviantintegral)
+ * bug #27668 [Lock] use 'r+' for fopen (fixes issue on Solaris) (fritzmg)
+ * bug #27669 [Filesystem] fix file lock on SunOS (fritzmg)
+ * bug #27662 [HttpKernel] fix handling of nested Error instances (xabbuh)
+ * bug #26845 [Config] Fixing GlobResource when inside phar archive (vworldat)
+ * bug #27382 [Form] Fix error when rendering a DateIntervalType form with exactly 0 weeks (krixon)
+ * bug #27309 Fix surrogate not using original request (Toflar)
+ * bug #27467 [HttpKernel] fix session tracking in surrogate master requests (nicolas-grekas)
+ * bug #27630 [Validator][Form] Remove BOM in some xlf files (gautierderuette)
+ * bug #27596 [Framework][Workflow] Added support for interfaces (vudaltsov)
+ * bug #27593 [ProxyManagerBridge] Fixed support of private services (nicolas-grekas)
+ * bug #27591 [VarDumper] Fix dumping ArrayObject and ArrayIterator instances (nicolas-grekas)
+ * bug #27581 Fix bad method call with guard authentication + session migration (weaverryan)
+ * bug #27576 [Cache] Fix expiry comparisons in array-based pools (nicolas-grekas)
+ * bug #27556 Avoiding session migration for stateless firewall UsernamePasswordJsonAuthenticationListener (weaverryan)
+ * bug #27452 Avoid migration on stateless firewalls (weaverryan)
+ * bug #27568 [DI] Deduplicate generated proxy classes (nicolas-grekas)
+ * bug #27326 [Serializer] deserialize from xml: Fix a collection that contains the only one element (webnet-fr)
+ * bug #27567 [PhpUnitBridge] Fix error on some Windows OS (Nsbx)
+ * bug #27357 [Lock] Remove released semaphore (jderusse)
+ * bug #27416 TagAwareAdapter over non-binary memcached connections corrupts memcache (Aleksey Prilipko)
+ * bug #27514 [Debug] Pass previous exception to FatalErrorException (pmontoya)
+ * bug #27516 Revert "bug #26138 [HttpKernel] Catch HttpExceptions when templating is not installed (cilefen)" (nicolas-grekas)
+ * bug #27318 [Cache] memcache connect should not add duplicate entries on sequential calls (Aleksey Prilipko)
+ * bug #27389 [Serializer] Fix serializer tries to denormalize null values on nullable properties (ogizanagi)
+ * bug #27272 [FrameworkBundle] Change priority of AddConsoleCommandPass to TYPE_BEFORE_REMOVING (upyx)
+ * bug #27396 [HttpKernel] fix registering IDE links (nicolas-grekas)
+ * bug #26973 [HttpKernel] Set first trusted proxy as REMOTE_ADDR in InlineFragmentRenderer. (kmadejski)
+ * bug #27303 [Process] Consider "executable" suffixes first on Windows (sanmai)
+ * bug #27297 Triggering RememberMe's loginFail() when token cannot be created (weaverryan)
+ * bug #27344 [HttpKernel] reset kernel start time on reboot (kiler129)
+ * bug #27365 [Serializer] Check the value of enable_max_depth if defined (dunglas)
+ * bug #27358 [PhpUnitBridge] silence some stderr outputs (ostrolucky)
+ * bug #27366 [DI] never inline lazy services (nicolas-grekas)
+
* 4.0.11 (2018-05-25)
* bug #27364 [DI] Fix bad exception on uninitialized references to non-shared services (nicolas-grekas)
diff --git a/CHANGELOG-4.1.md b/CHANGELOG-4.1.md
index b09b994c5cd63..e7126dcf6d28c 100644
--- a/CHANGELOG-4.1.md
+++ b/CHANGELOG-4.1.md
@@ -7,6 +7,53 @@ in 4.1 minor versions.
To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash
To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.1.0...v4.1.1
+* 4.1.2 (2018-07-23)
+
+ * bug #28005 [HttpKernel] Fixed templateExists on parse error of the template name (yceruto)
+ * bug #28013 [Messenger] Add missing typehint on chain sender (sroze)
+ * bug #27997 Serbo-Croatian has Serbian plural rule (kylekatarnls)
+ * bug #26193 Fix false-positive deprecation notices for TranslationLoader and WriteCheckSessionHandler (iquito)
+ * bug #27827 [Serializer] Supports nested abstract items (sroze)
+ * bug #27958 [Form] Remaining changes for bootstrap 4 file fields (apfelbox)
+ * bug #27919 [Form] Improve rendering of `file` field in bootstrap 4 (apfelbox)
+ * bug #27941 [WebProfilerBundle] Fixed icon alignment issue using Bootstrap 4.1.2 (jmsche)
+ * bug #27937 [HttpFoundation] reset callback on StreamedResponse when setNotModified() is called (rubencm)
+ * bug #27927 [HttpFoundation] Suppress side effects in 'get' and 'has' methods of NamespacedAttributeBag (webnet-fr)
+ * bug #27913 [EventDispatcher] Clear orphaned events on reset (acasademont)
+ * bug #27923 [Form/Profiler] Massively reducing memory footprint of form profiling pages... (VincentChalnot)
+ * bug #27918 [Console] correctly return parameter's default value on "--" (seschwar)
+ * bug #27826 [Serializer] Fix serialization of items with groups across entities and discrimination map (sroze)
+ * bug #27904 [Filesystem] fix lock file permissions (fritzmg)
+ * bug #27903 [Lock] fix lock file permissions (fritzmg)
+ * bug #27889 [Form] Replace .initialism with .text-uppercase. (vudaltsov)
+ * bug #27902 Fix the detection of the Process new argument (stof)
+ * bug #27885 [HttpFoundation] don't encode cookie name for BC (nicolas-grekas)
+ * bug #27782 [DI] Fix dumping ignore-on-uninitialized references to synthetic services (nicolas-grekas)
+ * bug #27435 [OptionResolver] resolve arrays (Doctrs)
+ * bug #27728 [TwigBridge] Fix missing path and separators in loader paths list on debug:twig output (yceruto)
+ * bug #27837 [PropertyInfo] Fix dock block lookup fallback loop (DerManoMann)
+ * bug #27848 [Workflow] Fixed BC break (lyrixx)
+ * bug #27758 [WebProfilerBundle] Prevent toolbar links color override by css (alcalyn)
+ * bug #27847 [Security] Fix accepting null as $uidKey in LdapUserProvider (louhde)
+ * bug #27820 [Messenger] Fix a bug when having more than one named handler per message subscriber (sroze)
+ * bug #27834 [DI] Don't show internal service id on binding errors (nicolas-grekas)
+ * bug #27831 Check for Hyper terminal on all operating systems. (azjezz)
+ * bug #27794 Add color support for Hyper terminal . (azjezz)
+ * bug #27809 [HttpFoundation] Fix tests: new message for status 425 (dunglas)
+ * bug #27618 [PropertyInfo] added handling of nullable types in PhpDoc (oxan)
+ * bug #27659 [HttpKernel] Make AbstractTestSessionListener compatible with CookieClearingLogoutHandler (thewilkybarkid)
+ * bug #27752 [Cache] provider does not respect option maxIdLength with versioning enabled (Constantine Shtompel)
+ * bug #27773 [Serializer] Class discriminator and serialization groups (sroze)
+ * bug #27710 [DependencyInjection] fix handling of empty DI extension configs (xabbuh)
+ * bug #27776 [ProxyManagerBridge] Fix support of private services (bis) (nicolas-grekas)
+ * bug #27714 [HttpFoundation] fix session tracking counter (nicolas-grekas, dmaicher)
+ * bug #27727 [Routing] Disallow object usage inside Route (paxal)
+ * bug #27736 [Routing] fix too much greediness in host-matching regex (nicolas-grekas)
+ * bug #27747 [HttpFoundation] fix registration of session proxies (nicolas-grekas)
+ * bug #27754 [HttpFoundation] missing namespace for RedisProxy (Bonfante)
+ * bug #27722 Redesign the Debug error page in prod (javiereguiluz)
+ * bug #27716 [DI] fix dumping deprecated service in yaml (nicolas-grekas)
+
* 4.1.1 (2018-06-25)
* bug #27626 [TwigBundle][DX] Only add the Twig WebLinkExtension if the WebLink component is enabled (thewilkybarkid)
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 672246e7f9da8..b6eef0b63198c 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
- Robin Chalas (chalas_r)
- Johannes S (johannes)
- Jakub Zalas (jakubzalas)
- - Kris Wallsmith (kriswallsmith)
- Maxime Steinhausser (ogizanagi)
+ - Kris Wallsmith (kriswallsmith)
- Ryan Weaver (weaverryan)
- Javier Eguiluz (javier.eguiluz)
- Grégoire Pineau (lyrixx)
@@ -25,8 +25,8 @@ Symfony is the result of the work of many people who made the code better
- Abdellatif Ait boudad (aitboudad)
- Romain Neutron (romain)
- Pascal Borreli (pborreli)
- - Wouter De Jong (wouterj)
- Roland Franssen (ro0)
+ - Wouter De Jong (wouterj)
- Joseph Bielawski (stloyd)
- Karma Dordrak (drak)
- Lukas Kahwe Smith (lsmith)
@@ -39,8 +39,8 @@ Symfony is the result of the work of many people who made the code better
- Jules Pietri (heah)
- Eriksen Costa (eriksencosta)
- Guilhem Niot (energetick)
- - Sarah Khalil (saro0h)
- Yonel Ceruto (yonelceruto)
+ - Sarah Khalil (saro0h)
- Jonathan Wage (jwage)
- Hamza Amrouche (simperfit)
- Diego Saint Esteben (dosten)
@@ -54,36 +54,37 @@ Symfony is the result of the work of many people who made the code better
- Bulat Shakirzyanov (avalanche123)
- Peter Rehm (rpet)
- Matthias Pigulla (mpdude)
+ - Dany Maillard (maidmaid)
- Saša Stamenković (umpirsky)
+ - Kevin Bond (kbond)
+ - Tobias Nyholm (tobias)
- Pierre du Plessis (pierredup)
- Henrik Bjørnskov (henrikbjorn)
- - Dany Maillard (maidmaid)
- Miha Vrhovnik
- - Kevin Bond (kbond)
- - Tobias Nyholm (tobias)
- Diego Saint Esteben (dii3g0)
- - Konstantin Kudryashov (everzet)
- Alexander M. Turek (derrabus)
+ - Konstantin Kudryashov (everzet)
- Bilal Amarni (bamarni)
- Jérémy DERUSSÉ (jderusse)
- Florin Patan (florinpatan)
- Mathieu Piot (mpiot)
- Gábor Egyed (1ed)
- Michel Weimerskirch (mweimerskirch)
+ - Titouan Galopin (tgalopin)
- Andrej Hudec (pulzarraider)
- Eric Clemmons (ericclemmons)
- Jáchym Toušek (enumag)
- Charles Sarrazin (csarrazi)
- - Titouan Galopin (tgalopin)
- Konstantin Myakshin (koc)
- Christian Raue
+ - David Maicher (dmaicher)
- Arnout Boks (aboks)
- Deni
- Henrik Westphal (snc)
- Dariusz Górecki (canni)
- Issei Murasawa (issei_m)
- Douglas Greenshields (shieldo)
- - David Maicher (dmaicher)
+ - Vladimir Reznichenko (kalessil)
- Lee McDermott
- Brandon Turner
- Luis Cordova (cordoval)
@@ -96,7 +97,6 @@ Symfony is the result of the work of many people who made the code better
- Jérôme Tamarelle (gromnan)
- John Wards (johnwards)
- Fran Moreno (franmomu)
- - Vladimir Reznichenko (kalessil)
- Antoine Hérault (herzult)
- Paráda József (paradajozsef)
- Arnaud Le Blanc (arnaud-lb)
@@ -105,18 +105,20 @@ Symfony is the result of the work of many people who made the code better
- Tim Nagel (merk)
- Grégoire Paris (greg0ire)
- Brice BERNARD (brikou)
+ - Valentin Udaltsov (vudaltsov)
+ - gadelat (gadelat)
- Baptiste Clavié (talus)
- marc.weistroff
- lenar
- Alexander Schwenn (xelaris)
- Włodzimierz Gajda (gajdaw)
+ - Peter Kokot (maastermedia)
- Jacob Dreesen (jdreesen)
- Florian Voutzinos (florianv)
- Colin Frei
- Adrien Brault (adrienbrault)
- Tomáš Votruba (tomas_votruba)
- Joshua Thijssen
- - Peter Kokot (maastermedia)
- David Buchmann (dbu)
- excelwebzone
- Fabien Pennequin (fabienpennequin)
@@ -131,6 +133,7 @@ Symfony is the result of the work of many people who made the code better
- Florian Lonqueu-Brochard (florianlb)
- Sebastiaan Stok (sstok)
- Stefano Sala (stefano.sala)
+ - Jérôme Vasseur (jvasseur)
- Evgeniy (ewgraf)
- Alex Pott
- Vincent AUBERT (vincent)
@@ -139,9 +142,8 @@ Symfony is the result of the work of many people who made the code better
- Sebastian Hörl (blogsh)
- Daniel Gomes (danielcsgomes)
- Hidenori Goto (hidenorigoto)
- - Jérôme Vasseur (jvasseur)
- - Valentin Udaltsov (vudaltsov)
- - gadelat (gadelat)
+ - Chris Wilkinson (thewilkybarkid)
+ - Arnaud Kleinpeter (nanocom)
- Guilherme Blanco (guilhermeblanco)
- Pablo Godel (pgodel)
- Jérémie Augustin (jaugustin)
@@ -149,12 +151,10 @@ Symfony is the result of the work of many people who made the code better
- Philipp Wahala (hifi)
- Julien Falque (julienfalque)
- Rafael Dohms (rdohms)
- - Arnaud Kleinpeter (nanocom)
- jwdeitch
- Teoh Han Hui (teohhanhui)
- Mikael Pajunen
- Joel Wurtz (brouznouf)
- - Chris Wilkinson (thewilkybarkid)
- Oleg Voronkovich
- Vyacheslav Pavlov
- Richard van Laak (rvanlaak)
@@ -170,6 +170,7 @@ Symfony is the result of the work of many people who made the code better
- Amal Raghav (kertz)
- Jonathan Ingram (jonathaningram)
- Artur Kotyrba
+ - Jannik Zschiesche (apfelbox)
- GDIBass
- jeremyFreeAgent (Jérémy Romey) (jeremyfreeagent)
- James Halsall (jaitsu)
@@ -178,6 +179,7 @@ Symfony is the result of the work of many people who made the code better
- Warnar Boekkooi (boekkooi)
- Dmitrii Chekaliuk (lazyhammer)
- Clément JOBEILI (dator)
+ - Niels Keurentjes (curry684)
- Daniel Espendiller
- Possum
- Dorian Villet (gnutix)
@@ -203,7 +205,6 @@ Symfony is the result of the work of many people who made the code better
- Matthieu Bontemps (mbontemps)
- apetitpa
- Pierre Minnieur (pminnieur)
- - Jannik Zschiesche (apfelbox)
- fivestar
- Dominique Bongiraud
- Jeremy Livingston (jeremylivingston)
@@ -219,22 +220,26 @@ Symfony is the result of the work of many people who made the code better
- Michele Orselli (orso)
- Tom Van Looy (tvlooy)
- Sven Paulus (subsven)
+ - Yanick Witschi (toflar)
- Thomas Calvet (fancyweb)
- Rui Marinho (ruimarinho)
- - Niels Keurentjes (curry684)
+ - Alessandro Chitolina
- Eugene Wissner
+ - Pascal Montoya
- Julien Brochet (mewt)
- Leo Feyer
- Tristan Darricau (nicofuma)
- Nikolay Labinskiy (e-moe)
- Michaël Perrin (michael.perrin)
- Marcel Beerta (mazen)
+ - Albert Casademont (acasademont)
- Loïc Faugeron
- Hidde Wieringa (hiddewie)
- Marco Pivetta (ocramius)
- Rob Frawley 2nd (robfrawley)
- julien pauli (jpauli)
- Lorenz Schori
+ - Oskar Stark (oskarstark)
- Sébastien Lavoie (lavoiesl)
- Gregor Harlan (gharlan)
- Dariusz
@@ -255,14 +260,13 @@ Symfony is the result of the work of many people who made the code better
- Arjen Brouwer (arjenjb)
- Katsuhiro OGAWA
- Patrick McDougle (patrick-mcdougle)
- - Yanick Witschi (toflar)
- Alif Rachmawadi
- - Alessandro Chitolina
- Kristen Gilden (kgilden)
- Pierre-Yves LEBECQ (pylebecq)
- Jordan Samouh (jordansamouh)
- Baptiste Lafontaine (magnetik)
- Jakub Kucharovic (jkucharovic)
+ - Edi Modrić (emodric)
- Uwe Jäger (uwej711)
- Eugene Leonovich (rybakit)
- Filippo Tessarotto
@@ -274,7 +278,6 @@ Symfony is the result of the work of many people who made the code better
- Tyson Andre
- Chekote
- Thomas Adam
- - Albert Casademont (acasademont)
- Viktor Bocharskyi (bocharsky_bw)
- Jhonny Lidfors (jhonne)
- Diego Agulló (aeoris)
@@ -284,7 +287,6 @@ Symfony is the result of the work of many people who made the code better
- Bob den Otter (bopp)
- Nikita Konstantinov
- Wodor Wodorski
- - Oskar Stark (oskarstark)
- Thomas Lallement (raziel057)
- Giorgio Premi
- Christian Schmidt
@@ -303,7 +305,7 @@ Symfony is the result of the work of many people who made the code better
- Marc Weistroff (futurecat)
- Christian Schmidt
- Maxime Veber (nek-)
- - Edi Modrić (emodric)
+ - MatTheCat
- Chad Sikorra (chadsikorra)
- Chris Smith (cs278)
- Florian Klein (docteurklein)
@@ -347,6 +349,7 @@ Symfony is the result of the work of many people who made the code better
- Artur Melo (restless)
- Matthew Lewinski (lewinski)
- Magnus Nordlander (magnusnordlander)
+ - Thomas Royer (cydonia7)
- alquerci
- Francesco Levorato
- Vitaliy Zakharov (zakharovvi)
@@ -358,11 +361,11 @@ Symfony is the result of the work of many people who made the code better
- Artur Eshenbrener
- François-Xavier de Guillebon (de-gui_f)
- Damien Alexandre (damienalexandre)
+ - Thomas Perez (scullwm)
- Felix Labrecque
- Yaroslav Kiliba
- Terje Bråten
- Mathieu Lechat
- - MatTheCat
- Robbert Klarenbeek (robbertkl)
- JhonnyL
- David Badura (davidbadura)
@@ -374,6 +377,7 @@ Symfony is the result of the work of many people who made the code better
- ShinDarth
- Stéphane PY (steph_py)
- Philipp Kräutli (pkraeutli)
+ - Grzegorz (Greg) Zdanowski (kiler129)
- Kirill chEbba Chebunin (chebba)
- Greg Thornton (xdissent)
- Gary PEGEOT (gary-p)
@@ -427,13 +431,13 @@ Symfony is the result of the work of many people who made the code better
- Christopher Davis (chrisguitarguy)
- Jan Schumann
- Niklas Fiekas
+ - Colin O'Dell (colinodell)
- Markus Bachmann (baachi)
- lancergr
- Zan Baldwin
- Mihai Stancu
- Olivier Dolbeau (odolbeau)
- Jan Rosier (rosier)
- - Thomas Royer (cydonia7)
- Arturs Vonda
- Josip Kruslin
- Asmir Mustafic (goetas)
@@ -453,7 +457,6 @@ Symfony is the result of the work of many people who made the code better
- Dirk Pahl (dirkaholic)
- cedric lombardot (cedriclombardot)
- Jonas Flodén (flojon)
- - Thomas Perez (scullwm)
- Marcin Sikoń (marphi)
- Dominik Zogg (dominik.zogg)
- Marek Pietrzak
@@ -511,6 +514,7 @@ Symfony is the result of the work of many people who made the code better
- Andrew Udvare (audvare)
- alexpods
- Arjen van der Meijden
+ - Adam Szaraniec (mimol)
- Dariusz Ruminski
- Erik Trapman (eriktrapman)
- De Cock Xavier (xdecock)
@@ -550,6 +554,7 @@ Symfony is the result of the work of many people who made the code better
- Ned Schwartz
- Ziumin
- Jeremy Benoist
+ - fritzmg
- Lenar Lõhmus
- Sander Toonen (xatoo)
- Benjamin Laugueux (yzalis)
@@ -588,9 +593,11 @@ Symfony is the result of the work of many people who made the code better
- Nahuel Cuesta (ncuesta)
- Chris Boden (cboden)
- Christophe Villeger (seragan)
+ - Bob van de Vijver (bobvandevijver)
- Stefan Gehrig (sgehrig)
- Hany el-Kerdany
- Wang Jingyu
+ - Webnet team (webnet)
- Åsmund Garfors
- Gunnstein Lye (glye)
- Maxime Douailin
@@ -609,6 +616,7 @@ Symfony is the result of the work of many people who made the code better
- David Fuhr
- Kamil Kokot (pamil)
- Max Grigorian (maxakawizard)
+ - DerManoMann
- mcfedr (mcfedr)
- Rostyslav Kinash
- Maciej Malarz (malarzm)
@@ -637,6 +645,7 @@ Symfony is the result of the work of many people who made the code better
- Richard Bradley
- Ulumuddin Yunus (joenoez)
- Johann Saunier (prophet777)
+ - Sergey (upyx)
- Michael Devery (mickadoo)
- Antoine Corcy
- Sascha Grossenbacher
@@ -666,31 +675,40 @@ Symfony is the result of the work of many people who made the code better
- Thomas Ploch
- Benjamin Grandfond (benjamin)
- Tiago Brito (blackmx)
+ -
- Richard van den Brand (ricbra)
- develop
+ - flip111
- Greg Anderson
- VJ
- Delf Tonder (leberknecht)
- Mark Sonnabaum
+ - Massimiliano Braglia (massimilianobraglia)
- Richard Quadling
- jochenvdv
- Arturas Smorgun (asarturas)
- Alexander Volochnev (exelenz)
- Michael Piecko
- yclian
+ - Aleksey Prilipko
- twifty
- Indra Gunawan (guind)
- Peter Ward
+ - Davide Borsatto (davide.borsatto)
+ - Rhodri Pugh (rodnaph)
- Julien DIDIER (juliendidier)
- Dominik Ritter (dritter)
- Sebastian Grodzicki (sgrodzicki)
- Jeroen van den Enden (stoefke)
- Pascal Helfenstein
+ - Anthony GRASSIOT (antograssiot)
- Baldur Rensch (brensch)
+ - Pierre Rineau
- Vladyslav Petrovych
- Alex Xandra Albert Sim
- Craig Duncan (duncan3dc)
- Carson Full
+ - Sergey Yastrebov
- Trent Steel (trsteel88)
- Yuen-Chi Lian
- Besnik Br
@@ -717,11 +735,13 @@ Symfony is the result of the work of many people who made the code better
- Joschi Kuphal
- John Bohn (jbohn)
- Marc Morera (mmoreram)
+ - Saif Eddin Gmati (azjezz)
+ - Smaine Milianni (ismail1432)
+ - Michael Moravec
- Andrew Hilobok (hilobok)
- Noah Heck (myesain)
- Christian Soronellas (theunic)
- Johann Pardanaud
- - Adam Szaraniec (mimol)
- Yosmany Garcia (yosmanyga)
- Wouter de Wild
- Antoine M (amakdessi)
@@ -734,6 +754,7 @@ Symfony is the result of the work of many people who made the code better
- Xavier Lacot (xavier)
- possum
- Denis Zunke (donalberto)
+ - Ahmadou Waly Ndiaye (waly)
- Philipp Cordes
- Ahmed TAILOULOUTE (ahmedtai)
- Olivier Maisonneuve (olineuve)
@@ -770,6 +791,7 @@ Symfony is the result of the work of many people who made the code better
- Abhoryo
- Fabian Vogler (fabian)
- Korvin Szanto
+ - Stéphan Kochen
- Arjan Keeman
- Alaattin Kahramanlar (alaattin)
- Sergey Zolotov (enleur)
@@ -777,6 +799,7 @@ Symfony is the result of the work of many people who made the code better
- Neil Ferreira
- Nathanael Noblet (gnat)
- Indra Gunawan (indragunawan)
+ - Julie Hourcade (juliehde)
- Dmitry Parnas (parnas)
- Paul LE CORRE
- Emanuele Iannone
@@ -853,6 +876,7 @@ Symfony is the result of the work of many people who made the code better
- LOUARDI Abdeltif (ouardisoft)
- Robert Gruendler (pulse00)
- Simon Terrien (sterrien)
+ - Tarmo Leppänen (tarlepp)
- Benoît Merlet (trompette)
- Koen Kuipers
- datibbaw
@@ -863,6 +887,7 @@ Symfony is the result of the work of many people who made the code better
- Sebastien Morel (plopix)
- Patrick Kaufmann
- Piotr Stankowski
+ - Anton Dyshkant
- Reece Fowell (reecefowell)
- Mátyás Somfai (smatyas)
- stefan.r
@@ -880,17 +905,18 @@ Symfony is the result of the work of many people who made the code better
- Sam Malone
- Phan Thanh Ha (haphan)
- Chris Jones (leek)
- - Colin O'Dell (colinodell)
- xaav
- Mahmoud Mostafa (mahmoud)
- Pieter
- Michael Tibben
- Billie Thompson
- Sander Marechal
+ - Oleg Golovakhin (doc_tr)
- Icode4Food (icode4food)
- Radosław Benkel
- jean pasqualini (darkilliant)
- Ross Motley (rossmotley)
+ - Julien Fredon
- ttomor
- Mei Gwilym (meigwilym)
- Michael H. Arieli (excelwebzone)
@@ -916,6 +942,7 @@ Symfony is the result of the work of many people who made the code better
- dantleech
- Bastien DURAND (deamon)
- Xavier Leune
+ - Rudy Onfroy
- Tero Alén (tero)
- DerManoMann
- Guillaume Royer
@@ -934,7 +961,6 @@ Symfony is the result of the work of many people who made the code better
- Máximo Cuadros (mcuadros)
- tamirvs
- julien.galenski
- - Bob van de Vijver
- Christian Neff
- Oliver Hoff
- Ole Rößner (basster)
@@ -952,8 +978,10 @@ Symfony is the result of the work of many people who made the code better
- ilyes kooli
- gr1ev0us
- mlazovla
+ - Behnoush norouzali (behnoush)
- Max Beutel
- Antanas Arvasevicius
+ - Pierre Dudoret
- Thomas
- Maximilian Berghoff (electricmaxxx)
- nacho
@@ -962,6 +990,7 @@ Symfony is the result of the work of many people who made the code better
- Sergey Novikov (s12v)
- Marcos Quesada (marcos_quesada)
- Matthew Vickery (mattvick)
+ - Viktor Novikov (panzer_commander)
- Paul Mitchum (paul-m)
- Angel Koilov (po_taka)
- Dan Finnie
@@ -996,7 +1025,6 @@ Symfony is the result of the work of many people who made the code better
- Thanos Polymeneas (thanos)
- Benoit Garret
- Jakub Sacha
- - DerManoMann
- Olaf Klischat
- orlovv
- Jonathan Hedstrom
@@ -1017,13 +1045,13 @@ Symfony is the result of the work of many people who made the code better
- Alex Bowers
- Jeremy Bush
- wizhippo
+ - Thomason, James
- Viacheslav Sychov
- Helmut Hummel (helhum)
- Matt Brunt
- Carlos Ortega Huetos
- rpg600
- Péter Buri (burci)
- - Davide Borsatto (davide.borsatto)
- kaiwa
- RJ Garcia
- Charles Sanquer (csanquer)
@@ -1033,7 +1061,6 @@ Symfony is the result of the work of many people who made the code better
- Will Donohoe
- peter
- Jaroslav Kuba
- - flip111
- Jérémy Jourdin (jjk801)
- BRAMILLE Sébastien (oktapodia)
- Artem Kolesnikov (tyomo4ka)
@@ -1043,11 +1070,9 @@ Symfony is the result of the work of many people who made the code better
- rchoquet
- gitlost
- Taras Girnyk
- - Anthony GRASSIOT (antograssiot)
- Eduardo García Sanz (coma)
- James Gilliland
- fduch (fduch)
- - Rhodri Pugh (rodnaph)
- David de Boer (ddeboer)
- Ryan Rogers
- Klaus Purer
@@ -1061,6 +1086,7 @@ Symfony is the result of the work of many people who made the code better
- Roger Webb
- Dmitriy Simushev
- Pawel Smolinski
+ - Oxan van Leeuwen
- pkowalczyk
- Max Voloshin (maxvoloshin)
- Nicolas Fabre (nfabre)
@@ -1111,6 +1137,7 @@ Symfony is the result of the work of many people who made the code better
- ConneXNL
- Aharon Perkel
- matze
+ - Rubén Calvo (rubencm)
- Abdul.Mohsen B. A. A
- Benoît Burnichon
- pthompson
@@ -1121,10 +1148,10 @@ Symfony is the result of the work of many people who made the code better
- Lars Ambrosius Wallenborn (larsborn)
- Oriol Mangas Abellan (oriolman)
- Sebastian Göttschkes (sgoettschkes)
- - Sergey (upyx)
- Tatsuya Tsuruoka
- Ross Tuck
- Kévin Gomez (kevin)
+ - Andrei Igna
- azine
- Dawid Sajdak
- Ludek Stepan
@@ -1134,6 +1161,7 @@ Symfony is the result of the work of many people who made the code better
- Erika Heidi Reinaldo (erikaheidi)
- Pierre Tachoire (krichprollsch)
- Marc J. Schmidt (marcjs)
+ - Sebastian Schwarz
- Marco Jantke
- Saem Ghani
- Clément LEFEBVRE
@@ -1142,7 +1170,6 @@ Symfony is the result of the work of many people who made the code better
- Adrien Gallou (agallou)
- Maks Rafalko (bornfree)
- Karol Sójko (karolsojko)
- - Grzegorz Zdanowski (kiler129)
- sl_toto (sl_toto)
- Walter Dal Mut (wdalmut)
- abluchet
@@ -1155,16 +1182,17 @@ Symfony is the result of the work of many people who made the code better
- Keri Henare (kerihenare)
- Cédric Lahouste (rapotor)
- Samuel Vogel (samuelvogel)
+ - Alexey Kopytko (sanmai)
- Berat Doğan
- Guillaume LECERF
- Juanmi Rodriguez Cerón
- - Sergey Yastrebov
- Andy Raines
- Anthony Ferrara
- Klaas Cuvelier (kcuvelier)
- Mathieu TUDISCO (mathieutu)
- markusu49
- Steve Frécinaux
+ - Constantine Shtompel
- Jules Lamur
- Renato Mendes Figueiredo
- ShiraNai7
@@ -1187,6 +1215,7 @@ Symfony is the result of the work of many people who made the code better
- Lance McNearney
- Gonzalo Vilaseca (gonzalovilaseca)
- Giorgio Premi
+ - Andrew Berry
- ncou
- Ian Carroll
- caponica
@@ -1205,10 +1234,10 @@ Symfony is the result of the work of many people who made the code better
- Tadcka
- Beth Binkovitz
- Gonzalo Míguez
- - Pierre Rineau
- Romain Geissler
- Adrien Moiruad
- Tomaz Ahlin
+ - Philip Ardery
- Marcus Stöhr (dafish)
- Emmanuel Vella (emmanuel.vella)
- Jonathan Johnson (jrjohnson)
@@ -1217,7 +1246,6 @@ Symfony is the result of the work of many people who made the code better
- Jay Severson
- René Kerner
- Nathaniel Catchpole
- -
- Adrien Samson (adriensamson)
- Samuel Gordalina (gordalina)
- Max Romanovsky (maxromanovsky)
@@ -1254,7 +1282,6 @@ Symfony is the result of the work of many people who made the code better
- Ergie Gonzaga
- Matthew J Mucklo
- AnrDaemon
- - Smaine Milianni (ismail1432)
- fdgdfg (psampaz)
- Stéphane Seng
- Maxwell Vandervelde
@@ -1275,18 +1302,22 @@ Symfony is the result of the work of many people who made the code better
- Jonathan Gough
- Benjamin Bender
- Jared Farrish
+ - karl.rixon
- Konrad Mohrfeldt
- Lance Chen
+ - Ciaran McNulty (ciaranmcnulty)
- Andrew (drew)
- kor3k kor3k (kor3k)
- Stelian Mocanita (stelian)
- Flavian (2much)
+ - Gautier Deuette
- mike
- Kirk Madera
- Keith Maika
- Mephistofeles
- Hoffmann András
- Olivier
+ - Cyril PASCAL
- pscheit
- Wybren Koelmans
- Zdeněk Drahoš
@@ -1313,6 +1344,7 @@ Symfony is the result of the work of many people who made the code better
- Artiom
- Jakub Simon
- Bouke Haarsma
+ - Evert Harmeling
- Martin Eckhardt
- natechicago
- Jonathan Poston
@@ -1339,6 +1371,7 @@ Symfony is the result of the work of many people who made the code better
- Harold Iedema
- Arnau González (arnaugm)
- Simon Bouland (bouland)
+ - Ivan Nikolaev (destillat)
- Matthew Foster (mfoster)
- Paul Seiffert (seiffert)
- Vasily Khayrulin (sirian)
@@ -1372,10 +1405,12 @@ Symfony is the result of the work of many people who made the code better
- Manatsawin Hanmongkolchai
- Gunther Konig
- Maciej Schmidt
+ - Greg ORIOL
- Dennis Væversted
- nuncanada
- flack
- František Bereň
+ - Kamil Madejski
- Jeremiah VALERIE
- Mike Francis
- Christoph Nissle (derstoffel)
@@ -1468,7 +1503,6 @@ Symfony is the result of the work of many people who made the code better
- Sam Ward
- Walther Lalk
- Adam
- - Stéphan Kochen
- devel
- taiiiraaa
- Trevor Suarez
@@ -1482,6 +1516,7 @@ Symfony is the result of the work of many people who made the code better
- Chansig
- Tischoi
- J Bruni
+ - Fritz Michael Gschwantner
- Alexey Prilipko
- Dmitriy Fedorenko
- vlakoff
@@ -1509,10 +1544,12 @@ Symfony is the result of the work of many people who made the code better
- Joel Marcey
- David Christmann
- root
+ - Vincent Chalnot
- James Hudson
- Tom Maguire
- Richard Quadling
- David Zuelke
+ - Adrian
- Oleg Andreyev
- Pierre Rineau
- Maxim Lovchikov
@@ -1535,6 +1572,7 @@ Symfony is the result of the work of many people who made the code better
- Hein Zaw Htet™
- Ruben Kruiswijk
- Cosmin-Romeo TANASE
+ - Julien Maulny
- Michael J
- Joseph Maarek
- Alexander Menk
@@ -1580,6 +1618,7 @@ Symfony is the result of the work of many people who made the code better
- Kuba Werłos
- Tomas Liubinas
- Alex
+ - Jan Hort
- Klaas Naaijkens
- Daniel González Cerviño
- Rafał
@@ -1686,7 +1725,6 @@ Symfony is the result of the work of many people who made the code better
- Christian Eikermann
- Kai Eichinger
- Antonio Angelino
- - Pascal Montoya
- Matt Fields
- Niklas Keller
- Vladimir Sazhin
@@ -1753,6 +1791,7 @@ Symfony is the result of the work of many people who made the code better
- Adam Klvač
- Yevgen Kovalienia
- Lebnik
+ - nsbx
- Shude
- Ondřej Führer
- Sema
@@ -1765,11 +1804,13 @@ Symfony is the result of the work of many people who made the code better
- Norman Soetbeer
- zorn
- Yuriy Potemkin
+ - Emilie Lorenzo
- Benjamin Long
- Matt Janssen
- Ben Miller
- Peter Gribanov
- kwiateusz
+ - jspee
- David Soria Parra
- Sergiy Sokolenko
- dinitrol
@@ -1827,6 +1868,7 @@ Symfony is the result of the work of many people who made the code better
- Damon Jones (damon__jones)
- Łukasz Giza (destroyer)
- Daniel Londero (dlondero)
+ - Samuele Lilli (doncallisto)
- Sebastian Landwehr (dword123)
- Adel ELHAIBA (eadel)
- Damián Nohales (eagleoneraptor)
@@ -1889,6 +1931,7 @@ Symfony is the result of the work of many people who made the code better
- scourgen hung (scourgen)
- Sébastien Alfaiate (seb33300)
- Sebastian Busch (sebu)
+ - Sepehr Lajevardi (sepehr)
- André Filipe Gonçalves Neves (seven)
- Bruno Ziegler (sfcoder)
- Andrea Giuliano (shark)
@@ -1898,12 +1941,13 @@ Symfony is the result of the work of many people who made the code better
- Julien Sanchez (sumbobyboys)
- Guillermo Gisinger (t3chn0r)
- Markus Tacker (tacker)
- - Tarmo Leppänen (tarlepp)
+ - Andrew Clark (tqt_andrew_clark)
- Tyler Stroud (tystr)
- Moritz Kraft (userfriendly)
- Víctor Mateo (victormateo)
- Vincent (vincent1870)
- Vincent CHALAMON (vincentchalamon)
+ - David Herrmann (vworldat)
- Eugene Babushkin (warl)
- Wouter Sioen (wouter_sioen)
- Xavier Amado (xamado)
@@ -1929,6 +1973,7 @@ Symfony is the result of the work of many people who made the code better
- fh-github@fholzhauer.de
- AbdElKader Bouadjadja
- DSeemiller
+ - Kyle
- Jan Emrich
- Mark Topper
- Xavier REN
@@ -1939,10 +1984,12 @@ Symfony is the result of the work of many people who made the code better
- Mohamed Karnichi (amiral)
- Andrew Carter (andrewcarteruk)
- Adam Elsodaney (archfizz)
+ - Gregório Bonfante Borba (bonfante)
- Daniel Kolvik (dkvk)
- Marc Lemay (flug)
- Henne Van Och (hennevo)
- Jeroen De Dauw (jeroendedauw)
+ - Jonathan Scheiber (jmsche)
- Daniel Alejandro Castro Arellano (lexcast)
- Maxime COLIN (maximecolin)
- Muharrem Demirci (mdemirci)
diff --git a/composer.json b/composer.json
index bf5bc53c4cc47..67065a8d919ad 100644
--- a/composer.json
+++ b/composer.json
@@ -90,7 +90,7 @@
"doctrine/cache": "~1.6",
"doctrine/data-fixtures": "1.0.*",
"doctrine/dbal": "~2.4",
- "doctrine/orm": "~2.4,>=2.4.5",
+ "doctrine/orm": "~2.4,>=2.4.5,<=2.7.0",
"doctrine/doctrine-bundle": "~1.4",
"monolog/monolog": "~1.11",
"ocramius/proxy-manager": "~0.4|~1.0|~2.0",
@@ -102,7 +102,7 @@
},
"conflict": {
"phpdocumentor/reflection-docblock": "<3.0||>=3.2.0,<3.2.2",
- "phpdocumentor/type-resolver": "<0.2.1",
+ "phpdocumentor/type-resolver": "<0.3.0",
"phpunit/phpunit": "<5.4.3"
},
"provide": {
diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPass.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPass.php
index c4b8202e744c5..d856b2c8db79d 100644
--- a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPass.php
+++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterEventListenersAndSubscribersPass.php
@@ -68,7 +68,7 @@ private function addTaggedSubscribers(ContainerBuilder $container)
$connections = isset($tag['connection']) ? array($tag['connection']) : array_keys($this->connections);
foreach ($connections as $con) {
if (!isset($this->connections[$con])) {
- throw new RuntimeException(sprintf('The Doctrine connection "%s" referenced in service "%s" does not exist. Available connections names: %s', $con, $taggedSubscriber, implode(', ', array_keys($this->connections))));
+ throw new RuntimeException(sprintf('The Doctrine connection "%s" referenced in service "%s" does not exist. Available connections names: %s', $con, $id, implode(', ', array_keys($this->connections))));
}
$this->getEventManagerDef($container, $con)->addMethodCall('addEventSubscriber', array(new Reference($id)));
diff --git a/src/Symfony/Bridge/Monolog/Handler/FirePHPHandler.php b/src/Symfony/Bridge/Monolog/Handler/FirePHPHandler.php
index 056496ae1325a..966a7baf83079 100644
--- a/src/Symfony/Bridge/Monolog/Handler/FirePHPHandler.php
+++ b/src/Symfony/Bridge/Monolog/Handler/FirePHPHandler.php
@@ -38,9 +38,10 @@ public function onKernelResponse(FilterResponseEvent $event)
return;
}
- if (!preg_match('{\bFirePHP/\d+\.\d+\b}', $event->getRequest()->headers->get('User-Agent'))
- && !$event->getRequest()->headers->has('X-FirePHP-Version')) {
- $this->sendHeaders = false;
+ $request = $event->getRequest();
+ if (!preg_match('{\bFirePHP/\d+\.\d+\b}', $request->headers->get('User-Agent'))
+ && !$request->headers->has('X-FirePHP-Version')) {
+ self::$sendHeaders = false;
$this->headers = array();
return;
@@ -58,7 +59,7 @@ public function onKernelResponse(FilterResponseEvent $event)
*/
protected function sendHeader($header, $content)
{
- if (!$this->sendHeaders) {
+ if (!self::$sendHeaders) {
return;
}
diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
index 29b1960798b8c..a2528db303fbb 100644
--- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
+++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
@@ -311,6 +311,10 @@ private static function hasColorSupport()
return false;
}
+ if ('Hyper' === getenv('TERM_PROGRAM')) {
+ return true;
+ }
+
if (DIRECTORY_SEPARATOR === '\\') {
return (function_exists('sapi_windows_vt100_support')
&& sapi_windows_vt100_support(STDOUT))
diff --git a/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php
index cabae2517b691..0871c4ce9d70d 100644
--- a/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php
+++ b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php
@@ -54,7 +54,7 @@ public function getProxyFactoryCode(Definition $definition, $id, $factoryCode =
$instantiation = 'return';
if ($definition->isShared()) {
- $instantiation .= sprintf(' $this->%s[\'%s\'] =', $definition->isPublic() && !$definition->isPrivate() ? 'services' : 'privates', $id);
+ $instantiation .= sprintf(' $this->%s[\'%s\'] =', \method_exists(ContainerBuilder::class, 'addClassResource') || ($definition->isPublic() && !$definition->isPrivate()) ? 'services' : 'privates', $id);
}
if (null === $factoryCode) {
diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php
index cd346dfe580eb..e12b25fcb02f8 100644
--- a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php
+++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/PhpDumper/ProxyDumperTest.php
@@ -13,6 +13,7 @@
use PHPUnit\Framework\TestCase;
use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\ProxyDumper;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
/**
@@ -98,7 +99,7 @@ public function getPrivatePublicDefinitions()
array(
(new Definition(__CLASS__))
->setPublic(false),
- 'privates',
+ \method_exists(ContainerBuilder::class, 'addClassResource') ? 'services' : 'privates',
),
array(
(new Definition(__CLASS__))
diff --git a/src/Symfony/Bridge/Twig/Command/DebugCommand.php b/src/Symfony/Bridge/Twig/Command/DebugCommand.php
index 5720096c46534..0d77fed339bcc 100644
--- a/src/Symfony/Bridge/Twig/Command/DebugCommand.php
+++ b/src/Symfony/Bridge/Twig/Command/DebugCommand.php
@@ -108,19 +108,27 @@ protected function execute(InputInterface $input, OutputInterface $output)
}
$rows = array();
+ $firstNamespace = true;
+ $prevHasSeparator = false;
foreach ($this->getLoaderPaths() as $namespace => $paths) {
- if (count($paths) > 1) {
+ if (!$firstNamespace && !$prevHasSeparator && count($paths) > 1) {
$rows[] = array('', '');
}
+ $firstNamespace = false;
foreach ($paths as $path) {
- $rows[] = array($namespace, '- '.$path);
+ $rows[] = array($namespace, $path.DIRECTORY_SEPARATOR);
$namespace = '';
}
if (count($paths) > 1) {
$rows[] = array('', '');
+ $prevHasSeparator = true;
+ } else {
+ $prevHasSeparator = false;
}
}
- array_pop($rows);
+ if ($prevHasSeparator) {
+ array_pop($rows);
+ }
$io->section('Loader Paths');
$io->table(array('Namespace', 'Paths'), $rows);
diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig
index dc4858e2f3871..8f790fdd19450 100644
--- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig
+++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_4_layout.html.twig
@@ -114,6 +114,20 @@
{%- endblock percent_widget %}
+{% block file_widget -%}
+
+ <{{ element|default('div') }} class="custom-file">
+ {%- set type = type|default('file') -%}
+ {{- block('form_widget_simple') -}}
+
+ {%- if attr.placeholder is defined -%}
+ {{- translation_domain is same as(false) ? attr.placeholder : attr.placeholder|trans({}, translation_domain) -}}
+ {%- endif -%}
+
+ {{ element|default('div') }}>
+
+{% endblock %}
+
{% block form_widget_simple -%}
{% if type is not defined or type != 'hidden' %}
{%- set attr = attr|merge({class: (attr.class|default('') ~ (type|default('') == 'file' ? ' custom-file-input' : ' form-control'))|trim}) -%}
@@ -186,10 +200,8 @@
{%- if compound is defined and compound -%}
{%- set element = 'legend' -%}
{%- set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' col-form-label')|trim}) -%}
- {% elseif type is defined and type == 'file' %}
- {%- set label_attr = label_attr|merge({for: id, class: (label_attr.class|default('') ~ ' custom-file-label')|trim}) -%}
{%- else -%}
- {%- set label_attr = label_attr|merge({for: id, class: (label_attr.class|default('') ~ ' form-control-label')|trim}) -%}
+ {%- set label_attr = label_attr|merge({for: id}) -%}
{%- endif -%}
{% if required -%}
{% set label_attr = label_attr|merge({class: (label_attr.class|default('') ~ ' required')|trim}) %}
@@ -269,23 +281,14 @@
{{ element|default('div') }}>
{%- endblock form_row %}
-{% block file_row -%}
-
- <{{ element|default('div') }} class="custom-file">
- {{- form_widget(form) -}}
- {{- form_label(form) -}}
- {{ element|default('div') }}>
-
-{% endblock %}
-
{# Errors #}
{% block form_errors -%}
{%- if errors|length > 0 -%}
{%- for error in errors -%}
-
- {{ 'Error'|trans({}, 'validators') }} {{ error.message }}
+
+ {{ 'Error'|trans({}, 'validators') }} {{ error.message }}
{%- endfor -%}
diff --git a/src/Symfony/Bridge/Twig/Tests/Command/DebugCommandTest.php b/src/Symfony/Bridge/Twig/Tests/Command/DebugCommandTest.php
new file mode 100644
index 0000000000000..77d522f5230aa
--- /dev/null
+++ b/src/Symfony/Bridge/Twig/Tests/Command/DebugCommandTest.php
@@ -0,0 +1,81 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bridge\Twig\Tests\Command;
+
+use PHPUnit\Framework\TestCase;
+use Symfony\Bridge\Twig\Command\DebugCommand;
+use Symfony\Component\Console\Application;
+use Symfony\Component\Console\Tester\CommandTester;
+use Twig\Loader\FilesystemLoader;
+use Twig\Environment;
+
+class DebugCommandTest extends TestCase
+{
+ public function testDebugCommand()
+ {
+ $tester = $this->createCommandTester();
+ $ret = $tester->execute(array(), array('decorated' => false));
+
+ $this->assertEquals(0, $ret, 'Returns 0 in case of success');
+ $this->assertContains('Functions', trim($tester->getDisplay()));
+ }
+
+ public function testLineSeparatorInLoaderPaths()
+ {
+ // these paths aren't realistic,
+ // they're configured to force the line separator
+ $tester = $this->createCommandTester(array(
+ 'Acme' => array('extractor', 'extractor'),
+ '!Acme' => array('extractor', 'extractor'),
+ FilesystemLoader::MAIN_NAMESPACE => array('extractor', 'extractor'),
+ ));
+ $ret = $tester->execute(array(), array('decorated' => false));
+ $ds = DIRECTORY_SEPARATOR;
+ $loaderPaths = <<assertEquals(0, $ret, 'Returns 0 in case of success');
+ $this->assertContains($loaderPaths, trim($tester->getDisplay(true)));
+ }
+
+ private function createCommandTester(array $paths = array())
+ {
+ $filesystemLoader = new FilesystemLoader(array(), dirname(__DIR__).'/Fixtures');
+ foreach ($paths as $namespace => $relDirs) {
+ foreach ($relDirs as $relDir) {
+ $filesystemLoader->addPath($relDir, $namespace);
+ }
+ }
+ $command = new DebugCommand(new Environment($filesystemLoader));
+
+ $application = new Application();
+ $application->add($command);
+ $command = $application->find('debug:twig');
+
+ return new CommandTester($command);
+ }
+}
diff --git a/src/Symfony/Component/Form/Tests/AbstractBootstrap3HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3HorizontalLayoutTest.php
similarity index 99%
rename from src/Symfony/Component/Form/Tests/AbstractBootstrap3HorizontalLayoutTest.php
rename to src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3HorizontalLayoutTest.php
index 04b5b5836c650..97311b38a93f9 100644
--- a/src/Symfony/Component/Form/Tests/AbstractBootstrap3HorizontalLayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3HorizontalLayoutTest.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Form\Tests;
+namespace Symfony\Bridge\Twig\Tests\Extension;
abstract class AbstractBootstrap3HorizontalLayoutTest extends AbstractBootstrap3LayoutTest
{
diff --git a/src/Symfony/Component/Form/Tests/AbstractBootstrap3LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php
similarity index 99%
rename from src/Symfony/Component/Form/Tests/AbstractBootstrap3LayoutTest.php
rename to src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php
index e9cc2c026191a..ff1c221b79ff7 100644
--- a/src/Symfony/Component/Form/Tests/AbstractBootstrap3LayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php
@@ -9,9 +9,10 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Form\Tests;
+namespace Symfony\Bridge\Twig\Tests\Extension;
use Symfony\Component\Form\FormError;
+use Symfony\Component\Form\Tests\AbstractLayoutTest;
abstract class AbstractBootstrap3LayoutTest extends AbstractLayoutTest
{
diff --git a/src/Symfony/Component/Form/Tests/AbstractBootstrap4HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4HorizontalLayoutTest.php
similarity index 94%
rename from src/Symfony/Component/Form/Tests/AbstractBootstrap4HorizontalLayoutTest.php
rename to src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4HorizontalLayoutTest.php
index 016792e0edaf6..9d216e38194f2 100644
--- a/src/Symfony/Component/Form/Tests/AbstractBootstrap4HorizontalLayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4HorizontalLayoutTest.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Form\Tests;
+namespace Symfony\Bridge\Twig\Tests\Extension;
use Symfony\Component\Form\FormError;
@@ -33,7 +33,7 @@ public function testRow()
./label[@for="name"]
[
./span[@class="alert alert-danger d-block"]
- [./span[@class="mb-0 d-block"]
+ [./span[@class="d-block"]
[./span[.="[trans]Error[/trans]"]]
[./span[.="[trans]Error![/trans]"]]
]
@@ -72,7 +72,7 @@ public function testLabelDoesNotRenderFieldAttributes()
$this->assertMatchesXpath($html,
'/label
[@for="name"]
- [@class="col-form-label col-sm-2 form-control-label required"]
+ [@class="col-form-label col-sm-2 required"]
'
);
}
@@ -89,7 +89,7 @@ public function testLabelWithCustomAttributesPassedDirectly()
$this->assertMatchesXpath($html,
'/label
[@for="name"]
- [@class="my&class col-form-label col-sm-2 form-control-label required"]
+ [@class="my&class col-form-label col-sm-2 required"]
'
);
}
@@ -106,7 +106,7 @@ public function testLabelWithCustomTextAndCustomAttributesPassedDirectly()
$this->assertMatchesXpath($html,
'/label
[@for="name"]
- [@class="my&class col-form-label col-sm-2 form-control-label required"]
+ [@class="my&class col-form-label col-sm-2 required"]
[.="[trans]Custom label[/trans]"]
'
);
@@ -126,7 +126,7 @@ public function testLabelWithCustomTextAsOptionAndCustomAttributesPassedDirectly
$this->assertMatchesXpath($html,
'/label
[@for="name"]
- [@class="my&class col-form-label col-sm-2 form-control-label required"]
+ [@class="my&class col-form-label col-sm-2 required"]
[.="[trans]Custom label[/trans]"]
'
);
diff --git a/src/Symfony/Component/Form/Tests/AbstractBootstrap4LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php
similarity index 95%
rename from src/Symfony/Component/Form/Tests/AbstractBootstrap4LayoutTest.php
rename to src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php
index 8cc1df5f52f27..1336405bdd30e 100644
--- a/src/Symfony/Component/Form/Tests/AbstractBootstrap4LayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap4LayoutTest.php
@@ -9,7 +9,7 @@
* file that was distributed with this source code.
*/
-namespace Symfony\Component\Form\Tests;
+namespace Symfony\Bridge\Twig\Tests\Extension;
use Symfony\Component\Form\Extension\Core\Type\ButtonType;
use Symfony\Component\Form\Extension\Core\Type\CheckboxType;
@@ -42,7 +42,7 @@ public function testRow()
./label[@for="name"]
[
./span[@class="alert alert-danger d-block"]
- [./span[@class="mb-0 d-block"]
+ [./span[@class="d-block"]
[./span[.="[trans]Error[/trans]"]]
[./span[.="[trans]Error![/trans]"]]
]
@@ -81,7 +81,7 @@ public function testLabelDoesNotRenderFieldAttributes()
$this->assertMatchesXpath($html,
'/label
[@for="name"]
- [@class="form-control-label required"]
+ [@class="required"]
'
);
}
@@ -98,7 +98,7 @@ public function testLabelWithCustomAttributesPassedDirectly()
$this->assertMatchesXpath($html,
'/label
[@for="name"]
- [@class="my&class form-control-label required"]
+ [@class="my&class required"]
'
);
}
@@ -115,7 +115,7 @@ public function testLabelWithCustomTextAndCustomAttributesPassedDirectly()
$this->assertMatchesXpath($html,
'/label
[@for="name"]
- [@class="my&class form-control-label required"]
+ [@class="my&class required"]
[.="[trans]Custom label[/trans]"]
'
);
@@ -135,7 +135,7 @@ public function testLabelWithCustomTextAsOptionAndCustomAttributesPassedDirectly
$this->assertMatchesXpath($html,
'/label
[@for="name"]
- [@class="my&class form-control-label required"]
+ [@class="my&class required"]
[.="[trans]Custom label[/trans]"]
'
);
@@ -189,11 +189,11 @@ public function testErrors()
'/span
[@class="alert alert-danger d-block"]
[
- ./span[@class="mb-0 d-block"]
+ ./span[@class="d-block"]
[./span[.="[trans]Error[/trans]"]]
[./span[.="[trans]Error 1[/trans]"]]
- /following-sibling::span[@class="mb-0 d-block"]
+ /following-sibling::span[@class="d-block"]
[./span[.="[trans]Error[/trans]"]]
[./span[.="[trans]Error 2[/trans]"]]
]
@@ -940,9 +940,42 @@ public function testFile()
{
$form = $this->factory->createNamed('name', FileType::class);
- $this->assertWidgetMatchesXpath($form->createView(), array('attr' => array('class' => 'my&class form-control-file')),
-'/input
- [@type="file"]
+ $this->assertWidgetMatchesXpath($form->createView(), array('id' => 'n/a', 'attr' => array('class' => 'my&class form-control-file')),
+'/div
+ [@class="form-group"]
+ [
+ ./div
+ [@class="custom-file"]
+ [
+ ./input
+ [@type="file"]
+ [@name="name"]
+ /following-sibling::label
+ [@for="name"]
+ ]
+ ]
+'
+ );
+ }
+
+ public function testFileWithPlaceholder()
+ {
+ $form = $this->factory->createNamed('name', FileType::class);
+
+ $this->assertWidgetMatchesXpath($form->createView(), array('id' => 'n/a', 'attr' => array('class' => 'my&class form-control-file', 'placeholder' => 'Custom Placeholder')),
+'/div
+ [@class="form-group"]
+ [
+ ./div
+ [@class="custom-file"]
+ [
+ ./input
+ [@type="file"]
+ [@name="name"]
+ /following-sibling::label
+ [@for="name" and text() = "[trans]Custom Placeholder[/trans]"]
+ ]
+ ]
'
);
}
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php
index 9c9ea12ab2b97..440bcf2a5e2e5 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3HorizontalLayoutTest.php
@@ -18,7 +18,6 @@
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
use Symfony\Component\Form\FormRenderer;
use Symfony\Component\Form\FormView;
-use Symfony\Component\Form\Tests\AbstractBootstrap3HorizontalLayoutTest;
use Twig\Environment;
class FormExtensionBootstrap3HorizontalLayoutTest extends AbstractBootstrap3HorizontalLayoutTest
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php
index 64559e6c5414c..bd19f5edb7fba 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap3LayoutTest.php
@@ -18,7 +18,6 @@
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
use Symfony\Component\Form\FormRenderer;
use Symfony\Component\Form\FormView;
-use Symfony\Component\Form\Tests\AbstractBootstrap3LayoutTest;
use Twig\Environment;
class FormExtensionBootstrap3LayoutTest extends AbstractBootstrap3LayoutTest
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4HorizontalLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4HorizontalLayoutTest.php
index de9f82beb054b..371101ff161f1 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4HorizontalLayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4HorizontalLayoutTest.php
@@ -18,7 +18,6 @@
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
use Symfony\Component\Form\FormRenderer;
use Symfony\Component\Form\FormView;
-use Symfony\Component\Form\Tests\AbstractBootstrap4HorizontalLayoutTest;
use Twig\Environment;
/**
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4LayoutTest.php
index 19f4b506816a4..540c67c4a1693 100644
--- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4LayoutTest.php
+++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionBootstrap4LayoutTest.php
@@ -18,7 +18,6 @@
use Symfony\Bridge\Twig\Tests\Extension\Fixtures\StubFilesystemLoader;
use Symfony\Component\Form\FormRenderer;
use Symfony\Component\Form\FormView;
-use Symfony\Component\Form\Tests\AbstractBootstrap4LayoutTest;
use Twig\Environment;
/**
diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json
index 14c80b21a33e2..839636282c78a 100644
--- a/src/Symfony/Bridge/Twig/composer.json
+++ b/src/Symfony/Bridge/Twig/composer.json
@@ -23,7 +23,7 @@
"symfony/asset": "~3.4|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/finder": "~3.4|~4.0",
- "symfony/form": "^4.1",
+ "symfony/form": "^4.1.2",
"symfony/http-foundation": "~3.4|~4.0",
"symfony/http-kernel": "~3.4|~4.0",
"symfony/polyfill-intl-icu": "~1.0",
@@ -41,7 +41,7 @@
"symfony/workflow": "~3.4|~4.0"
},
"conflict": {
- "symfony/form": "<4.1",
+ "symfony/form": "<4.1.2",
"symfony/console": "<3.4"
},
"suggest": {
diff --git a/src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php b/src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php
index ab6163e3ef4d7..5130071bcdec1 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Kernel/MicroKernelTrait.php
@@ -28,7 +28,7 @@ trait MicroKernelTrait
* Add or import routes into your application.
*
* $routes->import('config/routing.yml');
- * $routes->add('/admin', 'AppBundle:Admin:dashboard', 'admin_dashboard');
+ * $routes->add('/admin', 'App\Controller\AdminController::dashboard', 'admin_dashboard');
*
* @param RouteCollectionBuilder $routes
*/
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
index 2ae8411c22909..b1570333eb2eb 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php
@@ -268,7 +268,7 @@ public function testWorkflows()
$this->assertInstanceOf(Reference::class, $markingStoreRef);
$this->assertEquals('workflow_service', (string) $markingStoreRef);
- $this->assertTrue($container->hasDefinition('workflow.registry', 'Workflow registry is registered as a service'));
+ $this->assertTrue($container->hasDefinition('workflow.registry'), 'Workflow registry is registered as a service');
$registryDefinition = $container->getDefinition('workflow.registry');
$this->assertGreaterThan(0, count($registryDefinition->getMethodCalls()));
}
@@ -313,8 +313,8 @@ public function testWorkflowMultipleTransitionsWithSameName()
{
$container = $this->createContainerFromFile('workflow_with_multiple_transitions_with_same_name');
- $this->assertTrue($container->hasDefinition('workflow.article', 'Workflow is registered as a service'));
- $this->assertTrue($container->hasDefinition('workflow.article.definition', 'Workflow definition is registered as a service'));
+ $this->assertTrue($container->hasDefinition('workflow.article'), 'Workflow is registered as a service');
+ $this->assertTrue($container->hasDefinition('workflow.article.definition'), 'Workflow definition is registered as a service');
$workflowDefinition = $container->getDefinition('workflow.article.definition');
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SessionController.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SessionController.php
index a1d91e7929d65..0c82d8cc73eb2 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SessionController.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SessionController.php
@@ -43,6 +43,14 @@ public function welcomeAction(Request $request, $name = null)
return new Response(sprintf('Welcome back %s, nice to meet you.', $name));
}
+ public function cacheableAction()
+ {
+ $response = new Response('all good');
+ $response->setSharedMaxAge(100);
+
+ return $response;
+ }
+
public function logoutAction(Request $request)
{
$request->getSession()->invalidate();
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml
index 0730b723282cc..3cbdf944af3bb 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Resources/config/routing.yml
@@ -2,6 +2,10 @@ session_welcome:
path: /session
defaults: { _controller: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\SessionController::welcomeAction }
+session_cacheable:
+ path: /cacheable
+ defaults: { _controller: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\SessionController::cacheableAction }
+
session_welcome_name:
path: /session/{name}
defaults: { _controller: Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller\SessionController::welcomeAction }
diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SessionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SessionTest.php
index 166d8a33919df..2e1634220c3a5 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SessionTest.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SessionTest.php
@@ -126,6 +126,22 @@ public function testTwoClients($config, $insulate)
$this->assertContains('Welcome back client2, nice to meet you.', $crawler2->text());
}
+ /**
+ * @dataProvider getConfigs
+ */
+ public function testCorrectCacheControlHeadersForCacheableAction($config, $insulate)
+ {
+ $client = $this->createClient(array('test_case' => 'Session', 'root_config' => $config));
+ if ($insulate) {
+ $client->insulate();
+ }
+
+ $client->request('GET', '/cacheable');
+
+ $response = $client->getResponse();
+ $this->assertSame('public, s-maxage=100', $response->headers->get('cache-control'));
+ }
+
public function getConfigs()
{
return array(
diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json
index 0c2a3dec226d8..de0fe10f91224 100644
--- a/src/Symfony/Bundle/FrameworkBundle/composer.json
+++ b/src/Symfony/Bundle/FrameworkBundle/composer.json
@@ -71,6 +71,7 @@
"symfony/serializer": "<4.1",
"symfony/stopwatch": "<3.4",
"symfony/translation": "<3.4",
+ "symfony/twig-bridge": "<4.1.1",
"symfony/validator": "<4.1",
"symfony/workflow": "<4.1"
},
diff --git a/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php b/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php
index 84227cf47e72e..0b36054fd0679 100644
--- a/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php
+++ b/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php
@@ -70,7 +70,7 @@ protected function configure()
security:
encoders:
Symfony\Component\Security\Core\User\User: plaintext
- AppBundle\Entity\User: bcrypt
+ App\Entity\User: bcrypt
If you execute the command non-interactively, the first available configured
@@ -82,16 +82,16 @@ protected function configure()
Pass the full user class path as the second argument to encode passwords for
your own entities:
- php %command.full_name% --no-interaction [password] AppBundle\Entity\User
+ php %command.full_name% --no-interaction [password] App\Entity\User
Executing the command interactively allows you to generate a random salt for
encoding the password:
- php %command.full_name% [password] AppBundle\Entity\User
+ php %command.full_name% [password] App\Entity\User
In case your encoder doesn't require a salt, add the empty-salt option:
- php %command.full_name% --empty-salt [password] AppBundle\Entity\User
+ php %command.full_name% --empty-salt [password] App\Entity\User
EOF
)
diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php
index a2feb22c8e170..b0d7353834690 100644
--- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php
+++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php
@@ -363,8 +363,8 @@ private function addEncodersSection(ArrayNodeDefinition $rootNode)
->children()
->arrayNode('encoders')
->example(array(
- 'AppBundle\Entity\User1' => 'bcrypt',
- 'AppBundle\Entity\User2' => array(
+ 'App\Entity\User1' => 'bcrypt',
+ 'App\Entity\User2' => array(
'algorithm' => 'bcrypt',
'cost' => 13,
),
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig
index 2a2b3793fd845..09056e177093b 100644
--- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig
+++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig
@@ -70,6 +70,7 @@
.sf-toolbarreset svg,
.sf-toolbarreset img {
height: 20px;
+ width: 20px;
display: inline-block;
}
@@ -160,11 +161,11 @@
margin-bottom: 0;
}
-.sf-toolbar-block .sf-toolbar-info-piece a {
+div.sf-toolbar .sf-toolbar-block .sf-toolbar-info-piece a {
color: #99CDD8;
text-decoration: underline;
}
-.sf-toolbar-block .sf-toolbar-info-piece a:hover {
+div.sf-toolbar .sf-toolbar-block a:hover {
text-decoration: none;
}
@@ -292,6 +293,7 @@
border-width: 0;
position: relative;
top: 8px;
+ vertical-align: baseline;
}
.sf-toolbar-block .sf-toolbar-icon img + span,
diff --git a/src/Symfony/Component/Cache/Tests/Adapter/MaxIdLengthAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/MaxIdLengthAdapterTest.php
index cf2384c5f37e6..266e1f850c953 100644
--- a/src/Symfony/Component/Cache/Tests/Adapter/MaxIdLengthAdapterTest.php
+++ b/src/Symfony/Component/Cache/Tests/Adapter/MaxIdLengthAdapterTest.php
@@ -34,6 +34,34 @@ public function testLongKey()
$cache->hasItem(str_repeat('-', 39));
}
+ public function testLongKeyVersioning()
+ {
+ $cache = $this->getMockBuilder(MaxIdLengthAdapter::class)
+ ->setConstructorArgs(array(str_repeat('-', 26)))
+ ->getMock();
+
+ $reflectionClass = new \ReflectionClass(AbstractAdapter::class);
+
+ $reflectionMethod = $reflectionClass->getMethod('getId');
+ $reflectionMethod->setAccessible(true);
+
+ // No versioning enabled
+ $this->assertEquals('--------------------------:------------', $reflectionMethod->invokeArgs($cache, array(str_repeat('-', 12))));
+ $this->assertLessThanOrEqual(50, strlen($reflectionMethod->invokeArgs($cache, array(str_repeat('-', 12)))));
+ $this->assertLessThanOrEqual(50, strlen($reflectionMethod->invokeArgs($cache, array(str_repeat('-', 23)))));
+ $this->assertLessThanOrEqual(50, strlen($reflectionMethod->invokeArgs($cache, array(str_repeat('-', 40)))));
+
+ $reflectionProperty = $reflectionClass->getProperty('versioningIsEnabled');
+ $reflectionProperty->setAccessible(true);
+ $reflectionProperty->setValue($cache, true);
+
+ // Versioning enabled
+ $this->assertEquals('--------------------------:1:------------', $reflectionMethod->invokeArgs($cache, array(str_repeat('-', 12))));
+ $this->assertLessThanOrEqual(50, strlen($reflectionMethod->invokeArgs($cache, array(str_repeat('-', 12)))));
+ $this->assertLessThanOrEqual(50, strlen($reflectionMethod->invokeArgs($cache, array(str_repeat('-', 23)))));
+ $this->assertLessThanOrEqual(50, strlen($reflectionMethod->invokeArgs($cache, array(str_repeat('-', 40)))));
+ }
+
/**
* @expectedException \Symfony\Component\Cache\Exception\InvalidArgumentException
* @expectedExceptionMessage Namespace must be 26 chars max, 40 given ("----------------------------------------")
diff --git a/src/Symfony/Component/Cache/Traits/AbstractTrait.php b/src/Symfony/Component/Cache/Traits/AbstractTrait.php
index 7953ae6e8beee..ec60fe79c4a6b 100644
--- a/src/Symfony/Component/Cache/Traits/AbstractTrait.php
+++ b/src/Symfony/Component/Cache/Traits/AbstractTrait.php
@@ -255,7 +255,7 @@ private function getId($key)
return $this->namespace.$this->namespaceVersion.$key;
}
if (\strlen($id = $this->namespace.$this->namespaceVersion.$key) > $this->maxIdLength) {
- $id = $this->namespace.$this->namespaceVersion.substr_replace(base64_encode(hash('sha256', $key, true)), ':', -22);
+ $id = $this->namespace.$this->namespaceVersion.substr_replace(base64_encode(hash('sha256', $key, true)), ':', -(\strlen($this->namespaceVersion) + 22));
}
return $id;
diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php
index b64d9af361e55..62c3a834f6a2d 100644
--- a/src/Symfony/Component/Console/Command/Command.php
+++ b/src/Symfony/Component/Console/Command/Command.php
@@ -220,7 +220,7 @@ public function run(InputInterface $input, OutputInterface $output)
if (function_exists('cli_set_process_title')) {
if (!@cli_set_process_title($this->processTitle)) {
if ('Darwin' === PHP_OS) {
- $output->writeln('Running "cli_get_process_title" as an unprivileged user is not supported on MacOS. ');
+ $output->writeln('Running "cli_set_process_title" as an unprivileged user is not supported on MacOS. ', OutputInterface::VERBOSITY_VERY_VERBOSE);
} else {
cli_set_process_title($this->processTitle);
}
diff --git a/src/Symfony/Component/Console/Helper/TableStyle.php b/src/Symfony/Component/Console/Helper/TableStyle.php
index a0d0b5b770737..3339debe5dd02 100644
--- a/src/Symfony/Component/Console/Helper/TableStyle.php
+++ b/src/Symfony/Component/Console/Helper/TableStyle.php
@@ -110,7 +110,7 @@ public function setHorizontalBorderChars(string $outside, string $inside = null)
*/
public function setHorizontalBorderChar($horizontalBorderChar)
{
- @trigger_error(sprintf('Method %s() is deprecated since Symfony 4.1, use setHorizontalBorderChars() instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use setHorizontalBorderChars() instead.', __METHOD__), E_USER_DEPRECATED);
return $this->setHorizontalBorderChars($horizontalBorderChar, $horizontalBorderChar);
}
@@ -124,7 +124,7 @@ public function setHorizontalBorderChar($horizontalBorderChar)
*/
public function getHorizontalBorderChar()
{
- @trigger_error(sprintf('Method %s() is deprecated since Symfony 4.1, use getBorderChars() instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use getBorderChars() instead.', __METHOD__), E_USER_DEPRECATED);
return $this->horizontalOutsideBorderChar;
}
@@ -166,7 +166,7 @@ public function setVerticalBorderChars(string $outside, string $inside = null):
*/
public function setVerticalBorderChar($verticalBorderChar)
{
- @trigger_error(sprintf('Method %s() is deprecated since Symfony 4.1, use setVerticalBorderChars() instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use setVerticalBorderChars() instead.', __METHOD__), E_USER_DEPRECATED);
return $this->setVerticalBorderChars($verticalBorderChar, $verticalBorderChar);
}
@@ -180,7 +180,7 @@ public function setVerticalBorderChar($verticalBorderChar)
*/
public function getVerticalBorderChar()
{
- @trigger_error(sprintf('Method %s() is deprecated since Symfony 4.1, use getBorderChars() instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use getBorderChars() instead.', __METHOD__), E_USER_DEPRECATED);
return $this->verticalOutsideBorderChar;
}
@@ -268,7 +268,7 @@ public function setDefaultCrossingChar(string $char): self
*/
public function setCrossingChar($crossingChar)
{
- @trigger_error(sprintf('Method %s() is deprecated since Symfony 4.1. Use setDefaultCrossingChar() instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1. Use setDefaultCrossingChar() instead.', __METHOD__), E_USER_DEPRECATED);
return $this->setDefaultCrossingChar($crossingChar);
}
diff --git a/src/Symfony/Component/Console/Input/ArgvInput.php b/src/Symfony/Component/Console/Input/ArgvInput.php
index edeabdbf257bc..14276ba31711b 100644
--- a/src/Symfony/Component/Console/Input/ArgvInput.php
+++ b/src/Symfony/Component/Console/Input/ArgvInput.php
@@ -301,7 +301,7 @@ public function getParameterOption($values, $default = false, $onlyParams = fals
while (0 < count($tokens)) {
$token = array_shift($tokens);
if ($onlyParams && '--' === $token) {
- return false;
+ return $default;
}
foreach ($values as $value) {
diff --git a/src/Symfony/Component/Console/Input/ArrayInput.php b/src/Symfony/Component/Console/Input/ArrayInput.php
index 4d9797ba1af0c..595a8a0e8cbc1 100644
--- a/src/Symfony/Component/Console/Input/ArrayInput.php
+++ b/src/Symfony/Component/Console/Input/ArrayInput.php
@@ -81,7 +81,7 @@ public function getParameterOption($values, $default = false, $onlyParams = fals
foreach ($this->parameters as $k => $v) {
if ($onlyParams && ('--' === $k || (is_int($k) && '--' === $v))) {
- return false;
+ return $default;
}
if (is_int($k)) {
diff --git a/src/Symfony/Component/Console/Output/OutputInterface.php b/src/Symfony/Component/Console/Output/OutputInterface.php
index 5742e553a9310..0dfd12b98749c 100644
--- a/src/Symfony/Component/Console/Output/OutputInterface.php
+++ b/src/Symfony/Component/Console/Output/OutputInterface.php
@@ -33,7 +33,7 @@ interface OutputInterface
/**
* Writes a message to the output.
*
- * @param string|iterable $messages The message as an iterable of lines or a single string
+ * @param string|iterable $messages The message as an iterable of strings or a single string
* @param bool $newline Whether to add a newline
* @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
*/
@@ -42,7 +42,7 @@ public function write($messages, $newline = false, $options = 0);
/**
* Writes a message to the output and adds a newline at the end.
*
- * @param string|iterable $messages The message as an iterable of lines of a single string
+ * @param string|iterable $messages The message as an iterable of strings or a single string
* @param int $options A bitmask of options (one of the OUTPUT or VERBOSITY constants), 0 is considered the same as self::OUTPUT_NORMAL | self::VERBOSITY_NORMAL
*/
public function writeln($messages, $options = 0);
diff --git a/src/Symfony/Component/Console/Output/StreamOutput.php b/src/Symfony/Component/Console/Output/StreamOutput.php
index 476b2fa0dc05c..d012a0a5c6ebd 100644
--- a/src/Symfony/Component/Console/Output/StreamOutput.php
+++ b/src/Symfony/Component/Console/Output/StreamOutput.php
@@ -93,6 +93,10 @@ protected function doWrite($message, $newline)
*/
protected function hasColorSupport()
{
+ if ('Hyper' === getenv('TERM_PROGRAM')) {
+ return true;
+ }
+
if (DIRECTORY_SEPARATOR === '\\') {
return (function_exists('sapi_windows_vt100_support')
&& @sapi_windows_vt100_support($this->stream))
diff --git a/src/Symfony/Component/Console/Style/SymfonyStyle.php b/src/Symfony/Component/Console/Style/SymfonyStyle.php
index 08f86225c1b3c..26018e2338648 100644
--- a/src/Symfony/Component/Console/Style/SymfonyStyle.php
+++ b/src/Symfony/Component/Console/Style/SymfonyStyle.php
@@ -269,7 +269,7 @@ public function createProgressBar($max = 0)
{
$progressBar = parent::createProgressBar($max);
- if ('\\' !== DIRECTORY_SEPARATOR) {
+ if ('\\' !== DIRECTORY_SEPARATOR || 'Hyper' === getenv('TERM_PROGRAM')) {
$progressBar->setEmptyBarCharacter('░'); // light shade character \u2591
$progressBar->setProgressCharacter('');
$progressBar->setBarCharacter('▓'); // dark shade character \u2593
diff --git a/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php b/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php
index 61d1723e0842e..4cd7ab478f3a4 100644
--- a/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php
+++ b/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php
@@ -395,25 +395,26 @@ public function testToString()
/**
* @dataProvider provideGetParameterOptionValues
*/
- public function testGetParameterOptionEqualSign($argv, $key, $onlyParams, $expected)
+ public function testGetParameterOptionEqualSign($argv, $key, $default, $onlyParams, $expected)
{
$input = new ArgvInput($argv);
- $this->assertEquals($expected, $input->getParameterOption($key, false, $onlyParams), '->getParameterOption() returns the expected value');
+ $this->assertEquals($expected, $input->getParameterOption($key, $default, $onlyParams), '->getParameterOption() returns the expected value');
}
public function provideGetParameterOptionValues()
{
return array(
- array(array('app/console', 'foo:bar', '-e', 'dev'), '-e', false, 'dev'),
- array(array('app/console', 'foo:bar', '--env=dev'), '--env', false, 'dev'),
- array(array('app/console', 'foo:bar', '-e', 'dev'), array('-e', '--env'), false, 'dev'),
- array(array('app/console', 'foo:bar', '--env=dev'), array('-e', '--env'), false, 'dev'),
- array(array('app/console', 'foo:bar', '--env=dev', '--en=1'), array('--en'), false, '1'),
- array(array('app/console', 'foo:bar', '--env=dev', '', '--en=1'), array('--en'), false, '1'),
- array(array('app/console', 'foo:bar', '--env', 'val'), '--env', false, 'val'),
- array(array('app/console', 'foo:bar', '--env', 'val', '--dummy'), '--env', false, 'val'),
- array(array('app/console', 'foo:bar', '--', '--env=dev'), '--env', false, 'dev'),
- array(array('app/console', 'foo:bar', '--', '--env=dev'), '--env', true, false),
+ array(array('app/console', 'foo:bar'), '-e', 'default', false, 'default'),
+ array(array('app/console', 'foo:bar', '-e', 'dev'), '-e', 'default', false, 'dev'),
+ array(array('app/console', 'foo:bar', '--env=dev'), '--env', 'default', false, 'dev'),
+ array(array('app/console', 'foo:bar', '-e', 'dev'), array('-e', '--env'), 'default', false, 'dev'),
+ array(array('app/console', 'foo:bar', '--env=dev'), array('-e', '--env'), 'default', false, 'dev'),
+ array(array('app/console', 'foo:bar', '--env=dev', '--en=1'), array('--en'), 'default', false, '1'),
+ array(array('app/console', 'foo:bar', '--env=dev', '', '--en=1'), array('--en'), 'default', false, '1'),
+ array(array('app/console', 'foo:bar', '--env', 'val'), '--env', 'default', false, 'val'),
+ array(array('app/console', 'foo:bar', '--env', 'val', '--dummy'), '--env', 'default', false, 'val'),
+ array(array('app/console', 'foo:bar', '--', '--env=dev'), '--env', 'default', false, 'dev'),
+ array(array('app/console', 'foo:bar', '--', '--env=dev'), '--env', 'default', true, 'default'),
);
}
diff --git a/src/Symfony/Component/Console/Tests/Input/ArrayInputTest.php b/src/Symfony/Component/Console/Tests/Input/ArrayInputTest.php
index 6b443e0b2abae..34b67ac7f5235 100644
--- a/src/Symfony/Component/Console/Tests/Input/ArrayInputTest.php
+++ b/src/Symfony/Component/Console/Tests/Input/ArrayInputTest.php
@@ -47,14 +47,14 @@ public function testGetParameterOption()
{
$input = new ArrayInput(array('name' => 'Fabien', '--foo' => 'bar'));
$this->assertEquals('bar', $input->getParameterOption('--foo'), '->getParameterOption() returns the option of specified name');
- $this->assertFalse($input->getParameterOption('--bar'), '->getParameterOption() returns the default if an option is not present in the passed parameters');
+ $this->assertEquals('default', $input->getParameterOption('--bar', 'default'), '->getParameterOption() returns the default value if an option is not present in the passed parameters');
$input = new ArrayInput(array('Fabien', '--foo' => 'bar'));
$this->assertEquals('bar', $input->getParameterOption('--foo'), '->getParameterOption() returns the option of specified name');
$input = new ArrayInput(array('--foo', '--', '--bar' => 'woop'));
$this->assertEquals('woop', $input->getParameterOption('--bar'), '->getParameterOption() returns the correct value if an option is present in the passed parameters');
- $this->assertFalse($input->getParameterOption('--bar', false, true), '->getParameterOption() returns false if an option is present in the passed parameters after an end of options signal');
+ $this->assertEquals('default', $input->getParameterOption('--bar', 'default', true), '->getParameterOption() returns the default value if an option is present in the passed parameters after an end of options signal');
}
public function testParseArguments()
diff --git a/src/Symfony/Component/Debug/Exception/FlattenException.php b/src/Symfony/Component/Debug/Exception/FlattenException.php
index f70085160ba3a..2afffa21b6e82 100644
--- a/src/Symfony/Component/Debug/Exception/FlattenException.php
+++ b/src/Symfony/Component/Debug/Exception/FlattenException.php
@@ -186,7 +186,7 @@ public function getTrace()
*/
public function setTraceFromException(\Exception $exception)
{
- @trigger_error(sprintf('"%s" is deprecated since Symfony 4.1, use "setTraceFromThrowable()" instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use "setTraceFromThrowable()" instead.', __METHOD__), E_USER_DEPRECATED);
$this->setTraceFromThrowable($exception);
}
diff --git a/src/Symfony/Component/Debug/ExceptionHandler.php b/src/Symfony/Component/Debug/ExceptionHandler.php
index a67637ea6e655..0e3ec00717958 100644
--- a/src/Symfony/Component/Debug/ExceptionHandler.php
+++ b/src/Symfony/Component/Debug/ExceptionHandler.php
@@ -208,48 +208,54 @@ public function getContent(FlattenException $exception)
$title = 'Whoops, looks like something went wrong.';
}
+ if (!$this->debug) {
+ return <<
+ $title
+
+EOF;
+ }
+
$content = '';
- if ($this->debug) {
- try {
- $count = count($exception->getAllPrevious());
- $total = $count + 1;
- foreach ($exception->toArray() as $position => $e) {
- $ind = $count - $position + 1;
- $class = $this->formatClass($e['class']);
- $message = nl2br($this->escapeHtml($e['message']));
- $content .= sprintf(<<<'EOF'
-
-
-
-
- (%d/%d)
- %s
-
- %s
-
-
+ try {
+ $count = count($exception->getAllPrevious());
+ $total = $count + 1;
+ foreach ($exception->toArray() as $position => $e) {
+ $ind = $count - $position + 1;
+ $class = $this->formatClass($e['class']);
+ $message = nl2br($this->escapeHtml($e['message']));
+ $content .= sprintf(<<<'EOF'
+
+
+
+
+ (%d/%d)
+ %s
+
+ %s
+
+
EOF
- , $ind, $total, $class, $message);
- foreach ($e['trace'] as $trace) {
- $content .= '';
- if ($trace['function']) {
- $content .= sprintf('at %s %s %s (%s )', $this->formatClass($trace['class']), $trace['type'], $trace['function'], $this->formatArgs($trace['args']));
- }
- if (isset($trace['file']) && isset($trace['line'])) {
- $content .= $this->formatPath($trace['file'], $trace['line']);
- }
- $content .= " \n";
+ , $ind, $total, $class, $message);
+ foreach ($e['trace'] as $trace) {
+ $content .= '';
+ if ($trace['function']) {
+ $content .= sprintf('at %s %s %s (%s )', $this->formatClass($trace['class']), $trace['type'], $trace['function'], $this->formatArgs($trace['args']));
}
-
- $content .= " \n
\n
\n";
- }
- } catch (\Exception $e) {
- // something nasty happened and we cannot throw an exception anymore
- if ($this->debug) {
- $title = sprintf('Exception thrown when handling an exception (%s: %s)', get_class($e), $this->escapeHtml($e->getMessage()));
- } else {
- $title = 'Whoops, looks like something went wrong.';
+ if (isset($trace['file']) && isset($trace['line'])) {
+ $content .= $this->formatPath($trace['file'], $trace['line']);
+ }
+ $content .= "\n";
}
+
+ $content .= " \n
\n
\n";
+ }
+ } catch (\Exception $e) {
+ // something nasty happened and we cannot throw an exception anymore
+ if ($this->debug) {
+ $title = sprintf('Exception thrown when handling an exception (%s: %s)', get_class($e), $this->escapeHtml($e->getMessage()));
+ } else {
+ $title = 'Whoops, looks like something went wrong.';
}
}
@@ -278,6 +284,14 @@ public function getContent(FlattenException $exception)
*/
public function getStylesheet(FlattenException $exception)
{
+ if (!$this->debug) {
+ return <<<'EOF'
+ body { background-color: #fff; color: #222; font: 16px/1.5 -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; margin: 0; }
+ .container { margin: 30px; max-width: 600px; }
+ h1 { color: #dc3545; font-size: 24px; }
+EOF;
+ }
+
return <<<'EOF'
body { background-color: #F9F9F9; color: #222; font: 14px/1.4 Helvetica, Arial, sans-serif; margin: 0; padding-bottom: 45px; }
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveInstanceofConditionalsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveInstanceofConditionalsPass.php
index 500de64bc2f0f..63309b3a17e77 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveInstanceofConditionalsPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveInstanceofConditionalsPass.php
@@ -123,10 +123,11 @@ private function processDefinition(ContainerBuilder $container, $id, Definition
}
$definition->setMethodCalls(array_merge($instanceofCalls, $definition->getMethodCalls()));
+ $definition->setBindings($bindings);
// reset fields with "merge" behavior
$abstract
- ->setBindings($bindings)
+ ->setBindings(array())
->setArguments(array())
->setMethodCalls(array())
->setDecoratedService(null)
diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ValidateEnvPlaceholdersPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ValidateEnvPlaceholdersPass.php
index 402aca6378b63..06b655328b43d 100644
--- a/src/Symfony/Component/DependencyInjection/Compiler/ValidateEnvPlaceholdersPass.php
+++ b/src/Symfony/Component/DependencyInjection/Compiler/ValidateEnvPlaceholdersPass.php
@@ -65,7 +65,7 @@ public function process(ContainerBuilder $container)
$processor = new Processor();
foreach ($extensions as $name => $extension) {
- if (!$extension instanceof ConfigurationExtensionInterface || !$config = $container->getExtensionConfig($name)) {
+ if (!$extension instanceof ConfigurationExtensionInterface || !$config = array_filter($container->getExtensionConfig($name))) {
// this extension has no semantic configuration or was not called
continue;
}
diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php
index 1c2c239869131..2a8dd0c4f1246 100644
--- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php
+++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php
@@ -606,10 +606,10 @@ private function doGet($id, $invalidBehavior = ContainerInterface::EXCEPTION_ON_
* the parameters passed to the container constructor to have precedence
* over the loaded ones.
*
- * $container = new ContainerBuilder(array('foo' => 'bar'));
+ * $container = new ContainerBuilder(new ParameterBag(array('foo' => 'bar')));
* $loader = new LoaderXXX($container);
* $loader->load('resource_name');
- * $container->register('foo', new stdClass());
+ * $container->register('foo', 'stdClass');
*
* In the above example, even if the loaded resource defines a foo
* parameter, the value will still be 'bar' as defined in the ContainerBuilder
diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
index d790aff7d66d2..660f1f4defad6 100644
--- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
+++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php
@@ -1662,8 +1662,10 @@ private function getServiceCall(string $id, Reference $reference = null): string
return '$this';
}
- if ($this->container->hasDefinition($id) && ($definition = $this->container->getDefinition($id)) && !$definition->isSynthetic()) {
- if (null !== $reference && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $reference->getInvalidBehavior()) {
+ if ($this->container->hasDefinition($id) && $definition = $this->container->getDefinition($id)) {
+ if ($definition->isSynthetic()) {
+ $code = sprintf('$this->get(\'%s\'%s)', $id, null !== $reference ? ', '.$reference->getInvalidBehavior() : '');
+ } elseif (null !== $reference && ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE === $reference->getInvalidBehavior()) {
$code = 'null';
if (!$definition->isShared()) {
return $code;
diff --git a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php
index 8fa341bcadac4..73f29a6145e6d 100644
--- a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php
+++ b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php
@@ -94,7 +94,7 @@ private function addService(string $id, Definition $definition): string
}
if ($definition->isDeprecated()) {
- $code .= sprintf(" deprecated: %s\n", $definition->getDeprecationMessage('%service_id%'));
+ $code .= sprintf(" deprecated: %s\n", $this->dumper->dump($definition->getDeprecationMessage('%service_id%')));
}
if ($definition->isAutowired()) {
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveInstanceofConditionalsPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveInstanceofConditionalsPassTest.php
index 38164fc10589d..cc96c5a517849 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveInstanceofConditionalsPassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ResolveInstanceofConditionalsPassTest.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\DependencyInjection\Tests\Compiler;
use PHPUnit\Framework\TestCase;
+use Symfony\Component\DependencyInjection\Argument\BoundArgument;
use Symfony\Component\DependencyInjection\ChildDefinition;
use Symfony\Component\DependencyInjection\Compiler\ResolveInstanceofConditionalsPass;
use Symfony\Component\DependencyInjection\Compiler\ResolveChildDefinitionsPass;
@@ -268,4 +269,18 @@ public function testMergeReset()
$this->assertEmpty($abstract->getTags());
$this->assertTrue($abstract->isAbstract());
}
+
+ public function testBindings()
+ {
+ $container = new ContainerBuilder();
+ $def = $container->register('foo', self::class)->setBindings(array('$toto' => 123));
+ $def->setInstanceofConditionals(array(parent::class => new ChildDefinition('')));
+
+ (new ResolveInstanceofConditionalsPass())->process($container);
+
+ $bindings = $container->getDefinition('foo')->getBindings();
+ $this->assertSame(array('$toto'), array_keys($bindings));
+ $this->assertInstanceOf(BoundArgument::class, $bindings['$toto']);
+ $this->assertSame(123, $bindings['$toto']->getValues()[0]);
+ }
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php
index b5841f343a4e8..cbec6bf778a49 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ValidateEnvPlaceholdersPassTest.php
@@ -234,6 +234,18 @@ public function testConfigurationWithoutRootNode(): void
$this->addToAssertionCount(1);
}
+ public function testEmptyConfigFromMoreThanOneSource()
+ {
+ $container = new ContainerBuilder();
+ $container->registerExtension(new EnvExtension(new ConfigurationWithArrayNodeRequiringOneElement()));
+ $container->loadFromExtension('env_extension', array());
+ $container->loadFromExtension('env_extension', array());
+
+ $this->doProcess($container);
+
+ $this->addToAssertionCount(1);
+ }
+
public function testDiscardedEnvInConfig(): void
{
$container = new ContainerBuilder();
@@ -313,6 +325,24 @@ public function getConfigTreeBuilder()
}
}
+class ConfigurationWithArrayNodeRequiringOneElement implements ConfigurationInterface
+{
+ public function getConfigTreeBuilder()
+ {
+ $treeBuilder = new TreeBuilder();
+ $treeBuilder->root('env_extension')
+ ->children()
+ ->arrayNode('nodes')
+ ->isRequired()
+ ->requiresAtLeastOneElement()
+ ->scalarPrototype()->end()
+ ->end()
+ ->end();
+
+ return $treeBuilder;
+ }
+}
+
class EnvExtension extends Extension
{
private $configuration;
@@ -335,6 +365,10 @@ public function getConfiguration(array $config, ContainerBuilder $container)
public function load(array $configs, ContainerBuilder $container)
{
+ if (!array_filter($configs)) {
+ return;
+ }
+
try {
$this->config = $this->processConfiguration($this->getConfiguration($configs, $container), $configs);
} catch (TreeWithoutRootNodeException $e) {
diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php
index a8402569905a3..7fde6ec969408 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php
@@ -1399,6 +1399,21 @@ public function testArgumentsHaveHigherPriorityThanBindings()
$this->assertSame('via-bindings', $container->get('foo')->class2->identifier);
}
+ public function testUninitializedSyntheticReference()
+ {
+ $container = new ContainerBuilder();
+ $container->register('foo', 'stdClass')->setPublic(true)->setSynthetic(true);
+ $container->register('bar', 'stdClass')->setPublic(true)->setShared(false)
+ ->setProperty('foo', new Reference('foo', ContainerInterface::IGNORE_ON_UNINITIALIZED_REFERENCE));
+
+ $container->compile();
+
+ $this->assertEquals((object) array('foo' => null), $container->get('bar'));
+
+ $container->set('foo', (object) array(123));
+ $this->assertEquals((object) array('foo' => (object) array(123)), $container->get('bar'));
+ }
+
public function testIdCanBeAnObjectAsLongAsItCanBeCastToString()
{
$id = new Reference('another_service');
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
index 52e7ff18fab44..29cbf1f6a410a 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php
@@ -953,6 +953,29 @@ public function testDumpHandlesObjectClassNames()
$this->assertInstanceOf('stdClass', $container->get('bar'));
}
+ public function testUninitializedSyntheticReference()
+ {
+ $container = new ContainerBuilder();
+ $container->register('foo', 'stdClass')->setPublic(true)->setSynthetic(true);
+ $container->register('bar', 'stdClass')->setPublic(true)->setShared(false)
+ ->setProperty('foo', new Reference('foo', ContainerBuilder::IGNORE_ON_UNINITIALIZED_REFERENCE));
+
+ $container->compile();
+
+ $dumper = new PhpDumper($container);
+ eval('?>'.$dumper->dump(array(
+ 'class' => 'Symfony_DI_PhpDumper_Test_UninitializedSyntheticReference',
+ 'inline_class_loader_parameter' => 'inline_requires',
+ )));
+
+ $container = new \Symfony_DI_PhpDumper_Test_UninitializedSyntheticReference();
+
+ $this->assertEquals((object) array('foo' => null), $container->get('bar'));
+
+ $container->set('foo', (object) array(123));
+ $this->assertEquals((object) array('foo' => (object) array(123)), $container->get('bar'));
+ }
+
/**
* This test checks the trigger of a deprecation note and should not be removed in major releases.
*
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/prototype.expected.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/prototype.expected.yml
index 5394535caf1d8..ebfe087d779cf 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/prototype.expected.yml
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/config/prototype.expected.yml
@@ -10,7 +10,7 @@ services:
tags:
- { name: foo }
- { name: baz }
- deprecated: %service_id%
+ deprecated: '%service_id%'
arguments: [1]
factory: f
Symfony\Component\DependencyInjection\Tests\Fixtures\Prototype\Sub\Bar:
@@ -19,7 +19,7 @@ services:
tags:
- { name: foo }
- { name: baz }
- deprecated: %service_id%
+ deprecated: '%service_id%'
lazy: true
arguments: [1]
factory: f
diff --git a/src/Symfony/Component/DependencyInjection/TypedReference.php b/src/Symfony/Component/DependencyInjection/TypedReference.php
index 9d488ddbb478c..2bd25ab46d299 100644
--- a/src/Symfony/Component/DependencyInjection/TypedReference.php
+++ b/src/Symfony/Component/DependencyInjection/TypedReference.php
@@ -29,7 +29,7 @@ class TypedReference extends Reference
public function __construct(string $id, string $type, $invalidBehavior = ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE)
{
if (\is_string($invalidBehavior) || 3 < \func_num_args()) {
- @trigger_error(sprintf('The $requiringClass argument of "%s" is deprecated since Symfony 4.1.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The $requiringClass argument of "%s()" is deprecated since Symfony 4.1.', __METHOD__), E_USER_DEPRECATED);
$this->requiringClass = $invalidBehavior;
$invalidBehavior = 3 < \func_num_args() ? \func_get_arg(3) : ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE;
@@ -48,7 +48,7 @@ public function getType()
*/
public function getRequiringClass()
{
- @trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.1.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1.', __METHOD__), E_USER_DEPRECATED);
return $this->requiringClass ?? '';
}
@@ -58,7 +58,7 @@ public function getRequiringClass()
*/
public function canBeAutoregistered()
{
- @trigger_error(sprintf('The "%s" method is deprecated since Symfony 4.1.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1.', __METHOD__), E_USER_DEPRECATED);
return $this->requiringClass && (false !== $i = strpos($this->type, '\\')) && 0 === strncasecmp($this->type, $this->requiringClass, 1 + $i);
}
diff --git a/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php b/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php
index 4d3aebfba531f..b24bbd879b5ad 100644
--- a/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php
+++ b/src/Symfony/Component/DomCrawler/Field/ChoiceFormField.php
@@ -75,7 +75,7 @@ public function isDisabled()
/**
* Sets the value of the field.
*
- * @param string $value The value of the field
+ * @param string|array $value The value of the field
*/
public function select($value)
{
diff --git a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php
index 3b6e7cc393144..8d851623fb67a 100644
--- a/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php
+++ b/src/Symfony/Component/EventDispatcher/Debug/TraceableEventDispatcher.php
@@ -217,6 +217,7 @@ public function getOrphanedEvents(): array
public function reset()
{
$this->called = array();
+ $this->orphanedEvents = array();
}
/**
diff --git a/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php
index 2521f741ea1fc..ab3b33e3779a4 100644
--- a/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php
+++ b/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php
@@ -271,6 +271,17 @@ public function testListenerCanRemoveItselfWhenExecuted()
$this->assertCount(1, $eventDispatcher->getListeners('foo'), 'expected listener1 to be removed');
}
+
+ public function testClearOrphanedEvents()
+ {
+ $tdispatcher = new TraceableEventDispatcher(new EventDispatcher(), new Stopwatch());
+ $tdispatcher->dispatch('foo');
+ $events = $tdispatcher->getOrphanedEvents();
+ $this->assertCount(1, $events);
+ $tdispatcher->reset();
+ $events = $tdispatcher->getOrphanedEvents();
+ $this->assertCount(0, $events);
+ }
}
class EventSubscriber implements EventSubscriberInterface
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php
index e206936dd32e8..e7c41e0cec46f 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/CountryType.php
@@ -77,7 +77,7 @@ public function getBlockPrefix()
*/
public function loadChoiceList($value = null)
{
- @trigger_error(sprintf('Method "%s" is deprecated since Symfony 4.1, use "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use the "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
if (null !== $this->choiceList) {
return $this->choiceList;
@@ -93,7 +93,7 @@ public function loadChoiceList($value = null)
*/
public function loadChoicesForValues(array $values, $value = null)
{
- @trigger_error(sprintf('Method "%s" is deprecated since Symfony 4.1, use "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use the "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
// Optimize
$values = array_filter($values);
@@ -116,7 +116,7 @@ public function loadChoicesForValues(array $values, $value = null)
*/
public function loadValuesForChoices(array $choices, $value = null)
{
- @trigger_error(sprintf('Method "%s" is deprecated since Symfony 4.1, use "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use the "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
// Optimize
$choices = array_filter($choices);
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php b/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php
index 79d874ca400b6..c6759ea3da912 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/CurrencyType.php
@@ -77,7 +77,7 @@ public function getBlockPrefix()
*/
public function loadChoiceList($value = null)
{
- @trigger_error(sprintf('Method "%s" is deprecated since Symfony 4.1, use "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use the "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
if (null !== $this->choiceList) {
return $this->choiceList;
@@ -93,7 +93,7 @@ public function loadChoiceList($value = null)
*/
public function loadChoicesForValues(array $values, $value = null)
{
- @trigger_error(sprintf('Method "%s" is deprecated since Symfony 4.1, use "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use the "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
// Optimize
$values = array_filter($values);
@@ -116,7 +116,7 @@ public function loadChoicesForValues(array $values, $value = null)
*/
public function loadValuesForChoices(array $choices, $value = null)
{
- @trigger_error(sprintf('Method "%s" is deprecated since Symfony 4.1, use "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use the "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
// Optimize
$choices = array_filter($choices);
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php b/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php
index 6d35c2392140f..c9bc9e6042c35 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/LanguageType.php
@@ -77,7 +77,7 @@ public function getBlockPrefix()
*/
public function loadChoiceList($value = null)
{
- @trigger_error(sprintf('Method "%s" is deprecated since Symfony 4.1, use "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use the "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
if (null !== $this->choiceList) {
return $this->choiceList;
@@ -93,7 +93,7 @@ public function loadChoiceList($value = null)
*/
public function loadChoicesForValues(array $values, $value = null)
{
- @trigger_error(sprintf('Method "%s" is deprecated since Symfony 4.1, use "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use the "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
// Optimize
$values = array_filter($values);
@@ -116,7 +116,7 @@ public function loadChoicesForValues(array $values, $value = null)
*/
public function loadValuesForChoices(array $choices, $value = null)
{
- @trigger_error(sprintf('Method "%s" is deprecated since Symfony 4.1, use "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use the "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
// Optimize
$choices = array_filter($choices);
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php
index 4c0c467729ff1..c0de1c933bd17 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/LocaleType.php
@@ -77,7 +77,7 @@ public function getBlockPrefix()
*/
public function loadChoiceList($value = null)
{
- @trigger_error(sprintf('Method "%s" is deprecated since Symfony 4.1, use "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use the "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
if (null !== $this->choiceList) {
return $this->choiceList;
@@ -93,7 +93,7 @@ public function loadChoiceList($value = null)
*/
public function loadChoicesForValues(array $values, $value = null)
{
- @trigger_error(sprintf('Method "%s" is deprecated since Symfony 4.1, use "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use the "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
// Optimize
$values = array_filter($values);
@@ -116,7 +116,7 @@ public function loadChoicesForValues(array $values, $value = null)
*/
public function loadValuesForChoices(array $choices, $value = null)
{
- @trigger_error(sprintf('Method "%s" is deprecated since Symfony 4.1, use "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, use the "choice_loader" option instead.', __METHOD__), E_USER_DEPRECATED);
// Optimize
$choices = array_filter($choices);
diff --git a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php
index 3fac07591db98..a3b7765e12475 100644
--- a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php
+++ b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php
@@ -19,6 +19,7 @@
use Symfony\Component\Validator\ConstraintViolationInterface;
use Symfony\Component\VarDumper\Caster\Caster;
use Symfony\Component\VarDumper\Caster\ClassStub;
+use Symfony\Component\VarDumper\Caster\StubCaster;
use Symfony\Component\VarDumper\Cloner\Stub;
/**
@@ -261,6 +262,7 @@ protected function getCasters()
Caster::PREFIX_VIRTUAL.'type_class' => new ClassStub(get_class($f->getConfig()->getType()->getInnerType())),
);
},
+ FormView::class => array(StubCaster::class, 'cutInternals'),
ConstraintViolationInterface::class => function (ConstraintViolationInterface $v, array $a) {
return array(
Caster::PREFIX_VIRTUAL.'root' => $v->getRoot(),
diff --git a/src/Symfony/Component/Form/FormConfigBuilder.php b/src/Symfony/Component/Form/FormConfigBuilder.php
index 7ac98b1cf2e0b..e3660e19adbc0 100644
--- a/src/Symfony/Component/Form/FormConfigBuilder.php
+++ b/src/Symfony/Component/Form/FormConfigBuilder.php
@@ -138,7 +138,7 @@ class FormConfigBuilder implements FormConfigBuilderInterface
private $data;
/**
- * @var string
+ * @var string|null
*/
private $dataClass;
@@ -181,7 +181,7 @@ class FormConfigBuilder implements FormConfigBuilderInterface
* Creates an empty form configuration.
*
* @param string|int $name The form name
- * @param string $dataClass The class of the form's data
+ * @param string|null $dataClass The class of the form's data
* @param EventDispatcherInterface $dispatcher The event dispatcher
* @param array $options The form options
*
diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt
index c622057cdbdfd..391c3e694d974 100644
--- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt
+++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/default_option_with_normalizer.txt
@@ -15,9 +15,9 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (choice_translation_domain
---------------- --------------------%s
Allowed values - %s
---------------- --------------------%s
- Normalizer Closure { %s
+ Normalizer Closure%s{%w
parameters: 2 %s
- file: "%s%eExtension%eCore%eType%eChoiceType.php"
+ file: "%s%eExtension%eCore%eType%eChoiceType.php"%w
line: "%s to %s" %s
} %s
---------------- --------------------%s
diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt
index 231d1319bbeff..846d6f384684c 100644
--- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt
+++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/overridden_option_with_default_closures.txt
@@ -8,14 +8,14 @@ Symfony\Component\Form\Tests\Console\Descriptor\FooType (empty_data)
Default Value: null %s
%s
Closure(s): [ %s
- Closure { %s
+ Closure%s{%w
parameters: 1 %s
- file: "%s%eExtension%eCore%eType%eFormType.php"
+ file: "%s%eExtension%eCore%eType%eFormType.php"%w
line: "%s to %s" %s
}, %s
- Closure { %s
+ Closure%s{%w
parameters: 2 %s
- file: "%s%eTests%eConsole%eDescriptor%eAbstractDescriptorTest.php"
+ file: "%s%eTests%eConsole%eDescriptor%eAbstractDescriptorTest.php"%w
line: "%s to %s" %s
} %s
] %s
diff --git a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt
index da3e6c82d8b1a..8cc88a550ab70 100644
--- a/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt
+++ b/src/Symfony/Component/Form/Tests/Fixtures/Descriptor/required_option_with_allowed_values.txt
@@ -16,9 +16,9 @@ Symfony\Component\Form\Tests\Console\Descriptor\FooType (foo)
"baz" %s
] %s
---------------- --------------------%s
- Normalizer Closure { %s
+ Normalizer Closure%s{%w
parameters: 2 %s
- file: "%s%eTests%eConsole%eDescriptor%eAbstractDescriptorTest.php"
+ file: "%s%eTests%eConsole%eDescriptor%eAbstractDescriptorTest.php"%w
line: "%s to %s" %s
} %s
---------------- --------------------%s
diff --git a/src/Symfony/Component/HttpFoundation/File/UploadedFile.php b/src/Symfony/Component/HttpFoundation/File/UploadedFile.php
index 252f46ad8e59b..594decb067281 100644
--- a/src/Symfony/Component/HttpFoundation/File/UploadedFile.php
+++ b/src/Symfony/Component/HttpFoundation/File/UploadedFile.php
@@ -158,7 +158,7 @@ public function guessClientExtension()
*/
public function getClientSize()
{
- @trigger_error(sprintf('"%s" is deprecated since Symfony 4.1. Use getSize() instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1. Use getSize() instead.', __METHOD__), E_USER_DEPRECATED);
return $this->getSize();
}
diff --git a/src/Symfony/Component/HttpFoundation/HeaderBag.php b/src/Symfony/Component/HttpFoundation/HeaderBag.php
index 7026732fe7721..d11887fb61b2f 100644
--- a/src/Symfony/Component/HttpFoundation/HeaderBag.php
+++ b/src/Symfony/Component/HttpFoundation/HeaderBag.php
@@ -101,11 +101,11 @@ public function add(array $headers)
/**
* Returns a header value by name.
*
- * @param string $key The header name
- * @param string|string[] $default The default value
- * @param bool $first Whether to return the first value or all header values
+ * @param string $key The header name
+ * @param string|string[]|null $default The default value
+ * @param bool $first Whether to return the first value or all header values
*
- * @return string|string[] The first header value or default value if $first is true, an array of values otherwise
+ * @return string|string[]|null The first header value or default value if $first is true, an array of values otherwise
*/
public function get($key, $default = null, $first = true)
{
diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php
index 7cc9d91ab40a5..b7433173c7d9b 100644
--- a/src/Symfony/Component/HttpFoundation/Response.php
+++ b/src/Symfony/Component/HttpFoundation/Response.php
@@ -64,7 +64,12 @@ class Response
const HTTP_UNPROCESSABLE_ENTITY = 422; // RFC4918
const HTTP_LOCKED = 423; // RFC4918
const HTTP_FAILED_DEPENDENCY = 424; // RFC4918
+
+ /**
+ * @deprecated
+ */
const HTTP_RESERVED_FOR_WEBDAV_ADVANCED_COLLECTIONS_EXPIRED_PROPOSAL = 425; // RFC2817
+ const HTTP_TOO_EARLY = 425; // RFC-ietf-httpbis-replay-04
const HTTP_UPGRADE_REQUIRED = 426; // RFC2817
const HTTP_PRECONDITION_REQUIRED = 428; // RFC6585
const HTTP_TOO_MANY_REQUESTS = 429; // RFC6585
@@ -169,7 +174,7 @@ class Response
422 => 'Unprocessable Entity', // RFC4918
423 => 'Locked', // RFC4918
424 => 'Failed Dependency', // RFC4918
- 425 => 'Reserved for WebDAV advanced collections expired proposal', // RFC2817
+ 425 => 'Too Early', // RFC-ietf-httpbis-replay-04
426 => 'Upgrade Required', // RFC2817
428 => 'Precondition Required', // RFC6585
429 => 'Too Many Requests', // RFC6585
@@ -324,12 +329,17 @@ public function sendHeaders()
}
// headers
- foreach ($this->headers->allPreserveCase() as $name => $values) {
+ foreach ($this->headers->allPreserveCaseWithoutCookies() as $name => $values) {
foreach ($values as $value) {
header($name.': '.$value, false, $this->statusCode);
}
}
+ // cookies
+ foreach ($this->headers->getCookies() as $cookie) {
+ header('Set-Cookie: '.$cookie->getName().strstr($cookie, '='), false, $this->statusCode);
+ }
+
// status
header(sprintf('HTTP/%s %s %s', $this->version, $this->statusCode, $this->statusText), true, $this->statusCode);
diff --git a/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php b/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php
index 19b57762a69fd..dd7a7fad822f7 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php
@@ -124,7 +124,13 @@ protected function &resolveAttributePath($name, $writeContext = false)
foreach ($parts as $part) {
if (null !== $array && !array_key_exists($part, $array)) {
- $array[$part] = $writeContext ? array() : null;
+ if (!$writeContext) {
+ $null = null;
+
+ return $null;
+ }
+
+ $array[$part] = array();
}
$array = &$array[$part];
diff --git a/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBagInterface.php b/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBagInterface.php
index 80e97f17cdff3..f53c9dae6c0aa 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBagInterface.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBagInterface.php
@@ -24,7 +24,7 @@ interface FlashBagInterface extends SessionBagInterface
* Adds a flash message for type.
*
* @param string $type
- * @param string $message
+ * @param mixed $message
*/
public function add($type, $message);
diff --git a/src/Symfony/Component/HttpFoundation/Session/Session.php b/src/Symfony/Component/HttpFoundation/Session/Session.php
index f0379c1697b82..c0978d552f197 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Session.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Session.php
@@ -54,8 +54,6 @@ public function __construct(SessionStorageInterface $storage = null, AttributeBa
*/
public function start()
{
- ++$this->usageIndex;
-
return $this->storage->start();
}
@@ -160,7 +158,9 @@ public function getUsageIndex()
*/
public function isEmpty()
{
- ++$this->usageIndex;
+ if ($this->isStarted()) {
+ ++$this->usageIndex;
+ }
foreach ($this->data as &$data) {
if (!empty($data)) {
return false;
@@ -185,8 +185,6 @@ public function invalidate($lifetime = null)
*/
public function migrate($destroy = false, $lifetime = null)
{
- ++$this->usageIndex;
-
return $this->storage->regenerate($destroy, $lifetime);
}
@@ -195,8 +193,6 @@ public function migrate($destroy = false, $lifetime = null)
*/
public function save()
{
- ++$this->usageIndex;
-
$this->storage->save();
}
diff --git a/src/Symfony/Component/HttpFoundation/Session/SessionBagProxy.php b/src/Symfony/Component/HttpFoundation/Session/SessionBagProxy.php
index 88005ee092e2a..3504bdfe7b4a6 100644
--- a/src/Symfony/Component/HttpFoundation/Session/SessionBagProxy.php
+++ b/src/Symfony/Component/HttpFoundation/Session/SessionBagProxy.php
@@ -44,6 +44,9 @@ public function getBag()
*/
public function isEmpty()
{
+ if (!isset($this->data[$this->bag->getStorageKey()])) {
+ return true;
+ }
++$this->usageIndex;
return empty($this->data[$this->bag->getStorageKey()]);
@@ -81,8 +84,6 @@ public function getStorageKey()
*/
public function clear()
{
- ++$this->usageIndex;
-
return $this->bag->clear();
}
}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/RedisSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/RedisSessionHandler.php
index 59242ef387f81..bad59332a9c62 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/RedisSessionHandler.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/RedisSessionHandler.php
@@ -12,6 +12,7 @@
namespace Symfony\Component\HttpFoundation\Session\Storage\Handler;
use Predis\Response\ErrorInterface;
+use Symfony\Component\Cache\Traits\RedisProxy;
/**
* Redis based session storage handler based on the Redis class
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php
index 12e32df36afd5..bfe13f05ed2e5 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php
@@ -407,8 +407,6 @@ public function setSaveHandler($saveHandler = null)
}
if ($this->saveHandler instanceof SessionHandlerProxy) {
- session_set_save_handler($this->saveHandler->getHandler(), false);
- } elseif ($this->saveHandler instanceof \SessionHandlerInterface) {
session_set_save_handler($this->saveHandler, false);
}
}
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php
index 53c1209a1c07d..b11cc397a0973 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php
@@ -14,7 +14,7 @@
/**
* @author Drak
*/
-class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterface
+class SessionHandlerProxy extends AbstractProxy implements \SessionHandlerInterface, \SessionUpdateTimestampHandlerInterface
{
protected $handler;
@@ -82,4 +82,20 @@ public function gc($maxlifetime)
{
return (bool) $this->handler->gc($maxlifetime);
}
+
+ /**
+ * {@inheritdoc}
+ */
+ public function validateId($sessionId)
+ {
+ return !$this->handler instanceof \SessionUpdateTimestampHandlerInterface || $this->handler->validateId($sessionId);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function updateTimestamp($sessionId, $data)
+ {
+ return $this->handler instanceof \SessionUpdateTimestampHandlerInterface ? $this->handler->updateTimestamp($sessionId, $data) : $this->write($sessionId, $data);
+ }
}
diff --git a/src/Symfony/Component/HttpFoundation/StreamedResponse.php b/src/Symfony/Component/HttpFoundation/StreamedResponse.php
index a7c2150252eb6..2519f874cceca 100644
--- a/src/Symfony/Component/HttpFoundation/StreamedResponse.php
+++ b/src/Symfony/Component/HttpFoundation/StreamedResponse.php
@@ -141,4 +141,16 @@ public function getContent()
{
return false;
}
+
+ /**
+ * {@inheritdoc}
+ *
+ * @return $this
+ */
+ public function setNotModified()
+ {
+ $this->setCallback(function () {});
+
+ return parent::setNotModified();
+ }
}
diff --git a/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/cookie_urlencode.expected b/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/cookie_urlencode.expected
index 4e9c4c075f5ed..14e44a398af66 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/cookie_urlencode.expected
+++ b/src/Symfony/Component/HttpFoundation/Tests/Fixtures/response-functional/cookie_urlencode.expected
@@ -4,7 +4,7 @@ Array
[0] => Content-Type: text/plain; charset=utf-8
[1] => Cache-Control: no-cache, private
[2] => Date: Sat, 12 Nov 1955 20:04:00 GMT
- [3] => Set-Cookie: %3F%2A%28%29%3A%40%26%2B%24%2F%25%23%5B%5D=%3F%2A%28%29%3A%40%26%2B%24%2F%25%23%5B%5D; path=/
+ [3] => Set-Cookie: ?*():@&+$/%#[]=%3F%2A%28%29%3A%40%26%2B%24%2F%25%23%5B%5D; path=/
[4] => Set-Cookie: ?*():@&+$/%#[]=%3F%2A%28%29%3A%40%26%2B%24%2F%25%23%5B%5D; path=/
)
shutdown
diff --git a/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php
index b4af82ddf68de..a51b954fa0bd0 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/ResponseTest.php
@@ -126,7 +126,7 @@ public function testMustRevalidateWithProxyRevalidateCacheControlHeader()
public function testSetNotModified()
{
- $response = new Response();
+ $response = new Response('foo');
$modified = $response->setNotModified();
$this->assertObjectHasAttribute('headers', $modified);
$this->assertObjectHasAttribute('content', $modified);
@@ -135,6 +135,11 @@ public function testSetNotModified()
$this->assertObjectHasAttribute('statusText', $modified);
$this->assertObjectHasAttribute('charset', $modified);
$this->assertEquals(304, $modified->getStatusCode());
+
+ ob_start();
+ $modified->sendContent();
+ $string = ob_get_clean();
+ $this->assertEmpty($string);
}
public function testIsSuccessful()
diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Attribute/NamespacedAttributeBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Attribute/NamespacedAttributeBagTest.php
index f074ce1b26261..ec4cd5ad1a146 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/Session/Attribute/NamespacedAttributeBagTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Attribute/NamespacedAttributeBagTest.php
@@ -82,6 +82,17 @@ public function testHas($key, $value, $exists)
$this->assertEquals($exists, $this->bag->has($key));
}
+ /**
+ * @dataProvider attributesProvider
+ */
+ public function testHasNoSideEffect($key, $value, $expected)
+ {
+ $expected = json_encode($this->bag->all());
+ $this->bag->has($key);
+
+ $this->assertEquals($expected, json_encode($this->bag->all()));
+ }
+
/**
* @dataProvider attributesProvider
*/
@@ -96,6 +107,17 @@ public function testGetDefaults()
$this->assertEquals('default', $this->bag->get('user2.login', 'default'));
}
+ /**
+ * @dataProvider attributesProvider
+ */
+ public function testGetNoSideEffect($key, $value, $expected)
+ {
+ $expected = json_encode($this->bag->all());
+ $this->bag->get($key);
+
+ $this->assertEquals($expected, json_encode($this->bag->all()));
+ }
+
/**
* @dataProvider attributesProvider
*/
diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Flash/FlashBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Flash/FlashBagTest.php
index c4e75b1b18b40..905a1f7517306 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/Session/Flash/FlashBagTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Flash/FlashBagTest.php
@@ -74,6 +74,18 @@ public function testPeek()
$this->assertEquals(array('A previous flash message'), $this->bag->peek('notice'));
}
+ public function testAdd()
+ {
+ $tab = array('bar' => 'baz');
+ $this->bag->add('string_message', 'lorem');
+ $this->bag->add('object_message', new \stdClass());
+ $this->bag->add('array_message', $tab);
+
+ $this->assertEquals(array('lorem'), $this->bag->get('string_message'));
+ $this->assertEquals(array(new \stdClass()), $this->bag->get('object_message'));
+ $this->assertEquals(array($tab), $this->bag->get('array_message'));
+ }
+
public function testGet()
{
$this->assertEquals(array(), $this->bag->get('non_existing'));
@@ -112,6 +124,19 @@ public function testKeys()
$this->assertEquals(array('notice'), $this->bag->keys());
}
+ public function testSetAll()
+ {
+ $this->bag->add('one_flash', 'Foo');
+ $this->bag->add('another_flash', 'Bar');
+ $this->assertTrue($this->bag->has('one_flash'));
+ $this->assertTrue($this->bag->has('another_flash'));
+ $this->bag->setAll(array('unique_flash' => 'FooBar'));
+ $this->assertFalse($this->bag->has('one_flash'));
+ $this->assertFalse($this->bag->has('another_flash'));
+ $this->assertSame(array('unique_flash' => 'FooBar'), $this->bag->all());
+ $this->assertSame(array(), $this->bag->all());
+ }
+
public function testPeekAll()
{
$this->bag->set('notice', 'Foo');
diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php
index 682825356a724..0b48250e01010 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Proxy/SessionHandlerProxyTest.php
@@ -121,4 +121,37 @@ public function testGc()
$this->proxy->gc(86400);
}
+
+ /**
+ * @requires PHPUnit 5.1
+ */
+ public function testValidateId()
+ {
+ $mock = $this->getMockBuilder(array('SessionHandlerInterface', 'SessionUpdateTimestampHandlerInterface'))->getMock();
+ $mock->expects($this->once())
+ ->method('validateId');
+
+ $proxy = new SessionHandlerProxy($mock);
+ $proxy->validateId('id');
+
+ $this->assertTrue($this->proxy->validateId('id'));
+ }
+
+ /**
+ * @requires PHPUnit 5.1
+ */
+ public function testUpdateTimestamp()
+ {
+ $mock = $this->getMockBuilder(array('SessionHandlerInterface', 'SessionUpdateTimestampHandlerInterface'))->getMock();
+ $mock->expects($this->once())
+ ->method('updateTimestamp');
+
+ $proxy = new SessionHandlerProxy($mock);
+ $proxy->updateTimestamp('id', 'data');
+
+ $this->mock->expects($this->once())
+ ->method('write');
+
+ $this->proxy->updateTimestamp('id', 'data');
+ }
}
diff --git a/src/Symfony/Component/HttpFoundation/Tests/StreamedResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/StreamedResponseTest.php
index c2ded996fab4f..699222e37916e 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/StreamedResponseTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/StreamedResponseTest.php
@@ -123,4 +123,22 @@ public function testReturnThis()
$this->assertInstanceOf('Symfony\Component\HttpFoundation\StreamedResponse', $response->sendHeaders());
$this->assertInstanceOf('Symfony\Component\HttpFoundation\StreamedResponse', $response->sendHeaders());
}
+
+ public function testSetNotModified()
+ {
+ $response = new StreamedResponse(function () { echo 'foo'; });
+ $modified = $response->setNotModified();
+ $this->assertObjectHasAttribute('headers', $modified);
+ $this->assertObjectHasAttribute('content', $modified);
+ $this->assertObjectHasAttribute('version', $modified);
+ $this->assertObjectHasAttribute('statusCode', $modified);
+ $this->assertObjectHasAttribute('statusText', $modified);
+ $this->assertObjectHasAttribute('charset', $modified);
+ $this->assertEquals(304, $modified->getStatusCode());
+
+ ob_start();
+ $modified->sendContent();
+ $string = ob_get_clean();
+ $this->assertEmpty($string);
+ }
}
diff --git a/src/Symfony/Component/HttpKernel/Event/GetResponseEvent.php b/src/Symfony/Component/HttpKernel/Event/GetResponseEvent.php
index f7745ea3dc160..c25a0f1cf1a1a 100644
--- a/src/Symfony/Component/HttpKernel/Event/GetResponseEvent.php
+++ b/src/Symfony/Component/HttpKernel/Event/GetResponseEvent.php
@@ -29,7 +29,7 @@ class GetResponseEvent extends KernelEvent
/**
* Returns the response object.
*
- * @return Response
+ * @return Response|null
*/
public function getResponse()
{
diff --git a/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php b/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php
index 2636c65ff6951..bc02fe0a830f7 100644
--- a/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php
+++ b/src/Symfony/Component/HttpKernel/EventListener/AbstractSessionListener.php
@@ -62,7 +62,7 @@ public function onKernelRequest(GetResponseEvent $event)
}
$session = $session ?? ($this->container && $this->container->has('initialized_session') ? $this->container->get('initialized_session') : null);
- $this->sessionUsageStack[] = $session instanceof Session ? $session->getUsageIndex() : null;
+ $this->sessionUsageStack[] = $session instanceof Session ? $session->getUsageIndex() : 0;
}
public function onKernelResponse(FilterResponseEvent $event)
diff --git a/src/Symfony/Component/HttpKernel/EventListener/AbstractTestSessionListener.php b/src/Symfony/Component/HttpKernel/EventListener/AbstractTestSessionListener.php
index f07647f8a67dc..51e92e2ce3773 100644
--- a/src/Symfony/Component/HttpKernel/EventListener/AbstractTestSessionListener.php
+++ b/src/Symfony/Component/HttpKernel/EventListener/AbstractTestSessionListener.php
@@ -73,6 +73,13 @@ public function onKernelResponse(FilterResponseEvent $event)
if ($session instanceof Session ? !$session->isEmpty() || (null !== $this->sessionId && $session->getId() !== $this->sessionId) : $wasStarted) {
$params = session_get_cookie_params();
+
+ foreach ($event->getResponse()->headers->getCookies() as $cookie) {
+ if ($session->getName() === $cookie->getName() && $params['path'] === $cookie->getPath() && $params['domain'] == $cookie->getDomain()) {
+ return;
+ }
+ }
+
$event->getResponse()->headers->setCookie(new Cookie($session->getName(), $session->getId(), 0 === $params['lifetime'] ? 0 : time() + $params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly']));
$this->sessionId = $session->getId();
}
diff --git a/src/Symfony/Component/HttpKernel/Fragment/HIncludeFragmentRenderer.php b/src/Symfony/Component/HttpKernel/Fragment/HIncludeFragmentRenderer.php
index e737a141e93b7..d65d373ee30c7 100644
--- a/src/Symfony/Component/HttpKernel/Fragment/HIncludeFragmentRenderer.php
+++ b/src/Symfony/Component/HttpKernel/Fragment/HIncludeFragmentRenderer.php
@@ -126,7 +126,7 @@ private function templateExists(string $template): bool
if ($this->templating instanceof EngineInterface) {
try {
return $this->templating->exists($template);
- } catch (\InvalidArgumentException $e) {
+ } catch (\Exception $e) {
return false;
}
}
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index 1d5d2227579d8..f536bd0b30399 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -63,11 +63,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl
private $requestStackSize = 0;
private $resetServices = false;
- const VERSION = '4.1.1';
- const VERSION_ID = 40101;
+ const VERSION = '4.1.2';
+ const VERSION_ID = 40102;
const MAJOR_VERSION = 4;
const MINOR_VERSION = 1;
- const RELEASE_VERSION = 1;
+ const RELEASE_VERSION = 2;
const EXTRA_VERSION = '';
const END_OF_MAINTENANCE = '01/2019';
diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/TestSessionListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/TestSessionListenerTest.php
index 84ca04a680d61..2182a1d3d60c0 100644
--- a/src/Symfony/Component/HttpKernel/Tests/EventListener/TestSessionListenerTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/TestSessionListenerTest.php
@@ -106,6 +106,36 @@ public function testEmptySessionWithNewSessionIdDoesSendCookie()
$this->assertNotEmpty($response->headers->getCookies());
}
+ /**
+ * @dataProvider anotherCookieProvider
+ */
+ public function testSessionWithNewSessionIdAndNewCookieDoesNotSendAnotherCookie($existing, array $expected)
+ {
+ $this->sessionHasBeenStarted();
+ $this->sessionIsEmpty();
+ $this->fixSessionId('456');
+
+ $kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
+ $request = Request::create('/', 'GET', array(), array('MOCKSESSID' => '123'));
+ $event = new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST);
+ $this->listener->onKernelRequest($event);
+
+ $response = new Response('', 200, array('Set-Cookie' => $existing));
+
+ $response = $this->filterResponse(new Request(), HttpKernelInterface::MASTER_REQUEST, $response);
+
+ $this->assertSame($expected, $response->headers->get('Set-Cookie', null, false));
+ }
+
+ public function anotherCookieProvider()
+ {
+ return array(
+ 'same' => array('MOCKSESSID=789; path=/', array('MOCKSESSID=789; path=/')),
+ 'different domain' => array('MOCKSESSID=789; path=/; domain=example.com', array('MOCKSESSID=789; path=/; domain=example.com', 'MOCKSESSID=456; path=/')),
+ 'different path' => array('MOCKSESSID=789; path=/foo', array('MOCKSESSID=789; path=/foo', 'MOCKSESSID=456; path=/')),
+ );
+ }
+
public function testUnstartedSessionIsNotSave()
{
$this->sessionHasNotBeenStarted();
@@ -133,10 +163,10 @@ public function testDoesNotThrowIfRequestDoesNotHaveASession()
$this->assertTrue(true);
}
- private function filterResponse(Request $request, $type = HttpKernelInterface::MASTER_REQUEST)
+ private function filterResponse(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, Response $response = null)
{
$request->setSession($this->session);
- $response = new Response();
+ $response = $response ?: new Response();
$kernel = $this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock();
$event = new FilterResponseEvent($kernel, $request, $type, $response);
diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php
index 1be052e5e62fd..7171c71bc3af4 100644
--- a/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/HIncludeFragmentRendererTest.php
@@ -86,4 +86,17 @@ public function testRenderWithDefaultText()
$strategy = new HIncludeFragmentRenderer($engine);
$this->assertEquals('default ', $strategy->render('/foo', Request::create('/'), array('default' => 'default'))->getContent());
}
+
+ public function testRenderWithEngineAndDefaultText()
+ {
+ $engine = $this->getMockBuilder('Symfony\\Component\\Templating\\EngineInterface')->getMock();
+ $engine->expects($this->once())
+ ->method('exists')
+ ->with('loading...')
+ ->will($this->throwException(new \RuntimeException()));
+
+ // only default
+ $strategy = new HIncludeFragmentRenderer($engine);
+ $this->assertEquals('loading... ', $strategy->render('/foo', Request::create('/'), array('default' => 'loading...'))->getContent());
+ }
}
diff --git a/src/Symfony/Component/Lock/Store/FlockStore.php b/src/Symfony/Component/Lock/Store/FlockStore.php
index 1ef9ec8472ec7..5b2732d30ac6f 100644
--- a/src/Symfony/Component/Lock/Store/FlockStore.php
+++ b/src/Symfony/Component/Lock/Store/FlockStore.php
@@ -81,7 +81,7 @@ private function lock(Key $key, $blocking)
set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; });
if (!$handle = fopen($fileName, 'r+') ?: fopen($fileName, 'r')) {
if ($handle = fopen($fileName, 'x')) {
- chmod($fileName, 0444);
+ chmod($fileName, 0666);
} elseif (!$handle = fopen($fileName, 'r+') ?: fopen($fileName, 'r')) {
usleep(100); // Give some time for chmod() to complete
$handle = fopen($fileName, 'r+') ?: fopen($fileName, 'r');
diff --git a/src/Symfony/Component/Lock/Tests/Store/SemaphoreStoreTest.php b/src/Symfony/Component/Lock/Tests/Store/SemaphoreStoreTest.php
index 97c93c786c971..6c265b98bdb42 100644
--- a/src/Symfony/Component/Lock/Tests/Store/SemaphoreStoreTest.php
+++ b/src/Symfony/Component/Lock/Tests/Store/SemaphoreStoreTest.php
@@ -46,13 +46,22 @@ public function testResourceRemoval()
private function getOpenedSemaphores()
{
- $lines = explode(PHP_EOL, trim(`ipcs -su`));
+ if ('Darwin' === PHP_OS) {
+ $lines = explode(PHP_EOL, trim(`ipcs -s`));
+ if (-1 === $start = array_search('Semaphores:', $lines)) {
+ throw new \Exception('Failed to extract list of opened semaphores. Expected a Semaphore list, got '.implode(PHP_EOL, $lines));
+ }
+
+ return \count(\array_slice($lines, ++$start));
+ }
+
+ $lines = explode(PHP_EOL, trim(`LC_ALL=C ipcs -su`));
if ('------ Semaphore Status --------' !== $lines[0]) {
- throw new \Exception('Failed to extract list of opend semaphores. Expect a Semaphore status, got '.implode(PHP_EOL, $lines));
+ throw new \Exception('Failed to extract list of opened semaphores. Expected a Semaphore status, got '.implode(PHP_EOL, $lines));
}
list($key, $value) = explode(' = ', $lines[1]);
if ('used arrays' !== $key) {
- throw new \Exception('Failed to extract list of opend semaphores. Expect a used arrays key, got '.implode(PHP_EOL, $lines));
+ throw new \Exception('Failed to extract list of opened semaphores. Expected a "used arrays" key, got '.implode(PHP_EOL, $lines));
}
return (int) $value;
diff --git a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php
index 264f8bfdcdf5c..bd3c721b83752 100644
--- a/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php
+++ b/src/Symfony/Component/Messenger/DependencyInjection/MessengerPass.php
@@ -128,11 +128,13 @@ private function registerHandlers(ContainerBuilder $container, array $busIds)
if ('__invoke' !== $method) {
$wrapperDefinition = (new Definition('callable'))->addArgument(array(new Reference($serviceId), $method))->setFactory('Closure::fromCallable');
- $definitions[$serviceId = '.messenger.method_on_object_wrapper.'.ContainerBuilder::hash($messageClass.':'.$messagePriority.':'.$serviceId.':'.$method)] = $wrapperDefinition;
+ $definitions[$definitionId = '.messenger.method_on_object_wrapper.'.ContainerBuilder::hash($messageClass.':'.$messagePriority.':'.$serviceId.':'.$method)] = $wrapperDefinition;
+ } else {
+ $definitionId = $serviceId;
}
foreach ($handlerBuses as $handlerBus) {
- $handlersByBusAndMessage[$handlerBus][$messageClass][$messagePriority][] = $serviceId;
+ $handlersByBusAndMessage[$handlerBus][$messageClass][$messagePriority][] = $definitionId;
}
}
}
diff --git a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php
index 618604f2396c9..4b2a0de1b9981 100644
--- a/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php
+++ b/src/Symfony/Component/Messenger/Tests/DependencyInjection/MessengerPassTest.php
@@ -288,7 +288,12 @@ public function testItShouldNotThrowIfGeneratorIsReturnedInsteadOfArray()
$handlerMapping = $handlerLocatorDefinition->getArgument(0);
$this->assertArrayHasKey('handler.'.DummyMessage::class, $handlerMapping);
+ $firstReference = $handlerMapping['handler.'.DummyMessage::class]->getValues()[0];
+ $this->assertEquals(array(new Reference(HandlerWithGenerators::class), 'dummyMethod'), $container->getDefinition($firstReference)->getArgument(0));
+
$this->assertArrayHasKey('handler.'.SecondMessage::class, $handlerMapping);
+ $secondReference = $handlerMapping['handler.'.SecondMessage::class]->getValues()[0];
+ $this->assertEquals(array(new Reference(HandlerWithGenerators::class), 'secondMessage'), $container->getDefinition($secondReference)->getArgument(0));
}
/**
diff --git a/src/Symfony/Component/Messenger/Transport/ChainSender.php b/src/Symfony/Component/Messenger/Transport/ChainSender.php
index 97e3ce44bbaf1..2d2d55f03df76 100644
--- a/src/Symfony/Component/Messenger/Transport/ChainSender.php
+++ b/src/Symfony/Component/Messenger/Transport/ChainSender.php
@@ -11,6 +11,8 @@
namespace Symfony\Component\Messenger\Transport;
+use Symfony\Component\Messenger\Envelope;
+
/**
* @author Tobias Schultze
*/
@@ -29,7 +31,7 @@ public function __construct(iterable $senders)
/**
* {@inheritdoc}
*/
- public function send($message): void
+ public function send(Envelope $message): void
{
foreach ($this->senders as $sender) {
$sender->send($message);
diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php
index 68b4154b10da2..5f291f7cbff2b 100644
--- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php
+++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php
@@ -433,7 +433,7 @@ public function setAllowedValues($option, $allowedValues)
));
}
- $this->allowedValues[$option] = is_array($allowedValues) ? $allowedValues : array($allowedValues);
+ $this->allowedValues[$option] = \is_array($allowedValues) ? $allowedValues : array($allowedValues);
// Make sure the option is processed
unset($this->resolved[$option]);
@@ -785,14 +785,13 @@ public function offsetGet($option)
}
if (!$valid) {
- throw new InvalidOptionsException(sprintf(
- 'The option "%s" with value %s is expected to be of type '.
- '"%s", but is of type "%s".',
- $option,
- $this->formatValue($value),
- implode('" or "', $this->allowedTypes[$option]),
- implode('|', array_keys($invalidTypes))
- ));
+ $keys = array_keys($invalidTypes);
+
+ if (1 === \count($keys) && '[]' === substr($keys[0], -2)) {
+ throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but one of the elements is of type "%s".', $option, $this->formatValue($value), implode('" or "', $this->allowedTypes[$option]), $keys[0]));
+ }
+
+ throw new InvalidOptionsException(sprintf('The option "%s" with value %s is expected to be of type "%s", but is of type "%s".', $option, $this->formatValue($value), implode('" or "', $this->allowedTypes[$option]), implode('|', array_keys($invalidTypes))));
}
}
@@ -868,32 +867,10 @@ public function offsetGet($option)
return $value;
}
- /**
- * @param string $type
- * @param mixed $value
- * @param array &$invalidTypes
- *
- * @return bool
- */
- private function verifyTypes($type, $value, array &$invalidTypes)
+ private function verifyTypes(string $type, $value, array &$invalidTypes): bool
{
- if ('[]' === substr($type, -2) && is_array($value)) {
- $originalType = $type;
- $type = substr($type, 0, -2);
- $invalidValues = array_filter( // Filter out valid values, keeping invalid values in the resulting array
- $value,
- function ($value) use ($type) {
- return !self::isValueValidType($type, $value);
- }
- );
-
- if (!$invalidValues) {
- return true;
- }
-
- $invalidTypes[$this->formatTypeOf($value, $originalType)] = true;
-
- return false;
+ if (\is_array($value) && '[]' === substr($type, -2)) {
+ return $this->verifyArrayType($type, $value, $invalidTypes);
}
if (self::isValueValidType($type, $value)) {
@@ -907,6 +884,43 @@ function ($value) use ($type) {
return false;
}
+ private function verifyArrayType(string $type, array $value, array &$invalidTypes, int $level = 0): bool
+ {
+ $type = substr($type, 0, -2);
+
+ $suffix = '[]';
+ while (\strlen($suffix) <= $level * 2) {
+ $suffix .= '[]';
+ }
+
+ if ('[]' === substr($type, -2)) {
+ $success = true;
+ foreach ($value as $item) {
+ if (!\is_array($item)) {
+ $invalidTypes[$this->formatTypeOf($item, null).$suffix] = true;
+
+ return false;
+ }
+
+ if (!$this->verifyArrayType($type, $item, $invalidTypes, $level + 1)) {
+ $success = false;
+ }
+ }
+
+ return $success;
+ }
+
+ foreach ($value as $item) {
+ if (!self::isValueValidType($type, $item)) {
+ $invalidTypes[$this->formatTypeOf($item, $type).$suffix] = $value;
+
+ return false;
+ }
+ }
+
+ return true;
+ }
+
/**
* Returns whether a resolved option with the given name exists.
*
@@ -987,13 +1001,13 @@ private function formatTypeOf($value, ?string $type): string
while ('[]' === substr($type, -2)) {
$type = substr($type, 0, -2);
$value = array_shift($value);
- if (!is_array($value)) {
+ if (!\is_array($value)) {
break;
}
$suffix .= '[]';
}
- if (is_array($value)) {
+ if (\is_array($value)) {
$subTypes = array();
foreach ($value as $val) {
$subTypes[$this->formatTypeOf($val, null)] = true;
@@ -1003,7 +1017,7 @@ private function formatTypeOf($value, ?string $type): string
}
}
- return (is_object($value) ? get_class($value) : gettype($value)).$suffix;
+ return (\is_object($value) ? get_class($value) : gettype($value)).$suffix;
}
/**
@@ -1017,19 +1031,19 @@ private function formatTypeOf($value, ?string $type): string
*/
private function formatValue($value): string
{
- if (is_object($value)) {
+ if (\is_object($value)) {
return get_class($value);
}
- if (is_array($value)) {
+ if (\is_array($value)) {
return 'array';
}
- if (is_string($value)) {
+ if (\is_string($value)) {
return '"'.$value.'"';
}
- if (is_resource($value)) {
+ if (\is_resource($value)) {
return 'resource';
}
@@ -1065,8 +1079,21 @@ private function formatValues(array $values): string
return implode(', ', $values);
}
- private static function isValueValidType($type, $value)
+ private static function isValueValidType(string $type, $value): bool
{
return (function_exists($isFunction = 'is_'.$type) && $isFunction($value)) || $value instanceof $type;
}
+
+ private function getInvalidValues(array $arrayValues, string $type): array
+ {
+ $invalidValues = array();
+
+ foreach ($arrayValues as $key => $value) {
+ if (!self::isValueValidType($type, $value)) {
+ $invalidValues[$key] = $value;
+ }
+ }
+
+ return $invalidValues;
+ }
}
diff --git a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php
index 12dc77b3c6b1c..ac12984447604 100644
--- a/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php
+++ b/src/Symfony/Component/OptionsResolver/Tests/OptionsResolverTest.php
@@ -483,7 +483,7 @@ public function testFailIfSetAllowedTypesFromLazyOption()
/**
* @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
- * @expectedExceptionMessage The option "foo" with value array is expected to be of type "int[]", but is of type "DateTime[]".
+ * @expectedExceptionMessage The option "foo" with value array is expected to be of type "int[]", but one of the elements is of type "DateTime[]".
*/
public function testResolveFailsIfInvalidTypedArray()
{
@@ -507,7 +507,7 @@ public function testResolveFailsWithNonArray()
/**
* @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
- * @expectedExceptionMessage The option "foo" with value array is expected to be of type "int[]", but is of type "integer|stdClass|array|DateTime[]".
+ * @expectedExceptionMessage The option "foo" with value array is expected to be of type "int[]", but one of the elements is of type "stdClass[]".
*/
public function testResolveFailsIfTypedArrayContainsInvalidTypes()
{
@@ -524,7 +524,7 @@ public function testResolveFailsIfTypedArrayContainsInvalidTypes()
/**
* @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
- * @expectedExceptionMessage The option "foo" with value array is expected to be of type "int[][]", but is of type "double[][]".
+ * @expectedExceptionMessage The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "double[][]".
*/
public function testResolveFailsWithCorrectLevelsButWrongScalar()
{
@@ -1586,4 +1586,151 @@ public function testCountFailsOutsideResolve()
count($this->resolver);
}
+
+ public function testNestedArrays()
+ {
+ $this->resolver->setDefined('foo');
+ $this->resolver->setAllowedTypes('foo', 'int[][]');
+
+ $this->assertEquals(array(
+ 'foo' => array(
+ array(
+ 1, 2,
+ ),
+ ),
+ ), $this->resolver->resolve(
+ array(
+ 'foo' => array(
+ array(1, 2),
+ ),
+ )
+ ));
+ }
+
+ public function testNested2Arrays()
+ {
+ $this->resolver->setDefined('foo');
+ $this->resolver->setAllowedTypes('foo', 'int[][][][]');
+
+ $this->assertEquals(array(
+ 'foo' => array(
+ array(
+ array(
+ array(
+ 1, 2,
+ ),
+ ),
+ ),
+ ),
+ ), $this->resolver->resolve(
+ array(
+ 'foo' => array(
+ array(
+ array(
+ array(1, 2),
+ ),
+ ),
+ ),
+ )
+ ));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
+ * @expectedExceptionMessage The option "foo" with value array is expected to be of type "float[][][][]", but one of the elements is of type "integer[][][][]".
+ */
+ public function testNestedArraysException()
+ {
+ $this->resolver->setDefined('foo');
+ $this->resolver->setAllowedTypes('foo', 'float[][][][]');
+
+ $this->resolver->resolve(
+ array(
+ 'foo' => array(
+ array(
+ array(
+ array(1, 2),
+ ),
+ ),
+ ),
+ )
+ );
+ }
+
+ /**
+ * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
+ * @expectedExceptionMessage The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "boolean[][]".
+ */
+ public function testNestedArrayException1()
+ {
+ $this->resolver->setDefined('foo');
+ $this->resolver->setAllowedTypes('foo', 'int[][]');
+ $this->resolver->resolve(array(
+ 'foo' => array(
+ array(1, true, 'str', array(2, 3)),
+ ),
+ ));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
+ * @expectedExceptionMessage The option "foo" with value array is expected to be of type "int[][]", but one of the elements is of type "boolean[][]".
+ */
+ public function testNestedArrayException2()
+ {
+ $this->resolver->setDefined('foo');
+ $this->resolver->setAllowedTypes('foo', 'int[][]');
+ $this->resolver->resolve(array(
+ 'foo' => array(
+ array(true, 'str', array(2, 3)),
+ ),
+ ));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
+ * @expectedExceptionMessage The option "foo" with value array is expected to be of type "string[][][]", but one of the elements is of type "string[][]".
+ */
+ public function testNestedArrayException3()
+ {
+ $this->resolver->setDefined('foo');
+ $this->resolver->setAllowedTypes('foo', 'string[][][]');
+ $this->resolver->resolve(array(
+ 'foo' => array(
+ array('str', array(1, 2)),
+ ),
+ ));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
+ * @expectedExceptionMessage The option "foo" with value array is expected to be of type "string[][][]", but one of the elements is of type "integer[][][]".
+ */
+ public function testNestedArrayException4()
+ {
+ $this->resolver->setDefined('foo');
+ $this->resolver->setAllowedTypes('foo', 'string[][][]');
+ $this->resolver->resolve(array(
+ 'foo' => array(
+ array(
+ array('str'), array(1, 2), ),
+ ),
+ ));
+ }
+
+ /**
+ * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException
+ * @expectedExceptionMessage The option "foo" with value array is expected to be of type "string[]", but one of the elements is of type "array[]".
+ */
+ public function testNestedArrayException5()
+ {
+ $this->resolver->setDefined('foo');
+ $this->resolver->setAllowedTypes('foo', 'string[]');
+ $this->resolver->resolve(array(
+ 'foo' => array(
+ array(
+ array('str'), array(1, 2), ),
+ ),
+ ));
+ }
}
diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php
index f11569f162f66..f6f3ba06d1bf2 100644
--- a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php
+++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php
@@ -161,25 +161,21 @@ private function getDocBlock(string $class, string $property): array
$ucFirstProperty = ucfirst($property);
- try {
- switch (true) {
- case $docBlock = $this->getDocBlockFromProperty($class, $property):
- $data = array($docBlock, self::PROPERTY, null);
- break;
+ switch (true) {
+ case $docBlock = $this->getDocBlockFromProperty($class, $property):
+ $data = array($docBlock, self::PROPERTY, null);
+ break;
- case list($docBlock) = $this->getDocBlockFromMethod($class, $ucFirstProperty, self::ACCESSOR):
- $data = array($docBlock, self::ACCESSOR, null);
- break;
+ case list($docBlock) = $this->getDocBlockFromMethod($class, $ucFirstProperty, self::ACCESSOR):
+ $data = array($docBlock, self::ACCESSOR, null);
+ break;
- case list($docBlock, $prefix) = $this->getDocBlockFromMethod($class, $ucFirstProperty, self::MUTATOR):
- $data = array($docBlock, self::MUTATOR, $prefix);
- break;
+ case list($docBlock, $prefix) = $this->getDocBlockFromMethod($class, $ucFirstProperty, self::MUTATOR):
+ $data = array($docBlock, self::MUTATOR, $prefix);
+ break;
- default:
- $data = array(null, null, null);
- }
- } catch (\InvalidArgumentException $e) {
- $data = array(null, null, null);
+ default:
+ $data = array(null, null, null);
}
return $this->docBlocks[$propertyHash] = $data;
@@ -194,7 +190,11 @@ private function getDocBlockFromProperty(string $class, string $property): ?DocB
return null;
}
- return $this->docBlockFactory->create($reflectionProperty, $this->contextFactory->createFromReflector($reflectionProperty->getDeclaringClass()));
+ try {
+ return $this->docBlockFactory->create($reflectionProperty, $this->contextFactory->createFromReflector($reflectionProperty->getDeclaringClass()));
+ } catch (\InvalidArgumentException $e) {
+ return null;
+ }
}
private function getDocBlockFromMethod(string $class, string $ucFirstProperty, int $type): ?array
@@ -226,6 +226,10 @@ private function getDocBlockFromMethod(string $class, string $ucFirstProperty, i
return null;
}
- return array($this->docBlockFactory->create($reflectionMethod, $this->contextFactory->createFromReflector($reflectionMethod)), $prefix);
+ try {
+ return array($this->docBlockFactory->create($reflectionMethod, $this->contextFactory->createFromReflector($reflectionMethod)), $prefix);
+ } catch (\InvalidArgumentException $e) {
+ return null;
+ }
}
}
diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php
index af22aa9c918b7..080df2893a877 100644
--- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php
+++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/PhpDocExtractorTest.php
@@ -40,6 +40,31 @@ public function testExtract($property, array $type = null, $shortDescription, $l
$this->assertSame($longDescription, $this->extractor->getLongDescription('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property));
}
+ public function testParamTagTypeIsOmitted()
+ {
+ $this->assertNull($this->extractor->getTypes(OmittedParamTagTypeDocBlock::class, 'omittedType'));
+ }
+
+ /**
+ * @dataProvider typesWithCustomPrefixesProvider
+ */
+ public function testExtractTypesWithCustomPrefixes($property, array $type = null)
+ {
+ $customExtractor = new PhpDocExtractor(null, array('add', 'remove'), array('is', 'can'));
+
+ $this->assertEquals($type, $customExtractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property));
+ }
+
+ /**
+ * @dataProvider typesWithNoPrefixesProvider
+ */
+ public function testExtractTypesWithNoPrefixes($property, array $type = null)
+ {
+ $noPrefixExtractor = new PhpDocExtractor(null, array(), array(), array());
+
+ $this->assertEquals($type, $noPrefixExtractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property));
+ }
+
public function typesProvider()
{
return array(
@@ -68,8 +93,10 @@ public function typesProvider()
array('d', array(new Type(Type::BUILTIN_TYPE_BOOL)), null, null),
array('e', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_RESOURCE))), null, null),
array('f', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime'))), null, null),
- array('g', array(new Type(Type::BUILTIN_TYPE_BOOL, true)), null, null),
- array('array', array(new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true)), 'Nullable array.', null),
+ array('g', array(new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true)), 'Nullable array.', null),
+ array('h', array(new Type(Type::BUILTIN_TYPE_STRING, true)), null, null),
+ array('i', array(new Type(Type::BUILTIN_TYPE_STRING, true), new Type(Type::BUILTIN_TYPE_INT, true)), null, null),
+ array('j', array(new Type(Type::BUILTIN_TYPE_OBJECT, true, 'DateTime')), null, null),
array('donotexist', null, null, null),
array('staticGetter', null, null, null),
array('staticSetter', null, null, null),
@@ -77,21 +104,6 @@ public function typesProvider()
);
}
- public function testParamTagTypeIsOmitted()
- {
- $this->assertNull($this->extractor->getTypes(OmittedParamTagTypeDocBlock::class, 'omittedType'));
- }
-
- /**
- * @dataProvider typesWithCustomPrefixesProvider
- */
- public function testExtractTypesWithCustomPrefixes($property, array $type = null)
- {
- $customExtractor = new PhpDocExtractor(null, array('add', 'remove'), array('is', 'can'));
-
- $this->assertEquals($type, $customExtractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property));
- }
-
public function typesWithCustomPrefixesProvider()
{
return array(
@@ -120,23 +132,16 @@ public function typesWithCustomPrefixesProvider()
array('d', array(new Type(Type::BUILTIN_TYPE_BOOL)), null, null),
array('e', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_RESOURCE))), null, null),
array('f', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime'))), null, null),
- array('g', null),
+ array('g', array(new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true)), 'Nullable array.', null),
+ array('h', array(new Type(Type::BUILTIN_TYPE_STRING, true)), null, null),
+ array('i', array(new Type(Type::BUILTIN_TYPE_STRING, true), new Type(Type::BUILTIN_TYPE_INT, true)), null, null),
+ array('j', array(new Type(Type::BUILTIN_TYPE_OBJECT, true, 'DateTime')), null, null),
array('donotexist', null, null, null),
array('staticGetter', null, null, null),
array('staticSetter', null, null, null),
);
}
- /**
- * @dataProvider typesWithNoPrefixesProvider
- */
- public function testExtractTypesWithNoPrefixes($property, array $type = null)
- {
- $noPrefixExtractor = new PhpDocExtractor(null, array(), array(), array());
-
- $this->assertEquals($type, $noPrefixExtractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy', $property));
- }
-
public function typesWithNoPrefixesProvider()
{
return array(
@@ -165,7 +170,10 @@ public function typesWithNoPrefixesProvider()
array('d', null, null, null),
array('e', null, null, null),
array('f', null, null, null),
- array('g', null),
+ array('g', array(new Type(Type::BUILTIN_TYPE_ARRAY, true, null, true)), 'Nullable array.', null),
+ array('h', array(new Type(Type::BUILTIN_TYPE_STRING, true)), null, null),
+ array('i', array(new Type(Type::BUILTIN_TYPE_STRING, true), new Type(Type::BUILTIN_TYPE_INT, true)), null, null),
+ array('j', array(new Type(Type::BUILTIN_TYPE_OBJECT, true, 'DateTime')), null, null),
array('donotexist', null, null, null),
array('staticGetter', null, null, null),
array('staticSetter', null, null, null),
@@ -176,6 +184,29 @@ public function testReturnNullOnEmptyDocBlock()
{
$this->assertNull($this->extractor->getShortDescription(EmptyDocBlock::class, 'foo'));
}
+
+ public function dockBlockFallbackTypesProvider()
+ {
+ return array(
+ 'pub' => array(
+ 'pub', array(new Type(Type::BUILTIN_TYPE_STRING)),
+ ),
+ 'protAcc' => array(
+ 'protAcc', array(new Type(Type::BUILTIN_TYPE_INT)),
+ ),
+ 'protMut' => array(
+ 'protMut', array(new Type(Type::BUILTIN_TYPE_BOOL)),
+ ),
+ );
+ }
+
+ /**
+ * @dataProvider dockBlockFallbackTypesProvider
+ */
+ public function testDocBlockFallback($property, $types)
+ {
+ $this->assertEquals($types, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\DockBlockFallback', $property));
+ }
}
class EmptyDocBlock
diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php
index f5b47196ee5f4..4d188cb4bf265 100644
--- a/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php
+++ b/src/Symfony/Component/PropertyInfo/Tests/Extractor/ReflectionExtractorTest.php
@@ -40,7 +40,10 @@ public function testGetProperties()
'collection',
'B',
'Guid',
- 'array',
+ 'g',
+ 'h',
+ 'i',
+ 'j',
'emptyVar',
'foo',
'foo2',
@@ -58,7 +61,6 @@ public function testGetProperties()
'd',
'e',
'f',
- 'g',
),
$this->extractor->getProperties('Symfony\Component\PropertyInfo\Tests\Fixtures\Dummy')
);
@@ -77,7 +79,10 @@ public function testGetPropertiesWithCustomPrefixes()
'collection',
'B',
'Guid',
- 'array',
+ 'g',
+ 'h',
+ 'i',
+ 'j',
'emptyVar',
'foo',
'foo2',
@@ -105,7 +110,10 @@ public function testGetPropertiesWithNoPrefixes()
'collection',
'B',
'Guid',
- 'array',
+ 'g',
+ 'h',
+ 'i',
+ 'j',
'emptyVar',
'foo',
'foo2',
@@ -118,24 +126,6 @@ public function testGetPropertiesWithNoPrefixes()
);
}
- public function testGetPropertiesPhp71()
- {
- $noPrefixExtractor = new ReflectionExtractor();
-
- $this->assertSame(
- array(
- 'string',
- 'stringOrNull',
- 'foo',
- 'buz',
- 'bar',
- 'baz',
- 'intWithAccessor',
- ),
- $noPrefixExtractor->getProperties('Symfony\Component\PropertyInfo\Tests\Fixtures\Php71Dummy')
- );
- }
-
/**
* @dataProvider typesProvider
*/
@@ -197,22 +187,9 @@ public function php71TypesProvider()
array('bar', array(new Type(Type::BUILTIN_TYPE_INT, true))),
array('baz', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_STRING)))),
array('donotexist', null),
- array('string', array(new Type(Type::BUILTIN_TYPE_STRING, false))),
- array('stringOrNull', array(new Type(Type::BUILTIN_TYPE_STRING, true))),
- array('intPrivate', array(new Type(Type::BUILTIN_TYPE_INT, false))),
- array('intWithAccessor', array(new Type(Type::BUILTIN_TYPE_INT, false))),
);
}
- public function testExtractPhp71TypeWithParentConstructor()
- {
- $property = 'string';
- $type = array(new Type(Type::BUILTIN_TYPE_STRING, false));
- $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php71DummyChild', $property, array()));
- $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php71DummyChild2', $property, array()));
- $this->assertEquals($type, $this->extractor->getTypes('Symfony\Component\PropertyInfo\Tests\Fixtures\Php71DummyChild3', $property, array()));
- }
-
/**
* @dataProvider getReadableProperties
*/
@@ -236,12 +213,10 @@ public function getReadableProperties()
array('d', true),
array('e', false),
array('f', false),
- array('g', true),
array('Id', true),
array('id', true),
array('Guid', true),
array('guid', false),
- array('guid', false),
);
}
@@ -268,7 +243,6 @@ public function getWritableProperties()
array('d', false),
array('e', true),
array('f', true),
- array('g', false),
array('Id', false),
array('Guid', true),
array('guid', false),
diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DockBlockFallback.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DockBlockFallback.php
new file mode 100644
index 0000000000000..3f9c303b59137
--- /dev/null
+++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/DockBlockFallback.php
@@ -0,0 +1,64 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\PropertyInfo\Tests\Fixtures;
+
+/**
+ * PhpDocExtractor should fallback from property -> accessor -> mutator when looking up dockblocks.
+ *
+ * @author Martin Rademacher
+ */
+class DockBlockFallback
+{
+ /** @var string $pub */
+ public $pub = 'pub';
+
+ protected $protAcc;
+ protected $protMut;
+
+ public function getPub()
+ {
+ return $this->pub;
+ }
+
+ public function setPub($pub)
+ {
+ $this->pub = $pub;
+ }
+
+ /**
+ * @return int
+ */
+ public function getProtAcc()
+ {
+ return $this->protAcc;
+ }
+
+ public function setProt($protAcc)
+ {
+ $this->protAcc = $protAcc;
+ }
+
+ public function getProtMut()
+ {
+ return $this->protMut;
+ }
+
+ /**
+ * @param bool $protMut
+ */
+ public function setProtMut($protMut)
+ {
+ $this->protMut = $protMut;
+ }
+}
diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php
index afe09ef929dfe..76c2e1042c604 100644
--- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php
+++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php
@@ -66,7 +66,22 @@ class Dummy extends ParentDummy
*
* @var array|null
*/
- public $array;
+ public $g;
+
+ /**
+ * @var ?string
+ */
+ public $h;
+
+ /**
+ * @var ?string|int
+ */
+ public $i;
+
+ /**
+ * @var ?\DateTime
+ */
+ public $j;
/**
* This should not be removed.
diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/ParentDummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/ParentDummy.php
index b3f6d779077d3..8d5c4fe107162 100644
--- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/ParentDummy.php
+++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/ParentDummy.php
@@ -75,11 +75,4 @@ public function addE($e)
public function removeF(\DateTime $f)
{
}
-
- /**
- * @return bool|null
- */
- public function hasG()
- {
- }
}
diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php71Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php71Dummy.php
index 67d68eb9ccb81..e72d376c492fa 100644
--- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php71Dummy.php
+++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Php71Dummy.php
@@ -16,22 +16,6 @@
*/
class Php71Dummy
{
- public $string;
-
- public $stringOrNull;
-
- private $intPrivate;
-
- private $intWithAccessor;
-
- public function __construct(string $string, ?string $stringOrNull, int $intPrivate, int $intWithAccessor)
- {
- $this->string = $string;
- $this->stringOrNull = $stringOrNull;
- $this->intPrivate = $intPrivate;
- $this->intWithAccessor = $intWithAccessor;
- }
-
public function getFoo(): ?array
{
}
@@ -47,9 +31,4 @@ public function setBar(?int $bar)
public function addBaz(string $baz)
{
}
-
- public function getIntWithAccessor()
- {
- return $this->intWithAccessor;
- }
}
diff --git a/src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php b/src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php
index 939fb7c195932..7a1a9e03c9181 100644
--- a/src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php
+++ b/src/Symfony/Component/PropertyInfo/Util/PhpDocTypeHelper.php
@@ -14,6 +14,7 @@
use phpDocumentor\Reflection\Type as DocType;
use phpDocumentor\Reflection\Types\Compound;
use phpDocumentor\Reflection\Types\Null_;
+use phpDocumentor\Reflection\Types\Nullable;
use Symfony\Component\PropertyInfo\Type;
/**
@@ -34,6 +35,11 @@ public function getTypes(DocType $varType): array
$types = array();
$nullable = false;
+ if ($varType instanceof Nullable) {
+ $nullable = true;
+ $varType = $varType->getActualType();
+ }
+
if (!$varType instanceof Compound) {
if ($varType instanceof Null_) {
$nullable = true;
@@ -54,10 +60,10 @@ public function getTypes(DocType $varType): array
// If null is present, all types are nullable
$nullKey = array_search(Type::BUILTIN_TYPE_NULL, $varTypes);
- $nullable = false !== $nullKey;
+ $nullable = $nullable || false !== $nullKey;
// Remove the null type from the type if other types are defined
- if ($nullable && count($varTypes) > 1) {
+ if ($nullable && false !== $nullKey && count($varTypes) > 1) {
unset($varTypes[$nullKey]);
}
diff --git a/src/Symfony/Component/PropertyInfo/composer.json b/src/Symfony/Component/PropertyInfo/composer.json
index 0350fb411f315..88f177d00491f 100644
--- a/src/Symfony/Component/PropertyInfo/composer.json
+++ b/src/Symfony/Component/PropertyInfo/composer.json
@@ -35,7 +35,7 @@
},
"conflict": {
"phpdocumentor/reflection-docblock": "<3.0||>=3.2.0,<3.2.2",
- "phpdocumentor/type-resolver": "<0.2.1",
+ "phpdocumentor/type-resolver": "<0.3.0",
"symfony/dependency-injection": "<3.4"
},
"suggest": {
diff --git a/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php b/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php
index adb2b0a1c0148..c5af8c52a3679 100644
--- a/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php
+++ b/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php
@@ -379,7 +379,7 @@ private function compileDynamicRoutes(RouteCollection $collection, bool $matchHo
$hostRegex = '(?i:'.preg_replace_callback('#\?P<([^>]++)>#', $state->getVars, $rx[1]).')\.';
$state->hostVars = $state->vars;
} else {
- $hostRegex = '(?:(?:[^.]*+\.)++)';
+ $hostRegex = '(?:(?:[^./]*+\.)++)';
$state->hostVars = array();
}
$state->mark += strlen($rx = ($prev ? ')' : '')."|{$hostRegex}(?");
@@ -746,6 +746,10 @@ public static function export($value): string
return 'null';
}
if (!\is_array($value)) {
+ if (\is_object($value)) {
+ throw new \InvalidArgumentException('Symfony\Component\Routing\Route cannot contain objects.');
+ }
+
return str_replace("\n", '\'."\n".\'', var_export($value, true));
}
if (!$value) {
diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php
index b39bc7f2bae0a..c91066a46d281 100644
--- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php
+++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php
@@ -82,47 +82,47 @@ public function match($rawPathinfo)
$matchedPathinfo = $host.'.'.$pathinfo;
$regexList = array(
0 => '{^(?'
- .'|(?:(?:[^.]*+\\.)++)(?'
- .'|/foo/(baz|symfony)(*:46)'
+ .'|(?:(?:[^./]*+\\.)++)(?'
+ .'|/foo/(baz|symfony)(*:47)'
.'|/bar(?'
- .'|/([^/]++)(*:69)'
- .'|head/([^/]++)(*:89)'
+ .'|/([^/]++)(*:70)'
+ .'|head/([^/]++)(*:90)'
.')'
.'|/test/([^/]++)/(?'
- .'|(*:115)'
+ .'|(*:116)'
.')'
- .'|/([\']+)(*:131)'
+ .'|/([\']+)(*:132)'
.'|/a/(?'
.'|b\'b/([^/]++)(?'
- .'|(*:160)'
- .'|(*:168)'
+ .'|(*:161)'
+ .'|(*:169)'
.')'
- .'|(.*)(*:181)'
+ .'|(.*)(*:182)'
.'|b\'b/([^/]++)(?'
- .'|(*:204)'
- .'|(*:212)'
+ .'|(*:205)'
+ .'|(*:213)'
.')'
.')'
- .'|/multi/hello(?:/([^/]++))?(*:248)'
+ .'|/multi/hello(?:/([^/]++))?(*:249)'
.'|/([^/]++)/b/([^/]++)(?'
- .'|(*:279)'
- .'|(*:287)'
+ .'|(*:280)'
+ .'|(*:288)'
.')'
- .'|/aba/([^/]++)(*:309)'
+ .'|/aba/([^/]++)(*:310)'
.')|(?i:([^\\.]++)\\.example\\.com)\\.(?'
.'|/route1(?'
- .'|3/([^/]++)(*:371)'
- .'|4/([^/]++)(*:389)'
+ .'|3/([^/]++)(*:372)'
+ .'|4/([^/]++)(*:390)'
.')'
.')|(?i:c\\.example\\.com)\\.(?'
- .'|/route15/([^/]++)(*:441)'
- .')|(?:(?:[^.]*+\\.)++)(?'
- .'|/route16/([^/]++)(*:488)'
+ .'|/route15/([^/]++)(*:442)'
+ .')|(?:(?:[^./]*+\\.)++)(?'
+ .'|/route16/([^/]++)(*:490)'
.'|/a/(?'
- .'|a\\.\\.\\.(*:509)'
+ .'|a\\.\\.\\.(*:511)'
.'|b/(?'
- .'|([^/]++)(*:530)'
- .'|c/([^/]++)(*:548)'
+ .'|([^/]++)(*:532)'
+ .'|c/([^/]++)(*:550)'
.')'
.')'
.')'
@@ -132,7 +132,7 @@ public function match($rawPathinfo)
foreach ($regexList as $offset => $regex) {
while (preg_match($regex, $matchedPathinfo, $matches)) {
switch ($m = (int) $matches['MARK']) {
- case 115:
+ case 116:
$matches = array('foo' => $matches[1] ?? null);
// baz4
@@ -159,7 +159,7 @@ public function match($rawPathinfo)
not_bazbaz6:
break;
- case 160:
+ case 161:
$matches = array('foo' => $matches[1] ?? null);
// foo1
@@ -173,14 +173,14 @@ public function match($rawPathinfo)
not_foo1:
break;
- case 204:
+ case 205:
$matches = array('foo1' => $matches[1] ?? null);
// foo2
return $this->mergeDefaults(array('_route' => 'foo2') + $matches, array());
break;
- case 279:
+ case 280:
$matches = array('_locale' => $matches[1] ?? null, 'foo' => $matches[2] ?? null);
// foo3
@@ -189,23 +189,23 @@ public function match($rawPathinfo)
break;
default:
$routes = array(
- 46 => array(array('_route' => 'foo', 'def' => 'test'), array('bar'), null, null),
- 69 => array(array('_route' => 'bar'), array('foo'), array('GET' => 0, 'HEAD' => 1), null),
- 89 => array(array('_route' => 'barhead'), array('foo'), array('GET' => 0), null),
- 131 => array(array('_route' => 'quoter'), array('quoter'), null, null),
- 168 => array(array('_route' => 'bar1'), array('bar'), null, null),
- 181 => array(array('_route' => 'overridden'), array('var'), null, null),
- 212 => array(array('_route' => 'bar2'), array('bar1'), null, null),
- 248 => array(array('_route' => 'helloWorld', 'who' => 'World!'), array('who'), null, null),
- 287 => array(array('_route' => 'bar3'), array('_locale', 'bar'), null, null),
- 309 => array(array('_route' => 'foo4'), array('foo'), null, null),
- 371 => array(array('_route' => 'route13'), array('var1', 'name'), null, null),
- 389 => array(array('_route' => 'route14', 'var1' => 'val'), array('var1', 'name'), null, null),
- 441 => array(array('_route' => 'route15'), array('name'), null, null),
- 488 => array(array('_route' => 'route16', 'var1' => 'val'), array('name'), null, null),
- 509 => array(array('_route' => 'a'), array(), null, null),
- 530 => array(array('_route' => 'b'), array('var'), null, null),
- 548 => array(array('_route' => 'c'), array('var'), null, null),
+ 47 => array(array('_route' => 'foo', 'def' => 'test'), array('bar'), null, null),
+ 70 => array(array('_route' => 'bar'), array('foo'), array('GET' => 0, 'HEAD' => 1), null),
+ 90 => array(array('_route' => 'barhead'), array('foo'), array('GET' => 0), null),
+ 132 => array(array('_route' => 'quoter'), array('quoter'), null, null),
+ 169 => array(array('_route' => 'bar1'), array('bar'), null, null),
+ 182 => array(array('_route' => 'overridden'), array('var'), null, null),
+ 213 => array(array('_route' => 'bar2'), array('bar1'), null, null),
+ 249 => array(array('_route' => 'helloWorld', 'who' => 'World!'), array('who'), null, null),
+ 288 => array(array('_route' => 'bar3'), array('_locale', 'bar'), null, null),
+ 310 => array(array('_route' => 'foo4'), array('foo'), null, null),
+ 372 => array(array('_route' => 'route13'), array('var1', 'name'), null, null),
+ 390 => array(array('_route' => 'route14', 'var1' => 'val'), array('var1', 'name'), null, null),
+ 442 => array(array('_route' => 'route15'), array('name'), null, null),
+ 490 => array(array('_route' => 'route16', 'var1' => 'val'), array('name'), null, null),
+ 511 => array(array('_route' => 'a'), array(), null, null),
+ 532 => array(array('_route' => 'b'), array('var'), null, null),
+ 550 => array(array('_route' => 'c'), array('var'), null, null),
);
list($ret, $vars, $requiredMethods, $requiredSchemes) = $routes[$m];
@@ -231,7 +231,7 @@ public function match($rawPathinfo)
return $ret;
}
- if (548 === $m) {
+ if (550 === $m) {
break;
}
$regex = substr_replace($regex, 'F', $m - $offset, 1 + strlen($m));
diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php
index 79b650eb5b26d..a711dbaf61263 100644
--- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php
+++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php
@@ -119,47 +119,47 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a
$matchedPathinfo = $host.'.'.$pathinfo;
$regexList = array(
0 => '{^(?'
- .'|(?:(?:[^.]*+\\.)++)(?'
- .'|/foo/(baz|symfony)(*:46)'
+ .'|(?:(?:[^./]*+\\.)++)(?'
+ .'|/foo/(baz|symfony)(*:47)'
.'|/bar(?'
- .'|/([^/]++)(*:69)'
- .'|head/([^/]++)(*:89)'
+ .'|/([^/]++)(*:70)'
+ .'|head/([^/]++)(*:90)'
.')'
.'|/test/([^/]++)/(?'
- .'|(*:115)'
+ .'|(*:116)'
.')'
- .'|/([\']+)(*:131)'
+ .'|/([\']+)(*:132)'
.'|/a/(?'
.'|b\'b/([^/]++)(?'
- .'|(*:160)'
- .'|(*:168)'
+ .'|(*:161)'
+ .'|(*:169)'
.')'
- .'|(.*)(*:181)'
+ .'|(.*)(*:182)'
.'|b\'b/([^/]++)(?'
- .'|(*:204)'
- .'|(*:212)'
+ .'|(*:205)'
+ .'|(*:213)'
.')'
.')'
- .'|/multi/hello(?:/([^/]++))?(*:248)'
+ .'|/multi/hello(?:/([^/]++))?(*:249)'
.'|/([^/]++)/b/([^/]++)(?'
- .'|(*:279)'
- .'|(*:287)'
+ .'|(*:280)'
+ .'|(*:288)'
.')'
- .'|/aba/([^/]++)(*:309)'
+ .'|/aba/([^/]++)(*:310)'
.')|(?i:([^\\.]++)\\.example\\.com)\\.(?'
.'|/route1(?'
- .'|3/([^/]++)(*:371)'
- .'|4/([^/]++)(*:389)'
+ .'|3/([^/]++)(*:372)'
+ .'|4/([^/]++)(*:390)'
.')'
.')|(?i:c\\.example\\.com)\\.(?'
- .'|/route15/([^/]++)(*:441)'
- .')|(?:(?:[^.]*+\\.)++)(?'
- .'|/route16/([^/]++)(*:488)'
+ .'|/route15/([^/]++)(*:442)'
+ .')|(?:(?:[^./]*+\\.)++)(?'
+ .'|/route16/([^/]++)(*:490)'
.'|/a/(?'
- .'|a\\.\\.\\.(*:509)'
+ .'|a\\.\\.\\.(*:511)'
.'|b/(?'
- .'|([^/]++)(*:530)'
- .'|c/([^/]++)(*:548)'
+ .'|([^/]++)(*:532)'
+ .'|c/([^/]++)(*:550)'
.')'
.')'
.')'
@@ -169,7 +169,7 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a
foreach ($regexList as $offset => $regex) {
while (preg_match($regex, $matchedPathinfo, $matches)) {
switch ($m = (int) $matches['MARK']) {
- case 115:
+ case 116:
$matches = array('foo' => $matches[1] ?? null);
// baz4
@@ -196,7 +196,7 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a
not_bazbaz6:
break;
- case 160:
+ case 161:
$matches = array('foo' => $matches[1] ?? null);
// foo1
@@ -210,14 +210,14 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a
not_foo1:
break;
- case 204:
+ case 205:
$matches = array('foo1' => $matches[1] ?? null);
// foo2
return $this->mergeDefaults(array('_route' => 'foo2') + $matches, array());
break;
- case 279:
+ case 280:
$matches = array('_locale' => $matches[1] ?? null, 'foo' => $matches[2] ?? null);
// foo3
@@ -226,23 +226,23 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a
break;
default:
$routes = array(
- 46 => array(array('_route' => 'foo', 'def' => 'test'), array('bar'), null, null),
- 69 => array(array('_route' => 'bar'), array('foo'), array('GET' => 0, 'HEAD' => 1), null),
- 89 => array(array('_route' => 'barhead'), array('foo'), array('GET' => 0), null),
- 131 => array(array('_route' => 'quoter'), array('quoter'), null, null),
- 168 => array(array('_route' => 'bar1'), array('bar'), null, null),
- 181 => array(array('_route' => 'overridden'), array('var'), null, null),
- 212 => array(array('_route' => 'bar2'), array('bar1'), null, null),
- 248 => array(array('_route' => 'helloWorld', 'who' => 'World!'), array('who'), null, null),
- 287 => array(array('_route' => 'bar3'), array('_locale', 'bar'), null, null),
- 309 => array(array('_route' => 'foo4'), array('foo'), null, null),
- 371 => array(array('_route' => 'route13'), array('var1', 'name'), null, null),
- 389 => array(array('_route' => 'route14', 'var1' => 'val'), array('var1', 'name'), null, null),
- 441 => array(array('_route' => 'route15'), array('name'), null, null),
- 488 => array(array('_route' => 'route16', 'var1' => 'val'), array('name'), null, null),
- 509 => array(array('_route' => 'a'), array(), null, null),
- 530 => array(array('_route' => 'b'), array('var'), null, null),
- 548 => array(array('_route' => 'c'), array('var'), null, null),
+ 47 => array(array('_route' => 'foo', 'def' => 'test'), array('bar'), null, null),
+ 70 => array(array('_route' => 'bar'), array('foo'), array('GET' => 0, 'HEAD' => 1), null),
+ 90 => array(array('_route' => 'barhead'), array('foo'), array('GET' => 0), null),
+ 132 => array(array('_route' => 'quoter'), array('quoter'), null, null),
+ 169 => array(array('_route' => 'bar1'), array('bar'), null, null),
+ 182 => array(array('_route' => 'overridden'), array('var'), null, null),
+ 213 => array(array('_route' => 'bar2'), array('bar1'), null, null),
+ 249 => array(array('_route' => 'helloWorld', 'who' => 'World!'), array('who'), null, null),
+ 288 => array(array('_route' => 'bar3'), array('_locale', 'bar'), null, null),
+ 310 => array(array('_route' => 'foo4'), array('foo'), null, null),
+ 372 => array(array('_route' => 'route13'), array('var1', 'name'), null, null),
+ 390 => array(array('_route' => 'route14', 'var1' => 'val'), array('var1', 'name'), null, null),
+ 442 => array(array('_route' => 'route15'), array('name'), null, null),
+ 490 => array(array('_route' => 'route16', 'var1' => 'val'), array('name'), null, null),
+ 511 => array(array('_route' => 'a'), array(), null, null),
+ 532 => array(array('_route' => 'b'), array('var'), null, null),
+ 550 => array(array('_route' => 'c'), array('var'), null, null),
);
list($ret, $vars, $requiredMethods, $requiredSchemes) = $routes[$m];
@@ -268,7 +268,7 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a
return $ret;
}
- if (548 === $m) {
+ if (550 === $m) {
break;
}
$regex = substr_replace($regex, 'F', $m - $offset, 1 + strlen($m));
diff --git a/src/Symfony/Component/Routing/Tests/Matcher/Dumper/PhpMatcherDumperTest.php b/src/Symfony/Component/Routing/Tests/Matcher/Dumper/PhpMatcherDumperTest.php
index 4bbfe131a7bf9..a1c28ecab4d67 100644
--- a/src/Symfony/Component/Routing/Tests/Matcher/Dumper/PhpMatcherDumperTest.php
+++ b/src/Symfony/Component/Routing/Tests/Matcher/Dumper/PhpMatcherDumperTest.php
@@ -491,6 +491,18 @@ private function generateDumpedMatcher(RouteCollection $collection, $redirectabl
return $this->matcherClass;
}
+
+ /**
+ * @expectedException \InvalidArgumentException
+ * @expectedExceptionMessage Symfony\Component\Routing\Route cannot contain objects
+ */
+ public function testGenerateDumperMatcherWithObject()
+ {
+ $routeCollection = new RouteCollection();
+ $routeCollection->add('_', new Route('/', array(new \stdClass())));
+ $dumper = new PhpMatcherDumper($routeCollection);
+ $dumper->dump();
+ }
}
abstract class RedirectableUrlMatcherStub extends UrlMatcher implements RedirectableUrlMatcherInterface
diff --git a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
index f0013d7bc3d10..5a34535eb6cc2 100644
--- a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
+++ b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php
@@ -670,6 +670,16 @@ public function testUtf8AndMethodMatching()
$this->assertEquals('c', $matcher->match('/admin/api/package.json')['_route']);
}
+ public function testHostWithDot()
+ {
+ $coll = new RouteCollection();
+ $coll->add('a', new Route('/foo', array(), array(), array(), 'foo.example.com'));
+ $coll->add('b', new Route('/bar/{baz}'));
+
+ $matcher = $this->getUrlMatcher($coll);
+ $this->assertEquals('b', $matcher->match('/bar/abc.123')['_route']);
+ }
+
protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null)
{
return new UrlMatcher($routes, $context ?: new RequestContext());
diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php
index 5648dd730cdbe..491c62bcc491f 100644
--- a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php
+++ b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php
@@ -76,14 +76,7 @@ public function getUser()
}
/**
- * Sets the user in the token.
- *
- * The user can be a UserInterface instance, or an object implementing
- * a __toString method or the username as a regular string.
- *
- * @param string|object $user The user
- *
- * @throws \InvalidArgumentException
+ * {@inheritdoc}
*/
public function setUser($user)
{
@@ -261,7 +254,7 @@ private function hasUserChanged(UserInterface $user)
}
if ($this->user instanceof AdvancedUserInterface && $user instanceof AdvancedUserInterface) {
- @trigger_error(sprintf('Checking for the AdvancedUserInterface in %s has been deprecated in 4.1. Implement the %s to check if the user has been changed,', __METHOD__, EquatableInterface::class), E_USER_DEPRECATED);
+ @trigger_error(sprintf('Checking for the AdvancedUserInterface in "%s()" is deprecated since Symfony 4.1 and support for it will be removed in 5.0. Implement the %s to check if the user has been changed,', __METHOD__, EquatableInterface::class), E_USER_DEPRECATED);
if ($this->user->isAccountNonExpired() !== $user->isAccountNonExpired()) {
return true;
}
@@ -278,7 +271,7 @@ private function hasUserChanged(UserInterface $user)
return true;
}
} elseif ($this->user instanceof AdvancedUserInterface xor $user instanceof AdvancedUserInterface) {
- @trigger_error(sprintf('Checking for the AdvancedUserInterface in %s has been deprecated in 4.1. Implement the %s to check if the user has been changed,', __METHOD__, EquatableInterface::class), E_USER_DEPRECATED);
+ @trigger_error(sprintf('Checking for the AdvancedUserInterface in "%s()" is deprecated since Symfony 4.1 and support for it will be removed in 5.0. Implement the %s to check if the user has been changed,', __METHOD__, EquatableInterface::class), E_USER_DEPRECATED);
return true;
}
diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/TokenInterface.php b/src/Symfony/Component/Security/Core/Authentication/Token/TokenInterface.php
index bb5711ee89107..bcf6fbdd94621 100644
--- a/src/Symfony/Component/Security/Core/Authentication/Token/TokenInterface.php
+++ b/src/Symfony/Component/Security/Core/Authentication/Token/TokenInterface.php
@@ -47,17 +47,22 @@ public function getCredentials();
/**
* Returns a user representation.
*
- * @return mixed Can be a UserInterface instance, an object implementing a __toString method,
- * or the username as a regular string
+ * @return string|object Can be a UserInterface instance, an object implementing a __toString method,
+ * or the username as a regular string
*
* @see AbstractToken::setUser()
*/
public function getUser();
/**
- * Sets a user.
+ * Sets the user in the token.
*
- * @param mixed $user
+ * The user can be a UserInterface instance, or an object implementing
+ * a __toString method or the username as a regular string.
+ *
+ * @param string|object $user The user
+ *
+ * @throws \InvalidArgumentException
*/
public function setUser($user);
diff --git a/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php b/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php
index cbee938667789..187430884625a 100644
--- a/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php
+++ b/src/Symfony/Component/Security/Core/Authorization/Voter/ExpressionVoter.php
@@ -42,7 +42,7 @@ public function __construct(ExpressionLanguage $expressionLanguage, Authenticati
*/
public function addExpressionLanguageProvider(ExpressionFunctionProviderInterface $provider)
{
- @trigger_error(sprintf('The %s() method is deprecated since Symfony 4.1, register the provider directly on the injected ExpressionLanguage instance instead.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1, register the provider directly on the injected ExpressionLanguage instance instead.', __METHOD__), E_USER_DEPRECATED);
$this->expressionLanguage->registerProvider($provider);
}
diff --git a/src/Symfony/Component/Security/Core/Tests/User/UserCheckerTest.php b/src/Symfony/Component/Security/Core/Tests/User/UserCheckerTest.php
index 541c94ce6525b..1d1d98ed123ad 100644
--- a/src/Symfony/Component/Security/Core/Tests/User/UserCheckerTest.php
+++ b/src/Symfony/Component/Security/Core/Tests/User/UserCheckerTest.php
@@ -32,7 +32,7 @@ public function testCheckPostAuthPass()
/**
* @group legacy
- * @expectedDeprecation Calling Symfony\Component\Security\Core\User\UserChecker::checkPostAuth with an AdvancedUserInterface is deprecated since Symfony 4.1. Create a custom user checker if you wish to keep this functionality.
+ * @expectedDeprecation Calling "Symfony\Component\Security\Core\User\UserChecker::checkPostAuth()" with an AdvancedUserInterface is deprecated since Symfony 4.1. Create a custom user checker if you wish to keep this functionality.
*/
public function testCheckPostAuthPassAdvancedUser()
{
@@ -55,7 +55,7 @@ public function testCheckPostAuthCredentialsExpired()
/**
* @group legacy
- * @expectedDeprecation Calling Symfony\Component\Security\Core\User\UserChecker::checkPostAuth with an AdvancedUserInterface is deprecated since Symfony 4.1. Create a custom user checker if you wish to keep this functionality.
+ * @expectedDeprecation Calling "Symfony\Component\Security\Core\User\UserChecker::checkPostAuth()" with an AdvancedUserInterface is deprecated since Symfony 4.1. Create a custom user checker if you wish to keep this functionality.
* @expectedException \Symfony\Component\Security\Core\Exception\CredentialsExpiredException
*/
public function testCheckPostAuthCredentialsExpiredAdvancedUser()
@@ -70,7 +70,7 @@ public function testCheckPostAuthCredentialsExpiredAdvancedUser()
/**
* @group legacy
- * @expectedDeprecation Calling Symfony\Component\Security\Core\User\UserChecker::checkPreAuth with an AdvancedUserInterface is deprecated since Symfony 4.1. Create a custom user checker if you wish to keep this functionality.
+ * @expectedDeprecation Calling "Symfony\Component\Security\Core\User\UserChecker::checkPreAuth()" with an AdvancedUserInterface is deprecated since Symfony 4.1. Create a custom user checker if you wish to keep this functionality.
*/
public function testCheckPreAuthPassAdvancedUser()
{
@@ -95,7 +95,7 @@ public function testCheckPreAuthAccountLocked()
/**
* @group legacy
- * @expectedDeprecation Calling Symfony\Component\Security\Core\User\UserChecker::checkPreAuth with an AdvancedUserInterface is deprecated since Symfony 4.1. Create a custom user checker if you wish to keep this functionality.
+ * @expectedDeprecation Calling "Symfony\Component\Security\Core\User\UserChecker::checkPreAuth()" with an AdvancedUserInterface is deprecated since Symfony 4.1. Create a custom user checker if you wish to keep this functionality.
* @expectedException \Symfony\Component\Security\Core\Exception\LockedException
*/
public function testCheckPreAuthAccountLockedAdvancedUser()
@@ -119,7 +119,7 @@ public function testCheckPreAuthDisabled()
/**
* @group legacy
- * @expectedDeprecation Calling Symfony\Component\Security\Core\User\UserChecker::checkPreAuth with an AdvancedUserInterface is deprecated since Symfony 4.1. Create a custom user checker if you wish to keep this functionality.
+ * @expectedDeprecation Calling "Symfony\Component\Security\Core\User\UserChecker::checkPreAuth()" with an AdvancedUserInterface is deprecated since Symfony 4.1. Create a custom user checker if you wish to keep this functionality.
* @expectedException \Symfony\Component\Security\Core\Exception\DisabledException
*/
public function testCheckPreAuthDisabledAdvancedUser()
@@ -144,7 +144,7 @@ public function testCheckPreAuthAccountExpired()
/**
* @group legacy
- * @expectedDeprecation Calling Symfony\Component\Security\Core\User\UserChecker::checkPreAuth with an AdvancedUserInterface is deprecated since Symfony 4.1. Create a custom user checker if you wish to keep this functionality.
+ * @expectedDeprecation Calling "Symfony\Component\Security\Core\User\UserChecker::checkPreAuth()" with an AdvancedUserInterface is deprecated since Symfony 4.1. Create a custom user checker if you wish to keep this functionality.
* @expectedException \Symfony\Component\Security\Core\Exception\AccountExpiredException
*/
public function testCheckPreAuthAccountExpiredAdvancedUser()
diff --git a/src/Symfony/Component/Security/Core/User/LdapUserProvider.php b/src/Symfony/Component/Security/Core/User/LdapUserProvider.php
index b3fa3fa6b94f8..5f47fe8923b99 100644
--- a/src/Symfony/Component/Security/Core/User/LdapUserProvider.php
+++ b/src/Symfony/Component/Security/Core/User/LdapUserProvider.php
@@ -35,8 +35,12 @@ class LdapUserProvider implements UserProviderInterface
private $defaultSearch;
private $passwordAttribute;
- public function __construct(LdapInterface $ldap, string $baseDn, string $searchDn = null, string $searchPassword = null, array $defaultRoles = array(), string $uidKey = 'sAMAccountName', string $filter = '({uid_key}={username})', string $passwordAttribute = null)
+ public function __construct(LdapInterface $ldap, string $baseDn, string $searchDn = null, string $searchPassword = null, array $defaultRoles = array(), ?string $uidKey = 'sAMAccountName', string $filter = '({uid_key}={username})', string $passwordAttribute = null)
{
+ if (null === $uidKey) {
+ $uidKey = 'sAMAccountName';
+ }
+
$this->ldap = $ldap;
$this->baseDn = $baseDn;
$this->searchDn = $searchDn;
diff --git a/src/Symfony/Component/Security/Core/User/UserChecker.php b/src/Symfony/Component/Security/Core/User/UserChecker.php
index a4aa09031bc7a..37d567842519b 100644
--- a/src/Symfony/Component/Security/Core/User/UserChecker.php
+++ b/src/Symfony/Component/Security/Core/User/UserChecker.php
@@ -33,7 +33,7 @@ public function checkPreAuth(UserInterface $user)
}
if ($user instanceof AdvancedUserInterface && !$user instanceof User) {
- @trigger_error(sprintf('Calling %s with an AdvancedUserInterface is deprecated since Symfony 4.1. Create a custom user checker if you wish to keep this functionality.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('Calling "%s()" with an AdvancedUserInterface is deprecated since Symfony 4.1. Create a custom user checker if you wish to keep this functionality.', __METHOD__), E_USER_DEPRECATED);
}
if (!$user->isAccountNonLocked()) {
@@ -65,7 +65,7 @@ public function checkPostAuth(UserInterface $user)
}
if ($user instanceof AdvancedUserInterface && !$user instanceof User) {
- @trigger_error(sprintf('Calling %s with an AdvancedUserInterface is deprecated since Symfony 4.1. Create a custom user checker if you wish to keep this functionality.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('Calling "%s()" with an AdvancedUserInterface is deprecated since Symfony 4.1. Create a custom user checker if you wish to keep this functionality.', __METHOD__), E_USER_DEPRECATED);
}
if (!$user->isCredentialsNonExpired()) {
diff --git a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php
index 4b0d41f17fb95..2fb29bf58934f 100644
--- a/src/Symfony/Component/Security/Http/Firewall/ContextListener.php
+++ b/src/Symfony/Component/Security/Http/Firewall/ContextListener.php
@@ -70,7 +70,7 @@ public function __construct(TokenStorageInterface $tokenStorage, iterable $userP
*/
public function setLogoutOnUserChange($logoutOnUserChange)
{
- @trigger_error(sprintf('The %s() method is deprecated since Symfony 4.1.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1.', __METHOD__), E_USER_DEPRECATED);
}
/**
diff --git a/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php b/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php
index e03fcc0d7ff63..6d31fb36009b8 100644
--- a/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php
+++ b/src/Symfony/Component/Serializer/Encoder/CsvEncoder.php
@@ -28,6 +28,7 @@ class CsvEncoder implements EncoderInterface, DecoderInterface
const KEY_SEPARATOR_KEY = 'csv_key_separator';
const HEADERS_KEY = 'csv_headers';
const ESCAPE_FORMULAS_KEY = 'csv_escape_formulas';
+ const AS_COLLECTION_KEY = 'as_collection';
private $delimiter;
private $enclosure;
@@ -157,7 +158,7 @@ public function decode($data, $format, array $context = array())
}
fclose($handle);
- if ($context['as_collection'] ?? false) {
+ if ($context[self::AS_COLLECTION_KEY] ?? false) {
return $result;
}
diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
index 7f8d341846f7d..08e5841060dbd 100644
--- a/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
+++ b/src/Symfony/Component/Serializer/Normalizer/AbstractObjectNormalizer.php
@@ -294,7 +294,7 @@ abstract protected function setAttributeValue($object, $attribute, $value, $form
*/
private function validateAndDenormalize(string $currentClass, string $attribute, $data, ?string $format, array $context)
{
- if (null === $this->propertyTypeExtractor || null === $types = $this->propertyTypeExtractor->getTypes($currentClass, $attribute)) {
+ if (null === $types = $this->getTypes($currentClass, $attribute)) {
return $data;
}
@@ -357,6 +357,36 @@ private function validateAndDenormalize(string $currentClass, string $attribute,
throw new NotNormalizableValueException(sprintf('The type of the "%s" attribute for class "%s" must be one of "%s" ("%s" given).', $attribute, $currentClass, implode('", "', array_keys($expectedTypes)), gettype($data)));
}
+ /**
+ * @return Type[]|null
+ */
+ private function getTypes(string $currentClass, string $attribute)
+ {
+ if (null === $this->propertyTypeExtractor) {
+ return null;
+ }
+
+ if (null !== $types = $this->propertyTypeExtractor->getTypes($currentClass, $attribute)) {
+ return $types;
+ }
+
+ if (null !== $this->classDiscriminatorResolver && null !== $discriminatorMapping = $this->classDiscriminatorResolver->getMappingForClass($currentClass)) {
+ if ($discriminatorMapping->getTypeProperty() === $attribute) {
+ return array(
+ new Type(Type::BUILTIN_TYPE_STRING),
+ );
+ }
+
+ foreach ($discriminatorMapping->getTypesMapping() as $mappedClass) {
+ if (null !== $types = $this->propertyTypeExtractor->getTypes($mappedClass, $attribute)) {
+ return $types;
+ }
+ }
+ }
+
+ return null;
+ }
+
/**
* Sets an attribute and apply the name converter if necessary.
*
diff --git a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php
index bf463fe5457d3..77c98377ee70a 100644
--- a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php
+++ b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php
@@ -16,6 +16,7 @@
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
use Symfony\Component\PropertyInfo\PropertyTypeExtractorInterface;
use Symfony\Component\Serializer\Exception\RuntimeException;
+use Symfony\Component\Serializer\Mapping\AttributeMetadata;
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorResolverInterface;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
use Symfony\Component\Serializer\NameConverter\NameConverterInterface;
@@ -131,4 +132,29 @@ protected function setAttributeValue($object, $attribute, $value, $format = null
// Properties not found are ignored
}
}
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getAllowedAttributes($classOrObject, array $context, $attributesAsString = false)
+ {
+ if (false === $allowedAttributes = parent::getAllowedAttributes($classOrObject, $context, $attributesAsString)) {
+ return false;
+ }
+
+ if (null !== $this->classDiscriminatorResolver) {
+ $class = \is_object($classOrObject) ? \get_class($classOrObject) : $classOrObject;
+ if (null !== $discriminatorMapping = $this->classDiscriminatorResolver->getMappingForMappedObject($classOrObject)) {
+ $allowedAttributes[] = $attributesAsString ? $discriminatorMapping->getTypeProperty() : new AttributeMetadata($discriminatorMapping->getTypeProperty());
+ }
+
+ if (null !== $discriminatorMapping = $this->classDiscriminatorResolver->getMappingForClass($class)) {
+ foreach ($discriminatorMapping->getTypesMapping() as $mappedClass) {
+ $allowedAttributes = array_merge($allowedAttributes, parent::getAllowedAttributes($mappedClass, $context, $attributesAsString));
+ }
+ }
+ }
+
+ return $allowedAttributes;
+ }
}
diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php
index d990d51ec75b3..4a0bc8169b03b 100644
--- a/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php
+++ b/src/Symfony/Component/Serializer/Tests/Encoder/CsvEncoderTest.php
@@ -324,7 +324,7 @@ public function testDecodeOnlyOneAsCollection()
a
CSV
- , 'csv', array('as_collection' => true)));
+ , 'csv', array(CsvEncoder::AS_COLLECTION_KEY => true)));
}
public function testDecodeToManyRelation()
diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageInterface.php b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageInterface.php
index f0b4c4d128c38..55bb00bc8e253 100644
--- a/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageInterface.php
+++ b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageInterface.php
@@ -15,8 +15,8 @@
/**
* @DiscriminatorMap(typeProperty="type", mapping={
- * "first"="Symfony\Component\Serializer\Tests\Fixtures\AbstractDummyFirstChild",
- * "second"="Symfony\Component\Serializer\Tests\Fixtures\AbstractDummySecondChild"
+ * "one"="Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberOne",
+ * "two"="Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo"
* })
*
* @author Samuel Roze
diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageNumberOne.php b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageNumberOne.php
index 381f7f8a6c70b..200476b54232d 100644
--- a/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageNumberOne.php
+++ b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageNumberOne.php
@@ -11,10 +11,17 @@
namespace Symfony\Component\Serializer\Tests\Fixtures;
+use Symfony\Component\Serializer\Annotation\Groups;
+
/**
* @author Samuel Roze
*/
class DummyMessageNumberOne implements DummyMessageInterface
{
public $one;
+
+ /**
+ * @Groups({"two"})
+ */
+ public $two;
}
diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageNumberTwo.php b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageNumberTwo.php
new file mode 100644
index 0000000000000..5a24e7c9ff08e
--- /dev/null
+++ b/src/Symfony/Component/Serializer/Tests/Fixtures/DummyMessageNumberTwo.php
@@ -0,0 +1,40 @@
+
+ *
+ * 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;
+
+use Symfony\Component\Serializer\Annotation\Groups;
+
+/**
+ * @author Samuel Roze
+ */
+class DummyMessageNumberTwo implements DummyMessageInterface
+{
+ /**
+ * @Groups({"two"})
+ */
+ public $three;
+
+ /**
+ * @var DummyMessageNumberOne
+ */
+ private $nested;
+
+ public function setNested(DummyMessageNumberOne $nested)
+ {
+ $this->nested = $nested;
+ }
+
+ public function getNested(): DummyMessageNumberOne
+ {
+ return $this->nested;
+ }
+}
diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php
index 7550b3c9b7ba1..743461a727a01 100644
--- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php
+++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php
@@ -11,11 +11,15 @@
namespace Symfony\Component\Serializer\Tests;
+use Doctrine\Common\Annotations\AnnotationReader;
use PHPUnit\Framework\TestCase;
+use Symfony\Component\PropertyInfo\Extractor\ReflectionExtractor;
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorFromClassMetadata;
use Symfony\Component\Serializer\Mapping\ClassDiscriminatorMapping;
use Symfony\Component\Serializer\Mapping\ClassMetadata;
+use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactory;
use Symfony\Component\Serializer\Mapping\Factory\ClassMetadataFactoryInterface;
+use Symfony\Component\Serializer\Mapping\Loader\AnnotationLoader;
use Symfony\Component\Serializer\Normalizer\ArrayDenormalizer;
use Symfony\Component\Serializer\Normalizer\DenormalizerAwareInterface;
use Symfony\Component\Serializer\Normalizer\DenormalizerInterface;
@@ -32,6 +36,7 @@
use Symfony\Component\Serializer\Tests\Fixtures\AbstractDummySecondChild;
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface;
use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberOne;
+use Symfony\Component\Serializer\Tests\Fixtures\DummyMessageNumberTwo;
use Symfony\Component\Serializer\Tests\Fixtures\TraversableDummy;
use Symfony\Component\Serializer\Tests\Fixtures\NormalizableTraversableDummy;
use Symfony\Component\Serializer\Tests\Normalizer\TestNormalizer;
@@ -398,11 +403,9 @@ public function testDeserializeAndSerializeInterfacedObjectsWithTheClassMetadata
$example = new DummyMessageNumberOne();
$example->one = 1;
- $jsonData = '{"message-type":"one","one":1}';
-
- $discriminatorResolver = new ClassDiscriminatorFromClassMetadata($this->metadataFactoryMockForDummyInterface());
- $serializer = new Serializer(array(new ObjectNormalizer(null, null, null, null, $discriminatorResolver)), array('json' => new JsonEncoder()));
+ $jsonData = '{"type":"one","one":1,"two":null}';
+ $serializer = $this->serializerWithClassDiscriminator();
$deserialized = $serializer->deserialize($jsonData, DummyMessageInterface::class, 'json');
$this->assertEquals($example, $deserialized);
@@ -410,51 +413,64 @@ public function testDeserializeAndSerializeInterfacedObjectsWithTheClassMetadata
$this->assertEquals($jsonData, $serialized);
}
+ public function testDeserializeAndSerializeInterfacedObjectsWithTheClassMetadataDiscriminatorResolverAndGroups()
+ {
+ $example = new DummyMessageNumberOne();
+ $example->two = 2;
+
+ $serializer = $this->serializerWithClassDiscriminator();
+ $deserialized = $serializer->deserialize('{"type":"one","one":1,"two":2}', DummyMessageInterface::class, 'json', array(
+ 'groups' => array('two'),
+ ));
+
+ $this->assertEquals($example, $deserialized);
+
+ $serialized = $serializer->serialize($deserialized, 'json', array(
+ 'groups' => array('two'),
+ ));
+
+ $this->assertEquals('{"two":2,"type":"one"}', $serialized);
+ }
+
+ public function testDeserializeAndSerializeNestedInterfacedObjectsWithTheClassMetadataDiscriminator()
+ {
+ $nested = new DummyMessageNumberOne();
+ $nested->one = 'foo';
+
+ $example = new DummyMessageNumberTwo();
+ $example->setNested($nested);
+
+ $serializer = $this->serializerWithClassDiscriminator();
+
+ $serialized = $serializer->serialize($example, 'json');
+ $deserialized = $serializer->deserialize($serialized, DummyMessageInterface::class, 'json');
+
+ $this->assertEquals($example, $deserialized);
+ }
+
/**
* @expectedException \Symfony\Component\Serializer\Exception\RuntimeException
* @expectedExceptionMessage The type "second" has no mapped class for the abstract object "Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface"
*/
public function testExceptionWhenTypeIsNotKnownInDiscriminator()
{
- $discriminatorResolver = new ClassDiscriminatorFromClassMetadata($this->metadataFactoryMockForDummyInterface());
- $serializer = new Serializer(array(new ObjectNormalizer(null, null, null, null, $discriminatorResolver)), array('json' => new JsonEncoder()));
- $serializer->deserialize('{"message-type":"second","one":1}', DummyMessageInterface::class, 'json');
+ $this->serializerWithClassDiscriminator()->deserialize('{"type":"second","one":1}', DummyMessageInterface::class, 'json');
}
/**
* @expectedException \Symfony\Component\Serializer\Exception\RuntimeException
- * @expectedExceptionMessage Type property "message-type" not found for the abstract object "Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface"
+ * @expectedExceptionMessage Type property "type" not found for the abstract object "Symfony\Component\Serializer\Tests\Fixtures\DummyMessageInterface"
*/
public function testExceptionWhenTypeIsNotInTheBodyToDeserialiaze()
{
- $discriminatorResolver = new ClassDiscriminatorFromClassMetadata($this->metadataFactoryMockForDummyInterface());
- $serializer = new Serializer(array(new ObjectNormalizer(null, null, null, null, $discriminatorResolver)), array('json' => new JsonEncoder()));
- $serializer->deserialize('{"one":1}', DummyMessageInterface::class, 'json');
+ $this->serializerWithClassDiscriminator()->deserialize('{"one":1}', DummyMessageInterface::class, 'json');
}
- private function metadataFactoryMockForDummyInterface()
+ private function serializerWithClassDiscriminator()
{
- $factoryMock = $this->getMockBuilder(ClassMetadataFactoryInterface::class)->getMock();
- $factoryMock->method('hasMetadataFor')->will($this->returnValueMap(array(
- array(
- DummyMessageInterface::class,
- true,
- ),
- )));
-
- $factoryMock->method('getMetadataFor')->will($this->returnValueMap(array(
- array(
- DummyMessageInterface::class,
- new ClassMetadata(
- DummyMessageInterface::class,
- new ClassDiscriminatorMapping('message-type', array(
- 'one' => DummyMessageNumberOne::class,
- ))
- ),
- ),
- )));
+ $classMetadataFactory = new ClassMetadataFactory(new AnnotationLoader(new AnnotationReader()));
- return $factoryMock;
+ return new Serializer(array(new ObjectNormalizer($classMetadataFactory, null, null, new ReflectionExtractor(), new ClassDiscriminatorFromClassMetadata($classMetadataFactory))), array('json' => new JsonEncoder()));
}
}
diff --git a/src/Symfony/Component/Translation/Dumper/FileDumper.php b/src/Symfony/Component/Translation/Dumper/FileDumper.php
index 5a67b3a0d29dc..07c38b8291010 100644
--- a/src/Symfony/Component/Translation/Dumper/FileDumper.php
+++ b/src/Symfony/Component/Translation/Dumper/FileDumper.php
@@ -51,7 +51,7 @@ public function setRelativePathTemplate($relativePathTemplate)
*/
public function setBackup($backup)
{
- @trigger_error(sprintf('The %s() method is deprecated since Symfony 4.1.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1.', __METHOD__), E_USER_DEPRECATED);
if (false !== $backup) {
throw new \LogicException('The backup feature is no longer supported.');
diff --git a/src/Symfony/Component/Translation/PluralizationRules.php b/src/Symfony/Component/Translation/PluralizationRules.php
index 48a6c608cbfe2..94d9e4350c3c2 100644
--- a/src/Symfony/Component/Translation/PluralizationRules.php
+++ b/src/Symfony/Component/Translation/PluralizationRules.php
@@ -144,6 +144,7 @@ public static function get($number, $locale)
case 'bs':
case 'hr':
case 'ru':
+ case 'sh':
case 'sr':
case 'uk':
return ((1 == $number % 10) && (11 != $number % 100)) ? 0 : ((($number % 10 >= 2) && ($number % 10 <= 4) && (($number % 100 < 10) || ($number % 100 >= 20))) ? 1 : 2);
diff --git a/src/Symfony/Component/Translation/Writer/TranslationWriter.php b/src/Symfony/Component/Translation/Writer/TranslationWriter.php
index c03ded3c91993..ee35ff63eb61f 100644
--- a/src/Symfony/Component/Translation/Writer/TranslationWriter.php
+++ b/src/Symfony/Component/Translation/Writer/TranslationWriter.php
@@ -43,7 +43,7 @@ public function addDumper($format, DumperInterface $dumper)
*/
public function disableBackup()
{
- @trigger_error(sprintf('The %s() method is deprecated since Symfony 4.1.', __METHOD__), E_USER_DEPRECATED);
+ @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.1.', __METHOD__), E_USER_DEPRECATED);
foreach ($this->dumpers as $dumper) {
if (method_exists($dumper, 'setBackup')) {
diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf
index 85b6970fc31cf..078a25d052d10 100644
--- a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf
+++ b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf
@@ -302,6 +302,10 @@
An empty file is not allowed.
No està permès un fixter buit.
+
+ This is not a valid UUID.
+ Aquest valor no és un UUID vàlid.
+