diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 216a2ba4e5625..c9c3b75340557 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,6 @@ | Q | A | ------------- | --- -| Branch? | master / 2.7, 2.8, 3.1 or 3.2 +| Branch? | master / 2.7, 2.8 or 3.2 | Bug fix? | yes/no | New feature? | yes/no | BC breaks? | yes/no diff --git a/.php_cs.dist b/.php_cs.dist index 5f37bb77f694c..71c4a35f5883b 100644 --- a/.php_cs.dist +++ b/.php_cs.dist @@ -8,33 +8,34 @@ return PhpCsFixer\Config::create() 'no_unreachable_default_argument_value' => false, 'braces' => array('allow_single_line_closure' => true), 'heredoc_to_nowdoc' => false, + 'phpdoc_annotation_without_dot' => false, )) ->setRiskyAllowed(true) ->setFinder( PhpCsFixer\Finder::create() - ->in(__DIR__) + ->in(__DIR__.'/src') ->exclude(array( // directories containing files with content that is autogenerated by `var_export`, which breaks CS in output code - 'src/Symfony/Component/DependencyInjection/Tests/Fixtures', - 'src/Symfony/Component/Routing/Tests/Fixtures/dumper', + 'Symfony/Component/DependencyInjection/Tests/Fixtures', + 'Symfony/Component/Routing/Tests/Fixtures/dumper', // fixture templates - 'src/Symfony/Component/Templating/Tests/Fixtures/templates', - 'src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Custom', + 'Symfony/Component/Templating/Tests/Fixtures/templates', + 'Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Custom', // generated fixtures - 'src/Symfony/Component/VarDumper/Tests/Fixtures', + 'Symfony/Component/VarDumper/Tests/Fixtures', // resource templates - 'src/Symfony/Bundle/FrameworkBundle/Resources/views/Form', + 'Symfony/Bundle/FrameworkBundle/Resources/views/Form', )) // file content autogenerated by `var_export` - ->notPath('src/Symfony/Component/Translation/Tests/fixtures/resources.php') + ->notPath('Symfony/Component/Translation/Tests/fixtures/resources.php') // autogenerated xmls - ->notPath('src/Symfony/Component/Console/Tests/Fixtures/application_1.xml') - ->notPath('src/Symfony/Component/Console/Tests/Fixtures/application_2.xml') + ->notPath('Symfony/Component/Console/Tests/Fixtures/application_1.xml') + ->notPath('Symfony/Component/Console/Tests/Fixtures/application_2.xml') // yml - ->notPath('src/Symfony/Component/Yaml/Tests/Fixtures/sfTests.yml') + ->notPath('Symfony/Component/Yaml/Tests/Fixtures/sfTests.yml') // test template - ->notPath('src/Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Custom/_name_entry_label.html.php') + ->notPath('Symfony/Bundle/FrameworkBundle/Tests/Templating/Helper/Resources/Custom/_name_entry_label.html.php') // explicit heredoc test - ->notPath('src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Resources/views/translation.html.php') + ->notPath('Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Resources/views/translation.html.php') ) ; diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index fc198328e6002..36efff588f4d8 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -7,6 +7,52 @@ in 3.1 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v3.1.0...v3.1.1 +* 3.1.9 (2017-01-12) + + * bug #21218 [Form] DateTimeToLocalizedStringTransformer does not use timezone when using date only (magnetik) + * bug #20605 [Ldap] Always have a valid connection when using the EntryManager (bobvandevijver) + * bug #21104 [FrameworkBundle] fix IPv6 address handling in server commands (xabbuh) + * bug #20793 [Validator] Fix caching of constraints derived from non-serializable parents (uwej711) + * bug #19586 [TwigBundle] Fix bug where namespaced paths don't take parent bundles in account (wesleylancel) + * bug #21237 [FrameworkBundle] Fix relative paths used as cache keys (nicolas-grekas) + * bug #21183 [Validator] respect groups when merging constraints (xabbuh) + * bug #21179 [TwigBundle] Fixing regression in TwigEngine exception handling (Bertalan Attila) + * bug #21220 [DI] Fix missing new line after private alias (ogizanagi) + * bug #21211 Classloader tmpname (lyrixx) + * bug #21205 [TwigBundle] fixed usage when Templating is not installed (fabpot) + * bug #21155 [Validator] Check cascasdedGroups for being countable (scaytrase) + * bug #21200 [Filesystem] Check that directory is writable after created it in dumpFile() (chalasr) + * bug #21165 [Serializer] int is valid when float is expected when deserializing JSON (dunglas) + * bug #21166 [Cache] Fix order of writes in ChainAdapter (nicolas-grekas) + * bug #21113 [FrameworkBundle][HttpKernel] Fix resources loading for bundles with custom structure (chalasr) + * bug #21084 [Yaml] handle empty lines inside unindented collection (xabbuh) + * bug #20925 [HttpFoundation] Validate/cast cookie expire time (ro0NL) + * bug #21032 [SecurityBundle] Made collection of user provider unique when injecting them to the RemberMeService (lyrixx) + * bug #21078 [Console] Escape default value when dumping help (lyrixx) + * bug #21076 [Console] OS X Can't call cli_set_process_title php without superuser (ogizanagi) + * bug #20900 [Console] Descriptors should use Helper::strlen (ogizanagi) + * bug #21025 [Cache] remove is_writable check on filesystem cache (4rthem) + * bug #21064 [Debug] Wrap call to ->log in a try catch block (lyrixx) + * bug #21010 [Debug] UndefinedMethodFatalErrorHandler - Handle anonymous classes (SpacePossum) + * bug #20991 [cache] Bump RedisAdapter default timeout to 5s (Nicofuma) + * bug #20859 Avoid warning in PHP 7.2 because of non-countable data (wouterj) + * bug #21053 [Validator] override property constraints in child class (xabbuh) + * bug #21034 [FrameworkBundle] Make TemplateController working without the Templating component (dunglas) + * bug #20970 [Console] Fix question formatting using SymfonyStyle::ask() (chalasr, ogizanagi) + * bug #20999 [HttpKernel] Continuation of #20599 for 3.1 (ro0NL) + * bug #20975 [Form] fix group sequence based validation (xabbuh) + * bug #20599 [WebProfilerBundle] Display multiple HTTP headers in WDT (ro0NL) + * bug #20799 [TwigBundle] do not try to register incomplete definitions (xabbuh) + * bug #20961 [Validator] phpize default option values (xabbuh) + * bug #20934 [FrameworkBundle] Fix PHP form templates on translatable attributes (ro0NL) + * bug #20957 [FrameworkBundle] test for the Validator component to be present (xabbuh) + * bug #20936 [DependencyInjection] Fix on-invalid attribute type in xsd (ogizanagi) + * bug #20931 [VarDumper] Fix dumping by-ref variadics (nicolas-grekas) + * bug #20734 [Security] AbstractVoter->supportsAttribute gives false positive if attribute is zero (0) (martynas-foodpanda) + * bug #14082 [config] Fix issue when key removed and left value only (zerustech) + * bug #20910 [HttpFoundation] Fix cookie to string conversion for raw cookies (ro0NL) + * bug #20847 [Console] fixed BC issue with static closures (araines) + * 3.1.8 (2016-12-13) * bug #20714 [FrameworkBundle] Fix unresolved parameters from default configs in debug:config (chalasr) diff --git a/CHANGELOG-3.2.md b/CHANGELOG-3.2.md index cea91c29475e1..2d191a0eadb05 100644 --- a/CHANGELOG-3.2.md +++ b/CHANGELOG-3.2.md @@ -7,6 +7,42 @@ in 3.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/v3.2.0...v3.2.1 +* 3.2.3 (2017-02-06) + + * bug #21528 [Cache] Fix class exists checks in PhpArrayAdapter (nicolas-grekas) + * bug #20844 [Config] Fix checking cache for non existing meta file (hason) + * bug #21063 [Form] Fixed DateType format option for single text widget (HeahDude) + * bug #21430 Casting TableCell value to string. (jaydiablo) + * bug #21359 [FrameworkBundle] fixed custom domain for translations in php templates (robinlehrmann) + * bug #21485 [Process] Non ASCII characters disappearing during the escapeshellarg (GuillaumeVerdon) + * bug #21370 [FrameworkBundle] Execute the PhpDocExtractor earlier (GuilhemN) + * bug #21462 [BrowserKit] ignore invalid cookies expires date format (xabbuh) + * bug #21438 [Console] Fix TableCell issues with decoration (ogizanagi) + * bug #21431 [DoctrineBridge] always check for all fields to be mapped (xabbuh) + * bug #21360 [PropertyAccess] Handle interfaces in the invalid argument exception (fancyweb) + * bug #21403 [DI] Fix defaults overriding empty strings in AutowirePass (nicolas-grekas) + * bug #21401 [Debug] Workaround "null" $context (nicolas-grekas) + * bug #21381 [FrameworkBundle] Dont wire "annotations.cached_reader" before removing passes (nicolas-grekas) + * bug #21387 Fix double escaping of the decision attributes in the profiler (stof) + * bug #21372 [DependencyInjection] Fixed variadic method parameter in autowired classes (brainexe) + * bug #21338 [Cache] Fix tags expiration (nicolas-grekas) + * bug #21333 [HttpKernel] Fix ArgumentValueResolver for arguments default null (chalasr) + * bug #20871 [HttpKernel] Give higher priority to adding request formats (akeeman) + * bug #21332 [PropertyInfo] Don't try to access a property thru a static method (dunglas) + * bug #21336 [PhpUnit] Blacklist DeprecationErrorHandler in stack traces (nicolas-grekas) + * bug #21331 [PropertyInfo] Exclude static methods form properties guessing (dunglas) + * bug #21280 [Workflow] Fixed support of multiple transitions with the same name. (lyrixx) + * bug #21271 [Workflow] Added new validator to make sure each place has unique translation names (Nyholm) + * bug #21323 [Cache] [PdoAdapter] Fix MySQL 1170 error (blob as primary key) (akeeman) + * bug #21318 Don't add csp-headers if none are required (arjenm) + * bug #21291 [Ldap] Ldap username case fix (quentinus95) + * bug #21311 [Debug] Fix fatal error when changing ErrorHandler loggers if an exception is buffered (skalpa) + * bug #21288 [Doctrine Bridge] fix UniqueEntityValidator for composite object primary keys (dmaicher, HeahDude) + * bug #21285 [TwigBundle] do not lose already set method calls (xabbuh) + * bug #21279 #20411 fix Yaml parsing for very long quoted strings (RichardBradley) + * bug #21276 [Cache] Fix missing use statement in FilesystemAdapter (Lctrs) + * bug #21269 [Cache] Using strpbrk() instead of strcspn() is faster (nicolas-grekas) + * 3.2.2 (2017-01-12) * bug #21257 [Profiler][Form] Fix form profiler errors profiler_dump (ogizanagi) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 24f9845d0b517..f740b56abf6f9 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -27,18 +27,18 @@ Symfony is the result of the work of many people who made the code better - Karma Dordrak (drak) - Lukas Kahwe Smith (lsmith) - Martin Hasoň (hason) - - Jeremy Mikola (jmikola) - Grégoire Pineau (lyrixx) + - Jeremy Mikola (jmikola) - Jean-François Simon (jfsimon) - Benjamin Eberlei (beberlei) - Igor Wiedler (igorw) - Eriksen Costa (eriksencosta) - - Jules Pietri (heah) - Maxime Steinhausser (ogizanagi) + - Jules Pietri (heah) + - Robin Chalas (chalas_r) - Sarah Khalil (saro0h) - Jonathan Wage (jwage) - Diego Saint Esteben (dosten) - - Robin Chalas (chalas_r) - Alexandre Salomé (alexandresalome) - William Durand (couac) - ornicar @@ -49,11 +49,12 @@ Symfony is the result of the work of many people who made the code better - Saša Stamenković (umpirsky) - Henrik Bjørnskov (henrikbjorn) - Miha Vrhovnik - - Diego Saint Esteben (dii3g0) - Ener-Getick (energetick) + - Diego Saint Esteben (dii3g0) - Konstantin Kudryashov (everzet) - - Bilal Amarni (bamarni) - Iltar van der Berg (kjarli) + - Roland Franssen (ro0) + - Bilal Amarni (bamarni) - Florin Patan (florinpatan) - Peter Rehm (rpet) - Kevin Bond (kbond) @@ -69,19 +70,18 @@ Symfony is the result of the work of many people who made the code better - Henrik Westphal (snc) - Dariusz Górecki (canni) - Douglas Greenshields (shieldo) + - Titouan Galopin (tgalopin) - Konstantin Myakshin (koc) - Lee McDermott - Brandon Turner - Luis Cordova (cordoval) - Graham Campbell (graham) - - Titouan Galopin (tgalopin) - Daniel Holmes (dholmes) - Pierre du Plessis (pierredup) - Toni Uebernickel (havvg) - Bart van den Burg (burgov) - Jordan Alliot (jalliot) - John Wards (johnwards) - - Roland Franssen (ro0) - Fran Moreno (franmomu) - Jáchym Toušek (enumag) - Antoine Hérault (herzult) @@ -98,6 +98,7 @@ Symfony is the result of the work of many people who made the code better - lenar - Włodzimierz Gajda (gajdaw) - Baptiste Clavié (talus) + - Maxime STEINHAUSSER - Alexander Schwenn (xelaris) - Florian Voutzinos (florianv) - Colin Frei @@ -114,13 +115,13 @@ Symfony is the result of the work of many people who made the code better - Eric GELOEN (gelo) - David Buchmann (dbu) - Tugdual Saunier (tucksaun) - - Maxime STEINHAUSSER - Théo FIDRY (theofidry) - Robert Schönthal (digitalkaoz) - Florian Lonqueu-Brochard (florianlb) - Stefano Sala (stefano.sala) - Evgeniy (ewgraf) - Juti Noppornpitak (shiroyuki) + - Tobias Nyholm (tobias) - Tigran Azatyan (tigranazatyan) - Sebastian Hörl (blogsh) - Daniel Gomes (danielcsgomes) @@ -130,12 +131,11 @@ Symfony is the result of the work of many people who made the code better - Pablo Godel (pgodel) - Jérémie Augustin (jaugustin) - Andréia Bohner (andreia) + - Yonel Ceruto González (yonelceruto) - Rafael Dohms (rdohms) - Arnaud Kleinpeter (nanocom) - jwdeitch - - Tobias Nyholm (tobias) - Joel Wurtz (brouznouf) - - Yonel Ceruto González (yonelceruto) - Philipp Wahala (hifi) - Vyacheslav Pavlov - Javier Spagnoletti (phansys) @@ -179,6 +179,7 @@ Symfony is the result of the work of many people who made the code better - fivestar - Dominique Bongiraud - Jeremy Livingston (jeremylivingston) + - Michael Lee (zerustech) - Matthieu Auger (matthieuauger) - Leszek Prabucki (l3l0) - François Zaninotto (fzaninotto) @@ -187,6 +188,7 @@ Symfony is the result of the work of many people who made the code better - John Kary (johnkary) - Justin Hileman (bobthecow) - Blanchon Vincent (blanchonvincent) + - Chris Wilkinson (thewilkybarkid) - Michele Orselli (orso) - Tom Van Looy (tvlooy) - Sven Paulus (subsven) @@ -195,6 +197,7 @@ Symfony is the result of the work of many people who made the code better - Dawid Nowak - Eugene Wissner - Julien Brochet (mewt) + - Tristan Darricau (nicofuma) - Sergey Linnik (linniksa) - Michaël Perrin (michael.perrin) - Marcel Beerta (mazen) @@ -202,7 +205,6 @@ Symfony is the result of the work of many people who made the code better - Jannik Zschiesche (apfelbox) - Marco Pivetta (ocramius) - julien pauli (jpauli) - - Michael Lee (zerustech) - Lorenz Schori - Sébastien Lavoie (lavoiesl) - Francois Zaninotto @@ -216,20 +218,20 @@ Symfony is the result of the work of many people who made the code better - Roman Marintšenko (inori) - Christian Schmidt - Xavier Montaña Carreras (xmontana) - - Chris Wilkinson (thewilkybarkid) - Mickaël Andrieu (mickaelandrieu) - Xavier Perez - Arjen Brouwer (arjenjb) - Katsuhiro OGAWA + - Patrick McDougle (patrick-mcdougle) - James Halsall (jaitsu) - Alif Rachmawadi - Kristen Gilden (kgilden) + - SpacePossum - Pierre-Yves LEBECQ (pylebecq) - Alex Pott - Jakub Kucharovic (jkucharovic) - Eugene Leonovich (rybakit) - Filippo Tessarotto - - Tristan Darricau (nicofuma) - Joseph Rouff (rouffj) - Félix Labrecque (woodspire) - GordonsLondon @@ -259,7 +261,6 @@ Symfony is the result of the work of many people who made the code better - Peter Kruithof (pkruithof) - Michael Holm (hollo) - Marc Weistroff (futurecat) - - SpacePossum - Hidde Wieringa (hiddewie) - Chris Smith (cs278) - Florian Klein (docteurklein) @@ -278,12 +279,14 @@ Symfony is the result of the work of many people who made the code better - Ismael Ambrosi (iambrosi) - Uwe Jäger (uwej711) - Aurelijus Valeiša (aurelijus) + - Victor Bocharsky (bocharsky_bw) - Jan Decavele (jandc) - Gustavo Piltcher - Stepan Tanasiychuk (stfalcon) - Tiago Ribeiro (fixe) - Hidde Boomsma (hboomsma) - John Bafford (jbafford) + - Pavel Batanov (scaytrase) - Bob den Otter (bopp) - Adrian Rudnik (kreischweide) - Francesc Rosàs (frosas) @@ -304,6 +307,7 @@ Symfony is the result of the work of many people who made the code better - Matthew Lewinski (lewinski) - Magnus Nordlander (magnusnordlander) - alquerci + - Adam Prager (padam87) - Francesco Levorato - Vitaliy Zakharov (zakharovvi) - Tobias Sjösten (tobiassjosten) @@ -324,6 +328,7 @@ Symfony is the result of the work of many people who made the code better - Clément Gautier (clementgautier) - Eduardo Gulias (egulias) - giulio de donato (liuggio) + - ShinDarth - Stéphane PY (steph_py) - Philipp Kräutli (pkraeutli) - Kirill chEbba Chebunin (chebba) @@ -336,9 +341,9 @@ Symfony is the result of the work of many people who made the code better - Hassan Amouhzi - Tamas Szijarto - Pavel Volokitin (pvolok) + - François Pluchino (francoispluchino) - Nicolas Dewez (nicolas_dewez) - Endre Fejes - - Victor Bocharsky (bocharsky_bw) - Tobias Naumann (tna) - Daniel Beyer - Shein Alexey @@ -355,7 +360,6 @@ Symfony is the result of the work of many people who made the code better - Xavier HAUSHERR - Albert Jessurum (ajessu) - Laszlo Korte - - Pavel Batanov (scaytrase) - Miha Vrhovnik - Alessandro Desantis - hubert lecorche (hlecorche) @@ -412,6 +416,7 @@ Symfony is the result of the work of many people who made the code better - boombatower - Fabrice Bernhard (fabriceb) - Jérôme Macias (jeromemacias) + - Andrey Astakhov (aast) - Fabian Lange (codingfabian) - Frank Neff (fneff) - Roman Lapin (memphys) @@ -422,6 +427,7 @@ Symfony is the result of the work of many people who made the code better - Pablo Díez (pablodip) - Kevin McBride - Sergio Santoro + - Robin van der Vleuten (robinvdvleuten) - Philipp Rieber (bicpi) - Manuel de Ruiter (manuel) - Eduardo Oliveira (entering) @@ -478,7 +484,6 @@ Symfony is the result of the work of many people who made the code better - Alexander Deruwe (aderuwe) - Alain Hippolyte (aloneh) - Dave Hulbert (dave1010) - - François Pluchino (francoispluchino) - Ivan Rey (ivanrey) - Marcin Chyłek (songoq) - Ned Schwartz @@ -512,6 +517,7 @@ Symfony is the result of the work of many people who made the code better - Konstantin S. M. Möllers (ksmmoellers) - Sinan Eldem - Alexandre Dupuy (satchette) + - Rob Frawley 2nd - Nahuel Cuesta (ncuesta) - Chris Boden (cboden) - Asmir Mustafic (goetas) @@ -522,6 +528,7 @@ Symfony is the result of the work of many people who made the code better - Åsmund Garfors - Maxime Douailin - Jean Pasdeloup (pasdeloup) + - Benjamin Cremer (bcremer) - Javier López (loalf) - Andreas Braun - Reinier Kip @@ -551,7 +558,6 @@ Symfony is the result of the work of many people who made the code better - umpirski - Chris Heng (gigablah) - Ulumuddin Yunus (joenoez) - - Adam Prager (padam87) - Luc Vieillescazes (iamluc) - Johann Saunier (prophet777) - Samuel ROZE (sroze) @@ -586,6 +592,7 @@ Symfony is the result of the work of many people who made the code better - develop - ReenExe - Mark Sonnabaum + - Thomas Royer (cydonia7) - Richard Quadling - jochenvdv - Arturas Smorgun (asarturas) @@ -593,6 +600,7 @@ Symfony is the result of the work of many people who made the code better - Michael Piecko - yclian - twifty + - Indra Gunawan (guind) - Peter Ward - Julien DIDIER (juliendidier) - Dominik Ritter (dritter) @@ -600,10 +608,10 @@ Symfony is the result of the work of many people who made the code better - Martin Hujer (martinhujer) - Pascal Helfenstein - Baldur Rensch (brensch) + - Thomas Calvet - Vladyslav Petrovych - Alex Xandra Albert Sim - Carson Full - - Andrey Astakhov (aast) - Trent Steel (trsteel88) - Yuen-Chi Lian - Besnik Br @@ -630,11 +638,13 @@ Symfony is the result of the work of many people who made the code better - Christian Soronellas (theunic) - Romain Gautier (mykiwi) - Yosmany Garcia (yosmanyga) + - Wouter J - Wouter de Wild - Miroslav Sustek - Degory Valentine - Benoit Lévêque (benoit_leveque) - Jeroen Fiege (fieg) + - Arthur de Moulins (4rthem) - Krzysiek Łabuś - Xavier Lacot (xavier) - possum @@ -642,6 +652,7 @@ Symfony is the result of the work of many people who made the code better - Olivier Maisonneuve (olineuve) - Masterklavi - Francis Turmel (fturmel) + - Nikita Nefedov (nikita2206) - cgonzalez - Ben - Jayson Xu (superjavason) @@ -683,8 +694,10 @@ Symfony is the result of the work of many people who made the code better - Ivan Menshykov - David Romaní - Patrick Allaert + - Fabien Bourigault (fbourigault) - Gustavo Falco (gfalco) - Matt Robinson (inanimatt) + - Ruud Kamphuis (ruudk) - Aleksey Podskrebyshev - Calin Mihai Pristavu - David Marín Carreño (davefx) @@ -734,7 +747,6 @@ Symfony is the result of the work of many people who made the code better - Mikhail Yurasov (mym) - LOUARDI Abdeltif (ouardisoft) - Robert Gruendler (pulse00) - - Robin van der Vleuten (robinvdvleuten) - Simon Terrien (sterrien) - Benoît Merlet (trompette) - Koen Kuipers @@ -763,6 +775,7 @@ Symfony is the result of the work of many people who made the code better - Colin O'Dell (colinodell) - xaav - Mahmoud Mostafa (mahmoud) + - Alessandro Lai - Pieter - Michael Tibben - Sander Marechal @@ -811,8 +824,10 @@ Symfony is the result of the work of many people who made the code better - Nicolas Macherey - Lin Clark - Jeremy David (jeremy.david) + - Denis Brumann (dbrumann) - Troy McCabe - Ville Mattila + - ilyes kooli - Boris Vujicic (boris.vujicic) - Max Beutel - Antanas Arvasevicius @@ -832,6 +847,7 @@ Symfony is the result of the work of many people who made the code better - Christian - Sergii Smertin (nfx) - hugofonseca (fonsecas72) + - Martynas Narbutas - Bailey Parker - Eddie Jaoude - Haritz Iturbe (hizai) @@ -846,7 +862,6 @@ Symfony is the result of the work of many people who made the code better - Alex Demchenko (pilot) - Tadas Gliaubicas (tadcka) - Benoit Garret - - Thomas Royer (cydonia7) - DerManoMann - Olaf Klischat - orlovv @@ -867,7 +882,6 @@ Symfony is the result of the work of many people who made the code better - rpg600 - Péter Buri (burci) - Davide Borsatto (davide.borsatto) - - Indra Gunawan (guind) - kaiwa - Charles Sanquer (csanquer) - Albert Ganiev (helios-ag) @@ -909,6 +923,7 @@ Symfony is the result of the work of many people who made the code better - Krzysztof Przybyszewski - Paul Matthews - Juan Traverso + - Tarjei Huse (tarjei) - Philipp Strube - Christian Sciberras - Clement Herreman (clemherreman) @@ -919,7 +934,6 @@ Symfony is the result of the work of many people who made the code better - Alberto Aldegheri - heccjj - Alexandre Melard - - Thomas Calvet - Sergey Yuferev - Tobias Stöckler - Mario Young @@ -973,6 +987,7 @@ Symfony is the result of the work of many people who made the code better - Samuel Vogel (samuelvogel) - Berat Doğan - Juanmi Rodriguez Cerón + - Andy Raines - Anthony Ferrara - Klaas Cuvelier (kcuvelier) - Steve Frécinaux @@ -998,6 +1013,7 @@ Symfony is the result of the work of many people who made the code better - Alberto Pirovano (geezmo) - Pete Mitchell (peterjmit) - Tom Corrigan (tomcorrigan) + - Luis Galeas - Martin Pärtel - Noah Heck (myesain) - Patrick Daley (padrig) @@ -1014,7 +1030,6 @@ Symfony is the result of the work of many people who made the code better - Romain Geissler - Adrien Moiruad - Tomaz Ahlin - - Benjamin Cremer (bcremer) - Marcus Stöhr (dafish) - Emmanuel Vella (emmanuel.vella) - Carsten Nielsen (phreaknerd) @@ -1036,6 +1051,7 @@ Symfony is the result of the work of many people who made the code better - Damien Tournoud - Jon Gotlin (jongotlin) - Michael Dowling (mtdowling) + - Karlos Presumido (oneko) - BilgeXA - r1pp3rj4ck - Robert Queck @@ -1073,7 +1089,6 @@ Symfony is the result of the work of many people who made the code better - kor3k kor3k (kor3k) - Stelian Mocanita (stelian) - Flavian (2much) - - Arthur de Moulins (4rthem) - mike - Keith Maika - Mephistofeles @@ -1164,6 +1179,7 @@ Symfony is the result of the work of many people who made the code better - Julius Beckmann - Romain Dorgueil - Grayson Koonce (breerly) + - Fabien LUCAS (flucas2) - Karim Cassam Chenaï (ka) - Nicolas Bastien (nicolas_bastien) - Denis (yethee) @@ -1212,7 +1228,6 @@ Symfony is the result of the work of many people who made the code better - Bram Van der Sype (brammm) - Guile (guile) - Julien Moulin (lizjulien) - - Nikita Nefedov (nikita2206) - Mauro Foti (skler) - Yannick Warnier (ywarnier) - Kevin Decherf @@ -1235,7 +1250,9 @@ Symfony is the result of the work of many people who made the code better - Tischoi - J Bruni - Alexey Prilipko + - vlakoff - bertillon + - Bertalan Attila - Yannick Bensacq (cibou) - Luca Genuzio (genuzio) - Hans Nilsson (hansnilsson) @@ -1254,7 +1271,6 @@ Symfony is the result of the work of many people who made the code better - Joel Marcey - David Christmann - root - - Wouter J - James Hudson - Tom Maguire - David Zuelke @@ -1309,9 +1325,9 @@ Symfony is the result of the work of many people who made the code better - ddebree - Tomas Liubinas - Alex + - Patrick Dawkins - Klaas Naaijkens - Daniel González Cerviño - - ShinDarth - Rafał - Adria Lopez (adlpz) - Rosio (ben-rosio) @@ -1338,9 +1354,9 @@ Symfony is the result of the work of many people who made the code better - Michael Pohlers (mick_the_big) - Cayetano Soriano Gallego (neoshadybeat) - Ondrej Machulda (ondram) - - Patrick McDougle (patrick-mcdougle) - Pablo Monterde Perez (plebs) - Jimmy Leger (redpanda) + - Marcin Szepczynski (szepczynski) - Cyrille Jouineau (tuxosaurus) - Yorkie Chadwick (yorkie76) - Yanick Witschi @@ -1363,6 +1379,7 @@ Symfony is the result of the work of many people who made the code better - Arnaud Buathier (arnapou) - chesteroni (chesteroni) - Mauricio Lopez (diaspar) + - HADJEDJ Vincent (hadjedjvincent) - Daniele Cesarini (ijanki) - Ismail Asci (ismailasci) - Simon CONSTANS (kosssi) @@ -1505,7 +1522,6 @@ Symfony is the result of the work of many people who made the code better - Damián Nohales (eagleoneraptor) - Elliot Anderson (elliot) - Fabien D. (fabd) - - Fabien Bourigault (fbourigault) - Carsten Eilers (fnc) - Sorin Gitlan (forapathy) - Yohan Giarelli (frequence-web) @@ -1549,7 +1565,6 @@ Symfony is the result of the work of many people who made the code better - Daniel Perez Pinazo (pitiflautico) - Brayden Williams (redstar504) - Rich Sage (richsage) - - Ruud Kamphuis (ruudk) - Bart Ruysseveldt (ruyss) - Sascha Dens (saschadens) - scourgen hung (scourgen) diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index 866bd981cce79..cda0f4a0f5399 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -1907,3 +1907,9 @@ UPGRADE FROM 2.x to 3.0 ```php $request->query->get('foo')['bar']; ``` +### Monolog Bridge + + * `Symfony\Bridge\Monolog\Logger::emerg()` was removed. Use `emergency()` which is PSR-3 compatible. + * `Symfony\Bridge\Monolog\Logger::crit()` was removed. Use `critical()` which is PSR-3 compatible. + * `Symfony\Bridge\Monolog\Logger::err()` was removed. Use `error()` which is PSR-3 compatible. + * `Symfony\Bridge\Monolog\Logger::warn()` was removed. Use `warning()` which is PSR-3 compatible. diff --git a/composer.json b/composer.json index 9677a86460fbe..a1302a6737292 100644 --- a/composer.json +++ b/composer.json @@ -90,7 +90,8 @@ "symfony/phpunit-bridge": "~3.2", "symfony/polyfill-apcu": "~1.1", "symfony/security-acl": "~2.8|~3.0", - "phpdocumentor/reflection-docblock": "^3.0" + "phpdocumentor/reflection-docblock": "^3.0", + "sensio/framework-extra-bundle": "^3.0.2" }, "conflict": { "phpdocumentor/reflection-docblock": "<3.0", @@ -116,6 +117,9 @@ "**/Tests/" ] }, + "autoload-dev": { + "files": [ "src/Symfony/Component/VarDumper/Resources/functions/dump.php" ] + }, "minimum-stability": "dev", "extra": { "branch-alias": { diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmExtension.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmExtension.php index ed8e0a793444c..fe86b103cbb34 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmExtension.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmExtension.php @@ -14,38 +14,20 @@ use Doctrine\Common\Persistence\ManagerRegistry; use Symfony\Bridge\Doctrine\Form\Type\EntityType; use Symfony\Component\Form\AbstractExtension; -use Symfony\Component\Form\ChoiceList\Factory\CachingFactoryDecorator; -use Symfony\Component\Form\ChoiceList\Factory\ChoiceListFactoryInterface; -use Symfony\Component\Form\ChoiceList\Factory\DefaultChoiceListFactory; -use Symfony\Component\Form\ChoiceList\Factory\PropertyAccessDecorator; -use Symfony\Component\PropertyAccess\PropertyAccess; -use Symfony\Component\PropertyAccess\PropertyAccessorInterface; class DoctrineOrmExtension extends AbstractExtension { protected $registry; - /** - * @var PropertyAccessorInterface - */ - private $propertyAccessor; - - /** - * @var ChoiceListFactoryInterface - */ - private $choiceListFactory; - - public function __construct(ManagerRegistry $registry, PropertyAccessorInterface $propertyAccessor = null, ChoiceListFactoryInterface $choiceListFactory = null) + public function __construct(ManagerRegistry $registry) { $this->registry = $registry; - $this->propertyAccessor = $propertyAccessor ?: PropertyAccess::createPropertyAccessor(); - $this->choiceListFactory = $choiceListFactory ?: new CachingFactoryDecorator(new PropertyAccessDecorator(new DefaultChoiceListFactory(), $this->propertyAccessor)); } protected function loadTypes() { return array( - new EntityType($this->registry, $this->propertyAccessor, $this->choiceListFactory), + new EntityType($this->registry), ); } diff --git a/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/CompilerPass/RegisterMappingsPassTest.php b/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/CompilerPass/RegisterMappingsPassTest.php index c86ef117753eb..85e35f9b1fc7c 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/CompilerPass/RegisterMappingsPassTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/CompilerPass/RegisterMappingsPassTest.php @@ -15,7 +15,6 @@ class RegisterMappingsPassTest extends \PHPUnit_Framework_TestCase public function testNoDriverParmeterException() { $container = $this->createBuilder(array( - )); $this->process($container, array( 'manager.param.one', diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/CompositeObjectNoToStringIdEntity.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/CompositeObjectNoToStringIdEntity.php new file mode 100644 index 0000000000000..ac97367094bd5 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/CompositeObjectNoToStringIdEntity.php @@ -0,0 +1,53 @@ +objectOne = $objectOne; + $this->objectTwo = $objectTwo; + } + + /** + * @return SingleIntIdNoToStringEntity + */ + public function getObjectOne() + { + return $this->objectOne; + } + + /** + * @return SingleIntIdNoToStringEntity + */ + public function getObjectTwo() + { + return $this->objectTwo; + } +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php index a54f8d438610a..2881ed5f723e2 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php @@ -19,6 +19,7 @@ use Symfony\Bridge\Doctrine\Test\TestRepositoryFactory; use Symfony\Bridge\Doctrine\Tests\Fixtures\Employee; use Symfony\Bridge\Doctrine\Tests\Fixtures\Person; +use Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeObjectNoToStringIdEntity; use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity; use Symfony\Bridge\Doctrine\Tests\Fixtures\DoubleNameEntity; use Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity; @@ -146,6 +147,7 @@ private function createSchema(ObjectManager $em) $em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity2'), $em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\Person'), $em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\Employee'), + $em->getClassMetadata('Symfony\Bridge\Doctrine\Tests\Fixtures\CompositeObjectNoToStringIdEntity'), )); } @@ -179,7 +181,7 @@ public function testValidateUniqueness() $this->buildViolation('myMessage') ->atPath('property.path.name') ->setParameter('{{ value }}', '"Foo"') - ->setInvalidValue('Foo') + ->setInvalidValue($entity2) ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); } @@ -204,7 +206,7 @@ public function testValidateCustomErrorPath() $this->buildViolation('myMessage') ->atPath('property.path.bar') ->setParameter('{{ value }}', '"Foo"') - ->setInvalidValue('Foo') + ->setInvalidValue($entity2) ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); } @@ -262,6 +264,23 @@ public function testValidateUniquenessWithIgnoreNull() ->assertRaised(); } + /** + * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException + */ + public function testAllConfiguredFieldsAreCheckedOfBeingMappedByDoctrineWithIgnoreNullEnabled() + { + $constraint = new UniqueEntity(array( + 'message' => 'myMessage', + 'fields' => array('name', 'name2'), + 'em' => self::EM_NAME, + 'ignoreNull' => true, + )); + + $entity1 = new SingleIntIdEntity(1, null); + + $this->validator->validate($entity1, $constraint); + } + public function testValidateUniquenessWithValidCustomErrorPath() { $constraint = new UniqueEntity(array( @@ -423,7 +442,7 @@ public function testAssociatedEntity() $this->buildViolation('myMessage') ->atPath('property.path.single') - ->setParameter('{{ value }}', $entity1) + ->setParameter('{{ value }}', 'object("Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity") identified by (id => 1)') ->setInvalidValue($entity1) ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); @@ -456,12 +475,12 @@ public function testValidateUniquenessNotToStringEntityWithAssociatedEntity() $this->validator->validate($associated2, $constraint); - $expectedValue = 'Object of class "Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity2" identified by "2"'; + $expectedValue = 'object("Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdNoToStringEntity") identified by (id => 1)'; $this->buildViolation('myMessage') ->atPath('property.path.single') - ->setParameter('{{ value }}', '"'.$expectedValue.'"') - ->setInvalidValue($expectedValue) + ->setParameter('{{ value }}', $expectedValue) + ->setInvalidValue($entity1) ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); } @@ -617,4 +636,38 @@ public function testInvalidateRepositoryForInheritance() $entity = new Person(1, 'Foo'); $this->validator->validate($entity, $constraint); } + + public function testValidateUniquenessWithCompositeObjectNoToStringIdEntity() + { + $constraint = new UniqueEntity(array( + 'message' => 'myMessage', + 'fields' => array('objectOne', 'objectTwo'), + 'em' => self::EM_NAME, + )); + + $objectOne = new SingleIntIdNoToStringEntity(1, 'foo'); + $objectTwo = new SingleIntIdNoToStringEntity(2, 'bar'); + + $this->em->persist($objectOne); + $this->em->persist($objectTwo); + $this->em->flush(); + + $entity = new CompositeObjectNoToStringIdEntity($objectOne, $objectTwo); + + $this->em->persist($entity); + $this->em->flush(); + + $newEntity = new CompositeObjectNoToStringIdEntity($objectOne, $objectTwo); + + $this->validator->validate($newEntity, $constraint); + + $expectedValue = 'object("Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdNoToStringEntity") identified by (id => 1)'; + + $this->buildViolation('myMessage') + ->atPath('property.path.objectOne') + ->setParameter('{{ value }}', $expectedValue) + ->setInvalidValue($objectOne) + ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) + ->assertRaised(); + } } diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php index 9867a2779f61a..b079770c6b3d6 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php +++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php @@ -12,6 +12,8 @@ namespace Symfony\Bridge\Doctrine\Validator\Constraints; use Doctrine\Common\Persistence\ManagerRegistry; +use Doctrine\Common\Persistence\Mapping\ClassMetadata; +use Doctrine\Common\Persistence\ObjectManager; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Exception\ConstraintDefinitionException; @@ -84,12 +86,14 @@ public function validate($entity, Constraint $constraint) throw new ConstraintDefinitionException(sprintf('The field "%s" is not mapped by Doctrine, so it cannot be validated for uniqueness.', $fieldName)); } - $criteria[$fieldName] = $class->reflFields[$fieldName]->getValue($entity); + $fieldValue = $class->reflFields[$fieldName]->getValue($entity); - if ($constraint->ignoreNull && null === $criteria[$fieldName]) { - return; + if ($constraint->ignoreNull && null === $fieldValue) { + continue; } + $criteria[$fieldName] = $fieldValue; + if (null !== $criteria[$fieldName] && $class->hasAssociation($fieldName)) { /* Ensure the Proxy is initialized before using reflection to * read its identifiers. This is necessary because the wrapped @@ -99,6 +103,12 @@ public function validate($entity, Constraint $constraint) } } + // skip validation if there are no criteria (this can happen when the + // "ignoreNull" option is enabled and fields to be checked are null + if (empty($criteria)) { + return; + } + if (null !== $constraint->entityClass) { /* Retrieve repository from given entity name. * We ensure the retrieved repository can handle the entity @@ -141,15 +151,41 @@ public function validate($entity, Constraint $constraint) $errorPath = null !== $constraint->errorPath ? $constraint->errorPath : $fields[0]; $invalidValue = isset($criteria[$errorPath]) ? $criteria[$errorPath] : $criteria[$fields[0]]; - if (is_object($invalidValue) && !method_exists($invalidValue, '__toString')) { - $invalidValue = sprintf('Object of class "%s" identified by "%s"', get_class($entity), implode(', ', $class->getIdentifierValues($entity))); - } - $this->context->buildViolation($constraint->message) ->atPath($errorPath) - ->setParameter('{{ value }}', $this->formatValue($invalidValue, static::OBJECT_TO_STRING | static::PRETTY_DATE)) + ->setParameter('{{ value }}', $this->formatWithIdentifiers($em, $class, $invalidValue)) ->setInvalidValue($invalidValue) ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->addViolation(); } + + private function formatWithIdentifiers(ObjectManager $em, ClassMetadata $class, $value) + { + if (!is_object($value) || $value instanceof \DateTimeInterface) { + return $this->formatValue($value, self::PRETTY_DATE); + } + + // non unique value is a composite PK + if ($class->getName() !== $idClass = get_class($value)) { + $identifiers = $em->getClassMetadata($idClass)->getIdentifierValues($value); + } else { + $identifiers = $class->getIdentifierValues($value); + } + + if (!$identifiers) { + return sprintf('object("%s")', $idClass); + } + + array_walk($identifiers, function (&$id, $field) { + if (!is_object($id) || $id instanceof \DateTimeInterface) { + $idAsString = $this->formatValue($id, self::PRETTY_DATE); + } else { + $idAsString = sprintf('object("%s")', get_class($id)); + } + + $id = sprintf('%s => %s', $field, $idAsString); + }); + + return sprintf('object("%s") identified by (%s)', $idClass, implode(', ', $identifiers)); + } } diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php index ca85d8aba5994..831a26adaacaa 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php @@ -141,7 +141,7 @@ public static function register($mode = 0) return "\x1B[{$color}m{$str}\x1B[0m"; }; } else { - $colorize = function ($str) {return $str;}; + $colorize = function ($str) { return $str; }; } register_shutdown_function(function () use ($getMode, &$deprecations, $deprecationHandler, $colorize) { $mode = $getMode(); @@ -152,7 +152,7 @@ public static function register($mode = 0) restore_error_handler(); if (DeprecationErrorHandler::MODE_WEAK === $mode) { - $colorize = function ($str) {return $str;}; + $colorize = function ($str) { return $str; }; } if ($currErrorHandler !== $deprecationHandler) { echo "\n", $colorize('THE ERROR HANDLER HAS CHANGED!', true), "\n"; diff --git a/src/Symfony/Bridge/PhpUnit/SymfonyTestsListener.php b/src/Symfony/Bridge/PhpUnit/SymfonyTestsListener.php index 3ebe6e0839ba3..843522a0fc822 100644 --- a/src/Symfony/Bridge/PhpUnit/SymfonyTestsListener.php +++ b/src/Symfony/Bridge/PhpUnit/SymfonyTestsListener.php @@ -34,6 +34,7 @@ class SymfonyTestsListener extends \PHPUnit_Framework_BaseTestListener */ public function __construct(array $mockedNamespaces = array()) { + \PHPUnit_Util_Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\DeprecationErrorHandler'] = 1; \PHPUnit_Util_Blacklist::$blacklistedClassNames['\Symfony\Bridge\PhpUnit\SymfonyTestsListener'] = 1; $warn = false; diff --git a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit index 49a610ed14a6e..331ff8a02c686 100755 --- a/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit +++ b/src/Symfony/Bridge/PhpUnit/bin/simple-phpunit @@ -43,6 +43,9 @@ if (!file_exists("$PHPUNIT_DIR/phpunit-$PHPUNIT_VERSION/phpunit") || md5_file(__ @unlink("$PHPUNIT_VERSION.zip"); passthru("wget https://github.com/sebastianbergmann/phpunit/archive/$PHPUNIT_VERSION.zip"); } + if (!class_exists('ZipArchive')) { + throw new \Exception('simple-phpunit requires the "zip" PHP extension to be installed and enabled in order to uncompress the downloaded PHPUnit packages.'); + } $zip = new ZipArchive(); $zip->open("$PHPUNIT_VERSION.zip"); $zip->extractTo(getcwd()); diff --git a/src/Symfony/Bridge/PhpUnit/composer.json b/src/Symfony/Bridge/PhpUnit/composer.json index 1cf3ef04318e5..2d6a866742042 100644 --- a/src/Symfony/Bridge/PhpUnit/composer.json +++ b/src/Symfony/Bridge/PhpUnit/composer.json @@ -21,7 +21,8 @@ "php": ">=5.3.3" }, "suggest": { - "symfony/debug": "For tracking deprecated interfaces usages at runtime with DebugClassLoader" + "symfony/debug": "For tracking deprecated interfaces usages at runtime with DebugClassLoader", + "ext-zip": "Zip support is required when using bin/simple-phpunit" }, "autoload": { "files": [ "bootstrap.php" ], diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service.php b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service.php index fe98c150f71a2..77e04571e089c 100644 --- a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service.php +++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service.php @@ -122,9 +122,6 @@ public function __unset($name) unset($this->valueHolder5157dd96e88c0->$name); } - /** - * - */ public function __clone() { $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__clone', array()); @@ -132,9 +129,6 @@ public function __clone() $this->valueHolder5157dd96e88c0 = clone $this->valueHolder5157dd96e88c0; } - /** - * - */ public function __sleep() { $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__sleep', array()); @@ -142,9 +136,6 @@ public function __sleep() return array('valueHolder5157dd96e88c0'); } - /** - * - */ public function __wakeup() { } diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_with_hints.php b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_with_hints.php index 12409e8e637bf..6787b9ff8ed45 100644 --- a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_with_hints.php +++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_with_hints.php @@ -122,9 +122,6 @@ public function __unset($name) unset($this->valueHolder5157dd96e88c0->$name); } - /** - * - */ public function __clone() { $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__clone', array()); @@ -132,9 +129,6 @@ public function __clone() $this->valueHolder5157dd96e88c0 = clone $this->valueHolder5157dd96e88c0; } - /** - * - */ public function __sleep() { $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, '__sleep', array()); @@ -142,9 +136,6 @@ public function __sleep() return array('valueHolder5157dd96e88c0'); } - /** - * - */ public function __wakeup() { } @@ -168,7 +159,7 @@ public function getProxyInitializer() /** * {@inheritdoc} */ - public function initializeProxy() : bool + public function initializeProxy(): bool { return $this->initializer5157dd96e8924 && $this->initializer5157dd96e8924->__invoke($this->valueHolder5157dd96e88c0, $this, 'initializeProxy', array()); } @@ -176,7 +167,7 @@ public function initializeProxy() : bool /** * {@inheritdoc} */ - public function isProxyInitialized() : bool + public function isProxyInitialized(): bool { return null !== $this->valueHolder5157dd96e88c0; } diff --git a/src/Symfony/Bridge/Twig/Command/DebugCommand.php b/src/Symfony/Bridge/Twig/Command/DebugCommand.php index 44e23902e03de..d871a682f0a4c 100644 --- a/src/Symfony/Bridge/Twig/Command/DebugCommand.php +++ b/src/Symfony/Bridge/Twig/Command/DebugCommand.php @@ -140,7 +140,7 @@ private function getMetadata($type, $entity) } if ($type === 'functions' || $type === 'filters') { $cb = $entity->getCallable(); - if (is_null($cb)) { + if (null === $cb) { return; } if (is_array($cb)) { diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/DumpExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/DumpExtensionTest.php index 1d864eadd9faf..1024bbe0fdec5 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/DumpExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/DumpExtensionTest.php @@ -33,7 +33,7 @@ public function testDumpTag($template, $debug, $expectedOutput, $expectedDumped) $dumped = null; $exception = null; - $prevDumper = VarDumper::setHandler(function ($var) use (&$dumped) {$dumped = $var;}); + $prevDumper = VarDumper::setHandler(function ($var) use (&$dumped) { $dumped = $var; }); try { $this->assertEquals($expectedOutput, $twig->render('template')); diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php index 99adb3831b776..3471f7d07507d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/JsonDescriptor.php @@ -208,25 +208,17 @@ private function getContainerDefinitionData(Definition $definition, $omitTags = 'public' => $definition->isPublic(), 'synthetic' => $definition->isSynthetic(), 'lazy' => $definition->isLazy(), + 'shared' => $definition->isShared(), + 'abstract' => $definition->isAbstract(), + 'autowire' => $definition->isAutowired(), + 'autowiring_types' => array(), + 'file' => $definition->getFile(), ); - if (method_exists($definition, 'isShared')) { - $data['shared'] = $definition->isShared(); + foreach ($definition->getAutowiringTypes() as $autowiringType) { + $data['autowiring_types'][] = $autowiringType; } - $data['abstract'] = $definition->isAbstract(); - - if (method_exists($definition, 'isAutowired')) { - $data['autowire'] = $definition->isAutowired(); - - $data['autowiring_types'] = array(); - foreach ($definition->getAutowiringTypes() as $autowiringType) { - $data['autowiring_types'][] = $autowiringType; - } - } - - $data['file'] = $definition->getFile(); - if ($factory = $definition->getFactory()) { if (is_array($factory)) { if ($factory[0] instanceof Reference) { @@ -252,11 +244,9 @@ private function getContainerDefinitionData(Definition $definition, $omitTags = if (!$omitTags) { $data['tags'] = array(); - if (count($definition->getTags())) { - foreach ($definition->getTags() as $tagName => $tagData) { - foreach ($tagData as $parameters) { - $data['tags'][] = array('name' => $tagName, 'parameters' => $parameters); - } + foreach ($definition->getTags() as $tagName => $tagData) { + foreach ($tagData as $parameters) { + $data['tags'][] = array('name' => $tagName, 'parameters' => $parameters); } } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php index 5c91fa3bf9ad2..43771d4f70e52 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/MarkdownDescriptor.php @@ -179,20 +179,13 @@ protected function describeContainerDefinition(Definition $definition, array $op ."\n".'- Public: '.($definition->isPublic() ? 'yes' : 'no') ."\n".'- Synthetic: '.($definition->isSynthetic() ? 'yes' : 'no') ."\n".'- Lazy: '.($definition->isLazy() ? 'yes' : 'no') + ."\n".'- Shared: '.($definition->isShared() ? 'yes' : 'no') + ."\n".'- Abstract: '.($definition->isAbstract() ? 'yes' : 'no') + ."\n".'- Autowired: '.($definition->isAutowired() ? 'yes' : 'no') ; - if (method_exists($definition, 'isShared')) { - $output .= "\n".'- Shared: '.($definition->isShared() ? 'yes' : 'no'); - } - - $output .= "\n".'- Abstract: '.($definition->isAbstract() ? 'yes' : 'no'); - - if (method_exists($definition, 'isAutowired')) { - $output .= "\n".'- Autowired: '.($definition->isAutowired() ? 'yes' : 'no'); - - foreach ($definition->getAutowiringTypes() as $autowiringType) { - $output .= "\n".'- Autowiring Type: `'.$autowiringType.'`'; - } + foreach ($definition->getAutowiringTypes() as $autowiringType) { + $output .= "\n" . '- Autowiring Type: `' . $autowiringType . '`'; } if ($definition->getFile()) { @@ -230,7 +223,7 @@ protected function describeContainerDefinition(Definition $definition, array $op } } - $this->write(isset($options['id']) ? sprintf("%s\n%s\n\n%s\n", $options['id'], str_repeat('~', strlen($options['id'])), $output) : $output); + $this->write(isset($options['id']) ? sprintf("### %s\n\n%s\n", $options['id'], $output) : $output); } /** @@ -241,7 +234,7 @@ protected function describeContainerAlias(Alias $alias, array $options = array() $output = '- Service: `'.$alias.'`' ."\n".'- Public: '.($alias->isPublic() ? 'yes' : 'no'); - $this->write(isset($options['id']) ? sprintf("%s\n%s\n\n%s\n", $options['id'], str_repeat('~', strlen($options['id'])), $output) : $output); + $this->write(isset($options['id']) ? sprintf("### %s\n\n%s\n", $options['id'], $output) : $output); } /** @@ -356,7 +349,7 @@ protected function describeCallable($callable, array $options = array()) */ private function formatRouterConfig(array $array) { - if (!count($array)) { + if (!$array) { return 'NONE'; } diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php index 7d876eb71336a..93f1194072465 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/TextDescriptor.php @@ -252,8 +252,7 @@ protected function describeContainerDefinition(Definition $definition, array $op $tableRows[] = array('Service ID', isset($options['id']) ? $options['id'] : '-'); $tableRows[] = array('Class', $definition->getClass() ?: '-'); - $tags = $definition->getTags(); - if (count($tags)) { + if ($tags = $definition->getTags()) { $tagInformation = ''; foreach ($tags as $tagName => $tagData) { foreach ($tagData as $tagParameters) { @@ -286,23 +285,12 @@ protected function describeContainerDefinition(Definition $definition, array $op $tableRows[] = array('Public', $definition->isPublic() ? 'yes' : 'no'); $tableRows[] = array('Synthetic', $definition->isSynthetic() ? 'yes' : 'no'); $tableRows[] = array('Lazy', $definition->isLazy() ? 'yes' : 'no'); - if (method_exists($definition, 'isShared')) { - $tableRows[] = array('Shared', $definition->isShared() ? 'yes' : 'no'); - } + $tableRows[] = array('Shared', $definition->isShared() ? 'yes' : 'no'); $tableRows[] = array('Abstract', $definition->isAbstract() ? 'yes' : 'no'); + $tableRows[] = array('Autowired', $definition->isAutowired() ? 'yes' : 'no'); - if (method_exists($definition, 'isAutowired')) { - $tableRows[] = array('Autowired', $definition->isAutowired() ? 'yes' : 'no'); - - $autowiringTypes = $definition->getAutowiringTypes(); - if (count($autowiringTypes)) { - $autowiringTypesInformation = implode(', ', $autowiringTypes); - } else { - $autowiringTypesInformation = '-'; - } - - $tableRows[] = array('Autowiring Types', $autowiringTypesInformation); - } + $autowiringTypes = $definition->getAutowiringTypes(); + $tableRows[] = array('Autowiring Types', $autowiringTypes ? implode(', ', $autowiringTypes) : '-'); if ($definition->getFile()) { $tableRows[] = array('Required File', $definition->getFile() ? $definition->getFile() : '-'); diff --git a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php index 7d7d5f0956ed4..2c0b7d1669cbb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Console/Descriptor/XmlDescriptor.php @@ -187,7 +187,7 @@ private function getRouteDocument(Route $route, $name = null) $methodXML->appendChild(new \DOMText($method)); } - if (count($route->getDefaults())) { + if ($route->getDefaults()) { $routeXML->appendChild($defaultsXML = $dom->createElement('defaults')); foreach ($route->getDefaults() as $attribute => $value) { $defaultsXML->appendChild($defaultXML = $dom->createElement('default')); @@ -196,16 +196,18 @@ private function getRouteDocument(Route $route, $name = null) } } - if (count($route->getRequirements())) { + $originRequirements = $requirements = $route->getRequirements(); + unset($requirements['_scheme'], $requirements['_method']); + if ($requirements) { $routeXML->appendChild($requirementsXML = $dom->createElement('requirements')); - foreach ($route->getRequirements() as $attribute => $pattern) { + foreach ($originRequirements as $attribute => $pattern) { $requirementsXML->appendChild($requirementXML = $dom->createElement('requirement')); $requirementXML->setAttribute('key', $attribute); $requirementXML->appendChild(new \DOMText($pattern)); } } - if (count($route->getOptions())) { + if ($route->getOptions()) { $routeXML->appendChild($optionsXML = $dom->createElement('options')); foreach ($route->getOptions() as $name => $value) { $optionsXML->appendChild($optionXML = $dom->createElement('option')); @@ -349,15 +351,9 @@ private function getContainerDefinitionDocument(Definition $definition, $id = nu $serviceXML->setAttribute('public', $definition->isPublic() ? 'true' : 'false'); $serviceXML->setAttribute('synthetic', $definition->isSynthetic() ? 'true' : 'false'); $serviceXML->setAttribute('lazy', $definition->isLazy() ? 'true' : 'false'); - if (method_exists($definition, 'isShared')) { - $serviceXML->setAttribute('shared', $definition->isShared() ? 'true' : 'false'); - } + $serviceXML->setAttribute('shared', $definition->isShared() ? 'true' : 'false'); $serviceXML->setAttribute('abstract', $definition->isAbstract() ? 'true' : 'false'); - - if (method_exists($definition, 'isAutowired')) { - $serviceXML->setAttribute('autowired', $definition->isAutowired() ? 'true' : 'false'); - } - + $serviceXML->setAttribute('autowired', $definition->isAutowired() ? 'true' : 'false'); $serviceXML->setAttribute('file', $definition->getFile()); $calls = $definition->getMethodCalls(); @@ -370,9 +366,7 @@ private function getContainerDefinitionDocument(Definition $definition, $id = nu } if (!$omitTags) { - $tags = $definition->getTags(); - - if (count($tags) > 0) { + if ($tags = $definition->getTags()) { $serviceXML->appendChild($tagsXML = $dom->createElement('tags')); foreach ($tags as $tagName => $tagData) { foreach ($tagData as $parameters) { diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddAnnotationsCachedReaderPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddAnnotationsCachedReaderPass.php new file mode 100644 index 0000000000000..4b75738b2fd1a --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddAnnotationsCachedReaderPass.php @@ -0,0 +1,33 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +/** + * @internal + */ +class AddAnnotationsCachedReaderPass implements CompilerPassInterface +{ + /** + * {@inheritdoc} + */ + public function process(ContainerBuilder $container) + { + // "annotations.cached_reader" is wired late so that any passes using + // "annotation_reader" at build time don't get any cache + if ($container->hasDefinition('annotations.cached_reader')) { + $container->setAlias('annotation_reader', 'annotations.cached_reader'); + } + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolClearerPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolClearerPass.php index c859a6ba900a4..901722756bd4a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolClearerPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolClearerPass.php @@ -11,7 +11,6 @@ namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler; -use Symfony\Component\Cache\Adapter\AbstractAdapter; use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; @@ -39,22 +38,5 @@ public function process(ContainerBuilder $container) } } } - - if (!$container->has('cache.annotations')) { - return; - } - $factory = array(AbstractAdapter::class, 'createSystemCache'); - $annotationsPool = $container->getDefinition('cache.annotations'); - if ($factory !== $annotationsPool->getFactory() || 4 !== count($annotationsPool->getArguments())) { - return; - } - if ($container->has('monolog.logger.cache')) { - $annotationsPool->addArgument(new Reference('monolog.logger.cache')); - } elseif ($container->has('cache.system')) { - $systemPool = $container->getDefinition('cache.system'); - if ($factory === $systemPool->getFactory() && 5 <= count($systemArgs = $systemPool->getArguments())) { - $annotationsPool->addArgument($systemArgs[4]); - } - } } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index e6eb049e2ce83..7429eed2f27a0 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1043,7 +1043,8 @@ private function registerAnnotationsConfiguration(array $config, ContainerBuilde ->replaceArgument(2, $config['debug']) ->addAutowiringType(Reader::class) ; - $container->setAlias('annotation_reader', 'annotations.cached_reader'); + } else { + $container->removeDefinition('annotations.cached_reader'); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 4c20d146cb4bf..853e1f22e7b3e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -11,6 +11,7 @@ namespace Symfony\Bundle\FrameworkBundle; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddAnnotationsCachedReaderPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConstraintValidatorsPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddDebugLogProcessorPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddValidatorInitializersPass; @@ -79,6 +80,7 @@ public function build(ContainerBuilder $container) $container->addCompilerPass(new RegisterListenersPass(), PassConfig::TYPE_BEFORE_REMOVING); $container->addCompilerPass(new TemplatingPass()); $container->addCompilerPass(new AddConstraintValidatorsPass(), PassConfig::TYPE_BEFORE_REMOVING); + $container->addCompilerPass(new AddAnnotationsCachedReaderPass(), PassConfig::TYPE_BEFORE_REMOVING); $container->addCompilerPass(new AddValidatorInitializersPass()); $container->addCompilerPass(new AddConsoleCommandPass()); $container->addCompilerPass(new FormPass()); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.xml index 80cb00ada9652..461b40455a8c5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/cache.xml @@ -22,13 +22,8 @@ - - - - - 0 - - %kernel.cache_dir%/pools + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_info.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_info.xml index 33a0a661f8991..8f6a7c9e31bed 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_info.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/property_info.xml @@ -15,7 +15,7 @@ - + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 4663ee4ba66b7..fec9b4be16ab2 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -440,12 +440,15 @@ public function testAnnotations() $container = $this->createContainerFromFile('full'); $this->assertEquals($container->getParameter('kernel.cache_dir').'/annotations', $container->getDefinition('annotations.filesystem_cache')->getArgument(0)); - $this->assertSame('annotations.cached_reader', (string) $container->getAlias('annotation_reader')); $this->assertSame('annotations.filesystem_cache', (string) $container->getDefinition('annotations.cached_reader')->getArgument(1)); } public function testFileLinkFormat() { + if (ini_get('xdebug.file_link_format') || get_cfg_var('xdebug.file_link_format')) { + $this->markTestSkipped('A custom file_link_format is defined.'); + } + $container = $this->createContainerFromFile('full'); $this->assertEquals('file%link%format', $container->getParameter('debug.file_link_format')); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_public.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_public.json index 170dfa2887e7c..3039d03f1ed13 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_public.json +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_public.json @@ -7,14 +7,12 @@ "lazy": true, "shared": true, "abstract": true, + "autowire": false, + "autowiring_types": [], "file": null, "factory_class": "Full\\Qualified\\FactoryClass", "factory_method": "get", - "tags": [ - - ], - "autowire": false, - "autowiring_types": [] + "tags": [] } }, "aliases": { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_public.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_public.md index 279958648f9ac..d21d18053677f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_public.md +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_public.md @@ -4,8 +4,7 @@ Public services Definitions ----------- -definition_1 -~~~~~~~~~~~~ +### definition_1 - Class: `Full\Qualified\Class1` - Public: yes @@ -21,14 +20,12 @@ definition_1 Aliases ------- -alias_1 -~~~~~~~ +### alias_1 - Service: `service_1` - Public: yes -alias_2 -~~~~~~~ +### alias_2 - Service: `service_2` - Public: no diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json index fe2b183901904..d6f70eec2127d 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.json @@ -7,14 +7,12 @@ "lazy": true, "shared": true, "abstract": true, + "autowire": false, + "autowiring_types": [], "file": null, "factory_class": "Full\\Qualified\\FactoryClass", "factory_method": "get", - "tags": [ - - ], - "autowire": false, - "autowiring_types": [] + "tags": [] }, "definition_2": { "class": "Full\\Qualified\\Class2", @@ -23,9 +21,14 @@ "lazy": false, "shared": true, "abstract": false, + "autowire": false, + "autowiring_types": [], "file": "\/path\/to\/file", "factory_service": "factory.service", "factory_method": "get", + "calls": [ + "setMailer" + ], "tags": [ { "name": "tag1", @@ -42,16 +45,9 @@ }, { "name": "tag2", - "parameters": [ - - ] + "parameters": [] } - ], - "calls": [ - "setMailer" - ], - "autowire": false, - "autowiring_types": [] + ] } }, "aliases": { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md index f1e22ddba499c..26ea2f007ed51 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_services.md @@ -4,8 +4,7 @@ Public and private services Definitions ----------- -definition_1 -~~~~~~~~~~~~ +### definition_1 - Class: `Full\Qualified\Class1` - Public: yes @@ -17,8 +16,7 @@ definition_1 - Factory Class: `Full\Qualified\FactoryClass` - Factory Method: `get` -definition_2 -~~~~~~~~~~~~ +### definition_2 - Class: `Full\Qualified\Class2` - Public: no @@ -42,14 +40,12 @@ definition_2 Aliases ------- -alias_1 -~~~~~~~ +### alias_1 - Service: `service_1` - Public: yes -alias_2 -~~~~~~~ +### alias_2 - Service: `service_2` - Public: no diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.json index a25a34b44a89d..de1ae35eaad57 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.json +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.json @@ -7,9 +7,14 @@ "lazy": false, "shared": true, "abstract": false, + "autowire": false, + "autowiring_types": [], "file": "\/path\/to\/file", "factory_service": "factory.service", "factory_method": "get", + "calls": [ + "setMailer" + ], "tags": [ { "name": "tag1", @@ -26,22 +31,11 @@ }, { "name": "tag2", - "parameters": [ - - ] + "parameters": [] } - ], - "calls": [ - "setMailer" - ], - "autowire": false, - "autowiring_types": [] + ] } }, - "aliases": [ - - ], - "services": [ - - ] + "aliases": [], + "services": [] } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.md index 8a9636f71db16..e3dcc59f43bff 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.md +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tag1.md @@ -4,8 +4,7 @@ Public and private services with tag `tag1` Definitions ----------- -definition_2 -~~~~~~~~~~~~ +### definition_2 - Class: `Full\Qualified\Class2` - Public: no diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.json index 25138d78fd42c..d5f5596c4653a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.json +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.json @@ -7,14 +7,14 @@ "lazy": false, "shared": true, "abstract": false, + "autowire": false, + "autowiring_types": [], "file": "\/path\/to\/file", - "calls": [ - "setMailer" - ], "factory_service": "factory.service", "factory_method": "get", - "autowire": false, - "autowiring_types": [] + "calls": [ + "setMailer" + ] } ], "tag2": [ @@ -25,14 +25,14 @@ "lazy": false, "shared": true, "abstract": false, + "autowire": false, + "autowiring_types": [], "file": "\/path\/to\/file", - "calls": [ - "setMailer" - ], "factory_service": "factory.service", "factory_method": "get", - "autowire": false, - "autowiring_types": [] + "calls": [ + "setMailer" + ] } ] } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.md b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.md index 1731fc9f917ea..a0e1bcd1c4f8a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.md +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/builder_1_tags.md @@ -4,8 +4,7 @@ Container tags tag1 ---- -definition_2 -~~~~~~~~~~~~ +### definition_2 - Class: `Full\Qualified\Class2` - Public: no @@ -23,8 +22,7 @@ definition_2 tag2 ---- -definition_2 -~~~~~~~~~~~~ +### definition_2 - Class: `Full\Qualified\Class2` - Public: no diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_1.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_1.json index d11d6e92d49fc..cbabdc81a1079 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_1.json +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_1.json @@ -5,12 +5,10 @@ "lazy": true, "shared": true, "abstract": true, + "autowire": false, + "autowiring_types": [], "file": null, "factory_class": "Full\\Qualified\\FactoryClass", "factory_method": "get", - "tags": [ - - ], - "autowire": false, - "autowiring_types": [] + "tags": [] } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.json index 8a6611a37cd7d..2a29181874fab 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.json +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/definition_2.json @@ -5,9 +5,14 @@ "lazy": false, "shared": true, "abstract": false, + "autowire": false, + "autowiring_types": [], "file": "\/path\/to\/file", "factory_service": "factory.service", "factory_method": "get", + "calls": [ + "setMailer" + ], "tags": [ { "name": "tag1", @@ -24,14 +29,7 @@ }, { "name": "tag2", - "parameters": [ - - ] + "parameters": [] } - ], - "calls": [ - "setMailer" - ], - "autowire": false, - "autowiring_types": [] + ] } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.json index d34b3a77aec6e..58caf26d537e7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.json +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_2.json @@ -6,9 +6,7 @@ "scheme": "http|https", "method": "PUT|POST", "class": "Symfony\\Component\\Routing\\Route", - "defaults": [ - - ], + "defaults": [], "requirements": "NO CUSTOM", "options": { "compiler_class": "Symfony\\Component\\Routing\\RouteCompiler", diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_collection_1.json b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_collection_1.json index 7170953f5fee7..350bffdb3a9c7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_collection_1.json +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Descriptor/route_collection_1.json @@ -27,9 +27,7 @@ "scheme": "http|https", "method": "PUT|POST", "class": "Symfony\\Component\\Routing\\Route", - "defaults": [ - - ], + "defaults": [], "requirements": "NO CUSTOM", "options": { "compiler_class": "Symfony\\Component\\Routing\\RouteCompiler", diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Resources/views/translation.html.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Resources/views/translation.html.php index c0ae6ec5c6604..cb3c763f8f3c8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Resources/views/translation.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Fixtures/Resources/views/translation.html.php @@ -31,3 +31,19 @@ 10, array('%count%' => 10) ) ?> + +trans('other-domain-test-no-params-short-array', [], 'not_messages'); ?> + +trans('other-domain-test-no-params-long-array', array(), 'not_messages'); ?> + +trans('other-domain-test-params-short-array', ['foo' => 'bar'], 'not_messages'); ?> + +trans('other-domain-test-params-long-array', array('foo' => 'bar'), 'not_messages'); ?> + +transChoice('other-domain-test-trans-choice-short-array-%count%', 10, ['%count%' => 10], 'not_messages'); ?> + +transChoice('other-domain-test-trans-choice-long-array-%count%', 10, array('%count%' => 10), 'not_messages'); ?> + +trans('typecast', ['a' => (int) '123'], 'not_messages'); ?> +transChoice('msg1', 10 + 1, [], 'not_messages'); ?> +transChoice('msg2', intval(4.5), [], 'not_messages'); ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/AnnotatedControllerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/AnnotatedControllerTest.php new file mode 100644 index 0000000000000..2fdbef8839496 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/AnnotatedControllerTest.php @@ -0,0 +1,39 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional; + +class AnnotatedControllerTest extends WebTestCase +{ + /** + * @dataProvider getRoutes + */ + public function testAnnotatedController($path, $expectedValue) + { + $client = $this->createClient(array('test_case' => 'AnnotatedController', 'root_config' => 'config.yml')); + $client->request('GET', '/annotated'.$path); + + $this->assertSame(200, $client->getResponse()->getStatusCode()); + $this->assertSame($expectedValue, $client->getResponse()->getContent()); + } + + public function getRoutes() + { + return array( + array('/null_request', 'Symfony\Component\HttpFoundation\Request'), + array('/null_argument', ''), + array('/null_argument_with_route_param', ''), + array('/null_argument_with_route_param/value', 'value'), + array('/argument_with_route_param_and_default', 'value'), + array('/argument_with_route_param_and_default/custom', 'custom'), + ); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/AnnotatedController.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/AnnotatedController.php new file mode 100644 index 0000000000000..98a3ace982e33 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/AnnotatedController.php @@ -0,0 +1,51 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\Controller; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Annotation\Route; + +class AnnotatedController +{ + /** + * @Route("/null_request", name="null_request") + */ + public function requestDefaultNullAction(Request $request = null) + { + return new Response($request ? get_class($request) : null); + } + + /** + * @Route("/null_argument", name="null_argument") + */ + public function argumentDefaultNullWithoutRouteParamAction($value = null) + { + return new Response($value); + } + + /** + * @Route("/null_argument_with_route_param/{value}", name="null_argument_with_route_param") + */ + public function argumentDefaultNullWithRouteParamAction($value = null) + { + return new Response($value); + } + + /** + * @Route("/argument_with_route_param_and_default/{value}", defaults={"value": "value"}, name="argument_with_route_param_and_default") + */ + public function argumentWithoutDefaultWithRouteParamAndDefaultAction($value) + { + return new Response($value); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/DependencyInjection/AnnotationReaderPass.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/DependencyInjection/AnnotationReaderPass.php new file mode 100644 index 0000000000000..2de08632fa144 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/DependencyInjection/AnnotationReaderPass.php @@ -0,0 +1,24 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\DependencyInjection; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; + +class AnnotationReaderPass implements CompilerPassInterface +{ + public function process(ContainerBuilder $container) + { + // simulate using "annotation_reader" in a compiler pass + $container->get('annotation_reader'); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TestBundle.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TestBundle.php index e7982cfaab7cc..d63658bacf021 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TestBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/TestBundle.php @@ -13,6 +13,7 @@ use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\DependencyInjection\AnnotationReaderPass; use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\DependencyInjection\Config\CustomConfig; class TestBundle extends Bundle @@ -25,5 +26,7 @@ public function build(ContainerBuilder $container) $extension = $container->getExtension('test'); $extension->setCustomConfig(new CustomConfig()); + + $container->addCompilerPass(new AnnotationReaderPass()); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PropertyInfoTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PropertyInfoTest.php new file mode 100644 index 0000000000000..c02a6b84e519c --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/PropertyInfoTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\Tests\Functional; + +use Symfony\Component\PropertyInfo\Type; + +class PropertyInfoTest extends WebTestCase +{ + public function testPhpDocPriority() + { + static::bootKernel(array('test_case' => 'Serializer')); + $container = static::$kernel->getContainer(); + + $this->assertEquals(array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_INT))), $container->get('property_info')->getTypes('Symfony\Bundle\FrameworkBundle\Tests\Functional\Dummy', 'codes')); + } +} + +class Dummy +{ + /** + * @param int[] $codes + */ + public function setCodes(array $codes) + { + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AnnotatedController/bundles.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AnnotatedController/bundles.php new file mode 100644 index 0000000000000..f3290d7728541 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AnnotatedController/bundles.php @@ -0,0 +1,20 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Bundle\FrameworkBundle\Tests\Functional\Bundle\TestBundle\TestBundle; +use Symfony\Bundle\FrameworkBundle\FrameworkBundle; +use Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle; + +return array( + new FrameworkBundle(), + new TestBundle(), + new SensioFrameworkExtraBundle(), +); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AnnotatedController/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AnnotatedController/config.yml new file mode 100644 index 0000000000000..377d3e7852064 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AnnotatedController/config.yml @@ -0,0 +1,2 @@ +imports: + - { resource: ../config/default.yml } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AnnotatedController/routing.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AnnotatedController/routing.yml new file mode 100644 index 0000000000000..ebd18a0a4c282 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/AnnotatedController/routing.yml @@ -0,0 +1,4 @@ +annotated_controller: + prefix: /annotated + resource: "@TestBundle/Controller/AnnotatedController.php" + type: annotation diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/PhpExtractorTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/PhpExtractorTest.php index 420d2f2d71dd3..e8c56ee4d5e52 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/PhpExtractorTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Translation/PhpExtractorTest.php @@ -39,18 +39,31 @@ public function testExtraction($resource) nowdoc key with whitespace and nonescaped \$\n sequences EOF; // Assert - $expectedCatalogue = array('messages' => array( - 'single-quoted key' => 'prefixsingle-quoted key', - 'double-quoted key' => 'prefixdouble-quoted key', - 'heredoc key' => 'prefixheredoc key', - 'nowdoc key' => 'prefixnowdoc key', - "double-quoted key with whitespace and escaped \$\n\" sequences" => "prefixdouble-quoted key with whitespace and escaped \$\n\" sequences", - 'single-quoted key with whitespace and nonescaped \$\n\' sequences' => 'prefixsingle-quoted key with whitespace and nonescaped \$\n\' sequences', - 'single-quoted key with "quote mark at the end"' => 'prefixsingle-quoted key with "quote mark at the end"', - $expectedHeredoc => 'prefix'.$expectedHeredoc, - $expectedNowdoc => 'prefix'.$expectedNowdoc, - '{0} There is no apples|{1} There is one apple|]1,Inf[ There are %count% apples' => 'prefix{0} There is no apples|{1} There is one apple|]1,Inf[ There are %count% apples', - )); + $expectedCatalogue = array( + 'messages' => array( + 'single-quoted key' => 'prefixsingle-quoted key', + 'double-quoted key' => 'prefixdouble-quoted key', + 'heredoc key' => 'prefixheredoc key', + 'nowdoc key' => 'prefixnowdoc key', + "double-quoted key with whitespace and escaped \$\n\" sequences" => "prefixdouble-quoted key with whitespace and escaped \$\n\" sequences", + 'single-quoted key with whitespace and nonescaped \$\n\' sequences' => 'prefixsingle-quoted key with whitespace and nonescaped \$\n\' sequences', + 'single-quoted key with "quote mark at the end"' => 'prefixsingle-quoted key with "quote mark at the end"', + $expectedHeredoc => 'prefix'.$expectedHeredoc, + $expectedNowdoc => 'prefix'.$expectedNowdoc, + '{0} There is no apples|{1} There is one apple|]1,Inf[ There are %count% apples' => 'prefix{0} There is no apples|{1} There is one apple|]1,Inf[ There are %count% apples', + ), + 'not_messages' => array( + 'other-domain-test-no-params-short-array' => 'prefixother-domain-test-no-params-short-array', + 'other-domain-test-no-params-long-array' => 'prefixother-domain-test-no-params-long-array', + 'other-domain-test-params-short-array' => 'prefixother-domain-test-params-short-array', + 'other-domain-test-params-long-array' => 'prefixother-domain-test-params-long-array', + 'other-domain-test-trans-choice-short-array-%count%' => 'prefixother-domain-test-trans-choice-short-array-%count%', + 'other-domain-test-trans-choice-long-array-%count%' => 'prefixother-domain-test-trans-choice-long-array-%count%', + 'typecast' => 'prefixtypecast', + 'msg1' => 'prefixmsg1', + 'msg2' => 'prefixmsg2', + ), + ); $actualCatalogue = $catalogue->all(); $this->assertEquals($expectedCatalogue, $actualCatalogue); diff --git a/src/Symfony/Bundle/FrameworkBundle/Translation/PhpExtractor.php b/src/Symfony/Bundle/FrameworkBundle/Translation/PhpExtractor.php index cf7f3c5769bf2..97c94fdd14bf9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Translation/PhpExtractor.php +++ b/src/Symfony/Bundle/FrameworkBundle/Translation/PhpExtractor.php @@ -24,6 +24,8 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface { const MESSAGE_TOKEN = 300; + const METHOD_ARGUMENTS_TOKEN = 1000; + const DOMAIN_TOKEN = 1001; /** * Prefix for new found message. @@ -38,6 +40,28 @@ class PhpExtractor extends AbstractFileExtractor implements ExtractorInterface * @var array */ protected $sequences = array( + array( + '->', + 'trans', + '(', + self::MESSAGE_TOKEN, + ',', + self::METHOD_ARGUMENTS_TOKEN, + ',', + self::DOMAIN_TOKEN, + ), + array( + '->', + 'transChoice', + '(', + self::MESSAGE_TOKEN, + ',', + self::METHOD_ARGUMENTS_TOKEN, + ',', + self::METHOD_ARGUMENTS_TOKEN, + ',', + self::DOMAIN_TOKEN, + ), array( '->', 'trans', @@ -105,11 +129,32 @@ private function seekToNextRelevantToken(\Iterator $tokenIterator) } } + private function skipMethodArgument(\Iterator $tokenIterator) + { + $openBraces = 0; + + for (; $tokenIterator->valid(); $tokenIterator->next()) { + $t = $tokenIterator->current(); + + if ('[' === $t[0] || '(' === $t[0]) { + ++$openBraces; + } + + if (']' === $t[0] || ')' === $t[0]) { + --$openBraces; + } + + if ((0 === $openBraces && ',' === $t[0]) || (-1 === $openBraces && ')' === $t[0])) { + break; + } + } + } + /** * Extracts the message from the iterator while the tokens * match allowed message tokens. */ - private function getMessage(\Iterator $tokenIterator) + private function getValue(\Iterator $tokenIterator) { $message = ''; $docToken = ''; @@ -155,16 +200,26 @@ protected function parseTokens($tokens, MessageCatalogue $catalog) for ($key = 0; $key < $tokenIterator->count(); ++$key) { foreach ($this->sequences as $sequence) { $message = ''; + $domain = 'messages'; $tokenIterator->seek($key); - foreach ($sequence as $item) { + foreach ($sequence as $sequenceKey => $item) { $this->seekToNextRelevantToken($tokenIterator); - if ($this->normalizeToken($tokenIterator->current()) == $item) { + if ($this->normalizeToken($tokenIterator->current()) === $item) { $tokenIterator->next(); continue; - } elseif (self::MESSAGE_TOKEN == $item) { - $message = $this->getMessage($tokenIterator); + } elseif (self::MESSAGE_TOKEN === $item) { + $message = $this->getValue($tokenIterator); + + if (count($sequence) === ($sequenceKey + 1)) { + break; + } + } elseif (self::METHOD_ARGUMENTS_TOKEN === $item) { + $this->skipMethodArgument($tokenIterator); + } elseif (self::DOMAIN_TOKEN === $item) { + $domain = $this->getValue($tokenIterator); + break; } else { break; @@ -172,7 +227,7 @@ protected function parseTokens($tokens, MessageCatalogue $catalog) } if ($message) { - $catalog->set($message, $this->prefix.$message); + $catalog->set($message, $this->prefix.$message, $domain); break; } } diff --git a/src/Symfony/Bundle/FrameworkBundle/composer.json b/src/Symfony/Bundle/FrameworkBundle/composer.json index 34c0b2fe691d9..46e374408bc83 100644 --- a/src/Symfony/Bundle/FrameworkBundle/composer.json +++ b/src/Symfony/Bundle/FrameworkBundle/composer.json @@ -27,7 +27,9 @@ "symfony/polyfill-mbstring": "~1.0", "symfony/filesystem": "~2.8|~3.0", "symfony/finder": "~2.8|~3.0", - "symfony/routing": "~3.0", + "symfony/routing": "~3.1.10|~3.2.3", + "symfony/security-core": "~2.8|~3.0", + "symfony/security-csrf": "~2.8|~3.0", "symfony/stopwatch": "~2.8|~3.0", "doctrine/cache": "~1.0" }, @@ -49,10 +51,11 @@ "symfony/templating": "~2.8|~3.0", "symfony/validator": "~3.2", "symfony/yaml": "~3.2", - "symfony/property-info": "~2.8|~3.0", + "symfony/property-info": "~3.1", "doctrine/annotations": "~1.0", "phpdocumentor/reflection-docblock": "^3.0", - "twig/twig": "~1.26|~2.0" + "twig/twig": "~1.26|~2.0", + "sensio/framework-extra-bundle": "^3.0.2" }, "conflict": { "phpdocumentor/reflection-docblock": "<3.0", diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index b0aadc2f19e43..c2bcb7d0e3ef2 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -369,11 +369,11 @@ private function addProvidersSection(ArrayNodeDefinition $rootNode) $providerNodeBuilder ->validate() - ->ifTrue(function ($v) {return count($v) > 1;}) + ->ifTrue(function ($v) { return count($v) > 1; }) ->thenInvalid('You cannot set multiple provider types for the same provider') ->end() ->validate() - ->ifTrue(function ($v) {return count($v) === 0;}) + ->ifTrue(function ($v) { return count($v) === 0; }) ->thenInvalid('You must set a provider definition for the provider.') ->end() ; diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig b/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig index 3830e924a190b..073d0d869d8f0 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig +++ b/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig @@ -257,7 +257,13 @@ : 'DENIED' }} - {{ decision.attributes|length == 1 ? decision.attributes|first : profiler_dump(decision.attributes) }} + + {% if decision.attributes|length == 1 %} + {{ decision.attributes|first }} + {% else %} + {{ profiler_dump(decision.attributes) }} + {% endif %} + {{ profiler_dump(decision.object) }} {% endfor %} diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php index abb2fed46d839..1491b04ac0545 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php @@ -88,7 +88,7 @@ public function process(ContainerBuilder $container) $twigLoader = $container->getDefinition('twig.loader.native_filesystem'); if ($container->has('templating')) { $loader = $container->getDefinition('twig.loader.filesystem'); - $loader->setMethodCalls($twigLoader->getMethodCalls()); + $loader->setMethodCalls(array_merge($twigLoader->getMethodCalls(), $loader->getMethodCalls())); $loader->replaceArgument(2, $composerRootDir); $twigLoader->clearTag('twig.loader'); diff --git a/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Compiler/ExtensionPassTest.php b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Compiler/ExtensionPassTest.php new file mode 100644 index 0000000000000..e6ab0159fdadd --- /dev/null +++ b/src/Symfony/Bundle/TwigBundle/Tests/DependencyInjection/Compiler/ExtensionPassTest.php @@ -0,0 +1,46 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\TwigBundle\Tests\DependencyInjection\Compiler; + +use Symfony\Bundle\TwigBundle\DependencyInjection\Compiler\ExtensionPass; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Definition; + +class ExtensionPassTest extends \PHPUnit_Framework_TestCase +{ + public function testProcessDoesNotDropExistingFileLoaderMethodCalls() + { + $container = new ContainerBuilder(); + $container->setParameter('kernel.debug', false); + $container->setParameter('kernel.root_dir', __DIR__); + + $container->register('twig.app_variable', '\Symfony\Bridge\Twig\AppVariable'); + $container->register('templating', '\Symfony\Bundle\TwigBundle\TwigEngine'); + $container->register('twig.extension.yaml'); + $container->register('twig.extension.debug.stopwatch'); + $container->register('twig.extension.expression'); + + $nativeTwigLoader = new Definition('\Twig_Loader_Filesystem'); + $nativeTwigLoader->addMethodCall('addPath', array()); + $container->setDefinition('twig.loader.native_filesystem', $nativeTwigLoader); + + $filesystemLoader = new Definition('\Symfony\Bundle\TwigBundle\Loader\FilesystemLoader'); + $filesystemLoader->setArguments(array(null, null, null)); + $filesystemLoader->addMethodCall('addPath', array()); + $container->setDefinition('twig.loader.filesystem', $filesystemLoader); + + $extensionPass = new ExtensionPass(); + $extensionPass->process($container); + + $this->assertCount(2, $filesystemLoader->getMethodCalls()); + } +} diff --git a/src/Symfony/Bundle/TwigBundle/Tests/Functional/CacheWarmingTest.php b/src/Symfony/Bundle/TwigBundle/Tests/Functional/CacheWarmingTest.php index 8285d3451d9e8..5840668339c3f 100644 --- a/src/Symfony/Bundle/TwigBundle/Tests/Functional/CacheWarmingTest.php +++ b/src/Symfony/Bundle/TwigBundle/Tests/Functional/CacheWarmingTest.php @@ -17,7 +17,7 @@ use Symfony\Bundle\FrameworkBundle\FrameworkBundle; use Symfony\Bundle\TwigBundle\TwigBundle; -class NewCacheWamingTest extends \PHPUnit_Framework_TestCase +class CacheWarmingTest extends \PHPUnit_Framework_TestCase { public function testCacheIsProperlyWarmedWhenTemplatingIsAvailable() { diff --git a/src/Symfony/Bundle/WebProfilerBundle/Csp/ContentSecurityPolicyHandler.php b/src/Symfony/Bundle/WebProfilerBundle/Csp/ContentSecurityPolicyHandler.php index 195f3f18ff25d..52168924d3303 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Csp/ContentSecurityPolicyHandler.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Csp/ContentSecurityPolicyHandler.php @@ -135,7 +135,8 @@ private function updateCspHeaders(Response $response, array $nonces = array()) if (isset($headers[$header]['default-src'])) { $headers[$header][$type] = $headers[$header]['default-src']; } else { - $headers[$header][$type] = array(); + // If there is no script-src/style-src and no default-src, no additional rules required. + continue; } } $ruleIsSet = true; diff --git a/src/Symfony/Bundle/WebProfilerBundle/Tests/Csp/ContentSecurityPolicyHandlerTest.php b/src/Symfony/Bundle/WebProfilerBundle/Tests/Csp/ContentSecurityPolicyHandlerTest.php index a471e3a5cd5b7..2a78b581bf6a5 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Tests/Csp/ContentSecurityPolicyHandlerTest.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Tests/Csp/ContentSecurityPolicyHandlerTest.php @@ -118,6 +118,13 @@ public function provideRequestAndResponsesForOnKernelResponse() $this->createResponse($responseNonceHeaders), array('Content-Security-Policy' => null, 'X-Content-Security-Policy' => null), ), + array( + $nonce, + array('csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce), + $this->createRequest(), + $this->createResponse(array('Content-Security-Policy' => 'frame-ancestors https: ; form-action: https:')), + array('Content-Security-Policy' => 'frame-ancestors https: ; form-action: https:', 'X-Content-Security-Policy' => null), + ), array( $nonce, array('csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce), @@ -130,7 +137,7 @@ public function provideRequestAndResponsesForOnKernelResponse() array('csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce), $this->createRequest(), $this->createResponse(array('Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\'')), - array('Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\'; style-src \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'X-Content-Security-Policy' => null), + array('Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\'', 'X-Content-Security-Policy' => null), ), array( $nonce, @@ -144,21 +151,21 @@ public function provideRequestAndResponsesForOnKernelResponse() array('csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce), $this->createRequest(), $this->createResponse(array('X-Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\'')), - array('X-Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\'; style-src \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'Content-Security-Policy' => null), + array('X-Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\'', 'Content-Security-Policy' => null), ), array( $nonce, array('csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce), $this->createRequest(), $this->createResponse(array('X-Content-Security-Policy' => 'script-src \'self\'')), - array('X-Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\' \'nonce-'.$nonce.'\'; style-src \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'Content-Security-Policy' => null), + array('X-Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'Content-Security-Policy' => null), ), array( $nonce, array('csp_script_nonce' => $nonce, 'csp_style_nonce' => $nonce), $this->createRequest(), $this->createResponse(array('X-Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\' \'sha384-LALALALALAAL\'')), - array('X-Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\' \'sha384-LALALALALAAL\' \'nonce-'.$nonce.'\'; style-src \'unsafe-inline\' \'nonce-'.$nonce.'\'', 'Content-Security-Policy' => null), + array('X-Content-Security-Policy' => 'script-src \'self\' \'unsafe-inline\' \'sha384-LALALALALAAL\' \'nonce-'.$nonce.'\'', 'Content-Security-Policy' => null), ), array( $nonce, diff --git a/src/Symfony/Component/BrowserKit/Cookie.php b/src/Symfony/Component/BrowserKit/Cookie.php index 7e855bf351dad..42f184d532e02 100644 --- a/src/Symfony/Component/BrowserKit/Cookie.php +++ b/src/Symfony/Component/BrowserKit/Cookie.php @@ -213,8 +213,6 @@ private static function parseDate($dateValue) if (false !== $date = date_create($dateValue, new \DateTimeZone('GMT'))) { return $date->format('U'); } - - throw new \InvalidArgumentException(sprintf('Could not parse date "%s".', $dateValue)); } /** diff --git a/src/Symfony/Component/BrowserKit/Tests/CookieTest.php b/src/Symfony/Component/BrowserKit/Tests/CookieTest.php index 5a724333d350f..4722de6d7b04c 100644 --- a/src/Symfony/Component/BrowserKit/Tests/CookieTest.php +++ b/src/Symfony/Component/BrowserKit/Tests/CookieTest.php @@ -88,10 +88,11 @@ public function testFromStringThrowsAnExceptionIfCookieIsNotValid() Cookie::fromString('foo'); } - public function testFromStringThrowsAnExceptionIfCookieDateIsNotValid() + public function testFromStringIgnoresInvalidExpiresDate() { - $this->setExpectedException('InvalidArgumentException'); - Cookie::fromString('foo=bar; expires=Flursday July 31st 2020, 08:49:37 GMT'); + $cookie = Cookie::fromString('foo=bar; expires=Flursday July 31st 2020, 08:49:37 GMT'); + + $this->assertFalse($cookie->isExpired()); } public function testFromStringThrowsAnExceptionIfUrlIsNotValid() diff --git a/src/Symfony/Component/Cache/Adapter/AdapterInterface.php b/src/Symfony/Component/Cache/Adapter/AdapterInterface.php index 85a0da80db079..274ebec1ef445 100644 --- a/src/Symfony/Component/Cache/Adapter/AdapterInterface.php +++ b/src/Symfony/Component/Cache/Adapter/AdapterInterface.php @@ -15,10 +15,23 @@ use Symfony\Component\Cache\CacheItem; /** - * Interface for adapters managing instances of Symfony's {@see CacheItem}. + * Interface for adapters managing instances of Symfony's CacheItem. * * @author Kévin Dunglas */ interface AdapterInterface extends CacheItemPoolInterface { + /** + * {@inheritdoc} + * + * @return CacheItem + */ + public function getItem($key); + + /** + * {@inheritdoc} + * + * return \Traversable|CacheItem[] + */ + public function getItems(array $keys = array()); } diff --git a/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php b/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php index 5fd1d31a45e66..1c62641cf6d67 100644 --- a/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php @@ -11,6 +11,8 @@ namespace Symfony\Component\Cache\Adapter; +use Symfony\Component\Cache\Exception\CacheException; + /** * @author Nicolas Grekas */ diff --git a/src/Symfony/Component/Cache/Adapter/FilesystemAdapterTrait.php b/src/Symfony/Component/Cache/Adapter/FilesystemAdapterTrait.php index 34ed20e6d2660..156fc5c1fb63a 100644 --- a/src/Symfony/Component/Cache/Adapter/FilesystemAdapterTrait.php +++ b/src/Symfony/Component/Cache/Adapter/FilesystemAdapterTrait.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Cache\Adapter; -use Symfony\Component\Cache\Exception\CacheException; use Symfony\Component\Cache\Exception\InvalidArgumentException; /** diff --git a/src/Symfony/Component/Cache/Adapter/PdoAdapter.php b/src/Symfony/Component/Cache/Adapter/PdoAdapter.php index 24245fcf27d10..3fa3a40533d9e 100644 --- a/src/Symfony/Component/Cache/Adapter/PdoAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/PdoAdapter.php @@ -108,9 +108,20 @@ public function createTable() $conn = $this->getConnection(); if ($conn instanceof Connection) { + $types = array( + 'mysql' => 'binary', + 'sqlite' => 'text', + 'pgsql' => 'string', + 'oci' => 'string', + 'sqlsrv' => 'string', + ); + if (!isset($types[$this->driver])) { + throw new \DomainException(sprintf('Creating the cache table is currently not implemented for PDO driver "%s".', $this->driver)); + } + $schema = new Schema(); $table = $schema->createTable($this->table); - $table->addColumn($this->idCol, 'blob', array('length' => 255)); + $table->addColumn($this->idCol, $types[$this->driver], array('length' => 255)); $table->addColumn($this->dataCol, 'blob', array('length' => 16777215)); $table->addColumn($this->lifetimeCol, 'integer', array('unsigned' => true, 'notnull' => false)); $table->addColumn($this->timeCol, 'integer', array('unsigned' => true, 'foo' => 'bar')); diff --git a/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php b/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php index e4d8ad5eea318..c272ad0a4ae5f 100644 --- a/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/PhpArrayAdapter.php @@ -373,15 +373,15 @@ private function generateItems(array $keys) */ public static function throwOnRequiredClass($class) { - $e = new \ReflectionException(sprintf('Class %s does not exist', $class)); + $e = new \ReflectionException("Class $class does not exist"); $trace = $e->getTrace(); $autoloadFrame = array( 'function' => 'spl_autoload_call', 'args' => array($class), ); - $i = array_search($autoloadFrame, $trace); + $i = 1 + array_search($autoloadFrame, $trace, true); - if (false !== $i++ && isset($trace[$i]['function']) && !isset($trace[$i]['class'])) { + if (isset($trace[$i]['function']) && !isset($trace[$i]['class'])) { switch ($trace[$i]['function']) { case 'get_class_methods': case 'get_class_vars': diff --git a/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php b/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php index 802c30fa92d9e..b8c4a08021b70 100644 --- a/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/TagAwareAdapter.php @@ -26,6 +26,7 @@ class TagAwareAdapter implements TagAwareAdapterInterface private $deferred = array(); private $createCacheItem; private $getTagsByKey; + private $invalidateTags; private $tagsAdapter; public function __construct(AdapterInterface $itemsAdapter, AdapterInterface $tagsAdapter = null) @@ -33,17 +34,15 @@ public function __construct(AdapterInterface $itemsAdapter, AdapterInterface $ta $this->itemsAdapter = $itemsAdapter; $this->tagsAdapter = $tagsAdapter ?: $itemsAdapter; $this->createCacheItem = \Closure::bind( - function ($key, $value = null, CacheItem $protoItem = null) { + function ($key, $value, CacheItem $protoItem) { $item = new CacheItem(); $item->key = $key; $item->value = $value; $item->isHit = false; - - if (null !== $protoItem) { - $item->defaultLifetime = $protoItem->defaultLifetime; - $item->innerItem = $protoItem->innerItem; - $item->poolHash = $protoItem->poolHash; - } + $item->defaultLifetime = $protoItem->defaultLifetime; + $item->expiry = $protoItem->expiry; + $item->innerItem = $protoItem->innerItem; + $item->poolHash = $protoItem->poolHash; return $item; }, @@ -62,6 +61,20 @@ function ($deferred) { null, CacheItem::class ); + $this->invalidateTags = \Closure::bind( + function (AdapterInterface $tagsAdapter, array $tags) { + foreach ($tagsAdapter->getItems($tags) as $v) { + $v->set(1 + (int) $v->get()); + $v->defaultLifetime = 0; + $v->expiry = null; + $tagsAdapter->saveDeferred($v); + } + + return $tagsAdapter->commit(); + }, + null, + CacheItem::class + ); } /** @@ -74,13 +87,9 @@ public function invalidateTags(array $tags) $tags[$k] = $tag.static::TAGS_PREFIX; } } + $f = $this->invalidateTags; - foreach ($this->tagsAdapter->getItems($tags) as $v) { - $v->set(1 + (int) $v->get()); - $this->tagsAdapter->saveDeferred($v); - } - - return $this->tagsAdapter->commit(); + return $f($this->tagsAdapter, $tags); } /** @@ -211,7 +220,8 @@ public function commit() $ok = true; if ($this->deferred) { - foreach ($this->deferred as $key => $item) { + $items = $this->deferred; + foreach ($items as $key => $item) { if (!$this->itemsAdapter->saveDeferred($item)) { unset($this->deferred[$key]); $ok = false; @@ -219,14 +229,14 @@ public function commit() } $f = $this->getTagsByKey; - $tagsByKey = $f($this->deferred); + $tagsByKey = $f($items); $deletedTags = $this->deferred = array(); $tagVersions = $this->getTagVersions($tagsByKey); $f = $this->createCacheItem; foreach ($tagsByKey as $key => $tags) { if ($tags) { - $this->itemsAdapter->saveDeferred($f(static::TAGS_PREFIX.$key, array_intersect_key($tagVersions, $tags))); + $this->itemsAdapter->saveDeferred($f(static::TAGS_PREFIX.$key, array_intersect_key($tagVersions, $tags), $items[$key])); } else { $deletedTags[] = static::TAGS_PREFIX.$key; } diff --git a/src/Symfony/Component/Cache/CacheItem.php b/src/Symfony/Component/Cache/CacheItem.php index f3d8b83812672..941d0bc6cd5e9 100644 --- a/src/Symfony/Component/Cache/CacheItem.php +++ b/src/Symfony/Component/Cache/CacheItem.php @@ -104,7 +104,7 @@ public function expiresAfter($time) * * @return static * - * @throws InvalidArgumentException When $tag is not valid. + * @throws InvalidArgumentException When $tag is not valid */ public function tag($tags) { @@ -121,7 +121,7 @@ public function tag($tags) if (!isset($tag[0])) { throw new InvalidArgumentException('Cache tag length must be greater than zero'); } - if (isset($tag[strcspn($tag, '{}()/\@:')])) { + if (false !== strpbrk($tag, '{}()/\@:')) { throw new InvalidArgumentException(sprintf('Cache tag "%s" contains reserved characters {}()/\@:', $tag)); } $this->tags[$tag] = $tag; @@ -135,7 +135,7 @@ public function tag($tags) * * @param string $key The key to validate * - * @throws InvalidArgumentException When $key is not valid. + * @throws InvalidArgumentException When $key is not valid */ public static function validateKey($key) { @@ -145,7 +145,7 @@ public static function validateKey($key) if (!isset($key[0])) { throw new InvalidArgumentException('Cache key length must be greater than zero'); } - if (isset($key[strcspn($key, '{}()/\@:')])) { + if (false !== strpbrk($key, '{}()/\@:')) { throw new InvalidArgumentException(sprintf('Cache key "%s" contains reserved characters {}()/\@:', $key)); } } diff --git a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php index 20b1fd7a07fe2..24586c0ca9aae 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/TagAwareAdapterTest.php @@ -97,4 +97,21 @@ public function testTagsAreCleanedOnDelete() $this->assertTrue($pool->getItem('k')->isHit()); } + + public function testTagItemExpiry() + { + $pool = $this->createCachePool(10); + + $item = $pool->getItem('foo'); + $item->tag(array('baz')); + $item->expiresAfter(100); + + $pool->save($item); + $pool->invalidateTags(array('baz')); + $this->assertFalse($pool->getItem('foo')->isHit()); + + sleep(20); + + $this->assertFalse($pool->getItem('foo')->isHit()); + } } diff --git a/src/Symfony/Component/ClassLoader/Tests/Fixtures/Namespaced/WithStrictTypes.php b/src/Symfony/Component/ClassLoader/Tests/Fixtures/Namespaced/WithStrictTypes.php index 3c7870592b3cb..846611e38bbc4 100644 --- a/src/Symfony/Component/ClassLoader/Tests/Fixtures/Namespaced/WithStrictTypes.php +++ b/src/Symfony/Component/ClassLoader/Tests/Fixtures/Namespaced/WithStrictTypes.php @@ -4,7 +4,7 @@ * foo */ -declare (strict_types = 1); +declare(strict_types=1); namespace Namespaced; diff --git a/src/Symfony/Component/Config/ResourceCheckerConfigCache.php b/src/Symfony/Component/Config/ResourceCheckerConfigCache.php index ba7d600c7737b..0e3a411b07552 100644 --- a/src/Symfony/Component/Config/ResourceCheckerConfigCache.php +++ b/src/Symfony/Component/Config/ResourceCheckerConfigCache.php @@ -72,11 +72,6 @@ public function isFresh() return true; // shortcut - if we don't have any checkers we don't need to bother with the meta file at all } - $metadata = $this->getMetaFile(); - if (!is_file($metadata)) { - return true; - } - $metadata = $this->getMetaFile(); if (!is_file($metadata)) { return false; diff --git a/src/Symfony/Component/Config/Tests/ResourceCheckerConfigCacheTest.php b/src/Symfony/Component/Config/Tests/ResourceCheckerConfigCacheTest.php index d66c2e89d95b8..6c12c28a5b363 100644 --- a/src/Symfony/Component/Config/Tests/ResourceCheckerConfigCacheTest.php +++ b/src/Symfony/Component/Config/Tests/ResourceCheckerConfigCacheTest.php @@ -128,4 +128,16 @@ public function testCacheKeepsContent() $this->assertSame('FOOBAR', file_get_contents($cache->getPath())); } + + public function testCacheIsNotFreshIfNotExistsMetaFile() + { + $checker = $this->getMockBuilder('\Symfony\Component\Config\ResourceCheckerInterface')->getMock(); + $cache = new ResourceCheckerConfigCache($this->cacheFile, array($checker)); + $cache->write('foo', array(new FileResource(__FILE__))); + + $metaFile = "{$this->cacheFile}.meta"; + unlink($metaFile); + + $this->assertFalse($cache->isFresh()); + } } diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php index 37ba3f53238ee..6f784ae78df64 100644 --- a/src/Symfony/Component/Console/Helper/Table.php +++ b/src/Symfony/Component/Console/Helper/Table.php @@ -599,7 +599,7 @@ private function calculateColumnsWidth($rows) foreach ($row as $i => $cell) { if ($cell instanceof TableCell) { - $textLength = strlen($cell); + $textLength = Helper::strlenWithoutDecoration($this->output->getFormatter(), $cell); if ($textLength > 0) { $contentColumns = str_split($cell, ceil($textLength / $cell->getColspan())); foreach ($contentColumns as $position => $content) { diff --git a/src/Symfony/Component/Console/Helper/TableCell.php b/src/Symfony/Component/Console/Helper/TableCell.php index 69442d4249c66..a3064fc0981f6 100644 --- a/src/Symfony/Component/Console/Helper/TableCell.php +++ b/src/Symfony/Component/Console/Helper/TableCell.php @@ -37,6 +37,10 @@ class TableCell */ public function __construct($value = '', array $options = array()) { + if (is_numeric($value) && !is_string($value)) { + $value = (string) $value; + } + $this->value = $value; // check option names diff --git a/src/Symfony/Component/Console/Tester/CommandTester.php b/src/Symfony/Component/Console/Tester/CommandTester.php index 2c547a8f667ea..080ace5c95911 100644 --- a/src/Symfony/Component/Console/Tester/CommandTester.php +++ b/src/Symfony/Component/Console/Tester/CommandTester.php @@ -155,7 +155,7 @@ private static function createStream(array $inputs) { $stream = fopen('php://memory', 'r+', false); - fputs($stream, implode(PHP_EOL, $inputs)); + fwrite($stream, implode(PHP_EOL, $inputs)); rewind($stream); return $stream; diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/interactive_command_1.php b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/interactive_command_1.php index c370c00106b25..3c9c744050185 100644 --- a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/interactive_command_1.php +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/interactive_command_1.php @@ -9,7 +9,7 @@ $output = new SymfonyStyle($input, $output); $stream = fopen('php://memory', 'r+', false); - fputs($stream, "Foo\nBar\nBaz"); + fwrite($stream, "Foo\nBar\nBaz"); rewind($stream); $input->setStream($stream); diff --git a/src/Symfony/Component/Console/Tests/Helper/ProcessHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/ProcessHelperTest.php index 1dcddf8badd49..b0d7f9c2f6f4c 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProcessHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProcessHelperTest.php @@ -16,6 +16,7 @@ use Symfony\Component\Console\Output\StreamOutput; use Symfony\Component\Console\Helper\ProcessHelper; use Symfony\Component\Process\Process; +use Symfony\Component\Process\ProcessBuilder; class ProcessHelperTest extends \PHPUnit_Framework_TestCase { @@ -83,9 +84,9 @@ public function provideCommandsAndOutput() EOT; $errorMessage = 'An error occurred'; - if ('\\' === DIRECTORY_SEPARATOR) { - $successOutputProcessDebug = str_replace("'", '"', $successOutputProcessDebug); - } + $args = new ProcessBuilder(array('php', '-r', 'echo 42;')); + $args = $args->getProcess()->getCommandLine(); + $successOutputProcessDebug = str_replace("'php' '-r' 'echo 42;'", $args, $successOutputProcessDebug); return array( array('', 'php -r "echo 42;"', StreamOutput::VERBOSITY_VERBOSE, null), diff --git a/src/Symfony/Component/Console/Tests/Helper/TableTest.php b/src/Symfony/Component/Console/Tests/Helper/TableTest.php index 1ea7b11f646f6..f70d84b591449 100644 --- a/src/Symfony/Component/Console/Tests/Helper/TableTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/TableTest.php @@ -35,9 +35,9 @@ protected function tearDown() /** * @dataProvider testRenderProvider */ - public function testRender($headers, $rows, $style, $expected) + public function testRender($headers, $rows, $style, $expected, $decorated = false) { - $table = new Table($output = $this->getOutputStream()); + $table = new Table($output = $this->getOutputStream($decorated)); $table ->setHeaders($headers) ->setRows($rows) @@ -51,9 +51,9 @@ public function testRender($headers, $rows, $style, $expected) /** * @dataProvider testRenderProvider */ - public function testRenderAddRows($headers, $rows, $style, $expected) + public function testRenderAddRows($headers, $rows, $style, $expected, $decorated = false) { - $table = new Table($output = $this->getOutputStream()); + $table = new Table($output = $this->getOutputStream($decorated)); $table ->setHeaders($headers) ->addRows($rows) @@ -67,9 +67,9 @@ public function testRenderAddRows($headers, $rows, $style, $expected) /** * @dataProvider testRenderProvider */ - public function testRenderAddRowsOneByOne($headers, $rows, $style, $expected) + public function testRenderAddRowsOneByOne($headers, $rows, $style, $expected, $decorated = false) { - $table = new Table($output = $this->getOutputStream()); + $table = new Table($output = $this->getOutputStream($decorated)); $table ->setHeaders($headers) ->setStyle($style) @@ -485,6 +485,35 @@ public function testRenderProvider() TABLE ), + 'Coslpan and table cells with comment style' => array( + array( + new TableCell('Long Title', array('colspan' => 3)), + ), + array( + array( + new TableCell('9971-5-0210-0', array('colspan' => 3)), + ), + new TableSeparator(), + array( + 'Dante Alighieri', + 'J. R. R. Tolkien', + 'J. R. R', + ), + ), + 'default', + <<assertEquals($expected, $this->getOutputContent($output)); + } + + public function testTableCellWithNumericIntValue() + { + $table = new Table($output = $this->getOutputStream()); + + $table->setRows(array(array(new TableCell(12345)))); + $table->render(); + + $expected = +<<<'TABLE' ++-------+ +| 12345 | ++-------+ + +TABLE; + + $this->assertEquals($expected, $this->getOutputContent($output)); + } + + public function testTableCellWithNumericFloatValue() + { + $table = new Table($output = $this->getOutputStream()); + + $table->setRows(array(array(new TableCell(12345.01)))); + $table->render(); + + $expected = +<<<'TABLE' ++----------+ +| 12345.01 | ++----------+ + TABLE; $this->assertEquals($expected, $this->getOutputContent($output)); @@ -713,9 +778,9 @@ public function testGetStyleDefinition() Table::getStyleDefinition('absent'); } - protected function getOutputStream() + protected function getOutputStream($decorated = false) { - return new StreamOutput($this->stream, StreamOutput::VERBOSITY_NORMAL, false); + return new StreamOutput($this->stream, StreamOutput::VERBOSITY_NORMAL, $decorated); } protected function getOutputContent(StreamOutput $output) diff --git a/src/Symfony/Component/Console/Tests/Style/SymfonyStyleTest.php b/src/Symfony/Component/Console/Tests/Style/SymfonyStyleTest.php index 3338f4b055cc4..92d9d92c7a089 100644 --- a/src/Symfony/Component/Console/Tests/Style/SymfonyStyleTest.php +++ b/src/Symfony/Component/Console/Tests/Style/SymfonyStyleTest.php @@ -31,6 +31,7 @@ protected function setUp() protected function tearDown() { + putenv('COLUMNS'); $this->command = null; $this->tester = null; } diff --git a/src/Symfony/Component/Debug/ErrorHandler.php b/src/Symfony/Component/Debug/ErrorHandler.php index f03a93d6826db..6805ef156aa02 100644 --- a/src/Symfony/Component/Debug/ErrorHandler.php +++ b/src/Symfony/Component/Debug/ErrorHandler.php @@ -225,7 +225,7 @@ public function setLoggers(array $loggers) if ($flush) { foreach ($this->bootstrappingLogger->cleanLogs() as $log) { - $type = $log[2]['exception']->getSeverity(); + $type = $log[2]['exception'] instanceof \ErrorException ? $log[2]['exception']->getSeverity() : E_ERROR; if (!isset($flush[$type])) { $this->bootstrappingLogger->log($log[0], $log[1], $log[2]); } elseif ($this->loggers[$type][0]) { @@ -352,12 +352,10 @@ private function reRegister($prev) /** * Handles errors by filtering then logging them according to the configured bit fields. * - * @param int $type One of the E_* constants + * @param int $type One of the E_* constants * @param string $message * @param string $file * @param int $line - * @param array $context - * @param array $backtrace * * @return bool Returns false when no handling happens so that the PHP engine can handle the error itself * @@ -365,7 +363,7 @@ private function reRegister($prev) * * @internal */ - public function handleError($type, $message, $file, $line, array $context, array $backtrace = null) + public function handleError($type, $message, $file, $line) { // Level is the current error reporting level to manage silent error. // Strong errors are not authorized to be silenced. @@ -377,9 +375,20 @@ public function handleError($type, $message, $file, $line, array $context, array if (!$type || (!$log && !$throw)) { return $type && $log; } + $scope = $this->scopedErrors & $type; - if (isset($context['GLOBALS']) && ($this->scopedErrors & $type)) { - unset($context['GLOBALS']); + if (4 < $numArgs = func_num_args()) { + $context = $scope ? (func_get_arg(4) ?: array()) : array(); + $backtrace = 5 < $numArgs ? func_get_arg(5) : null; // defined on HHVM + } else { + $context = array(); + $backtrace = null; + } + + if (isset($context['GLOBALS']) && $scope) { + $e = $context; // Whatever the signature of the method, + unset($e['GLOBALS'], $context); // $context is always a reference in 5.3 + $context = $e; } if (null !== $backtrace && $type & E_ERROR) { @@ -399,7 +408,7 @@ public function handleError($type, $message, $file, $line, array $context, array } elseif (!$throw && !($type & $level)) { $errorAsException = new SilencedErrorContext($type, $file, $line); } else { - if ($this->scopedErrors & $type) { + if ($scope) { $errorAsException = new ContextErrorException($logMessage, 0, $type, $file, $line, $context); } else { $errorAsException = new \ErrorException($logMessage, 0, $type, $file, $line); diff --git a/src/Symfony/Component/Debug/Exception/FlattenException.php b/src/Symfony/Component/Debug/Exception/FlattenException.php index 51baeb9be8b75..286a71ec143c6 100644 --- a/src/Symfony/Component/Debug/Exception/FlattenException.php +++ b/src/Symfony/Component/Debug/Exception/FlattenException.php @@ -237,7 +237,7 @@ private function flattenArgs($args, $level = 0, &$count = 0) $result[$key] = array('null', null); } elseif (is_bool($value)) { $result[$key] = array('boolean', $value); - } elseif (is_integer($value)) { + } elseif (is_int($value)) { $result[$key] = array('integer', $value); } elseif (is_float($value)) { $result[$key] = array('float', $value); diff --git a/src/Symfony/Component/Debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php b/src/Symfony/Component/Debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php index c48d0d3fa5ae2..32ba9a09c5777 100644 --- a/src/Symfony/Component/Debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php +++ b/src/Symfony/Component/Debug/FatalErrorHandler/ClassNotFoundFatalErrorHandler.php @@ -173,7 +173,7 @@ private function convertFileToClass($path, $file, $prefix) ); if ($prefix) { - $candidates = array_filter($candidates, function ($candidate) use ($prefix) {return 0 === strpos($candidate, $prefix);}); + $candidates = array_filter($candidates, function ($candidate) use ($prefix) { return 0 === strpos($candidate, $prefix); }); } // We cannot use the autoloader here as most of them use require; but if the class diff --git a/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php b/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php index bc568fa3fa23b..3a5da7f4e26cf 100644 --- a/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php +++ b/src/Symfony/Component/Debug/Tests/ErrorHandlerTest.php @@ -417,6 +417,25 @@ public function testBootstrappingLogger() $handler->setLoggers(array(E_DEPRECATED => array($mockLogger, LogLevel::WARNING))); } + public function testSettingLoggerWhenExceptionIsBuffered() + { + $bootLogger = new BufferingLogger(); + $handler = new ErrorHandler($bootLogger); + + $exception = new \Exception('Foo message'); + + $mockLogger = $this->getMockBuilder('Psr\Log\LoggerInterface')->getMock(); + $mockLogger->expects($this->once()) + ->method('log') + ->with(LogLevel::CRITICAL, 'Uncaught Exception: Foo message', array('exception' => $exception)); + + $handler->setExceptionHandler(function () use ($handler, $mockLogger) { + $handler->setDefaultLogger($mockLogger); + }); + + $handler->handleException($exception); + } + public function testHandleFatalError() { try { diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index d1b1fd292cf06..fcb986383c3de 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -114,8 +114,10 @@ private function completeDefinition($id, Definition $definition) throw new RuntimeException(sprintf('Unable to autowire argument index %d ($%s) for the service "%s". If this is an object, give it a type-hint. Otherwise, specify this argument\'s value explicitly.', $index, $parameter->name, $id)); } - // specifically pass the default value - $arguments[$index] = $parameter->getDefaultValue(); + if (!array_key_exists($index, $arguments)) { + // specifically pass the default value + $arguments[$index] = $parameter->getDefaultValue(); + } continue; } @@ -345,10 +347,11 @@ private static function getResourceMetadataForMethod(\ReflectionMethod $method) $class = false; } + $isVariadic = method_exists($parameter, 'isVariadic') && $parameter->isVariadic(); $methodArgumentsMetadata[] = array( 'class' => $class, 'isOptional' => $parameter->isOptional(), - 'defaultValue' => $parameter->isOptional() ? $parameter->getDefaultValue() : null, + 'defaultValue' => ($parameter->isOptional() && !$isVariadic) ? $parameter->getDefaultValue() : null, ); } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/CheckCircularReferencesPass.php b/src/Symfony/Component/DependencyInjection/Compiler/CheckCircularReferencesPass.php index 156bcc0c3ab7b..f39a89af2be71 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/CheckCircularReferencesPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/CheckCircularReferencesPass.php @@ -60,7 +60,6 @@ private function checkOutEdges(array $edges) $id = $node->getId(); if (empty($this->checkedNodes[$id])) { - // don't check circular dependencies for lazy services if (!$node->getValue() || !$node->getValue()->isLazy()) { $searchKey = array_search($id, $this->currentPath); diff --git a/src/Symfony/Component/DependencyInjection/Definition.php b/src/Symfony/Component/DependencyInjection/Definition.php index 96928142264d8..d8e954329fa71 100644 --- a/src/Symfony/Component/DependencyInjection/Definition.php +++ b/src/Symfony/Component/DependencyInjection/Definition.php @@ -106,7 +106,7 @@ public function setDecoratedService($id, $renamedId = null, $priority = 0) } /** - * Gets the service that decorates this service. + * Gets the service that this service is decorating. * * @return null|array An array composed of the decorated service id, the new id for it and the priority of decoration, null if no service is decorated */ @@ -198,6 +198,10 @@ public function addArgument($argument) */ public function replaceArgument($index, $argument) { + if (0 === count($this->arguments)) { + throw new OutOfBoundsException('Cannot replace arguments if none have been configured yet.'); + } + if ($index < 0 || $index > count($this->arguments) - 1) { throw new OutOfBoundsException(sprintf('The index "%d" is not in the range [0, %d].', $index, count($this->arguments) - 1)); } diff --git a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php index 06cc506e670c9..a8f00986f7b18 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/YamlFileLoader.php @@ -110,7 +110,7 @@ public function supports($resource, $type = null) * @param array $content * @param string $file */ - private function parseImports($content, $file) + private function parseImports(array $content, $file) { if (!isset($content['imports'])) { return; @@ -137,7 +137,7 @@ private function parseImports($content, $file) * @param array $content * @param string $file */ - private function parseDefinitions($content, $file) + private function parseDefinitions(array $content, $file) { if (!isset($content['services'])) { return; @@ -155,9 +155,9 @@ private function parseDefinitions($content, $file) /** * Parses a definition. * - * @param string $id - * @param array $service - * @param string $file + * @param string $id + * @param array|string $service + * @param string $file * * @throws InvalidArgumentException When tags are invalid */ @@ -486,7 +486,7 @@ private function resolveServices($value) * * @param array $content */ - private function loadFromExtensions($content) + private function loadFromExtensions(array $content) { foreach ($content as $namespace => $values) { if (in_array($namespace, array('imports', 'parameters', 'services'))) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index 16c8130cd5cad..212b93d9724f3 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -14,6 +14,7 @@ use Symfony\Component\DependencyInjection\Compiler\AutowirePass; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; +use Symfony\Component\DependencyInjection\Tests\Fixtures\includes\FooVariadic; /** * @author Kévin Dunglas @@ -35,6 +36,23 @@ public function testProcess() $this->assertEquals('foo', (string) $container->getDefinition('bar')->getArgument(0)); } + /** + * @requires PHP 5.6 + */ + public function testProcessVariadic() + { + $container = new ContainerBuilder(); + $container->register('foo', Foo::class); + $definition = $container->register('fooVariadic', FooVariadic::class); + $definition->setAutowired(true); + + $pass = new AutowirePass(); + $pass->process($container); + + $this->assertCount(1, $container->getDefinition('fooVariadic')->getArguments()); + $this->assertEquals('foo', (string) $container->getDefinition('fooVariadic')->getArgument(0)); + } + public function testProcessAutowireParent() { $container = new ContainerBuilder(); @@ -476,6 +494,22 @@ public function testIgnoreServiceWithClassNotExisting() $this->assertTrue($container->hasDefinition('bar')); } + + public function testEmptyStringIsKept() + { + $container = new ContainerBuilder(); + + $container->register('a', __NAMESPACE__.'\A'); + $container->register('lille', __NAMESPACE__.'\Lille'); + $container->register('foo', __NAMESPACE__.'\MultipleArgumentsOptionalScalar') + ->setAutowired(true) + ->setArguments(array('', '')); + + $pass = new AutowirePass(); + $pass->process($container); + + $this->assertEquals(array(new Reference('a'), '', new Reference('lille')), $container->getDefinition('foo')->getArguments()); + } } class Foo diff --git a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php index 6a85f8044bde6..9b89b339412fb 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/DefinitionTest.php @@ -257,6 +257,7 @@ public function testGetArgumentShouldCheckBounds() /** * @expectedException \OutOfBoundsException + * @expectedExceptionMessage The index "1" is not in the range [0, 0]. */ public function testReplaceArgumentShouldCheckBounds() { @@ -266,6 +267,16 @@ public function testReplaceArgumentShouldCheckBounds() $def->replaceArgument(1, 'bar'); } + /** + * @expectedException \OutOfBoundsException + * @expectedExceptionMessage Cannot replace arguments if none have been configured yet. + */ + public function testReplaceArgumentWithoutExistingArgumentsShouldCheckBounds() + { + $def = new Definition('stdClass'); + $def->replaceArgument(0, 'bar'); + } + public function testSetGetProperties() { $def = new Definition('stdClass'); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/FooVariadic.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/FooVariadic.php new file mode 100644 index 0000000000000..12861c5611735 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/FooVariadic.php @@ -0,0 +1,16 @@ +validateOnParse = true; - set_error_handler(function () {throw new \Exception();}); + set_error_handler(function () { throw new \Exception(); }); try { // Convert charset to HTML-entities to work around bugs in DOMDocument::loadHTML() diff --git a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php index 90c060665bb5f..0d655a32d8e26 100755 --- a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php @@ -30,14 +30,14 @@ public function testConstructor() public function testGetUri() { $uri = 'http://symfony.com'; - $crawler = new Crawler(null, $uri); + $crawler = new Crawler(null, $uri); $this->assertEquals($uri, $crawler->getUri()); } public function testGetBaseHref() { $baseHref = 'http://symfony.com'; - $crawler = new Crawler(null, null, $baseHref); + $crawler = new Crawler(null, null, $baseHref); $this->assertEquals($baseHref, $crawler->getBaseHref()); } diff --git a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php index ca26ae572e363..af90793282948 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/DateType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/DateType.php @@ -56,11 +56,11 @@ public function buildForm(FormBuilderInterface $builder, array $options) throw new InvalidOptionsException('The "format" option must be one of the IntlDateFormatter constants (FULL, LONG, MEDIUM, SHORT) or a string representing a custom format.'); } - if (null !== $pattern && (false === strpos($pattern, 'y') || false === strpos($pattern, 'M') || false === strpos($pattern, 'd'))) { - throw new InvalidOptionsException(sprintf('The "format" option should contain the letters "y", "M" and "d". Its current value is "%s".', $pattern)); - } - if ('single_text' === $options['widget']) { + if (null !== $pattern && false === strpos($pattern, 'y') && false === strpos($pattern, 'M') && false === strpos($pattern, 'd')) { + throw new InvalidOptionsException(sprintf('The "format" option should contain the letters "y", "M" or "d". Its current value is "%s".', $pattern)); + } + $builder->addViewTransformer(new DateTimeToLocalizedStringTransformer( $options['model_timezone'], $options['view_timezone'], @@ -70,6 +70,10 @@ public function buildForm(FormBuilderInterface $builder, array $options) $pattern )); } else { + if (null !== $pattern && (false === strpos($pattern, 'y') || false === strpos($pattern, 'M') || false === strpos($pattern, 'd'))) { + throw new InvalidOptionsException(sprintf('The "format" option should contain the letters "y", "M" and "d". Its current value is "%s".', $pattern)); + } + $yearOptions = $monthOptions = $dayOptions = array( 'error_bubbling' => true, ); @@ -212,7 +216,7 @@ public function configureOptions(OptionsResolver $resolver) array('year' => $default, 'month' => $default, 'day' => $default), $choiceTranslationDomain ); - }; + } return array( 'year' => $choiceTranslationDomain, diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php b/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php index 4ba23a8c8b2e5..d1c04f73d9278 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php @@ -213,7 +213,7 @@ public function configureOptions(OptionsResolver $resolver) array('hour' => $default, 'minute' => $default, 'second' => $default), $choiceTranslationDomain ); - }; + } return array( 'hour' => $choiceTranslationDomain, diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php index 9b33db2a654ac..628a71f14c895 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/DateTypeTest.php @@ -67,12 +67,28 @@ public function testSubmitFromSingleTextDateTimeWithDefaultFormat() $this->assertEquals('2010-06-02', $form->getViewData()); } + public function testSubmitFromSingleTextDateTimeWithCustomFormat() + { + $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\DateType', null, array( + 'model_timezone' => 'UTC', + 'view_timezone' => 'UTC', + 'widget' => 'single_text', + 'input' => 'datetime', + 'format' => 'yyyy', + )); + + $form->submit('2010'); + + $this->assertDateTimeEquals(new \DateTime('2010-01-01 UTC'), $form->getData()); + $this->assertEquals('2010', $form->getViewData()); + } + public function testSubmitFromSingleTextDateTime() { - // we test against "de_AT", so we need the full implementation + // we test against "de_DE", so we need the full implementation IntlTestHelper::requireFullIntl($this, false); - \Locale::setDefault('de_AT'); + \Locale::setDefault('de_DE'); $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\DateType', null, array( 'format' => \IntlDateFormatter::MEDIUM, @@ -90,10 +106,10 @@ public function testSubmitFromSingleTextDateTime() public function testSubmitFromSingleTextString() { - // we test against "de_AT", so we need the full implementation + // we test against "de_DE", so we need the full implementation IntlTestHelper::requireFullIntl($this, false); - \Locale::setDefault('de_AT'); + \Locale::setDefault('de_DE'); $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\DateType', null, array( 'format' => \IntlDateFormatter::MEDIUM, @@ -111,10 +127,10 @@ public function testSubmitFromSingleTextString() public function testSubmitFromSingleTextTimestamp() { - // we test against "de_AT", so we need the full implementation + // we test against "de_DE", so we need the full implementation IntlTestHelper::requireFullIntl($this, false); - \Locale::setDefault('de_AT'); + \Locale::setDefault('de_DE'); $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\DateType', null, array( 'format' => \IntlDateFormatter::MEDIUM, @@ -134,10 +150,10 @@ public function testSubmitFromSingleTextTimestamp() public function testSubmitFromSingleTextRaw() { - // we test against "de_AT", so we need the full implementation + // we test against "de_DE", so we need the full implementation IntlTestHelper::requireFullIntl($this, false); - \Locale::setDefault('de_AT'); + \Locale::setDefault('de_DE'); $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\DateType', null, array( 'format' => \IntlDateFormatter::MEDIUM, @@ -337,6 +353,7 @@ public function testThrowExceptionIfFormatIsNoPattern() /** * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + * @expectedExceptionMessage The "format" option should contain the letters "y", "M" and "d". Its current value is "yy". */ public function testThrowExceptionIfFormatDoesNotContainYearMonthAndDay() { @@ -346,6 +363,18 @@ public function testThrowExceptionIfFormatDoesNotContainYearMonthAndDay() )); } + /** + * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException + * @expectedExceptionMessage The "format" option should contain the letters "y", "M" or "d". Its current value is "wrong". + */ + public function testThrowExceptionIfFormatMissesYearMonthAndDayWithSingleTextWidget() + { + $this->factory->create('Symfony\Component\Form\Extension\Core\Type\DateType', null, array( + 'widget' => 'single_text', + 'format' => 'wrong', + )); + } + /** * @expectedException \Symfony\Component\OptionsResolver\Exception\InvalidOptionsException */ @@ -398,10 +427,10 @@ public function testThrowExceptionIfDaysIsInvalid() public function testSetDataWithNegativeTimezoneOffsetStringInput() { - // we test against "de_AT", so we need the full implementation + // we test against "de_DE", so we need the full implementation IntlTestHelper::requireFullIntl($this, false); - \Locale::setDefault('de_AT'); + \Locale::setDefault('de_DE'); $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\DateType', null, array( 'format' => \IntlDateFormatter::MEDIUM, @@ -420,10 +449,10 @@ public function testSetDataWithNegativeTimezoneOffsetStringInput() public function testSetDataWithNegativeTimezoneOffsetDateTimeInput() { - // we test against "de_AT", so we need the full implementation + // we test against "de_DE", so we need the full implementation IntlTestHelper::requireFullIntl($this, false); - \Locale::setDefault('de_AT'); + \Locale::setDefault('de_DE'); $form = $this->factory->create('Symfony\Component\Form\Extension\Core\Type\DateType', null, array( 'format' => \IntlDateFormatter::MEDIUM, diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 54cc5f4de38eb..dc23d2ca1a1d7 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -596,6 +596,7 @@ public static function getTrustedHosts() * * Request::HEADER_CLIENT_HOST: defaults to X-Forwarded-Host (see getHost()) * * Request::HEADER_CLIENT_PORT: defaults to X-Forwarded-Port (see getPort()) * * Request::HEADER_CLIENT_PROTO: defaults to X-Forwarded-Proto (see getScheme() and isSecure()) + * * Request::HEADER_FORWARDED: defaults to Forwarded (see RFC 7239) * * Setting an empty value allows to disable the trusted header for the given key. * diff --git a/src/Symfony/Component/HttpKernel/Bundle/Bundle.php b/src/Symfony/Component/HttpKernel/Bundle/Bundle.php index 68e1157e4510b..8505bbbddd3f0 100644 --- a/src/Symfony/Component/HttpKernel/Bundle/Bundle.php +++ b/src/Symfony/Component/HttpKernel/Bundle/Bundle.php @@ -223,6 +223,8 @@ private function parseClassName() { $pos = strrpos(static::class, '\\'); $this->namespace = false === $pos ? '' : substr(static::class, 0, $pos); - $this->name = false === $pos ? static::class : substr(static::class, $pos + 1); + if (null === $this->name) { + $this->name = false === $pos ? static::class : substr(static::class, $pos + 1); + } } } diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php index e1ab2cc473b98..b638ba79059bd 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php @@ -290,7 +290,7 @@ private function htmlEncode($s) { $html = ''; - $dumper = new HtmlDumper(function ($line) use (&$html) {$html .= $line;}, $this->charset); + $dumper = new HtmlDumper(function ($line) use (&$html) { $html .= $line; }, $this->charset); $dumper->setDumpHeader(''); $dumper->setDumpBoundaries('', ''); diff --git a/src/Symfony/Component/HttpKernel/EventListener/AddRequestFormatsListener.php b/src/Symfony/Component/HttpKernel/EventListener/AddRequestFormatsListener.php index 14a5d435115d7..280844c18313e 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/AddRequestFormatsListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/AddRequestFormatsListener.php @@ -52,6 +52,6 @@ public function onKernelRequest(GetResponseEvent $event) */ public static function getSubscribedEvents() { - return array(KernelEvents::REQUEST => 'onKernelRequest'); + return array(KernelEvents::REQUEST => array('onKernelRequest', 1)); } } diff --git a/src/Symfony/Component/HttpKernel/EventListener/DebugHandlersListener.php b/src/Symfony/Component/HttpKernel/EventListener/DebugHandlersListener.php index ef2b17ff63ec1..29e1725adc672 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/DebugHandlersListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/DebugHandlersListener.php @@ -137,7 +137,7 @@ public static function getSubscribedEvents() { $events = array(KernelEvents::REQUEST => array('configure', 2048)); - if ('cli' === php_sapi_name() && defined('Symfony\Component\Console\ConsoleEvents::COMMAND')) { + if ('cli' === PHP_SAPI && defined('Symfony\Component\Console\ConsoleEvents::COMMAND')) { $events[ConsoleEvents::COMMAND] = array('configure', 2048); } diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 0f8d13868d28e..6bc132aa2d3c7 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,11 +58,11 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '3.2.2'; - const VERSION_ID = 30202; + const VERSION = '3.2.3'; + const VERSION_ID = 30203; const MAJOR_VERSION = 3; const MINOR_VERSION = 2; - const RELEASE_VERSION = 2; + const RELEASE_VERSION = 3; const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '07/2017'; diff --git a/src/Symfony/Component/HttpKernel/Tests/Bundle/BundleTest.php b/src/Symfony/Component/HttpKernel/Tests/Bundle/BundleTest.php index 0b11f8253c8b6..a8b91453c672e 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Bundle/BundleTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Bundle/BundleTest.php @@ -12,6 +12,7 @@ namespace Symfony\Component\HttpKernel\Tests\Bundle; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\HttpKernel\Bundle\Bundle; use Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionNotValidBundle\ExtensionNotValidBundle; use Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionPresentBundle\ExtensionPresentBundle; use Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionAbsentBundle\ExtensionAbsentBundle; @@ -66,4 +67,33 @@ public function testHttpKernelRegisterCommandsIgnoresCommandsThatAreRegisteredAs $bundle->setContainer($container); $bundle->registerCommands($application); } + + public function testBundleNameIsGuessedFromClass() + { + $bundle = new GuessedNameBundle(); + + $this->assertSame('Symfony\Component\HttpKernel\Tests\Bundle', $bundle->getNamespace()); + $this->assertSame('GuessedNameBundle', $bundle->getName()); + } + + public function testBundleNameCanBeExplicitlyProvided() + { + $bundle = new NamedBundle(); + + $this->assertSame('ExplicitlyNamedBundle', $bundle->getName()); + $this->assertSame('Symfony\Component\HttpKernel\Tests\Bundle', $bundle->getNamespace()); + $this->assertSame('ExplicitlyNamedBundle', $bundle->getName()); + } +} + +class NamedBundle extends Bundle +{ + public function __construct() + { + $this->name = 'ExplicitlyNamedBundle'; + } +} + +class GuessedNameBundle extends Bundle +{ } diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/AddRequestFormatsListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/AddRequestFormatsListenerTest.php index 0f3577cbdb14b..c5b2c51e40ecb 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/AddRequestFormatsListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/AddRequestFormatsListenerTest.php @@ -45,7 +45,7 @@ public function testIsAnEventSubscriber() public function testRegisteredEvent() { $this->assertEquals( - array(KernelEvents::REQUEST => 'onKernelRequest'), + array(KernelEvents::REQUEST => array('onKernelRequest', 1)), AddRequestFormatsListener::getSubscribedEvents() ); } diff --git a/src/Symfony/Component/Intl/Data/Generator/AbstractDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/AbstractDataGenerator.php index 84b7f74373992..6b7cf5a0caf1d 100644 --- a/src/Symfony/Component/Intl/Data/Generator/AbstractDataGenerator.php +++ b/src/Symfony/Component/Intl/Data/Generator/AbstractDataGenerator.php @@ -42,9 +42,6 @@ public function __construct(GenrbCompiler $compiler, $dirName) $this->dirName = $dirName; } - /** - * {@inheritdoc} - */ public function generateData(GeneratorConfig $config) { $filesystem = new Filesystem(); diff --git a/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php b/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php index 5f4f95102fd85..e89e5e8757b67 100644 --- a/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php +++ b/src/Symfony/Component/Intl/Data/Generator/LocaleDataGenerator.php @@ -57,9 +57,6 @@ public function __construct($dirName, LanguageDataProvider $languageDataProvider $this->regionDataProvider = $regionDataProvider; } - /** - * {@inheritdoc} - */ public function generateData(GeneratorConfig $config) { $filesystem = new Filesystem(); diff --git a/src/Symfony/Component/Intl/Util/IntlTestHelper.php b/src/Symfony/Component/Intl/Util/IntlTestHelper.php index 71fb4acdd72fa..c1e37a72ec8a4 100644 --- a/src/Symfony/Component/Intl/Util/IntlTestHelper.php +++ b/src/Symfony/Component/Intl/Util/IntlTestHelper.php @@ -41,7 +41,7 @@ public static function requireIntl(\PHPUnit_Framework_TestCase $testCase, $minim // * the intl extension is loaded with version Intl::getIcuStubVersion() // * the intl extension is not loaded - if (($minimumIcuVersion || defined('HHVM_VERSION_ID')) && IcuVersion::compare(Intl::getIcuVersion(), $minimumIcuVersion, '!=', 1)) { + if (($minimumIcuVersion || defined('HHVM_VERSION_ID')) && IcuVersion::compare(Intl::getIcuVersion(), $minimumIcuVersion, '<', 1)) { $testCase->markTestSkipped('ICU version '.$minimumIcuVersion.' is required.'); } diff --git a/src/Symfony/Component/Process/ProcessUtils.php b/src/Symfony/Component/Process/ProcessUtils.php index 500202e5844cd..cbc95708ed4a6 100644 --- a/src/Symfony/Component/Process/ProcessUtils.php +++ b/src/Symfony/Component/Process/ProcessUtils.php @@ -71,7 +71,7 @@ public static function escapeArgument($argument) return $escapedArgument; } - return escapeshellarg($argument); + return "'".str_replace("'", "'\\''", $argument)."'"; } /** diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index 811c98f15e7d8..c19206117e9fc 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -1281,7 +1281,7 @@ public function testInputStreamOnEmpty() { $i = 0; $input = new InputStream(); - $input->onEmpty(function () use (&$i) {++$i;}); + $input->onEmpty(function () use (&$i) { ++$i; }); $process = $this->getProcess(self::$phpBin.' -r '.escapeshellarg('echo 123; echo fread(STDIN, 1); echo 456;')); $process->setInput($input); diff --git a/src/Symfony/Component/Process/Tests/ProcessUtilsTest.php b/src/Symfony/Component/Process/Tests/ProcessUtilsTest.php index e6564cde5ba6d..0f554b6151801 100644 --- a/src/Symfony/Component/Process/Tests/ProcessUtilsTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessUtilsTest.php @@ -43,6 +43,7 @@ public function dataArguments() array("'<|>\" \"'\\''f'", '<|>" "\'f'), array("''", ''), array("'with\\trailingbs\\'", 'with\trailingbs\\'), + array("'withNonAsciiAccentLikeéÉèÈàÀöä'", 'withNonAsciiAccentLikeéÉèÈàÀöä'), ); } } diff --git a/src/Symfony/Component/Process/Tests/SignalListener.php b/src/Symfony/Component/Process/Tests/SignalListener.php index 03536577c40f2..9e30ce3bbbbc6 100644 --- a/src/Symfony/Component/Process/Tests/SignalListener.php +++ b/src/Symfony/Component/Process/Tests/SignalListener.php @@ -9,7 +9,7 @@ * file that was distributed with this source code. */ -pcntl_signal(SIGUSR1, function () {echo 'SIGUSR1'; exit;}); +pcntl_signal(SIGUSR1, function () { echo 'SIGUSR1'; exit; }); echo 'Caught '; diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccess.php b/src/Symfony/Component/PropertyAccess/PropertyAccess.php index 66a7e3a43fdf5..3c8dc1c56cc18 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccess.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccess.php @@ -31,7 +31,7 @@ public static function createPropertyAccessor() /** * Creates a property accessor builder. * - * @return PropertyAccessor + * @return PropertyAccessorBuilder */ public static function createPropertyAccessorBuilder() { diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 618007ef59980..6019544a19e8c 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -267,7 +267,7 @@ public static function handleError($type, $message, $file, $line, $context) private static function throwInvalidArgumentException($message, $trace, $i) { if (isset($trace[$i]['file']) && __FILE__ === $trace[$i]['file']) { - $pos = strpos($message, $delim = 'must be of the type ') ?: strpos($message, $delim = 'must be an instance of '); + $pos = strpos($message, $delim = 'must be of the type ') ?: (strpos($message, $delim = 'must be an instance of ') ?: strpos($message, $delim = 'must implement interface ')); $pos += strlen($delim); $type = $trace[$i]['args'][0]; $type = is_object($type) ? get_class($type) : gettype($type); diff --git a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TypeHinted.php b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TypeHinted.php index ca4c5745ae06c..ce0f3d89aaa30 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TypeHinted.php +++ b/src/Symfony/Component/PropertyAccess/Tests/Fixtures/TypeHinted.php @@ -18,6 +18,11 @@ class TypeHinted { private $date; + /** + * @var \Countable + */ + private $countable; + public function setDate(\DateTime $date) { $this->date = $date; @@ -27,4 +32,20 @@ public function getDate() { return $this->date; } + + /** + * @return \Countable + */ + public function getCountable() + { + return $this->countable; + } + + /** + * @param \Countable $countable + */ + public function setCountable(\Countable $countable) + { + $this->countable = $countable; + } } diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php index a3a82b0b63cba..33d4085b07969 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php @@ -566,4 +566,15 @@ public function testCacheReadAccess() $propertyAccessor->setValue($obj, 'publicGetSetter', 'baz'); $this->assertEquals('baz', $propertyAccessor->getValue($obj, 'publicGetSetter')); } + + /** + * @expectedException \Symfony\Component\PropertyAccess\Exception\InvalidArgumentException + * @expectedExceptionMessage Expected argument of type "Countable", "string" given + */ + public function testThrowTypeErrorWithInterface() + { + $object = new TypeHinted(); + + $this->propertyAccessor->setValue($object, 'countable', 'This is a string, \Countable expected.'); + } } diff --git a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php index 5e459f4b038d0..f7e4aa871e3cf 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/PhpDocExtractor.php @@ -223,6 +223,9 @@ private function getDocBlockFromMethod($class, $ucFirstProperty, $type) try { $reflectionMethod = new \ReflectionMethod($class, $methodName); + if ($reflectionMethod->isStatic()) { + continue; + } if ( (self::ACCESSOR === $type && 0 === $reflectionMethod->getNumberOfRequiredParameters()) || diff --git a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php index e92da1fcd0088..96c2e9b48ef5f 100644 --- a/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php +++ b/src/Symfony/Component/PropertyInfo/Extractor/ReflectionExtractor.php @@ -73,6 +73,10 @@ public function getProperties($class, array $context = array()) } foreach ($reflectionClass->getMethods(\ReflectionMethod::IS_PUBLIC) as $reflectionMethod) { + if ($reflectionMethod->isStatic()) { + continue; + } + $propertyName = $this->getPropertyName($reflectionMethod->name, $reflectionProperties); if (!$propertyName || isset($properties[$propertyName])) { continue; @@ -263,6 +267,9 @@ private function getAccessorMethod($class, $property) foreach (self::$accessorPrefixes as $prefix) { try { $reflectionMethod = new \ReflectionMethod($class, $prefix.$ucProperty); + if ($reflectionMethod->isStatic()) { + continue; + } if (0 === $reflectionMethod->getNumberOfRequiredParameters()) { return array($reflectionMethod, $prefix); @@ -298,6 +305,9 @@ private function getMutatorMethod($class, $property) foreach ($names as $name) { try { $reflectionMethod = new \ReflectionMethod($class, $prefix.$name); + if ($reflectionMethod->isStatic()) { + continue; + } // Parameter can be optional to allow things like: method(array $foo = null) if ($reflectionMethod->getNumberOfParameters() >= 1) { diff --git a/src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php b/src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php index 942318af605d8..031c8ac05e26a 100644 --- a/src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php +++ b/src/Symfony/Component/PropertyInfo/PropertyInfoExtractor.php @@ -44,7 +44,7 @@ class PropertyInfoExtractor implements PropertyInfoExtractorInterface * @param PropertyDescriptionExtractorInterface[] $descriptionExtractors * @param PropertyAccessExtractorInterface[] $accessExtractors */ - public function __construct(array $listExtractors = array(), array $typeExtractors = array(), array $descriptionExtractors = array(), array $accessExtractors = array()) + public function __construct(array $listExtractors = array(), array $typeExtractors = array(), array $descriptionExtractors = array(), array $accessExtractors = array()) { $this->listExtractors = $listExtractors; $this->typeExtractors = $typeExtractors; diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php index a8cc99ece0d08..942dd74c9cd3b 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractors/PhpDocExtractorTest.php @@ -68,6 +68,8 @@ public function typesProvider() array('e', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_RESOURCE))), null, null), array('f', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime'))), null, null), array('donotexist', null, null, null), + array('staticGetter', null, null, null), + array('staticSetter', null, null, null), ); } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php b/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php index 70050f94e6559..91974d689db2b 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Extractors/ReflectionExtractorTest.php @@ -73,6 +73,8 @@ public function typesProvider() array('e', null), array('f', array(new Type(Type::BUILTIN_TYPE_ARRAY, false, null, true, new Type(Type::BUILTIN_TYPE_INT), new Type(Type::BUILTIN_TYPE_OBJECT, false, 'DateTime')))), array('donotexist', null), + array('staticGetter', null), + array('staticSetter', null), ); } diff --git a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php index 41a513ac362e1..96cb87db4a8fa 100644 --- a/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php +++ b/src/Symfony/Component/PropertyInfo/Tests/Fixtures/Dummy.php @@ -51,6 +51,21 @@ class Dummy extends ParentDummy */ public $B; + public static function getStatic() + { + } + + /** + * @return string + */ + public static function staticGetter() + { + } + + public static function staticSetter(\DateTime $d) + { + } + /** * A. * diff --git a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php index 565698e808007..8463673e2d1ac 100644 --- a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php +++ b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php @@ -139,7 +139,7 @@ protected function addRoute(RouteCollection $collection, $annot, $globals, \Refl $defaults = array_replace($globals['defaults'], $annot->getDefaults()); foreach ($method->getParameters() as $param) { - if (!isset($defaults[$param->getName()]) && $param->isDefaultValueAvailable()) { + if (false !== strpos($globals['path'].$annot->getPath(), sprintf('{%s}', $param->getName())) && !isset($defaults[$param->getName()]) && $param->isDefaultValueAvailable()) { $defaults[$param->getName()] = $param->getDefaultValue(); } } diff --git a/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php b/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php index 83bf7108fb28b..44229633b5cbc 100644 --- a/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php +++ b/src/Symfony/Component/Routing/Tests/Loader/AnnotationClassLoaderTest.php @@ -136,11 +136,10 @@ public function testLoad($className, $routeData = array(), $methodArgs = array() array_intersect_assoc($routeData['options'], $route->getOptions()), '->load preserves options annotation' ); - $defaults = array_replace($methodArgs, $routeData['defaults']); $this->assertCount( - count($defaults), - array_intersect_assoc($defaults, $route->getDefaults()), - '->load preserves defaults annotation and merges them with default arguments in method signature' + count($routeData['defaults']), + $route->getDefaults(), + '->load preserves defaults annotation' ); $this->assertEquals($routeData['schemes'], $route->getSchemes(), '->load preserves schemes annotation'); $this->assertEquals($routeData['methods'], $route->getMethods(), '->load preserves methods annotation'); diff --git a/src/Symfony/Component/Security/Core/Tests/User/LdapUserProviderTest.php b/src/Symfony/Component/Security/Core/Tests/User/LdapUserProviderTest.php index a1ef0bbf19e8e..06baeae7d118f 100644 --- a/src/Symfony/Component/Security/Core/Tests/User/LdapUserProviderTest.php +++ b/src/Symfony/Component/Security/Core/Tests/User/LdapUserProviderTest.php @@ -151,6 +151,48 @@ public function testLoadUserByUsernameFailsIfMoreThanOneLdapPasswordsInEntry() ); } + /** + * @expectedException \Symfony\Component\Security\Core\Exception\InvalidArgumentException + */ + public function testLoadUserByUsernameFailsIfEntryHasNoUidKeyAttribute() + { + $result = $this->getMockBuilder(CollectionInterface::class)->getMock(); + $query = $this->getMockBuilder(QueryInterface::class)->getMock(); + $query + ->expects($this->once()) + ->method('execute') + ->will($this->returnValue($result)) + ; + $ldap = $this->getMockBuilder(LdapInterface::class)->getMock(); + $result + ->expects($this->once()) + ->method('offsetGet') + ->with(0) + ->will($this->returnValue(new Entry('foo', array()))) + ; + $result + ->expects($this->once()) + ->method('count') + ->will($this->returnValue(1)) + ; + $ldap + ->expects($this->once()) + ->method('escape') + ->will($this->returnValue('foo')) + ; + $ldap + ->expects($this->once()) + ->method('query') + ->will($this->returnValue($query)) + ; + + $provider = new LdapUserProvider($ldap, 'ou=MyBusiness,dc=symfony,dc=com', null, null, array(), 'sAMAccountName', '({uid_key}={username})'); + $this->assertInstanceOf( + 'Symfony\Component\Security\Core\User\User', + $provider->loadUserByUsername('foo') + ); + } + /** * @expectedException \Symfony\Component\Security\Core\Exception\InvalidArgumentException */ @@ -238,6 +280,45 @@ public function testLoadUserByUsernameIsSuccessfulWithoutPasswordAttribute() ); } + public function testLoadUserByUsernameIsSuccessfulWithoutPasswordAttributeAndWrongCase() + { + $result = $this->getMockBuilder(CollectionInterface::class)->getMock(); + $query = $this->getMockBuilder(QueryInterface::class)->getMock(); + $query + ->expects($this->once()) + ->method('execute') + ->will($this->returnValue($result)) + ; + $ldap = $this->getMockBuilder(LdapInterface::class)->getMock(); + $result + ->expects($this->once()) + ->method('offsetGet') + ->with(0) + ->will($this->returnValue(new Entry('foo', array( + 'sAMAccountName' => array('foo'), + ) + ))) + ; + $result + ->expects($this->once()) + ->method('count') + ->will($this->returnValue(1)) + ; + $ldap + ->expects($this->once()) + ->method('escape') + ->will($this->returnValue('Foo')) + ; + $ldap + ->expects($this->once()) + ->method('query') + ->will($this->returnValue($query)) + ; + + $provider = new LdapUserProvider($ldap, 'ou=MyBusiness,dc=symfony,dc=com'); + $this->assertSame('foo', $provider->loadUserByUsername('Foo')->getUsername()); + } + public function testLoadUserByUsernameIsSuccessfulWithPasswordAttribute() { $result = $this->getMockBuilder(CollectionInterface::class)->getMock(); diff --git a/src/Symfony/Component/Security/Core/User/LdapUserProvider.php b/src/Symfony/Component/Security/Core/User/LdapUserProvider.php index fc42419a6d1ab..1edf3f764ef04 100644 --- a/src/Symfony/Component/Security/Core/User/LdapUserProvider.php +++ b/src/Symfony/Component/Security/Core/User/LdapUserProvider.php @@ -31,6 +31,7 @@ class LdapUserProvider implements UserProviderInterface private $searchDn; private $searchPassword; private $defaultRoles; + private $uidKey; private $defaultSearch; private $passwordAttribute; @@ -46,11 +47,16 @@ class LdapUserProvider implements UserProviderInterface */ public function __construct(LdapInterface $ldap, $baseDn, $searchDn = null, $searchPassword = null, array $defaultRoles = array(), $uidKey = 'sAMAccountName', $filter = '({uid_key}={username})', $passwordAttribute = null) { + if (null === $uidKey) { + $uidKey = 'uid'; + } + $this->ldap = $ldap; $this->baseDn = $baseDn; $this->searchDn = $searchDn; $this->searchPassword = $searchPassword; $this->defaultRoles = $defaultRoles; + $this->uidKey = $uidKey; $this->defaultSearch = str_replace('{uid_key}', $uidKey, $filter); $this->passwordAttribute = $passwordAttribute; } @@ -80,7 +86,10 @@ public function loadUserByUsername($username) throw new UsernameNotFoundException('More than one user found'); } - return $this->loadUser($username, $entries[0]); + $entry = $entries[0]; + $username = $this->getAttributeValue($entry, $this->uidKey); + + return $this->loadUser($username, $entry); } /** @@ -113,30 +122,30 @@ public function supportsClass($class) */ protected function loadUser($username, Entry $entry) { - $password = $this->getPassword($entry); + $password = null; + if (null !== $this->passwordAttribute) { + $password = $this->getAttributeValue($entry, $this->passwordAttribute); + } return new User($username, $password, $this->defaultRoles); } /** - * Fetches the password from an LDAP entry. + * Fetches a required unique attribute value from an LDAP entry. * * @param null|Entry $entry + * @param string $attribute */ - private function getPassword(Entry $entry) + private function getAttributeValue(Entry $entry, $attribute) { - if (null === $this->passwordAttribute) { - return; - } - - if (!$entry->hasAttribute($this->passwordAttribute)) { - throw new InvalidArgumentException(sprintf('Missing attribute "%s" for user "%s".', $this->passwordAttribute, $entry->getDn())); + if (!$entry->hasAttribute($attribute)) { + throw new InvalidArgumentException(sprintf('Missing attribute "%s" for user "%s".', $attribute, $entry->getDn())); } - $values = $entry->getAttribute($this->passwordAttribute); + $values = $entry->getAttribute($attribute); if (1 !== count($values)) { - throw new InvalidArgumentException(sprintf('Attribute "%s" has multiple values.', $this->passwordAttribute)); + throw new InvalidArgumentException(sprintf('Attribute "%s" has multiple values.', $attribute)); } return $values[0]; diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/JsonDecodeTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/JsonDecodeTest.php index c87ab21b510a2..7818aeaf55df8 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/JsonDecodeTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/JsonDecodeTest.php @@ -61,7 +61,7 @@ public function decodeProvider() */ public function testDecodeWithException($value) { - $this->decode->decode($value, JsonEncoder::FORMAT); + $this->decode->decode($value, JsonEncoder::FORMAT); } public function decodeProviderException() diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/JsonEncodeTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/JsonEncodeTest.php index d255b21d22e7f..291c0f0965c80 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/JsonEncodeTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/JsonEncodeTest.php @@ -54,6 +54,6 @@ public function encodeProvider() */ public function testEncodeWithError() { - $this->encode->encode("\xB1\x31", JsonEncoder::FORMAT); + $this->encode->encode("\xB1\x31", JsonEncoder::FORMAT); } } diff --git a/src/Symfony/Component/Serializer/composer.json b/src/Symfony/Component/Serializer/composer.json index 8bbb2b18937b0..d7dbfc6509c09 100644 --- a/src/Symfony/Component/Serializer/composer.json +++ b/src/Symfony/Component/Serializer/composer.json @@ -31,6 +31,7 @@ }, "conflict": { "symfony/property-access": ">=3.0,<3.0.4|>=2.8,<2.8.4", + "symfony/property-info": "<3.1", "symfony/yaml": "<3.1" }, "suggest": { diff --git a/src/Symfony/Component/Translation/Tests/Dumper/FileDumperTest.php b/src/Symfony/Component/Translation/Tests/Dumper/FileDumperTest.php index 2b4b163a758f0..4fcabaf2c985a 100644 --- a/src/Symfony/Component/Translation/Tests/Dumper/FileDumperTest.php +++ b/src/Symfony/Component/Translation/Tests/Dumper/FileDumperTest.php @@ -26,7 +26,7 @@ public function testDump() $dumper = new ConcreteFileDumper(); $dumper->dump($catalogue, array('path' => $tempDir)); - $this->assertTrue(file_exists($tempDir.'/messages.en.concrete')); + $this->assertFileExists($tempDir.'/messages.en.concrete'); } /** diff --git a/src/Symfony/Component/Translation/Util/ArrayConverter.php b/src/Symfony/Component/Translation/Util/ArrayConverter.php index 60a55e9d3709c..9c0a420a8592f 100644 --- a/src/Symfony/Component/Translation/Util/ArrayConverter.php +++ b/src/Symfony/Component/Translation/Util/ArrayConverter.php @@ -62,7 +62,7 @@ private static function &getElementByPath(array &$tree, array $parts) * $tree['foo'] was string before we found array {bar: test2}. * Treat new element as string too, e.g. add $tree['foo.bar'] = 'test2'; */ - $elem = &$elem[ implode('.', array_slice($parts, $i)) ]; + $elem = &$elem[implode('.', array_slice($parts, $i))]; break; } $parentOfElem = &$elem; diff --git a/src/Symfony/Component/Validator/Constraints/BicValidator.php b/src/Symfony/Component/Validator/Constraints/BicValidator.php index f476713c74d14..d2188071fabf1 100644 --- a/src/Symfony/Component/Validator/Constraints/BicValidator.php +++ b/src/Symfony/Component/Validator/Constraints/BicValidator.php @@ -17,7 +17,7 @@ /** * @author Michael Hirschler * - * @link https://en.wikipedia.org/wiki/ISO_9362#Structure + * @see https://en.wikipedia.org/wiki/ISO_9362#Structure */ class BicValidator extends ConstraintValidator { diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf index 541ebaa0a8f85..192b992f8f3ba 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.de.xlf @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini. - Es wurde kein temporärer Ordner in der php.ini konfiguriert. + Es wurde kein temporärer Ordner in der php.ini konfiguriert oder der temporäre Ordner existiert nicht. Cannot write temporary file to disk. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf index ec072eb716dfc..2a5c97d8cf2d0 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.en.xlf @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini. - No temporary folder was configured in php.ini. + No temporary folder was configured in php.ini, or the configured folder does not exist. Cannot write temporary file to disk. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf index a11e825ccadad..8c62d899fdaec 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf @@ -278,6 +278,42 @@ This value should not be identical to {{ compared_value_type }} {{ compared_value }}. Ova vrijednost ne bi trebala biti {{ compared_value_type }} {{ compared_value }}. + + The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. + Omjer slike je prevelik ({{ ratio }}). Dozvoljeni maksimalni omjer je {{ max_ratio }}. + + + The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. + Omjer slike je premali ({{ ratio }}). Minimalni očekivani omjer je {{ min_ratio }}. + + + The image is square ({{ width }}x{{ height }}px). Square images are not allowed. + Slika je kvadratnog oblika ({{ width }}x{{ height }}px). Kvadratne slike nisu dozvoljene. + + + The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. + Slika je orijentirana horizontalno ({{ width }}x{{ height }}px). Horizontalno orijentirane slike nisu dozvoljene. + + + The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. + Slika je orijentirana vertikalno ({{ width }}x{{ height }}px). Vertikalno orijentirane slike nisu dozvoljene. + + + An empty file is not allowed. + Prazna datoteka nije dozvoljena. + + + The host could not be resolved. + Poslužitelj nije mogao biti razriješen. + + + This value does not match the expected {{ charset }} charset. + Znakovne oznake vrijednosti ne odgovaraju očekivanom {{ charset }} skupu. + + + This is not a valid Business Identifier Code (BIC). + Ovo nije validan poslovni identifikacijski broj (BIC). + diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf index f803628e6dc1f..e81141f0eed81 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini. - Er is geen tijdelijke map geconfigureerd in php.ini. + Er is geen tijdelijke map geconfigureerd in php.ini, of de gespecificeerde map bestaat niet. Cannot write temporary file to disk. diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf index ae4ed1df73c26..d364eba937e8d 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pl.xlf @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini. - Nie skonfigurowano folderu tymczasowego w php.ini. + Nie skonfigurowano folderu tymczasowego w php.ini, lub skonfigurowany folder nie istnieje. Cannot write temporary file to disk. diff --git a/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php index d8b1e3d6adb61..30ec8f22a1e8c 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/EmailValidatorTest.php @@ -123,7 +123,7 @@ public function testStrictWithInvalidEmails($email) } /** - * @link https://github.com/egulias/EmailValidator/blob/1.2.8/tests/egulias/Tests/EmailValidator/EmailValidatorTest.php + * @see https://github.com/egulias/EmailValidator/blob/1.2.8/tests/egulias/Tests/EmailValidator/EmailValidatorTest.php */ public function getInvalidEmailsForStrictChecks() { diff --git a/src/Symfony/Component/VarDumper/Cloner/Data.php b/src/Symfony/Component/VarDumper/Cloner/Data.php index 1c6dd0df86b60..22fd2fd1a4a28 100644 --- a/src/Symfony/Component/VarDumper/Cloner/Data.php +++ b/src/Symfony/Component/VarDumper/Cloner/Data.php @@ -256,7 +256,7 @@ private function dumpChildren($dumper, $parentCursor, &$refs, $children, $hashCu $cursor->hashCut = $hashCut; foreach ($children as $key => $child) { $cursor->hashKeyIsBinary = isset($key[0]) && !preg_match('//u', $key); - $cursor->hashKey = $dumpKeys ? $key : null; + $cursor->hashKey = $dumpKeys ? $key : null; $this->dumpItem($dumper, $cursor, $refs, $child); if (++$cursor->hashIndex === $this->maxItemsPerDepth || $cursor->stop) { $parentCursor->stop = true; diff --git a/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php b/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php index 13629e9ff822b..dd479670ce933 100644 --- a/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php @@ -289,7 +289,7 @@ public function testThrowingCaster() %sTemplate.php:%d: { : try { : \$this->display(\$context); - : } catch (Exception \$e) { + : } catch (%s \$e) { } %sCliDumperTest.php:{$line}: { : } diff --git a/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php b/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php index 30d2551fa1b0f..e75ebaf82e233 100644 --- a/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php +++ b/src/Symfony/Component/Workflow/Tests/Validator/WorkflowValidatorTest.php @@ -2,7 +2,9 @@ namespace Symfony\Component\Workflow\Tests\Validator; +use Symfony\Component\Workflow\Definition; use Symfony\Component\Workflow\Tests\WorkflowBuilderTrait; +use Symfony\Component\Workflow\Transition; use Symfony\Component\Workflow\Validator\WorkflowValidator; class WorkflowValidatorTest extends \PHPUnit_Framework_TestCase @@ -26,4 +28,36 @@ public function testSinglePlaceWorkflowValidatorAndSimpleWorkflow() (new WorkflowValidator(true))->validate($definition, 'foo'); } + + /** + * @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException + * @expectedExceptionMessage All transitions for a place must have an unique name. Multiple transitions named "t1" where found for place "a" in workflow "foo". + */ + public function testWorkflowWithInvalidNames() + { + $places = range('a', 'c'); + + $transitions = array(); + $transitions[] = new Transition('t0', 'c', 'b'); + $transitions[] = new Transition('t1', 'a', 'b'); + $transitions[] = new Transition('t1', 'a', 'c'); + + $definition = new Definition($places, $transitions); + + (new WorkflowValidator())->validate($definition, 'foo'); + } + + public function testSameTransitionNameButNotSamePlace() + { + $places = range('a', 'd'); + + $transitions = array(); + $transitions[] = new Transition('t1', 'a', 'b'); + $transitions[] = new Transition('t1', 'b', 'c'); + $transitions[] = new Transition('t1', 'd', 'c'); + + $definition = new Definition($places, $transitions); + + (new WorkflowValidator())->validate($definition, 'foo'); + } } diff --git a/src/Symfony/Component/Workflow/Tests/WorkflowBuilderTrait.php b/src/Symfony/Component/Workflow/Tests/WorkflowBuilderTrait.php index 5e8db29061295..3084be5749b7f 100644 --- a/src/Symfony/Component/Workflow/Tests/WorkflowBuilderTrait.php +++ b/src/Symfony/Component/Workflow/Tests/WorkflowBuilderTrait.php @@ -49,6 +49,34 @@ private function createSimpleWorkflowDefinition() // +---+ +----+ +---+ +----+ +---+ } + private function createWorkflowWithSameNameTransition() + { + $places = range('a', 'c'); + + $transitions = array(); + $transitions[] = new Transition('a_to_bc', 'a', array('b', 'c')); + $transitions[] = new Transition('b_to_c', 'b', 'c'); + $transitions[] = new Transition('to_a', 'b', 'a'); + $transitions[] = new Transition('to_a', 'c', 'a'); + + return new Definition($places, $transitions); + + // The graph looks like: + // +------------------------------------------------------------+ + // | | + // | | + // | +----------------------------------------+ | + // v | v | + // +---+ +---------+ +---+ +--------+ +---+ +------+ + // | a | --> | a_to_bc | --> | b | --> | b_to_c | --> | c | --> | to_a | -+ + // +---+ +---------+ +---+ +--------+ +---+ +------+ | + // ^ | ^ | + // | +----------------------------------+ | + // | | + // | | + // +--------------------------------------------------------------------+ + } + private function createComplexStateMachineDefinition() { $places = array('a', 'b', 'c', 'd'); diff --git a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php index cb5256f412933..1766e66fe3fb1 100644 --- a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php +++ b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php @@ -48,7 +48,7 @@ public function testGetMarkingWithEmptyDefinition() public function testGetMarkingWithImpossiblePlace() { $subject = new \stdClass(); - $subject->marking = array('nope' => true); + $subject->marking = array('nope' => 1); $workflow = new Workflow(new Definition(array(), array()), new MultipleStateMarkingStore()); $workflow->getMarking($subject); @@ -83,10 +83,6 @@ public function testGetMarkingWithExistingMarking() $this->assertTrue($marking->has('c')); } - /** - * @expectedException \Symfony\Component\Workflow\Exception\LogicException - * @expectedExceptionMessage Transition "foobar" does not exist for workflow "unnamed". - */ public function testCanWithUnexistingTransition() { $definition = $this->createComplexWorkflowDefinition(); @@ -94,7 +90,7 @@ public function testCanWithUnexistingTransition() $subject->marking = null; $workflow = new Workflow($definition, new MultipleStateMarkingStore()); - $workflow->can($subject, 'foobar'); + $this->assertFalse($workflow->can($subject, 'foobar')); } public function testCan() @@ -136,6 +132,23 @@ public function testApplyWithImpossibleTransition() $workflow->apply($subject, 't2'); } + public function testCanWithSameNameTransition() + { + $definition = $this->createWorkflowWithSameNameTransition(); + $workflow = new Workflow($definition, new MultipleStateMarkingStore()); + + $subject = new \stdClass(); + $subject->marking = null; + $this->assertTrue($workflow->can($subject, 'a_to_bc')); + $this->assertFalse($workflow->can($subject, 'b_to_c')); + $this->assertFalse($workflow->can($subject, 'to_a')); + + $subject->marking = array('b' => 1); + $this->assertFalse($workflow->can($subject, 'a_to_bc')); + $this->assertTrue($workflow->can($subject, 'b_to_c')); + $this->assertTrue($workflow->can($subject, 'to_a')); + } + public function testApply() { $definition = $this->createComplexWorkflowDefinition(); @@ -151,6 +164,59 @@ public function testApply() $this->assertTrue($marking->has('c')); } + public function testApplyWithSameNameTransition() + { + $subject = new \stdClass(); + $subject->marking = null; + $definition = $this->createWorkflowWithSameNameTransition(); + $workflow = new Workflow($definition, new MultipleStateMarkingStore()); + + $marking = $workflow->apply($subject, 'a_to_bc'); + + $this->assertFalse($marking->has('a')); + $this->assertTrue($marking->has('b')); + $this->assertTrue($marking->has('c')); + + $marking = $workflow->apply($subject, 'to_a'); + + $this->assertTrue($marking->has('a')); + $this->assertFalse($marking->has('b')); + $this->assertFalse($marking->has('c')); + + $marking = $workflow->apply($subject, 'a_to_bc'); + $marking = $workflow->apply($subject, 'b_to_c'); + + $this->assertFalse($marking->has('a')); + $this->assertFalse($marking->has('b')); + $this->assertTrue($marking->has('c')); + + $marking = $workflow->apply($subject, 'to_a'); + + $this->assertTrue($marking->has('a')); + $this->assertFalse($marking->has('b')); + $this->assertFalse($marking->has('c')); + } + + public function testApplyWithSameNameTransition2() + { + $subject = new \stdClass(); + $subject->marking = array('a' => 1, 'b' => 1); + + $places = range('a', 'd'); + $transitions = array(); + $transitions[] = new Transition('t', 'a', 'c'); + $transitions[] = new Transition('t', 'b', 'd'); + $definition = new Definition($places, $transitions); + $workflow = new Workflow($definition, new MultipleStateMarkingStore()); + + $marking = $workflow->apply($subject, 't'); + + $this->assertFalse($marking->has('a')); + $this->assertFalse($marking->has('b')); + $this->assertTrue($marking->has('c')); + $this->assertTrue($marking->has('d')); + } + public function testApplyWithEventDispatcher() { $definition = $this->createComplexWorkflowDefinition(); @@ -198,17 +264,36 @@ public function testGetEnabledTransitions() $this->assertEmpty($workflow->getEnabledTransitions($subject)); - $subject->marking = array('d' => true); + $subject->marking = array('d' => 1); $transitions = $workflow->getEnabledTransitions($subject); $this->assertCount(2, $transitions); $this->assertSame('t3', $transitions[0]->getName()); $this->assertSame('t4', $transitions[1]->getName()); - $subject->marking = array('c' => true, 'e' => true); + $subject->marking = array('c' => 1, 'e' => 1); $transitions = $workflow->getEnabledTransitions($subject); $this->assertCount(1, $transitions); $this->assertSame('t5', $transitions[0]->getName()); } + + public function testGetEnabledTransitionsWithSameNameTransition() + { + $definition = $this->createWorkflowWithSameNameTransition(); + $subject = new \stdClass(); + $subject->marking = null; + $workflow = new Workflow($definition, new MultipleStateMarkingStore()); + + $transitions = $workflow->getEnabledTransitions($subject); + $this->assertCount(1, $transitions); + $this->assertSame('a_to_bc', $transitions[0]->getName()); + + $subject->marking = array('b' => 1, 'c' => 1); + $transitions = $workflow->getEnabledTransitions($subject); + $this->assertCount(3, $transitions); + $this->assertSame('b_to_c', $transitions[0]->getName()); + $this->assertSame('to_a', $transitions[1]->getName()); + $this->assertSame('to_a', $transitions[2]->getName()); + } } class EventDispatcherMock implements \Symfony\Component\EventDispatcher\EventDispatcherInterface @@ -223,21 +308,27 @@ public function dispatch($eventName, \Symfony\Component\EventDispatcher\Event $e public function addListener($eventName, $listener, $priority = 0) { } + public function addSubscriber(\Symfony\Component\EventDispatcher\EventSubscriberInterface $subscriber) { } + public function removeListener($eventName, $listener) { } + public function removeSubscriber(\Symfony\Component\EventDispatcher\EventSubscriberInterface $subscriber) { } + public function getListeners($eventName = null) { } + public function getListenerPriority($eventName, $listener) { } + public function hasListeners($eventName = null) { } diff --git a/src/Symfony/Component/Workflow/Validator/WorkflowValidator.php b/src/Symfony/Component/Workflow/Validator/WorkflowValidator.php index cd31e1fb3e58b..27bd06f0d651b 100644 --- a/src/Symfony/Component/Workflow/Validator/WorkflowValidator.php +++ b/src/Symfony/Component/Workflow/Validator/WorkflowValidator.php @@ -31,6 +31,17 @@ public function __construct($singlePlace = false) public function validate(Definition $definition, $name) { + // Make sure all transitions for one place has unique name. + $places = array_fill_keys($definition->getPlaces(), array()); + foreach ($definition->getTransitions() as $transition) { + foreach ($transition->getFroms() as $from) { + if (in_array($transition->getName(), $places[$from])) { + throw new InvalidDefinitionException(sprintf('All transitions for a place must have an unique name. Multiple transitions named "%s" where found for place "%s" in workflow "%s".', $transition->getName(), $from, $name)); + } + $places[$from][] = $transition->getName(); + } + } + if (!$this->singlePlace) { return; } diff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.php index b66cc85f51d90..8fc64e979d3b8 100644 --- a/src/Symfony/Component/Workflow/Workflow.php +++ b/src/Symfony/Component/Workflow/Workflow.php @@ -89,15 +89,18 @@ public function getMarking($subject) * @param string $transitionName A transition * * @return bool true if the transition is enabled - * - * @throws LogicException If the transition does not exist */ public function can($subject, $transitionName) { - $transitions = $this->getTransitions($transitionName); - $marking = $this->getMarking($subject); + $transitions = $this->getEnabledTransitions($subject, $this->getMarking($subject)); + + foreach ($transitions as $transition) { + if ($transitionName === $transition->getName()) { + return true; + } + } - return null !== $this->getTransitionForSubject($subject, $marking, $transitions); + return false; } /** @@ -113,22 +116,36 @@ public function can($subject, $transitionName) */ public function apply($subject, $transitionName) { - $transitions = $this->getTransitions($transitionName); - $marking = $this->getMarking($subject); + $transitions = $this->getEnabledTransitions($subject, $this->getMarking($subject)); - if (null === $transition = $this->getTransitionForSubject($subject, $marking, $transitions)) { - throw new LogicException(sprintf('Unable to apply transition "%s" for workflow "%s".', $transitionName, $this->name)); - } + // We can shortcut the getMarking method in order to boost performance, + // since the "getEnabledTransitions" method already checks the Marking + // state + $marking = $this->markingStore->getMarking($subject); - $this->leave($subject, $transition, $marking); + $applied = false; - $this->transition($subject, $transition, $marking); + foreach ($transitions as $transition) { + if ($transitionName !== $transition->getName()) { + continue; + } - $this->enter($subject, $transition, $marking); + $applied = true; - $this->markingStore->setMarking($subject, $marking); + $this->leave($subject, $transition, $marking); - $this->announce($subject, $transition, $marking); + $this->transition($subject, $transition, $marking); + + $this->enter($subject, $transition, $marking); + + $this->markingStore->setMarking($subject, $marking); + + $this->announce($subject, $transition, $marking); + } + + if (!$applied) { + throw new LogicException(sprintf('Unable to apply transition "%s" for workflow "%s".', $transitionName, $this->name)); + } return $marking; } @@ -146,7 +163,7 @@ public function getEnabledTransitions($subject) $marking = $this->getMarking($subject); foreach ($this->definition->getTransitions() as $transition) { - if (null !== $this->getTransitionForSubject($subject, $marking, array($transition))) { + if ($this->doCan($subject, $marking, $transition)) { $enabled[] = $transition; } } @@ -167,6 +184,21 @@ public function getDefinition() return $this->definition; } + private function doCan($subject, Marking $marking, Transition $transition) + { + foreach ($transition->getFroms() as $place) { + if (!$marking->has($place)) { + return false; + } + } + + if (true === $this->guardTransition($subject, $marking, $transition)) { + return false; + } + + return true; + } + /** * @param object $subject * @param Marking $marking @@ -246,56 +278,8 @@ private function announce($subject, Transition $initialTransition, Marking $mark $event = new Event($subject, $marking, $initialTransition); - foreach ($this->definition->getTransitions() as $transition) { - if (null !== $this->getTransitionForSubject($subject, $marking, array($transition))) { - $this->dispatcher->dispatch(sprintf('workflow.%s.announce.%s', $this->name, $transition->getName()), $event); - } - } - } - - /** - * @param $transitionName - * - * @return Transition[] - */ - private function getTransitions($transitionName) - { - $transitions = $this->definition->getTransitions(); - - $transitions = array_filter($transitions, function (Transition $transition) use ($transitionName) { - return $transitionName === $transition->getName(); - }); - - if (!$transitions) { - throw new LogicException(sprintf('Transition "%s" does not exist for workflow "%s".', $transitionName, $this->name)); - } - - return $transitions; - } - - /** - * Return the first Transition in $transitions that is valid for the - * $subject and $marking. null is returned when you cannot do any Transition - * in $transitions on the $subject. - * - * @param object $subject - * @param Marking $marking - * @param Transition[] $transitions - * - * @return Transition|null - */ - private function getTransitionForSubject($subject, Marking $marking, array $transitions) - { - foreach ($transitions as $transition) { - foreach ($transition->getFroms() as $place) { - if (!$marking->has($place)) { - continue 2; - } - } - - if (true !== $this->guardTransition($subject, $marking, $transition)) { - return $transition; - } + foreach ($this->getEnabledTransitions($subject) as $transition) { + $this->dispatcher->dispatch(sprintf('workflow.%s.announce.%s', $this->name, $transition->getName()), $event); } } } diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index ac77d43eb8b78..8f846b2ba43af 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -23,7 +23,7 @@ */ class Inline { - const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*(?:\\\\.[^"\\\\]*)*)"|\'([^\']*(?:\'\'[^\']*)*)\')'; + const REGEX_QUOTED_STRING = '(?:"([^"\\\\]*+(?:\\\\.[^"\\\\]*+)*+)"|\'([^\']*+(?:\'\'[^\']*+)*+)\')'; public static $parsedLineNumber; diff --git a/src/Symfony/Component/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php index 355deb454af06..137ef5706836b 100644 --- a/src/Symfony/Component/Yaml/Tests/InlineTest.php +++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php @@ -676,4 +676,14 @@ public function testNotSupportedMissingValue() { Inline::parse('{this, is not, supported}'); } + + public function testVeryLongQuotedStrings() + { + $longStringWithQuotes = str_repeat("x\r\n\\\"x\"x", 1000); + + $yamlString = Inline::dump(array('longStringWithQuotes' => $longStringWithQuotes)); + $arrayFromYaml = Inline::parse($yamlString); + + $this->assertEquals($longStringWithQuotes, $arrayFromYaml['longStringWithQuotes']); + } }