diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 0bef18db33536..e459d1e55f616 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,6 +2,23 @@ /src/Symfony/Component/Console/Logger/ConsoleLogger.php @dunglas # DependencyInjection /src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @dunglas +# Form +/src/Symfony/Bridge/Twig/Extension/FormExtension.php @xabbuh +/src/Symfony/Bridge/Twig/Form/* @xabbuh +/src/Symfony/Bridge/Twig/Node/FormThemeNode.php @xabbuh +/src/Symfony/Bridge/Twig/Node/RenderBlockNode.php @xabbuh +/src/Symfony/Bridge/Twig/Node/SearchAndRenderBlockNode.php @xabbuh +/src/Symfony/Bridge/Twig/Tests/Extension/FormExtension* @xabbuh +/src/Symfony/Bridge/Twig/Tests/Node/FormThemeTest.php @xabbuh +/src/Symfony/Bridge/Twig/Tests/TokenParser/FormThemeTokenParserTest.php @xabbuh +/src/Symfony/Bridge/Twig/TokenParser/FormThemeTokenParser.php @xabbuh +/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/FormPass.php @xabbuh +/src/Symfony/Bundle/FrameworkBundle/Resources/views/* @xabbuh +/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/FormHelper.php @xabbuh +/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/FormPassTest.php @xabbuh +/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php @xabbuh +/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php @xabbuh +/src/Symfony/Component/Form/* @xabbuh # HttpKernel /src/Symfony/Component/HttpKernel/Log/Logger.php @dunglas # LDAP diff --git a/.travis.yml b/.travis.yml index 0cc2e3acbb3af..b279eac0215a8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -13,7 +13,6 @@ addons: - slapd - zookeeperd - libzookeeper-mt-dev - - libsasl2-dev env: global: @@ -50,6 +49,7 @@ before_install: sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 6B05F25D762E3157 sudo add-apt-repository -y ppa:ondrej/php sudo apt update + sudo apt install -y librabbitmq-dev libsodium-dev - | # Start Redis cluster @@ -153,8 +153,6 @@ before_install: phpenv global $PHP INI=~/.phpenv/versions/$PHP/etc/conf.d/travis.ini if ! php --ri sodium > /dev/null; then - # install libsodium - sudo apt-get install libsodium-dev -y tfold ext.libsodium tpecl libsodium sodium.so $INI fi @@ -162,23 +160,7 @@ before_install: tfold ext.mongodb tpecl mongodb-1.6.0alpha1 mongodb.so $INI tfold ext.igbinary tpecl igbinary-2.0.8 igbinary.so $INI tfold ext.zookeeper tpecl zookeeper-0.6.0 zookeeper.so $INI - - if [[ $PHP != 7.3 ]]; then - wget http://ftp.debian.org/debian/pool/main/libr/librabbitmq/librabbitmq-dev_0.5.2-2_amd64.deb - wget http://ftp.debian.org/debian/pool/main/libr/librabbitmq/librabbitmq1_0.5.2-2_amd64.deb - sudo dpkg -i librabbitmq1_0.5.2-2_amd64.deb librabbitmq-dev_0.5.2-2_amd64.deb - tfold ext.amqp tpecl amqp-1.9.3 amqp.so $INI - else - sudo apt install -y librabbitmq-dev - git clone https://github.com/pdezwart/php-amqp.git - cd php-amqp - phpize - ./configure - make - sudo make install - cd - - echo extension = amqp.so >> $INI - fi + tfold ext.amqp tpecl amqp-1.9.4 amqp.so $INI done - | diff --git a/CHANGELOG-4.2.md b/CHANGELOG-4.2.md index 96994ff62024a..bf1520b310051 100644 --- a/CHANGELOG-4.2.md +++ b/CHANGELOG-4.2.md @@ -7,6 +7,51 @@ in 4.2 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v4.2.0...v4.2.1 +* 4.2.4 (2019-03-03) + + * bug #30383 [WebProfilerBundle] toolbar: invisible route name in Firefox (inmarelibero) + * bug #26532 [HttpKernel] Correctly merging cache directives in HttpCache/ResponseCacheStrategy (aschempp) + * bug #30363 Fixed the DebugClassLoader compatibility with eval()'d code on Darwin (skalpa) + * bug #30329 [Form] IntegerType: reject submitted non-integer numbers (xabbuh) + * bug #30331 [Cache] fix warming up cache.system and apcu (nicolas-grekas) + * bug #30347 [Security] Change FormAuthenticator if condition (PReimers) + * bug #30354 [Console] handles multi-byte characters in autocomplete (jls-esokia) + * bug #30351 Fix getItems() performance issue with RedisCluster (php-redis) (andrerom) + * bug #30350 [VarDumper] Keep a ref to objects to ensure their handle cannot be reused while cloning (nicolas-grekas) + * bug #30327 [HttpKernel] Fix possible infinite loop of exceptions (enumag) + * bug #27601 [Routing] fix URL generation with look-around requirements (nasimnabavi) + * bug #30277 [Console] Prevent ArgvInput::getFirstArgument() from returning an option value (chalasr) + * bug #29981 [Security] Complain about an empty decision strategy (corphi) + * bug #29822 [EventDispatcher] Fix unknown priority (ro0NL) + * bug #30324 [Validator] Fixed duplicate UUID (ralfkuehnel) + * bug #30265 [Form] do not validate non-submitted form fields in PATCH requests (xabbuh) + * bug #30313 Avoid mutating the Finder when building the iterator (stof) + * bug #30294 [FrameworkBundle] Fix Descriptor throwing on non existent parent (GuilhemN) + * bug #30271 [Console] Fix command testing with missing user inputs (chalasr) + * bug #30278 Remove unnecessary ProgressBar stdout writes (fixes flickering) (ostrolucky) + * bug #30274 [VarDumper] fix serializing Stub instances (nicolas-grekas) + * bug #30273 [Validator] Added missing use statement for UnexpectedTypeException (devrck) + * bug #30247 Don't resolve the Deprecation error handler mode until a deprecation is triggered (ossinkine) + * bug #30264 [Debug][ErrorHandler] Preserve next error handler (fancyweb) + * bug #30245 fix lost namespace in eval (fizzka) + * bug #30090 [FrameworkBundle] add constraint validators before optimizations (xabbuh) + * feature #30126 [Form] forward valid numeric values to transform() (xabbuh) + * bug #30122 [Security] fix switch user without having current token (Antoine Lamirault) + * bug #30136 use PropertyAccessorInterface instead of PropertyAccessor (nick-zh) + * bug #30124 Fix KernelTestCase compatibility for PhpUnit 8 (bis) (nicolas-grekas) + * bug #30061 [Form] render integer types with grouping as text input (xabbuh) + * bug #30063 [Form] don't lose int precision with not needed type casts (xabbuh) + * bug #30076 [Form] ignore _method forms in NativeRequestHandler (xabbuh) + * bug #30084 Fix KernelTestCase compatibility for PhpUnit 8 (alexander-schranz) + * bug #30093 [DependencyInjection] add $lazyLoad context to the generated code for lazy non-shared service by PhpDumper (XuruDragon) + * bug #30102 [Workflow] Graphviz dumper escape not always a string (Korbeil) + * bug #29884 [Form] CsrfValidationListener marks the token as invalid if it is not a string (umpirsky) + * bug #30058 [Routing] fix perf issue when dumping large number of routes (nicolas-grekas) + * bug #30062 [Form] do not overwrite the constraint being evaluated (xabbuh) + * bug #30074 Fix wrong value in file id attribute for Xliff 2.0 (deguif) + * bug #30078 [Messenger] Fix DataCollector template (ottaviano) + * bug #30087 [PhpUnitBridge] fix PHP 5.3 compat (nicolas-grekas) + * 4.2.3 (2019-02-03) * bug #30050 [Cache] fix pruning pdo cache for vendors that throw on execute (bendavies) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 877cf0c796408..b6b40057db1df 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -10,15 +10,15 @@ Symfony is the result of the work of many people who made the code better - Christian Flothmann (xabbuh) - Tobias Schultze (tobion) - Christophe Coevoet (stof) + - Robin Chalas (chalas_r) - Jordi Boggiano (seldaek) - Victor Berchet (victor) - - Robin Chalas (chalas_r) - Kévin Dunglas (dunglas) - Maxime Steinhausser (ogizanagi) - Jakub Zalas (jakubzalas) - Johannes S (johannes) - - Kris Wallsmith (kriswallsmith) - Ryan Weaver (weaverryan) + - Kris Wallsmith (kriswallsmith) - Javier Eguiluz (javier.eguiluz) - Roland Franssen (ro0) - Grégoire Pineau (lyrixx) @@ -61,14 +61,14 @@ Symfony is the result of the work of many people who made the code better - Kevin Bond (kbond) - Pierre du Plessis (pierredup) - Henrik Bjørnskov (henrikbjorn) + - Alexander M. Turek (derrabus) - Miha Vrhovnik - Diego Saint Esteben (dii3g0) - - Alexander M. Turek (derrabus) - Konstantin Kudryashov (everzet) - Bilal Amarni (bamarni) + - Mathieu Piot (mpiot) - Florin Patan (florinpatan) - Gábor Egyed (1ed) - - Mathieu Piot (mpiot) - Titouan Galopin (tgalopin) - Vladimir Reznichenko (kalessil) - Michel Weimerskirch (mweimerskirch) @@ -82,11 +82,11 @@ Symfony is the result of the work of many people who made the code better - Issei Murasawa (issei_m) - Arnout Boks (aboks) - Deni + - Grégoire Paris (greg0ire) - Henrik Westphal (snc) - Dariusz Górecki (canni) - - Douglas Greenshields (shieldo) - - Grégoire Paris (greg0ire) - Valentin Udaltsov (vudaltsov) + - Douglas Greenshields (shieldo) - Dariusz Ruminski - Lee McDermott - Brandon Turner @@ -109,12 +109,13 @@ Symfony is the result of the work of many people who made the code better - Brice BERNARD (brikou) - Baptiste Clavié (talus) - marc.weistroff + - Tomáš Votruba (tomas_votruba) - David Buchmann (dbu) - lenar - Alexander Schwenn (xelaris) - Włodzimierz Gajda (gajdaw) - Chris Wilkinson (thewilkybarkid) - - Tomáš Votruba (tomas_votruba) + - Jérôme Vasseur (jvasseur) - Peter Kokot (maastermedia) - Jacob Dreesen (jdreesen) - Florian Voutzinos (florianv) @@ -124,7 +125,6 @@ Symfony is the result of the work of many people who made the code better - Daniel Wehner (dawehner) - excelwebzone - Gordon Franke (gimler) - - Jérôme Vasseur (jvasseur) - Javier Spagnoletti (phansys) - Fabien Pennequin (fabienpennequin) - Eric GELOEN (gelo) @@ -144,6 +144,7 @@ Symfony is the result of the work of many people who made the code better - Daniel Gomes (danielcsgomes) - Gabriel Caruso - Hidenori Goto (hidenorigoto) + - Thomas Calvet (fancyweb) - Arnaud Kleinpeter (nanocom) - Jannik Zschiesche (apfelbox) - Guilherme Blanco (guilhermeblanco) @@ -175,6 +176,7 @@ Symfony is the result of the work of many people who made the code better - Amal Raghav (kertz) - Jonathan Ingram (jonathaningram) - Artur Kotyrba + - Tyson Andre - GDIBass - SpacePossum - jeremyFreeAgent (Jérémy Romey) (jeremyfreeagent) @@ -182,7 +184,6 @@ Symfony is the result of the work of many people who made the code better - Matthieu Napoli (mnapoli) - Florent Mata (fmata) - Warnar Boekkooi (boekkooi) - - Thomas Calvet (fancyweb) - Dmitrii Chekaliuk (lazyhammer) - Clément JOBEILI (dator) - Daniel Espendiller @@ -198,6 +199,7 @@ Symfony is the result of the work of many people who made the code better - Mathieu Lemoine (lemoinem) - Christian Schmidt - Andreas Hucks (meandmymonkey) + - Tom Van Looy (tvlooy) - Noel Guilbert (noel) - Yanick Witschi (toflar) - Marek Štípek (maryo) @@ -205,6 +207,7 @@ Symfony is the result of the work of many people who made the code better - bronze1man - sun (sun) - Larry Garfield (crell) + - George Mponos (gmponos) - Michaël Perrin (michael.perrin) - Nikolay Labinskiy (e-moe) - Martin Schuhfuß (usefulthink) @@ -227,17 +230,16 @@ Symfony is the result of the work of many people who made the code better - Justin Hileman (bobthecow) - Blanchon Vincent (blanchonvincent) - Michele Orselli (orso) - - Tom Van Looy (tvlooy) - Sven Paulus (subsven) - Rui Marinho (ruimarinho) - Eugene Wissner - Pascal Montoya - - George Mponos (gmponos) - Julien Brochet (mewt) - Leo Feyer - Tristan Darricau (nicofuma) - Marcel Beerta (mazen) - Pavel Batanov (scaytrase) + - Samuel NELA (snela) - Loïc Faugeron - Hidde Wieringa (hiddewie) - Marco Pivetta (ocramius) @@ -282,7 +284,6 @@ Symfony is the result of the work of many people who made the code better - GordonsLondon - Jan Sorgalla (jsor) - Ray - - Tyson Andre - Chekote - Thomas Adam - Viktor Bocharskyi (bocharsky_bw) @@ -290,7 +291,6 @@ Symfony is the result of the work of many people who made the code better - Diego Agulló (aeoris) - Andreas Schempp (aschempp) - jdhoek - - Samuel NELA (snela) - Massimiliano Arione (garak) - Bob den Otter (bopp) - Frank de Jonge (frenkynet) @@ -301,6 +301,7 @@ Symfony is the result of the work of many people who made the code better - Colin O'Dell (colinodell) - Giorgio Premi - Jan Schädlich (jschaedl) + - Ben Davies (bendavies) - Beau Simensen (simensen) - Michael Hirschler (mvhirsch) - Robert Kiss (kepten) @@ -313,6 +314,7 @@ Symfony is the result of the work of many people who made the code better - Peter Kruithof (pkruithof) - Michael Holm (hollo) - Remon van de Kamp (rpkamp) + - Mathieu Lechat - Marc Weistroff (futurecat) - Christian Schmidt - MatTheCat @@ -356,7 +358,6 @@ Symfony is the result of the work of many people who made the code better - Ricard Clau (ricardclau) - Mark Challoner (markchalloner) - Gennady Telegin (gtelegin) - - Ben Davies (bendavies) - Erin Millard - Artur Melo (restless) - Matthew Lewinski (lewinski) @@ -379,11 +380,11 @@ Symfony is the result of the work of many people who made the code better - Felix Labrecque - Yaroslav Kiliba - Terje Bråten - - Mathieu Lechat - Robbert Klarenbeek (robbertkl) - JhonnyL - David Badura (davidbadura) - hossein zolfi (ocean) + - Alexander Schranz (alexander-schranz) - Clément Gautier (clementgautier) - Sanpi - Eduardo Gulias (egulias) @@ -483,7 +484,6 @@ Symfony is the result of the work of many people who made the code better - Marek Pietrzak - Luc Vieillescazes (iamluc) - franek (franek) - - Alexander Schranz (alexander-schranz) - Christian Wahler - Gintautas Miselis - Rob Bast @@ -606,6 +606,7 @@ Symfony is the result of the work of many people who made the code better - Sebastian Blum - aubx - Marvin Butkereit + - Renan - Ricky Su (ricky) - Gildas Quéméner (gquemener) - Charles-Henri Bruyand @@ -675,6 +676,7 @@ Symfony is the result of the work of many people who made the code better - Michael Devery (mickadoo) - Antoine Corcy - Sascha Grossenbacher + - Emanuele Panzeri (thepanz) - Szijarto Tamas - Robin Lehrmann (robinlehrmann) - Catalin Dan @@ -713,6 +715,7 @@ Symfony is the result of the work of many people who made the code better - Mark Sonnabaum - Massimiliano Braglia (massimilianobraglia) - Richard Quadling + - Raphaëll Roussel - jochenvdv - Arturas Smorgun (asarturas) - Alexander Volochnev (exelenz) @@ -731,6 +734,7 @@ Symfony is the result of the work of many people who made the code better - Pascal Helfenstein - Anthony GRASSIOT (antograssiot) - Baldur Rensch (brensch) + - Anthony MARTIN (xurudragon) - Pierre Rineau - Vladyslav Petrovych - Alex Xandra Albert Sim @@ -738,6 +742,7 @@ Symfony is the result of the work of many people who made the code better - Sergey Yastrebov - Trent Steel (trsteel88) - Yuen-Chi Lian + - Tarjei Huse (tarjei) - Besnik Br - Jose Gonzalez - Oleksii Zhurbytskyi @@ -764,6 +769,7 @@ Symfony is the result of the work of many people who made the code better - John Bohn (jbohn) - Marc Morera (mmoreram) - Saif Eddin Gmati (azjezz) + - Stadly - Andrew Hilobok (hilobok) - Noah Heck (myesain) - Christian Soronellas (theunic) @@ -853,6 +859,7 @@ Symfony is the result of the work of many people who made the code better - Jelle Kapitein - Benoît Bourgeois - mantulo + - Stefan Kruppa - corphi - grizlik - Derek ROTH @@ -885,6 +892,7 @@ Symfony is the result of the work of many people who made the code better - Forfarle (forfarle) - Harry Walter (haswalt) - Johnson Page (jwpage) + - Michael Käfer (michael_kaefer) - Ruben Gonzalez (rubenruateltek) - Michael Roterman (wtfzdotnet) - Arno Geurts @@ -950,6 +958,7 @@ Symfony is the result of the work of many people who made the code better - Franz Wilding (killerpoke) - ProgMiner - Oleg Golovakhin (doc_tr) + - Joost van Driel - Icode4Food (icode4food) - Radosław Benkel - kevin.nadin @@ -996,6 +1005,7 @@ Symfony is the result of the work of many people who made the code better - Wojciech Sznapka - Gavin Staniforth - Ariel J. Birnbaum + - Pablo Borowicz - Mathieu Santostefano - Arjan Keeman - Máximo Cuadros (mcuadros) @@ -1031,6 +1041,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) + - MARYNICH Mikhail (mmarynich-ext) - Viktor Novikov (panzer_commander) - Paul Mitchum (paul-m) - Angel Koilov (po_taka) @@ -1085,6 +1096,7 @@ Symfony is the result of the work of many people who made the code better - Andrew Tch - Alexander Cheprasov - Rodrigo Díez Villamuera (rodrigodiez) + - James Hudson - e-ivanov - Einenlum - Jochen Bayer (jocl) @@ -1095,6 +1107,7 @@ Symfony is the result of the work of many people who made the code better - wizhippo - Mathias STRASSER (roukmoute) - Thomason, James + - Gordienko Vladislav - Viacheslav Sychov - Alexandre Quercia (alquerci) - Helmut Hummel (helhum) @@ -1157,7 +1170,6 @@ Symfony is the result of the work of many people who made the code better - Vacheslav Silyutin - Juan Traverso - Alain Flaus (halundra) - - Tarjei Huse (tarjei) - tsufeki - Philipp Strube - Clement Herreman (clemherreman) @@ -1240,6 +1252,7 @@ Symfony is the result of the work of many people who made the code better - Berat Doğan - Guillaume LECERF - Juanmi Rodriguez Cerón + - renanbr - Andy Raines - Anthony Ferrara - Geoffrey Pécro (gpekz) @@ -1290,7 +1303,6 @@ Symfony is the result of the work of many people who made the code better - WedgeSama - Felds Liscia - Chihiro Adachi (chihiro-adachi) - - Emanuele Panzeri (thepanz) - Raphaëll Roussel - Tadcka - Beth Binkovitz @@ -1404,6 +1416,7 @@ Symfony is the result of the work of many people who made the code better - Gavin Staniforth - Alessandro Tagliapietra (alex88) - Biji (biji) + - Alex Teterin (errogaht) - Gunnar Lium (gunnarlium) - Tiago Garcia (tiagojsag) - Artiom @@ -1446,6 +1459,7 @@ Symfony is the result of the work of many people who made the code better - Paul Seiffert (seiffert) - Vasily Khayrulin (sirian) - Stefan Koopmanschap (skoop) + - Stas Soroka (stasyan) - Stefan Hüsges (tronsha) - Jake Bishop (yakobeyak) - Dan Blows @@ -1546,6 +1560,7 @@ Symfony is the result of the work of many people who made the code better - Muhammed Akbulut - Aaron Somi - Michał Dąbrowski (defrag) + - Konstantin Grachev (grachevko) - Simone Fumagalli (hpatoio) - Brian Graham (incognito) - Kevin Vergauwen (innocenzo) @@ -1635,6 +1650,7 @@ Symfony is the result of the work of many people who made the code better - Darryl Hein (xmmedia) - Sadicov Vladimir (xtech) - Kevin EMO (zarcox) + - Andrzej - Alexander Zogheb - Rémi Blaise - Nicolas Séverin @@ -1869,6 +1885,7 @@ Symfony is the result of the work of many people who made the code better - Şəhriyar İmanov - Alexis BOYER - Kaipi Yann + - adam-mospan - Sam Williams - Guillaume Aveline - Adrian Philipp @@ -1906,7 +1923,6 @@ Symfony is the result of the work of many people who made the code better - Shude - Ondřej Führer - Sema - - Michael Käfer - Elan Ruusamäe - Thorsten Hallwas - Michael Squires @@ -2074,9 +2090,9 @@ Symfony is the result of the work of many people who made the code better - drublic - Andreas Streichardt - Pascal Hofmann - - Stefan Kruppa - smokeybear87 - Gustavo Adrian + - damaya - Kevin Weber - Ben Scott - Dionysis Arvanitis diff --git a/UPGRADE-4.0.md b/UPGRADE-4.0.md index 23ed6fbd33534..8947744a9f180 100644 --- a/UPGRADE-4.0.md +++ b/UPGRADE-4.0.md @@ -230,7 +230,7 @@ DependencyInjection supported. * The ``strict`` attribute in service arguments has been removed. - The attribute is ignored since 3.0, so you can simply remove it. + The attribute is ignored since 3.0, you can remove it. * Top-level anonymous services in XML are no longer supported. diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterMappingsPass.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterMappingsPass.php index 5c33f71f0446d..5b1d78fbf82c8 100644 --- a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterMappingsPass.php +++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterMappingsPass.php @@ -24,8 +24,8 @@ * The compiler pass is meant to register the mappings with the metadata * chain driver corresponding to one of the object managers. * - * For concrete implementations that are easy to use, see the - * RegisterXyMappingsPass classes in the DoctrineBundle resp. + * For concrete implementations, see the RegisterXyMappingsPass classes + * in the DoctrineBundle resp. * DoctrineMongodbBundle, DoctrineCouchdbBundle and DoctrinePhpcrBundle. * * @author David Buchmann diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php index d9f7f391d2f2c..49dfd9bfbce6e 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php @@ -165,7 +165,7 @@ protected function getMetadata($class) // normalize class name $class = self::getRealClass(ltrim($class, '\\')); - if (array_key_exists($class, $this->cache)) { + if (\array_key_exists($class, $this->cache)) { return $this->cache[$class]; } diff --git a/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php b/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php index 769e9bb20e02f..20f68399571f9 100644 --- a/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php +++ b/src/Symfony/Bridge/Doctrine/Security/User/EntityUserProvider.php @@ -20,7 +20,7 @@ /** * Wrapper around a Doctrine ObjectManager. * - * Provides easy to use provisioning for Doctrine entity users. + * Provides provisioning for Doctrine entity users. * * @author Fabien Potencier * @author Johannes M. Schmitt diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypePerformanceTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypePerformanceTest.php index afdeb5f720e27..5012171542f7b 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypePerformanceTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypePerformanceTest.php @@ -30,6 +30,8 @@ class EntityTypePerformanceTest extends FormPerformanceTestCase */ private $em; + protected static $supportedFeatureSetVersion = 304; + protected function getExtensions() { $manager = $this->getMockBuilder('Doctrine\Common\Persistence\ManagerRegistry')->getMock(); diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php index 2869c2b804c4c..1cb59c38436ef 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/Type/EntityTypeTest.php @@ -57,6 +57,8 @@ class EntityTypeTest extends BaseTypeTest */ private $emRegistry; + protected static $supportedFeatureSetVersion = 304; + protected function setUp() { $this->em = DoctrineTestHelper::createTestEntityManager(); diff --git a/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/HttpCodeActivationStrategy.php b/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/HttpCodeActivationStrategy.php index b31817d76d515..ae8fd3650a36b 100644 --- a/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/HttpCodeActivationStrategy.php +++ b/src/Symfony/Bridge/Monolog/Handler/FingersCrossed/HttpCodeActivationStrategy.php @@ -31,10 +31,10 @@ class HttpCodeActivationStrategy extends ErrorLevelActivationStrategy public function __construct(RequestStack $requestStack, array $exclusions, $actionLevel) { foreach ($exclusions as $exclusion) { - if (!array_key_exists('code', $exclusion)) { + if (!\array_key_exists('code', $exclusion)) { throw new \LogicException(sprintf('An exclusion must have a "code" key')); } - if (!array_key_exists('urls', $exclusion)) { + if (!\array_key_exists('urls', $exclusion)) { throw new \LogicException(sprintf('An exclusion must have a "urls" key')); } } diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php index d18e161dd9079..3b71124eb8e2e 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php @@ -98,15 +98,15 @@ public static function register($mode = 0) 'legacyCount' => 0, 'otherCount' => 0, 'remaining vendorCount' => 0, - 'unsilenced' => [], - 'remaining' => [], - 'legacy' => [], - 'other' => [], - 'remaining vendor' => [], + 'unsilenced' => array(), + 'remaining' => array(), + 'legacy' => array(), + 'other' => array(), + 'remaining vendor' => array(), ]; - $deprecationHandler = function ($type, $msg, $file, $line, $context = []) use (&$deprecations, $getMode, $UtilPrefix, $inVendors) { + $deprecationHandler = function ($type, $msg, $file, $line, $context = array()) use (&$deprecations, $getMode, $UtilPrefix, $inVendors) { $mode = $getMode(); - if ((E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) || self::MODE_DISABLED === $mode) { + if ((E_USER_DEPRECATED !== $type && E_DEPRECATED !== $type) || DeprecationErrorHandler::MODE_DISABLED === $mode) { $ErrorHandler = $UtilPrefix.'ErrorHandler'; return $ErrorHandler::handleError($type, $msg, $file, $line, $context); diff --git a/src/Symfony/Bridge/PhpUnit/composer.json b/src/Symfony/Bridge/PhpUnit/composer.json index 4d72603eb452f..c629e8719b5ab 100644 --- a/src/Symfony/Bridge/PhpUnit/composer.json +++ b/src/Symfony/Bridge/PhpUnit/composer.json @@ -21,8 +21,7 @@ "php": ">=5.3.3" }, "suggest": { - "symfony/debug": "For tracking deprecated interfaces usages at runtime with DebugClassLoader", - "ext-zip": "Zip support is required when using bin/simple-phpunit" + "symfony/debug": "For tracking deprecated interfaces usages at runtime with DebugClassLoader" }, "conflict": { "phpunit/phpunit": "<4.8.35|<5.4.3,>=5.0" diff --git a/src/Symfony/Bridge/Twig/DataCollector/TwigDataCollector.php b/src/Symfony/Bridge/Twig/DataCollector/TwigDataCollector.php index c9611e3761654..800d86c20ef0f 100644 --- a/src/Symfony/Bridge/Twig/DataCollector/TwigDataCollector.php +++ b/src/Symfony/Bridge/Twig/DataCollector/TwigDataCollector.php @@ -16,6 +16,7 @@ use Symfony\Component\HttpKernel\DataCollector\DataCollector; use Symfony\Component\HttpKernel\DataCollector\LateDataCollectorInterface; use Twig\Environment; +use Twig\Error\LoaderError; use Twig\Markup; use Twig\Profiler\Dumper\HtmlDumper; use Twig\Profiler\Profile; @@ -70,7 +71,7 @@ public function lateCollect() if ($profile->isTemplate()) { try { $template = $this->twig->load($name = $profile->getName()); - } catch (\Twig_Error_Loader $e) { + } catch (LoaderError $e) { $template = null; } diff --git a/src/Symfony/Bridge/Twig/NodeVisitor/Scope.php b/src/Symfony/Bridge/Twig/NodeVisitor/Scope.php index d5bcfa8b8fceb..642623f2a693c 100644 --- a/src/Symfony/Bridge/Twig/NodeVisitor/Scope.php +++ b/src/Symfony/Bridge/Twig/NodeVisitor/Scope.php @@ -77,7 +77,7 @@ public function set($key, $value) */ public function has($key) { - if (array_key_exists($key, $this->data)) { + if (\array_key_exists($key, $this->data)) { return true; } @@ -98,7 +98,7 @@ public function has($key) */ public function get($key, $default = null) { - if (array_key_exists($key, $this->data)) { + if (\array_key_exists($key, $this->data)) { return $this->data[$key]; } diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php index 7d063614e7a29..3bf3d5ed41359 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/AbstractBootstrap3LayoutTest.php @@ -16,6 +16,8 @@ abstract class AbstractBootstrap3LayoutTest extends AbstractLayoutTest { + protected static $supportedFeatureSetVersion = 304; + public function testLabelOnForm() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\DateType'); @@ -1900,6 +1902,22 @@ public function testInteger() ); } + public function testIntegerTypeWithGroupingRendersAsTextInput() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\IntegerType', 123, [ + 'grouping' => true, + ]); + + $this->assertWidgetMatchesXpath($form->createView(), ['attr' => ['class' => 'my&class']], +'/input + [@type="text"] + [@name="name"] + [@class="my&class form-control"] + [@value="123"] +' + ); + } + public function testLanguage() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\LanguageType', 'de'); diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php index 330b8e70fa7fc..f8a8e45e8ff59 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php @@ -31,6 +31,8 @@ class FormExtensionDivLayoutTest extends AbstractDivLayoutTest */ private $renderer; + protected static $supportedFeatureSetVersion = 304; + protected function setUp() { parent::setUp(); diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php index 0b712562a98c7..ed8db234ad8c9 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionTableLayoutTest.php @@ -30,6 +30,8 @@ class FormExtensionTableLayoutTest extends AbstractTableLayoutTest */ private $renderer; + protected static $supportedFeatureSetVersion = 304; + protected function setUp() { parent::setUp(); diff --git a/src/Symfony/Bridge/Twig/Tests/Node/TransNodeTest.php b/src/Symfony/Bridge/Twig/Tests/Node/TransNodeTest.php index 6bb2ab6d43abf..f974f08580360 100644 --- a/src/Symfony/Bridge/Twig/Tests/Node/TransNodeTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Node/TransNodeTest.php @@ -50,7 +50,7 @@ protected function getVariableGetterWithoutStrictCheck($name) protected function getVariableGetterWithStrictCheck($name) { if (Environment::MAJOR_VERSION >= 2) { - return sprintf('(isset($context["%s"]) || array_key_exists("%1$s", $context) ? $context["%1$s"] : (function () { throw new Twig_Error_Runtime(\'Variable "%1$s" does not exist.\', 0, $this->source); })())', $name); + return sprintf('(isset($context["%1$s"]) || array_key_exists("%1$s", $context) ? $context["%1$s"] : (function () { throw new %2$s(\'Variable "%1$s" does not exist.\', 0, $this->source); })())', $name, Environment::VERSION_ID >= 20700 ? 'RuntimeError' : 'Twig_Error_Runtime'); } return sprintf('($context["%s"] ?? $this->getContext($context, "%1$s"))', $name); diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index ec231764f8012..24034230f8f49 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -24,7 +24,7 @@ "symfony/asset": "~3.4|~4.0", "symfony/dependency-injection": "~3.4|~4.0", "symfony/finder": "~3.4|~4.0", - "symfony/form": "^4.2.3", + "symfony/form": "^4.2.4", "symfony/http-foundation": "~3.4|~4.0", "symfony/http-kernel": "~3.4|~4.0", "symfony/polyfill-intl-icu": "~1.0", @@ -43,7 +43,7 @@ }, "conflict": { "symfony/console": "<3.4", - "symfony/form": "<4.2.3", + "symfony/form": "<4.2.4", "symfony/translation": "<4.2" }, "suggest": { diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php index a4a10805f677a..7d3373f3ebbf8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php @@ -138,7 +138,7 @@ private function getConfigForPath(array $config, string $path, string $alias) $steps = explode('.', $path); foreach ($steps as $step) { - if (!array_key_exists($step, $config)) { + if (!\array_key_exists($step, $config)) { throw new LogicException(sprintf('Unable to find configuration for "%s.%s"', $alias, $path)); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php index d2afe921ff104..484ca4fefd8c2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/Descriptor.php @@ -11,6 +11,7 @@ namespace Symfony\Bundle\FrameworkBundle\Console\Descriptor; +use Symfony\Component\Config\Resource\ClassExistenceResource; use Symfony\Component\Console\Descriptor\DescriptorInterface; use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\DependencyInjection\Alias; @@ -226,7 +227,7 @@ protected function resolveServiceDefinition(ContainerBuilder $builder, $serviceI return $builder->getDefinition($serviceId); } - // Some service IDs don't have a Definition, they're simply an Alias + // Some service IDs don't have a Definition, they're aliases if ($builder->hasAlias($serviceId)) { return $builder->getAlias($serviceId); } @@ -292,6 +293,11 @@ public static function getClassDescription(string $class, string &$resolvedClass { $resolvedClass = $class; try { + $resource = new ClassExistenceResource($class, false); + + // isFresh() will explode ONLY if a parent class/trait does not exist + $resource->isFresh(0); + $r = new \ReflectionClass($class); $resolvedClass = $r->name; diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php index 06d57dcdb24da..44fae86bc05a7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php @@ -156,7 +156,7 @@ protected function describeContainerAlias(Alias $alias, array $options = [], Con */ protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = []) { - $this->writeData($this->getEventDispatcherListenersData($eventDispatcher, array_key_exists('event', $options) ? $options['event'] : null), $options); + $this->writeData($this->getEventDispatcherListenersData($eventDispatcher, \array_key_exists('event', $options) ? $options['event'] : null), $options); } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php index 89180c03ca5b1..56e11b07f6aba 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php @@ -274,7 +274,7 @@ protected function describeContainerParameter($parameter, array $options = []) */ protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = []) { - $event = array_key_exists('event', $options) ? $options['event'] : null; + $event = \array_key_exists('event', $options) ? $options['event'] : null; $title = 'Registered listeners'; if (null !== $event) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index 79566a1ad97a8..c0ec5e412e616 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -385,7 +385,7 @@ protected function describeContainerParameter($parameter, array $options = []) */ protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = []) { - $event = array_key_exists('event', $options) ? $options['event'] : null; + $event = \array_key_exists('event', $options) ? $options['event'] : null; if (null !== $event) { $title = sprintf('Registered Listeners for "%s" Event', $event); diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php index d66a081aabaa0..3e66b05d0ba81 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php @@ -112,7 +112,7 @@ protected function describeContainerAlias(Alias $alias, array $options = [], Con */ protected function describeEventDispatcherListeners(EventDispatcherInterface $eventDispatcher, array $options = []) { - $this->writeDocument($this->getEventDispatcherListenersDocument($eventDispatcher, array_key_exists('event', $options) ? $options['event'] : null)); + $this->writeDocument($this->getEventDispatcherListenersDocument($eventDispatcher, \array_key_exists('event', $options) ? $options['event'] : null)); } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 4f5e1a1dcc316..5a2aebc2eda42 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -327,7 +327,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) } foreach ($places as $name => $place) { - if (\is_array($place) && array_key_exists('name', $place)) { + if (\is_array($place) && \array_key_exists('name', $place)) { continue; } $place['name'] = $name; @@ -365,7 +365,7 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) } foreach ($transitions as $name => $transition) { - if (\is_array($transition) && array_key_exists('name', $transition)) { + if (\is_array($transition) && \array_key_exists('name', $transition)) { continue; } $transition['name'] = $name; diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 87ce95e44bc13..b786923b8e045 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -919,7 +919,7 @@ private function registerAssetsConfiguration(array $config, ContainerBuilder $co foreach ($config['packages'] as $name => $package) { if (null !== $package['version_strategy']) { $version = new Reference($package['version_strategy']); - } elseif (!array_key_exists('version', $package) && null === $package['json_manifest_path']) { + } elseif (!\array_key_exists('version', $package) && null === $package['json_manifest_path']) { // if neither version nor json_manifest_path are specified, use the default $version = $defaultVersion; } else { @@ -1117,7 +1117,7 @@ private function registerValidationConfiguration(array $config, ContainerBuilder $definition = $container->findDefinition('validator.email'); $definition->replaceArgument(0, $config['email_validation_mode']); - if (array_key_exists('enable_annotations', $config) && $config['enable_annotations']) { + if (\array_key_exists('enable_annotations', $config) && $config['enable_annotations']) { if (!$this->annotationsConfigEnabled) { throw new \LogicException('"enable_annotations" on the validator cannot be set as Annotations support is disabled.'); } @@ -1125,7 +1125,7 @@ private function registerValidationConfiguration(array $config, ContainerBuilder $validatorBuilder->addMethodCall('enableAnnotationMapping', [new Reference('annotation_reader')]); } - if (array_key_exists('static_method', $config) && $config['static_method']) { + if (\array_key_exists('static_method', $config) && $config['static_method']) { foreach ($config['static_method'] as $methodName) { $validatorBuilder->addMethodCall('addMethodMapping', [$methodName]); } diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 999f4aed36f96..166122c03cf78 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -95,7 +95,7 @@ public function build(ContainerBuilder $container) // but as late as possible to get resolved parameters $container->addCompilerPass((new RegisterListenersPass())->setHotPathEvents($hotPathEvents), PassConfig::TYPE_BEFORE_REMOVING); $container->addCompilerPass(new TemplatingPass()); - $this->addCompilerPassIfExists($container, AddConstraintValidatorsPass::class, PassConfig::TYPE_BEFORE_REMOVING); + $this->addCompilerPassIfExists($container, AddConstraintValidatorsPass::class); $container->addCompilerPass(new AddAnnotationsCachedReaderPass(), PassConfig::TYPE_AFTER_REMOVING, -255); $this->addCompilerPassIfExists($container, AddValidatorInitializersPass::class); $this->addCompilerPassIfExists($container, AddConsoleCommandPass::class, PassConfig::TYPE_BEFORE_REMOVING); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd index f2b57a31e72c6..7de149d7e51ce 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/schema/symfony-1.0.xsd @@ -35,7 +35,6 @@ - @@ -76,10 +75,6 @@ - - - - @@ -90,18 +85,13 @@ - - - - - - + @@ -114,13 +104,14 @@ + - + @@ -238,7 +229,6 @@ - @@ -258,6 +248,7 @@ + @@ -352,6 +343,14 @@ + + + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/KernelShutdownOnTearDownTrait.php b/src/Symfony/Bundle/FrameworkBundle/Test/KernelShutdownOnTearDownTrait.php new file mode 100644 index 0000000000000..217c2ae4576be --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Test/KernelShutdownOnTearDownTrait.php @@ -0,0 +1,43 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Test; + +use PHPUnit\Framework\TestCase; + +// Auto-adapt to PHPUnit 8 that added a `void` return-type to the tearDown method + +if (method_exists(\ReflectionMethod::class, 'hasReturnType') && (new \ReflectionMethod(TestCase::class, 'tearDown'))->hasReturnType()) { + /** + * @internal + */ + trait KernelShutdownOnTearDownTrait + { + protected function tearDown(): void + { + static::ensureKernelShutdown(); + } + } +} else { + /** + * @internal + */ + trait KernelShutdownOnTearDownTrait + { + /** + * @return void + */ + protected function tearDown() + { + static::ensureKernelShutdown(); + } + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php index fa562f608858e..666831b041590 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Test/KernelTestCase.php @@ -23,6 +23,8 @@ */ abstract class KernelTestCase extends TestCase { + use KernelShutdownOnTearDownTrait; + protected static $class; /** @@ -112,7 +114,7 @@ protected static function createKernel(array $options = []) } /** - * Shuts the kernel down if it was used in the test. + * Shuts the kernel down if it was used in the test - called by the tearDown method by default. */ protected static function ensureKernelShutdown() { @@ -125,12 +127,4 @@ protected static function ensureKernelShutdown() } static::$container = null; } - - /** - * Clean up Kernel usage in this test. - */ - protected function tearDown() - { - static::ensureKernelShutdown(); - } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/CacheClearCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/CacheClearCommandTest.php index e91ecc50caca2..9e4c46d585557 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/CacheClearCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/CacheClearCommand/CacheClearCommandTest.php @@ -51,7 +51,7 @@ public function testCacheIsFreshAfterCacheClearedWithWarmup() // Ensure that all *.meta files are fresh $finder = new Finder(); $metaFiles = $finder->files()->in($this->kernel->getCacheDir())->name('*.php.meta'); - // simply check that cache is warmed up + // check that cache is warmed up $this->assertNotEmpty($metaFiles); $configCacheFactory = new ConfigCacheFactory(true); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php index 93028bf8c2278..ee13386a4b767 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/ContainerDebugCommandTest.php @@ -22,7 +22,7 @@ class ContainerDebugCommandTest extends WebTestCase { public function testDumpContainerIfNotExists() { - static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml']); + static::bootKernel(['test_case' => 'ContainerDebug', 'root_config' => 'config.yml', 'debug' => true]); $application = new Application(static::$kernel); $application->setAutoExit(false); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/WebTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/WebTestCase.php index 3f7bb4c7ee680..00eda6570906d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/WebTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/WebTestCase.php @@ -62,7 +62,7 @@ protected static function createKernel(array $options = []) $options['test_case'], isset($options['root_config']) ? $options['root_config'] : 'config.yml', isset($options['environment']) ? $options['environment'] : strtolower(static::getVarDir().$options['test_case']), - isset($options['debug']) ? $options['debug'] : true + isset($options['debug']) ? $options['debug'] : false ); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php index b00b6a10e5337..acdaea9a8cbed 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperDivLayoutTest.php @@ -27,6 +27,8 @@ class FormHelperDivLayoutTest extends AbstractDivLayoutTest */ protected $engine; + protected static $supportedFeatureSetVersion = 304; + protected function getExtensions() { // should be moved to the Form component once absolute file paths are supported diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php index 8b1bf4cbdd81a..dc145f1e63038 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/FormHelperTableLayoutTest.php @@ -27,6 +27,8 @@ class FormHelperTableLayoutTest extends AbstractTableLayoutTest */ protected $engine; + protected static $supportedFeatureSetVersion = 304; + public function testStartTagHasNoActionAttributeWhenActionIsEmpty() { $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\FormType', null, [ diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 108afc2f7cea4..a3d41a70a6a15 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -67,7 +67,7 @@ public function prepend(ContainerBuilder $container) foreach ($container->getExtensionConfig('framework') as $config) { if (isset($config['session']) && \is_array($config['session'])) { $rememberMeSecureDefault = $config['session']['cookie_secure'] ?? $rememberMeSecureDefault; - $rememberMeSameSiteDefault = array_key_exists('cookie_samesite', $config['session']) ? $config['session']['cookie_samesite'] : $rememberMeSameSiteDefault; + $rememberMeSameSiteDefault = \array_key_exists('cookie_samesite', $config['session']) ? $config['session']['cookie_samesite'] : $rememberMeSameSiteDefault; } } foreach ($this->listenerPositions as $position) { @@ -412,7 +412,7 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a foreach ($this->factories as $position) { foreach ($position as $factory) { $key = str_replace('-', '_', $factory->getKey()); - if (array_key_exists($key, $firewall)) { + if (\array_key_exists($key, $firewall)) { $listenerKeys[] = $key; } } diff --git a/src/Symfony/Bundle/SecurityBundle/Templating/Helper/LogoutUrlHelper.php b/src/Symfony/Bundle/SecurityBundle/Templating/Helper/LogoutUrlHelper.php index 3597b14a909c8..3051ed38dc165 100644 --- a/src/Symfony/Bundle/SecurityBundle/Templating/Helper/LogoutUrlHelper.php +++ b/src/Symfony/Bundle/SecurityBundle/Templating/Helper/LogoutUrlHelper.php @@ -11,7 +11,6 @@ namespace Symfony\Bundle\SecurityBundle\Templating\Helper; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Http\Logout\LogoutUrlGenerator; use Symfony\Component\Templating\Helper\Helper; @@ -38,7 +37,7 @@ public function __construct(LogoutUrlGenerator $generator) */ public function getLogoutPath($key) { - return $this->generator->getLogoutPath($key, UrlGeneratorInterface::ABSOLUTE_PATH); + return $this->generator->getLogoutPath($key); } /** @@ -50,7 +49,7 @@ public function getLogoutPath($key) */ public function getLogoutUrl($key) { - return $this->generator->getLogoutUrl($key, UrlGeneratorInterface::ABSOLUTE_URL); + return $this->generator->getLogoutUrl($key); } /** diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/WebTestCase.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/WebTestCase.php index f1d23b6054ad7..9bcbc0532481d 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/WebTestCase.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/WebTestCase.php @@ -62,7 +62,7 @@ protected static function createKernel(array $options = []) $options['test_case'], isset($options['root_config']) ? $options['root_config'] : 'config.yml', isset($options['environment']) ? $options['environment'] : strtolower(static::getVarDir().$options['test_case']), - isset($options['debug']) ? $options['debug'] : true + isset($options['debug']) ? $options['debug'] : false ); } diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/messenger.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/messenger.html.twig index ed1183738098c..f3e8fecece384 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/messenger.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/messenger.html.twig @@ -30,15 +30,15 @@ {% endblock %} {% block menu %} - - {{ include('@WebProfiler/Icon/messenger.svg') }} - Messages - {% if collector.exceptionsCount > 0 %} - - {{ collector.exceptionsCount }} - - {% endif %} - + + {{ include('@WebProfiler/Icon/messenger.svg') }} + Messages + {% if collector.exceptionsCount > 0 %} + + {{ collector.exceptionsCount }} + + {% endif %} + {% endblock %} {% block head %} @@ -71,31 +71,31 @@

No messages have been collected.

{% else %} - -
-
- {% set messages = collector.messages %} - {% set exceptionsCount = collector.exceptionsCount %} -

All{{ messages|length }}

- -
-

Ordered list of dispatched messages across all your buses

- {{ helper.render_bus_messages(messages, true) }} +
+
+ {% set messages = collector.messages %} + {% set exceptionsCount = collector.exceptionsCount %} +

All{{ messages|length }}

+ +
+

Ordered list of dispatched messages across all your buses

+ {{ helper.render_bus_messages(messages, true) }} +
-
- {% for bus in collector.buses %} -
- {% set messages = collector.messages(bus) %} - {% set exceptionsCount = collector.exceptionsCount(bus) %} -

{{ bus }}{{ messages|length }}

- -
-

Ordered list of messages dispatched on the {{ bus }} bus

- {{ helper.render_bus_messages(messages) }} -
+ {% for bus in collector.buses %} +
+ {% set messages = collector.messages(bus) %} + {% set exceptionsCount = collector.exceptionsCount(bus) %} +

{{ bus }}{{ messages|length }}

+ +
+

Ordered list of messages dispatched on the {{ bus }} bus

+ {{ helper.render_bus_messages(messages) }} +
+
+ {% endfor %}
- {% endfor %} {% endif %} {% endblock %} @@ -105,24 +105,24 @@ {% for dispatchCall in messages %} - - - + + + @@ -133,7 +133,7 @@ {% set link = caller.file|file_link(caller.line) %} {% if link %} {{ caller.name }} - {% else %} + {% else %} {{ caller.name }} {% endif %} {% else %} @@ -150,10 +150,10 @@ {% if showBus %} - - - - + + + + {% endif %} @@ -170,12 +170,12 @@ {% if dispatchCall.exception is defined %} - - - - + + + + {% endif %}
- {{ profiler_dump(dispatchCall.message.type) }} - {% if showBus %} - {{ dispatchCall.bus }} - {% endif %} - {% if dispatchCall.exception is defined %} - exception - {% endif %} - - {{ include('@Twig/images/icon-minus-square.svg') }} - {{ include('@Twig/images/icon-plus-square.svg') }} - -
+ {{ profiler_dump(dispatchCall.message.type) }} + {% if showBus %} + {{ dispatchCall.bus }} + {% endif %} + {% if dispatchCall.exception is defined %} + exception + {% endif %} + + {{ include('@Twig/images/icon-minus-square.svg') }} + {{ include('@Twig/images/icon-plus-square.svg') }} + +
Bus{{ dispatchCall.bus }}
Bus{{ dispatchCall.bus }}
Message
Exception - {{ profiler_dump(dispatchCall.exception.value, maxDepth=1) }} -
Exception + {{ profiler_dump(dispatchCall.exception.value, maxDepth=1) }} +
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 9c1cad235047f..0230c84fb90d1 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/toolbar.css.twig @@ -103,6 +103,7 @@ .sf-toolbar-block > a:hover { display: block; text-decoration: none; + color: inherit; } .sf-toolbar-block span { @@ -514,7 +515,7 @@ div.sf-toolbar .sf-toolbar-block a:hover { @media (min-width: 1024px) { .sf-toolbar-block .sf-toolbar-info-piece-additional, .sf-toolbar-block .sf-toolbar-info-piece-additional-detail { - display: inline-block; + display: inline; } .sf-toolbar-block .sf-toolbar-info-piece-additional:empty, diff --git a/src/Symfony/Bundle/WebServerBundle/Resources/router.php b/src/Symfony/Bundle/WebServerBundle/Resources/router.php index a366b381aae47..30d6b258a29de 100644 --- a/src/Symfony/Bundle/WebServerBundle/Resources/router.php +++ b/src/Symfony/Bundle/WebServerBundle/Resources/router.php @@ -17,8 +17,8 @@ * If you have custom directory layout, then you have to write your own router * and pass it as a value to 'router' option of server:run command. * - * @author: Michał Pipa - * @author: Albert Jessurum + * @author Michał Pipa + * @author Albert Jessurum */ // Workaround https://bugs.php.net/64566 diff --git a/src/Symfony/Component/BrowserKit/Client.php b/src/Symfony/Component/BrowserKit/Client.php index de6a01c90ec0e..d6c033d57245f 100644 --- a/src/Symfony/Component/BrowserKit/Client.php +++ b/src/Symfony/Component/BrowserKit/Client.php @@ -548,7 +548,7 @@ public function back() { do { $request = $this->history->back(); - } while (array_key_exists(serialize($request), $this->redirects)); + } while (\array_key_exists(serialize($request), $this->redirects)); return $this->requestFromRequest($request, false); } @@ -562,7 +562,7 @@ public function forward() { do { $request = $this->history->forward(); - } while (array_key_exists(serialize($request), $this->redirects)); + } while (\array_key_exists(serialize($request), $this->redirects)); return $this->requestFromRequest($request, false); } diff --git a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php index d93ae711bdac2..6897fbceee530 100644 --- a/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/AbstractAdapter.php @@ -94,7 +94,7 @@ function ($deferred, $namespace, &$expiredIds) use ($getId) { } /** - * Returns an ApcuAdapter if supported, a PhpFilesAdapter otherwise. + * Returns the best possible adapter that your runtime supports. * * Using ApcuAdapter makes system caches compatible with read-only filesystems. * @@ -108,16 +108,12 @@ function ($deferred, $namespace, &$expiredIds) use ($getId) { */ public static function createSystemCache($namespace, $defaultLifetime, $version, $directory, LoggerInterface $logger = null) { - if (null === self::$apcuSupported) { - self::$apcuSupported = ApcuAdapter::isSupported(); + $opcache = new PhpFilesAdapter($namespace, $defaultLifetime, $directory, true); + if (null !== $logger) { + $opcache->setLogger($logger); } - if (!self::$apcuSupported) { - $opcache = new PhpFilesAdapter($namespace, $defaultLifetime, $directory, true); - if (null !== $logger) { - $opcache->setLogger($logger); - } - + if (!self::$apcuSupported = self::$apcuSupported ?? ApcuAdapter::isSupported()) { return $opcache; } @@ -128,7 +124,7 @@ public static function createSystemCache($namespace, $defaultLifetime, $version, $apcu->setLogger($logger); } - return $apcu; + return new ChainAdapter([$apcu, $opcache]); } public static function createConnection($dsn, array $options = []) diff --git a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php index 8a7d147808bfe..0eceb6e572b39 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/AdapterTestCase.php @@ -22,7 +22,7 @@ protected function setUp() { parent::setUp(); - if (!array_key_exists('testPrune', $this->skippedTests) && !$this->createCachePool() instanceof PruneableInterface) { + if (!\array_key_exists('testPrune', $this->skippedTests) && !$this->createCachePool() instanceof PruneableInterface) { $this->skippedTests['testPrune'] = 'Not a pruneable cache pool.'; } } diff --git a/src/Symfony/Component/Cache/Tests/Simple/CacheTestCase.php b/src/Symfony/Component/Cache/Tests/Simple/CacheTestCase.php index 1a13cbaae826e..3c8824869bd08 100644 --- a/src/Symfony/Component/Cache/Tests/Simple/CacheTestCase.php +++ b/src/Symfony/Component/Cache/Tests/Simple/CacheTestCase.php @@ -21,7 +21,7 @@ protected function setUp() { parent::setUp(); - if (!array_key_exists('testPrune', $this->skippedTests) && !$this->createSimpleCache() instanceof PruneableInterface) { + if (!\array_key_exists('testPrune', $this->skippedTests) && !$this->createSimpleCache() instanceof PruneableInterface) { $this->skippedTests['testPrune'] = 'Not a pruneable cache pool.'; } } diff --git a/src/Symfony/Component/Cache/Traits/MemcachedTrait.php b/src/Symfony/Component/Cache/Traits/MemcachedTrait.php index b83d69593715a..9c52323943b58 100644 --- a/src/Symfony/Component/Cache/Traits/MemcachedTrait.php +++ b/src/Symfony/Component/Cache/Traits/MemcachedTrait.php @@ -166,7 +166,7 @@ public static function createConnection($servers, array $options = []) $client->setOption(\Memcached::OPT_BINARY_PROTOCOL, true); $client->setOption(\Memcached::OPT_NO_BLOCK, true); $client->setOption(\Memcached::OPT_TCP_NODELAY, true); - if (!array_key_exists('LIBKETAMA_COMPATIBLE', $options) && !array_key_exists(\Memcached::OPT_LIBKETAMA_COMPATIBLE, $options)) { + if (!\array_key_exists('LIBKETAMA_COMPATIBLE', $options) && !\array_key_exists(\Memcached::OPT_LIBKETAMA_COMPATIBLE, $options)) { $client->setOption(\Memcached::OPT_LIBKETAMA_COMPATIBLE, true); } foreach ($options as $name => $value) { diff --git a/src/Symfony/Component/Cache/Traits/RedisTrait.php b/src/Symfony/Component/Cache/Traits/RedisTrait.php index 0276c4fb6de65..8da2e257a88fe 100644 --- a/src/Symfony/Component/Cache/Traits/RedisTrait.php +++ b/src/Symfony/Component/Cache/Traits/RedisTrait.php @@ -284,7 +284,7 @@ protected function doFetch(array $ids) $result = []; - if ($this->redis instanceof \Predis\Client) { + if ($this->redis instanceof \Predis\Client && $this->redis->getConnection() instanceof ClusterInterface) { $values = $this->pipeline(function () use ($ids) { foreach ($ids as $id) { yield 'get' => [$id]; diff --git a/src/Symfony/Component/Config/Definition/ArrayNode.php b/src/Symfony/Component/Config/Definition/ArrayNode.php index dd908c999e384..43697ef27943c 100644 --- a/src/Symfony/Component/Config/Definition/ArrayNode.php +++ b/src/Symfony/Component/Config/Definition/ArrayNode.php @@ -59,7 +59,7 @@ protected function preNormalize($value) $normalized = []; foreach ($value as $k => $v) { - if (false !== strpos($k, '-') && false === strpos($k, '_') && !array_key_exists($normalizedKey = str_replace('-', '_', $k), $value)) { + if (false !== strpos($k, '-') && false === strpos($k, '_') && !\array_key_exists($normalizedKey = str_replace('-', '_', $k), $value)) { $normalized[$normalizedKey] = $v; } else { $normalized[$k] = $v; @@ -223,7 +223,7 @@ protected function finalizeValue($value) } foreach ($this->children as $name => $child) { - if (!array_key_exists($name, $value)) { + if (!\array_key_exists($name, $value)) { if ($child->isRequired()) { $ex = new InvalidConfigurationException(sprintf('The child node "%s" at path "%s" must be configured.', $name, $this->getPath())); $ex->setPath($this->getPath()); @@ -383,7 +383,7 @@ protected function mergeValues($leftSide, $rightSide) foreach ($rightSide as $k => $v) { // no conflict - if (!array_key_exists($k, $leftSide)) { + if (!\array_key_exists($k, $leftSide)) { if (!$this->allowNewKeys) { $ex = new InvalidConfigurationException(sprintf('You are not allowed to define new elements for path "%s". Please define all elements for this path in one config file. If you are trying to overwrite an element, make sure you redefine it with the same name.', $this->getPath())); $ex->setPath($this->getPath()); diff --git a/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php b/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php index 43c2b8b73188f..dca5687a2045e 100644 --- a/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php +++ b/src/Symfony/Component/Config/Definition/Builder/ArrayNodeDefinition.php @@ -332,10 +332,10 @@ public function performNoDeepMerging() * Allows extra config keys to be specified under an array without * throwing an exception. * - * Those config values are simply ignored and removed from the - * resulting array. This should be used only in special cases where - * you want to send an entire configuration array through a special - * tree that processes only part of the array. + * Those config values are ignored and removed from the resulting + * array. This should be used only in special cases where you want + * to send an entire configuration array through a special tree that + * processes only part of the array. * * @param bool $remove Whether to remove the extra keys * diff --git a/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php b/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php index 4a3446f52ffe8..dd6ccd94a3585 100644 --- a/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php +++ b/src/Symfony/Component/Config/Definition/PrototypedArrayNode.php @@ -245,7 +245,7 @@ protected function normalizeValue($value) // if only "value" is left if (array_keys($v) === ['value']) { $v = $v['value']; - if ($this->prototype instanceof ArrayNode && ($children = $this->prototype->getChildren()) && array_key_exists('value', $children)) { + if ($this->prototype instanceof ArrayNode && ($children = $this->prototype->getChildren()) && \array_key_exists('value', $children)) { $valuePrototype = current($this->valuePrototypes) ?: clone $children['value']; $valuePrototype->parent = $this; $originalClosures = $this->prototype->normalizationClosures; @@ -258,7 +258,7 @@ protected function normalizeValue($value) } } - if (array_key_exists($k, $normalized)) { + if (\array_key_exists($k, $normalized)) { $ex = new DuplicateKeyException(sprintf('Duplicate key "%s" for path "%s".', $k, $this->getPath())); $ex->setPath($this->getPath()); @@ -301,14 +301,14 @@ protected function mergeValues($leftSide, $rightSide) } foreach ($rightSide as $k => $v) { - // prototype, and key is irrelevant, so simply append the element + // prototype, and key is irrelevant, append the element if (null === $this->keyAttribute) { $leftSide[] = $v; continue; } // no conflict - if (!array_key_exists($k, $leftSide)) { + if (!\array_key_exists($k, $leftSide)) { if (!$this->allowNewKeys) { $ex = new InvalidConfigurationException(sprintf('You are not allowed to define new elements for path "%s". Please define all elements for this path in one config file.', $this->getPath())); $ex->setPath($this->getPath()); diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index f96d690589042..17df91f994483 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -199,6 +199,13 @@ public function doRun(InputInterface $input, OutputInterface $output) return 0; } + try { + // Makes ArgvInput::getFirstArgument() able to distinguish an option from an argument. + $input->bind($this->getDefinition()); + } catch (ExceptionInterface $e) { + // Errors must be ignored, full binding/validation happens later when the command is known. + } + $name = $this->getCommandName($input); if (true === $input->hasParameterOption(['--help', '-h'], true)) { if (!$name) { diff --git a/src/Symfony/Component/Console/Helper/ProgressBar.php b/src/Symfony/Component/Console/Helper/ProgressBar.php index b68d9fe389a17..12a6cf22453e4 100644 --- a/src/Symfony/Component/Console/Helper/ProgressBar.php +++ b/src/Symfony/Component/Console/Helper/ProgressBar.php @@ -381,20 +381,17 @@ private function overwrite(string $message): void $lines = floor(Helper::strlen($message) / $this->terminal->getWidth()) + $this->formatLineCount + 1; $this->output->clear($lines); } else { - // Move the cursor to the beginning of the line - $this->output->write("\x0D"); - - // Erase the line - $this->output->write("\x1B[2K"); - // Erase previous lines if ($this->formatLineCount > 0) { - $this->output->write(str_repeat("\x1B[1A\x1B[2K", $this->formatLineCount)); + $message = str_repeat("\x1B[1A\x1B[2K", $this->formatLineCount).$message; } + + // Move the cursor to the beginning of the line and erase the line + $message = "\x0D\x1B[2K$message"; } } } elseif ($this->step > 0) { - $this->output->writeln(''); + $message = PHP_EOL.$message; } $this->firstRun = false; diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php index 575c53458d72a..cf6447a4bcb50 100644 --- a/src/Symfony/Component/Console/Helper/QuestionHelper.php +++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php @@ -126,7 +126,7 @@ private function doAsk(OutputInterface $output, Question $question) if (false === $ret) { $ret = fgets($inputStream, 4096); if (false === $ret) { - throw new RuntimeException('Aborted'); + throw new RuntimeException('Aborted.'); } $ret = trim($ret); } @@ -213,8 +213,10 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu while (!feof($inputStream)) { $c = fread($inputStream, 1); - // Backspace Character - if ("\177" === $c) { + // as opposed to fgets(), fread() returns an empty string when the stream content is empty, not false. + if (false === $c || ('' === $ret && '' === $c && null === $question->getDefault())) { + throw new RuntimeException('Aborted.'); + } elseif ("\177" === $c) { // Backspace Character if (0 === $numMatches && 0 !== $i) { --$i; // Move cursor backwards @@ -267,6 +269,10 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu continue; } else { + if ("\x80" <= $c) { + $c .= fread($inputStream, ["\xC0" => 1, "\xD0" => 1, "\xE0" => 2, "\xF0" => 3][$c & "\xF0"]); + } + $output->write($c); $ret .= $c; ++$i; @@ -339,7 +345,7 @@ private function getHiddenResponse(OutputInterface $output, $inputStream): strin shell_exec(sprintf('stty %s', $sttyMode)); if (false === $value) { - throw new RuntimeException('Aborted'); + throw new RuntimeException('Aborted.'); } $value = trim($value); diff --git a/src/Symfony/Component/Console/Input/ArgvInput.php b/src/Symfony/Component/Console/Input/ArgvInput.php index 85ff6f91d8736..c56c20c684e80 100644 --- a/src/Symfony/Component/Console/Input/ArgvInput.php +++ b/src/Symfony/Component/Console/Input/ArgvInput.php @@ -257,8 +257,27 @@ private function addLongOption($name, $value) */ public function getFirstArgument() { - foreach ($this->tokens as $token) { + $isOption = false; + foreach ($this->tokens as $i => $token) { if ($token && '-' === $token[0]) { + if (false !== strpos($token, '=') || !isset($this->tokens[$i + 1])) { + continue; + } + + // If it's a long option, consider that everything after "--" is the option name. + // Otherwise, use the last char (if it's a short option set, only the last one can take a value with space separator) + $name = '-' === $token[1] ? substr($token, 2) : substr($token, -1); + if (!isset($this->options[$name]) && !$this->definition->hasShortcut($name)) { + // noop + } elseif ((isset($this->options[$name]) || isset($this->options[$name = $this->definition->shortcutToName($name)])) && $this->tokens[$i + 1] === $this->options[$name]) { + $isOption = true; + } + + continue; + } + + if ($isOption) { + $isOption = false; continue; } diff --git a/src/Symfony/Component/Console/Input/ArrayInput.php b/src/Symfony/Component/Console/Input/ArrayInput.php index cf09ff45ecb49..44c2f0d5c66aa 100644 --- a/src/Symfony/Component/Console/Input/ArrayInput.php +++ b/src/Symfony/Component/Console/Input/ArrayInput.php @@ -19,7 +19,7 @@ * * Usage: * - * $input = new ArrayInput(['name' => 'foo', '--bar' => 'foobar']); + * $input = new ArrayInput(['command' => 'foo:bar', 'foo' => 'bar', '--bar' => 'foobar']); * * @author Fabien Potencier */ diff --git a/src/Symfony/Component/Console/Input/Input.php b/src/Symfony/Component/Console/Input/Input.php index 7a16e0ee4b9f2..c1220316dcfff 100644 --- a/src/Symfony/Component/Console/Input/Input.php +++ b/src/Symfony/Component/Console/Input/Input.php @@ -69,7 +69,7 @@ public function validate() $givenArguments = $this->arguments; $missingArguments = array_filter(array_keys($definition->getArguments()), function ($argument) use ($definition, $givenArguments) { - return !array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired(); + return !\array_key_exists($argument, $givenArguments) && $definition->getArgument($argument)->isRequired(); }); if (\count($missingArguments) > 0) { @@ -150,7 +150,7 @@ public function getOption($name) throw new InvalidArgumentException(sprintf('The "%s" option does not exist.', $name)); } - return array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); + return \array_key_exists($name, $this->options) ? $this->options[$name] : $this->definition->getOption($name)->getDefault(); } /** diff --git a/src/Symfony/Component/Console/Input/InputDefinition.php b/src/Symfony/Component/Console/Input/InputDefinition.php index c7e5c987e5752..2189c46282264 100644 --- a/src/Symfony/Component/Console/Input/InputDefinition.php +++ b/src/Symfony/Component/Console/Input/InputDefinition.php @@ -338,8 +338,10 @@ public function getOptionDefaults() * @return string The InputOption name * * @throws InvalidArgumentException When option given does not exist + * + * @internal */ - private function shortcutToName($shortcut) + public function shortcutToName($shortcut) { if (!isset($this->shortcuts[$shortcut])) { throw new InvalidArgumentException(sprintf('The "-%s" option does not exist.', $shortcut)); diff --git a/src/Symfony/Component/Console/Tester/CommandTester.php b/src/Symfony/Component/Console/Tester/CommandTester.php index da51559faddca..57efc9a6754b2 100644 --- a/src/Symfony/Component/Console/Tester/CommandTester.php +++ b/src/Symfony/Component/Console/Tester/CommandTester.php @@ -60,9 +60,8 @@ public function execute(array $input, array $options = []) } $this->input = new ArrayInput($input); - if ($this->inputs) { - $this->input->setStream(self::createStream($this->inputs)); - } + // Use an in-memory input stream even if no inputs are set so that QuestionHelper::ask() does not rely on the blocking STDIN. + $this->input->setStream(self::createStream($this->inputs)); if (isset($options['interactive'])) { $this->input->setInteractive($options['interactive']); diff --git a/src/Symfony/Component/Console/Tester/TesterTrait.php b/src/Symfony/Component/Console/Tester/TesterTrait.php index e5df56d8357c7..7b5e128c49b63 100644 --- a/src/Symfony/Component/Console/Tester/TesterTrait.php +++ b/src/Symfony/Component/Console/Tester/TesterTrait.php @@ -126,7 +126,7 @@ public function setInputs(array $inputs) */ private function initOutput(array $options) { - $this->captureStreamsIndependently = array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately']; + $this->captureStreamsIndependently = \array_key_exists('capture_stderr_separately', $options) && $options['capture_stderr_separately']; if (!$this->captureStreamsIndependently) { $this->output = new StreamOutput(fopen('php://memory', 'w', false)); if (isset($options['decorated'])) { diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index 2aaf9d7dae442..e9b1be32a647b 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -968,6 +968,19 @@ public function testRun() $this->assertSame('called'.PHP_EOL, $tester->getDisplay(), '->run() does not call interact() if -n is passed'); } + public function testRunWithGlobalOptionAndNoCommand() + { + $application = new Application(); + $application->setAutoExit(false); + $application->setCatchExceptions(false); + $application->getDefinition()->addOption(new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL)); + + $output = new StreamOutput(fopen('php://memory', 'w', false)); + $input = new ArgvInput(['cli.php', '--foo', 'bar']); + + $this->assertSame(0, $application->run($input, $output)); + } + /** * Issue #9285. * diff --git a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php index de3ec4559be4d..e3edbed02973f 100644 --- a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php @@ -237,6 +237,43 @@ public function testAskWithAutocompleteWithExactMatch() $this->assertSame('b', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); } + public function getInputs() + { + return [ + ['$'], // 1 byte character + ['¢'], // 2 bytes character + ['€'], // 3 bytes character + ['𐍈'], // 4 bytes character + ]; + } + + /** + * @dataProvider getInputs + */ + public function testAskWithAutocompleteWithMultiByteCharacter($character) + { + if (!$this->hasSttyAvailable()) { + $this->markTestSkipped('`stty` is required to test autocomplete functionality'); + } + + $inputStream = $this->getInputStream("$character\n"); + + $possibleChoices = [ + '$' => '1 byte character', + '¢' => '2 bytes character', + '€' => '3 bytes character', + '𐍈' => '4 bytes character', + ]; + + $dialog = new QuestionHelper(); + $dialog->setHelperSet(new HelperSet([new FormatterHelper()])); + + $question = new ChoiceQuestion('Please select a character', $possibleChoices); + $question->setMaxAttempts(1); + + $this->assertSame($character, $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); + } + public function testAutocompleteWithTrailingBackslash() { if (!$this->hasSttyAvailable()) { @@ -549,7 +586,7 @@ public function testChoiceOutputFormattingQuestionForUtf8Keys() /** * @expectedException \Symfony\Component\Console\Exception\RuntimeException - * @expectedExceptionMessage Aborted + * @expectedExceptionMessage Aborted. */ public function testAskThrowsExceptionOnMissingInput() { @@ -559,7 +596,17 @@ public function testAskThrowsExceptionOnMissingInput() /** * @expectedException \Symfony\Component\Console\Exception\RuntimeException - * @expectedExceptionMessage Aborted + * @expectedExceptionMessage Aborted. + */ + public function testAskThrowsExceptionOnMissingInputForChoiceQuestion() + { + $dialog = new QuestionHelper(); + $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), new ChoiceQuestion('Choice', ['a', 'b'])); + } + + /** + * @expectedException \Symfony\Component\Console\Exception\RuntimeException + * @expectedExceptionMessage Aborted. */ public function testAskThrowsExceptionOnMissingInputWithValidator() { diff --git a/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php index e7fd806064d2c..cf7a78c34ecda 100644 --- a/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php @@ -124,7 +124,7 @@ public function testLabelTrailingBackslash() /** * @expectedException \Symfony\Component\Console\Exception\RuntimeException - * @expectedExceptionMessage Aborted + * @expectedExceptionMessage Aborted. */ public function testAskThrowsExceptionOnMissingInput() { diff --git a/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php b/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php index 37caaf2d1cd72..e20bcdd21bc7c 100644 --- a/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php +++ b/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php @@ -312,6 +312,14 @@ public function testGetFirstArgument() $input = new ArgvInput(['cli.php', '-fbbar', 'foo']); $this->assertEquals('foo', $input->getFirstArgument(), '->getFirstArgument() returns the first argument from the raw input'); + + $input = new ArgvInput(['cli.php', '--foo', 'fooval', 'bar']); + $input->bind(new InputDefinition([new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputArgument('arg')])); + $this->assertSame('bar', $input->getFirstArgument()); + + $input = new ArgvInput(['cli.php', '-bf', 'fooval', 'argval']); + $input->bind(new InputDefinition([new InputOption('bar', 'b', InputOption::VALUE_NONE), new InputOption('foo', 'f', InputOption::VALUE_OPTIONAL), new InputArgument('arg')])); + $this->assertSame('argval', $input->getFirstArgument()); } public function testHasParameterOption() diff --git a/src/Symfony/Component/Console/Tests/Tester/CommandTesterTest.php b/src/Symfony/Component/Console/Tests/Tester/CommandTesterTest.php index 6d9b7417d679c..706629673c8da 100644 --- a/src/Symfony/Component/Console/Tests/Tester/CommandTesterTest.php +++ b/src/Symfony/Component/Console/Tests/Tester/CommandTesterTest.php @@ -17,6 +17,7 @@ use Symfony\Component\Console\Helper\HelperSet; use Symfony\Component\Console\Helper\QuestionHelper; use Symfony\Component\Console\Output\Output; +use Symfony\Component\Console\Question\ChoiceQuestion; use Symfony\Component\Console\Question\Question; use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\Console\Tester\CommandTester; @@ -139,7 +140,7 @@ public function testCommandWithDefaultInputs() /** * @expectedException \RuntimeException - * @expectedMessage Aborted + * @expectedExceptionMessage Aborted. */ public function testCommandWithWrongInputsNumber() { @@ -153,13 +154,40 @@ public function testCommandWithWrongInputsNumber() $command->setHelperSet(new HelperSet([new QuestionHelper()])); $command->setCode(function ($input, $output) use ($questions, $command) { $helper = $command->getHelper('question'); + $helper->ask($input, $output, new ChoiceQuestion('choice', ['a', 'b'])); + $helper->ask($input, $output, new Question($questions[0])); + $helper->ask($input, $output, new Question($questions[1])); + $helper->ask($input, $output, new Question($questions[2])); + }); + + $tester = new CommandTester($command); + $tester->setInputs(['a', 'Bobby', 'Fine']); + $tester->execute([]); + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage Aborted. + */ + public function testCommandWithQuestionsButNoInputs() + { + $questions = [ + 'What\'s your name?', + 'How are you?', + 'Where do you come from?', + ]; + + $command = new Command('foo'); + $command->setHelperSet(new HelperSet([new QuestionHelper()])); + $command->setCode(function ($input, $output) use ($questions, $command) { + $helper = $command->getHelper('question'); + $helper->ask($input, $output, new ChoiceQuestion('choice', ['a', 'b'])); $helper->ask($input, $output, new Question($questions[0])); $helper->ask($input, $output, new Question($questions[1])); $helper->ask($input, $output, new Question($questions[2])); }); $tester = new CommandTester($command); - $tester->setInputs(['Bobby', 'Fine']); $tester->execute([]); } diff --git a/src/Symfony/Component/Debug/DebugClassLoader.php b/src/Symfony/Component/Debug/DebugClassLoader.php index 35f1f55bef841..2816c4fba77b2 100644 --- a/src/Symfony/Component/Debug/DebugClassLoader.php +++ b/src/Symfony/Component/Debug/DebugClassLoader.php @@ -427,6 +427,11 @@ private function darwinRealpath($real) $dirFiles = self::$darwinCache[$kDir][1]; + if (!isset($dirFiles[$file]) && ') : eval()\'d code' === substr($file, -17)) { + // Get the file name from "file_name.php(123) : eval()'d code" + $file = substr($file, 0, strrpos($file, '(', -17)); + } + if (isset($dirFiles[$file])) { return $real .= $dirFiles[$file]; } diff --git a/src/Symfony/Component/Debug/ErrorHandler.php b/src/Symfony/Component/Debug/ErrorHandler.php index b47e40211643d..78ac0240ab9ab 100644 --- a/src/Symfony/Component/Debug/ErrorHandler.php +++ b/src/Symfony/Component/Debug/ErrorHandler.php @@ -220,7 +220,7 @@ public function setLoggers(array $loggers) } if (!\is_array($log)) { $log = [$log]; - } elseif (!array_key_exists(0, $log)) { + } elseif (!\array_key_exists(0, $log)) { throw new \InvalidArgumentException('No logger provided'); } if (null === $log[0]) { @@ -490,6 +490,11 @@ public function handleError($type, $message, $file, $line) if ($this->isRecursive) { $log = 0; } else { + if (!\defined('HHVM_VERSION')) { + $currentErrorHandler = set_error_handler('var_dump'); + restore_error_handler(); + } + try { $this->isRecursive = true; $level = ($type & $level) ? $this->loggers[$type][1] : LogLevel::DEBUG; @@ -498,7 +503,7 @@ public function handleError($type, $message, $file, $line) $this->isRecursive = false; if (!\defined('HHVM_VERSION')) { - set_error_handler([$this, __FUNCTION__]); + set_error_handler($currentErrorHandler); } } } diff --git a/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php b/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php index fc68b86460445..da02cf855f300 100644 --- a/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php +++ b/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php @@ -44,7 +44,7 @@ public function testIdempotence() $functions = spl_autoload_functions(); foreach ($functions as $function) { - if (is_array($function) && $function[0] instanceof DebugClassLoader) { + if (\is_array($function) && $function[0] instanceof DebugClassLoader) { $reflClass = new \ReflectionClass($function[0]); $reflProp = $reflClass->getProperty('classLoader'); $reflProp->setAccessible(true); @@ -205,7 +205,7 @@ public function testExtendedFinalClass() require __DIR__.'/Fixtures/FinalClasses.php'; $i = 1; - while(class_exists($finalClass = __NAMESPACE__.'\\Fixtures\\FinalClass'.$i++, false)) { + while (class_exists($finalClass = __NAMESPACE__.'\\Fixtures\\FinalClass'.$i++, false)) { spl_autoload_call($finalClass); class_exists('Test\\'.__NAMESPACE__.'\\Extends'.substr($finalClass, strrpos($finalClass, '\\') + 1), true); } @@ -311,6 +311,11 @@ class_exists('Test\\'.__NAMESPACE__.'\\UseTraitWithInternalMethod', true); $this->assertSame([], $deprecations); } + + public function testEvaluatedCode() + { + $this->assertTrue(class_exists(__NAMESPACE__.'\Fixtures\DefinitionInEvaluatedCode', true)); + } } class ClassLoader @@ -326,7 +331,7 @@ public function getClassMap() public function findFile($class) { - $fixtureDir = __DIR__.DIRECTORY_SEPARATOR.'Fixtures'.DIRECTORY_SEPARATOR; + $fixtureDir = __DIR__.\DIRECTORY_SEPARATOR.'Fixtures'.\DIRECTORY_SEPARATOR; if (__NAMESPACE__.'\TestingUnsilencing' === $class) { eval('-- parse error --'); @@ -335,7 +340,7 @@ public function findFile($class) } elseif (__NAMESPACE__.'\TestingCaseMismatch' === $class) { eval('namespace '.__NAMESPACE__.'; class TestingCaseMisMatch {}'); } elseif (__NAMESPACE__.'\Fixtures\Psr4CaseMismatch' === $class) { - return $fixtureDir.'psr4'.DIRECTORY_SEPARATOR.'Psr4CaseMismatch.php'; + return $fixtureDir.'psr4'.\DIRECTORY_SEPARATOR.'Psr4CaseMismatch.php'; } elseif (__NAMESPACE__.'\Fixtures\NotPSR0' === $class) { return $fixtureDir.'reallyNotPsr0.php'; } elseif (__NAMESPACE__.'\Fixtures\NotPSR0bis' === $class) { diff --git a/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php b/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php index f3205840550c5..cf23365d4f0df 100644 --- a/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php +++ b/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php @@ -12,12 +12,12 @@ namespace Symfony\Component\Debug\Tests; use PHPUnit\Framework\TestCase; -use Psr\Log\LoggerInterface; use Psr\Log\LogLevel; use Psr\Log\NullLogger; use Symfony\Component\Debug\BufferingLogger; use Symfony\Component\Debug\ErrorHandler; use Symfony\Component\Debug\Exception\SilencedErrorContext; +use Symfony\Component\Debug\Tests\Fixtures\ErrorHandlerThatUsesThePreviousOne; use Symfony\Component\Debug\Tests\Fixtures\LoggerThatSetAnErrorHandler; /** @@ -508,26 +508,40 @@ public function testCustomExceptionHandler() } /** - * @dataProvider errorHandlerIsNotLostWhenLoggingProvider + * @dataProvider errorHandlerWhenLoggingProvider */ - public function testErrorHandlerIsNotLostWhenLogging($customErrorHandlerHasBeenPreviouslyDefined, LoggerInterface $logger) + public function testErrorHandlerWhenLogging($previousHandlerWasDefined, $loggerSetsAnotherHandler, $nextHandlerIsDefined) { try { - if ($customErrorHandlerHasBeenPreviouslyDefined) { + if ($previousHandlerWasDefined) { set_error_handler('count'); } + $logger = $loggerSetsAnotherHandler ? new LoggerThatSetAnErrorHandler() : new NullLogger(); + $handler = ErrorHandler::register(); $handler->setDefaultLogger($logger); + if ($nextHandlerIsDefined) { + $handler = ErrorHandlerThatUsesThePreviousOne::register(); + } + @trigger_error('foo', E_USER_DEPRECATED); @trigger_error('bar', E_USER_DEPRECATED); $this->assertSame([$handler, 'handleError'], set_error_handler('var_dump')); + if ($logger instanceof LoggerThatSetAnErrorHandler) { + $this->assertCount(2, $logger->cleanLogs()); + } + restore_error_handler(); - if ($customErrorHandlerHasBeenPreviouslyDefined) { + if ($previousHandlerWasDefined) { + restore_error_handler(); + } + + if ($nextHandlerIsDefined) { restore_error_handler(); } } finally { @@ -536,13 +550,14 @@ public function testErrorHandlerIsNotLostWhenLogging($customErrorHandlerHasBeenP } } - public function errorHandlerIsNotLostWhenLoggingProvider() + public function errorHandlerWhenLoggingProvider() { - return [ - [false, new NullLogger()], - [true, new NullLogger()], - [false, new LoggerThatSetAnErrorHandler()], - [true, new LoggerThatSetAnErrorHandler()], - ]; + foreach ([false, true] as $previousHandlerWasDefined) { + foreach ([false, true] as $loggerSetsAnotherHandler) { + foreach ([false, true] as $nextHandlerIsDefined) { + yield [$previousHandlerWasDefined, $loggerSetsAnotherHandler, $nextHandlerIsDefined]; + } + } + } } } diff --git a/src/Symfony/Component/Debug/Tests/Fixtures/DefinitionInEvaluatedCode.php b/src/Symfony/Component/Debug/Tests/Fixtures/DefinitionInEvaluatedCode.php new file mode 100644 index 0000000000000..ff6976e0fb1d7 --- /dev/null +++ b/src/Symfony/Component/Debug/Tests/Fixtures/DefinitionInEvaluatedCode.php @@ -0,0 +1,11 @@ +arguments)) { + if (\array_key_exists('index_'.$index, $this->arguments)) { return $this->arguments['index_'.$index]; } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index 8929f26fe8118..f6995cc355031 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -189,7 +189,7 @@ private function autowireMethod(\ReflectionFunctionAbstract $reflectionMethod, a } foreach ($parameters as $index => $parameter) { - if (array_key_exists($index, $arguments) && '' !== $arguments[$index]) { + if (\array_key_exists($index, $arguments) && '' !== $arguments[$index]) { continue; } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php b/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php index 8c34ce418269d..aeb96418112c9 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/RegisterServiceSubscribersPass.php @@ -43,10 +43,10 @@ protected function processValue($value, $isRoot = false) if ([] !== array_diff(array_keys($attributes), ['id', 'key'])) { throw new InvalidArgumentException(sprintf('The "container.service_subscriber" tag accepts only the "key" and "id" attributes, "%s" given for service "%s".', implode('", "', array_keys($attributes)), $this->currentId)); } - if (!array_key_exists('id', $attributes)) { + if (!\array_key_exists('id', $attributes)) { throw new InvalidArgumentException(sprintf('Missing "id" attribute on "container.service_subscriber" tag with key="%s" for service "%s".', $attributes['key'], $this->currentId)); } - if (!array_key_exists('key', $attributes)) { + if (!\array_key_exists('key', $attributes)) { $attributes['key'] = $attributes['id']; } if (isset($serviceMap[$attributes['key']])) { diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php index cf7d96fceb3b9..2238779a25e2c 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveBindingsPass.php @@ -119,19 +119,19 @@ protected function processValue($value, $isRoot = false) } foreach ($reflectionMethod->getParameters() as $key => $parameter) { - if (array_key_exists($key, $arguments) && '' !== $arguments[$key]) { + if (\array_key_exists($key, $arguments) && '' !== $arguments[$key]) { continue; } $typeHint = ProxyHelper::getTypeHint($reflectionMethod, $parameter); - if (array_key_exists($k = ltrim($typeHint, '\\').' $'.$parameter->name, $bindings)) { + if (\array_key_exists($k = ltrim($typeHint, '\\').' $'.$parameter->name, $bindings)) { $arguments[$key] = $this->getBindingValue($bindings[$k]); continue; } - if (array_key_exists('$'.$parameter->name, $bindings)) { + if (\array_key_exists('$'.$parameter->name, $bindings)) { $arguments[$key] = $this->getBindingValue($bindings['$'.$parameter->name]); continue; diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveNamedArgumentsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveNamedArgumentsPass.php index 70f2556df5e1c..771c8f7b381f4 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveNamedArgumentsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveNamedArgumentsPass.php @@ -77,7 +77,7 @@ protected function processValue($value, $isRoot = false) $typeFound = false; foreach ($parameters as $j => $p) { - if (!array_key_exists($j, $resolvedArguments) && ProxyHelper::getTypeHint($r, $p, true) === $key) { + if (!\array_key_exists($j, $resolvedArguments) && ProxyHelper::getTypeHint($r, $p, true) === $key) { $resolvedArguments[$j] = $argument; $typeFound = true; } diff --git a/src/Symfony/Component/DependencyInjection/Container.php b/src/Symfony/Component/DependencyInjection/Container.php index 938c0a8e3c817..f1bafe9812d66 100644 --- a/src/Symfony/Component/DependencyInjection/Container.php +++ b/src/Symfony/Component/DependencyInjection/Container.php @@ -385,7 +385,7 @@ protected function getEnv($name) if (isset($this->resolving[$envName = "env($name)"])) { throw new ParameterCircularReferenceException(array_keys($this->resolving)); } - if (isset($this->envCache[$name]) || array_key_exists($name, $this->envCache)) { + if (isset($this->envCache[$name]) || \array_key_exists($name, $this->envCache)) { return $this->envCache[$name]; } if (!$this->has($id = 'container.env_var_processors_locator')) { diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php index b096237c3a6b7..a7a862cbbfab7 100644 --- a/src/Symfony/Component/DependencyInjection/Definition.php +++ b/src/Symfony/Component/DependencyInjection/Definition.php @@ -269,7 +269,7 @@ public function replaceArgument($index, $argument) throw new OutOfBoundsException(sprintf('The index "%d" is not in the range [0, %d].', $index, \count($this->arguments) - 1)); } - if (!array_key_exists($index, $this->arguments)) { + if (!\array_key_exists($index, $this->arguments)) { throw new OutOfBoundsException(sprintf('The argument "%s" doesn\'t exist.', $index)); } @@ -314,7 +314,7 @@ public function getArguments() */ public function getArgument($index) { - if (!array_key_exists($index, $this->arguments)) { + if (!\array_key_exists($index, $this->arguments)) { throw new OutOfBoundsException(sprintf('The argument "%s" doesn\'t exist.', $index)); } diff --git a/src/Symfony/Component/DependencyInjection/Dumper/GraphvizDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/GraphvizDumper.php index b1a9016b0f67b..08c3e306fb12d 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/GraphvizDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/GraphvizDumper.php @@ -171,7 +171,7 @@ private function findNodes(): array } foreach ($container->getServiceIds() as $id) { - if (array_key_exists($id, $container->getAliases())) { + if (\array_key_exists($id, $container->getAliases())) { continue; } diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index 96b0812479467..f58e8b56d9fc2 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -687,8 +687,8 @@ protected function {$methodName}($lazyInitialization) $code .= $this->addServiceInclude($id, $definition); if ($this->getProxyDumper()->isProxyCandidate($definition)) { - $factoryCode = $asFile ? "\$this->load('%s.php', false)" : '$this->%s(false)'; - $code .= $this->getProxyDumper()->getProxyFactoryCode($definition, $id, sprintf($factoryCode, $methodName)); + $factoryCode = $asFile ? ($definition->isShared() ? "\$this->load('%s.php', false)" : "\$this->factories['%2$s'](false)") : '$this->%s(false)'; + $code .= $this->getProxyDumper()->getProxyFactoryCode($definition, $id, sprintf($factoryCode, $methodName, $this->export($id))); } if ($definition->isDeprecated()) { @@ -862,7 +862,9 @@ private function generateServiceFiles(array $services) } $code[1] = implode("\n", array_map(function ($line) { return $line ? ' '.$line : $line; }, explode("\n", $code[1]))); $factory = sprintf('$this->factories%s[\'%s\']', $definition->isPublic() ? '' : "['service_container']", $id); - $code[1] = sprintf("%s = function () {\n%s};\n\nreturn %1\$s();\n", $factory, $code[1]); + $lazyloadInitialization = $definition->isLazy() ? '$lazyLoad = true' : ''; + + $code[1] = sprintf("%s = function (%s) {\n%s};\n\nreturn %1\$s();\n", $factory, $lazyloadInitialization, $code[1]); $code = $code[0].$code[1]; } diff --git a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php index 527060005d69d..03e822154d589 100644 --- a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php +++ b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php @@ -65,7 +65,7 @@ public function getEnv($prefix, $name, \Closure $getEnv) if (!\is_array($array)) { throw new RuntimeException(sprintf('Resolved value of "%s" did not result in an array value.', $next)); } - if (!array_key_exists($key, $array)) { + if (!\array_key_exists($key, $array)) { throw new RuntimeException(sprintf('Key "%s" not found in "%s" (resolved from "%s")', $key, json_encode($array), $next)); } diff --git a/src/Symfony/Component/DependencyInjection/Extension/Extension.php b/src/Symfony/Component/DependencyInjection/Extension/Extension.php index 25d07ff83b3af..1285334f58a77 100644 --- a/src/Symfony/Component/DependencyInjection/Extension/Extension.php +++ b/src/Symfony/Component/DependencyInjection/Extension/Extension.php @@ -127,7 +127,7 @@ final public function getProcessedConfigs() */ protected function isConfigEnabled(ContainerBuilder $container, array $config) { - if (!array_key_exists('enabled', $config)) { + if (!\array_key_exists('enabled', $config)) { throw new InvalidArgumentException("The config array has no 'enabled' key."); } diff --git a/src/Symfony/Component/DependencyInjection/LazyProxy/Instantiator/RealServiceInstantiator.php b/src/Symfony/Component/DependencyInjection/LazyProxy/Instantiator/RealServiceInstantiator.php index 4d6a9f05a9395..2e36704080e6d 100644 --- a/src/Symfony/Component/DependencyInjection/LazyProxy/Instantiator/RealServiceInstantiator.php +++ b/src/Symfony/Component/DependencyInjection/LazyProxy/Instantiator/RealServiceInstantiator.php @@ -17,7 +17,7 @@ /** * {@inheritdoc} * - * Noop proxy instantiator - simply produces the real service instead of a proxy instance. + * Noop proxy instantiator - produces the real service instead of a proxy instance. * * @author Marco Pivetta */ diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 54c6fee5e2931..f9e0e472f2182 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -349,7 +349,7 @@ private function parseDefinition(\DOMElement $service, $file, array $defaults) continue; } - if (false !== strpos($name, '-') && false === strpos($name, '_') && !array_key_exists($normalizedName = str_replace('-', '_', $name), $parameters)) { + if (false !== strpos($name, '-') && false === strpos($name, '_') && !\array_key_exists($normalizedName = str_replace('-', '_', $name), $parameters)) { $parameters[$normalizedName] = XmlUtils::phpize($node->nodeValue); } // keep not normalized key diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 3377b9aea47d7..9ad295fe1b48a 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -203,7 +203,7 @@ private function parseDefinitions(array $content, string $file) throw new InvalidArgumentException(sprintf('The "services" key should contain an array in %s. Check your YAML syntax.', $file)); } - if (array_key_exists('_instanceof', $content['services'])) { + if (\array_key_exists('_instanceof', $content['services'])) { $instanceof = $content['services']['_instanceof']; unset($content['services']['_instanceof']); @@ -235,7 +235,7 @@ private function parseDefinitions(array $content, string $file) */ private function parseDefaults(array &$content, string $file): array { - if (!array_key_exists('_defaults', $content['services'])) { + if (!\array_key_exists('_defaults', $content['services'])) { return []; } $defaults = $content['services']['_defaults']; @@ -342,7 +342,7 @@ private function parseDefinition($id, $service, $file, array $defaults) if (isset($service['alias'])) { $this->container->setAlias($id, $alias = new Alias($service['alias'])); - if (array_key_exists('public', $service)) { + if (\array_key_exists('public', $service)) { $alias->setPublic($service['public']); } elseif (isset($defaults['public'])) { $alias->setPublic($defaults['public']); @@ -426,7 +426,7 @@ private function parseDefinition($id, $service, $file, array $defaults) $definition->setAbstract($service['abstract']); } - if (array_key_exists('deprecated', $service)) { + if (\array_key_exists('deprecated', $service)) { $definition->setDeprecated(true, $service['deprecated']); } @@ -541,11 +541,11 @@ private function parseDefinition($id, $service, $file, array $defaults) } } - if (array_key_exists('namespace', $service) && !array_key_exists('resource', $service)) { + if (\array_key_exists('namespace', $service) && !\array_key_exists('resource', $service)) { throw new InvalidArgumentException(sprintf('A "resource" attribute must be set when the "namespace" attribute is set for service "%s" in %s. Check your YAML syntax.', $id, $file)); } - if (array_key_exists('resource', $service)) { + if (\array_key_exists('resource', $service)) { if (!\is_string($service['resource'])) { throw new InvalidArgumentException(sprintf('A "resource" attribute must be of type string for service "%s" in %s. Check your YAML syntax.', $id, $file)); } diff --git a/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php b/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php index 84170577fc8d7..988dbf88cca64 100644 --- a/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php +++ b/src/Symfony/Component/DependencyInjection/ParameterBag/ParameterBag.php @@ -68,7 +68,7 @@ public function get($name) { $name = (string) $name; - if (!array_key_exists($name, $this->parameters)) { + if (!\array_key_exists($name, $this->parameters)) { if (!$name) { throw new ParameterNotFoundException($name); } @@ -119,7 +119,7 @@ public function set($name, $value) */ public function has($name) { - return array_key_exists((string) $name, $this->parameters); + return \array_key_exists((string) $name, $this->parameters); } /** diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index b4acc949c2619..9a77e51548a5e 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -230,6 +230,24 @@ public function testDumpAsFiles() $this->assertStringMatchesFormatFile(self::$fixturesPath.'/php/services9_as_files.txt', $dump); } + public function testNonSharedLazyDumpAsFiles() + { + $container = include self::$fixturesPath.'/containers/container_non_shared_lazy.php'; + $container->register('non_shared_foo', \Bar\FooLazyClass::class) + ->setFile(realpath(self::$fixturesPath.'/includes/foo_lazy.php')) + ->setShared(false) + ->setPublic(true) + ->setLazy(true); + $container->compile(); + $dumper = new PhpDumper($container); + $dump = print_r($dumper->dump(['as_files' => true, 'file' => __DIR__]), true); + + if ('\\' === \DIRECTORY_SEPARATOR) { + $dump = str_replace('\\\\Fixtures\\\\includes\\\\foo_lazy.php', '/Fixtures/includes/foo_lazy.php', $dump); + } + $this->assertStringMatchesFormatFile(self::$fixturesPath.'/php/services_non_shared_lazy_as_files.txt', $dump); + } + public function testServicesWithAnonymousFactories() { $container = include self::$fixturesPath.'/containers/container19.php'; diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_non_shared_lazy.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_non_shared_lazy.php new file mode 100644 index 0000000000000..58ff0bd5dcd57 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container_non_shared_lazy.php @@ -0,0 +1,5 @@ + true, + 'Symfony\\Component\\DependencyInjection\\ContainerInterface' => true, +]; + + [Container%s/getNonSharedFooService.php] => targetDirs[0].'/Fixtures/includes/foo_lazy.php'); + +$this->factories['non_shared_foo'] = function ($lazyLoad = true) { + return new \Bar\FooLazyClass(); +}; + +return $this->factories['non_shared_foo'](); + + [Container%s/ProjectServiceContainer.php] => targetDirs[0] = \dirname($containerDir); + for ($i = 1; $i <= 5; ++$i) { + $this->targetDirs[$i] = $dir = \dirname($dir); + } + $this->buildParameters = $buildParameters; + $this->containerDir = $containerDir; + $this->services = $this->privates = []; + $this->fileMap = [ + 'non_shared_foo' => 'getNonSharedFooService.php', + ]; + + $this->aliases = []; + } + + public function compile() + { + throw new LogicException('You cannot compile a dumped container that was already compiled.'); + } + + public function isCompiled() + { + return true; + } + + public function getRemovedIds() + { + return require $this->containerDir.\DIRECTORY_SEPARATOR.'removed-ids.php'; + } + + protected function load($file, $lazyLoad = true) + { + return require $this->containerDir.\DIRECTORY_SEPARATOR.$file; + } +} + + [ProjectServiceContainer.php] => '%s', + 'container.build_id' => '%s', + 'container.build_time' => %d, +], __DIR__.\DIRECTORY_SEPARATOR.'Container%s'); + +) \ No newline at end of file diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php index d8a287a56e07f..5dbffe42c609a 100644 --- a/src/Symfony/Component/DomCrawler/Crawler.php +++ b/src/Symfony/Component/DomCrawler/Crawler.php @@ -971,7 +971,7 @@ private function relativize(string $xpath): string $expressions = []; // An expression which will never match to replace expressions which cannot match in the crawler - // We cannot simply drop + // We cannot drop $nonMatchingExpression = 'a[name() = "b"]'; $xpathLen = \strlen($xpath); diff --git a/src/Symfony/Component/DomCrawler/Field/FileFormField.php b/src/Symfony/Component/DomCrawler/Field/FileFormField.php index af9c6e6f25ff4..9e21c9c4b9bd1 100644 --- a/src/Symfony/Component/DomCrawler/Field/FileFormField.php +++ b/src/Symfony/Component/DomCrawler/Field/FileFormField.php @@ -60,7 +60,7 @@ public function setValue($value) // copy to a tmp location $tmp = sys_get_temp_dir().'/'.strtr(substr(base64_encode(hash('sha256', uniqid(mt_rand(), true), true)), 0, 7), '/', '_'); - if (array_key_exists('extension', $info)) { + if (\array_key_exists('extension', $info)) { $tmp .= '.'.$info['extension']; } if (is_file($tmp)) { diff --git a/src/Symfony/Component/DomCrawler/FormFieldRegistry.php b/src/Symfony/Component/DomCrawler/FormFieldRegistry.php index 10c7e8cb365b2..8f432cfbbb830 100644 --- a/src/Symfony/Component/DomCrawler/FormFieldRegistry.php +++ b/src/Symfony/Component/DomCrawler/FormFieldRegistry.php @@ -57,7 +57,7 @@ public function remove($name) $target = &$this->fields; while (\count($segments) > 1) { $path = array_shift($segments); - if (!array_key_exists($path, $target)) { + if (!\array_key_exists($path, $target)) { return; } $target = &$target[$path]; @@ -80,7 +80,7 @@ public function &get($name) $target = &$this->fields; while ($segments) { $path = array_shift($segments); - if (!array_key_exists($path, $target)) { + if (!\array_key_exists($path, $target)) { throw new \InvalidArgumentException(sprintf('Unreachable field "%s"', $path)); } $target = &$target[$path]; diff --git a/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php b/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php index 5c9249de28c53..24e2bb4324988 100644 --- a/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php +++ b/src/Symfony/Component/EventDispatcher/Debug/WrappedListener.php @@ -29,6 +29,7 @@ class WrappedListener private $dispatcher; private $pretty; private $stub; + private $priority; private static $hasClassStub; public function __construct($listener, $name, Stopwatch $stopwatch, EventDispatcherInterface $dispatcher = null) @@ -96,7 +97,7 @@ public function getInfo($eventName) return [ 'event' => $eventName, - 'priority' => null !== $this->dispatcher ? $this->dispatcher->getListenerPriority($eventName, $this->listener) : null, + 'priority' => null !== $this->priority ? $this->priority : (null !== $this->dispatcher ? $this->dispatcher->getListenerPriority($eventName, $this->listener) : null), 'pretty' => $this->pretty, 'stub' => $this->stub, ]; @@ -104,11 +105,14 @@ public function getInfo($eventName) public function __invoke(Event $event, $eventName, EventDispatcherInterface $dispatcher) { + $dispatcher = $this->dispatcher ?: $dispatcher; + $this->called = true; + $this->priority = $dispatcher->getListenerPriority($eventName, $this->listener); $e = $this->stopwatch->start($this->name, 'event_listener'); - ($this->listener)($event, $eventName, $this->dispatcher ?: $dispatcher); + ($this->listener)($event, $eventName, $dispatcher); if ($e->isStarted()) { $e->stop(); diff --git a/src/Symfony/Component/EventDispatcher/GenericEvent.php b/src/Symfony/Component/EventDispatcher/GenericEvent.php index a9a0a5dfa59c6..f005e3a3db076 100644 --- a/src/Symfony/Component/EventDispatcher/GenericEvent.php +++ b/src/Symfony/Component/EventDispatcher/GenericEvent.php @@ -111,7 +111,7 @@ public function setArguments(array $args = []) */ public function hasArgument($key) { - return array_key_exists($key, $this->arguments); + return \array_key_exists($key, $this->arguments); } /** diff --git a/src/Symfony/Component/Filesystem/Exception/IOExceptionInterface.php b/src/Symfony/Component/Filesystem/Exception/IOExceptionInterface.php index c11965a4247ee..f9d4644a87279 100644 --- a/src/Symfony/Component/Filesystem/Exception/IOExceptionInterface.php +++ b/src/Symfony/Component/Filesystem/Exception/IOExceptionInterface.php @@ -21,7 +21,7 @@ interface IOExceptionInterface extends ExceptionInterface /** * Returns the associated path for the exception. * - * @return string The path + * @return string|null The path */ public function getPath(); } diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index 4c87b11a5b4cd..082084b4d93d1 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -138,8 +138,8 @@ public function exists($files) * Sets access and modification time of file. * * @param string|iterable $files A filename, an array of files, or a \Traversable instance to create - * @param int $time The touch time as a Unix timestamp - * @param int $atime The access time as a Unix timestamp + * @param int|null $time The touch time as a Unix timestamp, if not supplied the current system time is used + * @param int|null $atime The access time as a Unix timestamp, if not supplied the current system time is used * * @throws IOException When touch fails */ @@ -194,7 +194,7 @@ public function remove($files) * @param int $umask The mode mask (octal) * @param bool $recursive Whether change the mod recursively or not * - * @throws IOException When the change fail + * @throws IOException When the change fails */ public function chmod($files, $mode, $umask = 0000, $recursive = false) { @@ -215,7 +215,7 @@ public function chmod($files, $mode, $umask = 0000, $recursive = false) * @param string $user The new owner user name * @param bool $recursive Whether change the owner recursively or not * - * @throws IOException When the change fail + * @throws IOException When the change fails */ public function chown($files, $user, $recursive = false) { @@ -242,7 +242,7 @@ public function chown($files, $user, $recursive = false) * @param string $group The group name * @param bool $recursive Whether change the group recursively or not * - * @throws IOException When the change fail + * @throws IOException When the change fails */ public function chgrp($files, $group, $recursive = false) { @@ -524,14 +524,14 @@ public function makePathRelative($endPath, $startPath) * - existing files in the target directory will be overwritten, except if they are newer (see the `override` option) * - files in the target directory that do not exist in the source directory will not be deleted (see the `delete` option) * - * @param string $originDir The origin directory - * @param string $targetDir The target directory - * @param \Traversable $iterator Iterator that filters which files and directories to copy - * @param array $options An array of boolean options - * Valid options are: - * - $options['override'] If true, target files newer than origin files are overwritten (see copy(), defaults to false) - * - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see symlink(), defaults to false) - * - $options['delete'] Whether to delete files that are not in the source directory (defaults to false) + * @param string $originDir The origin directory + * @param string $targetDir The target directory + * @param \Traversable|null $iterator Iterator that filters which files and directories to copy, if null a recursive iterator is created + * @param array $options An array of boolean options + * Valid options are: + * - $options['override'] If true, target files newer than origin files are overwritten (see copy(), defaults to false) + * - $options['copy_on_windows'] Whether to copy files instead of links on Windows (see symlink(), defaults to false) + * - $options['delete'] Whether to delete files that are not in the source directory (defaults to false) * * @throws IOException When file type is unknown */ diff --git a/src/Symfony/Component/Finder/Finder.php b/src/Symfony/Component/Finder/Finder.php index ab8f92b366299..83163f51d52eb 100644 --- a/src/Symfony/Component/Finder/Finder.php +++ b/src/Symfony/Component/Finder/Finder.php @@ -29,7 +29,7 @@ * * All rules may be invoked several times. * - * All methods return the current Finder object to allow easy chaining: + * All methods return the current Finder object to allow chaining: * * $finder = Finder::create()->files()->name('*.php')->in(__DIR__); * @@ -674,12 +674,15 @@ public function count() private function searchInDirectory(string $dir): \Iterator { + $exclude = $this->exclude; + $notPaths = $this->notPaths; + if (static::IGNORE_VCS_FILES === (static::IGNORE_VCS_FILES & $this->ignore)) { - $this->exclude = array_merge($this->exclude, self::$vcsPatterns); + $exclude = array_merge($exclude, self::$vcsPatterns); } if (static::IGNORE_DOT_FILES === (static::IGNORE_DOT_FILES & $this->ignore)) { - $this->notPaths[] = '#(^|/)\..+(/|$)#'; + $notPaths[] = '#(^|/)\..+(/|$)#'; } $minDepth = 0; @@ -712,8 +715,8 @@ private function searchInDirectory(string $dir): \Iterator $iterator = new Iterator\RecursiveDirectoryIterator($dir, $flags, $this->ignoreUnreadableDirs); - if ($this->exclude) { - $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $this->exclude); + if ($exclude) { + $iterator = new Iterator\ExcludeDirectoryFilterIterator($iterator, $exclude); } $iterator = new \RecursiveIteratorIterator($iterator, \RecursiveIteratorIterator::SELF_FIRST); @@ -746,8 +749,8 @@ private function searchInDirectory(string $dir): \Iterator $iterator = new Iterator\CustomFilterIterator($iterator, $this->filters); } - if ($this->paths || $this->notPaths) { - $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $this->notPaths); + if ($this->paths || $notPaths) { + $iterator = new Iterator\PathFilterIterator($iterator, $this->paths, $notPaths); } if ($this->sort || $this->reverseSorting) { diff --git a/src/Symfony/Component/Finder/Tests/FinderTest.php b/src/Symfony/Component/Finder/Tests/FinderTest.php index 1b50663e9f13c..9217cb7190b53 100644 --- a/src/Symfony/Component/Finder/Tests/FinderTest.php +++ b/src/Symfony/Component/Finder/Tests/FinderTest.php @@ -421,6 +421,59 @@ public function testIgnoreVCS() ]), $finder->in(self::$tmpDir)->getIterator()); } + public function testIgnoreVCSCanBeDisabledAfterFirstIteration() + { + $finder = $this->buildFinder(); + $finder->in(self::$tmpDir); + $finder->ignoreDotFiles(false); + + $this->assertIterator($this->toAbsolute([ + 'foo', + 'foo/bar.tmp', + 'qux', + 'qux/baz_100_1.py', + 'qux/baz_1_2.py', + 'qux_0_1.php', + 'qux_1000_1.php', + 'qux_1002_0.php', + 'qux_10_2.php', + 'qux_12_0.php', + 'qux_2_0.php', + 'test.php', + 'test.py', + 'toto', + '.bar', + '.foo', + '.foo/.bar', + '.foo/bar', + 'foo bar', + ]), $finder->getIterator()); + + $finder->ignoreVCS(false); + $this->assertIterator($this->toAbsolute(['.git', + 'foo', + 'foo/bar.tmp', + 'qux', + 'qux/baz_100_1.py', + 'qux/baz_1_2.py', + 'qux_0_1.php', + 'qux_1000_1.php', + 'qux_1002_0.php', + 'qux_10_2.php', + 'qux_12_0.php', + 'qux_2_0.php', + 'test.php', + 'test.py', + 'toto', + 'toto/.git', + '.bar', + '.foo', + '.foo/.bar', + '.foo/bar', + 'foo bar', + ]), $finder->getIterator()); + } + public function testIgnoreDotFiles() { $finder = $this->buildFinder(); @@ -496,6 +549,53 @@ public function testIgnoreDotFiles() ]), $finder->in(self::$tmpDir)->getIterator()); } + public function testIgnoreDotFilesCanBeDisabledAfterFirstIteration() + { + $finder = $this->buildFinder(); + $finder->in(self::$tmpDir); + + $this->assertIterator($this->toAbsolute([ + 'foo', + 'foo/bar.tmp', + 'qux', + 'qux/baz_100_1.py', + 'qux/baz_1_2.py', + 'qux_0_1.php', + 'qux_1000_1.php', + 'qux_1002_0.php', + 'qux_10_2.php', + 'qux_12_0.php', + 'qux_2_0.php', + 'test.php', + 'test.py', + 'toto', + 'foo bar', + ]), $finder->getIterator()); + + $finder->ignoreDotFiles(false); + $this->assertIterator($this->toAbsolute([ + 'foo', + 'foo/bar.tmp', + 'qux', + 'qux/baz_100_1.py', + 'qux/baz_1_2.py', + 'qux_0_1.php', + 'qux_1000_1.php', + 'qux_1002_0.php', + 'qux_10_2.php', + 'qux_12_0.php', + 'qux_2_0.php', + 'test.php', + 'test.py', + 'toto', + '.bar', + '.foo', + '.foo/.bar', + '.foo/bar', + 'foo bar', + ]), $finder->getIterator()); + } + public function testSortByName() { $finder = $this->buildFinder(); diff --git a/src/Symfony/Component/Form/ButtonBuilder.php b/src/Symfony/Component/Form/ButtonBuilder.php index 5a67b7d23f872..27d8e70f2bc65 100644 --- a/src/Symfony/Component/Form/ButtonBuilder.php +++ b/src/Symfony/Component/Form/ButtonBuilder.php @@ -658,7 +658,7 @@ public function getAttributes() */ public function hasAttribute($name) { - return array_key_exists($name, $this->attributes); + return \array_key_exists($name, $this->attributes); } /** @@ -671,7 +671,7 @@ public function hasAttribute($name) */ public function getAttribute($name, $default = null) { - return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default; + return \array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default; } /** @@ -765,7 +765,7 @@ public function getOptions() */ public function hasOption($name) { - return array_key_exists($name, $this->options); + return \array_key_exists($name, $this->options); } /** @@ -778,7 +778,7 @@ public function hasOption($name) */ public function getOption($name, $default = null) { - return array_key_exists($name, $this->options) ? $this->options[$name] : $default; + return \array_key_exists($name, $this->options) ? $this->options[$name] : $default; } /** diff --git a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php index b24f32a8cdbe4..a3150d275f558 100644 --- a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php +++ b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php @@ -78,7 +78,7 @@ public function __construct(iterable $choices, callable $value = null) // If a deterministic value generator was passed, use it later $this->valueCallback = $value; } else { - // Otherwise simply generate incrementing integers as values + // Otherwise generate incrementing integers as values $i = 0; $value = function () use (&$i) { return $i++; @@ -135,7 +135,7 @@ public function getChoicesForValues(array $values) $choices = []; foreach ($values as $i => $givenValue) { - if (array_key_exists($givenValue, $this->choices)) { + if (\array_key_exists($givenValue, $this->choices)) { $choices[$i] = $this->choices[$givenValue]; } } diff --git a/src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php b/src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php index 30cc97551c2e0..b1a671d0c65eb 100644 --- a/src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php +++ b/src/Symfony/Component/Form/ChoiceList/LazyChoiceList.php @@ -32,7 +32,7 @@ class LazyChoiceList implements ChoiceListInterface /** * The callable creating string values for each choice. * - * If null, choices are simply cast to strings. + * If null, choices are cast to strings. * * @var callable|null */ diff --git a/src/Symfony/Component/Form/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Component/Form/Console/Descriptor/JsonDescriptor.php index 31d9aa485e676..18a288b444dd6 100644 --- a/src/Symfony/Component/Form/Console/Descriptor/JsonDescriptor.php +++ b/src/Symfony/Component/Form/Console/Descriptor/JsonDescriptor.php @@ -79,7 +79,7 @@ protected function describeOption(OptionsResolver $optionsResolver, array $optio 'allowed_values' => 'allowedValues', ]; foreach ($map as $label => $name) { - if (array_key_exists($name, $definition)) { + if (\array_key_exists($name, $definition)) { $data[$label] = $definition[$name]; if ('default' === $name) { diff --git a/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php b/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php index 4ea8ab6d834e5..48e0112e95d85 100644 --- a/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Component/Form/Console/Descriptor/TextDescriptor.php @@ -114,7 +114,7 @@ protected function describeOption(OptionsResolver $optionsResolver, array $optio ]; $rows = []; foreach ($map as $label => $name) { - $value = array_key_exists($name, $definition) ? $dump($definition[$name]) : '-'; + $value = \array_key_exists($name, $definition) ? $dump($definition[$name]) : '-'; if ('default' === $name && isset($definition['lazy'])) { $value = "Value: $value\n\nClosure(s): ".$dump($definition['lazy']); } diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php index e4f077d277a8a..392aa49e51a19 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformer.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Form\Extension\Core\DataTransformer; +use Symfony\Component\Form\Exception\TransformationFailedException; + /** * Transforms between an integer and a localized number with grouping * (each thousand) and comma separators. @@ -42,8 +44,22 @@ public function __construct($grouping = false, $roundingMode = self::ROUND_DOWN) */ public function reverseTransform($value) { + $decimalSeparator = $this->getNumberFormatter()->getSymbol(\NumberFormatter::DECIMAL_SEPARATOR_SYMBOL); + + if (\is_string($value) && false !== strpos($value, $decimalSeparator)) { + throw new TransformationFailedException(sprintf('The value "%s" is not a valid integer.', $value)); + } + $result = parent::reverseTransform($value); return null !== $result ? (int) $result : null; } + + /** + * @internal + */ + protected function castParsedValue($value) + { + return $value; + } } diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php index 787805e2abcf2..ca341ac7120a0 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformer.php @@ -58,7 +58,7 @@ public function transform($value) if (!is_numeric($value)) { throw new TransformationFailedException('Expected a numeric.'); } - $value = (string) ($value / $this->divisor); + $value /= $this->divisor; } return parent::transform($value); diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php index f6f98e6de39ee..b019fff4a8e72 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php @@ -181,9 +181,7 @@ public function reverseTransform($value) throw new TransformationFailedException('I don\'t have a clear idea what infinity looks like'); } - if (\is_int($result) && $result === (int) $float = (float) $result) { - $result = $float; - } + $result = $this->castParsedValue($result); if (false !== $encoding = mb_detect_encoding($value, null, true)) { $length = mb_strlen($value, $encoding); @@ -228,6 +226,18 @@ protected function getNumberFormatter() return $formatter; } + /** + * @internal + */ + protected function castParsedValue($value) + { + if (\is_int($value) && $value === (int) $float = (float) $value) { + return $float; + } + + return $value; + } + /** * Rounds a number according to the configured scale and rounding mode. * diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php index 31757e2887184..11ff3fa89b481 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/FormType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/FormType.php @@ -38,7 +38,7 @@ public function buildForm(FormBuilderInterface $builder, array $options) { parent::buildForm($builder, $options); - $isDataOptionSet = array_key_exists('data', $options); + $isDataOptionSet = \array_key_exists('data', $options); $builder ->setRequired($options['required']) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/IntegerType.php b/src/Symfony/Component/Form/Extension/Core/Type/IntegerType.php index af52002ebd183..540cdb6f79db3 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/IntegerType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/IntegerType.php @@ -14,6 +14,8 @@ use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\Extension\Core\DataTransformer\IntegerToLocalizedStringTransformer; use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\OptionsResolver; class IntegerType extends AbstractType @@ -26,6 +28,16 @@ public function buildForm(FormBuilderInterface $builder, array $options) $builder->addViewTransformer(new IntegerToLocalizedStringTransformer($options['grouping'], $options['rounding_mode'])); } + /** + * {@inheritdoc} + */ + public function buildView(FormView $view, FormInterface $form, array $options) + { + if ($options['grouping']) { + $view->vars['type'] = 'text'; + } + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php b/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php index fe25f1f497753..7c5181e17d9b8 100644 --- a/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php +++ b/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php @@ -66,8 +66,10 @@ public function preSubmit(FormEvent $event) if ($form->isRoot() && $form->getConfig()->getOption('compound') && !$postRequestSizeExceeded) { $data = $event->getData(); - $csrfToken = new CsrfToken($this->tokenId, $data[$this->fieldName] ?? null); - if (!isset($data[$this->fieldName]) || !$this->tokenManager->isTokenValid($csrfToken)) { + $csrfValue = \is_string($data[$this->fieldName] ?? null) ? $data[$this->fieldName] : null; + $csrfToken = new CsrfToken($this->tokenId, $csrfValue); + + if (null === $csrfValue || !$this->tokenManager->isTokenValid($csrfToken)) { $errorMessage = $this->errorMessage; if (null !== $this->translator) { diff --git a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php index 28cf9510d8be3..96baf9b58d7f5 100644 --- a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php +++ b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php @@ -229,9 +229,6 @@ public function getData() return $this->data; } - /** - * @internal - */ public function serialize() { foreach ($this->data['forms_by_hash'] as &$form) { diff --git a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php index 6e6ef0c876781..db96bc731b9ba 100644 --- a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php +++ b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php @@ -26,10 +26,10 @@ class FormValidator extends ConstraintValidator /** * {@inheritdoc} */ - public function validate($form, Constraint $constraint) + public function validate($form, Constraint $formConstraint) { - if (!$constraint instanceof Form) { - throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Form'); + if (!$formConstraint instanceof Form) { + throw new UnexpectedTypeException($formConstraint, __NAMESPACE__.'\Form'); } if (!$form instanceof FormInterface) { @@ -41,7 +41,7 @@ public function validate($form, Constraint $constraint) $validator = $this->context->getValidator()->inContext($this->context); - if ($form->isSynchronized()) { + if ($form->isSubmitted() && $form->isSynchronized()) { // Validate the form data only if transformation succeeded $groups = self::getValidationGroups($form); $data = $form->getData(); @@ -62,8 +62,8 @@ public function validate($form, Constraint $constraint) // Otherwise validate a constraint only once for the first // matching group foreach ($groups as $group) { - if (\in_array($group, $constraint->groups)) { - $validator->atPath('data')->validate($form->getData(), $constraint, $group); + if (\in_array($group, $formConstraint->groups)) { + $validator->atPath('data')->validate($form->getData(), $formConstraint, $group); if (\count($this->context->getViolations()) > 0) { break; } @@ -90,7 +90,7 @@ public function validate($form, Constraint $constraint) } } } - } else { + } elseif (!$form->isSynchronized()) { $childrenSynchronized = true; /** @var FormInterface $child */ @@ -113,7 +113,7 @@ public function validate($form, Constraint $constraint) ? (string) $form->getViewData() : \gettype($form->getViewData()); - $this->context->setConstraint($constraint); + $this->context->setConstraint($formConstraint); $this->context->buildViolation($config->getOption('invalid_message')) ->setParameters(array_replace(['{{ value }}' => $clientDataAsString], $config->getOption('invalid_message_parameters'))) ->setInvalidValue($form->getViewData()) @@ -125,7 +125,7 @@ public function validate($form, Constraint $constraint) // Mark the form with an error if it contains extra fields if (!$config->getOption('allow_extra_fields') && \count($form->getExtraData()) > 0) { - $this->context->setConstraint($constraint); + $this->context->setConstraint($formConstraint); $this->context->buildViolation($config->getOption('extra_fields_message')) ->setParameter('{{ extra_fields }}', '"'.implode('", "', array_keys($form->getExtraData())).'"') ->setInvalidValue($form->getExtraData()) diff --git a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php index eda99c0a62162..d322c1d8d99e5 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php +++ b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/MappingRule.php @@ -50,7 +50,7 @@ public function getOrigin() */ public function match($propertyPath) { - if ($propertyPath === (string) $this->propertyPath) { + if ($propertyPath === $this->propertyPath) { return $this->getTarget(); } } diff --git a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php index 86a77044d13d5..659c266ce6fa9 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php +++ b/src/Symfony/Component/Form/Extension/Validator/ViolationMapper/ViolationMapper.php @@ -273,9 +273,6 @@ private function reconstructPath(ViolationPath $violationPath, FormInterface $or */ private function acceptsErrors(FormInterface $form) { - // Ignore non-submitted forms. This happens, for example, in PATCH - // requests. - // https://github.com/symfony/symfony/pull/10567 - return $form->isSubmitted() && ($this->allowNonSynchronized || $form->isSynchronized()); + return $this->allowNonSynchronized || $form->isSynchronized(); } } diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index fb0ba683e82e7..17ecfd6f47741 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -42,9 +42,9 @@ * * In most cases, format (1) and format (2) will be the same. For example, * a checkbox field uses a Boolean value for both internal processing and - * storage in the object. In these cases you simply need to set a view - * transformer to convert between formats (2) and (3). You can do this by - * calling addViewTransformer(). + * storage in the object. In these cases you need to set a view transformer + * to convert between formats (2) and (3). You can do this by calling + * addViewTransformer(). * * In some cases though it makes sense to make format (1) configurable. To * demonstrate this, let's extend our above date field to store the value @@ -574,7 +574,7 @@ public function submit($submittedData, $clearMissing = true) } foreach ($this->children as $name => $child) { - $isSubmitted = array_key_exists($name, $submittedData); + $isSubmitted = \array_key_exists($name, $submittedData); if ($isSubmitted || $clearMissing) { $child->submit($isSubmitted ? $submittedData[$name] : null, $clearMissing); diff --git a/src/Symfony/Component/Form/FormConfigBuilder.php b/src/Symfony/Component/Form/FormConfigBuilder.php index 344751b15976d..1a581d9b8e67e 100644 --- a/src/Symfony/Component/Form/FormConfigBuilder.php +++ b/src/Symfony/Component/Form/FormConfigBuilder.php @@ -418,7 +418,7 @@ public function getAttributes() */ public function hasAttribute($name) { - return array_key_exists($name, $this->attributes); + return \array_key_exists($name, $this->attributes); } /** @@ -426,7 +426,7 @@ public function hasAttribute($name) */ public function getAttribute($name, $default = null) { - return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default; + return \array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default; } /** @@ -513,7 +513,7 @@ public function getOptions() */ public function hasOption($name) { - return array_key_exists($name, $this->options); + return \array_key_exists($name, $this->options); } /** @@ -521,7 +521,7 @@ public function hasOption($name) */ public function getOption($name, $default = null) { - return array_key_exists($name, $this->options) ? $this->options[$name] : $default; + return \array_key_exists($name, $this->options) ? $this->options[$name] : $default; } /** diff --git a/src/Symfony/Component/Form/FormFactory.php b/src/Symfony/Component/Form/FormFactory.php index d474d5903f86f..b397f9a21fbfa 100644 --- a/src/Symfony/Component/Form/FormFactory.php +++ b/src/Symfony/Component/Form/FormFactory.php @@ -63,7 +63,7 @@ public function createBuilder($type = 'Symfony\Component\Form\Extension\Core\Typ */ public function createNamedBuilder($name, $type = 'Symfony\Component\Form\Extension\Core\Type\FormType', $data = null, array $options = []) { - if (null !== $data && !array_key_exists('data', $options)) { + if (null !== $data && !\array_key_exists('data', $options)) { $options['data'] = $data; } diff --git a/src/Symfony/Component/Form/FormRenderer.php b/src/Symfony/Component/Form/FormRenderer.php index 4b3866fe1cbe7..91e6faa9cc358 100644 --- a/src/Symfony/Component/Form/FormRenderer.php +++ b/src/Symfony/Component/Form/FormRenderer.php @@ -165,7 +165,7 @@ public function searchAndRenderBlock(FormView $view, $blockNameSuffix, array $va // "form_widget" in this example (again, no matter in which theme). // If the designer wants to explicitly fallback to "form_widget" in their // custom "choice_widget", for example because they only want to wrap - // a
around the original implementation, they can simply call the + // a
around the original implementation, they can call the // widget() function again to render the block for the parent type. // // The second kind is implemented in the following blocks. diff --git a/src/Symfony/Component/Form/FormTypeGuesserInterface.php b/src/Symfony/Component/Form/FormTypeGuesserInterface.php index 0aec6364c4ac7..6521ea47ca767 100644 --- a/src/Symfony/Component/Form/FormTypeGuesserInterface.php +++ b/src/Symfony/Component/Form/FormTypeGuesserInterface.php @@ -32,7 +32,7 @@ public function guessType($class, $property); * @param string $class The fully qualified class name * @param string $property The name of the property to guess for * - * @return Guess\ValueGuess A guess for the field's required setting + * @return Guess\ValueGuess|null A guess for the field's required setting */ public function guessRequired($class, $property); diff --git a/src/Symfony/Component/Form/NativeRequestHandler.php b/src/Symfony/Component/Form/NativeRequestHandler.php index fe0b3b7ab75a3..cfccf180b9abc 100644 --- a/src/Symfony/Component/Form/NativeRequestHandler.php +++ b/src/Symfony/Component/Form/NativeRequestHandler.php @@ -94,10 +94,10 @@ public function handleRequest(FormInterface $form, $request = null) if ('' === $name) { $params = $_POST; $files = $fixedFiles; - } elseif (array_key_exists($name, $_POST) || array_key_exists($name, $fixedFiles)) { + } elseif (\array_key_exists($name, $_POST) || \array_key_exists($name, $fixedFiles)) { $default = $form->getConfig()->getCompound() ? [] : null; - $params = array_key_exists($name, $_POST) ? $_POST[$name] : $default; - $files = array_key_exists($name, $fixedFiles) ? $fixedFiles[$name] : $default; + $params = \array_key_exists($name, $_POST) ? $_POST[$name] : $default; + $files = \array_key_exists($name, $fixedFiles) ? $fixedFiles[$name] : $default; } else { // Don't submit the form if it is not present in the request return; @@ -115,6 +115,10 @@ public function handleRequest(FormInterface $form, $request = null) return; } + if (\is_array($data) && \array_key_exists('_method', $data) && $method === $data['_method'] && !$form->has('_method')) { + unset($data['_method']); + } + $form->submit($data, 'PATCH' !== $method); } diff --git a/src/Symfony/Component/Form/Test/FormPerformanceTestCase.php b/src/Symfony/Component/Form/Test/FormPerformanceTestCase.php index 01440575a1126..e11ce03357f6d 100644 --- a/src/Symfony/Component/Form/Test/FormPerformanceTestCase.php +++ b/src/Symfony/Component/Form/Test/FormPerformanceTestCase.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Form\Test; +use Symfony\Component\Form\Tests\VersionAwareTest; + /** * Base class for performance tests. * @@ -21,6 +23,8 @@ */ abstract class FormPerformanceTestCase extends FormIntegrationTestCase { + use VersionAwareTest; + /** * @var int */ diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index ab03646bbb332..4440776a8f3b8 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -19,6 +19,8 @@ abstract class AbstractLayoutTest extends FormIntegrationTestCase { + use VersionAwareTest; + protected $csrfTokenManager; protected $testableFeatures = []; @@ -1796,6 +1798,21 @@ public function testInteger() ); } + public function testIntegerTypeWithGroupingRendersAsTextInput() + { + $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\IntegerType', 123, [ + 'grouping' => true, + ]); + + $this->assertWidgetMatchesXpath($form->createView(), [], +'/input + [@type="text"] + [@name="name"] + [@value="123"] +' + ); + } + public function testLanguage() { $form = $this->factory->createNamed('name', 'Symfony\Component\Form\Extension\Core\Type\LanguageType', 'de'); diff --git a/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php b/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php index dd73dcde23e4e..16d4045e6d580 100644 --- a/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTest.php @@ -200,7 +200,7 @@ public function testMergeParamsAndFiles($method) $form = $this->createForm('param1', $method, true); $form->add($this->createForm('field1')); $form->add($this->createBuilder('field2', false, ['allow_file_upload' => true])->getForm()); - $file = $this->getMockFile(); + $file = $this->getUploadedFile(); $this->setRequestData($method, [ 'param1' => [ @@ -225,7 +225,7 @@ public function testMergeParamsAndFiles($method) public function testParamTakesPrecedenceOverFile($method) { $form = $this->createForm('param1', $method); - $file = $this->getMockFile(); + $file = $this->getUploadedFile(); $this->setRequestData($method, [ 'param1' => 'DATA', @@ -247,7 +247,7 @@ public function testSubmitFileIfNoParam($method) $form = $this->createBuilder('param1', false, ['allow_file_upload' => true]) ->setMethod($method) ->getForm(); - $file = $this->getMockFile(); + $file = $this->getUploadedFile(); $this->setRequestData($method, [ 'param1' => null, @@ -269,14 +269,14 @@ public function testSubmitMultipleFiles($method) $form = $this->createBuilder('param1', false, ['allow_file_upload' => true]) ->setMethod($method) ->getForm(); - $file = $this->getMockFile(); + $file = $this->getUploadedFile(); $this->setRequestData($method, [ 'param1' => null, ], [ - 'param2' => $this->getMockFile('2'), + 'param2' => $this->getUploadedFile('2'), 'param1' => $file, - 'param3' => $this->getMockFile('3'), + 'param3' => $this->getUploadedFile('3'), ]); $this->requestHandler->handleRequest($form, $this->request); @@ -285,6 +285,26 @@ public function testSubmitMultipleFiles($method) $this->assertSame($file, $form->getData()); } + /** + * @dataProvider methodExceptGetProvider + */ + public function testSubmitFileWithNamelessForm($method) + { + $form = $this->createForm('', $method, true); + $fileForm = $this->createBuilder('document', false, ['allow_file_upload' => true])->getForm(); + $form->add($fileForm); + $file = $this->getUploadedFile(); + $this->setRequestData($method, [ + 'document' => null, + ], [ + 'document' => $file, + ]); + $this->requestHandler->handleRequest($form, $this->request); + + $this->assertTrue($form->isSubmitted()); + $this->assertSame($file, $fileForm->getData()); + } + /** * @dataProvider getPostMaxSizeFixtures */ @@ -332,7 +352,7 @@ public function getPostMaxSizeFixtures() public function testUploadedFilesAreAccepted() { - $this->assertTrue($this->requestHandler->isFileUpload($this->getMockFile())); + $this->assertTrue($this->requestHandler->isFileUpload($this->getUploadedFile())); } public function testInvalidFilesAreRejected() @@ -344,7 +364,7 @@ abstract protected function setRequestData($method, $data, $files = []); abstract protected function getRequestHandler(); - abstract protected function getMockFile($suffix = ''); + abstract protected function getUploadedFile($suffix = ''); abstract protected function getInvalidFile(); diff --git a/src/Symfony/Component/Form/Tests/DependencyInjection/FormPassTest.php b/src/Symfony/Component/Form/Tests/DependencyInjection/FormPassTest.php index 1b202b5df1263..5d0518689a0f8 100644 --- a/src/Symfony/Component/Form/Tests/DependencyInjection/FormPassTest.php +++ b/src/Symfony/Component/Form/Tests/DependencyInjection/FormPassTest.php @@ -20,8 +20,9 @@ use Symfony\Component\DependencyInjection\ServiceLocator; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\AbstractTypeExtension; +use Symfony\Component\Form\Command\DebugCommand; use Symfony\Component\Form\DependencyInjection\FormPass; -use Symfony\Component\Form\FormRegistryInterface; +use Symfony\Component\Form\FormRegistry; /** * @author Bernhard Schussek @@ -71,8 +72,12 @@ public function testAddTaggedTypesToDebugCommand() { $container = $this->createContainerBuilder(); + $container->register('form.registry', FormRegistry::class); + $commandDefinition = new Definition(DebugCommand::class, [new Reference('form.registry')]); + $commandDefinition->setPublic(true); + $container->setDefinition('form.extension', $this->createExtensionDefinition()); - $container->setDefinition('console.command.form_debug', $this->createDebugCommandDefinition()); + $container->setDefinition('console.command.form_debug', $commandDefinition); $container->register('my.type1', __CLASS__.'_Type1')->addTag('form.type')->setPublic(true); $container->register('my.type2', __CLASS__.'_Type2')->addTag('form.type')->setPublic(true); @@ -379,19 +384,6 @@ private function createExtensionDefinition() return $definition; } - private function createDebugCommandDefinition() - { - $definition = new Definition('Symfony\Component\Form\Command\DebugCommand'); - $definition->setPublic(true); - $definition->setArguments([ - $formRegistry = $this->getMockBuilder(FormRegistryInterface::class)->getMock(), - [], - ['Symfony\Component\Form\Extension\Core\Type'], - ]); - - return $definition; - } - private function createContainerBuilder() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataMapper/PropertyPathMapperTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataMapper/PropertyPathMapperTest.php index e96162d642ecf..da351295c381e 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataMapper/PropertyPathMapperTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataMapper/PropertyPathMapperTest.php @@ -12,9 +12,14 @@ namespace Symfony\Component\Form\Tests\Extension\Core\DataMapper; use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; +use Symfony\Component\Form\Form; use Symfony\Component\Form\FormConfigBuilder; -use Symfony\Component\Form\FormConfigInterface; +use Symfony\Component\PropertyAccess\PropertyAccess; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; +use Symfony\Component\PropertyAccess\PropertyPath; class PropertyPathMapperTest extends TestCase { @@ -24,74 +29,36 @@ class PropertyPathMapperTest extends TestCase private $mapper; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var EventDispatcherInterface */ private $dispatcher; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var PropertyAccessorInterface */ private $propertyAccessor; protected function setUp() { - $this->dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); - $this->propertyAccessor = $this->getMockBuilder('Symfony\Component\PropertyAccess\PropertyAccessorInterface')->getMock(); + $this->dispatcher = new EventDispatcher(); + $this->propertyAccessor = PropertyAccess::createPropertyAccessor(); $this->mapper = new PropertyPathMapper($this->propertyAccessor); } - /** - * @return \PHPUnit_Framework_MockObject_MockObject - */ - private function getPropertyPath($path) - { - return $this->getMockBuilder('Symfony\Component\PropertyAccess\PropertyPath') - ->setConstructorArgs([$path]) - ->setMethods(['getValue', 'setValue']) - ->getMock(); - } - - /** - * @return \PHPUnit_Framework_MockObject_MockObject - */ - private function getForm(FormConfigInterface $config, bool $synchronized = true, bool $submitted = true) - { - $form = $this->getMockBuilder('Symfony\Component\Form\Form') - ->setConstructorArgs([$config]) - ->setMethods(['isSynchronized', 'isSubmitted']) - ->getMock(); - - $form->expects($this->any()) - ->method('isSynchronized') - ->will($this->returnValue($synchronized)); - - $form->expects($this->any()) - ->method('isSubmitted') - ->will($this->returnValue($submitted)); - - return $form; - } - public function testMapDataToFormsPassesObjectRefIfByReference() { $car = new \stdClass(); $engine = new \stdClass(); - $propertyPath = $this->getPropertyPath('engine'); - - $this->propertyAccessor->expects($this->once()) - ->method('getValue') - ->with($car, $propertyPath) - ->will($this->returnValue($engine)); + $car->engine = $engine; + $propertyPath = new PropertyPath('engine'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); $config->setByReference(true); $config->setPropertyPath($propertyPath); - $form = $this->getForm($config); + $form = new Form($config); $this->mapper->mapDataToForms($car, [$form]); - // Can't use isIdentical() above because mocks always clone their - // arguments which can't be disabled in PHPUnit 3.6 $this->assertSame($engine, $form->getData()); } @@ -99,17 +66,14 @@ public function testMapDataToFormsPassesObjectCloneIfNotByReference() { $car = new \stdClass(); $engine = new \stdClass(); - $propertyPath = $this->getPropertyPath('engine'); - - $this->propertyAccessor->expects($this->once()) - ->method('getValue') - ->with($car, $propertyPath) - ->will($this->returnValue($engine)); + $engine->brand = 'Rolls-Royce'; + $car->engine = $engine; + $propertyPath = new PropertyPath('engine'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); $config->setByReference(false); $config->setPropertyPath($propertyPath); - $form = $this->getForm($config); + $form = new Form($config); $this->mapper->mapDataToForms($car, [$form]); @@ -123,7 +87,7 @@ public function testMapDataToFormsIgnoresEmptyPropertyPath() $config = new FormConfigBuilder(null, '\stdClass', $this->dispatcher); $config->setByReference(true); - $form = $this->getForm($config); + $form = new Form($config); $this->assertNull($form->getPropertyPath()); @@ -135,16 +99,14 @@ public function testMapDataToFormsIgnoresEmptyPropertyPath() public function testMapDataToFormsIgnoresUnmapped() { $car = new \stdClass(); - $propertyPath = $this->getPropertyPath('engine'); - - $this->propertyAccessor->expects($this->never()) - ->method('getValue'); + $car->engine = new \stdClass(); + $propertyPath = new PropertyPath('engine'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); $config->setByReference(true); $config->setMapped(false); $config->setPropertyPath($propertyPath); - $form = $this->getForm($config); + $form = new Form($config); $this->mapper->mapDataToForms($car, [$form]); @@ -154,204 +116,188 @@ public function testMapDataToFormsIgnoresUnmapped() public function testMapDataToFormsSetsDefaultDataIfPassedDataIsNull() { $default = new \stdClass(); - $propertyPath = $this->getPropertyPath('engine'); - - $this->propertyAccessor->expects($this->never()) - ->method('getValue'); + $propertyPath = new PropertyPath('engine'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); $config->setByReference(true); $config->setPropertyPath($propertyPath); $config->setData($default); - $form = $this->getMockBuilder('Symfony\Component\Form\Form') - ->setConstructorArgs([$config]) - ->setMethods(['setData']) - ->getMock(); - - $form->expects($this->once()) - ->method('setData') - ->with($default); + $form = new Form($config); $this->mapper->mapDataToForms(null, [$form]); + + $this->assertSame($default, $form->getData()); } public function testMapDataToFormsSetsDefaultDataIfPassedDataIsEmptyArray() { $default = new \stdClass(); - $propertyPath = $this->getPropertyPath('engine'); - - $this->propertyAccessor->expects($this->never()) - ->method('getValue'); + $propertyPath = new PropertyPath('engine'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); $config->setByReference(true); $config->setPropertyPath($propertyPath); $config->setData($default); - $form = $this->getMockBuilder('Symfony\Component\Form\Form') - ->setConstructorArgs([$config]) - ->setMethods(['setData']) - ->getMock(); - - $form->expects($this->once()) - ->method('setData') - ->with($default); + $form = new Form($config); $this->mapper->mapDataToForms([], [$form]); + + $this->assertSame($default, $form->getData()); } public function testMapFormsToDataWritesBackIfNotByReference() { $car = new \stdClass(); + $car->engine = new \stdClass(); $engine = new \stdClass(); - $propertyPath = $this->getPropertyPath('engine'); - - $this->propertyAccessor->expects($this->once()) - ->method('setValue') - ->with($car, $propertyPath, $engine); + $engine->brand = 'Rolls-Royce'; + $propertyPath = new PropertyPath('engine'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); $config->setByReference(false); $config->setPropertyPath($propertyPath); $config->setData($engine); - $form = $this->getForm($config); + $form = new SubmittedForm($config); $this->mapper->mapFormsToData([$form], $car); + + $this->assertEquals($engine, $car->engine); + $this->assertNotSame($engine, $car->engine); } public function testMapFormsToDataWritesBackIfByReferenceButNoReference() { $car = new \stdClass(); + $car->engine = new \stdClass(); $engine = new \stdClass(); - $propertyPath = $this->getPropertyPath('engine'); - - $this->propertyAccessor->expects($this->once()) - ->method('setValue') - ->with($car, $propertyPath, $engine); + $propertyPath = new PropertyPath('engine'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); $config->setByReference(true); $config->setPropertyPath($propertyPath); $config->setData($engine); - $form = $this->getForm($config); + $form = new SubmittedForm($config); $this->mapper->mapFormsToData([$form], $car); + + $this->assertSame($engine, $car->engine); } public function testMapFormsToDataWritesBackIfByReferenceAndReference() { $car = new \stdClass(); - $engine = new \stdClass(); - $propertyPath = $this->getPropertyPath('engine'); - - // $car already contains the reference of $engine - $this->propertyAccessor->expects($this->once()) - ->method('getValue') - ->with($car, $propertyPath) - ->will($this->returnValue($engine)); + $car->engine = 'BMW'; + $propertyPath = new PropertyPath('engine'); - $this->propertyAccessor->expects($this->never()) - ->method('setValue'); - - $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); + $config = new FormConfigBuilder('engine', null, $this->dispatcher); $config->setByReference(true); $config->setPropertyPath($propertyPath); - $config->setData($engine); - $form = $this->getForm($config); + $config->setData('Rolls-Royce'); + $form = new SubmittedForm($config); + + $car->engine = 'Rolls-Royce'; $this->mapper->mapFormsToData([$form], $car); + + $this->assertSame('Rolls-Royce', $car->engine); } public function testMapFormsToDataIgnoresUnmapped() { + $initialEngine = new \stdClass(); $car = new \stdClass(); + $car->engine = $initialEngine; $engine = new \stdClass(); - $propertyPath = $this->getPropertyPath('engine'); - - $this->propertyAccessor->expects($this->never()) - ->method('setValue'); + $propertyPath = new PropertyPath('engine'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); $config->setByReference(true); $config->setPropertyPath($propertyPath); $config->setData($engine); $config->setMapped(false); - $form = $this->getForm($config); + $form = new SubmittedForm($config); $this->mapper->mapFormsToData([$form], $car); + + $this->assertSame($initialEngine, $car->engine); } public function testMapFormsToDataIgnoresUnsubmittedForms() { + $initialEngine = new \stdClass(); $car = new \stdClass(); + $car->engine = $initialEngine; $engine = new \stdClass(); - $propertyPath = $this->getPropertyPath('engine'); - - $this->propertyAccessor->expects($this->never()) - ->method('setValue'); + $propertyPath = new PropertyPath('engine'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); $config->setByReference(true); $config->setPropertyPath($propertyPath); $config->setData($engine); - $form = $this->getForm($config, true, false); + $form = new Form($config); $this->mapper->mapFormsToData([$form], $car); + + $this->assertSame($initialEngine, $car->engine); } public function testMapFormsToDataIgnoresEmptyData() { + $initialEngine = new \stdClass(); $car = new \stdClass(); - $propertyPath = $this->getPropertyPath('engine'); - - $this->propertyAccessor->expects($this->never()) - ->method('setValue'); + $car->engine = $initialEngine; + $propertyPath = new PropertyPath('engine'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); $config->setByReference(true); $config->setPropertyPath($propertyPath); $config->setData(null); - $form = $this->getForm($config); + $form = new Form($config); $this->mapper->mapFormsToData([$form], $car); + + $this->assertSame($initialEngine, $car->engine); } public function testMapFormsToDataIgnoresUnsynchronized() { + $initialEngine = new \stdClass(); $car = new \stdClass(); + $car->engine = $initialEngine; $engine = new \stdClass(); - $propertyPath = $this->getPropertyPath('engine'); - - $this->propertyAccessor->expects($this->never()) - ->method('setValue'); + $propertyPath = new PropertyPath('engine'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); $config->setByReference(true); $config->setPropertyPath($propertyPath); $config->setData($engine); - $form = $this->getForm($config, false); + $form = new NotSynchronizedForm($config); $this->mapper->mapFormsToData([$form], $car); + + $this->assertSame($initialEngine, $car->engine); } public function testMapFormsToDataIgnoresDisabled() { + $initialEngine = new \stdClass(); $car = new \stdClass(); + $car->engine = $initialEngine; $engine = new \stdClass(); - $propertyPath = $this->getPropertyPath('engine'); - - $this->propertyAccessor->expects($this->never()) - ->method('setValue'); + $propertyPath = new PropertyPath('engine'); $config = new FormConfigBuilder('name', '\stdClass', $this->dispatcher); $config->setByReference(true); $config->setPropertyPath($propertyPath); $config->setData($engine); $config->setDisabled(true); - $form = $this->getForm($config); + $form = new Form($config); $this->mapper->mapFormsToData([$form], $car); + + $this->assertSame($initialEngine, $car->engine); } /** @@ -361,24 +307,19 @@ public function testMapFormsToDataDoesNotChangeEqualDateTimeInstance($date) { $article = []; $publishedAt = $date; - $article['publishedAt'] = clone $publishedAt; - $propertyPath = $this->getPropertyPath('[publishedAt]'); - - $this->propertyAccessor->expects($this->once()) - ->method('getValue') - ->willReturn($article['publishedAt']) - ; - $this->propertyAccessor->expects($this->never()) - ->method('setValue') - ; + $publishedAtValue = clone $publishedAt; + $article['publishedAt'] = $publishedAtValue; + $propertyPath = new PropertyPath('[publishedAt]'); $config = new FormConfigBuilder('publishedAt', \get_class($publishedAt), $this->dispatcher); $config->setByReference(false); $config->setPropertyPath($propertyPath); $config->setData($publishedAt); - $form = $this->getForm($config); + $form = new SubmittedForm($config); $this->mapper->mapFormsToData([$form], $article); + + $this->assertSame($publishedAtValue, $article['publishedAt']); } public function provideDate() @@ -389,3 +330,19 @@ public function provideDate() ]; } } + +class SubmittedForm extends Form +{ + public function isSubmitted() + { + return true; + } +} + +class NotSynchronizedForm extends Form +{ + public function isSynchronized() + { + return false; + } +} diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformerTest.php index 8d54b064f82d8..dc723dc486869 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/IntegerToLocalizedStringTransformerTest.php @@ -107,9 +107,7 @@ public function testReverseTransform() $transformer = new IntegerToLocalizedStringTransformer(); $this->assertEquals(1, $transformer->reverseTransform('1')); - $this->assertEquals(1, $transformer->reverseTransform('1,5')); - $this->assertEquals(1234, $transformer->reverseTransform('1234,5')); - $this->assertEquals(12345, $transformer->reverseTransform('12345,912')); + $this->assertEquals(12345, $transformer->reverseTransform('12345')); } public function testReverseTransformEmpty() @@ -128,10 +126,10 @@ public function testReverseTransformWithGrouping() $transformer = new IntegerToLocalizedStringTransformer(true); - $this->assertEquals(1234, $transformer->reverseTransform('1.234,5')); - $this->assertEquals(12345, $transformer->reverseTransform('12.345,912')); - $this->assertEquals(1234, $transformer->reverseTransform('1234,5')); - $this->assertEquals(12345, $transformer->reverseTransform('12345,912')); + $this->assertEquals(1234, $transformer->reverseTransform('1.234')); + $this->assertEquals(12345, $transformer->reverseTransform('12.345')); + $this->assertEquals(1234, $transformer->reverseTransform('1234')); + $this->assertEquals(12345, $transformer->reverseTransform('12345')); } /** @@ -147,10 +145,10 @@ public function testReverseTransformWithGroupingUsingLegacyConstructorSignature( $transformer = new IntegerToLocalizedStringTransformer(null, true); - $this->assertEquals(1234, $transformer->reverseTransform('1.234,5')); - $this->assertEquals(12345, $transformer->reverseTransform('12.345,912')); - $this->assertEquals(1234, $transformer->reverseTransform('1234,5')); - $this->assertEquals(12345, $transformer->reverseTransform('12345,912')); + $this->assertEquals(1234, $transformer->reverseTransform('1.234')); + $this->assertEquals(12345, $transformer->reverseTransform('12.345')); + $this->assertEquals(1234, $transformer->reverseTransform('1234')); + $this->assertEquals(12345, $transformer->reverseTransform('12345')); } public function reverseTransformWithRoundingProvider() @@ -246,6 +244,29 @@ public function testReverseTransformExpectsValidNumber() $transformer->reverseTransform('foo'); } + /** + * @dataProvider floatNumberProvider + * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException + */ + public function testReverseTransformExpectsInteger($number, $locale) + { + IntlTestHelper::requireFullIntl($this, false); + + \Locale::setDefault($locale); + + $transformer = new IntegerToLocalizedStringTransformer(); + + $transformer->reverseTransform($number); + } + + public function floatNumberProvider() + { + return [ + ['12345.912', 'en'], + ['1.234,5', 'de_DE'], + ]; + } + /** * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException */ diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php index d9fafdff13a35..c5bffe4d96e65 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/MoneyToLocalizedStringTransformerTest.php @@ -17,6 +17,18 @@ class MoneyToLocalizedStringTransformerTest extends TestCase { + private $previousLocale; + + protected function setUp() + { + $this->previousLocale = setlocale(LC_ALL, '0'); + } + + protected function tearDown() + { + setlocale(LC_ALL, $this->previousLocale); + } + public function testTransform() { // Since we test against "de_AT", we need the full implementation @@ -73,7 +85,7 @@ public function testReverseTransformEmpty() $this->assertNull($transformer->reverseTransform('')); } - public function testFloatToIntConversionMismatchOnReversTransform() + public function testFloatToIntConversionMismatchOnReverseTransform() { $transformer = new MoneyToLocalizedStringTransformer(null, null, null, 100); IntlTestHelper::requireFullIntl($this, false); @@ -90,4 +102,16 @@ public function testFloatToIntConversionMismatchOnTransform() $this->assertSame('10,20', $transformer->transform(1020)); } + + public function testValidNumericValuesWithNonDotDecimalPointCharacter() + { + // calling setlocale() here is important as it changes the representation of floats when being cast to strings + setlocale(LC_ALL, 'de_AT.UTF-8'); + + $transformer = new MoneyToLocalizedStringTransformer(4, null, null, 100); + IntlTestHelper::requireFullIntl($this, false); + \Locale::setDefault('de_AT'); + + $this->assertSame('0,0035', $transformer->transform(12 / 34)); + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixUrlProtocolListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixUrlProtocolListenerTest.php index 0182aa23d301e..e00cb9e9e1978 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixUrlProtocolListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixUrlProtocolListenerTest.php @@ -12,9 +12,10 @@ namespace Symfony\Component\Form\Tests\Extension\Core\EventListener; use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Form\Extension\Core\EventListener\FixUrlProtocolListener; use Symfony\Component\Form\Form; -use Symfony\Component\Form\FormConfigInterface; +use Symfony\Component\Form\FormConfigBuilder; use Symfony\Component\Form\FormEvent; class FixUrlProtocolListenerTest extends TestCase @@ -22,7 +23,7 @@ class FixUrlProtocolListenerTest extends TestCase public function testFixHttpUrl() { $data = 'www.symfony.com'; - $form = new Form($this->getMockBuilder(FormConfigInterface::class)->getMock()); + $form = new Form(new FormConfigBuilder('name', null, new EventDispatcher())); $event = new FormEvent($form, $data); $filter = new FixUrlProtocolListener('http'); @@ -34,7 +35,7 @@ public function testFixHttpUrl() public function testSkipKnownUrl() { $data = 'http://www.symfony.com'; - $form = new Form($this->getMockBuilder(FormConfigInterface::class)->getMock()); + $form = new Form(new FormConfigBuilder('name', null, new EventDispatcher())); $event = new FormEvent($form, $data); $filter = new FixUrlProtocolListener('http'); @@ -59,7 +60,7 @@ public function provideUrlsWithSupportedProtocols() */ public function testSkipOtherProtocol($url) { - $form = new Form($this->getMockBuilder(FormConfigInterface::class)->getMock()); + $form = new Form(new FormConfigBuilder('name', null, new EventDispatcher())); $event = new FormEvent($form, $url); $filter = new FixUrlProtocolListener('http'); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerArrayObjectTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerArrayObjectTest.php index 6f46c9d7fab37..5944537927de9 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerArrayObjectTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerArrayObjectTest.php @@ -11,7 +11,9 @@ namespace Symfony\Component\Form\Tests\Extension\Core\EventListener; +use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Form\FormBuilder; +use Symfony\Component\Form\FormFactoryBuilder; class MergeCollectionListenerArrayObjectTest extends MergeCollectionListenerTest { @@ -22,6 +24,6 @@ protected function getData(array $data) protected function getBuilder($name = 'name') { - return new FormBuilder($name, '\ArrayObject', $this->dispatcher, $this->factory); + return new FormBuilder($name, '\ArrayObject', new EventDispatcher(), (new FormFactoryBuilder())->getFormFactory()); } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerArrayTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerArrayTest.php index c0f3d59734bcb..4f19a3ff8e777 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerArrayTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerArrayTest.php @@ -11,7 +11,9 @@ namespace Symfony\Component\Form\Tests\Extension\Core\EventListener; +use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Form\FormBuilder; +use Symfony\Component\Form\FormFactoryBuilder; class MergeCollectionListenerArrayTest extends MergeCollectionListenerTest { @@ -22,6 +24,6 @@ protected function getData(array $data) protected function getBuilder($name = 'name') { - return new FormBuilder($name, null, $this->dispatcher, $this->factory); + return new FormBuilder($name, null, new EventDispatcher(), (new FormFactoryBuilder())->getFormFactory()); } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerCustomArrayObjectTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerCustomArrayObjectTest.php index 76bdc7682366b..4be3b4babae98 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerCustomArrayObjectTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerCustomArrayObjectTest.php @@ -11,7 +11,9 @@ namespace Symfony\Component\Form\Tests\Extension\Core\EventListener; +use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Form\FormBuilder; +use Symfony\Component\Form\FormFactoryBuilder; use Symfony\Component\Form\Tests\Fixtures\CustomArrayObject; class MergeCollectionListenerCustomArrayObjectTest extends MergeCollectionListenerTest @@ -23,6 +25,6 @@ protected function getData(array $data) protected function getBuilder($name = 'name') { - return new FormBuilder($name, 'Symfony\Component\Form\Tests\Fixtures\CustomArrayObject', $this->dispatcher, $this->factory); + return new FormBuilder($name, 'Symfony\Component\Form\Tests\Fixtures\CustomArrayObject', new EventDispatcher(), (new FormFactoryBuilder())->getFormFactory()); } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerTest.php index 98cd78385a80d..8c691dffc1d75 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/MergeCollectionListenerTest.php @@ -17,21 +17,15 @@ abstract class MergeCollectionListenerTest extends TestCase { - protected $dispatcher; - protected $factory; protected $form; protected function setUp() { - $this->dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); - $this->factory = $this->getMockBuilder('Symfony\Component\Form\FormFactoryInterface')->getMock(); $this->form = $this->getForm('axes'); } protected function tearDown() { - $this->dispatcher = null; - $this->factory = null; $this->form = null; } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/ResizeFormListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/ResizeFormListenerTest.php index 84a8c1db88847..ae7d2db4678dd 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/ResizeFormListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/ResizeFormListenerTest.php @@ -13,36 +13,37 @@ use Doctrine\Common\Collections\ArrayCollection; use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\Core\EventListener\ResizeFormListener; +use Symfony\Component\Form\Extension\Core\Type\TextType; use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormEvent; +use Symfony\Component\Form\FormFactoryBuilder; class ResizeFormListenerTest extends TestCase { - private $dispatcher; private $factory; private $form; protected function setUp() { - $this->dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); - $this->factory = $this->getMockBuilder('Symfony\Component\Form\FormFactoryInterface')->getMock(); + $this->factory = (new FormFactoryBuilder())->getFormFactory(); $this->form = $this->getBuilder() ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); } protected function tearDown() { - $this->dispatcher = null; $this->factory = null; $this->form = null; } protected function getBuilder($name = 'name') { - return new FormBuilder($name, null, $this->dispatcher, $this->factory); + return new FormBuilder($name, null, new EventDispatcher(), $this->factory); } protected function getForm($name = 'name') @@ -50,31 +51,14 @@ protected function getForm($name = 'name') return $this->getBuilder($name)->getForm(); } - /** - * @return \PHPUnit_Framework_MockObject_MockObject - */ - private function getDataMapper() - { - return $this->getMockBuilder('Symfony\Component\Form\DataMapperInterface')->getMock(); - } - public function testPreSetDataResizesForm() { $this->form->add($this->getForm('0')); $this->form->add($this->getForm('1')); - $this->factory->expects($this->at(0)) - ->method('createNamed') - ->with(1, 'text', null, ['property_path' => '[1]', 'attr' => ['maxlength' => 10], 'auto_initialize' => false]) - ->will($this->returnValue($this->getForm('1'))); - $this->factory->expects($this->at(1)) - ->method('createNamed') - ->with(2, 'text', null, ['property_path' => '[2]', 'attr' => ['maxlength' => 10], 'auto_initialize' => false]) - ->will($this->returnValue($this->getForm('2'))); - $data = [1 => 'string', 2 => 'string']; $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener('text', ['attr' => ['maxlength' => 10]], false, false); + $listener = new ResizeFormListener(TextType::class, ['attr' => ['maxlength' => 10]], false, false); $listener->preSetData($event); $this->assertFalse($this->form->has('0')); @@ -95,26 +79,21 @@ public function testPreSetDataRequiresArrayOrTraversable() public function testPreSetDataDealsWithNullData() { - $this->factory->expects($this->never())->method('createNamed'); - $data = null; $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener('text', [], false, false); + $listener = new ResizeFormListener(TextType::class, [], false, false); $listener->preSetData($event); + + $this->assertSame(0, $this->form->count()); } public function testPreSubmitResizesUpIfAllowAdd() { $this->form->add($this->getForm('0')); - $this->factory->expects($this->once()) - ->method('createNamed') - ->with(1, 'text', null, ['property_path' => '[1]', 'attr' => ['maxlength' => 10], 'auto_initialize' => false]) - ->will($this->returnValue($this->getForm('1'))); - $data = [0 => 'string', 1 => 'string']; $event = new FormEvent($this->form, $data); - $listener = new ResizeFormListener('text', ['attr' => ['maxlength' => 10]], true, false); + $listener = new ResizeFormListener(TextType::class, ['attr' => ['maxlength' => 10]], true, false); $listener->preSubmit($event); $this->assertTrue($this->form->has('0')); @@ -293,12 +272,12 @@ public function testOnSubmitDeleteEmptyCompoundEntriesIfAllowDelete() $this->form->setData(['0' => ['name' => 'John'], '1' => ['name' => 'Jane']]); $form1 = $this->getBuilder('0') ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $form1->add($this->getForm('name')); $form2 = $this->getBuilder('1') ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $form2->add($this->getForm('name')); $this->form->add($form1); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/TrimListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/TrimListenerTest.php index 78dae1bd82231..a61fb86a39b6e 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/TrimListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/TrimListenerTest.php @@ -12,9 +12,10 @@ namespace Symfony\Component\Form\Tests\Extension\Core\EventListener; use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Form\Extension\Core\EventListener\TrimListener; use Symfony\Component\Form\Form; -use Symfony\Component\Form\FormConfigInterface; +use Symfony\Component\Form\FormConfigBuilder; use Symfony\Component\Form\FormEvent; class TrimListenerTest extends TestCase @@ -22,7 +23,7 @@ class TrimListenerTest extends TestCase public function testTrim() { $data = ' Foo! '; - $form = new Form($this->getMockBuilder(FormConfigInterface::class)->getMock()); + $form = new Form(new FormConfigBuilder('name', null, new EventDispatcher())); $event = new FormEvent($form, $data); $filter = new TrimListener(); @@ -34,7 +35,7 @@ public function testTrim() public function testTrimSkipNonStrings() { $data = 1234; - $form = new Form($this->getMockBuilder(FormConfigInterface::class)->getMock()); + $form = new Form(new FormConfigBuilder('name', null, new EventDispatcher())); $event = new FormEvent($form, $data); $filter = new TrimListener(); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php index 92eff38669ff2..62654fc618376 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/BaseTypeTest.php @@ -12,12 +12,15 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; use Symfony\Component\Form\Test\TypeTestCase; +use Symfony\Component\Form\Tests\VersionAwareTest; /** * @author Bernhard Schussek */ abstract class BaseTypeTest extends TypeTestCase { + use VersionAwareTest; + const TESTED_TYPE = ''; public function testPassDisabledAsOption() diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php index 14340989cecb4..6dde61e870414 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php @@ -14,6 +14,7 @@ use Symfony\Component\Form\Extension\HttpFoundation\HttpFoundationRequestHandler; use Symfony\Component\Form\NativeRequestHandler; use Symfony\Component\Form\RequestHandlerInterface; +use Symfony\Component\HttpFoundation\File\File; use Symfony\Component\HttpFoundation\File\UploadedFile; class FileTypeTest extends BaseTypeTest @@ -24,9 +25,7 @@ class FileTypeTest extends BaseTypeTest public function testSetData() { $form = $this->factory->createBuilder(static::TESTED_TYPE)->getForm(); - $data = $this->getMockBuilder('Symfony\Component\HttpFoundation\File\File') - ->setConstructorArgs([__DIR__.'/../../../Fixtures/foo', 'foo']) - ->getMock(); + $data = new File(__DIR__.'/../../../Fixtures/foo', false); $form->setData($data); @@ -40,7 +39,7 @@ public function testSetData() public function testSubmit(RequestHandlerInterface $requestHandler) { $form = $this->factory->createBuilder(static::TESTED_TYPE)->setRequestHandler($requestHandler)->getForm(); - $data = $this->createUploadedFileMock($requestHandler, __DIR__.'/../../../Fixtures/foo', 'foo.jpg'); + $data = $this->createUploadedFile($requestHandler, __DIR__.'/../../../Fixtures/foo', 'foo.jpg'); $form->submit($data); @@ -57,8 +56,8 @@ public function testSetDataMultiple(RequestHandlerInterface $requestHandler) ])->setRequestHandler($requestHandler)->getForm(); $data = [ - $this->createUploadedFileMock($requestHandler, __DIR__.'/../../../Fixtures/foo', 'foo.jpg'), - $this->createUploadedFileMock($requestHandler, __DIR__.'/../../../Fixtures/foo2', 'foo2.jpg'), + $this->createUploadedFile($requestHandler, __DIR__.'/../../../Fixtures/foo', 'foo.jpg'), + $this->createUploadedFile($requestHandler, __DIR__.'/../../../Fixtures/foo2', 'foo2.jpg'), ]; $form->setData($data); @@ -75,8 +74,8 @@ public function testSubmitMultiple(RequestHandlerInterface $requestHandler) ])->setRequestHandler($requestHandler)->getForm(); $data = [ - $this->createUploadedFileMock($requestHandler, __DIR__.'/../../../Fixtures/foo', 'foo.jpg'), - $this->createUploadedFileMock($requestHandler, __DIR__.'/../../../Fixtures/foo2', 'foo2.jpg'), + $this->createUploadedFile($requestHandler, __DIR__.'/../../../Fixtures/foo', 'foo.jpg'), + $this->createUploadedFile($requestHandler, __DIR__.'/../../../Fixtures/foo2', 'foo2.jpg'), ]; $form->submit($data); @@ -94,7 +93,7 @@ public function testDontPassValueToView(RequestHandlerInterface $requestHandler) { $form = $this->factory->createBuilder(static::TESTED_TYPE)->setRequestHandler($requestHandler)->getForm(); $form->submit([ - 'file' => $this->createUploadedFileMock($requestHandler, __DIR__.'/../../../Fixtures/foo', 'foo.jpg'), + 'file' => $this->createUploadedFile($requestHandler, __DIR__.'/../../../Fixtures/foo', 'foo.jpg'), ]); $this->assertEquals('', $form->createView()->vars['value']); @@ -152,8 +151,8 @@ public function testMultipleSubmittedFilePathsAreDropped(RequestHandlerInterface ->getForm(); $form->submit([ 'file:///etc/passwd', - $this->createUploadedFileMock(new HttpFoundationRequestHandler(), __DIR__.'/../../../Fixtures/foo', 'foo.jpg'), - $this->createUploadedFileMock(new NativeRequestHandler(), __DIR__.'/../../../Fixtures/foo2', 'foo2.jpg'), + $this->createUploadedFile(new HttpFoundationRequestHandler(), __DIR__.'/../../../Fixtures/foo', 'foo.jpg'), + $this->createUploadedFile(new NativeRequestHandler(), __DIR__.'/../../../Fixtures/foo2', 'foo2.jpg'), ]); $this->assertCount(1, $form->getData()); @@ -185,7 +184,7 @@ public function requestHandlerProvider() ]; } - private function createUploadedFileMock(RequestHandlerInterface $requestHandler, $path, $originalName) + private function createUploadedFile(RequestHandlerInterface $requestHandler, $path, $originalName) { if ($requestHandler instanceof HttpFoundationRequestHandler) { return new UploadedFile($path, $originalName, null, null, true); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/IntegerTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/IntegerTypeTest.php index 273402aefeb32..c5c7dd9161b7e 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/IntegerTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/IntegerTypeTest.php @@ -24,14 +24,15 @@ protected function setUp() parent::setUp(); } - public function testSubmitCastsToInteger() + public function testSubmitRejectsFloats() { $form = $this->factory->create(static::TESTED_TYPE); $form->submit('1.678'); - $this->assertSame(1, $form->getData()); - $this->assertSame('1', $form->getViewData()); + $this->assertTrue($form->isSubmitted()); + $this->assertFalse($form->isValid()); + $this->assertFalse($form->isSynchronized()); } public function testSubmitNull($expected = null, $norm = null, $view = null) @@ -50,4 +51,45 @@ public function testSubmitNullUsesDefaultEmptyData($emptyData = '10', $expectedD $this->assertSame($expectedData, $form->getNormData()); $this->assertSame($expectedData, $form->getData()); } + + public function testSubmittedLargeIntegersAreNotCastToFloat() + { + if (4 === \PHP_INT_SIZE) { + $this->markTestSkipped('This test requires a 64bit PHP.'); + } + + $form = $this->factory->create(static::TESTED_TYPE); + $form->submit('201803221011791'); + + $this->assertSame(201803221011791, $form->getData()); + $this->assertSame('201803221011791', $form->getViewData()); + } + + public function testTooSmallIntegersAreNotValid() + { + if (4 === \PHP_INT_SIZE) { + $min = '-2147483649'; + } else { + $min = '-9223372036854775808'; + } + + $form = $this->factory->create(static::TESTED_TYPE); + $form->submit($min); + + $this->assertFalse($form->isSynchronized()); + } + + public function testTooGreatIntegersAreNotValid() + { + if (4 === \PHP_INT_SIZE) { + $max = '2147483648'; + } else { + $max = '9223372036854775808'; + } + + $form = $this->factory->create(static::TESTED_TYPE); + $form->submit($max); + + $this->assertFalse($form->isSynchronized()); + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php index 43e9acad057c4..5876b092b9da0 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php @@ -12,9 +12,13 @@ namespace Symfony\Component\Form\Tests\Extension\Csrf\EventListener; use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener; use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormEvent; +use Symfony\Component\Form\FormFactoryBuilder; +use Symfony\Component\Security\Csrf\CsrfTokenManager; class CsrfValidationListenerTest extends TestCase { @@ -25,11 +29,11 @@ class CsrfValidationListenerTest extends TestCase protected function setUp() { - $this->dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); - $this->factory = $this->getMockBuilder('Symfony\Component\Form\FormFactoryInterface')->getMock(); - $this->tokenManager = $this->getMockBuilder('Symfony\Component\Security\Csrf\CsrfTokenManagerInterface')->getMock(); + $this->dispatcher = new EventDispatcher(); + $this->factory = (new FormFactoryBuilder())->getFormFactory(); + $this->tokenManager = new CsrfTokenManager(); $this->form = $this->getBuilder() - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); } @@ -46,11 +50,6 @@ protected function getBuilder() return new FormBuilder('post', null, $this->dispatcher, $this->factory, ['compound' => true]); } - protected function getDataMapper() - { - return $this->getMockBuilder('Symfony\Component\Form\DataMapperInterface')->getMock(); - } - // https://github.com/symfony/symfony/pull/5838 public function testStringFormData() { @@ -64,6 +63,16 @@ public function testStringFormData() $this->assertSame($data, $event->getData()); } + public function testArrayCsrfToken() + { + $event = new FormEvent($this->form, ['csrf' => []]); + + $validation = new CsrfValidationListener('csrf', $this->tokenManager, 'unknown', 'Invalid.'); + $validation->preSubmit($event); + + $this->assertNotEmpty($this->form->getErrors()); + } + public function testMaxPostSizeExceeded() { $serverParams = $this diff --git a/src/Symfony/Component/Form/Tests/Extension/DependencyInjection/DependencyInjectionExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/DependencyInjection/DependencyInjectionExtensionTest.php index 0498c764d102e..62a1ec286d793 100644 --- a/src/Symfony/Component/Form/Tests/Extension/DependencyInjection/DependencyInjectionExtensionTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/DependencyInjection/DependencyInjectionExtensionTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Form\Tests\Extension\DependencyInjection; use PHPUnit\Framework\TestCase; +use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\Form\AbstractTypeExtension; use Symfony\Component\Form\Extension\DependencyInjection\DependencyInjectionExtension; use Symfony\Component\Form\FormTypeGuesserChain; @@ -21,9 +22,6 @@ class DependencyInjectionExtensionTest extends TestCase { public function testGetTypeExtensions() { - $container = $this->createContainerMock(); - $container->expects($this->never())->method('get'); - $typeExtension1 = new TestTypeExtension(); $typeExtension2 = new TestTypeExtension(); $typeExtension3 = new OtherTypeExtension(); @@ -34,7 +32,7 @@ public function testGetTypeExtensions() 'other' => new \ArrayIterator([$typeExtension3, $typeExtension4]), ]; - $extension = new DependencyInjectionExtension($container, $extensions, []); + $extension = new DependencyInjectionExtension(new ContainerBuilder(), $extensions, []); $this->assertTrue($extension->hasTypeExtensions('test')); $this->assertTrue($extension->hasTypeExtensions('other')); @@ -48,40 +46,28 @@ public function testGetTypeExtensions() */ public function testThrowExceptionForInvalidExtendedType() { - $container = $this->getMockBuilder('Psr\Container\ContainerInterface')->getMock(); - $container->expects($this->never())->method('get'); - $extensions = [ 'unmatched' => new \ArrayIterator([new TestTypeExtension()]), ]; - $extension = new DependencyInjectionExtension($container, $extensions, []); + $extension = new DependencyInjectionExtension(new ContainerBuilder(), $extensions, []); $extension->getTypeExtensions('unmatched'); } public function testGetTypeGuesser() { - $container = $this->createContainerMock(); - $extension = new DependencyInjectionExtension($container, [], [$this->getMockBuilder(FormTypeGuesserInterface::class)->getMock()]); + $extension = new DependencyInjectionExtension(new ContainerBuilder(), [], [$this->getMockBuilder(FormTypeGuesserInterface::class)->getMock()]); $this->assertInstanceOf(FormTypeGuesserChain::class, $extension->getTypeGuesser()); } public function testGetTypeGuesserReturnsNullWhenNoTypeGuessersHaveBeenConfigured() { - $container = $this->createContainerMock(); - $extension = new DependencyInjectionExtension($container, [], []); + $extension = new DependencyInjectionExtension(new ContainerBuilder(), [], []); $this->assertNull($extension->getTypeGuesser()); } - - private function createContainerMock() - { - return $this->getMockBuilder('Psr\Container\ContainerInterface') - ->setMethods(['get', 'has']) - ->getMock(); - } } class TestTypeExtension extends AbstractTypeExtension diff --git a/src/Symfony/Component/Form/Tests/Extension/HttpFoundation/HttpFoundationRequestHandlerTest.php b/src/Symfony/Component/Form/Tests/Extension/HttpFoundation/HttpFoundationRequestHandlerTest.php index 5597e835542df..2b134511830e7 100644 --- a/src/Symfony/Component/Form/Tests/Extension/HttpFoundation/HttpFoundationRequestHandlerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/HttpFoundation/HttpFoundationRequestHandlerTest.php @@ -47,7 +47,7 @@ protected function getRequestHandler() return new HttpFoundationRequestHandler($this->serverParams); } - protected function getMockFile($suffix = '') + protected function getUploadedFile($suffix = '') { return new UploadedFile(__DIR__.'/../../Fixtures/foo'.$suffix, 'foo'.$suffix); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php index 7910dd0b559e9..9a8b5c259ebdd 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php @@ -11,18 +11,26 @@ namespace Symfony\Component\Form\Tests\Extension\Validator\Constraints; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\CallbackTransformer; use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\Validator\Constraints\Form; use Symfony\Component\Form\Extension\Validator\Constraints\FormValidator; use Symfony\Component\Form\FormBuilder; +use Symfony\Component\Form\FormFactoryBuilder; +use Symfony\Component\Form\FormFactoryInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\SubmitButtonBuilder; +use Symfony\Component\Translation\IdentityTranslator; use Symfony\Component\Validator\Constraints\GroupSequence; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\NotNull; use Symfony\Component\Validator\Constraints\Valid; +use Symfony\Component\Validator\Context\ExecutionContext; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; +use Symfony\Component\Validator\Validation; /** * @author Bernhard Schussek @@ -30,43 +38,31 @@ class FormValidatorTest extends ConstraintValidatorTestCase { /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var EventDispatcherInterface */ private $dispatcher; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var FormFactoryInterface */ private $factory; - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - protected $serverParams; - protected function setUp() { - $this->dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); - $this->factory = $this->getMockBuilder('Symfony\Component\Form\FormFactoryInterface')->getMock(); - $this->serverParams = $this->getMockBuilder('Symfony\Component\Form\Extension\Validator\Util\ServerParams')->setMethods(['getNormalizedIniPostMaxSize', 'getContentLength'])->getMock(); + $this->dispatcher = new EventDispatcher(); + $this->factory = (new FormFactoryBuilder())->getFormFactory(); parent::setUp(); $this->constraint = new Form(); } - protected function createValidator() - { - return new FormValidator($this->serverParams); - } - public function testValidate() { - $object = $this->getMockBuilder('\stdClass')->getMock(); + $object = new \stdClass(); $options = ['validation_groups' => ['group1', 'group2']]; - $form = $this->getBuilder('name', '\stdClass', $options) - ->setData($object) - ->getForm(); + $form = $this->getCompoundForm($object, $options); + $form->submit([]); $this->expectValidateAt(0, 'data', $object, ['group1', 'group2']); @@ -77,7 +73,7 @@ public function testValidate() public function testValidateConstraints() { - $object = $this->getMockBuilder('\stdClass')->getMock(); + $object = new \stdClass(); $constraint1 = new NotNull(['groups' => ['group1', 'group2']]); $constraint2 = new NotBlank(['groups' => 'group2']); @@ -85,9 +81,8 @@ public function testValidateConstraints() 'validation_groups' => ['group1', 'group2'], 'constraints' => [$constraint1, $constraint2], ]; - $form = $this->getBuilder('name', '\stdClass', $options) - ->setData($object) - ->getForm(); + $form = $this->getCompoundForm($object, $options); + $form->submit([]); // First default constraints $this->expectValidateAt(0, 'data', $object, ['group1', 'group2']); @@ -103,20 +98,19 @@ public function testValidateConstraints() public function testValidateChildIfValidConstraint() { - $object = $this->getMockBuilder('\stdClass')->getMock(); + $object = new \stdClass(); $parent = $this->getBuilder('parent') ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $options = [ 'validation_groups' => ['group1', 'group2'], 'constraints' => [new Valid()], ]; - $form = $this->getBuilder('name', '\stdClass', $options)->getForm(); + $form = $this->getCompoundForm($object, $options); $parent->add($form); - - $form->setData($object); + $parent->submit([]); $this->expectValidateAt(0, 'data', $object, ['group1', 'group2']); @@ -127,11 +121,11 @@ public function testValidateChildIfValidConstraint() public function testDontValidateIfParentWithoutValidConstraint() { - $object = $this->getMockBuilder('\stdClass')->getMock(); + $object = new \stdClass(); $parent = $this->getBuilder('parent', null) ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $options = ['validation_groups' => ['group1', 'group2']]; $form = $this->getBuilder('name', '\stdClass', $options)->getForm(); @@ -149,8 +143,8 @@ public function testDontValidateIfParentWithoutValidConstraint() public function testMissingConstraintIndex() { $object = new \stdClass(); - $form = new FormBuilder('name', '\stdClass', $this->dispatcher, $this->factory); - $form = $form->setData($object)->getForm(); + $form = $this->getCompoundForm($object); + $form->submit([]); $this->expectValidateAt(0, 'data', $object, ['Default']); @@ -161,22 +155,21 @@ public function testMissingConstraintIndex() public function testValidateConstraintsOptionEvenIfNoValidConstraint() { - $object = $this->getMockBuilder('\stdClass')->getMock(); + $object = new \stdClass(); $constraint1 = new NotNull(['groups' => ['group1', 'group2']]); $constraint2 = new NotBlank(['groups' => 'group2']); $parent = $this->getBuilder('parent', null) ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $options = [ 'validation_groups' => ['group1', 'group2'], 'constraints' => [$constraint1, $constraint2], ]; - $form = $this->getBuilder('name', '\stdClass', $options) - ->setData($object) - ->getForm(); + $form = $this->getCompoundForm($object, $options); $parent->add($form); + $parent->submit([]); $this->expectValidateValueAt(0, 'data', $object, $constraint1, 'group1'); $this->expectValidateValueAt(1, 'data', $object, $constraint2, 'group2'); @@ -188,7 +181,7 @@ public function testValidateConstraintsOptionEvenIfNoValidConstraint() public function testDontValidateIfNoValidationGroups() { - $object = $this->getMockBuilder('\stdClass')->getMock(); + $object = new \stdClass(); $form = $this->getBuilder('name', '\stdClass', [ 'validation_groups' => [], @@ -207,13 +200,11 @@ public function testDontValidateIfNoValidationGroups() public function testDontValidateConstraintsIfNoValidationGroups() { - $object = $this->getMockBuilder('\stdClass')->getMock(); - $constraint1 = $this->getMockBuilder('Symfony\Component\Validator\Constraint')->getMock(); - $constraint2 = $this->getMockBuilder('Symfony\Component\Validator\Constraint')->getMock(); + $object = new \stdClass(); $options = [ 'validation_groups' => [], - 'constraints' => [$constraint1, $constraint2], + 'constraints' => [new NotBlank(), new NotNull()], ]; $form = $this->getBuilder('name', '\stdClass', $options) ->setData($object) @@ -231,7 +222,7 @@ public function testDontValidateConstraintsIfNoValidationGroups() public function testDontValidateIfNotSynchronized() { - $object = $this->getMockBuilder('\stdClass')->getMock(); + $object = new \stdClass(); $form = $this->getBuilder('name', '\stdClass', [ 'invalid_message' => 'invalid_message_key', @@ -265,7 +256,7 @@ function () { throw new TransformationFailedException(); } public function testAddInvalidErrorEvenIfNoValidationGroups() { - $object = $this->getMockBuilder('\stdClass')->getMock(); + $object = new \stdClass(); $form = $this->getBuilder('name', '\stdClass', [ 'invalid_message' => 'invalid_message_key', @@ -300,14 +291,12 @@ function () { throw new TransformationFailedException(); } public function testDontValidateConstraintsIfNotSynchronized() { - $object = $this->getMockBuilder('\stdClass')->getMock(); - $constraint1 = $this->getMockBuilder('Symfony\Component\Validator\Constraint')->getMock(); - $constraint2 = $this->getMockBuilder('Symfony\Component\Validator\Constraint')->getMock(); + $object = new \stdClass(); $options = [ 'invalid_message' => 'invalid_message_key', 'validation_groups' => ['group1', 'group2'], - 'constraints' => [$constraint1, $constraint2], + 'constraints' => [new NotBlank(), new NotBlank()], ]; $form = $this->getBuilder('name', '\stdClass', $options) ->setData($object) @@ -335,7 +324,8 @@ function () { throw new TransformationFailedException(); } // https://github.com/symfony/symfony/issues/4359 public function testDontMarkInvalidIfAnyChildIsNotSynchronized() { - $object = $this->getMockBuilder('\stdClass')->getMock(); + $object = new \stdClass(); + $object->child = 'bar'; $failingTransformer = new CallbackTransformer( function ($data) { return $data; }, @@ -346,7 +336,7 @@ function () { throw new TransformationFailedException(); } ->setData($object) ->addViewTransformer($failingTransformer) ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->add( $this->getBuilder('child') ->addViewTransformer($failingTransformer) @@ -365,11 +355,10 @@ function () { throw new TransformationFailedException(); } public function testHandleGroupSequenceValidationGroups() { - $object = $this->getMockBuilder('\stdClass')->getMock(); + $object = new \stdClass(); $options = ['validation_groups' => new GroupSequence(['group1', 'group2'])]; - $form = $this->getBuilder('name', '\stdClass', $options) - ->setData($object) - ->getForm(); + $form = $this->getCompoundForm($object, $options); + $form->submit([]); $this->expectValidateAt(0, 'data', $object, new GroupSequence(['group1', 'group2'])); $this->expectValidateAt(1, 'data', $object, new GroupSequence(['group1', 'group2'])); @@ -381,11 +370,10 @@ public function testHandleGroupSequenceValidationGroups() public function testHandleCallbackValidationGroups() { - $object = $this->getMockBuilder('\stdClass')->getMock(); + $object = new \stdClass(); $options = ['validation_groups' => [$this, 'getValidationGroups']]; - $form = $this->getBuilder('name', '\stdClass', $options) - ->setData($object) - ->getForm(); + $form = $this->getCompoundForm($object, $options); + $form->submit([]); $this->expectValidateAt(0, 'data', $object, ['group1', 'group2']); @@ -396,11 +384,10 @@ public function testHandleCallbackValidationGroups() public function testDontExecuteFunctionNames() { - $object = $this->getMockBuilder('\stdClass')->getMock(); + $object = new \stdClass(); $options = ['validation_groups' => 'header']; - $form = $this->getBuilder('name', '\stdClass', $options) - ->setData($object) - ->getForm(); + $form = $this->getCompoundForm($object, $options); + $form->submit([]); $this->expectValidateAt(0, 'data', $object, ['header']); @@ -411,13 +398,12 @@ public function testDontExecuteFunctionNames() public function testHandleClosureValidationGroups() { - $object = $this->getMockBuilder('\stdClass')->getMock(); + $object = new \stdClass(); $options = ['validation_groups' => function (FormInterface $form) { return ['group1', 'group2']; }]; - $form = $this->getBuilder('name', '\stdClass', $options) - ->setData($object) - ->getForm(); + $form = $this->getCompoundForm($object, $options); + $form->submit([]); $this->expectValidateAt(0, 'data', $object, ['group1', 'group2']); @@ -428,11 +414,11 @@ public function testHandleClosureValidationGroups() public function testUseValidationGroupOfClickedButton() { - $object = $this->getMockBuilder('\stdClass')->getMock(); + $object = new \stdClass(); $parent = $this->getBuilder('parent') ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $form = $this->getForm('name', '\stdClass', [ 'validation_groups' => 'form_group', @@ -455,13 +441,13 @@ public function testUseValidationGroupOfClickedButton() public function testDontUseValidationGroupOfUnclickedButton() { - $object = $this->getMockBuilder('\stdClass')->getMock(); + $object = new \stdClass(); $parent = $this->getBuilder('parent') ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); - $form = $this->getForm('name', '\stdClass', [ + $form = $this->getCompoundForm($object, [ 'validation_groups' => 'form_group', 'constraints' => [new Valid()], ]); @@ -471,7 +457,7 @@ public function testDontUseValidationGroupOfUnclickedButton() 'validation_groups' => 'button_group', ])); - $form->setData($object); + $parent->submit([]); $this->expectValidateAt(0, 'data', $object, ['form_group']); @@ -482,18 +468,17 @@ public function testDontUseValidationGroupOfUnclickedButton() public function testUseInheritedValidationGroup() { - $object = $this->getMockBuilder('\stdClass')->getMock(); + $object = new \stdClass(); $parentOptions = ['validation_groups' => 'group']; $parent = $this->getBuilder('parent', null, $parentOptions) ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $formOptions = ['constraints' => [new Valid()]]; - $form = $this->getBuilder('name', '\stdClass', $formOptions)->getForm(); + $form = $this->getCompoundForm($object, $formOptions); $parent->add($form); - - $form->setData($object); + $parent->submit([]); $this->expectValidateAt(0, 'data', $object, ['group']); @@ -504,18 +489,17 @@ public function testUseInheritedValidationGroup() public function testUseInheritedCallbackValidationGroup() { - $object = $this->getMockBuilder('\stdClass')->getMock(); + $object = new \stdClass(); $parentOptions = ['validation_groups' => [$this, 'getValidationGroups']]; $parent = $this->getBuilder('parent', null, $parentOptions) ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $formOptions = ['constraints' => [new Valid()]]; - $form = $this->getBuilder('name', '\stdClass', $formOptions)->getForm(); + $form = $this->getCompoundForm($object, $formOptions); $parent->add($form); - - $form->setData($object); + $parent->submit([]); $this->expectValidateAt(0, 'data', $object, ['group1', 'group2']); @@ -526,22 +510,21 @@ public function testUseInheritedCallbackValidationGroup() public function testUseInheritedClosureValidationGroup() { - $object = $this->getMockBuilder('\stdClass')->getMock(); + $object = new \stdClass(); $parentOptions = [ - 'validation_groups' => function (FormInterface $form) { + 'validation_groups' => function () { return ['group1', 'group2']; }, ]; $parent = $this->getBuilder('parent', null, $parentOptions) ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->getForm(); $formOptions = ['constraints' => [new Valid()]]; - $form = $this->getBuilder('name', '\stdClass', $formOptions)->getForm(); + $form = $this->getCompoundForm($object, $formOptions); $parent->add($form); - - $form->setData($object); + $parent->submit([]); $this->expectValidateAt(0, 'data', $object, ['group1', 'group2']); @@ -552,10 +535,9 @@ public function testUseInheritedClosureValidationGroup() public function testAppendPropertyPath() { - $object = $this->getMockBuilder('\stdClass')->getMock(); - $form = $this->getBuilder('name', '\stdClass') - ->setData($object) - ->getForm(); + $object = new \stdClass(); + $form = $this->getCompoundForm($object); + $form->submit([]); $this->expectValidateAt(0, 'data', $object, ['Default']); @@ -581,7 +563,7 @@ public function testViolationIfExtraData() { $form = $this->getBuilder('parent', null, ['extra_fields_message' => 'Extra!']) ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->add($this->getBuilder('child')) ->getForm(); @@ -602,7 +584,7 @@ public function testViolationFormatIfMultipleExtraFields() { $form = $this->getBuilder('parent', null, ['extra_fields_message' => 'Extra!']) ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->add($this->getBuilder('child')) ->getForm(); @@ -621,22 +603,21 @@ public function testViolationFormatIfMultipleExtraFields() public function testNoViolationIfAllowExtraData() { - $context = $this->getMockExecutionContext(); - $form = $this ->getBuilder('parent', null, ['allow_extra_fields' => true]) ->setCompound(true) - ->setDataMapper($this->getDataMapper()) + ->setDataMapper(new PropertyPathMapper()) ->add($this->getBuilder('child')) ->getForm(); - $form->submit(['foo' => 'bar']); + $context = new ExecutionContext(Validation::createValidator(), $form, new IdentityTranslator()); - $context->expects($this->never()) - ->method('addViolation'); + $form->submit(['foo' => 'bar']); $this->validator->initialize($context); $this->validator->validate($form, new Form()); + + $this->assertCount(0, $context->getViolations()); } /** @@ -649,22 +630,30 @@ public function getValidationGroups(FormInterface $form) return ['group1', 'group2']; } - private function getMockExecutionContext() + public function testCauseForNotAllowedExtraFieldsIsTheFormConstraint() { - $context = $this->getMockBuilder('Symfony\Component\Validator\Context\ExecutionContextInterface')->getMock(); - $validator = $this->getMockBuilder('Symfony\Component\Validator\Validator\ValidatorInterface')->getMock(); - $contextualValidator = $this->getMockBuilder('Symfony\Component\Validator\Validator\ContextualValidatorInterface')->getMock(); + $form = $this + ->getBuilder('form', null, ['constraints' => [new NotBlank(['groups' => ['foo']])]]) + ->setCompound(true) + ->setDataMapper(new PropertyPathMapper()) + ->getForm(); + $form->submit([ + 'extra_data' => 'foo', + ]); - $validator->expects($this->any()) - ->method('inContext') - ->with($context) - ->will($this->returnValue($contextualValidator)); + $context = new ExecutionContext(Validation::createValidator(), $form, new IdentityTranslator()); + $constraint = new Form(); - $context->expects($this->any()) - ->method('getValidator') - ->will($this->returnValue($validator)); + $this->validator->initialize($context); + $this->validator->validate($form, $constraint); - return $context; + $this->assertCount(1, $context->getViolations()); + $this->assertSame($constraint, $context->getViolations()->get(0)->getConstraint()); + } + + protected function createValidator() + { + return new FormValidator(); } private function getBuilder(string $name = 'name', string $dataClass = null, array $options = []): FormBuilder @@ -682,18 +671,19 @@ private function getForm($name = 'name', $dataClass = null, array $options = []) return $this->getBuilder($name, $dataClass, $options)->getForm(); } + private function getCompoundForm($data, array $options = []) + { + return $this->getBuilder('name', \get_class($data), $options) + ->setData($data) + ->setCompound(true) + ->setDataMapper(new PropertyPathMapper()) + ->getForm(); + } + private function getSubmitButton($name = 'name', array $options = []) { $builder = new SubmitButtonBuilder($name, $options); return $builder->getForm(); } - - /** - * @return \PHPUnit_Framework_MockObject_MockObject - */ - private function getDataMapper() - { - return $this->getMockBuilder('Symfony\Component\Form\DataMapperInterface')->getMock(); - } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php index 855a90d2e3479..76bc07b2ee981 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/EventListener/ValidationListenerTest.php @@ -12,40 +12,41 @@ namespace Symfony\Component\Form\Tests\Extension\Validator\EventListener; use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\Validator\Constraints\Form as FormConstraint; use Symfony\Component\Form\Extension\Validator\EventListener\ValidationListener; +use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper; use Symfony\Component\Form\Form; use Symfony\Component\Form\FormBuilder; +use Symfony\Component\Form\FormConfigBuilder; use Symfony\Component\Form\FormEvent; +use Symfony\Component\Form\FormFactoryBuilder; use Symfony\Component\Form\FormFactoryInterface; -use Symfony\Component\PropertyAccess\PropertyPath; use Symfony\Component\Validator\ConstraintViolation; -use Symfony\Component\Validator\ConstraintViolationList; +use Symfony\Component\Validator\ConstraintViolationInterface; +use Symfony\Component\Validator\Context\ExecutionContextInterface; +use Symfony\Component\Validator\Validation; +use Symfony\Component\Validator\Validator\ValidatorInterface; class ValidationListenerTest extends TestCase { /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var EventDispatcherInterface */ private $dispatcher; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var FormFactoryInterface */ private $factory; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var ValidatorInterface */ private $validator; - /** - * @var \PHPUnit_Framework_MockObject_MockObject - */ - private $violationMapper; - /** * @var ValidationListener */ @@ -59,40 +60,18 @@ class ValidationListenerTest extends TestCase protected function setUp() { - $this->dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); - $this->factory = $this->getMockBuilder('Symfony\Component\Form\FormFactoryInterface')->getMock(); - $this->validator = $this->getMockBuilder('Symfony\Component\Validator\Validator\ValidatorInterface')->getMock(); - $this->violationMapper = $this->getMockBuilder('Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapperInterface')->getMock(); - $this->listener = new ValidationListener($this->validator, $this->violationMapper); + $this->dispatcher = new EventDispatcher(); + $this->factory = (new FormFactoryBuilder())->getFormFactory(); + $this->validator = Validation::createValidator(); + $this->listener = new ValidationListener($this->validator, new ViolationMapper()); $this->message = 'Message'; $this->messageTemplate = 'Message template'; $this->params = ['foo' => 'bar']; } - private function getConstraintViolation($code = null) - { - return new ConstraintViolation($this->message, $this->messageTemplate, $this->params, null, 'prop.path', null, null, $code, new FormConstraint()); - } - - private function getBuilder($name = 'name', $propertyPath = null, $dataClass = null) - { - $builder = new FormBuilder($name, $dataClass, $this->dispatcher, $this->factory); - $builder->setPropertyPath(new PropertyPath($propertyPath ?: $name)); - $builder->setAttribute('error_mapping', []); - $builder->setErrorBubbling(false); - $builder->setMapped(true); - - return $builder; - } - - private function getForm($name = 'name', $propertyPath = null, $dataClass = null) - { - return $this->getBuilder($name, $propertyPath, $dataClass)->getForm(); - } - private function createForm($name = '', $compound = false) { - $config = new FormBuilder($name, null, $this->getMockBuilder(EventDispatcherInterface::class)->getMock(), $this->getMockBuilder(FormFactoryInterface::class)->getMock()); + $config = new FormBuilder($name, null, new EventDispatcher(), (new FormFactoryBuilder())->getFormFactory()); $config->setCompound($compound); if ($compound) { @@ -105,35 +84,29 @@ private function createForm($name = '', $compound = false) // More specific mapping tests can be found in ViolationMapperTest public function testMapViolation() { - $violation = $this->getConstraintViolation(); - $form = $this->getForm('street'); + $violation = new ConstraintViolation($this->message, $this->messageTemplate, $this->params, null, 'data', null, null, null, new FormConstraint()); + $form = new Form(new FormConfigBuilder('street', null, new EventDispatcher())); + $form->submit(null); - $this->validator->expects($this->once()) - ->method('validate') - ->will($this->returnValue([$violation])); + $validator = new DummyValidator($violation); + $listener = new ValidationListener($validator, new ViolationMapper()); + $listener->validateForm(new FormEvent($form, null)); - $this->violationMapper->expects($this->once()) - ->method('mapViolation') - ->with($violation, $form, false); - - $this->listener->validateForm(new FormEvent($form, null)); + $this->assertCount(1, $form->getErrors()); + $this->assertSame($violation, $form->getErrors()[0]->getCause()); } public function testMapViolationAllowsNonSyncIfInvalid() { - $violation = $this->getConstraintViolation(FormConstraint::NOT_SYNCHRONIZED_ERROR); - $form = $this->getForm('street'); + $violation = new ConstraintViolation($this->message, $this->messageTemplate, $this->params, null, 'data', null, null, FormConstraint::NOT_SYNCHRONIZED_ERROR, new FormConstraint()); + $form = new SubmittedNotSynchronizedForm(new FormConfigBuilder('street', null, new EventDispatcher())); - $this->validator->expects($this->once()) - ->method('validate') - ->will($this->returnValue([$violation])); + $validator = new DummyValidator($violation); + $listener = new ValidationListener($validator, new ViolationMapper()); + $listener->validateForm(new FormEvent($form, null)); - $this->violationMapper->expects($this->once()) - ->method('mapViolation') - // pass true now - ->with($violation, $form, true); - - $this->listener->validateForm(new FormEvent($form, null)); + $this->assertCount(1, $form->getErrors()); + $this->assertSame($violation, $form->getErrors()[0]->getCause()); } public function testValidateIgnoresNonRoot() @@ -143,36 +116,72 @@ public function testValidateIgnoresNonRoot() $form = $this->createForm('', true); $form->add($childForm); - $this->validator->expects($this->never()) - ->method('validate'); - - $this->violationMapper->expects($this->never()) - ->method('mapViolation'); + $form->submit(['child' => null]); $this->listener->validateForm(new FormEvent($childForm, null)); + + $this->assertTrue($childForm->isValid()); } public function testValidateWithEmptyViolationList() { $form = $this->createForm(); + $form->submit(null); - $this->validator - ->expects($this->once()) - ->method('validate') - ->will($this->returnValue(new ConstraintViolationList())); + $this->listener->validateForm(new FormEvent($form, null)); - $this->violationMapper - ->expects($this->never()) - ->method('mapViolation'); + $this->assertTrue($form->isValid()); + } +} - $this->listener->validateForm(new FormEvent($form, null)); +class SubmittedNotSynchronizedForm extends Form +{ + public function isSubmitted() + { + return true; } - public function testValidatorInterface() + public function isSynchronized() { - $validator = $this->getMockBuilder('Symfony\Component\Validator\Validator\ValidatorInterface')->getMock(); + return false; + } +} + +class DummyValidator implements ValidatorInterface +{ + private $violation; - $listener = new ValidationListener($validator, $this->violationMapper); - $this->assertAttributeSame($validator, 'validator', $listener); + public function __construct(ConstraintViolationInterface $violation) + { + $this->violation = $violation; + } + + public function getMetadataFor($value) + { + } + + public function hasMetadataFor($value) + { + } + + public function validate($value, $constraints = null, $groups = null) + { + return [$this->violation]; + } + + public function validateProperty($object, $propertyName, $groups = null) + { + } + + public function validatePropertyValue($objectOrClass, $propertyName, $value, $groups = null) + { + } + + public function startContext() + { + } + + public function inContext(ExecutionContextInterface $context) + { } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php index 8437d6f0975e8..53d29a19112c7 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Type/FormTypeValidatorExtensionTest.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Form\Tests\Extension\Validator\Type; -use Symfony\Component\Form\Extension\Validator\Type\FormTypeValidatorExtension; use Symfony\Component\Form\Extension\Validator\ValidatorExtension; use Symfony\Component\Form\Forms; use Symfony\Component\Form\Test\Traits\ValidatorExtensionTrait; @@ -56,14 +55,6 @@ public function testValidConstraint() $this->assertSame([$valid], $form->getConfig()->getOption('constraints')); } - public function testValidatorInterface() - { - $validator = $this->getMockBuilder('Symfony\Component\Validator\Validator\ValidatorInterface')->getMock(); - - $formTypeValidatorExtension = new FormTypeValidatorExtension($validator); - $this->assertAttributeSame($validator, 'validator', $formTypeValidatorExtension); - } - public function testGroupSequenceWithConstraintsOption() { $form = Forms::createFormFactoryBuilder() diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Type/UploadValidatorExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Type/UploadValidatorExtensionTest.php index 7d1733e20db76..34ff556d15300 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Type/UploadValidatorExtensionTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Type/UploadValidatorExtensionTest.php @@ -21,18 +21,11 @@ class UploadValidatorExtensionTest extends TypeTestCase { public function testPostMaxSizeTranslation() { - $translator = $this->getMockBuilder(TranslatorInterface::class)->getMock(); - - $translator->expects($this->any()) - ->method('trans') - ->with($this->equalTo('old max {{ max }}!')) - ->willReturn('translated max {{ max }}!'); - - $extension = new UploadValidatorExtension($translator); + $extension = new UploadValidatorExtension(new DummyTranslator()); $resolver = new OptionsResolver(); $resolver->setDefault('post_max_size_message', 'old max {{ max }}!'); - $resolver->setDefault('upload_max_size_message', function (Options $options, $message) { + $resolver->setDefault('upload_max_size_message', function (Options $options) { return function () use ($options) { return $options['post_max_size_message']; }; @@ -44,3 +37,25 @@ public function testPostMaxSizeTranslation() $this->assertEquals('translated max {{ max }}!', $options['upload_max_size_message']()); } } + +class DummyTranslator implements TranslatorInterface +{ + public function trans($id, array $parameters = [], $domain = null, $locale = null) + { + return 'translated max {{ max }}!'; + } + + public function transChoice($id, $number, array $parameters = [], $domain = null, $locale = null) + { + return 'translated max {{ max }}!'; + } + + public function setLocale($locale) + { + } + + public function getLocale() + { + return 'en'; + } +} diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Util/ServerParamsTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Util/ServerParamsTest.php index 0803e18de9e83..049876246c507 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Util/ServerParamsTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Util/ServerParamsTest.php @@ -14,6 +14,7 @@ use PHPUnit\Framework\TestCase; use Symfony\Component\Form\Extension\Validator\Util\ServerParams; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\RequestStack; class ServerParamsTest extends TestCase { @@ -32,8 +33,8 @@ public function testGetContentLengthFromSuperglobals() public function testGetContentLengthFromRequest() { $request = Request::create('http://foo', 'GET', [], [], [], ['CONTENT_LENGTH' => 1024]); - $requestStack = $this->getMockBuilder('Symfony\Component\HttpFoundation\RequestStack')->setMethods(['getCurrentRequest'])->getMock(); - $requestStack->expects($this->once())->method('getCurrentRequest')->will($this->returnValue($request)); + $requestStack = new RequestStack(); + $requestStack->push($request); $serverParams = new ServerParams($requestStack); $this->assertEquals(1024, $serverParams->getContentLength()); @@ -42,11 +43,7 @@ public function testGetContentLengthFromRequest() /** @dataProvider getGetPostMaxSizeTestData */ public function testGetPostMaxSize($size, $bytes) { - $serverParams = $this->getMockBuilder('Symfony\Component\Form\Extension\Validator\Util\ServerParams')->setMethods(['getNormalizedIniPostMaxSize'])->getMock(); - $serverParams - ->expects($this->any()) - ->method('getNormalizedIniPostMaxSize') - ->will($this->returnValue(strtoupper($size))); + $serverParams = new DummyServerParams($size); $this->assertEquals($bytes, $serverParams->getPostMaxSize()); } @@ -70,3 +67,20 @@ public function getGetPostMaxSizeTestData() ]; } } + +class DummyServerParams extends ServerParams +{ + private $size; + + public function __construct($size) + { + parent::__construct(); + + $this->size = $size; + } + + public function getNormalizedIniPostMaxSize() + { + return $this->size; + } +} diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorExtensionTest.php index ce18d0b6c5718..136086a5e5ba8 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorExtensionTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorExtensionTest.php @@ -12,37 +12,118 @@ namespace Symfony\Component\Form\Tests\Extension\Validator; use PHPUnit\Framework\TestCase; +use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\Extension\Validator\Constraints\Form as FormConstraint; use Symfony\Component\Form\Extension\Validator\ValidatorExtension; +use Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser; +use Symfony\Component\Form\Form; +use Symfony\Component\Form\FormBuilderInterface; +use Symfony\Component\Form\FormFactoryBuilder; +use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\Validator\Constraints\NotBlank; +use Symfony\Component\Validator\Mapping\CascadingStrategy; +use Symfony\Component\Validator\Mapping\ClassMetadata; +use Symfony\Component\Validator\Mapping\Factory\LazyLoadingMetadataFactory; +use Symfony\Component\Validator\Mapping\Loader\StaticMethodLoader; +use Symfony\Component\Validator\Mapping\TraversalStrategy; +use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory; +use Symfony\Component\Validator\Validation; class ValidatorExtensionTest extends TestCase { public function test2Dot5ValidationApi() { - $validator = $this->getMockBuilder('Symfony\Component\Validator\Validator\RecursiveValidator') - ->disableOriginalConstructor() - ->getMock(); - $metadata = $this->getMockBuilder('Symfony\Component\Validator\Mapping\ClassMetadata') - ->setMethods(['addConstraint', 'addPropertyConstraint']) - ->disableOriginalConstructor() - ->getMock(); + $metadata = new ClassMetadata(Form::class); - $validator->expects($this->once()) - ->method('getMetadataFor') - ->with($this->identicalTo('Symfony\Component\Form\Form')) - ->will($this->returnValue($metadata)); + $metadataFactory = new FakeMetadataFactory(); + $metadataFactory->addMetadata($metadata); - // Verify that the constraints are added - $metadata->expects($this->once()) - ->method('addConstraint') - ->with($this->isInstanceOf('Symfony\Component\Form\Extension\Validator\Constraints\Form')); - - $metadata->expects($this->once()) - ->method('addPropertyConstraint') - ->with('children', $this->isInstanceOf('Symfony\Component\Validator\Constraints\Valid')); + $validator = Validation::createValidatorBuilder() + ->setMetadataFactory($metadataFactory) + ->getValidator(); $extension = new ValidatorExtension($validator); - $guesser = $extension->loadTypeGuesser(); - $this->assertInstanceOf('Symfony\Component\Form\Extension\Validator\ValidatorTypeGuesser', $guesser); + $this->assertInstanceOf(ValidatorTypeGuesser::class, $extension->loadTypeGuesser()); + + $this->assertCount(1, $metadata->getConstraints()); + $this->assertInstanceOf(FormConstraint::class, $metadata->getConstraints()[0]); + + $this->assertSame(CascadingStrategy::CASCADE, $metadata->getPropertyMetadata('children')[0]->cascadingStrategy); + $this->assertSame(TraversalStrategy::IMPLICIT, $metadata->getPropertyMetadata('children')[0]->traversalStrategy); + } + + public function testDataConstraintsInvalidateFormEvenIfFieldIsNotSubmitted() + { + $form = $this->createForm(FooType::class); + $form->submit(['baz' => 'foobar'], false); + + $this->assertTrue($form->isSubmitted()); + $this->assertFalse($form->isValid()); + $this->assertFalse($form->get('bar')->isSubmitted()); + $this->assertCount(1, $form->get('bar')->getErrors()); + } + + public function testFieldConstraintsDoNotInvalidateFormIfFieldIsNotSubmitted() + { + $form = $this->createForm(FooType::class); + $form->submit(['bar' => 'foobar'], false); + + $this->assertTrue($form->isSubmitted()); + $this->assertTrue($form->isValid()); + } + + public function testFieldConstraintsInvalidateFormIfFieldIsSubmitted() + { + $form = $this->createForm(FooType::class); + $form->submit(['bar' => 'foobar', 'baz' => ''], false); + + $this->assertTrue($form->isSubmitted()); + $this->assertFalse($form->isValid()); + $this->assertTrue($form->get('bar')->isSubmitted()); + $this->assertTrue($form->get('bar')->isValid()); + $this->assertTrue($form->get('baz')->isSubmitted()); + $this->assertFalse($form->get('baz')->isValid()); + } + + private function createForm($type) + { + $validator = Validation::createValidatorBuilder() + ->setMetadataFactory(new LazyLoadingMetadataFactory(new StaticMethodLoader())) + ->getValidator(); + $formFactoryBuilder = new FormFactoryBuilder(); + $formFactoryBuilder->addExtension(new ValidatorExtension($validator)); + $formFactory = $formFactoryBuilder->getFormFactory(); + + return $formFactory->create($type); + } +} + +class Foo +{ + public $bar; + public $baz; + + public static function loadValidatorMetadata(ClassMetadata $metadata) + { + $metadata->addPropertyConstraint('bar', new NotBlank()); + } +} + +class FooType extends AbstractType +{ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $builder + ->add('bar') + ->add('baz', null, [ + 'constraints' => [new NotBlank()], + ]) + ; + } + + public function configureOptions(OptionsResolver $resolver) + { + $resolver->setDefault('data_class', Foo::class); } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php index d14c89c2cbda1..878bbfad21bc5 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorTypeGuesserTest.php @@ -23,6 +23,8 @@ use Symfony\Component\Validator\Constraints\Range; use Symfony\Component\Validator\Constraints\Type; use Symfony\Component\Validator\Mapping\ClassMetadata; +use Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface; +use Symfony\Component\Validator\Tests\Fixtures\FakeMetadataFactory; /** * @author franek @@ -45,18 +47,15 @@ class ValidatorTypeGuesserTest extends TestCase private $metadata; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var MetadataFactoryInterface */ private $metadataFactory; protected function setUp() { $this->metadata = new ClassMetadata(self::TEST_CLASS); - $this->metadataFactory = $this->getMockBuilder('Symfony\Component\Validator\Mapping\Factory\MetadataFactoryInterface')->getMock(); - $this->metadataFactory->expects($this->any()) - ->method('getMetadataFor') - ->with(self::TEST_CLASS) - ->will($this->returnValue($this->metadata)); + $this->metadataFactory = new FakeMetadataFactory(); + $this->metadataFactory->addMetadata($this->metadata); $this->guesser = new ValidatorTypeGuesser($this->metadataFactory); } diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php index 1278a86e22c2a..2fa3e928926ee 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ViolationMapper/ViolationMapperTest.php @@ -12,8 +12,11 @@ namespace Symfony\Component\Form\Tests\Extension\Validator\ViolationMapper; use PHPUnit\Framework\TestCase; +use Symfony\Component\EventDispatcher\EventDispatcher; +use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Form\CallbackTransformer; use Symfony\Component\Form\Exception\TransformationFailedException; +use Symfony\Component\Form\Extension\Core\DataMapper\PropertyPathMapper; use Symfony\Component\Form\Extension\Validator\ViolationMapper\ViolationMapper; use Symfony\Component\Form\Form; use Symfony\Component\Form\FormConfigBuilder; @@ -34,7 +37,7 @@ class ViolationMapperTest extends TestCase const LEVEL_2 = 3; /** - * @var \PHPUnit_Framework_MockObject_MockObject + * @var EventDispatcherInterface */ private $dispatcher; @@ -60,7 +63,7 @@ class ViolationMapperTest extends TestCase protected function setUp() { - $this->dispatcher = $this->getMockBuilder('Symfony\Component\EventDispatcher\EventDispatcherInterface')->getMock(); + $this->dispatcher = new EventDispatcher(); $this->mapper = new ViolationMapper(); $this->message = 'Message'; $this->messageTemplate = 'Message template'; @@ -76,7 +79,7 @@ protected function getForm($name = 'name', $propertyPath = null, $dataClass = nu $config->setInheritData($inheritData); $config->setPropertyPath($propertyPath); $config->setCompound(true); - $config->setDataMapper($this->getDataMapper()); + $config->setDataMapper(new PropertyPathMapper()); if (!$synchronized) { $config->addViewTransformer(new CallbackTransformer( @@ -88,14 +91,6 @@ function () { throw new TransformationFailedException(); } return new Form($config); } - /** - * @return \PHPUnit_Framework_MockObject_MockObject - */ - private function getDataMapper() - { - return $this->getMockBuilder('Symfony\Component\Form\DataMapperInterface')->getMock(); - } - /** * @param $propertyPath * @@ -210,7 +205,7 @@ public function testAbortDotRuleMappingIfNotSynchronized() $this->assertCount(0, $grandChild->getErrors(), $grandChild->getName().' should not have an error, but has one'); } - public function testAbortMappingIfNotSubmitted() + public function testMappingIfNotSubmitted() { $violation = $this->getConstraintViolation('children[address].data.street'); $parent = $this->getForm('parent'); @@ -230,10 +225,10 @@ public function testAbortMappingIfNotSubmitted() $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one'); $this->assertCount(0, $child->getErrors(), $child->getName().' should not have an error, but has one'); - $this->assertCount(0, $grandChild->getErrors(), $grandChild->getName().' should not have an error, but has one'); + $this->assertCount(1, $grandChild->getErrors(), $grandChild->getName().' should have one error'); } - public function testAbortDotRuleMappingIfNotSubmitted() + public function testDotRuleMappingIfNotSubmitted() { $violation = $this->getConstraintViolation('data.address'); $parent = $this->getForm('parent'); @@ -255,7 +250,7 @@ public function testAbortDotRuleMappingIfNotSubmitted() $this->assertCount(0, $parent->getErrors(), $parent->getName().' should not have an error, but has one'); $this->assertCount(0, $child->getErrors(), $child->getName().' should not have an error, but has one'); - $this->assertCount(0, $grandChild->getErrors(), $grandChild->getName().' should not have an error, but has one'); + $this->assertCount(1, $grandChild->getErrors(), $grandChild->getName().' should have one error'); } public function provideDefaultTests() diff --git a/src/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php b/src/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php index 39758e781884a..006724014a2a1 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php +++ b/src/Symfony/Component/Form/Tests/Fixtures/CustomArrayObject.php @@ -26,7 +26,7 @@ public function __construct(array $array = null) public function offsetExists($offset) { - return array_key_exists($offset, $this->array); + return \array_key_exists($offset, $this->array); } public function offsetGet($offset) 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 391c3e694d974..1824c46a7e5f8 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,10 +15,9 @@ Symfony\Component\Form\Extension\Core\Type\ChoiceType (choice_translation_domain ---------------- --------------------%s Allowed values - %s ---------------- --------------------%s - Normalizer Closure%s{%w - parameters: 2 %s + Normalizer Closure%s{%A file: "%s%eExtension%eCore%eType%eChoiceType.php"%w - line: "%s to %s" %s + line: %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 846d6f384684c..780a4e5cb3589 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,15 +8,13 @@ Symfony\Component\Form\Tests\Console\Descriptor\FooType (empty_data) Default Value: null %s %s Closure(s): [ %s - Closure%s{%w - parameters: 1 %s + Closure%s{%A file: "%s%eExtension%eCore%eType%eFormType.php"%w - line: "%s to %s" %s + line: %s }, %s - Closure%s{%w - parameters: 2 %s + Closure%s{%A file: "%s%eTests%eConsole%eDescriptor%eAbstractDescriptorTest.php"%w - line: "%s to %s" %s + line: %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 8cc88a550ab70..ca203a285b2c2 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,10 +16,9 @@ Symfony\Component\Form\Tests\Console\Descriptor\FooType (foo) "baz" %s ] %s ---------------- --------------------%s - Normalizer Closure%s{%w - parameters: 2 %s + Normalizer Closure%s{%A file: "%s%eTests%eConsole%eDescriptor%eAbstractDescriptorTest.php"%w - line: "%s to %s" %s + line: %s } %s ---------------- --------------------%s diff --git a/src/Symfony/Component/Form/Tests/Fixtures/FixedDataTransformer.php b/src/Symfony/Component/Form/Tests/Fixtures/FixedDataTransformer.php index e768b1d7cfac9..29391160968e2 100644 --- a/src/Symfony/Component/Form/Tests/Fixtures/FixedDataTransformer.php +++ b/src/Symfony/Component/Form/Tests/Fixtures/FixedDataTransformer.php @@ -25,7 +25,7 @@ public function __construct(array $mapping) public function transform($value) { - if (!array_key_exists($value, $this->mapping)) { + if (!\array_key_exists($value, $this->mapping)) { throw new TransformationFailedException(sprintf('No mapping for value "%s"', $value)); } diff --git a/src/Symfony/Component/Form/Tests/NativeRequestHandlerTest.php b/src/Symfony/Component/Form/Tests/NativeRequestHandlerTest.php index 077f477d4a23a..25a4716650755 100644 --- a/src/Symfony/Component/Form/Tests/NativeRequestHandlerTest.php +++ b/src/Symfony/Component/Form/Tests/NativeRequestHandlerTest.php @@ -179,6 +179,59 @@ public function testMethodOverrideHeaderIgnoredIfNotPost() $this->assertFalse($form->isSubmitted()); } + public function testFormIgnoresMethodFieldIfRequestMethodIsMatched() + { + $form = $this->createForm('foo', 'PUT', true); + $form->add($this->createForm('bar')); + + $this->setRequestData('PUT', [ + 'foo' => [ + '_method' => 'PUT', + 'bar' => 'baz', + ], + ]); + + $this->requestHandler->handleRequest($form, $this->request); + + $this->assertSame([], $form->getExtraData()); + } + + public function testFormDoesNotIgnoreMethodFieldIfRequestMethodIsNotMatched() + { + $form = $this->createForm('foo', 'PUT', true); + $form->add($this->createForm('bar')); + + $this->setRequestData('PUT', [ + 'foo' => [ + '_method' => 'DELETE', + 'bar' => 'baz', + ], + ]); + + $this->requestHandler->handleRequest($form, $this->request); + + $this->assertSame(['_method' => 'DELETE'], $form->getExtraData()); + } + + public function testMethodSubFormIsSubmitted() + { + $form = $this->createForm('foo', 'PUT', true); + $form->add($this->createForm('_method')); + $form->add($this->createForm('bar')); + + $this->setRequestData('PUT', [ + 'foo' => [ + '_method' => 'PUT', + 'bar' => 'baz', + ], + ]); + + $this->requestHandler->handleRequest($form, $this->request); + + $this->assertTrue($form->get('_method')->isSubmitted()); + $this->assertSame('PUT', $form->get('_method')->getData()); + } + protected function setRequestData($method, $data, $files = []) { if ('GET' === $method) { @@ -201,7 +254,7 @@ protected function getRequestHandler() return new NativeRequestHandler($this->serverParams); } - protected function getMockFile($suffix = '') + protected function getUploadedFile($suffix = '') { return [ 'name' => 'upload'.$suffix.'.txt', diff --git a/src/Symfony/Component/Form/Tests/VersionAwareTest.php b/src/Symfony/Component/Form/Tests/VersionAwareTest.php new file mode 100644 index 0000000000000..2b8489a6a27cf --- /dev/null +++ b/src/Symfony/Component/Form/Tests/VersionAwareTest.php @@ -0,0 +1,27 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Tests; + +trait VersionAwareTest +{ + protected static $supportedFeatureSetVersion = 304; + + /** + * @param int $requiredFeatureSetVersion + */ + protected function requiresFeatureSet($requiredFeatureSetVersion) + { + if ($requiredFeatureSetVersion > static::$supportedFeatureSetVersion) { + $this->markTestSkipped(sprintf('Test requires features from symfony/form %.2f but only version %.2f is supported.', $requiredFeatureSetVersion / 100, static::$supportedFeatureSetVersion / 100)); + } + } +} diff --git a/src/Symfony/Component/HttpFoundation/HeaderBag.php b/src/Symfony/Component/HttpFoundation/HeaderBag.php index b37a72e47ebd7..fa9d17313cbe7 100644 --- a/src/Symfony/Component/HttpFoundation/HeaderBag.php +++ b/src/Symfony/Component/HttpFoundation/HeaderBag.php @@ -112,7 +112,7 @@ public function get($key, $default = null, $first = true) $key = str_replace('_', '-', strtolower($key)); $headers = $this->all(); - if (!array_key_exists($key, $headers)) { + if (!\array_key_exists($key, $headers)) { if (null === $default) { return $first ? null : []; } @@ -168,7 +168,7 @@ public function set($key, $values, $replace = true) */ public function has($key) { - return array_key_exists(str_replace('_', '-', strtolower($key)), $this->all()); + return \array_key_exists(str_replace('_', '-', strtolower($key)), $this->all()); } /** @@ -245,7 +245,7 @@ public function addCacheControlDirective($key, $value = true) */ public function hasCacheControlDirective($key) { - return array_key_exists($key, $this->cacheControl); + return \array_key_exists($key, $this->cacheControl); } /** @@ -257,7 +257,7 @@ public function hasCacheControlDirective($key) */ public function getCacheControlDirective($key) { - return array_key_exists($key, $this->cacheControl) ? $this->cacheControl[$key] : null; + return \array_key_exists($key, $this->cacheControl) ? $this->cacheControl[$key] : null; } /** diff --git a/src/Symfony/Component/HttpFoundation/ParameterBag.php b/src/Symfony/Component/HttpFoundation/ParameterBag.php index 3c6ba46a6a08e..f05e4a2154ecb 100644 --- a/src/Symfony/Component/HttpFoundation/ParameterBag.php +++ b/src/Symfony/Component/HttpFoundation/ParameterBag.php @@ -81,7 +81,7 @@ public function add(array $parameters = []) */ public function get($key, $default = null) { - return array_key_exists($key, $this->parameters) ? $this->parameters[$key] : $default; + return \array_key_exists($key, $this->parameters) ? $this->parameters[$key] : $default; } /** @@ -104,7 +104,7 @@ public function set($key, $value) */ public function has($key) { - return array_key_exists($key, $this->parameters); + return \array_key_exists($key, $this->parameters); } /** diff --git a/src/Symfony/Component/HttpFoundation/RedirectResponse.php b/src/Symfony/Component/HttpFoundation/RedirectResponse.php index 22e5fbb2d07c4..f685856584598 100644 --- a/src/Symfony/Component/HttpFoundation/RedirectResponse.php +++ b/src/Symfony/Component/HttpFoundation/RedirectResponse.php @@ -42,7 +42,7 @@ public function __construct(?string $url, int $status = 302, array $headers = [] throw new \InvalidArgumentException(sprintf('The HTTP status code is not a redirect ("%s" given).', $status)); } - if (301 == $status && !array_key_exists('cache-control', $headers)) { + if (301 == $status && !\array_key_exists('cache-control', $headers)) { $this->headers->remove('cache-control'); } } diff --git a/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php b/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php index 9dd8908b2772d..9e07221933096 100644 --- a/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php +++ b/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php @@ -160,7 +160,7 @@ public function remove($key) */ public function hasCacheControlDirective($key) { - return array_key_exists($key, $this->computedCacheControl); + return \array_key_exists($key, $this->computedCacheControl); } /** @@ -168,7 +168,7 @@ public function hasCacheControlDirective($key) */ public function getCacheControlDirective($key) { - return array_key_exists($key, $this->computedCacheControl) ? $this->computedCacheControl[$key] : null; + return \array_key_exists($key, $this->computedCacheControl) ? $this->computedCacheControl[$key] : null; } public function setCookie(Cookie $cookie) diff --git a/src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php b/src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php index 7b53e7fc766b9..ee33698cf0842 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php +++ b/src/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php @@ -63,7 +63,7 @@ public function getStorageKey() */ public function has($name) { - return array_key_exists($name, $this->attributes); + return \array_key_exists($name, $this->attributes); } /** @@ -71,7 +71,7 @@ public function has($name) */ public function get($name, $default = null) { - return array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default; + return \array_key_exists($name, $this->attributes) ? $this->attributes[$name] : $default; } /** @@ -107,7 +107,7 @@ public function replace(array $attributes) public function remove($name) { $retval = null; - if (array_key_exists($name, $this->attributes)) { + if (\array_key_exists($name, $this->attributes)) { $retval = $this->attributes[$name]; unset($this->attributes[$name]); } diff --git a/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php b/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php index 7890214e82533..162c4b5295849 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php +++ b/src/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php @@ -44,7 +44,7 @@ public function has($name) return false; } - return array_key_exists($name, $attributes); + return \array_key_exists($name, $attributes); } /** @@ -60,7 +60,7 @@ public function get($name, $default = null) return $default; } - return array_key_exists($name, $attributes) ? $attributes[$name] : $default; + return \array_key_exists($name, $attributes) ? $attributes[$name] : $default; } /** @@ -81,7 +81,7 @@ public function remove($name) $retval = null; $attributes = &$this->resolveAttributePath($name); $name = $this->resolveKey($name); - if (null !== $attributes && array_key_exists($name, $attributes)) { + if (null !== $attributes && \array_key_exists($name, $attributes)) { $retval = $attributes[$name]; unset($attributes[$name]); } @@ -123,7 +123,7 @@ protected function &resolveAttributePath($name, $writeContext = false) unset($parts[\count($parts) - 1]); foreach ($parts as $part) { - if (null !== $array && !array_key_exists($part, $array)) { + if (null !== $array && !\array_key_exists($part, $array)) { if (!$writeContext) { $null = null; diff --git a/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php b/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php index 782665caffbc6..6502f3d50155f 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php +++ b/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php @@ -53,7 +53,7 @@ public function initialize(array &$flashes) // The logic: messages from the last request will be stored in new, so we move them to previous // This request we will show what is in 'display'. What is placed into 'new' this time round will // be moved to display next time round. - $this->flashes['display'] = array_key_exists('new', $this->flashes) ? $this->flashes['new'] : []; + $this->flashes['display'] = \array_key_exists('new', $this->flashes) ? $this->flashes['new'] : []; $this->flashes['new'] = []; } @@ -78,7 +78,7 @@ public function peek($type, array $default = []) */ public function peekAll() { - return array_key_exists('display', $this->flashes) ? (array) $this->flashes['display'] : []; + return \array_key_exists('display', $this->flashes) ? (array) $this->flashes['display'] : []; } /** @@ -132,7 +132,7 @@ public function set($type, $messages) */ public function has($type) { - return array_key_exists($type, $this->flashes['display']) && $this->flashes['display'][$type]; + return \array_key_exists($type, $this->flashes['display']) && $this->flashes['display'][$type]; } /** diff --git a/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBag.php b/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBag.php index 9674e3514b537..c6b7ce354cec4 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBag.php +++ b/src/Symfony/Component/HttpFoundation/Session/Flash/FlashBag.php @@ -123,7 +123,7 @@ public function setAll(array $messages) */ public function has($type) { - return array_key_exists($type, $this->flashes) && $this->flashes[$type]; + return \array_key_exists($type, $this->flashes) && $this->flashes[$type]; } /** diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php index 14ea230f57bdb..efe1705179b6d 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php @@ -34,9 +34,6 @@ abstract class DataCollector implements DataCollectorInterface, \Serializable */ private $cloner; - /** - * @internal - */ public function serialize() { $trace = debug_backtrace(DEBUG_BACKTRACE_PROVIDE_OBJECT, 2); @@ -45,9 +42,6 @@ public function serialize() return $isCalledFromOverridingMethod ? $this->data : serialize($this->data); } - /** - * @internal - */ public function unserialize($data) { $this->data = \is_array($data) ? $data : unserialize($data); diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php index 04ea44a073ec4..323ebf20547e7 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php @@ -133,9 +133,6 @@ public function reset() $this->clonesIndex = 0; } - /** - * @internal - */ public function serialize() { if ($this->clonesCount !== $this->clonesIndex) { @@ -152,9 +149,6 @@ public function serialize() return $ser; } - /** - * @internal - */ public function unserialize($data) { $this->data = unserialize($data); diff --git a/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php b/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php index dd00797f5f088..811f99bd9de8f 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/ExceptionListener.php @@ -79,13 +79,12 @@ public function onKernelException(GetResponseForExceptionEvent $event) $this->logException($e, sprintf('Exception thrown when handling an exception (%s: %s at %s line %s)', $f->getClass(), $f->getMessage(), $e->getFile(), $e->getLine())); - $wrapper = $e; - - while ($prev = $wrapper->getPrevious()) { + $prev = $e; + do { if ($exception === $wrapper = $prev) { throw $e; } - } + } while ($prev = $wrapper->getPrevious()); $prev = new \ReflectionProperty($wrapper instanceof \Exception ? \Exception::class : \Error::class, 'previous'); $prev->setAccessible(true); diff --git a/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php b/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php index 5ee09fb1a7f9c..c01b09559afd2 100644 --- a/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php +++ b/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php @@ -80,7 +80,7 @@ public function render($uri, Request $request, array $options = []) return SubRequestHandler::handle($this->kernel, $subRequest, HttpKernelInterface::SUB_REQUEST, false); } catch (\Exception $e) { // we dispatch the exception event to trigger the logging - // the response that comes back is simply ignored + // the response that comes back is ignored if (isset($options['ignore_errors']) && $options['ignore_errors'] && $this->dispatcher) { $event = new GetResponseForExceptionEvent($this->kernel, $request, HttpKernelInterface::SUB_REQUEST, $e); diff --git a/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php b/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php index 168e9564b0c99..862bac557dd77 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php @@ -5,10 +5,6 @@ * * (c) Fabien Potencier * - * This code is partially based on the Rack-Cache library by Ryan Tomayko, - * which is released under the MIT license. - * (based on commit 02d2b48d75bcb63cf1c0c7149c077ad256542801) - * * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ @@ -28,30 +24,69 @@ */ class ResponseCacheStrategy implements ResponseCacheStrategyInterface { - private $cacheable = true; + /** + * Cache-Control headers that are sent to the final response if they appear in ANY of the responses. + */ + private static $overrideDirectives = ['private', 'no-cache', 'no-store', 'no-transform', 'must-revalidate', 'proxy-revalidate']; + + /** + * Cache-Control headers that are sent to the final response if they appear in ALL of the responses. + */ + private static $inheritDirectives = ['public', 'immutable']; + private $embeddedResponses = 0; - private $ttls = []; - private $maxAges = []; private $isNotCacheableResponseEmbedded = false; + private $age = 0; + private $flagDirectives = [ + 'no-cache' => null, + 'no-store' => null, + 'no-transform' => null, + 'must-revalidate' => null, + 'proxy-revalidate' => null, + 'public' => null, + 'private' => null, + 'immutable' => null, + ]; + private $ageDirectives = [ + 'max-age' => null, + 's-maxage' => null, + 'expires' => null, + ]; /** * {@inheritdoc} */ public function add(Response $response) { - if (!$response->isFresh() || !$response->isCacheable()) { - $this->cacheable = false; - } else { - $maxAge = $response->getMaxAge(); - $this->ttls[] = $response->getTtl(); - $this->maxAges[] = $maxAge; - - if (null === $maxAge) { - $this->isNotCacheableResponseEmbedded = true; + ++$this->embeddedResponses; + + foreach (self::$overrideDirectives as $directive) { + if ($response->headers->hasCacheControlDirective($directive)) { + $this->flagDirectives[$directive] = true; } } - ++$this->embeddedResponses; + foreach (self::$inheritDirectives as $directive) { + if (false !== $this->flagDirectives[$directive]) { + $this->flagDirectives[$directive] = $response->headers->hasCacheControlDirective($directive); + } + } + + $age = $response->getAge(); + $this->age = max($this->age, $age); + + if ($this->willMakeFinalResponseUncacheable($response)) { + $this->isNotCacheableResponseEmbedded = true; + + return; + } + + $this->storeRelativeAgeDirective('max-age', $response->headers->getCacheControlDirective('max-age'), $age); + $this->storeRelativeAgeDirective('s-maxage', $response->headers->getCacheControlDirective('s-maxage') ?: $response->headers->getCacheControlDirective('max-age'), $age); + + $expires = $response->getExpires(); + $expires = null !== $expires ? $expires->format('U') - $response->getDate()->format('U') : null; + $this->storeRelativeAgeDirective('expires', $expires >= 0 ? $expires : null, 0); } /** @@ -64,33 +99,124 @@ public function update(Response $response) return; } - // Remove validation related headers in order to avoid browsers using - // their own cache, because some of the response content comes from - // at least one embedded response (which likely has a different caching strategy). - if ($response->isValidateable()) { - $response->setEtag(null); - $response->setLastModified(null); + // Remove validation related headers of the master response, + // because some of the response content comes from at least + // one embedded response (which likely has a different caching strategy). + $response->setEtag(null); + $response->setLastModified(null); + + $this->add($response); + + $response->headers->set('Age', $this->age); + + if ($this->isNotCacheableResponseEmbedded) { + $response->setExpires($response->getDate()); + + if ($this->flagDirectives['no-store']) { + $response->headers->set('Cache-Control', 'no-cache, no-store, must-revalidate'); + } else { + $response->headers->set('Cache-Control', 'no-cache, must-revalidate'); + } + + return; + } + + $flags = array_filter($this->flagDirectives); + + if (isset($flags['must-revalidate'])) { + $flags['no-cache'] = true; } - if (!$response->isFresh() || !$response->isCacheable()) { - $this->cacheable = false; + $response->headers->set('Cache-Control', implode(', ', array_keys($flags))); + + $maxAge = null; + $sMaxage = null; + + if (\is_numeric($this->ageDirectives['max-age'])) { + $maxAge = $this->ageDirectives['max-age'] + $this->age; + $response->headers->addCacheControlDirective('max-age', $maxAge); } - if (!$this->cacheable) { - $response->headers->set('Cache-Control', 'no-cache, must-revalidate'); + if (\is_numeric($this->ageDirectives['s-maxage'])) { + $sMaxage = $this->ageDirectives['s-maxage'] + $this->age; - return; + if ($maxAge !== $sMaxage) { + $response->headers->addCacheControlDirective('s-maxage', $sMaxage); + } + } + + if (\is_numeric($this->ageDirectives['expires'])) { + $date = clone $response->getDate(); + $date->modify('+'.($this->ageDirectives['expires'] + $this->age).' seconds'); + $response->setExpires($date); } + } - $this->ttls[] = $response->getTtl(); - $this->maxAges[] = $response->getMaxAge(); + /** + * RFC2616, Section 13.4. + * + * @see https://www.w3.org/Protocols/rfc2616/rfc2616-sec13.html#sec13.4 + * + * @return bool + */ + private function willMakeFinalResponseUncacheable(Response $response) + { + // RFC2616: A response received with a status code of 200, 203, 300, 301 or 410 + // MAY be stored by a cache […] unless a cache-control directive prohibits caching. + if ($response->headers->hasCacheControlDirective('no-cache') + || $response->headers->getCacheControlDirective('no-store') + ) { + return true; + } - if ($this->isNotCacheableResponseEmbedded) { - $response->headers->removeCacheControlDirective('s-maxage'); - } elseif (null !== $maxAge = min($this->maxAges)) { - $response->setSharedMaxAge($maxAge); - $response->headers->set('Age', $maxAge - min($this->ttls)); + // Last-Modified and Etag headers cannot be merged, they render the response uncacheable + // by default (except if the response also has max-age etc.). + if (\in_array($response->getStatusCode(), [200, 203, 300, 301, 410]) + && null === $response->getLastModified() + && null === $response->getEtag() + ) { + return false; + } + + // RFC2616: A response received with any other status code (e.g. status codes 302 and 307) + // MUST NOT be returned in a reply to a subsequent request unless there are + // cache-control directives or another header(s) that explicitly allow it. + $cacheControl = ['max-age', 's-maxage', 'must-revalidate', 'proxy-revalidate', 'public', 'private']; + foreach ($cacheControl as $key) { + if ($response->headers->hasCacheControlDirective($key)) { + return false; + } + } + + if ($response->headers->has('Expires')) { + return false; + } + + return true; + } + + /** + * Store lowest max-age/s-maxage/expires for the final response. + * + * The response might have been stored in cache a while ago. To keep things comparable, + * we have to subtract the age so that the value is normalized for an age of 0. + * + * If the value is lower than the currently stored value, we update the value, to keep a rolling + * minimal value of each instruction. If the value is NULL, the directive will not be set on the final response. + * + * @param string $directive + * @param int|null $value + * @param int $age + */ + private function storeRelativeAgeDirective($directive, $value, $age) + { + if (null === $value) { + $this->ageDirectives[$directive] = false; + } + + if (false !== $this->ageDirectives[$directive]) { + $value = $value - $age; + $this->ageDirectives[$directive] = null !== $this->ageDirectives[$directive] ? min($this->ageDirectives[$directive], $value) : $value; } - $response->setMaxAge(0); } } diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index c5e351ca3a209..6737caee9e1a0 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -73,11 +73,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '4.2.3'; - const VERSION_ID = 40203; + const VERSION = '4.2.4'; + const VERSION_ID = 40204; const MAJOR_VERSION = 4; const MINOR_VERSION = 2; - const RELEASE_VERSION = 3; + const RELEASE_VERSION = 4; const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '07/2019'; diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php index 6d67a177398c2..22cadf7129528 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php @@ -237,4 +237,233 @@ public function testResponseIsExpirableButNotValidateableWhenMasterResponseCombi $this->assertSame('60', $masterResponse->headers->getCacheControlDirective('s-maxage')); $this->assertFalse($masterResponse->isValidateable()); } + + /** + * @dataProvider cacheControlMergingProvider + */ + public function testCacheControlMerging(array $expects, array $master, array $surrogates) + { + $cacheStrategy = new ResponseCacheStrategy(); + $buildResponse = function ($config) { + $response = new Response(); + + foreach ($config as $key => $value) { + switch ($key) { + case 'age': + $response->headers->set('Age', $value); + break; + + case 'expires': + $expires = clone $response->getDate(); + $expires->modify('+'.$value.' seconds'); + $response->setExpires($expires); + break; + + case 'max-age': + $response->setMaxAge($value); + break; + + case 's-maxage': + $response->setSharedMaxAge($value); + break; + + case 'private': + $response->setPrivate(); + break; + + case 'public': + $response->setPublic(); + break; + + default: + $response->headers->addCacheControlDirective($key, $value); + } + } + + return $response; + }; + + foreach ($surrogates as $config) { + $cacheStrategy->add($buildResponse($config)); + } + + $response = $buildResponse($master); + $cacheStrategy->update($response); + + foreach ($expects as $key => $value) { + if ('expires' === $key) { + $this->assertSame($value, $response->getExpires()->format('U') - $response->getDate()->format('U')); + } elseif ('age' === $key) { + $this->assertSame($value, $response->getAge()); + } elseif (true === $value) { + $this->assertTrue($response->headers->hasCacheControlDirective($key), sprintf('Cache-Control header must have "%s" flag', $key)); + } elseif (false === $value) { + $this->assertFalse( + $response->headers->hasCacheControlDirective($key), + sprintf('Cache-Control header must NOT have "%s" flag', $key) + ); + } else { + $this->assertSame($value, $response->headers->getCacheControlDirective($key), sprintf('Cache-Control flag "%s" should be "%s"', $key, $value)); + } + } + } + + public function cacheControlMergingProvider() + { + yield 'result is public if all responses are public' => [ + ['private' => false, 'public' => true], + ['public' => true], + [ + ['public' => true], + ], + ]; + + yield 'result is private by default' => [ + ['private' => true, 'public' => false], + ['public' => true], + [ + [], + ], + ]; + + yield 'combines public and private responses' => [ + ['must-revalidate' => false, 'private' => true, 'public' => false], + ['public' => true], + [ + ['private' => true], + ], + ]; + + yield 'inherits no-cache from surrogates' => [ + ['no-cache' => true, 'public' => false], + ['public' => true], + [ + ['no-cache' => true], + ], + ]; + + yield 'inherits no-store from surrogate' => [ + ['no-store' => true, 'public' => false], + ['public' => true], + [ + ['no-store' => true], + ], + ]; + + yield 'resolve to lowest possible max-age' => [ + ['public' => false, 'private' => true, 's-maxage' => false, 'max-age' => '60'], + ['public' => true, 'max-age' => 3600], + [ + ['private' => true, 'max-age' => 60], + ], + ]; + + yield 'resolves multiple max-age' => [ + ['public' => false, 'private' => true, 's-maxage' => false, 'max-age' => '60'], + ['private' => true, 'max-age' => 100], + [ + ['private' => true, 'max-age' => 3600], + ['public' => true, 'max-age' => 60, 's-maxage' => 60], + ['private' => true, 'max-age' => 60], + ], + ]; + + yield 'merge max-age and s-maxage' => [ + ['public' => true, 's-maxage' => '60', 'max-age' => null], + ['public' => true, 's-maxage' => 3600], + [ + ['public' => true, 'max-age' => 60], + ], + ]; + + yield 'result is private when combining private responses' => [ + ['no-cache' => false, 'must-revalidate' => false, 'private' => true], + ['s-maxage' => 60, 'private' => true], + [ + ['s-maxage' => 60, 'private' => true], + ], + ]; + + yield 'result can have s-maxage and max-age' => [ + ['public' => true, 'private' => false, 's-maxage' => '60', 'max-age' => '30'], + ['s-maxage' => 100, 'max-age' => 2000], + [ + ['s-maxage' => 1000, 'max-age' => 30], + ['s-maxage' => 500, 'max-age' => 500], + ['s-maxage' => 60, 'max-age' => 1000], + ], + ]; + + yield 'does not set headers without value' => [ + ['max-age' => null, 's-maxage' => null, 'public' => null], + ['private' => true], + [ + ['private' => true], + ], + ]; + + yield 'max-age 0 is sent to the client' => [ + ['private' => true, 'max-age' => '0'], + ['max-age' => 0, 'private' => true], + [ + ['max-age' => 60, 'private' => true], + ], + ]; + + yield 'max-age is relative to age' => [ + ['max-age' => '240', 'age' => 60], + ['max-age' => 180], + [ + ['max-age' => 600, 'age' => 60], + ], + ]; + + yield 'retains lowest age of all responses' => [ + ['max-age' => '160', 'age' => 60], + ['max-age' => 600, 'age' => 60], + [ + ['max-age' => 120, 'age' => 20], + ], + ]; + + yield 'max-age can be less than age, essentially expiring the response' => [ + ['age' => 120, 'max-age' => '90'], + ['max-age' => 90, 'age' => 120], + [ + ['max-age' => 120, 'age' => 60], + ], + ]; + + yield 'max-age is 0 regardless of age' => [ + ['max-age' => '0'], + ['max-age' => 60], + [ + ['max-age' => 0, 'age' => 60], + ], + ]; + + yield 'max-age is not negative' => [ + ['max-age' => '0'], + ['max-age' => 0], + [ + ['max-age' => 0, 'age' => 60], + ], + ]; + + yield 'calculates lowest Expires header' => [ + ['expires' => 60], + ['expires' => 60], + [ + ['expires' => 120], + ], + ]; + + yield 'calculates Expires header relative to age' => [ + ['expires' => 210, 'age' => 120], + ['expires' => 90], + [ + ['expires' => 600, 'age' => '120'], + ], + ]; + } } diff --git a/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php index d1fc3c01e0559..84940e63ae92e 100644 --- a/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php +++ b/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php @@ -164,7 +164,7 @@ private function generateLocaleName($locale, $displayLocale) // the name sorting // $name = $this->langBundle->getLanguageName($displayLocale, $lang, $region); - // Some languages are simply not translated + // Some languages are not translated // Example: "az" (Azerbaijani) has no translation in "af" (Afrikaans) if (null === ($name = $this->languageDataProvider->getName($lang, $displayLocale))) { return; diff --git a/src/Symfony/Component/Intl/Data/Util/RecursiveArrayAccess.php b/src/Symfony/Component/Intl/Data/Util/RecursiveArrayAccess.php index c133932c9e6ff..09dd551dafa5e 100644 --- a/src/Symfony/Component/Intl/Data/Util/RecursiveArrayAccess.php +++ b/src/Symfony/Component/Intl/Data/Util/RecursiveArrayAccess.php @@ -25,7 +25,7 @@ public static function get($array, array $indices) foreach ($indices as $index) { // Use array_key_exists() for arrays, isset() otherwise if (\is_array($array)) { - if (array_key_exists($index, $array)) { + if (\array_key_exists($index, $array)) { $array = $array[$index]; continue; } diff --git a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php index d3979fabff4a1..c668d9a3c13ca 100644 --- a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php +++ b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php @@ -460,7 +460,7 @@ public function getPattern() */ public function getSymbol($attr) { - return array_key_exists($this->style, self::$enSymbols) && array_key_exists($attr, self::$enSymbols[$this->style]) ? self::$enSymbols[$this->style][$attr] : false; + return \array_key_exists($this->style, self::$enSymbols) && \array_key_exists($attr, self::$enSymbols[$this->style]) ? self::$enSymbols[$this->style][$attr] : false; } /** @@ -474,7 +474,7 @@ public function getSymbol($attr) */ public function getTextAttribute($attr) { - return array_key_exists($this->style, self::$enTextAttributes) && array_key_exists($attr, self::$enTextAttributes[$this->style]) ? self::$enTextAttributes[$this->style][$attr] : false; + return \array_key_exists($this->style, self::$enTextAttributes) && \array_key_exists($attr, self::$enTextAttributes[$this->style]) ? self::$enTextAttributes[$this->style][$attr] : false; } /** @@ -484,7 +484,7 @@ public function getTextAttribute($attr) * @param string $currency Parameter to receive the currency name (reference) * @param int $position Offset to begin the parsing on return this value will hold the offset at which the parsing ended * - * @return bool|string The parsed numeric value of false on error + * @return bool|string The parsed numeric value or false on error * * @see http://www.php.net/manual/en/numberformatter.parsecurrency.php * @@ -502,7 +502,7 @@ public function parseCurrency($value, &$currency, &$position = null) * @param int $type Type of the formatting, one of the format type constants. NumberFormatter::TYPE_DOUBLE by default. * @param int $position Offset to begin the parsing on return this value will hold the offset at which the parsing ended * - * @return int|float|false The parsed value of false on error + * @return int|float|false The parsed value or false on error * * @see http://www.php.net/manual/en/numberformatter.parse.php */ diff --git a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php index cffc49df29c78..19415c7aede7c 100644 --- a/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/AmqpExt/Connection.php @@ -110,7 +110,7 @@ public static function fromDsn(string $dsn, array $options = [], bool $debug = f private static function normalizeQueueArguments(array $arguments): array { foreach (self::ARGUMENTS_AS_INTEGER as $key) { - if (!array_key_exists($key, $arguments)) { + if (!\array_key_exists($key, $arguments)) { continue; } @@ -253,6 +253,6 @@ private function clear(): void private function shouldSetup(): bool { - return !array_key_exists('auto-setup', $this->connectionCredentials) || !\in_array($this->connectionCredentials['auto-setup'], [false, 'false'], true); + return !\array_key_exists('auto-setup', $this->connectionCredentials) || !\in_array($this->connectionCredentials['auto-setup'], [false, 'false'], true); } } diff --git a/src/Symfony/Component/OptionsResolver/Debug/OptionsResolverIntrospector.php b/src/Symfony/Component/OptionsResolver/Debug/OptionsResolverIntrospector.php index 3867447a30ecb..ccce082fed29d 100644 --- a/src/Symfony/Component/OptionsResolver/Debug/OptionsResolverIntrospector.php +++ b/src/Symfony/Component/OptionsResolver/Debug/OptionsResolverIntrospector.php @@ -32,7 +32,7 @@ public function __construct(OptionsResolver $optionsResolver) throw new UndefinedOptionsException(sprintf('The option "%s" does not exist.', $option)); } - if (!array_key_exists($option, $this->{$property})) { + if (!\array_key_exists($option, $this->{$property})) { throw new NoConfigurationException($message); } diff --git a/src/Symfony/Component/OptionsResolver/OptionsResolver.php b/src/Symfony/Component/OptionsResolver/OptionsResolver.php index 6532fe0a0ab8d..eb0a6c2480601 100644 --- a/src/Symfony/Component/OptionsResolver/OptionsResolver.php +++ b/src/Symfony/Component/OptionsResolver/OptionsResolver.php @@ -219,7 +219,7 @@ public function setDefault($option, $value) // to resolve options with lazy closures, normalizers or validation // rules, none of which can exist for undefined options // If the option was resolved before, update the resolved value - if (!isset($this->defined[$option]) || array_key_exists($option, $this->resolved)) { + if (!isset($this->defined[$option]) || \array_key_exists($option, $this->resolved)) { $this->resolved[$option] = $value; } @@ -259,7 +259,7 @@ public function setDefaults(array $defaults) */ public function hasDefault($option) { - return array_key_exists($option, $this->defaults); + return \array_key_exists($option, $this->defaults); } /** @@ -324,7 +324,7 @@ public function getRequiredOptions() */ public function isMissing($option) { - return isset($this->required[$option]) && !array_key_exists($option, $this->defaults); + return isset($this->required[$option]) && !\array_key_exists($option, $this->defaults); } /** @@ -800,7 +800,7 @@ public function offsetGet($option/*, bool $triggerDeprecation = true*/) $triggerDeprecation = 1 === \func_num_args() || \func_get_arg(1); // Shortcut for resolved options - if (isset($this->resolved[$option]) || array_key_exists($option, $this->resolved)) { + if (isset($this->resolved[$option]) || \array_key_exists($option, $this->resolved)) { if ($triggerDeprecation && isset($this->deprecated[$option]) && (isset($this->given[$option]) || $this->calling) && \is_string($this->deprecated[$option])) { @trigger_error(strtr($this->deprecated[$option], ['%name%' => $option]), E_USER_DEPRECATED); } @@ -809,7 +809,7 @@ public function offsetGet($option/*, bool $triggerDeprecation = true*/) } // Check whether the option is set at all - if (!isset($this->defaults[$option]) && !array_key_exists($option, $this->defaults)) { + if (!isset($this->defaults[$option]) && !\array_key_exists($option, $this->defaults)) { if (!isset($this->defined[$option])) { throw new NoSuchOptionException(sprintf('The option "%s" does not exist. Defined options are: "%s".', $option, implode('", "', array_keys($this->defined)))); } @@ -1033,7 +1033,7 @@ public function offsetExists($option) throw new AccessException('Array access is only supported within closures of lazy options and normalizers.'); } - return array_key_exists($option, $this->defaults); + return \array_key_exists($option, $this->defaults); } /** diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index f063e8f007438..6bf6e210968e6 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -164,7 +164,7 @@ private static function throwInvalidArgumentException($message, $trace, $i, $pro return; } - if (isset($trace[$i]['file']) && __FILE__ === $trace[$i]['file'] && array_key_exists(0, $trace[$i]['args'])) { + if (isset($trace[$i]['file']) && __FILE__ === $trace[$i]['file'] && \array_key_exists(0, $trace[$i]['args'])) { $pos = strpos($message, $delim = 'must be of the type ') ?: (strpos($message, $delim = 'must be an instance of ') ?: strpos($message, $delim = 'must implement interface ')); $pos += \strlen($delim); $type = $trace[$i]['args'][0]; @@ -266,7 +266,7 @@ private function readPropertiesUntil($zval, PropertyPathInterface $propertyPath, if ($isIndex) { // Create missing nested arrays on demand if (($zval[self::VALUE] instanceof \ArrayAccess && !$zval[self::VALUE]->offsetExists($property)) || - (\is_array($zval[self::VALUE]) && !isset($zval[self::VALUE][$property]) && !array_key_exists($property, $zval[self::VALUE])) + (\is_array($zval[self::VALUE]) && !isset($zval[self::VALUE][$property]) && !\array_key_exists($property, $zval[self::VALUE])) ) { if (!$ignoreInvalidIndices) { if (!\is_array($zval[self::VALUE])) { diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/NonTraversableArrayObject.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/NonTraversableArrayObject.php index 4852e8d58ff98..4b18e725ae9e4 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/NonTraversableArrayObject.php +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/NonTraversableArrayObject.php @@ -26,7 +26,7 @@ public function __construct(array $array = null) public function offsetExists($offset) { - return array_key_exists($offset, $this->array); + return \array_key_exists($offset, $this->array); } public function offsetGet($offset) diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TraversableArrayObject.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TraversableArrayObject.php index 9803a11f848fc..b075286f4a70e 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TraversableArrayObject.php +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TraversableArrayObject.php @@ -26,7 +26,7 @@ public function __construct(array $array = null) public function offsetExists($offset) { - return array_key_exists($offset, $this->array); + return \array_key_exists($offset, $this->array); } public function offsetGet($offset) diff --git a/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php b/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php index ac883e7c042a0..0eb9f63a54856 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php +++ b/src/Symfony/Component/PropertyInfo/PropertyInfoCacheExtractor.php @@ -105,7 +105,7 @@ private function extract(string $method, array $arguments) // Calling rawurlencode escapes special characters not allowed in PSR-6's keys $key = rawurlencode($method.'.'.$serializedArguments); - if (array_key_exists($key, $this->arrayCache)) { + if (\array_key_exists($key, $this->arrayCache)) { return $this->arrayCache[$key]; } diff --git a/src/Symfony/Component/Routing/Generator/UrlGenerator.php b/src/Symfony/Component/Routing/Generator/UrlGenerator.php index fab14ca366373..1bc720bbbaadb 100644 --- a/src/Symfony/Component/Routing/Generator/UrlGenerator.php +++ b/src/Symfony/Component/Routing/Generator/UrlGenerator.php @@ -156,9 +156,9 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa $message = 'Parameter "{parameter}" for route "{route}" must match "{expected}" ("{given}" given) to generate a corresponding URL.'; foreach ($tokens as $token) { if ('variable' === $token[0]) { - if (!$optional || !array_key_exists($token[3], $defaults) || null !== $mergedParams[$token[3]] && (string) $mergedParams[$token[3]] !== (string) $defaults[$token[3]]) { - // check requirement - if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#'.(empty($token[4]) ? '' : 'u'), $mergedParams[$token[3]])) { + if (!$optional || !\array_key_exists($token[3], $defaults) || null !== $mergedParams[$token[3]] && (string) $mergedParams[$token[3]] !== (string) $defaults[$token[3]]) { + // check requirement (while ignoring look-around patterns) + if (null !== $this->strictRequirements && !preg_match('#^'.preg_replace('/\(\?(?:=|<=|!|strictRequirements) { throw new InvalidParameterException(strtr($message, ['{parameter}' => $token[3], '{route}' => $name, '{expected}' => $token[2], '{given}' => $mergedParams[$token[3]]])); } @@ -212,7 +212,8 @@ protected function doGenerate($variables, $defaults, $requirements, $tokens, $pa $routeHost = ''; foreach ($hostTokens as $token) { if ('variable' === $token[0]) { - if (null !== $this->strictRequirements && !preg_match('#^'.$token[2].'$#i'.(empty($token[4]) ? '' : 'u'), $mergedParams[$token[3]])) { + // check requirement (while ignoring look-around patterns) + if (null !== $this->strictRequirements && !preg_match('#^'.preg_replace('/\(\?(?:=|<=|!|strictRequirements) { throw new InvalidParameterException(strtr($message, ['{parameter}' => $token[3], '{route}' => $name, '{expected}' => $token[2], '{given}' => $mergedParams[$token[3]]])); } diff --git a/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php b/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php index 61b2ed320a223..754e903d89ed0 100644 --- a/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php +++ b/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php @@ -159,6 +159,7 @@ private function groupStaticRoutes(RouteCollection $collection): array foreach ($collection->all() as $name => $route) { $compiledRoute = $route->compile(); + $staticPrefix = rtrim($compiledRoute->getStaticPrefix(), '/'); $hostRegex = $compiledRoute->getHostRegex(); $regex = $compiledRoute->getRegex(); if ($hasTrailingSlash = '/' !== $route->getPath()) { @@ -173,9 +174,9 @@ private function groupStaticRoutes(RouteCollection $collection): array if ($hasTrailingSlash) { $url = substr($url, 0, -1); } - foreach ($dynamicRegex as list($hostRx, $rx)) { - if (preg_match($rx, $url) && (!$host || !$hostRx || preg_match($hostRx, $host))) { - $dynamicRegex[] = [$hostRegex, $regex]; + foreach ($dynamicRegex as list($hostRx, $rx, $prefix)) { + if (('' === $prefix || 0 === strpos($url, $prefix)) && preg_match($rx, $url) && (!$host || !$hostRx || preg_match($hostRx, $host))) { + $dynamicRegex[] = [$hostRegex, $regex, $staticPrefix]; $dynamicRoutes->add($name, $route); continue 2; } @@ -183,7 +184,7 @@ private function groupStaticRoutes(RouteCollection $collection): array $staticRoutes[$url][$name] = [$route, $hasTrailingSlash]; } else { - $dynamicRegex[] = [$hostRegex, $regex]; + $dynamicRegex[] = [$hostRegex, $regex, $staticPrefix]; $dynamicRoutes->add($name, $route); } } diff --git a/src/Symfony/Component/Routing/RequestContext.php b/src/Symfony/Component/Routing/RequestContext.php index dc3e4be1e7bc4..591dd15938695 100644 --- a/src/Symfony/Component/Routing/RequestContext.php +++ b/src/Symfony/Component/Routing/RequestContext.php @@ -306,7 +306,7 @@ public function getParameter($name) */ public function hasParameter($name) { - return array_key_exists($name, $this->parameters); + return \array_key_exists($name, $this->parameters); } /** diff --git a/src/Symfony/Component/Routing/Route.php b/src/Symfony/Component/Routing/Route.php index 58675902a1c58..4e0463b57578c 100644 --- a/src/Symfony/Component/Routing/Route.php +++ b/src/Symfony/Component/Routing/Route.php @@ -327,7 +327,7 @@ public function getOption($name) */ public function hasOption($name) { - return array_key_exists($name, $this->options); + return \array_key_exists($name, $this->options); } /** @@ -396,7 +396,7 @@ public function getDefault($name) */ public function hasDefault($name) { - return array_key_exists($name, $this->defaults); + return \array_key_exists($name, $this->defaults); } /** @@ -481,7 +481,7 @@ public function getRequirement($key) */ public function hasRequirement($key) { - return array_key_exists($key, $this->requirements); + return \array_key_exists($key, $this->requirements); } /** diff --git a/src/Symfony/Component/Routing/Router.php b/src/Symfony/Component/Routing/Router.php index 5fa85a538acc9..27c32e14ae8c6 100644 --- a/src/Symfony/Component/Routing/Router.php +++ b/src/Symfony/Component/Routing/Router.php @@ -142,7 +142,7 @@ public function setOptions(array $options) // check option names and live merge, if errors are encountered Exception will be thrown $invalid = []; foreach ($options as $key => $value) { - if (array_key_exists($key, $this->options)) { + if (\array_key_exists($key, $this->options)) { $this->options[$key] = $value; } else { $invalid[] = $key; @@ -164,7 +164,7 @@ public function setOptions(array $options) */ public function setOption($key, $value) { - if (!array_key_exists($key, $this->options)) { + if (!\array_key_exists($key, $this->options)) { throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key)); } @@ -182,7 +182,7 @@ public function setOption($key, $value) */ public function getOption($key) { - if (!array_key_exists($key, $this->options)) { + if (!\array_key_exists($key, $this->options)) { throw new \InvalidArgumentException(sprintf('The Router does not support the "%s" option.', $key)); } diff --git a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php index d92161c05c336..7f64a1f378326 100644 --- a/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php +++ b/src/Symfony/Component/Routing/Tests/Generator/UrlGeneratorTest.php @@ -703,6 +703,23 @@ public function testFragmentsCanBeDefinedAsDefaults() $this->assertEquals('/app.php/testing#fragment', $url); } + /** + * @dataProvider provideLookAroundRequirementsInPath + */ + public function testLookRoundRequirementsInPath($expected, $path, $requirement) + { + $routes = $this->getRoutes('test', new Route($path, [], ['foo' => $requirement, 'baz' => '.+?'])); + $this->assertSame($expected, $this->getGenerator($routes)->generate('test', ['foo' => 'a/b', 'baz' => 'c/d/e'])); + } + + public function provideLookAroundRequirementsInPath() + { + yield ['/app.php/a/b/b%28ar/c/d/e', '/{foo}/b(ar/{baz}', '.+(?=/b\\(ar/)']; + yield ['/app.php/a/b/bar/c/d/e', '/{foo}/bar/{baz}', '.+(?!$)']; + yield ['/app.php/bar/a/b/bam/c/d/e', '/bar/{foo}/bam/{baz}', '(?<=/bar/).+']; + yield ['/app.php/bar/a/b/bam/c/d/e', '/bar/{foo}/bam/{baz}', '(?attributes); + return \array_key_exists($name, $this->attributes); } /** @@ -192,7 +192,7 @@ public function hasAttribute($name) */ public function getAttribute($name) { - if (!array_key_exists($name, $this->attributes)) { + if (!\array_key_exists($name, $this->attributes)) { throw new \InvalidArgumentException(sprintf('This token has no "%s" attribute.', $name)); } diff --git a/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php b/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php index 058085e349c95..8509844f9a17b 100644 --- a/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php +++ b/src/Symfony/Component/Security/Core/Authorization/AccessDecisionManager.php @@ -42,7 +42,7 @@ class AccessDecisionManager implements AccessDecisionManagerInterface public function __construct(iterable $voters = [], string $strategy = self::STRATEGY_AFFIRMATIVE, bool $allowIfAllAbstainDecisions = false, bool $allowIfEqualGrantedDeniedDecisions = true) { $strategyMethod = 'decide'.ucfirst($strategy); - if (!\is_callable([$this, $strategyMethod])) { + if ('' === $strategy || !\is_callable([$this, $strategyMethod])) { throw new \InvalidArgumentException(sprintf('The strategy "%s" is not supported.', $strategy)); } diff --git a/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php b/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php index a774d7e11c777..8695ba3401d72 100644 --- a/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php +++ b/src/Symfony/Component/Security/Core/Encoder/EncoderFactory.php @@ -33,7 +33,7 @@ public function getEncoder($user) $encoderKey = null; if ($user instanceof EncoderAwareInterface && (null !== $encoderName = $user->getEncoderName())) { - if (!array_key_exists($encoderName, $this->encoders)) { + if (!\array_key_exists($encoderName, $this->encoders)) { throw new \RuntimeException(sprintf('The encoder "%s" was not configured.', $encoderName)); } diff --git a/src/Symfony/Component/Security/Guard/composer.json b/src/Symfony/Component/Security/Guard/composer.json index 982b16f012a32..0547bed04ad39 100644 --- a/src/Symfony/Component/Security/Guard/composer.json +++ b/src/Symfony/Component/Security/Guard/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": "^7.1.3", - "symfony/security-core": "~3.4|~4.0", + "symfony/security-core": "~3.4.22|^4.2.3", "symfony/security-http": "~3.4|~4.0" }, "require-dev": { diff --git a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php index f6fd0c1ec405f..a8ccee0f7d557 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SimpleFormAuthenticationListener.php @@ -97,7 +97,7 @@ protected function attemptAuthentication(Request $request) $password = ParameterBagUtils::getRequestParameterValue($request, $this->options['password_parameter']); } - if (!\is_string($username) || (\is_object($username) && !\method_exists($username, '__toString'))) { + if (!\is_string($username) && (!\is_object($username) || !\method_exists($username, '__toString'))) { throw new BadRequestHttpException(sprintf('The key "%s" must be a string, "%s" given.', $this->options['username_parameter'], \gettype($username))); } diff --git a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php index 80082b0099c78..4aff3b45811fa 100644 --- a/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/SwitchUserListener.php @@ -83,6 +83,10 @@ public function handle(GetResponseEvent $event) return; } + if (null === $this->tokenStorage->getToken()) { + throw new AuthenticationCredentialsNotFoundException('Could not find original Token object.'); + } + if (self::EXIT_VALUE === $username) { $this->tokenStorage->setToken($this->attemptExitUser($request)); } else { @@ -165,7 +169,7 @@ private function attemptSwitchUser(Request $request, $username) */ private function attemptExitUser(Request $request) { - if (null === ($currentToken = $this->tokenStorage->getToken()) || false === $original = $this->getOriginalToken($currentToken)) { + if (false === $original = $this->getOriginalToken($this->tokenStorage->getToken())) { throw new AuthenticationCredentialsNotFoundException('Could not find original Token object.'); } diff --git a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php index f6ce869b299d1..2b8ab8d09f578 100644 --- a/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/UsernamePasswordFormAuthenticationListener.php @@ -85,7 +85,7 @@ protected function attemptAuthentication(Request $request) $password = ParameterBagUtils::getRequestParameterValue($request, $this->options['password_parameter']); } - if (!\is_string($username) || (\is_object($username) && !\method_exists($username, '__toString'))) { + if (!\is_string($username) && (!\is_object($username) || !\method_exists($username, '__toString'))) { throw new BadRequestHttpException(sprintf('The key "%s" must be a string, "%s" given.', $this->options['username_parameter'], \gettype($username))); } diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php index 2be2cc220763e..f26b72fc148e1 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/SwitchUserListenerTest.php @@ -267,6 +267,17 @@ public function testSwitchUserWithReplacedToken() $this->assertSame($replacedToken, $this->tokenStorage->getToken()); } + /** + * @expectedException \Symfony\Component\Security\Core\Exception\AuthenticationCredentialsNotFoundException + */ + public function testSwitchtUserThrowsAuthenticationExceptionIfNoCurrentToken() + { + $this->tokenStorage->setToken(null); + $this->request->query->set('_switch_user', 'username'); + $listener = new SwitchUserListener($this->tokenStorage, $this->userProvider, $this->userChecker, 'provider123', $this->accessDecisionManager); + $listener->handle($this->event); + } + public function testSwitchUserStateless() { $token = new UsernamePasswordToken('username', '', 'key', ['ROLE_FOO']); diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php index 198ee6566dfdd..f1536db6d25a6 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/UsernamePasswordFormAuthenticationListenerTest.php @@ -81,7 +81,7 @@ public function testHandleWhenUsernameLength($username, $ok) * @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException * @expectedExceptionMessage The key "_username" must be a string, "array" given. */ - public function testHandleNonStringUsername($postOnly) + public function testHandleNonStringUsernameWithArray($postOnly) { $request = Request::create('/login_check', 'POST', ['_username' => []]); $request->setSession($this->getMockBuilder('Symfony\Component\HttpFoundation\Session\SessionInterface')->getMock()); @@ -99,6 +99,79 @@ public function testHandleNonStringUsername($postOnly) $listener->handle($event); } + /** + * @dataProvider postOnlyDataProvider + * @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException + * @expectedExceptionMessage The key "_username" must be a string, "integer" given. + */ + public function testHandleNonStringUsernameWithInt($postOnly) + { + $request = Request::create('/login_check', 'POST', ['_username' => 42]); + $request->setSession($this->getMockBuilder('Symfony\Component\HttpFoundation\Session\SessionInterface')->getMock()); + $listener = new UsernamePasswordFormAuthenticationListener( + new TokenStorage(), + $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface')->getMock(), + new SessionAuthenticationStrategy(SessionAuthenticationStrategy::NONE), + $httpUtils = new HttpUtils(), + 'foo', + new DefaultAuthenticationSuccessHandler($httpUtils), + new DefaultAuthenticationFailureHandler($this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(), $httpUtils), + ['require_previous_session' => false, 'post_only' => $postOnly] + ); + $event = new GetResponseEvent($this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(), $request, HttpKernelInterface::MASTER_REQUEST); + $listener->handle($event); + } + + /** + * @dataProvider postOnlyDataProvider + * @expectedException \Symfony\Component\HttpKernel\Exception\BadRequestHttpException + * @expectedExceptionMessage The key "_username" must be a string, "object" given. + */ + public function testHandleNonStringUsernameWithObject($postOnly) + { + $request = Request::create('/login_check', 'POST', ['_username' => new \stdClass()]); + $request->setSession($this->getMockBuilder('Symfony\Component\HttpFoundation\Session\SessionInterface')->getMock()); + $listener = new UsernamePasswordFormAuthenticationListener( + new TokenStorage(), + $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface')->getMock(), + new SessionAuthenticationStrategy(SessionAuthenticationStrategy::NONE), + $httpUtils = new HttpUtils(), + 'foo', + new DefaultAuthenticationSuccessHandler($httpUtils), + new DefaultAuthenticationFailureHandler($this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(), $httpUtils), + ['require_previous_session' => false, 'post_only' => $postOnly] + ); + $event = new GetResponseEvent($this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(), $request, HttpKernelInterface::MASTER_REQUEST); + $listener->handle($event); + } + + /** + * @dataProvider postOnlyDataProvider + */ + public function testHandleNonStringUsernameWith__toString($postOnly) + { + $usernameClass = $this->getMockBuilder(DummyUserClass::class)->getMock(); + $usernameClass + ->expects($this->atLeastOnce()) + ->method('__toString') + ->will($this->returnValue('someUsername')); + + $request = Request::create('/login_check', 'POST', ['_username' => $usernameClass]); + $request->setSession($this->getMockBuilder('Symfony\Component\HttpFoundation\Session\SessionInterface')->getMock()); + $listener = new UsernamePasswordFormAuthenticationListener( + new TokenStorage(), + $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface')->getMock(), + new SessionAuthenticationStrategy(SessionAuthenticationStrategy::NONE), + $httpUtils = new HttpUtils(), + 'foo', + new DefaultAuthenticationSuccessHandler($httpUtils), + new DefaultAuthenticationFailureHandler($this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(), $httpUtils), + ['require_previous_session' => false, 'post_only' => $postOnly] + ); + $event = new GetResponseEvent($this->getMockBuilder('Symfony\Component\HttpKernel\HttpKernelInterface')->getMock(), $request, HttpKernelInterface::MASTER_REQUEST); + $listener->handle($event); + } + public function postOnlyDataProvider() { return [ @@ -115,3 +188,11 @@ public function getUsernameForLength() ]; } } + +class DummyUserClass +{ + public function __toString() + { + return ''; + } +} diff --git a/src/Symfony/Component/Serializer/Mapping/ClassDiscriminatorFromClassMetadata.php b/src/Symfony/Component/Serializer/Mapping/ClassDiscriminatorFromClassMetadata.php index 1178f03cfb9cc..23554ffda98ab 100644 --- a/src/Symfony/Component/Serializer/Mapping/ClassDiscriminatorFromClassMetadata.php +++ b/src/Symfony/Component/Serializer/Mapping/ClassDiscriminatorFromClassMetadata.php @@ -55,7 +55,7 @@ public function getMappingForMappedObject($object): ?ClassDiscriminatorMapping } $cacheKey = \is_object($object) ? \get_class($object) : $object; - if (!array_key_exists($cacheKey, $this->mappingForMappedObjectCache)) { + if (!\array_key_exists($cacheKey, $this->mappingForMappedObjectCache)) { $this->mappingForMappedObjectCache[$cacheKey] = $this->resolveMappingForMappedObject($object); } diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index 300c7f1b3c681..e1f5d136dd17e 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -398,14 +398,14 @@ protected function instantiateObject(array &$data, $class, array &$context, \Ref $allowed = false === $allowedAttributes || \in_array($paramName, $allowedAttributes); $ignored = !$this->isAllowedAttribute($class, $paramName, $format, $context); if ($constructorParameter->isVariadic()) { - if ($allowed && !$ignored && (isset($data[$key]) || array_key_exists($key, $data))) { + if ($allowed && !$ignored && (isset($data[$key]) || \array_key_exists($key, $data))) { if (!\is_array($data[$paramName])) { throw new RuntimeException(sprintf('Cannot create an instance of %s from serialized data because the variadic parameter %s can only accept an array.', $class, $constructorParameter->name)); } $params = array_merge($params, $data[$paramName]); } - } elseif ($allowed && !$ignored && (isset($data[$key]) || array_key_exists($key, $data))) { + } elseif ($allowed && !$ignored && (isset($data[$key]) || \array_key_exists($key, $data))) { $parameterData = $data[$key]; if (null === $parameterData && $constructorParameter->allowsNull()) { $params[] = null; @@ -417,9 +417,9 @@ protected function instantiateObject(array &$data, $class, array &$context, \Ref // Don't run set for a parameter passed to the constructor $params[] = $this->denormalizeParameter($reflectionClass, $constructorParameter, $paramName, $parameterData, $context, $format); unset($data[$key]); - } elseif (array_key_exists($key, $context[static::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class] ?? [])) { + } elseif (\array_key_exists($key, $context[static::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class] ?? [])) { $params[] = $context[static::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class][$key]; - } elseif (array_key_exists($key, $this->defaultContext[self::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class] ?? [])) { + } elseif (\array_key_exists($key, $this->defaultContext[self::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class] ?? [])) { $params[] = $this->defaultContext[self::DEFAULT_CONSTRUCTOR_ARGUMENTS][$class][$key]; } elseif ($constructorParameter->isDefaultValueAvailable()) { $params[] = $constructorParameter->getDefaultValue(); diff --git a/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php index d3de806e186aa..51ad59a7e782e 100644 --- a/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php @@ -157,6 +157,7 @@ private function formatDateTimeErrors(array $errors) private function getTimezone(array $context) { $dateTimeZone = $context[self::TIMEZONE_KEY] ?? $this->defaultContext[self::TIMEZONE_KEY]; + if (null === $dateTimeZone) { return null; } diff --git a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php index 530f168c6a7b5..94ed6d8b6394d 100644 --- a/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/ObjectNormalizer.php @@ -113,7 +113,7 @@ protected function extractAttributes($object, $format = null, array $context = [ protected function getAttributeValue($object, $attribute, $format = null, array $context = []) { $cacheKey = \get_class($object); - if (!array_key_exists($cacheKey, $this->discriminatorCache)) { + if (!\array_key_exists($cacheKey, $this->discriminatorCache)) { $this->discriminatorCache[$cacheKey] = null; if (null !== $this->classDiscriminatorResolver) { $mapping = $this->classDiscriminatorResolver->getMappingForMappedObject($object); diff --git a/src/Symfony/Component/Templating/TemplateReference.php b/src/Symfony/Component/Templating/TemplateReference.php index 18c6bda2df2b3..ddff4db857654 100644 --- a/src/Symfony/Component/Templating/TemplateReference.php +++ b/src/Symfony/Component/Templating/TemplateReference.php @@ -41,7 +41,7 @@ public function __toString() */ public function set($name, $value) { - if (array_key_exists($name, $this->parameters)) { + if (\array_key_exists($name, $this->parameters)) { $this->parameters[$name] = $value; } else { throw new \InvalidArgumentException(sprintf('The template does not support the "%s" parameter.', $name)); @@ -55,7 +55,7 @@ public function set($name, $value) */ public function get($name) { - if (array_key_exists($name, $this->parameters)) { + if (\array_key_exists($name, $this->parameters)) { return $this->parameters[$name]; } diff --git a/src/Symfony/Component/Translation/DataCollector/TranslationDataCollector.php b/src/Symfony/Component/Translation/DataCollector/TranslationDataCollector.php old mode 100755 new mode 100644 diff --git a/src/Symfony/Component/Translation/Dumper/FileDumper.php b/src/Symfony/Component/Translation/Dumper/FileDumper.php index 57ce9d21414ef..8457ecc7ecd7a 100644 --- a/src/Symfony/Component/Translation/Dumper/FileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/FileDumper.php @@ -63,7 +63,7 @@ public function setBackup($backup) */ public function dump(MessageCatalogue $messages, $options = []) { - if (!array_key_exists('path', $options)) { + if (!\array_key_exists('path', $options)) { throw new InvalidArgumentException('The file dumper needs a path option.'); } diff --git a/src/Symfony/Component/Translation/Dumper/XliffFileDumper.php b/src/Symfony/Component/Translation/Dumper/XliffFileDumper.php index 8ee8d5a009a1f..8d2694f24e2d2 100644 --- a/src/Symfony/Component/Translation/Dumper/XliffFileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/XliffFileDumper.php @@ -27,11 +27,11 @@ class XliffFileDumper extends FileDumper public function formatCatalogue(MessageCatalogue $messages, $domain, array $options = []) { $xliffVersion = '1.2'; - if (array_key_exists('xliff_version', $options)) { + if (\array_key_exists('xliff_version', $options)) { $xliffVersion = $options['xliff_version']; } - if (array_key_exists('default_locale', $options)) { + if (\array_key_exists('default_locale', $options)) { $defaultLocale = $options['default_locale']; } else { $defaultLocale = \Locale::getDefault(); @@ -58,7 +58,7 @@ protected function getExtension() private function dumpXliff1($defaultLocale, MessageCatalogue $messages, $domain, array $options = []) { $toolInfo = ['tool-id' => 'symfony', 'tool-name' => 'Symfony']; - if (array_key_exists('tool_info', $options)) { + if (\array_key_exists('tool_info', $options)) { $toolInfo = array_merge($toolInfo, $options['tool_info']); } @@ -141,7 +141,11 @@ private function dumpXliff2($defaultLocale, MessageCatalogue $messages, $domain, $xliff->setAttribute('trgLang', str_replace('_', '-', $messages->getLocale())); $xliffFile = $xliff->appendChild($dom->createElement('file')); - $xliffFile->setAttribute('id', $domain.'.'.$messages->getLocale()); + if (MessageCatalogue::INTL_DOMAIN_SUFFIX === substr($domain, -($suffixLength = \strlen(MessageCatalogue::INTL_DOMAIN_SUFFIX)))) { + $xliffFile->setAttribute('id', substr($domain, 0, -$suffixLength).'.'.$messages->getLocale()); + } else { + $xliffFile->setAttribute('id', $domain.'.'.$messages->getLocale()); + } foreach ($messages->all($domain) as $source => $target) { $translation = $dom->createElement('unit'); @@ -200,6 +204,6 @@ private function dumpXliff2($defaultLocale, MessageCatalogue $messages, $domain, */ private function hasMetadataArrayInfo($key, $metadata = null) { - return null !== $metadata && array_key_exists($key, $metadata) && ($metadata[$key] instanceof \Traversable || \is_array($metadata[$key])); + return null !== $metadata && \array_key_exists($key, $metadata) && ($metadata[$key] instanceof \Traversable || \is_array($metadata[$key])); } } diff --git a/src/Symfony/Component/Translation/Resources/bin/translation-status.php b/src/Symfony/Component/Translation/Resources/bin/translation-status.php new file mode 100644 index 0000000000000..acc8b4e227222 --- /dev/null +++ b/src/Symfony/Component/Translation/Resources/bin/translation-status.php @@ -0,0 +1,195 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +$usageInstructions = << false, + // NULL = analyze all locales + 'locale_to_analyze' => null, + // the reference files all the other translations are compared to + 'original_files' => [ + 'src/Symfony/Component/Form/Resources/translations/validators.en.xlf', + 'src/Symfony/Component/Security/Core/Resources/translations/security.en.xlf', + 'src/Symfony/Component/Validator/Resources/translations/validators.en.xlf', + ], +]; + +$argc = $_SERVER['argc']; +$argv = $_SERVER['argv']; + +if ($argc > 3) { + echo str_replace('translation-status.php', $argv[0], $usageInstructions); + exit(1); +} + +foreach (array_slice($argv, 1) as $argumentOrOption) { + if (0 === strpos($argumentOrOption, '-')) { + $config['verbose_output'] = true; + } else { + $config['locale_to_analyze'] = $argumentOrOption; + } +} + +foreach ($config['original_files'] as $originalFilePath) { + if (!file_exists($originalFilePath)) { + echo sprintf('The following file does not exist. Make sure that you execute this command at the root dir of the Symfony code repository.%s %s', PHP_EOL, $originalFilePath); + exit(1); + } +} + +$totalMissingTranslations = 0; + +foreach ($config['original_files'] as $originalFilePath) { + $translationFilePaths = findTranslationFiles($originalFilePath, $config['locale_to_analyze']); + $translationStatus = calculateTranslationStatus($originalFilePath, $translationFilePaths); + + $totalMissingTranslations += array_sum(array_map(function ($translation) { + return \count($translation['missingKeys']); + }, array_values($translationStatus))); + + printTranslationStatus($originalFilePath, $translationStatus, $config['verbose_output']); +} + +exit($totalMissingTranslations > 0 ? 1 : 0); + +function findTranslationFiles($originalFilePath, $localeToAnalyze) +{ + $translations = []; + + $translationsDir = dirname($originalFilePath); + $originalFileName = basename($originalFilePath); + $translationFileNamePattern = str_replace('.en.', '.*.', $originalFileName); + + $translationFiles = glob($translationsDir.'/'.$translationFileNamePattern); + foreach ($translationFiles as $filePath) { + $locale = extractLocaleFromFilePath($filePath); + + if (null !== $localeToAnalyze && $locale !== $localeToAnalyze) { + continue; + } + + $translations[$locale] = $filePath; + } + + return $translations; +} + +function calculateTranslationStatus($originalFilePath, $translationFilePaths) +{ + $translationStatus = []; + $allTranslationKeys = extractTranslationKeys($originalFilePath); + + foreach ($translationFilePaths as $locale => $translationPath) { + $translatedKeys = extractTranslationKeys($translationPath); + $missingKeys = array_diff_key($allTranslationKeys, $translatedKeys); + + $translationStatus[$locale] = [ + 'total' => \count($allTranslationKeys), + 'translated' => \count($translatedKeys), + 'missingKeys' => $missingKeys, + ]; + } + + return $translationStatus; +} + +function printTranslationStatus($originalFilePath, $translationStatus, $verboseOutput) +{ + printTitle($originalFilePath); + printTable($translationStatus, $verboseOutput); + echo PHP_EOL.PHP_EOL; +} + +function extractLocaleFromFilePath($filePath) +{ + $parts = explode('.', $filePath); + + return $parts[count($parts) - 2]; +} + +function extractTranslationKeys($filePath) +{ + $translationKeys = []; + $contents = new \SimpleXMLElement(file_get_contents($filePath)); + + foreach ($contents->file->body->{'trans-unit'} as $translationKey) { + $translationId = (string) $translationKey['id']; + $translationKey = (string) $translationKey->source; + + $translationKeys[$translationId] = $translationKey; + } + + return $translationKeys; +} + +function printTitle($title) +{ + echo $title.PHP_EOL; + echo str_repeat('=', strlen($title)).PHP_EOL.PHP_EOL; +} + +function printTable($translations, $verboseOutput) +{ + $longestLocaleNameLength = max(array_map('strlen', array_keys($translations))); + + foreach ($translations as $locale => $translation) { + $isTranslationCompleted = $translation['translated'] === $translation['total']; + if ($isTranslationCompleted) { + textColorGreen(); + } + + echo sprintf('| Locale: %-'.$longestLocaleNameLength.'s | Translated: %d/%d', $locale, $translation['translated'], $translation['total']).PHP_EOL; + + textColorNormal(); + + if (true === $verboseOutput && \count($translation['missingKeys']) > 0) { + echo str_repeat('-', 80).PHP_EOL; + echo '| Missing Translations:'.PHP_EOL; + + foreach ($translation['missingKeys'] as $id => $content) { + echo sprintf('| (id=%s) %s', $id, $content).PHP_EOL; + } + + echo str_repeat('-', 80).PHP_EOL; + } + } +} + +function textColorGreen() +{ + echo "\033[32m"; +} + +function textColorNormal() +{ + echo "\033[0m"; +} diff --git a/src/Symfony/Component/Translation/Tests/Dumper/XliffFileDumperTest.php b/src/Symfony/Component/Translation/Tests/Dumper/XliffFileDumperTest.php index c634a27936711..6377132f7009b 100644 --- a/src/Symfony/Component/Translation/Tests/Dumper/XliffFileDumperTest.php +++ b/src/Symfony/Component/Translation/Tests/Dumper/XliffFileDumperTest.php @@ -54,6 +54,21 @@ public function testFormatCatalogueXliff2() ); } + public function testFormatIcuCatalogueXliff2() + { + $catalogue = new MessageCatalogue('en_US'); + $catalogue->add([ + 'foo' => 'bar', + ], 'messages'.MessageCatalogue::INTL_DOMAIN_SUFFIX); + + $dumper = new XliffFileDumper(); + + $this->assertStringEqualsFile( + __DIR__.'/../fixtures/resources-2.0+intl-icu.xlf', + $dumper->formatCatalogue($catalogue, 'messages'.MessageCatalogue::INTL_DOMAIN_SUFFIX, ['default_locale' => 'fr_FR', 'xliff_version' => '2.0']) + ); + } + public function testFormatCatalogueWithCustomToolInfo() { $options = [ diff --git a/src/Symfony/Component/Translation/Tests/fixtures/resources-2.0+intl-icu.xlf b/src/Symfony/Component/Translation/Tests/fixtures/resources-2.0+intl-icu.xlf new file mode 100644 index 0000000000000..6294f162fd7b0 --- /dev/null +++ b/src/Symfony/Component/Translation/Tests/fixtures/resources-2.0+intl-icu.xlf @@ -0,0 +1,11 @@ + + + + + + foo + bar + + + + diff --git a/src/Symfony/Component/Validator/Constraint.php b/src/Symfony/Component/Validator/Constraint.php index ae27ba21635ee..b1a5e0c1a2b7e 100644 --- a/src/Symfony/Component/Validator/Constraint.php +++ b/src/Symfony/Component/Validator/Constraint.php @@ -122,7 +122,7 @@ public function __construct($options = null) } if ($options && \is_array($options) && \is_string(key($options))) { foreach ($options as $option => $value) { - if (array_key_exists($option, $knownOptions)) { + if (\array_key_exists($option, $knownOptions)) { $this->$option = $value; unset($missingOptions[$option]); } else { @@ -136,7 +136,7 @@ public function __construct($options = null) throw new ConstraintDefinitionException(sprintf('No default option is configured for constraint %s', \get_class($this))); } - if (array_key_exists($option, $knownOptions)) { + if (\array_key_exists($option, $knownOptions)) { $this->$option = $options; unset($missingOptions[$option]); } else { diff --git a/src/Symfony/Component/Validator/Constraints/AbstractComparisonValidator.php b/src/Symfony/Component/Validator/Constraints/AbstractComparisonValidator.php index fec0080fe02e9..3c95c097e8e9a 100644 --- a/src/Symfony/Component/Validator/Constraints/AbstractComparisonValidator.php +++ b/src/Symfony/Component/Validator/Constraints/AbstractComparisonValidator.php @@ -13,7 +13,7 @@ use Symfony\Component\PropertyAccess\Exception\NoSuchPropertyException; use Symfony\Component\PropertyAccess\PropertyAccess; -use Symfony\Component\PropertyAccess\PropertyAccessor; +use Symfony\Component\PropertyAccess\PropertyAccessorInterface; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; @@ -29,7 +29,7 @@ abstract class AbstractComparisonValidator extends ConstraintValidator { private $propertyAccessor; - public function __construct(PropertyAccessor $propertyAccessor = null) + public function __construct(PropertyAccessorInterface $propertyAccessor = null) { $this->propertyAccessor = $propertyAccessor; } diff --git a/src/Symfony/Component/Validator/Constraints/CollectionValidator.php b/src/Symfony/Component/Validator/Constraints/CollectionValidator.php index 731501e08db14..cbc3e198a35bf 100644 --- a/src/Symfony/Component/Validator/Constraints/CollectionValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CollectionValidator.php @@ -51,7 +51,7 @@ public function validate($value, Constraint $constraint) foreach ($constraint->fields as $field => $fieldConstraint) { // bug fix issue #2779 - $existsInArray = \is_array($value) && array_key_exists($field, $value); + $existsInArray = \is_array($value) && \array_key_exists($field, $value); $existsInArrayAccess = $value instanceof \ArrayAccess && $value->offsetExists($field); if ($existsInArray || $existsInArrayAccess) { diff --git a/src/Symfony/Component/Validator/Constraints/CountValidator.php b/src/Symfony/Component/Validator/Constraints/CountValidator.php index adedacdc6247f..301358bcf714c 100644 --- a/src/Symfony/Component/Validator/Constraints/CountValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CountValidator.php @@ -13,6 +13,7 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Exception\UnexpectedValueException; /** diff --git a/src/Symfony/Component/Validator/Constraints/Email.php b/src/Symfony/Component/Validator/Constraints/Email.php index 7d13eceaf7a4e..c6c760c2c0d74 100644 --- a/src/Symfony/Component/Validator/Constraints/Email.php +++ b/src/Symfony/Component/Validator/Constraints/Email.php @@ -76,19 +76,19 @@ class Email extends Constraint public function __construct($options = null) { - if (\is_array($options) && array_key_exists('strict', $options)) { + if (\is_array($options) && \array_key_exists('strict', $options)) { @trigger_error(sprintf('The "strict" property is deprecated since Symfony 4.1. Use "mode"=>"%s" instead.', self::VALIDATION_MODE_STRICT), E_USER_DEPRECATED); } - if (\is_array($options) && array_key_exists('checkMX', $options)) { + if (\is_array($options) && \array_key_exists('checkMX', $options)) { @trigger_error('The "checkMX" option is deprecated since Symfony 4.2.', E_USER_DEPRECATED); } - if (\is_array($options) && array_key_exists('checkHost', $options)) { + if (\is_array($options) && \array_key_exists('checkHost', $options)) { @trigger_error('The "checkHost" option is deprecated since Symfony 4.2.', E_USER_DEPRECATED); } - if (\is_array($options) && array_key_exists('mode', $options) && !\in_array($options['mode'], self::$validationModes, true)) { + if (\is_array($options) && \array_key_exists('mode', $options) && !\in_array($options['mode'], self::$validationModes, true)) { throw new \InvalidArgumentException('The "mode" parameter value is not valid.'); } diff --git a/src/Symfony/Component/Validator/Constraints/IbanValidator.php b/src/Symfony/Component/Validator/Constraints/IbanValidator.php index d6530ab101702..e927f013aa052 100644 --- a/src/Symfony/Component/Validator/Constraints/IbanValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IbanValidator.php @@ -182,7 +182,7 @@ public function validate($value, Constraint $constraint) } // ...have a format available - if (!array_key_exists($countryCode, self::$formats)) { + if (!\array_key_exists($countryCode, self::$formats)) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) ->setCode(Iban::NOT_SUPPORTED_COUNTRY_CODE_ERROR) diff --git a/src/Symfony/Component/Validator/Constraints/LessThanOrEqual.php b/src/Symfony/Component/Validator/Constraints/LessThanOrEqual.php index 74f7aeb8fadea..806ca4990fa02 100644 --- a/src/Symfony/Component/Validator/Constraints/LessThanOrEqual.php +++ b/src/Symfony/Component/Validator/Constraints/LessThanOrEqual.php @@ -20,7 +20,7 @@ */ class LessThanOrEqual extends AbstractComparison { - const TOO_HIGH_ERROR = '079d7420-2d13-460c-8756-de810eeb37d2'; + const TOO_HIGH_ERROR = '30fbb013-d015-4232-8b3b-8f3be97a7e14'; protected static $errorNames = [ self::TOO_HIGH_ERROR => 'TOO_HIGH_ERROR', diff --git a/src/Symfony/Component/Validator/Constraints/Regex.php b/src/Symfony/Component/Validator/Constraints/Regex.php index a71e4de2590e6..dc9e5ea8859d9 100644 --- a/src/Symfony/Component/Validator/Constraints/Regex.php +++ b/src/Symfony/Component/Validator/Constraints/Regex.php @@ -79,7 +79,7 @@ public function getHtmlPattern() // Unescape the delimiter $pattern = str_replace('\\'.$delimiter, $delimiter, substr($this->pattern, 1, -1)); - // If the pattern is inverted, we can simply wrap it in + // If the pattern is inverted, we can wrap it in // ((?!pattern).)* if (!$this->match) { return '((?!'.$pattern.').)*'; diff --git a/src/Symfony/Component/Validator/Constraints/Traverse.php b/src/Symfony/Component/Validator/Constraints/Traverse.php index 4572c9b2193c4..78d115fdbbc74 100644 --- a/src/Symfony/Component/Validator/Constraints/Traverse.php +++ b/src/Symfony/Component/Validator/Constraints/Traverse.php @@ -25,7 +25,7 @@ class Traverse extends Constraint public function __construct($options = null) { - if (\is_array($options) && array_key_exists('groups', $options)) { + if (\is_array($options) && \array_key_exists('groups', $options)) { throw new ConstraintDefinitionException(sprintf('The option "groups" is not supported by the constraint %s', __CLASS__)); } diff --git a/src/Symfony/Component/Validator/Constraints/Url.php b/src/Symfony/Component/Validator/Constraints/Url.php index 2a237bffad3cc..815d73be7cd09 100644 --- a/src/Symfony/Component/Validator/Constraints/Url.php +++ b/src/Symfony/Component/Validator/Constraints/Url.php @@ -109,10 +109,10 @@ class Url extends Constraint public function __construct($options = null) { if (\is_array($options)) { - if (array_key_exists('checkDNS', $options)) { + if (\array_key_exists('checkDNS', $options)) { @trigger_error(sprintf('The "checkDNS" option in "%s" is deprecated since Symfony 4.1. Its false-positive rate is too high to be relied upon.', self::class), E_USER_DEPRECATED); } - if (array_key_exists('dnsMessage', $options)) { + if (\array_key_exists('dnsMessage', $options)) { @trigger_error(sprintf('The "dnsMessage" option in "%s" is deprecated since Symfony 4.1.', self::class), E_USER_DEPRECATED); } } diff --git a/src/Symfony/Component/Validator/Mapping/ClassMetadata.php b/src/Symfony/Component/Validator/Mapping/ClassMetadata.php index afbe72b73508e..6e0256c29018e 100644 --- a/src/Symfony/Component/Validator/Mapping/ClassMetadata.php +++ b/src/Symfony/Component/Validator/Mapping/ClassMetadata.php @@ -366,7 +366,7 @@ public function mergeConstraints(self $source) */ public function hasPropertyMetadata($property) { - return array_key_exists($property, $this->members); + return \array_key_exists($property, $this->members); } /** diff --git a/src/Symfony/Component/Validator/Mapping/ClassMetadataInterface.php b/src/Symfony/Component/Validator/Mapping/ClassMetadataInterface.php index e48e241ab8d5f..1b6f07ac8eed8 100644 --- a/src/Symfony/Component/Validator/Mapping/ClassMetadataInterface.php +++ b/src/Symfony/Component/Validator/Mapping/ClassMetadataInterface.php @@ -86,8 +86,8 @@ public function hasPropertyMetadata($property); /** * Returns all metadata instances for the given named property. * - * If your implementation does not support properties, simply throw an - * exception in this method (for example a BadMethodCallException). + * If your implementation does not support properties, throw an exception + * in this method (for example a BadMethodCallException). * * @param string $property The property name * diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf index 177bb0038f523..731e64aa7f2a4 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.af.xlf @@ -222,6 +222,118 @@ Unsupported card type or invalid card number. Nie-ondersteunde tipe kaart of ongeldige kredietkaart nommer. + + This is not a valid International Bank Account Number (IBAN). + Hierdie is nie 'n geldige Internationale Bank Rekening Nommer (IBAN) nie. + + + This value is not a valid ISBN-10. + Hierdie waarde is nie 'n geldige ISBN-10 nie. + + + This value is not a valid ISBN-13. + Hierdie waarde is nie 'n geldige ISBN-13 nie. + + + This value is neither a valid ISBN-10 nor a valid ISBN-13. + Hierdie waarde is nie 'n geldige ISBN-10 of ISBN-13 nie. + + + This value is not a valid ISSN. + Hierdie waarde is nie 'n geldige ISSN nie. + + + This value is not a valid currency. + Hierdie waarde is nie 'n geldige geldeenheid nie. + + + This value should be equal to {{ compared_value }}. + Hierdie waarde moet gelyk aan {{ compared_value }} wees. + + + This value should be greater than {{ compared_value }}. + Hierdie waarde moet meer as {{ compared_value }} wees. + + + This value should be greater than or equal to {{ compared_value }}. + Hierdie waarde moet meer of gelyk aan {{ compared_value }} wees. + + + This value should be identical to {{ compared_value_type }} {{ compared_value }}. + Hierdie waarde moet identies aan {{ compared_value_type }} {{ compared_value }} wees. + + + This value should be less than {{ compared_value }}. + Hierdie waarde moet minder as {{ compared_value }} wees. + + + This value should be less than or equal to {{ compared_value }}. + Hierdie waarde moet minder of gelyk aan {{ compared_value }} wees. + + + This value should not be equal to {{ compared_value }}. + Hierdie waarde moet nie dieselfde as {{ compared_value }} wees nie. + + + This value should not be identical to {{ compared_value_type }} {{ compared_value }}. + Hierdie waarde moet nie identies as {{ compared_value_type }} {{ compared_value }} wees nie. + + + The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. + Die beeld aspek is te groot ({{ ratio }}). Die maksimum toegelate aspek is {{ max_ratio }}. + + + The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. + Die beeld aspek is te klein ({{ ratio }}). Die minimum toegelate aspek is {{ min_ratio }}. + + + The image is square ({{ width }}x{{ height }}px). Square images are not allowed. + Die beeld is vierkantig ({{ width }}x{{ height }}px). Vierkantige beelde word nie toegelaat nie. + + + The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + Die beeld is landskap georiënteerd ({{ width }}x{{ height }}px). Landskap georiënteerde beelde word nie toegelaat nie. + + + The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + Die beeld dis portret georiënteerd ({{ width }}x{{ height }}px). Portret georiënteerde beelde word nie toegelaat nie. + + + An empty file is not allowed. + 'n Leë lêer word nie toegelaat nie. + + + The host could not be resolved. + Die gasheer kon nie opgelos word nie. + + + This value does not match the expected {{ charset }} charset. + Die waarde stem nie ooreen met die verwagte {{ charset }} karakterstel nie. + + + This is not a valid Business Identifier Code (BIC). + Hierdie is nie 'n geldige Besigheids Identifikasie Kode (BIC) nie. + + + Error + Fout + + + This is not a valid UUID. + Hierdie is nie 'n geldige UUID nie. + + + This value should be a multiple of {{ compared_value }}. + Hierdie waarde moet 'n veelvoud van {{ compared_value }} wees. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Hierdie Besigheids Identifikasie Kode (BIK) is nie geassosieer met IBAN {{ iban }} nie. + + + This value should be valid JSON. + Hierdie waarde moet geldige JSON wees. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf index 4950e0ccd1183..eacd8d777ddec 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf @@ -310,6 +310,26 @@ This value does not match the expected {{ charset }} charset. هذه القيمة غير متطابقة مع صيغة التحويل {{ charset }}. + + This is not a valid Business Identifier Code (BIC). + هذه القيمة ليست رمز معرّف نشاط تجاري صالح (BIC). + + + Error + خطأ + + + This is not a valid UUID. + هذا ليس UUID صالح. + + + This value should be a multiple of {{ compared_value }}. + هذه القيمة يجب أن تكون مضاعف ل {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + رمز المعرّف نشاط تجاري (BIC) هذا لا يرتبط مع IBAN {{ iban }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf index dc6f95ff130fa..bd09da5d0ef0a 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.bg.xlf @@ -318,6 +318,22 @@ Error Грешка + + This is not a valid UUID. + Това не е валиден UUID. + + + This value should be a multiple of {{ compared_value }}. + Тази стойност трябва да бъде кратно число на {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Този бизнес идентификационен код (BIC) не е свързана с IBAN {{ iban }}. + + + This value should be valid JSON. + Тази стойност трябва да е валидна JSON. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf index 078a25d052d10..d6ae6e91bce2a 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf @@ -301,11 +301,35 @@ An empty file is not allowed. No està permès un fixter buit. + + + The host could not be resolved. + No s'ha pogut resoldre l'amfitrió. + + + This value does not match the expected {{ charset }} charset. + Aquest valor no coincideix amb l'esperat {{ charset }} joc de caràcters. + + + This is not a valid Business Identifier Code (BIC). + Aquest no és un codi d'identificació bancari (BIC) vàlid. + + + Error + Error This is not a valid UUID. Aquest valor no és un UUID vàlid. + + This value should be a multiple of {{ compared_value }}. + Aquest valor ha de ser múltiple de {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Aquest Codi d'identificació bancari (BIC) no està associat amb l'IBAN {{ iban }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf index da7cb9aab2986..752b6c2ae5143 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.cy.xlf @@ -222,6 +222,114 @@ Unsupported card type or invalid card number. Unai ni dderbynir y math yna o gerdyn, neu nid yw rhif y cerdyn yn ddilys. + + This is not a valid International Bank Account Number (IBAN). + Nid yw hwn yn Rhif Cyfrif Banc Rhyngwladol (IBAN) dilys. + + + This value is not a valid ISBN-10. + Nid yw'r gwerth hwn yn ISBN-10 dilys. + + + This value is not a valid ISBN-13. + Nid yw'r gwerth hwn yn ISBN-13 dilys. + + + This value is neither a valid ISBN-10 nor a valid ISBN-13. + Nid yw'r gwerth hwn yn Rhif ISBN-10 dilys nac yn ISBN-13 dilys. + + + This value is not a valid ISSN. + Nid yw'r gwerth hwn yn ISSN dilys. + + + This value is not a valid currency. + Nid yw'r gwerth hwn yn arian dilys. + + + This value should be equal to {{ compared_value }}. + Dylai'r gwerth hwn fod yn gyfartal â {{ compared_value }}. + + + This value should be greater than {{ compared_value }}. + Dylai'r gwerth hwn fod yn fwy na {{ compared_value }}. + + + This value should be greater than or equal to {{ compared_value }}. + Dylai'r gwerth hwn fod yn fwy na neu'n hafal i {{ compared_value }}. + + + This value should be identical to {{ compared_value_type }} {{ compared_value }}. + Dylai'r gwerth hwn fod yn union yr un fath â {{ compared_value_type }} {{ compared_value }}. + + + This value should be less than {{ compared_value }}. + Dylai'r gwerth hwn fod yn llai na {{ compared_value }}. + + + This value should be less than or equal to {{ compared_value }}. + Dylai'r gwerth hwn fod yn llai na neu'n hafal i {{ compared_value }}. + + + This value should not be equal to {{ compared_value }}. + Ni ddylai'r gwerth hwn fod yn hafal i {{ compared_value }}. + + + This value should not be identical to {{ compared_value_type }} {{ compared_value }}. + Ni ddylai'r gwerth hwn fod yn union yr un fath â {{ compared_value_type }} {{ compared_value }}. + + + The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. + Mae'r gymhareb delwedd yn rhy fawr ({{ ratio }}). Y gymhareb uchaf a ganiateir yw {{ max_ratio }}. + + + The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. + Mae'r gymhareb delwedd yn rhy fach ({{ ratio }}). Y gymhareb isaf a ddisgwylir yw {{ min_ratio }}. + + + The image is square ({{ width }}x{{ height }}px). Square images are not allowed. + Mae'r ddelwedd yn sgwâr ({{ width }}x{{ height }}px). Ni chaniateir delweddau sgwâr. + + + The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + Mae'r ddelwedd mewn fformat tirlun ({{ width }}x{{ height }}px). Ni chaniateir delweddau mewn fformat tirlun. + + + The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + Mae'r ddelwedd mewn fformat portread ({{ width }}x{{ height }}px). Ni chaniateir delweddau mewn fformat portread. + + + An empty file is not allowed. + Ni chaniateir ffeil wag. + + + The host could not be resolved. + Ni fu modd datrys y gwesteiwr. + + + This value does not match the expected {{ charset }} charset. + Nid yw'r gwerth hwn yn cyfateb â'r {{ charset }} set nodau ddisgwyliedig. + + + This is not a valid Business Identifier Code (BIC). + Nid yw hwn yn God Adnabod Busnes (BIC) dilys. + + + Error + Gwall + + + This is not a valid UUID. + Nid yw hyn yn UUID dilys. + + + This value should be a multiple of {{ compared_value }}. + Dylai'r gwerth hwn fod yn luosrif o {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Nid yw'r Cod Adnabod Busnes (BIC) hwn yn gysylltiedig ag IBAN {{ iban }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf index 454d733fc633d..aab53e727b9e4 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf @@ -326,6 +326,10 @@ This value should be a multiple of {{ compared_value }}. Dieser Wert sollte ein Vielfaches von {{ compared_value }} sein. + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Diese internationale Bankleitzahl (BIC) ist nicht mit der IBAN {{ iban }} assoziiert. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf index a3199bcc9d79e..3b9bbef66e5a4 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf @@ -278,6 +278,58 @@ This value should not be identical to {{ compared_value_type }} {{ compared_value }}. Αυτή η τιμή δεν πρέπει να είναι πανομοιότυπη με {{ compared_value_type }} {{ compared_value }}. + + The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. + Η αναλογία πλάτους-ύψους της εικόνας είναι πολύ μεγάλη ({{ ratio }}). Μέγιστη επιτρεπτή αναλογία {{ max_ratio }}. + + + The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. + Η αναλογία πλάτους-ύψους της εικόνας είναι πολύ μικρή ({{ ratio }}). Ελάχιστη επιτρεπτή αναλογία {{ min_ratio }}. + + + The image is square ({{ width }}x{{ height }}px). Square images are not allowed. + Η εικόνα είναι τετράγωνη ({{ width }}x{{ height }}px). Δεν επιτρέπονται τετράγωνες εικόνες. + + + The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + Η εικόνα έχει οριζόντιο προσανατολισμό ({{ width }}x{{ height }}px). Δεν επιτρέπονται εικόνες με οριζόντιο προσανατολισμό. + + + The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + Η εικόνα έχει κάθετο προσανατολισμό ({{ width }}x{{ height }}px). Δεν επιτρέπονται εικόνες με κάθετο προσανατολισμό. + + + An empty file is not allowed. + Δεν επιτρέπεται κενό αρχείο. + + + The host could not be resolved. + Η διεύθυνση δεν μπόρεσε να επιλυθεί. + + + This value does not match the expected {{ charset }} charset. + Αυτή η τιμή δεν ταιριάζει στο αναμενόμενο {{ charset }} σύνολο χαρακτήρων. + + + This is not a valid Business Identifier Code (BIC). + Αυτός δεν έιναι ένας έγκυρος κωδικός BIC. + + + Error + Σφάλμα + + + This is not a valid UUID. + Αυτό δεν είναι ένα έγκυρο UUID. + + + This value should be a multiple of {{ compared_value }}. + Αυτή η τιμή θα έπρεπε να είναι πολλαπλάσιο του {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Αυτός ο κωδικός BIC δεν σχετίζεται με το IBAN {{ iban }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf index 4bb2760b418e3..465ad220d8790 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf @@ -326,6 +326,14 @@ This value should be a multiple of {{ compared_value }}. This value should be a multiple of {{ compared_value }}. + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + + + This value should be valid JSON. + This value should be valid JSON. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf index 18eb8f4ca2da3..69ab34e8b29ce 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf @@ -324,7 +324,11 @@ This value should be a multiple of {{ compared_value }}. - Este valor debería ser un múltiplo de {{ compared_value }}. + Este valor debería ser múltiplo de {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Este Código de Identificación Bancaria (BIC) no está asociado con el IBAN {{ iban }}. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.eu.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.eu.xlf index d311dedb5e62e..ee9529e3e3ba4 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.eu.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.eu.xlf @@ -278,6 +278,42 @@ This value should not be identical to {{ compared_value_type }} {{ compared_value }}. Balio hau ez litzateke {{ compared_value_type }} {{ compared_value }}-(r)en berbera izan behar. + + The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. + Irudiaren proportzioa oso handia da ({{ ratio }}). Onartutako proportzio handienda {{ max_ratio }} da. + + + The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. + Irudiaren proportzioa oso txikia da ({{ ratio }}). Onartutako proportzio txikiena {{ min_ratio }} da. + + + The image is square ({{ width }}x{{ height }}px). Square images are not allowed. + Irudia karratua da ({{ width }}x{{ height }}px). Karratuak diren irudiak ez dira onartzen. + + + The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + Irudia horizontalki bideratua dago ({{ width }}x{{ height }}px). Horizontalki bideratutako irudiak ez dira onartzen. + + + The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + Irudia bertikalki bideratua dago ({{ width }}x{{ height }}px). Bertikalki bideratutako irudiak ez dira onartzen. + + + An empty file is not allowed. + Hutsik dagoen fitxategia ez da onartzen. + + + The host could not be resolved. + Host-a ezin da ebatzi. + + + This value does not match the expected {{ charset }} charset. + Balio honen karaktere kodea ez da esperotakoa {{ charset }}. + + + This is not a valid Business Identifier Code (BIC). + Ez da balizko Banku Identifikazioko Kodea (BIC). + Error Errore @@ -286,6 +322,14 @@ This is not a valid UUID. Balio hau ez da onartutako UUID bat. + + This value should be a multiple of {{ compared_value }}. + Balio honek {{ compared_value }}-ren multiploa izan beharko luke. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Banku Identifikazioko Kode hau ez dago lotuta {{ IBAN }} IBAN-rekin. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf index 98b4bd66f08e8..ff1aa7c0b1ec0 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf @@ -278,6 +278,58 @@ This value should not be identical to {{ compared_value_type }} {{ compared_value }}. این مقدار نباید {{ compared_value_type }} {{ compared_value }} یکی باشد. + + The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. + ابعاد {{ ratio }} عکس بیش از حد بزرگ است.حداکثر ابعاد مجاز {{ max_ratio }} است. + + + The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. + ابعاد {{ ratio }} عکس بیش از حد کوچک است.حداقل ابعاد مجاز {{ min_ratio }} است. + + + The image is square ({{ width }}x{{ height }}px). Square images are not allowed. + این عکس مربع width }}x{{ height }}px}} می باشد.عکس مربع مجاز نمی باشد. + + + The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + این عکس افقی width }}x{{ height }}px}} می باشد.عکس افقی مجاز نمی باشد. + + + The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + این عکس عمودی width }}x{{ height }}px}} می باشد.عکس عمودی مجاز نمی باشد. + + + An empty file is not allowed. + فایل خالی مجاز نمی باشد. + + + The host could not be resolved. + هاست قابل حل نیست. + + + This value does not match the expected {{ charset }} charset. + این مقدار مورد نظر نمی باشد. مقدار مورد نظر {{ charset }} می باشد. + + + This is not a valid Business Identifier Code (BIC). + این مقدار یک BIC درست نیست. + + + Error + خطا + + + This is not a valid UUID. + این مقدار یک UUID درست نیست. + + + This value should be a multiple of {{ compared_value }}. + این مقدار باید چند برابر {{ compared_value }} باشد. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + این BIC با IBAN ارتباط ندارد. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf index c7ee2795b553e..7b1799d53315c 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fr.xlf @@ -326,6 +326,14 @@ This value should be a multiple of {{ compared_value }}. Cette valeur doit être un multiple de {{ compared_value }}. + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Ce code d'identification d'entreprise (BIC) n'est pas associé à l'IBAN {{ iban }}. + + + This value should be valid JSON. + Cette valeur doit être un JSON valide. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf index ecb7155cac892..71df1d240bde7 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.gl.xlf @@ -314,6 +314,22 @@ This is not a valid Business Identifier Code (BIC). Non é un Código de Identificación Bancaria (BIC) válido. + + Error + Erro + + + This is not a valid UUID. + Isto non é un UUID válido. + + + This value should be a multiple of {{ compared_value }}. + Este valor debería ser multiplo de {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Este Código de identificación bancaria (BIC) non está asociado co IBAN {{ iban }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf index 126ef90332e30..ab033a11c3b01 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf @@ -318,6 +318,22 @@ Error Greška + + This is not a valid UUID. + Ovo nije validan UUID. + + + This value should be a multiple of {{ compared_value }}. + Ova vrijednost treba biti višekratnik od {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Poslovni identifikacijski broj (BIC) nije povezan sa IBAN brojem {{ iban }}. + + + This value should be valid JSON. + Ova vrijednost treba biti validan JSON. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf index 1011d5481829b..30c3cc399d3ef 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hu.xlf @@ -322,6 +322,14 @@ This is not a valid UUID. Érvénytelen egyedi azonosító (UUID). + + This value should be a multiple of {{ compared_value }}. + Ennek az értéknek oszthatónak kell lennie a következővel: {{ compared_value }} + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Ez a Bankazonosító kód (BIC) nem kapcsolódik az IBAN kódhoz ({{ iban }}). + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf index 535bdac08238c..bf4b85deefc35 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf @@ -318,6 +318,18 @@ Error Galat + + This is not a valid UUID. + Ini bukan UUID yang sah. + + + This value should be a multiple of {{ compared_value }}. + Nilai ini harus kelipatan dari {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Business Identifier Code (BIC) ini tidak terkait dengan IBAN {{ iban }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf index f19544701d637..235d44d1bbee9 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf @@ -322,6 +322,14 @@ This is not a valid UUID. Questo non è un UUID valido. + + This value should be a multiple of {{ compared_value }}. + Questo valore dovrebbe essere un multiplo di {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Questo codice identificativo bancario (BIC) non è associato all'IBAN {{ iban }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf index bdbc9da09c88c..4c3579fb58478 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lb.xlf @@ -322,6 +322,18 @@ This is not a valid UUID. Dëst ass keng gëlteg UUID. + + This value should be a multiple of {{ compared_value }}. + Dëse Wäert sollt e puer vun {{ compared_value }} sinn. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Dëse "Business Identifier Code" (BIC) ass net mat IBAN verbonnen {{ iban }}. + + + This value should be valid JSON. + Dëse Wäert sollt gëlteg JSON. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf index 60641b5e68dbd..02eece5965d14 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lt.xlf @@ -302,10 +302,38 @@ An empty file is not allowed. Failas negali būti tuščias. + + The host could not be resolved. + Serveris nepasiekiamas. + + + This value does not match the expected {{ charset }} charset. + Ši reikšmė neatitinka {{ charset }} koduotės. + + + This is not a valid Business Identifier Code (BIC). + Bendrovės Identifikavimo Kodas (BIC) nėra tinkamas. + Error Klaida + + This is not a valid UUID. + Ši reikšmė nėra tinkamas UUID. + + + This value should be a multiple of {{ compared_value }}. + Ši reikšmė turi būti skaičiaus {{ compared_value }} kartotinis. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Šis bendrovės identifikavimo kodas (BIC) nesusijęs su IBAN {{ iban }}. + + + This value should be valid JSON. + Ši reikšmė turi būti tinkamo JSON formato. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf index 2ad19cd283c18..4c0e192521d27 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.lv.xlf @@ -310,6 +310,30 @@ This value does not match the expected {{ charset }} charset. Šī vērtība neatbilst sagaidāmajai rakstzīmju kopai {{ charset }}. + + This is not a valid Business Identifier Code (BIC). + Šī vērtība nav derīgs Biznesa Identifikācijas Kods (BIC). + + + Error + Kļūda + + + This is not a valid UUID. + Šis nav derīgs UUID. + + + This value should be a multiple of {{ compared_value }}. + Šai vērtībai jābūt vairākas reizes atkārtotai {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Šis Biznesa Identifikācijas Kods (BIC) neatbilst {{ iban }} konta numuram (IBAN). + + + This value should be valid JSON. + Šai vērtībai jābūt derīgam JSON. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf index 250576531cfe4..db534528d1d99 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nb.xlf @@ -314,6 +314,26 @@ This is not a valid Business Identifier Code (BIC). Dette er ikke en gyldig BIC. + + Error + Feil + + + This is not a valid UUID. + Dette er ikke en gyldig UUID. + + + This value should be a multiple of {{ compared_value }}. + Verdien skal være flertall av {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Business Identifier Code (BIC) er ikke tilknyttet en IBAN {{ iban }}. + + + This value should be valid JSON. + Verdien er ikke gyldig JSON. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf index 4f2dc08baf2cb..52815e8e721f3 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf @@ -302,6 +302,10 @@ An empty file is not allowed. Lege bestanden zijn niet toegestaan. + + The host could not be resolved. + De hostnaam kon niet worden bepaald. + This value does not match the expected {{ charset }} charset. Deze waarde is niet in de verwachte tekencodering {{ charset }}. @@ -320,7 +324,11 @@ This value should be a multiple of {{ compared_value }}. - Deze waarde moet een veelvoud zijn van {{ compared_value }}. + Deze waarde zou een meervoud van {{ compared_value }} moeten zijn. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Deze bedrijfsidentificatiecode (BIC) is niet gekoppeld aan IBAN {{ iban }}. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf index 250576531cfe4..db534528d1d99 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.no.xlf @@ -314,6 +314,26 @@ This is not a valid Business Identifier Code (BIC). Dette er ikke en gyldig BIC. + + Error + Feil + + + This is not a valid UUID. + Dette er ikke en gyldig UUID. + + + This value should be a multiple of {{ compared_value }}. + Verdien skal være flertall av {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Business Identifier Code (BIC) er ikke tilknyttet en IBAN {{ iban }}. + + + This value should be valid JSON. + Verdien er ikke gyldig JSON. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf index e7ad1eca8de23..888e73b157007 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf @@ -326,6 +326,10 @@ This value should be a multiple of {{ compared_value }}. Ta wartość powinna być wielokrotnością {{ compared_value }}. + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Ten kod BIC (Business Identifier Code) nie jest powiązany z międzynarodowym numerem rachunku bankowego (IBAN) {{ iban }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf index 0561c048f512c..e5cf660686358 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf @@ -302,10 +302,34 @@ An empty file is not allowed. Ficheiro vazio não é permitido. + + The host could not be resolved. + O host não pode ser resolvido. + + + This value does not match the expected {{ charset }} charset. + O valor não corresponde ao conjunto de caracteres {{ charset }} esperado. + + + This is not a valid Business Identifier Code (BIC). + O Código de Identificação de Empresa (BIC) não é válido. + Error Erro + + This is not a valid UUID. + Este valor não é um UUID válido. + + + This value should be a multiple of {{ compared_value }}. + Este valor deve ser um múltiplo de {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + O Código de Identificação de Empresa (BIC) não está associado ao IBAN {{ iban }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf index b61706231887f..8616edf4b9096 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf @@ -314,6 +314,26 @@ This is not a valid Business Identifier Code (BIC). Este não é um Código Identificador Bancário (BIC) válido. + + Error + Erro + + + This is not a valid UUID. + Este não é um UUID válido. + + + This value should be a multiple of {{ compared_value }}. + Este valor deve ser múltiplo de {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Este Código Identificador Bancário (BIC) não está associado ao IBAN {{ iban }}. + + + This value should be valid JSON. + Este valor deve ser um JSON válido. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf index 11bfead5e505c..b77e04e8471c8 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf @@ -310,10 +310,26 @@ This value does not match the expected {{ charset }} charset. Значение не совпадает с ожидаемой {{ charset }} кодировкой. + + This is not a valid Business Identifier Code (BIC). + Значение не соответствует формату BIC. + Error Ошибка + + This is not a valid UUID. + Значение не соответствует формату UUID. + + + This value should be a multiple of {{ compared_value }}. + Значение должно быть кратно {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Данный BIC не связан с IBAN {{ iban }}. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf index ffc8ccf2f9831..569ebca47f02e 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sq.xlf @@ -24,15 +24,15 @@ You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. - Duhet të zgjedhni së paku {{ limit }} alternativa.|Duhet të zgjedhni së paku {{ limit }} alternativa. + Duhet të zgjedhni së paku {{ limit }} alternativë.|Duhet të zgjedhni së paku {{ limit }} alternativa. You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. - Duhet të zgjedhni më së shumti {{ limit }} alternativa.|Duhet të zgjedhni më së shumti {{ limit }} alternativa. + Duhet të zgjedhni më së shumti {{ limit }} alternativë.|Duhet të zgjedhni më së shumti {{ limit }} alternativa. One or more of the given values is invalid. - Një apo më shumë nga vlerat e dhëna nuk janë të sakta. + Një apo më shumë nga vlerat e dhëna janë të pavlefshme. This field was not expected. @@ -40,7 +40,7 @@ This field is missing. - Kjo fushë është zhdukur. + Kjo fushë mungon. This value is not a valid date. @@ -52,7 +52,7 @@ This value is not a valid email address. - Kjo vlerë nuk është e-mail adresë e vlefshme. + Kjo vlerë nuk është adresë email-i e vlefshme. The file could not be found. @@ -64,11 +64,11 @@ The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}. - File është shumë i madh ({{ size }} {{ suffix }}). Madhësia më e madhe e lejuar është {{ limit }} {{ suffix }}. + File është shumë i madh ({{ size }} {{ suffix }}). Madhësia maksimale e lejuar është {{ limit }} {{ suffix }}. The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}. - Lloji mime i files nuk është i vlefshëm ({{ type }}). Llojet mime të lejuara janë {{ types }}. + Lloji mime i file-it është i pavlefshëm ({{ type }}). Llojet mime të lejuara janë {{ types }}. This value should be {{ limit }} or less. @@ -76,7 +76,7 @@ This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. - Kjo vlerë është shumë e gjatë. Duhet t'i ketë {{ limit }} ose më pak karaktere.|Kjo vlerë është shumë e gjatë. Duhet t'i ketë {{ limit }} ose më pak karaktere. + Kjo vlerë është shumë e gjatë. Duhet të përmbaj {{ limit }} karakter ose më pak.|Kjo vlerë është shumë e gjatë. Duhet të përmbaj {{ limit }} karaktere ose më pak. This value should be {{ limit }} or more. @@ -84,7 +84,7 @@ This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. - Kjo vlerë është shumë e shkurtër. Duhet t'i ketë {{ limit }} ose më shumë karaktere.|Kjo vlerë është shumë e shkurtër. Duhet t'i ketë {{ limit }} ose më shumë karaktere. + Kjo vlerë është shumë e shkurtër. Duhet të përmbaj {{ limit }} karakter ose më shumë.|Kjo vlerë është shumë e shkurtër. Duhet të përmbaj {{ limit }} karaktere ose më shumë. This value should not be blank. @@ -136,7 +136,7 @@ This is not a valid IP address. - Kjo vlerë nuk është IP adresë e vlefshme. + Kjo adresë IP nuk është e vlefshme. This value is not a valid language. @@ -144,7 +144,7 @@ This value is not a valid locale. - Kjo vlerë nuk është përcaktim rajonal i vlefshëm. + Kjo vlerë nuk është nje locale i vlefshëm. This value is not a valid country. @@ -156,7 +156,7 @@ The size of the image could not be detected. - Madhësia e këtij imazhi nuk mund të zbulohet. + Madhësia e imazhit nuk mund të zbulohet. The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px. @@ -180,7 +180,7 @@ This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. - Kjo vlerë duhet të ketë saktësisht {{ limit }} karaktere.|Kjo vlerë duhet të ketë saktësisht {{ limit }} karaktere. + Kjo vlerë duhet të ketë saktësisht {{ limit }} karakter.|Kjo vlerë duhet të ketë saktësisht {{ limit }} karaktere. The file was only partially uploaded. @@ -200,27 +200,135 @@ A PHP extension caused the upload to fail. - Një ekstenzion i PHP-së bëri të dështojë ngarkimi i files. + Një ekstension i PHP-së shkaktoi dështimin e ngarkimit. This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. - Ky kolekcion duhet të përmbajë {{ limit }} ose më shumë elemente.|Ky kolekcion duhet të përmbajë {{ limit }} ose më shumë elemente. + Ky koleksion duhet të përmbajë {{ limit }} element ose më shumë.|Ky koleksion duhet të përmbajë {{ limit }} elemente ose më shumë. This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. - Ky kolekcion duhet të përmbajë {{ limit }} ose më shumë elemente.|Ky kolekcion duhet të përmbajë {{ limit }} ose më shumë elemente. + Ky koleksion duhet të përmbajë {{ limit }} element ose më pak.|Ky koleksion duhet të përmbajë {{ limit }} elemente ose më pak. This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. - Ky kolekcion duhet të përmbajë saktësisht {{ limit }} elemente.|Ky kolekcion duhet të përmbajë saktësisht {{ limit }} elemente. + Ky koleksion duhet të përmbajë saktësisht {{ limit }} element.|Ky koleksion duhet të përmbajë saktësisht {{ limit }} elemente. Invalid card number. - Numër kartele i pavlefshëm. + Numër karte i pavlefshëm. Unsupported card type or invalid card number. - Lloj kartele i pambështetur ose numër kartele i pavlefshëm. + Lloj karte i papranuar ose numër karte i pavlefshëm. + + + This is not a valid International Bank Account Number (IBAN). + Ky nuk është një numër i vlefshëm ndërkombëtar i llogarisë bankare (IBAN). + + + This value is not a valid ISBN-10. + Kjo vlerë nuk është një ISBN-10 e vlefshme. + + + This value is not a valid ISBN-13. + Kjo vlerë nuk është një ISBN-13 e vlefshme. + + + This value is neither a valid ISBN-10 nor a valid ISBN-13. + Kjo vlerë nuk është as ISBN-10 e vlefshme as ISBN-13 e vlefshme. + + + This value is not a valid ISSN. + Kjo vlerë nuk është një ISSN e vlefshme. + + + This value is not a valid currency. + Kjo vlerë nuk është një monedhë e vlefshme. + + + This value should be equal to {{ compared_value }}. + Kjo vlerë duhet të jetë e barabartë me {{ compared_value }}. + + + This value should be greater than {{ compared_value }}. + Kjo vlerë duhet të jetë më e madhe se {{ compared_value }}. + + + This value should be greater than or equal to {{ compared_value }}. + Kjo vlerë duhet të jetë më e madhe ose e barabartë me {{ compared_value }}. + + + This value should be identical to {{ compared_value_type }} {{ compared_value }}. + Kjo vlerë duhet të jetë identike me {{ compared_value_type }} {{ compared_value }}. + + + This value should be less than {{ compared_value }}. + Kjo vlerë duhet të jetë më vogël se {{ compared_value }}. + + + This value should be less than or equal to {{ compared_value }}. + Kjo vlerë duhet të jetë më e vogël ose e barabartë me {{ compared_value }}. + + + This value should not be equal to {{ compared_value }}. + Kjo vlerë nuk duhet të jetë e barabartë me {{ compared_value }}. + + + This value should not be identical to {{ compared_value_type }} {{ compared_value }}. + Kjo vlerë nuk duhet të jetë identike me {{ compared_value_type }} {{ compared_value }}. + + + The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. + Raporti i imazhit është shumë i madh ({{ ratio }}). Raporti maksimal i lejuar është {{ max_ratio }}. + + + The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. + Raporti i imazhit është shumë i vogël ({{ ratio }}). Raporti minimal pritet të jetë {{ min_ratio }}. + + + The image is square ({{ width }}x{{ height }}px). Square images are not allowed. + Imazhi është katror ({{ width }}x{{ height }}px). Imazhet katrore nuk janë të lejuara. + + + The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + Imazhi është i orientuar horizontalisht ({{ width }}x{{ height }}px). Imazhet e orientuara horizontalisht nuk lejohen. + + + The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + Imazhi është i orientuar vertikalisht ({{ width }}x{{ height }}px). Imazhet orientuara vertikalisht nuk lejohen. + + + An empty file is not allowed. + Një file i zbrazët nuk lejohet. + + + The host could not be resolved. + Host-i nuk mund te zbulohej. + + + This value does not match the expected {{ charset }} charset. + Kjo vlerë nuk përputhet me kodifikimin e karaktereve {{ charset }} që pritej. + + + This is not a valid Business Identifier Code (BIC). + Ky nuk është një Kod Identifikues i Biznesit (BIC) i vleflshem. + + + Error + Gabim + + + This is not a valid UUID. + Ky nuk është një UUID i vlefshëm. + + + This value should be a multiple of {{ compared_value }}. + Kjo vlerë duhet të jetë një shumëfish i {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Ky Kod Identifikues i Biznesit (BIC) nuk është i lidhur me IBAN {{ iban }}. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf index 60c093aebf795..9ac1ad6bce294 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sr_Latn.xlf @@ -4,39 +4,39 @@ This value should be false. - Vrednost treba da bude netačna. + Vrednost bi trebalo da bude netačna. This value should be true. - Vrednost treba da bude tačna. + Vrednost bi trebalo da bude tačna. This value should be of type {{ type }}. - Vrednost treba da bude tipa {{ type }}. + Vrednost bi trebalo da bude tipa {{ type }}. This value should be blank. - Vrednost treba da bude prazna. + Vrednost bi trebalo da bude prazna. The value you selected is not a valid choice. - Vrednost treba da bude jedna od ponuđenih. + Odabrana vrednost nije validan izbor. You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. - Izaberite bar {{ limit }} mogućnost.|Izaberite bar {{ limit }} mogućnosti.|Izaberite bar {{ limit }} mogućnosti. + Morate odabrati bar {{ limit }} mogućnost.|Morate odabrati bar {{ limit }} mogućnosti. You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. - Izaberite najviše {{ limit }} mogućnost.|Izaberite najviše {{ limit }} mogućnosti.|Izaberite najviše {{ limit }} mogućnosti. + Morate odabrati najviše {{ limit }} mogućnost.|Morate odabrati najviše {{ limit }} mogućnosti. One or more of the given values is invalid. - Jedna ili više vrednosti je nevalidna. + Jedna ili više vrednosti nisu validne. This field was not expected. - Ovo polje ne očekuje. + Ovo polje nije bilo očekivano. This field is missing. @@ -48,7 +48,7 @@ This value is not a valid datetime. - Vrednost nije validan datum-vreme. + Vrednost nije validno vreme. This value is not a valid email address. @@ -68,39 +68,39 @@ The mime type of the file is invalid ({{ type }}). Allowed mime types are {{ types }}. - Mime tip datoteke nije validan ({{ type }}). Dozvoljeni mime tipovi su {{ types }}. + MIME tip datoteke nije validan ({{ type }}). Dozvoljeni MIME tipovi su {{ types }}. This value should be {{ limit }} or less. - Vrednost treba da bude {{ limit }} ili manje. + Vrednost bi trebalo da bude {{ limit }} ili manje. This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. - Vrednost je predugačka. Treba da ima {{ limit }} karakter ili manje.|Vrednost je predugačka. Treba da ima {{ limit }} karaktera ili manje.|Vrednost je predugačka. Treba da ima {{ limit }} karaktera ili manje. + Vrednost je predugačka. Trebalo bi da ima {{ limit }} karakter ili manje.|Vrednost je predugačka. Trebalo bi da ima {{ limit }} karaktera ili manje. This value should be {{ limit }} or more. - Vrednost treba da bude {{ limit }} ili više. + Vrednost bi trebalo da bude {{ limit }} ili više. This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. - Vrednost je prekratka. Treba da ima {{ limit }} karakter ili više.|Vrednost je prekratka. Treba da ima {{ limit }} karaktera ili više.|Vrednost je prekratka. Treba da ima {{ limit }} karaktera ili više. + Vrednost je prekratka. Trebalo bi da ima {{ limit }} karakter ili više.|Vrednost je prekratka. Trebalo bi da ima {{ limit }} karaktera ili više. This value should not be blank. - Vrednost ne treba da bude prazna. + Vrednost ne bi trebalo da bude prazna. This value should not be null. - Vrednost ne treba da bude null. + Vrednost ne bi trebalo da bude prazna. This value should be null. - Vrednost treba da bude null. + Vrednost bi trebalo da bude prazna. This value is not valid. - Vrednost je nevalidna. + Vrednost nije validna. This value is not a valid time. @@ -112,7 +112,7 @@ The two values should be equal. - Obe vrednosti treba da budu jednake. + Obe vrednosti bi trebalo da budu jednake. The file is too large. Allowed maximum size is {{ limit }} {{ suffix }}. @@ -128,7 +128,7 @@ This value should be a valid number. - Vrednost treba da bude validan broj. + Vrednost bi trebalo da bude validan broj. This file is not a valid image. @@ -144,11 +144,11 @@ This value is not a valid locale. - Vrednost nije validan lokal. + Vrednost nije validna međunarodna oznaka jezika. This value is not a valid country. - Vrednost nije validna zemlja. + Vrednost nije validna država. This value is already used. @@ -160,27 +160,27 @@ The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px. - Širina slike je prevelika ({{ width }}px). Najeća dozvoljena širina je {{ max_width }}px. + Širina slike je prevelika ({{ width }} piksela). Najveća dozvoljena širina je {{ max_width }} piksela. The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px. - Širina slike je premala ({{ width }}px). Najmanja dozvoljena širina je {{ min_width }}px. + Širina slike je premala ({{ width }} piksela). Najmanja dozvoljena širina je {{ min_width }} piksela. The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px. - Visina slike je prevelika ({{ height }}px). Najeća dozvoljena visina je {{ max_height }}px. + Visina slike je prevelika ({{ height }} piksela). Najveća dozvoljena visina je {{ max_height }} piksela. The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px. - Visina slike je premala ({{ height }}px). Najmanja dozvoljena visina je {{ min_height }}px. + Visina slike je premala ({{ height }} piksela). Najmanja dozvoljena visina je {{ min_height }} piksela. This value should be the user's current password. - Vrednost treba da bude trenutna korisnička lozinka. + Vrednost bi trebalo da bude trenutna korisnička lozinka. This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. - Vrednost treba da ima tačno {{ limit }} karakter.|Vrednost treba da ima tačno {{ limit }} karaktera.|Vrednost treba da ima tačno {{ limit }} karaktera. + Vrednost bi trebalo da ima tačno {{ limit }} karakter.|Vrednost bi trebalo da ima tačno {{ limit }} karaktera. The file was only partially uploaded. @@ -204,23 +204,23 @@ This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. - Ova kolekcija treba da sadrži {{ limit }} ili više elemenata.|Ova kolekcija treba da sadrži {{ limit }} ili više elemenata.|Ova kolekcija treba da sadrži {{ limit }} ili više elemenata. + Ova kolekcija bi trebalo da sadrži {{ limit }} ili više elemenata.|Ova kolekcija bi trebalo da sadrži {{ limit }} ili više elemenata. This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. - Ova kolekcija treba da sadrži {{ limit }} ili manje elemenata.|Ova kolekcija treba da sadrži {{ limit }} ili manje elemenata.|Ova kolekcija treba da sadrži {{ limit }} ili manje elemenata. + Ova kolekcija bi trebalo da sadrži {{ limit }} ili manje elemenata.|Ova kolekcija bi trebalo da sadrži {{ limit }} ili manje elemenata. This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. - Ova kolekcija treba da sadrži tačno {{ limit }} element.|Ova kolekcija treba da sadrži tačno {{ limit }} elementa.|Ova kolekcija treba da sadrži tačno {{ limit }} elemenata. + Ova kolekcija bi trebalo da sadrži tačno {{ limit }} element.|Ova kolekcija bi trebalo da sadrži tačno {{ limit }} elemenata. Invalid card number. - Nevalidan broj kartice. + Broj kartice nije validan. Unsupported card type or invalid card number. - Nevalidan broj kartice ili tip kartice nije podržan. + Tip kartije nije podržan ili broj kartice nije validan. This is not a valid International Bank Account Number (IBAN). @@ -248,35 +248,35 @@ This value should be equal to {{ compared_value }}. - Ova vrednost treba da bude {{ compared_value }}. + Ova vrednost bi trebalo da bude jednaka {{ compared_value }}. This value should be greater than {{ compared_value }}. - Ova vrednost treba da bude veća od {{ compared_value }}. + Ova vrednost bi trebalo da bude veća od {{ compared_value }}. This value should be greater than or equal to {{ compared_value }}. - Ova vrednost treba da bude veća ili jednaka {{ compared_value }}. + Ova vrednost bi trebalo da bude veća ili jednaka {{ compared_value }}. This value should be identical to {{ compared_value_type }} {{ compared_value }}. - Ova vrednost treba da bude identična sa {{ compared_value_type }} {{ compared_value }}. + Ova vrednost bi trebalo da bude identična sa {{ compared_value_type }} {{ compared_value }}. This value should be less than {{ compared_value }}. - Ova vrednost treba da bude manja od {{ compared_value }}. + Ova vrednost bi trebalo da bude manja od {{ compared_value }}. This value should be less than or equal to {{ compared_value }}. - Ova vrednost treba da bude manja ili jednaka {{ compared_value }}. + Ova vrednost bi trebalo da bude manja ili jednaka {{ compared_value }}. This value should not be equal to {{ compared_value }}. - Ova vrednost ne treba da bude jednaka {{ compared_value }}. + Ova vrednost ne bi trebalo da bude jednaka {{ compared_value }}. This value should not be identical to {{ compared_value_type }} {{ compared_value }}. - Ova vrednost ne treba da bude identična sa {{ compared_value_type }} {{ compared_value }}. + Ova vrednost ne bi trebalo da bude identična sa {{ compared_value_type }} {{ compared_value }}. The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. @@ -288,15 +288,51 @@ The image is square ({{ width }}x{{ height }}px). Square images are not allowed. - Slika je kvadratna ({{ width }}x{{ height }}px). Kvadratne slike nisu dozvoljene. + Slika je kvadratna ({{ width }}x{{ height }} piksela). Kvadratne slike nisu dozvoljene. The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. - Slika je orijentacije pejzaža ({{ width }}x{{ height }}px). Pejzažna orijentacija slika nije dozvoljena. + Slika je pejzažno orijentisana ({{ width }}x{{ height }} piksela). Pejzažna orijentisane slike nisu dozvoljene. The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. - Slika je orijantacije portreta ({{ width }}x{{ height }}px). Portretna orijentacija slika nije dozvoljena. + Slika je portretno orijentisana ({{ width }}x{{ height }} piksela). Portretno orijentisane slike nisu dozvoljene. + + + An empty file is not allowed. + Prazna datoteka nije dozvoljena. + + + The host could not be resolved. + Nije moguće odrediti poslužitelja. + + + This value does not match the expected {{ charset }} charset. + Vrednost se ne poklapa sa očekivanim {{ charset }} setom karaktera. + + + This is not a valid Business Identifier Code (BIC). + Ovo nije validan BIC. + + + Error + Greška + + + This is not a valid UUID. + Ovo nije validan univerzalni unikatni identifikator (UUID). + + + This value should be a multiple of {{ compared_value }}. + Ova vrednost bi trebalo da bude višestruko veća od {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + BIC kod nije povezan sa IBAN {{ iban }}. + + + This value should be valid JSON. + Ova vrednost bi trebalo da bude validan JSON. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf index 5e19e3e5a3c66..a23c652b176e8 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.tr.xlf @@ -222,10 +222,114 @@ Unsupported card type or invalid card number. Desteklenmeyen kart tipi veya geçersiz kart numarası. + + This is not a valid International Bank Account Number (IBAN). + Bu geçerli bir Uluslararası Banka Hesap Numarası (IBAN) değildir. + + + This value is not a valid ISBN-10. + Bu değer geçerli bir ISBN-10 değildir. + + + This value is not a valid ISBN-13. + Bu değer geçerli bir ISBN-13 değildir. + + + This value is neither a valid ISBN-10 nor a valid ISBN-13. + Bu değer geçerli bir ISBN-10 veya ISBN-13 değildir. + + + This value is not a valid ISSN. + Bu değer geçerli bir ISSN değildir. + + + This value is not a valid currency. + Bu değer geçerli bir para birimi değil. + + + This value should be equal to {{ compared_value }}. + Bu değer {{ compared_value }} ile eşit olmalıdır. + + + This value should be greater than {{ compared_value }}. + Bu değer {{ compared_value }} değerinden büyük olmalıdır. + + + This value should be greater than or equal to {{ compared_value }}. + Bu değer {{ compared_value }} ile eşit veya büyük olmalıdır. + + + This value should be identical to {{ compared_value_type }} {{ compared_value }}. + Bu değer {{ compared_value_type }} {{ compared_value }} ile aynı olmalıdır. + + + This value should be less than {{ compared_value }}. + Bu değer {{ compared_value }} değerinden düşük olmalıdır. + + + This value should be less than or equal to {{ compared_value }}. + .Bu değer {{ compared_value }} ile eşit veya düşük olmalıdır. + + + This value should not be equal to {{ compared_value }}. + Bu değer {{ compared_value }} ile eşit olmamalıdır. + + + This value should not be identical to {{ compared_value_type }} {{ compared_value }}. + Bu değer {{ compared_value_type }} {{ compared_value }} ile aynı olmamalıdır. + + + The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. + Resim oranı çok büyük ({{ ratio }}). İzin verilen maksimum oran: {{ max_ratio }}. + + + The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. + Resim oranı çok ufak ({{ ratio }}). Beklenen minimum oran {{ min_ratio }}. + + + The image is square ({{ width }}x{{ height }}px). Square images are not allowed. + Resim karesi ({{ width }}x{{ height }}px). Kare resimlerine izin verilmiyor. + + + The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + Resim manzara odaklı ({{ width }}x{{ height }}px). Manzara odaklı resimlere izin verilmiyor. + + + The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + Resim portre odaklı ({{ width }}x{{ height }}px). Portre odaklı resimlere izin verilmiyor. + + + An empty file is not allowed. + Boş bir dosyaya izin verilmiyor. + + + The host could not be resolved. + Sunucu çözülemedi. + + + This value does not match the expected {{ charset }} charset. + Bu değer beklenen {{ charset }} karakter kümesiyle eşleşmiyor. + + + This is not a valid Business Identifier Code (BIC). + Bu geçerli bir İşletme Tanımlayıcı Kodu (BIC) değildir. + Error Hata + + This is not a valid UUID. + Bu geçerli bir UUID değildir. + + + This value should be a multiple of {{ compared_value }}. + Bu değer {{ compare_value }} değerinin katlarından biri olmalıdır. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Bu İşletme Tanımlayıcı Kodu (BIC), IBAN {{ iban }} ile ilişkili değildir. + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf index 6a92801c9b47d..5ddc429854e54 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf @@ -318,6 +318,18 @@ Error Помилка + + This is not a valid UUID. + Це не валідне значення UUID. + + + This value should be a multiple of {{ compared_value }}. + Це значення повинне бути кратним {{ compared_value }}. + + + This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. + Банківський код (BIC) не пов’язаний із міжнародним номером банківського рахунку (IBAN) {{ iban }}. + diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/CustomArrayObject.php b/src/Symfony/Component/Validator/Tests/Fixtures/CustomArrayObject.php index ac48a512c6292..1edf1de0811db 100644 --- a/src/Symfony/Component/Validator/Tests/Fixtures/CustomArrayObject.php +++ b/src/Symfony/Component/Validator/Tests/Fixtures/CustomArrayObject.php @@ -26,7 +26,7 @@ public function __construct(array $array = null) public function offsetExists($offset) { - return array_key_exists($offset, $this->array); + return \array_key_exists($offset, $this->array); } public function offsetGet($offset) diff --git a/src/Symfony/Component/VarDumper/Caster/DoctrineCaster.php b/src/Symfony/Component/VarDumper/Caster/DoctrineCaster.php index 6adf9dd837623..696b87816ea8e 100644 --- a/src/Symfony/Component/VarDumper/Caster/DoctrineCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/DoctrineCaster.php @@ -26,7 +26,7 @@ class DoctrineCaster public static function castCommonProxy(CommonProxy $proxy, array $a, Stub $stub, $isNested) { foreach (['__cloner__', '__initializer__'] as $k) { - if (array_key_exists($k, $a)) { + if (\array_key_exists($k, $a)) { unset($a[$k]); ++$stub->cut; } @@ -38,7 +38,7 @@ public static function castCommonProxy(CommonProxy $proxy, array $a, Stub $stub, public static function castOrmProxy(OrmProxy $proxy, array $a, Stub $stub, $isNested) { foreach (['_entityPersister', '_identifier'] as $k) { - if (array_key_exists($k = "\0Doctrine\\ORM\\Proxy\\Proxy\0".$k, $a)) { + if (\array_key_exists($k = "\0Doctrine\\ORM\\Proxy\\Proxy\0".$k, $a)) { unset($a[$k]); ++$stub->cut; } @@ -50,7 +50,7 @@ public static function castOrmProxy(OrmProxy $proxy, array $a, Stub $stub, $isNe public static function castPersistentCollection(PersistentCollection $coll, array $a, Stub $stub, $isNested) { foreach (['snapshot', 'association', 'typeClass'] as $k) { - if (array_key_exists($k = "\0Doctrine\\ORM\\PersistentCollection\0".$k, $a)) { + if (\array_key_exists($k = "\0Doctrine\\ORM\\PersistentCollection\0".$k, $a)) { $a[$k] = new CutStub($a[$k]); } } diff --git a/src/Symfony/Component/VarDumper/Cloner/Data.php b/src/Symfony/Component/VarDumper/Cloner/Data.php index 92a6f41cdd12e..838aeb0c6a65d 100644 --- a/src/Symfony/Component/VarDumper/Cloner/Data.php +++ b/src/Symfony/Component/VarDumper/Cloner/Data.php @@ -245,7 +245,7 @@ public function seek($key) $children = $this->data[$item->position]; foreach ($keys as $key) { - if (isset($children[$key]) || array_key_exists($key, $children)) { + if (isset($children[$key]) || \array_key_exists($key, $children)) { $data = clone $this; $data->key = $key; $data->position = $item->position; diff --git a/src/Symfony/Component/VarDumper/Cloner/Stub.php b/src/Symfony/Component/VarDumper/Cloner/Stub.php index 08fba759301c6..27dd3ef32c4df 100644 --- a/src/Symfony/Component/VarDumper/Cloner/Stub.php +++ b/src/Symfony/Component/VarDumper/Cloner/Stub.php @@ -39,22 +39,29 @@ class Stub public $position = 0; public $attr = []; + private static $defaultProperties = []; + /** * @internal */ public function __sleep() { - $this->serialized = [$this->class, $this->position, $this->cut, $this->type, $this->value, $this->handle, $this->refCount, $this->attr]; + $properties = []; - return ['serialized']; - } + if (!isset(self::$defaultProperties[$c = \get_class($this)])) { + self::$defaultProperties[$c] = get_class_vars($c); - /** - * @internal - */ - public function __wakeup() - { - list($this->class, $this->position, $this->cut, $this->type, $this->value, $this->handle, $this->refCount, $this->attr) = $this->serialized; - unset($this->serialized); + foreach ((new \ReflectionClass($c))->getStaticProperties() as $k => $v) { + unset(self::$defaultProperties[$c][$k]); + } + } + + foreach (self::$defaultProperties[$c] as $k => $v) { + if ($this->$k !== $v) { + $properties[] = $k; + } + } + + return $properties; } } diff --git a/src/Symfony/Component/VarDumper/Cloner/VarCloner.php b/src/Symfony/Component/VarDumper/Cloner/VarCloner.php index a50adef9f5262..b8318c514ffbf 100644 --- a/src/Symfony/Component/VarDumper/Cloner/VarCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/VarCloner.php @@ -31,6 +31,7 @@ protected function doClone($var) $indexedArrays = []; // Map of queue indexes that hold numerically indexed arrays $hardRefs = []; // Map of original zval ids to stub objects $objRefs = []; // Map of original object handles to their stub object counterpart + $objects = []; // Keep a ref to objects to ensure their handle cannot be reused while cloning $resRefs = []; // Map of original resource handles to their stub object counterpart $values = []; // Map of stub objects' ids to original values $maxItems = $this->maxItems; @@ -193,6 +194,7 @@ protected function doClone($var) } if (empty($objRefs[$h])) { $objRefs[$h] = $stub; + $objects[] = $v; } else { $stub = $objRefs[$h]; ++$stub->refCount; diff --git a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php index 5bd652bfef708..9c0ff36fbfac7 100644 --- a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php @@ -39,7 +39,7 @@ abstract class AbstractDumper implements DataDumperInterface, DumperInterface /** * @param callable|resource|string|null $output A line dumper callable, an opened stream or an output path, defaults to static::$defaultOutput - * @param string $charset The default character encoding to use for non-UTF8 strings + * @param string|null $charset The default character encoding to use for non-UTF8 strings * @param int $flags A bit field of static::DUMP_* constants to fine tune dumps representation */ public function __construct($output = null, string $charset = null, int $flags = 0) diff --git a/src/Symfony/Component/Workflow/DependencyInjection/ValidateWorkflowsPass.php b/src/Symfony/Component/Workflow/DependencyInjection/ValidateWorkflowsPass.php index b4e222d335fcd..175a1f5b96d71 100644 --- a/src/Symfony/Component/Workflow/DependencyInjection/ValidateWorkflowsPass.php +++ b/src/Symfony/Component/Workflow/DependencyInjection/ValidateWorkflowsPass.php @@ -34,13 +34,13 @@ public function process(ContainerBuilder $container) $taggedServices = $container->findTaggedServiceIds($this->definitionTag, true); foreach ($taggedServices as $id => $tags) { foreach ($tags as $tag) { - if (!array_key_exists('name', $tag)) { + if (!\array_key_exists('name', $tag)) { throw new RuntimeException(sprintf('The "name" for the tag "%s" of service "%s" must be set.', $this->definitionTag, $id)); } - if (!array_key_exists('type', $tag)) { + if (!\array_key_exists('type', $tag)) { throw new RuntimeException(sprintf('The "type" for the tag "%s" of service "%s" must be set.', $this->definitionTag, $id)); } - if (!array_key_exists('marking_store', $tag)) { + if (!\array_key_exists('marking_store', $tag)) { throw new RuntimeException(sprintf('The "marking_store" for the tag "%s" of service "%s" must be set.', $this->definitionTag, $id)); } diff --git a/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php b/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php index f8c0fa5457427..918c0c8335619 100644 --- a/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php +++ b/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php @@ -204,9 +204,9 @@ protected function dotize($id) /** * @internal */ - protected function escape(string $string): string + protected function escape($value): string { - return addslashes($string); + return \is_bool($value) ? ($value ? '1' : '0') : \addslashes($value); } private function addAttributes(array $attributes): string diff --git a/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php b/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php index c43292899b893..4e344560557d4 100644 --- a/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php +++ b/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php @@ -94,7 +94,7 @@ public function testValid() (new StateMachineValidator())->validate($definition, 'foo'); - // the test simply ensures that the validation does not fail (i.e. it does not throw any exceptions) + // the test ensures that the validation does not fail (i.e. it does not throw any exceptions) $this->addToAssertionCount(1); // The graph looks like: diff --git a/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php b/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php index cdf10ecdaba93..4a5c5a57dd85f 100644 --- a/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php +++ b/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php @@ -29,7 +29,7 @@ public function testSinglePlaceWorkflowValidatorAndSimpleWorkflow() (new WorkflowValidator(true))->validate($definition, 'foo'); - // the test simply ensures that the validation does not fail (i.e. it does not throw any exceptions) + // the test ensures that the validation does not fail (i.e. it does not throw any exceptions) $this->addToAssertionCount(1); } @@ -64,7 +64,7 @@ public function testSameTransitionNameButNotSamePlace() (new WorkflowValidator())->validate($definition, 'foo'); - // the test simply ensures that the validation does not fail (i.e. it does not throw any exceptions) + // the test ensures that the validation does not fail (i.e. it does not throw any exceptions) $this->addToAssertionCount(1); } } diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index 1619b3183aa7c..4b12b9b11a9ba 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -555,7 +555,7 @@ private static function evaluateScalar(string $scalar, int $flags, array $refere throw new ParseException('A reference must contain at least one character.', self::$parsedLineNumber + 1, $value, self::$parsedFilename); } - if (!array_key_exists($value, $references)) { + if (!\array_key_exists($value, $references)) { throw new ParseException(sprintf('Reference "%s" does not exist.', $value), self::$parsedLineNumber + 1, $value, self::$parsedFilename); } diff --git a/src/Symfony/Component/Yaml/Parser.php b/src/Symfony/Component/Yaml/Parser.php index d63467084b89d..cfec2de670eb0 100644 --- a/src/Symfony/Component/Yaml/Parser.php +++ b/src/Symfony/Component/Yaml/Parser.php @@ -237,7 +237,7 @@ private function doParse(string $value, int $flags) $allowOverwrite = true; if (isset($values['value'][0]) && '*' === $values['value'][0]) { $refName = substr(rtrim($values['value']), 1); - if (!array_key_exists($refName, $this->refs)) { + if (!\array_key_exists($refName, $this->refs)) { if (false !== $pos = array_search($refName, $this->refsBeingParsed, true)) { throw new ParseException(sprintf('Circular reference [%s, %s] detected for reference "%s".', implode(', ', \array_slice($this->refsBeingParsed, $pos)), $refName, $refName), $this->currentLineNb + 1, $this->currentLine, $this->filename); } @@ -648,7 +648,7 @@ private function parseValue(string $value, int $flags, string $context) $value = substr($value, 1); } - if (!array_key_exists($value, $this->refs)) { + if (!\array_key_exists($value, $this->refs)) { if (false !== $pos = array_search($value, $this->refsBeingParsed, true)) { throw new ParseException(sprintf('Circular reference [%s, %s] detected for reference "%s".', implode(', ', \array_slice($this->refsBeingParsed, $pos)), $value, $value), $this->currentLineNb + 1, $this->currentLine, $this->filename); }