From 6856faf6e55c208905aa2acfdcefea1fedcc51a1 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 25 Oct 2016 14:37:33 +0200 Subject: [PATCH 001/113] [SecurityBundle] Fix twig-bridge lowest dep --- src/Symfony/Bundle/SecurityBundle/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 5c80d97691403..ee1faf659a260 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -31,7 +31,7 @@ "symfony/framework-bundle": "~2.7", "symfony/http-foundation": "~2.3", "symfony/twig-bundle": "~2.7", - "symfony/twig-bridge": "~2.7", + "symfony/twig-bridge": "~2.7,>=2.7.4", "symfony/process": "~2.0,>=2.0.5", "symfony/validator": "~2.5", "symfony/yaml": "~2.0,>=2.0.5", From 9b49723426f5cdd143cac27bcb5c8e4d2147ef80 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Wed, 26 Oct 2016 12:44:26 -0400 Subject: [PATCH 002/113] remove dead code --- .../Bridge/Doctrine/Form/Type/DoctrineType.php | 17 +---------------- 1 file changed, 1 insertion(+), 16 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php index 5919ca95734a0..b28b9d51ad67b 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php @@ -20,14 +20,10 @@ use Symfony\Bridge\Doctrine\Form\EventListener\MergeDoctrineCollectionListener; use Symfony\Component\Form\AbstractType; 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\Form\Exception\RuntimeException; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\PropertyAccess\PropertyAccessorInterface; abstract class DoctrineType extends AbstractType { @@ -36,11 +32,6 @@ abstract class DoctrineType extends AbstractType */ protected $registry; - /** - * @var ChoiceListFactoryInterface - */ - private $choiceListFactory; - /** * @var IdReader[] */ @@ -108,15 +99,9 @@ public function getQueryBuilderPartsForCachingHash($queryBuilder) return false; } - public function __construct(ManagerRegistry $registry, PropertyAccessorInterface $propertyAccessor = null, ChoiceListFactoryInterface $choiceListFactory = null) + public function __construct(ManagerRegistry $registry) { $this->registry = $registry; - $this->choiceListFactory = $choiceListFactory ?: new CachingFactoryDecorator( - new PropertyAccessDecorator( - new DefaultChoiceListFactory(), - $propertyAccessor - ) - ); } public function buildForm(FormBuilderInterface $builder, array $options) From 3dadbe6e2facb7f35ea95641460f68a7c5ae1dca Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 26 Oct 2016 18:36:58 -0700 Subject: [PATCH 003/113] updated CHANGELOG for 2.7.20 --- CHANGELOG-2.7.md | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/CHANGELOG-2.7.md b/CHANGELOG-2.7.md index e05a5f9bf7142..c6f63e1b6c2b5 100644 --- a/CHANGELOG-2.7.md +++ b/CHANGELOG-2.7.md @@ -7,6 +7,28 @@ in 2.7 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/v2.7.0...v2.7.1 +* 2.7.20 (2016-10-27) + + * bug #20289 Fix edge case with StreamedResponse where headers are sent twice (Nicofuma) + * bug #20278 [DependencyInjection] merge tags instead of completely replacing them (xabbuh) + * bug #20271 Changes related to Twig 1.27 (fabpot) + * bug #20252 Trim constant values in XmlFileLoader (lstrojny) + * bug #20253 [TwigBridge] Use non-deprecated Twig_Node::getTemplateLine() (fabpot) + * bug #20235 [DomCrawler] Allow pipe (|) character in link tags when using Xpath expressions (klausi, nicolas-grekas) + * bug #20224 [Twig] removed deprecations added in Twig 1.27 (fabpot) + * bug #19478 fixed Filesystem:makePathRelative and added 2 more testcases (muhammedeminakbulut) + * bug #20218 [HttpFoundation] no 304 response if method is not cacheable (xabbuh) + * bug #20207 [DependencyInjection] move tags from decorated to decorating service (xabbuh) + * bug #20205 [HttpCache] fix: do not cache OPTIONS request (dmaicher) + * bug #20146 [Validator] Prevent infinite loop in PropertyMetadata (wesleylancel) + * bug #20184 [FrameworkBundle] Convert null prefix to an empty string in translation:update (chalasr) + * bug #19725 [Security] $attributes can be anything, but RoleVoter assumes strings (Jonatan Männchen) + * bug #20127 [HttpFoundation] JSONP callback validation (ro0NL) + * bug #20163 add missing use statement (xabbuh) + * bug #19961 [Console] Escape question text and default value in SymfonyStyle::ask() (chalasr) + * bug #20141 [Console] Fix validation of empty values using SymfonyQuestionHelper::ask() (chalasr) + * bug #20147 [FrameworkBundle] Alter container class instead of kernel name in cache:clear command (nicolas-grekas) + * 2.7.19 (2016-10-03) * bug #20102 [Validator] Url validator not validating hosts ending in a number (gwkunze) From 7891a33175a2d5525b0fc91a09d77e8fd9a9cc9c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 26 Oct 2016 18:37:04 -0700 Subject: [PATCH 004/113] update CONTRIBUTORS for 2.7.20 --- CONTRIBUTORS.md | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index b0646cc1303cd..41c883159c8e2 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -33,8 +33,8 @@ Symfony is the result of the work of many people who made the code better - Igor Wiedler (igorw) - Grégoire Pineau (lyrixx) - Eriksen Costa (eriksencosta) - - Sarah Khalil (saro0h) - Jules Pietri (heah) + - Sarah Khalil (saro0h) - Maxime Steinhausser (ogizanagi) - Jonathan Wage (jwage) - Diego Saint Esteben (dosten) @@ -49,13 +49,13 @@ Symfony is the result of the work of many people who made the code better - Henrik Bjørnskov (henrikbjorn) - Miha Vrhovnik - Diego Saint Esteben (dii3g0) + - Robin Chalas (chalas_r) - Ener-Getick (energetick) - Konstantin Kudryashov (everzet) - Bilal Amarni (bamarni) - Florin Patan (florinpatan) - Peter Rehm (rpet) - Iltar van der Berg (kjarli) - - Robin Chalas (chalas_r) - Kevin Bond (kbond) - Andrej Hudec (pulzarraider) - Gábor Egyed (1ed) @@ -69,6 +69,7 @@ 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) + - Konstantin Myakshin (koc) - Lee McDermott - Brandon Turner - Luis Cordova (cordoval) @@ -76,7 +77,6 @@ Symfony is the result of the work of many people who made the code better - Titouan Galopin (tgalopin) - Daniel Holmes (dholmes) - Pierre du Plessis (pierredup) - - Konstantin Myakshin (koc) - Bart van den Burg (burgov) - Jordan Alliot (jalliot) - John Wards (johnwards) @@ -84,17 +84,19 @@ Symfony is the result of the work of many people who made the code better - Fran Moreno (franmomu) - Antoine Hérault (herzult) - Paráda József (paradajozsef) + - Jáchym Toušek (enumag) - Arnaud Le Blanc (arnaud-lb) - Jérôme Tamarelle (gromnan) - Michal Piotrowski (eventhorizon) - Tim Nagel (merk) + - Dariusz Ruminski - Brice BERNARD (brikou) - Alexander M. Turek (derrabus) - - Dariusz Ruminski - marc.weistroff - Issei Murasawa (issei_m) - lenar - Włodzimierz Gajda (gajdaw) + - Roland Franssen (ro0) - Baptiste Clavié (talus) - Alexander Schwenn (xelaris) - Florian Voutzinos (florianv) @@ -104,8 +106,6 @@ Symfony is the result of the work of many people who made the code better - Peter Kokot (maastermedia) - excelwebzone - Jacob Dreesen (jdreesen) - - Jáchym Toušek (enumag) - - Roland Franssen (ro0) - Jérémy DERUSSÉ (jderusse) - Vladimir Reznichenko (kalessil) - Tomáš Votruba (tomas_votruba) @@ -131,6 +131,7 @@ Symfony is the result of the work of many people who made the code better - Andréia Bohner (andreia) - Rafael Dohms (rdohms) - Arnaud Kleinpeter (nanocom) + - jwdeitch - Joel Wurtz (brouznouf) - Philipp Wahala (hifi) - Vyacheslav Pavlov @@ -139,6 +140,7 @@ Symfony is the result of the work of many people who made the code better - Thomas Rabaix (rande) - Vincent AUBERT (vincent) - Rouven Weßling (realityking) + - Teoh Han Hui (teohhanhui) - Mikael Pajunen - Clemens Tolboom - Helmer Aaviksoo @@ -149,7 +151,6 @@ Symfony is the result of the work of many people who made the code better - Amal Raghav (kertz) - Jonathan Ingram (jonathaningram) - Artur Kotyrba - - Teoh Han Hui (teohhanhui) - Warnar Boekkooi (boekkooi) - Dmitrii Chekaliuk (lazyhammer) - Clément JOBEILI (dator) @@ -159,10 +160,12 @@ Symfony is the result of the work of many people who made the code better - Richard Miller (mr_r_miller) - Mario A. Alvarez Garcia (nomack84) - Dennis Benkert (denderello) + - jeremyFreeAgent (Jérémy Romey) (jeremyfreeagent) - Benjamin Dulau (dbenjamin) - Mathieu Lemoine (lemoinem) - Andreas Hucks (meandmymonkey) - Noel Guilbert (noel) + - Lars Strojny (lstrojny) - Yonel Ceruto González (yonelceruto) - Stepan Anchugov (kix) - bronze1man @@ -185,13 +188,11 @@ Symfony is the result of the work of many people who made the code better - Michele Orselli (orso) - Tom Van Looy (tvlooy) - Sven Paulus (subsven) - - Lars Strojny (lstrojny) - Rui Marinho (ruimarinho) - Daniel Espendiller - Dawid Nowak - Eugene Wissner - Julien Brochet (mewt) - - jeremyFreeAgent (jeremyfreeagent) - Sergey Linnik (linniksa) - Michaël Perrin (michael.perrin) - Marcel Beerta (mazen) @@ -226,6 +227,7 @@ Symfony is the result of the work of many people who made the code better - Jakub Kucharovic (jkucharovic) - Eugene Leonovich (rybakit) - Filippo Tessarotto + - Tristan Darricau (nicofuma) - Joseph Rouff (rouffj) - Félix Labrecque (woodspire) - GordonsLondon @@ -262,7 +264,6 @@ Symfony is the result of the work of many people who made the code better - Oleg Voronkovich - Manuel Kiessling (manuelkiessling) - Daniel Wehner - - Tristan Darricau (nicofuma) - Atsuhiro KUBO (iteman) - Andrew Moore (finewolf) - Bertrand Zuchuat (garfield-fr) @@ -387,6 +388,7 @@ Symfony is the result of the work of many people who made the code better - Ariel Ferrandini (aferrandini) - Dirk Pahl (dirkaholic) - cedric lombardot (cedriclombardot) + - David Maicher (dmaicher) - Jonas Flodén (flojon) - Christian Schmidt - Marcin Sikoń (marphi) @@ -535,6 +537,7 @@ Symfony is the result of the work of many people who made the code better - Daisuke Ohata - Vincent Simonin - Alex Bogomazov (alebo) + - maxime.steinhausser - Stefan Warman - Tristan Maindron (tmaindron) - Ke WANG (yktd26) @@ -546,11 +549,11 @@ Symfony is the result of the work of many people who made the code better - Ulumuddin Yunus (joenoez) - Luc Vieillescazes (iamluc) - Johann Saunier (prophet777) + - Michael Devery (mickadoo) - Antoine Corcy - Artur Eshenbrener - Arturs Vonda - Sascha Grossenbacher - - David Maicher (dmaicher) - Szijarto Tamas - Catalin Dan - Stephan Vock @@ -593,6 +596,7 @@ Symfony is the result of the work of many people who made the code better - Vladyslav Petrovych - Alex Xandra Albert Sim - Carson Full + - Andrey Astakhov (aast) - Trent Steel (trsteel88) - Yuen-Chi Lian - Besnik Br @@ -602,12 +606,14 @@ Symfony is the result of the work of many people who made the code better - avorobiev - Venu - Lars Vierbergen + - Jonatan Männchen - Dennis Hotson - Andrew Tchircoff (andrewtch) - michaelwilliams - 1emming - Victor Bocharsky (bocharsky_bw) - Leevi Graham (leevigraham) + - Jordan Deitch - Casper Valdemar Poulsen - Josiah (josiah) - Joschi Kuphal @@ -740,6 +746,7 @@ Symfony is the result of the work of many people who made the code better - Alexandru Furculita (afurculita) - Ben Ramsey (ramsey) - Christian Jul Jensen + - Alexandre GESLIN (alexandregeslin) - The Whole Life to Learn - Farhad Safarov - Liverbool (liverbool) @@ -870,12 +877,14 @@ Symfony is the result of the work of many people who made the code better - James Gilliland - Rhodri Pugh (rodnaph) - David de Boer (ddeboer) + - Klaus Purer - Gilles Doge (gido) - abulford - antograssiot - Brooks Boyd - Roger Webb - Dmitriy Simushev + - Ivo Bathke (ivoba) - Max Voloshin (maxvoloshin) - Nicolas Fabre (nfabre) - Raul Rodriguez (raul782) @@ -964,7 +973,6 @@ Symfony is the result of the work of many people who made the code better - ChrisC - Ilya Biryukov - Kim Laï Trinh - - Jonatan Männchen - Jason Desrosiers - m.chwedziak - Philip Frank @@ -994,7 +1002,6 @@ Symfony is the result of the work of many people who made the code better - Emmanuel Vella (emmanuel.vella) - Carsten Nielsen (phreaknerd) - Mathieu Rochette - - maxime.steinhausser - Jay Severson - René Kerner - Nathaniel Catchpole @@ -1044,7 +1051,6 @@ Symfony is the result of the work of many people who made the code better - Benjamin Bender - Konrad Mohrfeldt - Lance Chen - - Andrey Astakhov (aast) - Andrew (drew) - Nikolay Labinskiy (e-moe) - kor3k kor3k (kor3k) @@ -1055,6 +1061,7 @@ Symfony is the result of the work of many people who made the code better - Mephistofeles - Hoffmann András - Olivier + - Wesley Lancel - pscheit - Zdeněk Drahoš - Dan Harper @@ -1160,6 +1167,7 @@ Symfony is the result of the work of many people who made the code better - JakeFr - Simon Sargeant - efeen + - Muhammed Akbulut - Michał Dąbrowski (defrag) - Simone Fumagalli (hpatoio) - Brian Graham (incognito) @@ -1176,6 +1184,7 @@ Symfony is the result of the work of many people who made the code better - Artem Lopata (bumz) - Nicole Cordes - Alexey Popkov + - Gijs Kunze - Artyom Protaskin - Nathanael d. Noblet - helmer @@ -1445,6 +1454,7 @@ Symfony is the result of the work of many people who made the code better - Matthias Althaus - Michaël VEROUX - Julia + - Lin Lu - arduanov - sualko - Nicolas Roudaire From 8beacd2dd885742983c7fefbe69b7f4658d8187d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 26 Oct 2016 18:37:19 -0700 Subject: [PATCH 005/113] updated VERSION for 2.7.20 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index a4d715cad3665..836d786e7e6bc 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,12 +58,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.7.20-DEV'; + const VERSION = '2.7.20'; const VERSION_ID = 20720; const MAJOR_VERSION = 2; const MINOR_VERSION = 7; const RELEASE_VERSION = 20; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '05/2018'; const END_OF_LIFE = '05/2019'; From ed11f2236065241b9416fe458e2aecd1a028af53 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 26 Oct 2016 19:12:15 -0700 Subject: [PATCH 006/113] bumped Symfony version to 2.7.21 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 836d786e7e6bc..5bd08cbd1537b 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,12 +58,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.7.20'; - const VERSION_ID = 20720; + const VERSION = '2.7.21-DEV'; + const VERSION_ID = 20721; const MAJOR_VERSION = 2; const MINOR_VERSION = 7; - const RELEASE_VERSION = 20; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 21; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '05/2018'; const END_OF_LIFE = '05/2019'; From 5ea7fcc92bf070901fa15fe69c97ee12e3101d9c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 26 Oct 2016 19:18:10 -0700 Subject: [PATCH 007/113] updated CHANGELOG for 2.8.13 --- CHANGELOG-2.8.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/CHANGELOG-2.8.md b/CHANGELOG-2.8.md index edb544ab415a8..8f0a5d2bd6bf9 100644 --- a/CHANGELOG-2.8.md +++ b/CHANGELOG-2.8.md @@ -7,6 +7,32 @@ in 2.8 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/v2.8.0...v2.8.1 +* 2.8.13 (2016-10-27) + + * bug #20289 Fix edge case with StreamedResponse where headers are sent twice (Nicofuma) + * bug #20267 [DependencyInjection] A decorated service should not keep the autowiring types (chalasr) + * bug #20278 [DependencyInjection] merge tags instead of completely replacing them (xabbuh) + * bug #20271 Changes related to Twig 1.27 (fabpot) + * bug #20252 Trim constant values in XmlFileLoader (lstrojny) + * bug #20253 [TwigBridge] Use non-deprecated Twig_Node::getTemplateLine() (fabpot) + * bug #20243 [WebProfilerBundle][btn-link] add `cursor: pointer` (aitboudad) + * bug #20175 [VarDumper] Fix source links with latests Twig versions (nicolas-grekas) + * bug #20235 [DomCrawler] Allow pipe (|) character in link tags when using Xpath expressions (klausi, nicolas-grekas) + * bug #20224 [Twig] removed deprecations added in Twig 1.27 (fabpot) + * bug #19478 fixed Filesystem:makePathRelative and added 2 more testcases (muhammedeminakbulut) + * bug #20218 [HttpFoundation] no 304 response if method is not cacheable (xabbuh) + * bug #20207 [DependencyInjection] move tags from decorated to decorating service (xabbuh) + * bug #20205 [HttpCache] fix: do not cache OPTIONS request (dmaicher) + * bug #20146 [Validator] Prevent infinite loop in PropertyMetadata (wesleylancel) + * bug #20184 [FrameworkBundle] Convert null prefix to an empty string in translation:update (chalasr) + * bug #20154 [PropertyInfo] Fix edge cases in ReflectionExtractor (nicolas-grekas) + * bug #19725 [Security] $attributes can be anything, but RoleVoter assumes strings (Jonatan Männchen) + * bug #20127 [HttpFoundation] JSONP callback validation (ro0NL) + * bug #20163 add missing use statement (xabbuh) + * bug #19961 [Console] Escape question text and default value in SymfonyStyle::ask() (chalasr) + * bug #20141 [Console] Fix validation of empty values using SymfonyQuestionHelper::ask() (chalasr) + * bug #20147 [FrameworkBundle] Alter container class instead of kernel name in cache:clear command (nicolas-grekas) + * 2.8.12 (2016-10-03) * bug #20102 [Validator] Url validator not validating hosts ending in a number (gwkunze) From 10b7b5da3b5aaf995251acede7a57044cb149f53 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 26 Oct 2016 19:18:22 -0700 Subject: [PATCH 008/113] updated VERSION for 2.8.13 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index f286285766815..b7a9462a9a9eb 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,12 +59,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.8.13-DEV'; + const VERSION = '2.8.13'; const VERSION_ID = 20813; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; const RELEASE_VERSION = 13; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '11/2018'; const END_OF_LIFE = '11/2019'; From 5abd889480e208f32ccafcc76da6f440c275a2f2 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 26 Oct 2016 19:36:03 -0700 Subject: [PATCH 009/113] bumped Symfony version to 2.8.14 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index b7a9462a9a9eb..62c27c0322e16 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,12 +59,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.8.13'; - const VERSION_ID = 20813; + const VERSION = '2.8.14-DEV'; + const VERSION_ID = 20814; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; - const RELEASE_VERSION = 13; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 14; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '11/2018'; const END_OF_LIFE = '11/2019'; From 27ce7bf6575dda204f782f6cc7d9ce845a727a55 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 26 Oct 2016 19:38:08 -0700 Subject: [PATCH 010/113] updated CHANGELOG for 3.1.6 --- CHANGELOG-3.1.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/CHANGELOG-3.1.md b/CHANGELOG-3.1.md index 33ad4d31965d3..07d0350ddfada 100644 --- a/CHANGELOG-3.1.md +++ b/CHANGELOG-3.1.md @@ -7,6 +7,36 @@ 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.6 (2016-10-27) + + * bug #20291 [Yaml] Fix 7.1 compat (nicolas-grekas) + * bug #20289 Fix edge case with StreamedResponse where headers are sent twice (Nicofuma) + * bug #20267 [DependencyInjection] A decorated service should not keep the autowiring types (chalasr) + * bug #20278 [DependencyInjection] merge tags instead of completely replacing them (xabbuh) + * bug #20271 Changes related to Twig 1.27 (fabpot) + * bug #20252 Trim constant values in XmlFileLoader (lstrojny) + * bug #20239 [HttpKernel] Fix a regression in the RequestDataCollector (jakzal) + * bug #20253 [TwigBridge] Use non-deprecated Twig_Node::getTemplateLine() (fabpot) + * bug #20243 [WebProfilerBundle][btn-link] add `cursor: pointer` (aitboudad) + * bug #20175 [VarDumper] Fix source links with latests Twig versions (nicolas-grekas) + * bug #20235 [DomCrawler] Allow pipe (|) character in link tags when using Xpath expressions (klausi, nicolas-grekas) + * bug #20224 [Twig] removed deprecations added in Twig 1.27 (fabpot) + * bug #19478 fixed Filesystem:makePathRelative and added 2 more testcases (muhammedeminakbulut) + * bug #20218 [HttpFoundation] no 304 response if method is not cacheable (xabbuh) + * bug #20207 [DependencyInjection] move tags from decorated to decorating service (xabbuh) + * bug #20205 [HttpCache] fix: do not cache OPTIONS request (dmaicher) + * bug #20146 [Validator] Prevent infinite loop in PropertyMetadata (wesleylancel) + * bug #20184 [FrameworkBundle] Convert null prefix to an empty string in translation:update (chalasr) + * bug #20154 [PropertyInfo] Fix edge cases in ReflectionExtractor (nicolas-grekas) + * bug #19725 [Security] $attributes can be anything, but RoleVoter assumes strings (Jonatan Männchen) + * bug #20127 [HttpFoundation] JSONP callback validation (ro0NL) + * bug #20163 add missing use statement (xabbuh) + * bug #19961 [Console] Escape question text and default value in SymfonyStyle::ask() (chalasr) + * bug #20141 [Console] Fix validation of empty values using SymfonyQuestionHelper::ask() (chalasr) + * bug #20147 [FrameworkBundle] Alter container class instead of kernel name in cache:clear command (nicolas-grekas) + * bug #20156 Fix event annotation for arguments resolving event (Koc) + * bug #20152 [HttpKernel] Fix nullable types handling (nicolas-grekas) + * 3.1.5 (2016-10-03) * bug #20102 [Validator] Url validator not validating hosts ending in a number (gwkunze) From c1a76dad1a13c149de13339c62c4d4e54749f158 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 26 Oct 2016 19:38:31 -0700 Subject: [PATCH 011/113] updated VERSION for 3.1.6 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 965c8e1556140..e6f9f4ab3da40 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,12 +59,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '3.1.6-DEV'; + const VERSION = '3.1.6'; const VERSION_ID = 30106; const MAJOR_VERSION = 3; const MINOR_VERSION = 1; const RELEASE_VERSION = 6; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '01/2017'; const END_OF_LIFE = '07/2017'; From 0dc1a3dab156e14ae6aea0d1b72aadd27a3246d9 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 26 Oct 2016 19:53:37 -0700 Subject: [PATCH 012/113] bumped Symfony version to 3.1.7 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index e6f9f4ab3da40..e923c098b00af 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,12 +59,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '3.1.6'; - const VERSION_ID = 30106; + const VERSION = '3.1.7-DEV'; + const VERSION_ID = 30107; const MAJOR_VERSION = 3; const MINOR_VERSION = 1; - const RELEASE_VERSION = 6; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 7; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '01/2017'; const END_OF_LIFE = '07/2017'; From bda7e6b7e545b37e76d76bc030ef70eee41db827 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 26 Oct 2016 21:11:23 -0700 Subject: [PATCH 013/113] bumped Symfony version to 3.2.0 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 70210cd751ca7..f1013f23c61b2 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,12 +58,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '3.2.0-BETA1'; + const VERSION = '3.2.0-DEV'; const VERSION_ID = 30200; const MAJOR_VERSION = 3; const MINOR_VERSION = 2; const RELEASE_VERSION = 0; - const EXTRA_VERSION = 'BETA1'; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '07/2017'; const END_OF_LIFE = '01/2018'; From d090159fb27a7e4026df2ef10c27b48db6e6b713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Haso=C5=88?= Date: Thu, 27 Oct 2016 10:29:18 +0200 Subject: [PATCH 014/113] [DependencyInjection] Remove old code in XML loader --- .../Component/DependencyInjection/Loader/XmlFileLoader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 32b62820190b1..77420ba98d407 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -152,7 +152,7 @@ private function parseDefinition(\DOMElement $service, $file) foreach (array('class', 'shared', 'public', 'synthetic', 'lazy', 'abstract') as $key) { if ($value = $service->getAttribute($key)) { - $method = 'set'.str_replace('-', '', $key); + $method = 'set'.$key; $definition->$method(XmlUtils::phpize($value)); } } From f2f232d599d114c0a186aefe8dc011aa4bb8ead2 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 25 Oct 2016 10:15:38 +0200 Subject: [PATCH 015/113] Enhance GAE compat by removing some realpath() --- .../AbstractDoctrineExtension.php | 5 +---- .../CompilerPass/DoctrineValidationPass.php | 2 +- .../Bridge/Twig/Translation/TwigExtractor.php | 2 +- .../FrameworkExtension.php | 22 +++++++++---------- .../FrameworkExtensionTest.php | 4 ++-- .../ClassLoader/ClassCollectionLoader.php | 2 +- .../ClassLoader/ClassMapGenerator.php | 2 +- .../Config/Resource/FileResource.php | 2 +- .../Iterator/DateRangeFilterIterator.php | 2 +- .../Finder/Iterator/SortableIterator.php | 4 ++-- src/Symfony/Component/Intl/Intl.php | 2 +- 11 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php index e1cbbbfb1a36e..940ca6fdf9fbd 100644 --- a/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php +++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php @@ -134,10 +134,7 @@ protected function setMappingDriverConfig(array $mappingConfig, $mappingName) throw new \InvalidArgumentException(sprintf('Invalid Doctrine mapping path given. Cannot load Doctrine mapping/bundle named "%s".', $mappingName)); } - if (substr($mappingDirectory, 0, 7) !== 'phar://') { - $mappingDirectory = realpath($mappingDirectory); - } - $this->drivers[$mappingConfig['type']][$mappingConfig['prefix']] = $mappingDirectory; + $this->drivers[$mappingConfig['type']][$mappingConfig['prefix']] = realpath($mappingDirectory) ?: $mappingDirectory; } /** diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/DoctrineValidationPass.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/DoctrineValidationPass.php index 96f05eb5b60c9..f8382ed2ebfb8 100644 --- a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/DoctrineValidationPass.php +++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/DoctrineValidationPass.php @@ -61,7 +61,7 @@ private function updateValidatorMappingFiles(ContainerBuilder $container, $mappi foreach ($container->getParameter('kernel.bundles') as $bundle) { $reflection = new \ReflectionClass($bundle); if (is_file($file = dirname($reflection->getFileName()).'/'.$validationPath)) { - $files[] = realpath($file); + $files[] = $file; $container->addResource(new FileResource($file)); } } diff --git a/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php b/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php index 917687ad34eee..950c4d0810db0 100644 --- a/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php +++ b/src/Symfony/Bridge/Twig/Translation/TwigExtractor.php @@ -64,7 +64,7 @@ public function extract($resource, MessageCatalogue $catalogue) if ($file instanceof SplFileInfo) { $e->setTemplateName($file->getRelativePathname()); } elseif ($file instanceof \SplFileInfo) { - $e->setTemplateName($file->getRealPath()); + $e->setTemplateName($file->getRealPath() ?: $file->getPathname()); } throw $e; diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index c8e105cddcc41..278b8b9b7d672 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -52,7 +52,7 @@ class FrameworkExtension extends Extension */ public function load(array $configs, ContainerBuilder $container) { - $loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config')); + $loader = new XmlFileLoader($container, new FileLocator(dirname(__DIR__).'/Resources/config')); $loader->load('web.xml'); $loader->load('services.xml'); @@ -689,7 +689,7 @@ private function registerTranslatorConfiguration(array $config, ContainerBuilder if (class_exists('Symfony\Component\Security\Core\Exception\AuthenticationException')) { $r = new \ReflectionClass('Symfony\Component\Security\Core\Exception\AuthenticationException'); - $dirs[] = dirname($r->getFileName()).'/../Resources/translations'; + $dirs[] = dirname(dirname($r->getFileName())).'/Resources/translations'; } $rootDir = $container->getParameter('kernel.root_dir'); foreach ($container->getParameter('kernel.bundles') as $bundle => $class) { @@ -811,21 +811,21 @@ private function getValidatorMappingFiles(ContainerBuilder $container) $dirname = dirname($reflection->getFileName()); if (is_file($file = $dirname.'/Resources/config/validation.xml')) { - $files[0][] = realpath($file); + $files[0][] = $file; $container->addResource(new FileResource($file)); } if (is_file($file = $dirname.'/Resources/config/validation.yml')) { - $files[1][] = realpath($file); + $files[1][] = $file; $container->addResource(new FileResource($file)); } if (is_dir($dir = $dirname.'/Resources/config/validation')) { foreach (Finder::create()->files()->in($dir)->name('*.xml') as $file) { - $files[0][] = $file->getRealPath(); + $files[0][] = $file->getPathname(); } foreach (Finder::create()->files()->in($dir)->name('*.yml') as $file) { - $files[1][] = $file->getRealPath(); + $files[1][] = $file->getPathname(); } $container->addResource(new DirectoryResource($dir)); @@ -926,7 +926,7 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder $dirname = dirname($reflection->getFileName()); if (is_file($file = $dirname.'/Resources/config/serialization.xml')) { - $definition = new Definition('Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader', array(realpath($file))); + $definition = new Definition('Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader', array($file)); $definition->setPublic(false); $serializerLoaders[] = $definition; @@ -934,7 +934,7 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder } if (is_file($file = $dirname.'/Resources/config/serialization.yml')) { - $definition = new Definition('Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader', array(realpath($file))); + $definition = new Definition('Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader', array($file)); $definition->setPublic(false); $serializerLoaders[] = $definition; @@ -943,13 +943,13 @@ private function registerSerializerConfiguration(array $config, ContainerBuilder if (is_dir($dir = $dirname.'/Resources/config/serialization')) { foreach (Finder::create()->files()->in($dir)->name('*.xml') as $file) { - $definition = new Definition('Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader', array($file->getRealPath())); + $definition = new Definition('Symfony\Component\Serializer\Mapping\Loader\XmlFileLoader', array($file->getPathname())); $definition->setPublic(false); $serializerLoaders[] = $definition; } foreach (Finder::create()->files()->in($dir)->name('*.yml') as $file) { - $definition = new Definition('Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader', array($file->getRealPath())); + $definition = new Definition('Symfony\Component\Serializer\Mapping\Loader\YamlFileLoader', array($file->getPathname())); $definition->setPublic(false); $serializerLoaders[] = $definition; @@ -996,7 +996,7 @@ private function getKernelRootHash(ContainerBuilder $container) */ public function getXsdValidationBasePath() { - return __DIR__.'/../Resources/config/schema'; + return dirname(__DIR__).'/Resources/config/schema'; } public function getNamespace() diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 9d93263963f9b..922d6f95738f6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -363,11 +363,11 @@ public function testValidationPaths() // Testing symfony/framework-bundle with deps=high $this->assertStringEndsWith('symfony'.DIRECTORY_SEPARATOR.'form/Resources/config/validation.xml', $xmlMappings[0]); } - $this->assertStringEndsWith('TestBundle'.DIRECTORY_SEPARATOR.'Resources'.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'validation.xml', $xmlMappings[1]); + $this->assertStringEndsWith('TestBundle/Resources/config/validation.xml', $xmlMappings[1]); $yamlMappings = $calls[4][1][0]; $this->assertCount(1, $yamlMappings); - $this->assertStringEndsWith('TestBundle'.DIRECTORY_SEPARATOR.'Resources'.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'validation.yml', $yamlMappings[0]); + $this->assertStringEndsWith('TestBundle/Resources/config/validation.yml', $yamlMappings[0]); } public function testValidationNoStaticMethod() diff --git a/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php b/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php index 18e22a5bca603..9f2001839b1da 100644 --- a/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php +++ b/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php @@ -62,7 +62,7 @@ public static function load($classes, $cacheDir, $name, $autoReload, $adaptive = if (!is_dir($cacheDir) && !@mkdir($cacheDir, 0777, true) && !is_dir($cacheDir)) { throw new \RuntimeException(sprintf('Class Collection Loader was not able to create directory "%s"', $cacheDir)); } - $cacheDir = rtrim(realpath($cacheDir), '/'.DIRECTORY_SEPARATOR); + $cacheDir = rtrim(realpath($cacheDir) ?: $cacheDir, '/'.DIRECTORY_SEPARATOR); $cache = $cacheDir.DIRECTORY_SEPARATOR.$name.$extension; // auto-reload diff --git a/src/Symfony/Component/ClassLoader/ClassMapGenerator.php b/src/Symfony/Component/ClassLoader/ClassMapGenerator.php index 07c974f4283dd..2976eb81c09cf 100644 --- a/src/Symfony/Component/ClassLoader/ClassMapGenerator.php +++ b/src/Symfony/Component/ClassLoader/ClassMapGenerator.php @@ -64,7 +64,7 @@ public static function createMap($dir) continue; } - $path = $file->getRealPath(); + $path = $file->getRealPath() ?: $file->getPathname(); if (pathinfo($path, PATHINFO_EXTENSION) !== 'php') { continue; diff --git a/src/Symfony/Component/Config/Resource/FileResource.php b/src/Symfony/Component/Config/Resource/FileResource.php index 4c00ae4140abc..0723ddf0e1f20 100644 --- a/src/Symfony/Component/Config/Resource/FileResource.php +++ b/src/Symfony/Component/Config/Resource/FileResource.php @@ -32,7 +32,7 @@ class FileResource implements ResourceInterface, \Serializable */ public function __construct($resource) { - $this->resource = realpath($resource); + $this->resource = realpath($resource) ?: (file_exists($resource) ? $resource : false); } /** diff --git a/src/Symfony/Component/Finder/Iterator/DateRangeFilterIterator.php b/src/Symfony/Component/Finder/Iterator/DateRangeFilterIterator.php index 4d5ef9a4bc431..0f2d48f39ef99 100644 --- a/src/Symfony/Component/Finder/Iterator/DateRangeFilterIterator.php +++ b/src/Symfony/Component/Finder/Iterator/DateRangeFilterIterator.php @@ -44,7 +44,7 @@ public function accept() { $fileinfo = $this->current(); - if (!file_exists($fileinfo->getRealPath())) { + if (!file_exists($fileinfo->getPathname())) { return false; } diff --git a/src/Symfony/Component/Finder/Iterator/SortableIterator.php b/src/Symfony/Component/Finder/Iterator/SortableIterator.php index fa3458077acf1..f1134c00b9489 100644 --- a/src/Symfony/Component/Finder/Iterator/SortableIterator.php +++ b/src/Symfony/Component/Finder/Iterator/SortableIterator.php @@ -41,7 +41,7 @@ public function __construct(\Traversable $iterator, $sort) if (self::SORT_BY_NAME === $sort) { $this->sort = function ($a, $b) { - return strcmp($a->getRealpath(), $b->getRealpath()); + return strcmp($a->getRealpath() ?: $a->getPathname(), $b->getRealpath() ?: $b->getPathname()); }; } elseif (self::SORT_BY_TYPE === $sort) { $this->sort = function ($a, $b) { @@ -51,7 +51,7 @@ public function __construct(\Traversable $iterator, $sort) return 1; } - return strcmp($a->getRealpath(), $b->getRealpath()); + return strcmp($a->getRealpath() ?: $a->getPathname(), $b->getRealpath() ?: $b->getPathname()); }; } elseif (self::SORT_BY_ACCESSED_TIME === $sort) { $this->sort = function ($a, $b) { diff --git a/src/Symfony/Component/Intl/Intl.php b/src/Symfony/Component/Intl/Intl.php index 15816cbfa17c6..d49a6c9127608 100644 --- a/src/Symfony/Component/Intl/Intl.php +++ b/src/Symfony/Component/Intl/Intl.php @@ -244,7 +244,7 @@ public static function getIcuStubVersion() */ public static function getDataDirectory() { - return realpath(__DIR__.'/Resources/data'); + return __DIR__.'/Resources/data'; } /** From bc1ffeaecdbf06d77eed10a079fbd8abca38e025 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Thu, 27 Oct 2016 13:24:04 +0200 Subject: [PATCH 016/113] Remove reverted feature from changelog --- CHANGELOG-3.2.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG-3.2.md b/CHANGELOG-3.2.md index d6313f4f808dc..6335978da8a0d 100644 --- a/CHANGELOG-3.2.md +++ b/CHANGELOG-3.2.md @@ -149,7 +149,6 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c * feature #18869 [Routing] Throw exception when PHP start tag is missing (WouterJ) * feature #18781 [Console] Display errors in quiet mode (multi-io) * feature #19011 [HttpKernel] Add convenient method ArgumentResolver:: getDefaultArgumentValueResolvers (romainneutron) - * feature #18977 [PropertyAccess] Add missing arguments to PropertyAccess::createPropertyAccessor() (chalasr) * feature #18568 [WebProfilerBundle] Fix bundle usage in Content-Security-Policy context without unsafe-inline (romainneutron) * feature #16838 [PropertyAccess] Add PSR-6 cache (dunglas) * feature #18790 [Console] Show aliases in command description instead of in different lines in application description (juanmirod) From 06203b160afa76a658e44af48011002a6f4e11db Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 27 Oct 2016 13:30:59 +0200 Subject: [PATCH 017/113] [VarDumper] Fix source links to Twig files --- .../Component/VarDumper/Caster/ExceptionCaster.php | 10 ++++------ .../Component/VarDumper/Cloner/AbstractCloner.php | 2 +- .../Component/VarDumper/Tests/CliDumperTest.php | 14 +++++++------- 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php b/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php index bb5647a2acef8..e2b85eec1b90e 100644 --- a/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php @@ -157,17 +157,15 @@ public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, $is $template = isset($f['object']) ? $f['object'] : new $f['class'](new \Twig_Environment(new \Twig_Loader_Filesystem())); $ellipsis = 0; - $templateName = $template->getTemplateName(); $templateSrc = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (method_exists($template, 'getSource') ? $template->getSource() : ''); $templateInfo = $template->getDebugInfo(); if (isset($templateInfo[$f['line']])) { - if (method_exists($template, 'getSourceContext')) { - $templateName = $template->getSourceContext()->getPath() ?: $templateName; - } + $templatePath = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getPath() : null; + if ($templateSrc) { $templateSrc = explode("\n", $templateSrc); - $src = self::extractSource($templateSrc, $templateInfo[$f['line']], self::$srcContext, $caller, 'twig'); - $srcKey = $templateName.':'.$templateInfo[$f['line']]; + $src = self::extractSource($templateSrc, $templateInfo[$f['line']], self::$srcContext, $caller, 'twig', $templatePath); + $srcKey = ($templatePath ?: $template->getTemplateName()).':'.$templateInfo[$f['line']]; } } } diff --git a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php index 947b4167eeab9..d49d2b545e1d1 100644 --- a/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/AbstractCloner.php @@ -312,7 +312,7 @@ private function callCaster($callback, $obj, $a, $stub, $isNested) $a = $cast; } } catch (\Exception $e) { - $a[(Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠'] = new ThrowingCasterException($e); + $a = array((Stub::TYPE_OBJECT === $stub->type ? Caster::PREFIX_VIRTUAL : '').'⚠' => new ThrowingCasterException($e)) + $a; } return $a; diff --git a/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php b/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php index aaaf781441c17..25a1bec0f01db 100644 --- a/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php @@ -268,13 +268,6 @@ public function testThrowingCaster() $this->assertStringMatchesFormat( << Date: Thu, 27 Oct 2016 13:18:01 +0200 Subject: [PATCH 018/113] [VarDumper] Fix dumping Twig source in stack traces --- .../HttpKernel/DataCollector/DumpDataCollector.php | 4 ++-- .../Component/VarDumper/Caster/ExceptionCaster.php | 3 ++- .../VarDumper/Tests/Caster/ExceptionCasterTest.php | 14 +++++--------- .../Component/VarDumper/Tests/CliDumperTest.php | 2 +- .../Component/VarDumper/Tests/Fixtures/Twig.php | 10 ++++++---- 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php index 538d73c783ba3..3f5e6acf63444 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php @@ -103,7 +103,7 @@ public function dump(Data $data) $info = $template->getDebugInfo(); if (isset($info[$trace[$i - 1]['line']])) { $line = $info[$trace[$i - 1]['line']]; - $file = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getPath() : false; + $file = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getPath() : null; if ($src) { $src = explode("\n", $src); @@ -266,7 +266,7 @@ private function doDump($data, $name, $file, $line) if (PHP_VERSION_ID >= 50400 && $this->dumper instanceof CliDumper) { $contextDumper = function ($name, $file, $line, $fileLinkFormat) { if ($this instanceof HtmlDumper) { - if ('' !== $file) { + if ($file) { $s = $this->style('meta', '%s'); $name = strip_tags($this->style('', $name)); $file = strip_tags($this->style('', $file)); diff --git a/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php b/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php index 173d79dd41d64..25635399f7bd7 100644 --- a/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php @@ -149,7 +149,8 @@ public static function castFrameStub(FrameStub $frame, array $a, Stub $stub, $is $src[$f['file'].':'.$f['line']] = self::extractSource(explode("\n", file_get_contents($f['file'])), $f['line'], self::$srcContext); if (!empty($f['class']) && is_subclass_of($f['class'], 'Twig_Template') && method_exists($f['class'], 'getDebugInfo')) { - $template = isset($f['object']) ? $f['object'] : new $f['class'](new \Twig_Environment(new \Twig_Loader_Filesystem())); + $template = isset($f['object']) ? $f['object'] : unserialize(sprintf('O:%d:"%s":0:{}', strlen($f['class']), $f['class'])); + $templateName = $template->getTemplateName(); $templateSrc = method_exists($template, 'getSourceContext') ? $template->getSourceContext()->getCode() : (method_exists($template, 'getSource') ? $template->getSource() : ''); $templateInfo = $template->getDebugInfo(); diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/ExceptionCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/ExceptionCasterTest.php index 4c72eb1f7529b..1614f58a9ae9b 100644 --- a/src/Symfony/Component/VarDumper/Tests/Caster/ExceptionCasterTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Caster/ExceptionCasterTest.php @@ -26,15 +26,14 @@ public function testFrameWithTwig() $f = array( new FrameStub(array( 'file' => dirname(__DIR__).'/Fixtures/Twig.php', - 'line' => 19, + 'line' => 21, 'class' => '__TwigTemplate_VarDumperFixture_u75a09', - 'object' => new \__TwigTemplate_VarDumperFixture_u75a09(new \Twig_Environment(new \Twig_Loader_Filesystem())), )), new FrameStub(array( 'file' => dirname(__DIR__).'/Fixtures/Twig.php', - 'line' => 19, + 'line' => 21, 'class' => '__TwigTemplate_VarDumperFixture_u75a09', - 'object' => new \__TwigTemplate_VarDumperFixture_u75a09(new \Twig_Environment(new \Twig_Loader_Filesystem()), null), + 'object' => new \__TwigTemplate_VarDumperFixture_u75a09(null, false), )), ); @@ -42,11 +41,8 @@ public function testFrameWithTwig() array:2 [ 0 => { class: "__TwigTemplate_VarDumperFixture_u75a09" - object: __TwigTemplate_VarDumperFixture_u75a09 { - %A - } src: { - %sTwig.php:19: """ + %sTwig.php:21: """ // line 2\n throw new \Exception('Foobar');\n }\n @@ -64,7 +60,7 @@ class: "__TwigTemplate_VarDumperFixture_u75a09" %A } src: { - %sTwig.php:19: """ + %sTwig.php:21: """ // line 2\n throw new \Exception('Foobar');\n }\n diff --git a/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php b/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php index 36d45b6b5bb11..7a5ee0c5c3c0d 100644 --- a/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php @@ -254,7 +254,7 @@ public function testThrowingCaster() -trace: { %d. __TwigTemplate_VarDumperFixture_u75a09->doDisplay() ==> new Exception(): { src: { - %sTwig.php:19: """ + %sTwig.php:21: """ // line 2\\n throw new \Exception('Foobar');\\n }\\n diff --git a/src/Symfony/Component/VarDumper/Tests/Fixtures/Twig.php b/src/Symfony/Component/VarDumper/Tests/Fixtures/Twig.php index 7ffdd2bd54a63..9eaa39c88909c 100644 --- a/src/Symfony/Component/VarDumper/Tests/Fixtures/Twig.php +++ b/src/Symfony/Component/VarDumper/Tests/Fixtures/Twig.php @@ -5,9 +5,11 @@ class __TwigTemplate_VarDumperFixture_u75a09 extends Twig_Template { private $filename; - public function __construct(Twig_Environment $env, $filename = 'bar.twig') + public function __construct(Twig_Environment $env = null, $filename = null) { - parent::__construct($env); + if (null !== $env) { + parent::__construct($env); + } $this->parent = false; $this->blocks = array(); $this->filename = $filename; @@ -26,11 +28,11 @@ public function getTemplateName() public function getDebugInfo() { - return array(19 => 2); + return array(21 => 2); } public function getSourceContext() { - return new Twig_Source(" foo bar\n twig source\n\n", 'foo.twig', $this->filename); + return new Twig_Source(" foo bar\n twig source\n\n", 'foo.twig', false === $this->filename ? null : ($this->filename ?: 'bar.twig')); } } From 6bfd0f1f45e6c65f8b71c7057522e096eb9289f3 Mon Sep 17 00:00:00 2001 From: Victor Bocharsky Date: Thu, 27 Oct 2016 17:15:50 +0300 Subject: [PATCH 019/113] Remove extra line in doc-block comment --- src/Symfony/Component/Form/Extension/Core/Type/TextType.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TextType.php b/src/Symfony/Component/Form/Extension/Core/Type/TextType.php index 4776ebc4287b8..0944c38b61a2c 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/TextType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/TextType.php @@ -59,7 +59,6 @@ public function transform($data) /** * {@inheritdoc} - *. */ public function reverseTransform($data) { From 77c5395a79328a26c7098eb6f1282afa5356eca1 Mon Sep 17 00:00:00 2001 From: Xavier HAUSHERR Date: Thu, 27 Oct 2016 09:19:56 +0200 Subject: [PATCH 020/113] Compatibility with Twig 1.27 --- .../Bundle/TwigBundle/Loader/FilesystemLoader.php | 7 ++++++- .../Tests/Loader/FilesystemLoaderTest.php | 13 +++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/TwigBundle/Loader/FilesystemLoader.php b/src/Symfony/Bundle/TwigBundle/Loader/FilesystemLoader.php index 4e0bef365ebbb..53fe300e29a62 100644 --- a/src/Symfony/Bundle/TwigBundle/Loader/FilesystemLoader.php +++ b/src/Symfony/Bundle/TwigBundle/Loader/FilesystemLoader.php @@ -58,6 +58,7 @@ public function exists($name) * Otherwise the template is located using the locator from the twig library. * * @param string|TemplateReferenceInterface $template The template + * @param bool $throw When true, a \Twig_Error_Loader exception will be thrown if a template could not be found * * @return string The path to the template file * @@ -87,7 +88,11 @@ protected function findTemplate($template, $throw = true) } if (false === $file || null === $file) { - throw $twigLoaderException; + if ($throw) { + throw $twigLoaderException; + } + + return false; } return $this->cache[$logicalName] = $file; diff --git a/src/Symfony/Bundle/TwigBundle/Tests/Loader/FilesystemLoaderTest.php b/src/Symfony/Bundle/TwigBundle/Tests/Loader/FilesystemLoaderTest.php index 9804c08a1923b..132893e23b1d4 100644 --- a/src/Symfony/Bundle/TwigBundle/Tests/Loader/FilesystemLoaderTest.php +++ b/src/Symfony/Bundle/TwigBundle/Tests/Loader/FilesystemLoaderTest.php @@ -115,4 +115,17 @@ public function testTwigErrorIfTemplateDoesNotExist() $method->setAccessible(true); $method->invoke($loader, 'name.format.engine'); } + + public function testTwigSoftErrorIfTemplateDoesNotExist() + { + $parser = $this->getMock('Symfony\Component\Templating\TemplateNameParserInterface'); + $locator = $this->getMock('Symfony\Component\Config\FileLocatorInterface'); + + $loader = new FilesystemLoader($locator, $parser); + $loader->addPath(__DIR__.'/../DependencyInjection/Fixtures/Resources/views'); + + $method = new \ReflectionMethod('Symfony\Bundle\TwigBundle\Loader\FilesystemLoader', 'findTemplate'); + $method->setAccessible(true); + $this->assertFalse($method->invoke($loader, 'name.format.engine', false)); + } } From 8ad991e6c1aa35a174423da61224a84a59345cb8 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 27 Oct 2016 15:19:01 +0200 Subject: [PATCH 021/113] [Console] Fix empty COLUMNS/LINES env vars --- src/Symfony/Component/Console/Terminal.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Console/Terminal.php b/src/Symfony/Component/Console/Terminal.php index 9189f2ded3574..ddef70d7bf0cc 100644 --- a/src/Symfony/Component/Console/Terminal.php +++ b/src/Symfony/Component/Console/Terminal.php @@ -31,7 +31,7 @@ public function getWidth() self::initDimensions(); } - return self::$width; + return self::$width ?: 80; } /** @@ -49,7 +49,7 @@ public function getHeight() self::initDimensions(); } - return self::$height; + return self::$height ?: 50; } private static function initDimensions() From c4cc3927c39f62fb27e62b444b142aef0cd9465c Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Fri, 28 Oct 2016 09:07:59 +0200 Subject: [PATCH 022/113] [PhpUnitBridge] Fix undefined variable Otherwise `$mode` is not defined on line 115 --- src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php index cdf36b479dbba..0d4deb9a9bdcb 100644 --- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php +++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php @@ -68,7 +68,8 @@ public static function register($mode = 0) 'other' => array(), ); $deprecationHandler = function ($type, $msg, $file, $line, $context) use (&$deprecations, $getMode) { - if (E_USER_DEPRECATED !== $type || DeprecationErrorHandler::MODE_DISABLED === $mode = $getMode()) { + $mode = $getMode(); + if (E_USER_DEPRECATED !== $type || DeprecationErrorHandler::MODE_DISABLED === $mode) { return \PHPUnit_Util_ErrorHandler::handleError($type, $msg, $file, $line, $context); } From bc095a5c364e0a952dc65d31d088849f7c2b2a66 Mon Sep 17 00:00:00 2001 From: Romain Neutron Date: Fri, 28 Oct 2016 09:34:49 +0200 Subject: [PATCH 023/113] [Yaml] Fix String offset cast error in Inline parser --- src/Symfony/Component/Yaml/Inline.php | 5 ++++- src/Symfony/Component/Yaml/Tests/InlineTest.php | 9 +++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index b4a7072228e9b..ec3392161447c 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -458,7 +458,10 @@ private static function parseMapping($mapping, $flags, &$i = 0, $references = ar // key $key = self::parseScalar($mapping, $flags, array(':', ' '), array('"', "'"), $i, false); - $i = strpos($mapping, ':', $i); + + if (false === $i = strpos($mapping, ':', $i)) { + break; + } if (!isset($mapping[$i + 1]) || ' ' !== $mapping[$i + 1]) { @trigger_error('Omitting the space after the colon that follows a mapping key definition is deprecated since version 3.2 and will throw a ParseException in 4.0.', E_USER_DEPRECATED); diff --git a/src/Symfony/Component/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php index 35cd6b73aad20..22a3964809144 100644 --- a/src/Symfony/Component/Yaml/Tests/InlineTest.php +++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php @@ -654,4 +654,13 @@ public function getInvalidBinaryData() 'misplaced equals character' => array('!!binary "SGVsbG8gd29ybG=Q"', '/The base64 encoded data \(.*\) contains invalid characters/'), ); } + + /** + * @expectedException \Symfony\Component\Yaml\Exception\ParseException + * @expectedExceptionMessage Malformed inline YAML string {this, is not, yaml} + */ + public function testStringOffsetCastError() + { + Inline::parse('{this, is not, yaml}'); + } } From ae96079dab6262121a1aba55e770249d0fb241c6 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 28 Oct 2016 10:37:24 +0200 Subject: [PATCH 024/113] [SecurityBundle] Fix test context --- .../Tests/Functional/UserPasswordEncoderCommandTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php index 86a69fdb7624c..9f20bc56189f2 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php @@ -140,6 +140,7 @@ public function testEncodePasswordNoConfigForGivenUserClass() protected function setUp() { + putenv('COLUMNS=120'); $kernel = $this->createKernel(array('test_case' => 'PasswordEncode')); $kernel->boot(); From 8c787a539a7117cb08f567ff0c1e18e08b8ffeb0 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 28 Oct 2016 10:50:54 +0200 Subject: [PATCH 025/113] [SecurityBundle] Fix test context --- .../Tests/Functional/UserPasswordEncoderCommandTest.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php index 86a69fdb7624c..bdba22d2b3f0e 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php @@ -144,6 +144,7 @@ protected function setUp() $kernel->boot(); $application = new Application($kernel); + $application->setTerminalDimensions(120, 80); $application->add(new UserPasswordEncoderCommand()); $passwordEncoderCommand = $application->find('security:encode-password'); From 8e04643b909bd101628f8a98b82ddb12edf314aa Mon Sep 17 00:00:00 2001 From: Maxime STEINHAUSSER Date: Fri, 28 Oct 2016 14:44:09 +0200 Subject: [PATCH 026/113] Fix YamlReferenceDumper unnamed nested prototypes --- .../Config/Definition/Dumper/YamlReferenceDumper.php | 2 +- .../Definition/Dumper/XmlReferenceDumperTest.php | 8 ++++++++ .../Definition/Dumper/YamlReferenceDumperTest.php | 4 ++++ .../Fixtures/Configuration/ExampleConfiguration.php | 11 +++++++++++ 4 files changed, 24 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php b/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php index 940b1e7b9fdff..41724bd807105 100644 --- a/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php +++ b/src/Symfony/Component/Config/Definition/Dumper/YamlReferenceDumper.php @@ -201,7 +201,7 @@ private function getPrototypeChildren(PrototypedArrayNode $node) $keyNode = new ArrayNode($key, $node); $children = $prototype->getChildren(); - if ($prototype instanceof PrototypedArrayNode) { + if ($prototype instanceof PrototypedArrayNode && $prototype->getKeyAttribute()) { $children = $this->getPrototypeChildren($prototype); } diff --git a/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php b/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php index f65ac41e60b3a..e1f6118355f74 100644 --- a/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php @@ -92,6 +92,14 @@ enum="" + + + + + + + + EOL diff --git a/src/Symfony/Component/Config/Tests/Definition/Dumper/YamlReferenceDumperTest.php b/src/Symfony/Component/Config/Tests/Definition/Dumper/YamlReferenceDumperTest.php index 12b6caefb56ce..796a82733be9d 100644 --- a/src/Symfony/Component/Config/Tests/Definition/Dumper/YamlReferenceDumperTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/Dumper/YamlReferenceDumperTest.php @@ -74,6 +74,10 @@ enum: ~ # One of "this"; "that" locale: title: ~ # Required path: ~ # Required + pipou: + + # Prototype + name: [] EOL; } diff --git a/src/Symfony/Component/Config/Tests/Fixtures/Configuration/ExampleConfiguration.php b/src/Symfony/Component/Config/Tests/Fixtures/Configuration/ExampleConfiguration.php index 9f9080ec878ba..833266f30e28e 100644 --- a/src/Symfony/Component/Config/Tests/Fixtures/Configuration/ExampleConfiguration.php +++ b/src/Symfony/Component/Config/Tests/Fixtures/Configuration/ExampleConfiguration.php @@ -80,6 +80,17 @@ public function getConfigTreeBuilder() ->end() ->end() ->end() + ->arrayNode('pipou') + ->useAttributeAsKey('name') + ->prototype('array') + ->prototype('array') + ->children() + ->scalarNode('didou') + ->end() + ->end() + ->end() + ->end() + ->end() ->end() ; From a55058f097cc6bb30b5f732a8fa01c84e0026eea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Romey?= Date: Tue, 25 Oct 2016 21:57:41 +0200 Subject: [PATCH 027/113] [SecurityBundle] Changed encoder configuration example to bcrypt --- .../DependencyInjection/MainConfiguration.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php index 36dbcdf89a1bd..a3e5e233f9d71 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/MainConfiguration.php @@ -407,11 +407,10 @@ private function addEncodersSection(ArrayNodeDefinition $rootNode) ->children() ->arrayNode('encoders') ->example(array( - 'Acme\DemoBundle\Entity\User1' => 'sha512', - 'Acme\DemoBundle\Entity\User2' => array( - 'algorithm' => 'sha512', - 'encode_as_base64' => 'true', - 'iterations' => 5000, + 'AppBundle\Entity\User1' => 'bcrypt', + 'AppBundle\Entity\User2' => array( + 'algorithm' => 'bcrypt', + 'cost' => 13, ), )) ->requiresAtLeastOneElement() From 46dd3b9acb19c279b56be28fb3062f9a961b51ea Mon Sep 17 00:00:00 2001 From: Maxime STEINHAUSSER Date: Fri, 28 Oct 2016 15:52:16 +0200 Subject: [PATCH 028/113] [Form] Fix UrlType transforms valid protocols --- .../EventListener/FixUrlProtocolListener.php | 2 +- .../FixUrlProtocolListenerTest.php | 21 +++++++++++++++---- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/EventListener/FixUrlProtocolListener.php b/src/Symfony/Component/Form/Extension/Core/EventListener/FixUrlProtocolListener.php index a08337ec51908..e9a51cc988b7e 100644 --- a/src/Symfony/Component/Form/Extension/Core/EventListener/FixUrlProtocolListener.php +++ b/src/Symfony/Component/Form/Extension/Core/EventListener/FixUrlProtocolListener.php @@ -38,7 +38,7 @@ public function onSubmit(FormEvent $event) { $data = $event->getData(); - if ($this->defaultProtocol && $data && !preg_match('~^\w+://~', $data)) { + if ($this->defaultProtocol && $data && !preg_match('~^[\w+.-]+://~', $data)) { $event->setData($this->defaultProtocol.'://'.$data); } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixUrlProtocolListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixUrlProtocolListenerTest.php index a971ea215c02b..c3c9d08463efa 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixUrlProtocolListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/EventListener/FixUrlProtocolListenerTest.php @@ -40,15 +40,28 @@ public function testSkipKnownUrl() $this->assertEquals('http://www.symfony.com', $event->getData()); } - public function testSkipOtherProtocol() + public function provideUrlsWithSupportedProtocols() + { + return array( + array('ftp://www.symfony.com'), + array('chrome-extension://foo'), + array('h323://foo'), + array('iris.beep://foo'), + array('foo+bar://foo'), + ); + } + + /** + * @dataProvider provideUrlsWithSupportedProtocols + */ + public function testSkipOtherProtocol($url) { - $data = 'ftp://www.symfony.com'; $form = $this->getMock('Symfony\Component\Form\Test\FormInterface'); - $event = new FormEvent($form, $data); + $event = new FormEvent($form, $url); $filter = new FixUrlProtocolListener('http'); $filter->onSubmit($event); - $this->assertEquals('ftp://www.symfony.com', $event->getData()); + $this->assertEquals($url, $event->getData()); } } From 0aca9bf03cf01438810cd1510f68c5ad509113ff Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 31 Oct 2016 11:00:03 -0700 Subject: [PATCH 029/113] [Console] simplified code --- .../Console/Helper/ProgressIndicator.php | 19 +------------------ .../Tests/Helper/ProgressIndicatorTest.php | 10 +++++----- 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/ProgressIndicator.php b/src/Symfony/Component/Console/Helper/ProgressIndicator.php index ccf9771bcf9e4..2e43bc3f5a3b8 100644 --- a/src/Symfony/Component/Console/Helper/ProgressIndicator.php +++ b/src/Symfony/Component/Console/Helper/ProgressIndicator.php @@ -28,7 +28,6 @@ class ProgressIndicator private $indicatorCurrent; private $indicatorChangeInterval; private $indicatorUpdateTime; - private $lastMessagesLength; private $started = false; private static $formatters; @@ -125,7 +124,6 @@ public function start($message) $this->message = $message; $this->started = true; - $this->lastMessagesLength = 0; $this->startTime = time(); $this->indicatorUpdateTime = $this->getCurrentTimeInMilliseconds() + $this->indicatorChangeInterval; $this->indicatorCurrent = 0; @@ -262,27 +260,12 @@ private function determineBestFormat() */ private function overwrite($message) { - // append whitespace to match the line's length - if (null !== $this->lastMessagesLength) { - if ($this->lastMessagesLength > Helper::strlenWithoutDecoration($this->output->getFormatter(), $message)) { - $message = str_pad($message, $this->lastMessagesLength, "\x20", STR_PAD_RIGHT); - } - } - if ($this->output->isDecorated()) { - $this->output->write("\x0D"); + $this->output->write("\x0D\x1B[2K"); $this->output->write($message); } else { $this->output->writeln($message); } - - $this->lastMessagesLength = 0; - - $len = Helper::strlenWithoutDecoration($this->output->getFormatter(), $message); - - if ($len > $this->lastMessagesLength) { - $this->lastMessagesLength = $len; - } } private function getCurrentTimeInMilliseconds() diff --git a/src/Symfony/Component/Console/Tests/Helper/ProgressIndicatorTest.php b/src/Symfony/Component/Console/Tests/Helper/ProgressIndicatorTest.php index 192625263db87..2f72d3094b9bb 100644 --- a/src/Symfony/Component/Console/Tests/Helper/ProgressIndicatorTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/ProgressIndicatorTest.php @@ -44,11 +44,11 @@ public function testDefaultIndicator() $this->generateOutput(' \\ Starting...'). $this->generateOutput(' \\ Advancing...'). $this->generateOutput(' | Advancing...'). - $this->generateOutput(' | Done... '). + $this->generateOutput(' | Done...'). PHP_EOL. $this->generateOutput(' - Starting Again...'). $this->generateOutput(' \\ Starting Again...'). - $this->generateOutput(' \\ Done Again... '). + $this->generateOutput(' \\ Done Again...'). PHP_EOL, stream_get_contents($output->getStream()) ); @@ -70,8 +70,8 @@ public function testNonDecoratedOutput() $this->assertEquals( ' Starting...'.PHP_EOL. - ' Midway... '.PHP_EOL. - ' Done... '.PHP_EOL.PHP_EOL, + ' Midway...'.PHP_EOL. + ' Done...'.PHP_EOL.PHP_EOL, stream_get_contents($output->getStream()) ); } @@ -177,6 +177,6 @@ protected function generateOutput($expected) { $count = substr_count($expected, "\n"); - return "\x0D".($count ? sprintf("\033[%dA", $count) : '').$expected; + return "\x0D\x1B[2K".($count ? sprintf("\033[%dA", $count) : '').$expected; } } From 7a17080d558248a99b27e5e5f68090ed237b8f28 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Wed, 2 Nov 2016 09:26:37 +0100 Subject: [PATCH 030/113] Don't trim long strings in the profiler logs --- .../Bundle/WebProfilerBundle/Resources/config/profiler.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/config/profiler.xml b/src/Symfony/Bundle/WebProfilerBundle/Resources/config/profiler.xml index ecb97231d95f2..931363ac6d328 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/config/profiler.xml +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/config/profiler.xml @@ -42,6 +42,7 @@ Symfony\Component\VarDumper\Dumper\HtmlDumper::DUMP_LIGHT_ARRAY + 4096 From bf91eda705c2083ab059e93f3aef1ef99a902b4a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 2 Nov 2016 10:24:10 +0100 Subject: [PATCH 031/113] Revert "feature #17608 [DependencyInjection] Autowiring: add setter injection support (dunglas)" This reverts commit 7eab6b92042eee1afd32e37d9fb8583cc9dec100, reversing changes made to 35f201f9d6509f194081b1b04597ddb9d6bd54c6. --- CHANGELOG-3.2.md | 1 - .../DependencyInjection/CHANGELOG.md | 1 - .../Compiler/AutowirePass.php | 68 ++-------- .../Tests/Compiler/AutowirePassTest.php | 119 ------------------ 4 files changed, 9 insertions(+), 180 deletions(-) diff --git a/CHANGELOG-3.2.md b/CHANGELOG-3.2.md index 6335978da8a0d..41bb9a4f3dc37 100644 --- a/CHANGELOG-3.2.md +++ b/CHANGELOG-3.2.md @@ -101,7 +101,6 @@ To get the diff between two versions, go to https://github.com/symfony/symfony/c * feature #19325 [FrameworkBundle] Allow to specify a domain when updating translations (antograssiot) * feature #19277 [Serializer] Argument objects (theofidry, dunglas) * feature #19322 [HttpFoundation] Add Request::isMethodIdempotent method (dunglas) - * feature #17608 [DependencyInjection] Autowiring: add setter injection support (dunglas) * feature #18510 Added a SecurityUserValueResolver for controllers (iltar) * feature #19203 [Bridge/Doctrine] Reset the EM lazy-proxy instead of the EM service (nicolas-grekas) * feature #19236 [FrameworkBundle] Deprecate the service serializer.mapping.cache.doctrine.apc (Ener-Getick) diff --git a/src/Symfony/Component/DependencyInjection/CHANGELOG.md b/src/Symfony/Component/DependencyInjection/CHANGELOG.md index e006527ce24a5..43f445736f55c 100644 --- a/src/Symfony/Component/DependencyInjection/CHANGELOG.md +++ b/src/Symfony/Component/DependencyInjection/CHANGELOG.md @@ -4,7 +4,6 @@ CHANGELOG 3.2.0 ----- - * added support for setter autowiring * allowed to prioritize compiler passes by introducing a third argument to `PassConfig::addPass()`, to `Compiler::addPass` and to `ContainerBuilder::addCompilerPass()` * added support for PHP constants in YAML configuration files * deprecated the ability to set or unset a private service with the `Container::set()` method diff --git a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php index 09cbd4b06c354..d1b1fd292cf06 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/AutowirePass.php @@ -97,42 +97,12 @@ private function completeDefinition($id, Definition $definition) $this->container->addResource(static::createResourceForClass($reflectionClass)); } - if ($constructor = $reflectionClass->getConstructor()) { - $this->autowireMethod($id, $definition, $constructor, true); - } - - $methodsCalled = array(); - foreach ($definition->getMethodCalls() as $methodCall) { - $methodsCalled[$methodCall[0]] = true; - } - - foreach (self::getSetters($reflectionClass) as $reflectionMethod) { - if (!isset($methodsCalled[$reflectionMethod->name])) { - $this->autowireMethod($id, $definition, $reflectionMethod, false); - } - } - } - - /** - * Autowires the constructor or a setter. - * - * @param string $id - * @param Definition $definition - * @param \ReflectionMethod $reflectionMethod - * @param bool $isConstructor - * - * @throws RuntimeException - */ - private function autowireMethod($id, Definition $definition, \ReflectionMethod $reflectionMethod, $isConstructor) - { - if ($isConstructor) { - $arguments = $definition->getArguments(); - } else { - $arguments = array(); + if (!$constructor = $reflectionClass->getConstructor()) { + return; } - $addMethodCall = false; - foreach ($reflectionMethod->getParameters() as $index => $parameter) { + $arguments = $definition->getArguments(); + foreach ($constructor->getParameters() as $index => $parameter) { if (array_key_exists($index, $arguments) && '' !== $arguments[$index]) { continue; } @@ -141,11 +111,7 @@ private function autowireMethod($id, Definition $definition, \ReflectionMethod $ if (!$typeHint = $parameter->getClass()) { // no default value? Then fail if (!$parameter->isOptional()) { - if ($isConstructor) { - 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)); - } - - return; + 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 @@ -160,23 +126,16 @@ private function autowireMethod($id, Definition $definition, \ReflectionMethod $ if (isset($this->types[$typeHint->name])) { $value = new Reference($this->types[$typeHint->name]); - $addMethodCall = true; } else { try { $value = $this->createAutowiredDefinition($typeHint, $id); - $addMethodCall = true; } catch (RuntimeException $e) { if ($parameter->allowsNull()) { $value = null; } elseif ($parameter->isDefaultValueAvailable()) { $value = $parameter->getDefaultValue(); } else { - // The exception code is set to 1 if the exception must be thrown even if it's a setter - if (1 === $e->getCode() || $isConstructor) { - throw $e; - } - - return; + throw $e; } } } @@ -184,11 +143,7 @@ private function autowireMethod($id, Definition $definition, \ReflectionMethod $ // Typehint against a non-existing class if (!$parameter->isDefaultValueAvailable()) { - if ($isConstructor) { - throw new RuntimeException(sprintf('Cannot autowire argument %s for %s because the type-hinted class does not exist (%s).', $index + 1, $definition->getClass(), $e->getMessage()), 0, $e); - } - - return; + throw new RuntimeException(sprintf('Cannot autowire argument %s for %s because the type-hinted class does not exist (%s).', $index + 1, $definition->getClass(), $e->getMessage()), 0, $e); } $value = $parameter->getDefaultValue(); @@ -200,12 +155,7 @@ private function autowireMethod($id, Definition $definition, \ReflectionMethod $ // it's possible index 1 was set, then index 0, then 2, etc // make sure that we re-order so they're injected as expected ksort($arguments); - - if ($isConstructor) { - $definition->setArguments($arguments); - } elseif ($addMethodCall) { - $definition->addMethodCall($reflectionMethod->name, $arguments); - } + $definition->setArguments($arguments); } /** @@ -303,7 +253,7 @@ private function createAutowiredDefinition(\ReflectionClass $typeHint, $id) $classOrInterface = $typeHint->isInterface() ? 'interface' : 'class'; $matchingServices = implode(', ', $this->ambiguousServiceTypes[$typeHint->name]); - throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $typeHint->name, $id, $classOrInterface, $matchingServices), 1); + throw new RuntimeException(sprintf('Unable to autowire argument of type "%s" for the service "%s". Multiple services exist for this %s (%s).', $typeHint->name, $id, $classOrInterface, $matchingServices)); } if (!$typeHint->isInstantiable()) { diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php index 684e99b63228f..a8b1be355017a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/AutowirePassTest.php @@ -429,47 +429,6 @@ public function testOptionalScalarArgsNotPassedIfLast() ); } - public function testSetterInjection() - { - $container = new ContainerBuilder(); - $container->register('app_foo', Foo::class); - $container->register('app_a', A::class); - $container->register('app_collision_a', CollisionA::class); - $container->register('app_collision_b', CollisionB::class); - - // manually configure *one* call, to override autowiring - $container - ->register('setter_injection', SetterInjection::class) - ->setAutowired(true) - ->addMethodCall('setWithCallsConfigured', array('manual_arg1', 'manual_arg2')) - ; - - $pass = new AutowirePass(); - $pass->process($container); - - $methodCalls = $container->getDefinition('setter_injection')->getMethodCalls(); - - // grab the call method names - $actualMethodNameCalls = array_map(function ($call) { - return $call[0]; - }, $methodCalls); - $this->assertEquals( - array('setWithCallsConfigured', 'setFoo'), - $actualMethodNameCalls - ); - - // test setWithCallsConfigured args - $this->assertEquals( - array('manual_arg1', 'manual_arg2'), - $methodCalls[0][1] - ); - // test setFoo args - $this->assertEquals( - array(new Reference('app_foo')), - $methodCalls[1][1] - ); - } - /** * @dataProvider getCreateResourceTests */ @@ -517,24 +476,6 @@ public function testIgnoreServiceWithClassNotExisting() $this->assertTrue($container->hasDefinition('bar')); } - - /** - * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException - * @expectedExceptionMessage Unable to autowire argument of type "Symfony\Component\DependencyInjection\Tests\Compiler\CollisionInterface" for the service "setter_injection_collision". Multiple services exist for this interface (c1, c2). - * @expectedExceptionCode 1 - */ - public function testSetterInjectionCollisionThrowsException() - { - $container = new ContainerBuilder(); - - $container->register('c1', CollisionA::class); - $container->register('c2', CollisionB::class); - $aDefinition = $container->register('setter_injection_collision', SetterInjectionCollision::class); - $aDefinition->setAutowired(true); - - $pass = new AutowirePass(); - $pass->process($container); - } } class Foo @@ -707,69 +648,9 @@ public function setBar(Bar $bar) class IdenticalClassResource extends ClassForResource { } - class ClassChangedConstructorArgs extends ClassForResource { public function __construct($foo, Bar $bar, $baz) { } } - -class SetterInjection -{ - public function setFoo(Foo $foo) - { - // should be called - } - - public function setDependencies(Foo $foo, A $a) - { - // should be called - } - - public function setBar() - { - // should not be called - } - - public function setNotAutowireable(NotARealClass $n) - { - // should not be called - } - - public function setArgCannotAutowire($foo) - { - // should not be called - } - - public function setOptionalNotAutowireable(NotARealClass $n = null) - { - // should not be called - } - - public function setOptionalNoTypeHint($foo = null) - { - // should not be called - } - - public function setOptionalArgNoAutowireable($other = 'default_val') - { - // should not be called - } - - public function setWithCallsConfigured(A $a) - { - // this method has a calls configured on it - // should not be called - } -} - -class SetterInjectionCollision -{ - public function setMultipleInstancesForOneArg(CollisionInterface $collision) - { - // The CollisionInterface cannot be autowired - there are multiple - - // should throw an exception - } -} From 52faa007ae173913bd9899b1d0d5e9b14d7fdbfd Mon Sep 17 00:00:00 2001 From: Maxime STEINHAUSSER Date: Fri, 28 Oct 2016 10:44:52 +0200 Subject: [PATCH 032/113] Fix base DataCollector throws warning on unsupported scheme strings --- .../DataCollector/DataCollector.php | 2 +- .../Tests/DataCollector/DataCollectorTest.php | 49 +++++++++++++++++++ .../DataCollector/CloneVarDataCollector.php | 41 ++++++++++++++++ 3 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/HttpKernel/Tests/DataCollector/DataCollectorTest.php create mode 100644 src/Symfony/Component/HttpKernel/Tests/Fixtures/DataCollector/CloneVarDataCollector.php diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php index 904baeedbe2f1..1f8538a9f2522 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/DataCollector.php @@ -130,7 +130,7 @@ private function decorateVar($var) return new ClassStub($var); } } - if (false !== strpos($var, DIRECTORY_SEPARATOR) && file_exists($var)) { + if (false !== strpos($var, DIRECTORY_SEPARATOR) && false === strpos($var, '://') && file_exists($var)) { return new LinkStub($var); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/DataCollector/DataCollectorTest.php b/src/Symfony/Component/HttpKernel/Tests/DataCollector/DataCollectorTest.php new file mode 100644 index 0000000000000..a7fb447ad67c8 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/DataCollector/DataCollectorTest.php @@ -0,0 +1,49 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\DataCollector; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\Tests\Fixtures\DataCollector\CloneVarDataCollector; +use Symfony\Component\VarDumper\Cloner\Stub; +use Symfony\Component\VarDumper\Cloner\VarCloner; +use Symfony\Component\VarDumper\Dumper\CliDumper; + +class DataCollectorTest extends \PHPUnit_Framework_TestCase +{ + public function testCloneVarStringWithScheme() + { + $c = new CloneVarDataCollector('scheme://foo'); + $c->collect(new Request(), new Response()); + $cloner = new VarCloner(); + + $this->assertEquals($cloner->cloneVar('scheme://foo'), $c->getData()); + } + + public function testCloneVarExistingFilePath() + { + $c = new CloneVarDataCollector($filePath = tempnam(sys_get_temp_dir(), 'clone_var_data_collector_')); + $c->collect(new Request(), new Response()); + + $data = $c->getData(); + $this->assertInstanceOf(Stub::class, $data->getRawData()[0][0]); + $this->assertDumpEquals("\"$filePath\"", $data); + } + + private function assertDumpEquals($dump, $data, $message = '') + { + $dumper = new CliDumper(); + $dumper->setColors(false); + + $this->assertSame(rtrim($dump), rtrim($dumper->dump($data, true)), $message); + } +} diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/DataCollector/CloneVarDataCollector.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/DataCollector/CloneVarDataCollector.php new file mode 100644 index 0000000000000..867ccdce57892 --- /dev/null +++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/DataCollector/CloneVarDataCollector.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\HttpKernel\Tests\Fixtures\DataCollector; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\HttpKernel\DataCollector\DataCollector; + +class CloneVarDataCollector extends DataCollector +{ + private $varToClone; + + public function __construct($varToClone) + { + $this->varToClone = $varToClone; + } + + public function collect(Request $request, Response $response, \Exception $exception = null) + { + $this->data = $this->cloneVar($this->varToClone); + } + + public function getData() + { + return $this->data; + } + + public function getName() + { + return 'clone_var'; + } +} From e3420568751cb72e3c64b3e0b77f610c52ed09d6 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 2 Nov 2016 11:26:05 +0100 Subject: [PATCH 033/113] [SecurityBundle] Fix term width in UserPasswordEncoderCommandTest --- .../Tests/Functional/UserPasswordEncoderCommandTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php index bdba22d2b3f0e..844349ff8c576 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Functional/UserPasswordEncoderCommandTest.php @@ -144,7 +144,7 @@ protected function setUp() $kernel->boot(); $application = new Application($kernel); - $application->setTerminalDimensions(120, 80); + $application->setTerminalDimensions(119 + strlen(PHP_EOL), 80); $application->add(new UserPasswordEncoderCommand()); $passwordEncoderCommand = $application->find('security:encode-password'); From 0423d894f43a60da6d1625906f1fea536dcb5513 Mon Sep 17 00:00:00 2001 From: VJ Date: Tue, 1 Nov 2016 13:31:37 -0400 Subject: [PATCH 034/113] [HttpFoundation][Session] memcached connection should not be closed --- .../Session/Storage/Handler/MemcacheSessionHandler.php | 2 +- .../Session/Storage/Handler/MemcacheSessionHandlerTest.php | 6 ------ 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandler.php index a386bdd184e43..962a3878d9767 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandler.php @@ -71,7 +71,7 @@ public function open($savePath, $sessionName) */ public function close() { - return $this->memcache->close(); + return true; } /** diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MemcacheSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MemcacheSessionHandlerTest.php index 0c579d7724846..6745a22455edd 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MemcacheSessionHandlerTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MemcacheSessionHandlerTest.php @@ -56,12 +56,6 @@ public function testOpenSession() public function testCloseSession() { - $this->memcache - ->expects($this->once()) - ->method('close') - ->will($this->returnValue(true)) - ; - $this->assertTrue($this->storage->close()); } From 7520f7b937a717dc4d4ba87ffaefcb9a57a06ba9 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 2 Nov 2016 14:42:53 +0100 Subject: [PATCH 035/113] [Yaml] Clean some messages + add test case --- src/Symfony/Component/Yaml/Inline.php | 8 ++++---- src/Symfony/Component/Yaml/Tests/InlineTest.php | 9 +++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index 125def97fb04b..7f2a75b8c70b5 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -249,7 +249,7 @@ public static function parseScalar($scalar, $delimiters = null, $stringDelimiter $output = $match[1]; $i += strlen($output); } else { - throw new ParseException(sprintf('Malformed inline YAML string (%s).', $scalar)); + throw new ParseException(sprintf('Malformed inline YAML string: %s.', $scalar)); } if ($evaluate) { @@ -273,7 +273,7 @@ public static function parseScalar($scalar, $delimiters = null, $stringDelimiter private static function parseQuotedScalar($scalar, &$i) { if (!preg_match('/'.self::REGEX_QUOTED_STRING.'/Au', substr($scalar, $i), $match)) { - throw new ParseException(sprintf('Malformed inline YAML string (%s).', substr($scalar, $i))); + throw new ParseException(sprintf('Malformed inline YAML string: %s.', substr($scalar, $i))); } $output = substr($match[0], 1, strlen($match[0]) - 2); @@ -346,7 +346,7 @@ private static function parseSequence($sequence, &$i = 0, $references = array()) ++$i; } - throw new ParseException(sprintf('Malformed inline YAML string %s', $sequence)); + throw new ParseException(sprintf('Malformed inline YAML string: %s.', $sequence)); } /** @@ -434,7 +434,7 @@ private static function parseMapping($mapping, &$i = 0, $references = array()) } } - throw new ParseException(sprintf('Malformed inline YAML string %s', $mapping)); + throw new ParseException(sprintf('Malformed inline YAML string: %s.', $mapping)); } /** diff --git a/src/Symfony/Component/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php index 0e03e36a87a8a..755dfce592df8 100644 --- a/src/Symfony/Component/Yaml/Tests/InlineTest.php +++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php @@ -401,4 +401,13 @@ public function getTestsForDump() array('{ foo: { bar: { 1: 2, baz: 3 } } }', array('foo' => array('bar' => array(1 => 2, 'baz' => 3)))), ); } + + /** + * @expectedException \Symfony\Component\Yaml\Exception\ParseException + * @expectedExceptionMessage Malformed inline YAML string: {this, is not, supported}. + */ + public function testNotSupportedMissingValue() + { + Inline::parse('{this, is not, supported}'); + } } From 52d25edb5a485c72bf324a46cd90ae2fc29a6be6 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Thu, 21 Jul 2016 00:32:37 +0200 Subject: [PATCH 036/113] Introduce a FirewallConfig class Add a FirewallConfig object, pass it to the FirewallContext Add FirewallContextTest & FirewallConfigTest Populate FirewallConfig definition from SecurityExtension Add missing anonymous listener in FirewallConfig::listenerConfigs Add a functional test Fabbot fixes Fix security option value Add ContextAwareFirewallMapInterface Remove bool casts from getters CS/Spelling Fixes Remove FirewallConfig::listenerConfigs in favor of FirewallConfig::listeners; Add FirewallConfig::allowAnonymous() Add allowAnonymous()/isSecurityEnabled, update comments Fabbot fixes Fix deprecation message Remove interface CS Fixes --- .../DependencyInjection/SecurityExtension.php | 49 ++++++- .../Resources/config/security.xml | 16 ++- .../Security/FirewallConfig.php | 126 ++++++++++++++++++ .../Security/FirewallContext.php | 13 +- .../SecurityBundle/Security/FirewallMap.php | 32 ++++- .../CompleteConfigurationTest.php | 61 ++++++++- .../Tests/Security/FirewallConfigTest.php | 60 +++++++++ .../Tests/Security/FirewallContextTest.php | 45 +++++++ 8 files changed, 394 insertions(+), 8 deletions(-) create mode 100644 src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallConfigTest.php create mode 100644 src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallContextTest.php diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 4398a2a36d433..6ac5c63338279 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -110,6 +110,7 @@ public function load(array $configs, ContainerBuilder $container) 'Symfony\Component\Security\Core\Authorization\AccessDecisionManager', 'Symfony\Component\Security\Core\Authorization\AuthorizationChecker', 'Symfony\Component\Security\Core\Authorization\Voter\VoterInterface', + 'Symfony\Bundle\SecurityBundle\Security\FirewallConfig', 'Symfony\Bundle\SecurityBundle\Security\FirewallMap', 'Symfony\Bundle\SecurityBundle\Security\FirewallContext', 'Symfony\Component\HttpFoundation\RequestMatcher', @@ -236,14 +237,18 @@ private function createFirewalls($config, ContainerBuilder $container) $mapDef = $container->getDefinition('security.firewall.map'); $map = $authenticationProviders = array(); foreach ($firewalls as $name => $firewall) { - list($matcher, $listeners, $exceptionListener) = $this->createFirewall($container, $name, $firewall, $authenticationProviders, $providerIds); + $configId = 'security.firewall.map.config.'.$name; + + list($matcher, $listeners, $exceptionListener) = $this->createFirewall($container, $name, $firewall, $authenticationProviders, $providerIds, $configId); $contextId = 'security.firewall.map.context.'.$name; $context = $container->setDefinition($contextId, new DefinitionDecorator('security.firewall.context')); $context ->replaceArgument(0, $listeners) ->replaceArgument(1, $exceptionListener) + ->replaceArgument(2, new Reference($configId)) ; + $map[$contextId] = $matcher; } $mapDef->replaceArgument(1, $map); @@ -258,8 +263,11 @@ private function createFirewalls($config, ContainerBuilder $container) ; } - private function createFirewall(ContainerBuilder $container, $id, $firewall, &$authenticationProviders, $providerIds) + private function createFirewall(ContainerBuilder $container, $id, $firewall, &$authenticationProviders, $providerIds, $configId) { + $config = $container->setDefinition($configId, new DefinitionDecorator('security.firewall.config')); + $config->replaceArgument(0, $id); + // Matcher $matcher = null; if (isset($firewall['request_matcher'])) { @@ -271,11 +279,16 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a $matcher = $this->createRequestMatcher($container, $pattern, $host, $methods); } + $config->replaceArgument(1, (string) $matcher); + $config->replaceArgument(2, $firewall['security']); + // Security disabled? if (false === $firewall['security']) { return array($matcher, array(), null); } + $config->replaceArgument(3, $firewall['stateless']); + // Provider id (take the first registered provider if none defined) if (isset($firewall['provider'])) { $defaultProvider = $this->getUserProviderId($firewall['provider']); @@ -283,8 +296,11 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a $defaultProvider = reset($providerIds); } + $config->replaceArgument(4, $defaultProvider); + // Register listeners $listeners = array(); + $listenerKeys = array(); // Channel listener $listeners[] = new Reference('security.channel_listener'); @@ -296,11 +312,14 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a $contextKey = $firewall['context']; } + $config->replaceArgument(5, $contextKey); + $listeners[] = new Reference($this->createContextListener($container, $contextKey)); } // Logout listener if (isset($firewall['logout'])) { + $listenerKeys[] = 'logout'; $listenerId = 'security.logout_listener.'.$id; $listener = $container->setDefinition($listenerId, new DefinitionDecorator('security.logout_listener')); $listener->replaceArgument(3, array( @@ -363,10 +382,13 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a // Authentication listeners list($authListeners, $defaultEntryPoint) = $this->createAuthenticationListeners($container, $id, $firewall, $authenticationProviders, $defaultProvider, $configuredEntryPoint); + $config->replaceArgument(6, $configuredEntryPoint ?: $defaultEntryPoint); + $listeners = array_merge($listeners, $authListeners); // Switch user listener if (isset($firewall['switch_user'])) { + $listenerKeys[] = 'switch_user'; $listeners[] = new Reference($this->createSwitchUserListener($container, $id, $firewall['switch_user'], $defaultProvider)); } @@ -376,7 +398,30 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a // Exception listener $exceptionListener = new Reference($this->createExceptionListener($container, $firewall, $id, $configuredEntryPoint ?: $defaultEntryPoint, $firewall['stateless'])); + if (isset($firewall['access_denied_handler'])) { + $config->replaceArgument(7, $firewall['access_denied_handler']); + } + if (isset($firewall['access_denied_url'])) { + $config->replaceArgument(8, $firewall['access_denied_url']); + } + $container->setAlias(new Alias('security.user_checker.'.$id, false), $firewall['user_checker']); + $config->replaceArgument(9, $firewall['user_checker']); + + foreach ($this->factories as $position) { + foreach ($position as $factory) { + $key = str_replace('-', '_', $factory->getKey()); + if (array_key_exists($key, $firewall)) { + $listenerKeys[] = $key; + } + } + } + + if (isset($firewall['anonymous'])) { + $listenerKeys[] = 'anonymous'; + } + + $config->replaceArgument(10, $listenerKeys); return array($matcher, $listeners, $exceptionListener); } diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml index c34453cb3854f..244e75dea0921 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml @@ -111,6 +111,21 @@ + + + + + + + + + + + + + + + @@ -119,7 +134,6 @@ - diff --git a/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php b/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php new file mode 100644 index 0000000000000..4cc5ce17baaa4 --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php @@ -0,0 +1,126 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\SecurityBundle\Security; + +/** + * @author Robin Chalas + */ +class FirewallConfig +{ + private $name; + private $requestMatcher; + private $securityEnabled; + private $stateless; + private $provider; + private $context; + private $entryPoint; + private $accessDeniedHandler; + private $accessDeniedUrl; + private $userChecker; + private $listeners; + + public function __construct($name, $requestMatcher, $securityEnabled = true, $stateless = false, $provider = null, $context = null, $entryPoint = null, $accessDeniedHandler = null, $accessDeniedUrl = null, $userChecker = null, $listeners = array()) + { + $this->name = $name; + $this->requestMatcher = $requestMatcher; + $this->securityEnabled = $securityEnabled; + $this->stateless = $stateless; + $this->provider = $provider; + $this->context = $context; + $this->entryPoint = $entryPoint; + $this->accessDeniedHandler = $accessDeniedHandler; + $this->accessDeniedUrl = $accessDeniedUrl; + $this->userChecker = $userChecker; + $this->listeners = $listeners; + } + + public function getName() + { + return $this->name; + } + + /** + * @return string The request matcher service id + */ + public function getRequestMatcher() + { + return $this->requestMatcher; + } + + public function isSecurityEnabled() + { + return $this->securityEnabled; + } + + public function allowsAnonymous() + { + return in_array('anonymous', $this->listeners, true); + } + + public function isStateless() + { + return $this->stateless; + } + + /** + * @return string The provider service id + */ + public function getProvider() + { + return $this->provider; + } + + /** + * @return string The context key + */ + public function getContext() + { + return $this->context; + } + + /** + * @return string The entry_point service id + */ + public function getEntryPoint() + { + return $this->entryPoint; + } + + /** + * @return string The user_checker service id + */ + public function getUserChecker() + { + return $this->userChecker; + } + + /** + * @return string The access_denied_handler service id + */ + public function getAccessDeniedHandler() + { + return $this->accessDeniedHandler; + } + + public function getAccessDeniedUrl() + { + return $this->accessDeniedUrl; + } + + /** + * @return array An array of listener keys + */ + public function getListeners() + { + return $this->listeners; + } +} diff --git a/src/Symfony/Bundle/SecurityBundle/Security/FirewallContext.php b/src/Symfony/Bundle/SecurityBundle/Security/FirewallContext.php index 13d096d97e951..9d00c121e5160 100644 --- a/src/Symfony/Bundle/SecurityBundle/Security/FirewallContext.php +++ b/src/Symfony/Bundle/SecurityBundle/Security/FirewallContext.php @@ -23,11 +23,22 @@ class FirewallContext { private $listeners; private $exceptionListener; + private $config; - public function __construct(array $listeners, ExceptionListener $exceptionListener = null) + public function __construct(array $listeners, ExceptionListener $exceptionListener = null, FirewallConfig $config = null) { + if (null === $config) { + @trigger_error(sprintf('"%s()" expects an instance of "%s" as third argument since version 3.2 and will trigger an error in 4.0 if not provided.', __METHOD__, FirewallConfig::class), E_USER_DEPRECATED); + } + $this->listeners = $listeners; $this->exceptionListener = $exceptionListener; + $this->config = $config; + } + + public function getConfig() + { + return $this->config; } public function getContext() diff --git a/src/Symfony/Bundle/SecurityBundle/Security/FirewallMap.php b/src/Symfony/Bundle/SecurityBundle/Security/FirewallMap.php index da79e3c8c2926..f833a63e65966 100644 --- a/src/Symfony/Bundle/SecurityBundle/Security/FirewallMap.php +++ b/src/Symfony/Bundle/SecurityBundle/Security/FirewallMap.php @@ -35,7 +35,35 @@ public function __construct(ContainerInterface $container, array $map) $this->contexts = new \SplObjectStorage(); } + /** + * {@inheritdoc} + */ public function getListeners(Request $request) + { + $context = $this->getFirewallContext($request); + + if (null === $context) { + return array(array(), null); + } + + return $context->getContext(); + } + + /** + * @return FirewallConfig|null + */ + public function getFirewallConfig(Request $request) + { + $context = $this->getFirewallContext($request); + + if (null === $context) { + return; + } + + return $context->getConfig(); + } + + private function getFirewallContext(Request $request) { if ($this->contexts->contains($request)) { return $this->contexts[$request]; @@ -43,10 +71,8 @@ public function getListeners(Request $request) foreach ($this->map as $contextId => $requestMatcher) { if (null === $requestMatcher || $requestMatcher->matches($request)) { - return $this->contexts[$request] = $this->container->get($contextId)->getContext(); + return $this->contexts[$request] = $this->container->get($contextId); } } - - return array(array(), null); } } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php index a0dc39a11629e..8f877de4cc870 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php @@ -63,15 +63,74 @@ public function testUserProviders() public function testFirewalls() { $container = $this->getContainer('container1'); - $arguments = $container->getDefinition('security.firewall.map')->getArguments(); $listeners = array(); + $configs = array(); foreach (array_keys($arguments[1]) as $contextId) { $contextDef = $container->getDefinition($contextId); $arguments = $contextDef->getArguments(); $listeners[] = array_map(function ($ref) { return (string) $ref; }, $arguments['index_0']); + + $configDef = $container->getDefinition($arguments['index_2']); + $configs[] = array_values($configDef->getArguments()); } + $this->assertEquals(array( + array( + 'simple', + 'security.request_matcher.707b20193d4cb9f2718114abcbebb32af48f948484fc166a03482f49bf14f25e271f72c7', + false, + ), + array( + 'secure', + '', + true, + true, + 'security.user.provider.concrete.default', + 'security.authentication.form_entry_point.secure', + 'security.user_checker', + array( + 'logout', + 'switch_user', + 'x509', + 'remote_user', + 'form_login', + 'http_basic', + 'http_digest', + 'remember_me', + 'anonymous', + ), + ), + array( + 'host', + 'security.request_matcher.dda8b565689ad8509623ee68fb2c639cd81cd4cb339d60edbaf7d67d30e6aa09bd8c63c3', + true, + false, + 'security.user.provider.concrete.default', + 'host', + 'security.authentication.basic_entry_point.host', + 'security.user_checker', + array( + 'http_basic', + 'anonymous', + ), + ), + array( + 'with_user_checker', + '', + true, + false, + 'security.user.provider.concrete.default', + 'with_user_checker', + 'security.authentication.basic_entry_point.with_user_checker', + 'app.user_checker', + array( + 'http_basic', + 'anonymous', + ), + ), + ), $configs); + $this->assertEquals(array( array(), array( diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallConfigTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallConfigTest.php new file mode 100644 index 0000000000000..8d9b0519b197e --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallConfigTest.php @@ -0,0 +1,60 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\SecurityBundle\Tests\Security; + +use Symfony\Bundle\SecurityBundle\Security\FirewallConfig; + +class FirewallConfigTest extends \PHPUnit_Framework_TestCase +{ + public function testGetters() + { + $listeners = array('logout', 'remember_me', 'anonymous'); + $options = array( + 'request_matcher' => 'foo_request_matcher', + 'security' => false, + 'stateless' => false, + 'provider' => 'foo_provider', + 'context' => 'foo_context', + 'entry_point' => 'foo_entry_point', + 'access_denied_url' => 'foo_access_denied_url', + 'access_denied_handler' => 'foo_access_denied_handler', + 'user_checker' => 'foo_user_checker', + ); + + $config = new FirewallConfig( + 'foo_firewall', + $options['request_matcher'], + $options['security'], + $options['stateless'], + $options['provider'], + $options['context'], + $options['entry_point'], + $options['access_denied_handler'], + $options['access_denied_url'], + $options['user_checker'], + $listeners + ); + + $this->assertSame('foo_firewall', $config->getName()); + $this->assertSame($options['request_matcher'], $config->getRequestMatcher()); + $this->assertSame($options['security'], $config->isSecurityEnabled()); + $this->assertSame($options['stateless'], $config->isStateless()); + $this->assertSame($options['provider'], $config->getProvider()); + $this->assertSame($options['context'], $config->getContext()); + $this->assertSame($options['entry_point'], $config->getEntryPoint()); + $this->assertSame($options['access_denied_handler'], $config->getAccessDeniedHandler()); + $this->assertSame($options['access_denied_url'], $config->getAccessDeniedUrl()); + $this->assertSame($options['user_checker'], $config->getUserChecker()); + $this->assertTrue($config->allowsAnonymous()); + $this->assertSame($listeners, $config->getListeners()); + } +} diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallContextTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallContextTest.php new file mode 100644 index 0000000000000..86aecc1aa2d3e --- /dev/null +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallContextTest.php @@ -0,0 +1,45 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\SecurityBundle\Tests\Security; + +use Symfony\Bundle\SecurityBundle\Security\FirewallConfig; +use Symfony\Bundle\SecurityBundle\Security\FirewallContext; +use Symfony\Component\Security\Http\Firewall\ExceptionListener; +use Symfony\Component\Security\Http\Firewall\ListenerInterface; + +class FirewallContextTest extends \PHPUnit_Framework_TestCase +{ + public function testGetters() + { + $config = $this + ->getMockBuilder(FirewallConfig::class) + ->disableOriginalConstructor() + ->getMock(); + + $exceptionListener = $this + ->getMockBuilder(ExceptionListener::class) + ->disableOriginalConstructor() + ->getMock(); + + $listeners = array( + $this + ->getMockBuilder(ListenerInterface::class) + ->disableOriginalConstructor() + ->getMock(), + ); + + $context = new FirewallContext($listeners, $exceptionListener, $config); + + $this->assertEquals(array($listeners, $exceptionListener), $context->getContext()); + $this->assertEquals($config, $context->getConfig()); + } +} From 75e208e419dc8120535432ad99a3c59713b7a7ec Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sat, 30 Jul 2016 11:03:31 +0200 Subject: [PATCH 037/113] Integrate current firewall in profiler --- .../DataCollector/SecurityDataCollector.php | 39 +++- .../Resources/config/collectors.xml | 1 + .../views/Collector/security.html.twig | 166 +++++++++++++----- .../SecurityDataCollectorTest.php | 69 ++++++++ 4 files changed, 229 insertions(+), 46 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php index 2c66e86c34c15..7234c15030917 100644 --- a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php +++ b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php @@ -21,6 +21,8 @@ use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface; use Symfony\Component\Security\Core\Authorization\DebugAccessDecisionManager; use Symfony\Component\VarDumper\Cloner\Data; +use Symfony\Component\Security\Http\FirewallMapInterface; +use Symfony\Bundle\SecurityBundle\Security\FirewallMAp; /** * SecurityDataCollector. @@ -33,6 +35,7 @@ class SecurityDataCollector extends DataCollector private $roleHierarchy; private $logoutUrlGenerator; private $accessDecisionManager; + private $firewallMap; /** * Constructor. @@ -41,13 +44,15 @@ class SecurityDataCollector extends DataCollector * @param RoleHierarchyInterface|null $roleHierarchy * @param LogoutUrlGenerator|null $logoutUrlGenerator * @param AccessDecisionManagerInterface|null $accessDecisionManager + * @param FirewallMapInterface|null $firewallMap */ - public function __construct(TokenStorageInterface $tokenStorage = null, RoleHierarchyInterface $roleHierarchy = null, LogoutUrlGenerator $logoutUrlGenerator = null, AccessDecisionManagerInterface $accessDecisionManager = null) + public function __construct(TokenStorageInterface $tokenStorage = null, RoleHierarchyInterface $roleHierarchy = null, LogoutUrlGenerator $logoutUrlGenerator = null, AccessDecisionManagerInterface $accessDecisionManager = null, FirewallMapInterface $firewallMap = null) { $this->tokenStorage = $tokenStorage; $this->roleHierarchy = $roleHierarchy; $this->logoutUrlGenerator = $logoutUrlGenerator; $this->accessDecisionManager = $accessDecisionManager; + $this->firewallMap = $firewallMap; } /** @@ -132,6 +137,28 @@ public function collect(Request $request, Response $response, \Exception $except $this->data['voter_strategy'] = 'unknown'; $this->data['voters'] = array(); } + + // collect firewall context information + $this->data['firewall'] = null; + if ($this->firewallMap instanceof FirewallMap) { + $firewallConfig = $this->firewallMap->getFirewallConfig($request); + if (null !== $firewallConfig) { + $this->data['firewall'] = array( + 'name' => $firewallConfig->getName(), + 'allows_anonymous' => $firewallConfig->allowsAnonymous(), + 'request_matcher' => $firewallConfig->getRequestMatcher(), + 'security_enabled' => $firewallConfig->isSecurityEnabled(), + 'stateless' => $firewallConfig->isStateless(), + 'provider' => $firewallConfig->getProvider(), + 'context' => $firewallConfig->getContext(), + 'entry_point' => $firewallConfig->getEntryPoint(), + 'access_denied_handler' => $firewallConfig->getAccessDeniedHandler(), + 'access_denied_url' => $firewallConfig->getAccessDeniedUrl(), + 'user_checker' => $firewallConfig->getUserChecker(), + 'listeners' => $this->cloneVar($firewallConfig->getListeners()), + ); + } + } } /** @@ -255,6 +282,16 @@ public function getAccessDecisionLog() return $this->data['access_decision_log']; } + /** + * Returns the configuration of the current firewall context. + * + * @return array + */ + public function getFirewall() + { + return $this->data['firewall']; + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/collectors.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/collectors.xml index de157d51824ce..f812a9d790bb8 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/collectors.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/collectors.xml @@ -11,6 +11,7 @@ + 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 e857f579e30b3..31ffe3c9d23b6 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig +++ b/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig @@ -33,6 +33,12 @@ {{ collector.tokenClass|abbr_class }} {% endif %} + {% if collector.firewall %} +
+ Firewall name + {{ collector.firewall.name }} +
+ {% endif %} {% if collector.logoutUrl %}
Actions @@ -63,57 +69,127 @@ {% block panel %}

Security Token

- {% if collector.token %} -
-
- {{ collector.user == 'anon.' ? 'Anonymous' : collector.user }} - Username + {% if collector.enabled %} + {% if collector.token %} +
+
+ {{ collector.user == 'anon.' ? 'Anonymous' : collector.user }} + Username +
+ +
+ {{ include('@WebProfiler/Icon/' ~ (collector.authenticated ? 'yes' : 'no') ~ '.svg') }} + Authenticated +
-
- {{ include('@WebProfiler/Icon/' ~ (collector.authenticated ? 'yes' : 'no') ~ '.svg') }} - Authenticated + + + + + + + + + + + + + + {% if collector.supportsRoleHierarchy %} + + + + + {% endif %} + + {% if collector.token %} + + + + + {% endif %} + +
PropertyValue
Roles + {{ collector.roles is empty ? 'none' : profiler_dump(collector.roles, maxDepth=1) }} + + {% if not collector.authenticated and collector.roles is empty %} +

User is not authenticated probably because they have no roles.

+ {% endif %} +
Inherited Roles{{ collector.inheritedRoles is empty ? 'none' : profiler_dump(collector.inheritedRoles, maxDepth=1) }}
Token{{ profiler_dump(collector.token) }}
+ {% elseif collector.enabled %} +
+

There is no security token.

-
+ {% endif %} - - - - - - - - - - - - - {% if collector.supportsRoleHierarchy %} - - - - - {% endif %} +

Security Firewall

- {% if collector.token %} - - - - - {% endif %} - -
PropertyValue
Roles - {{ collector.roles is empty ? 'none' : profiler_dump(collector.roles, maxDepth=1) }} - - {% if not collector.authenticated and collector.roles is empty %} -

User is not authenticated probably because they have no roles.

- {% endif %} -
Inherited Roles{{ collector.inheritedRoles is empty ? 'none' : profiler_dump(collector.inheritedRoles, maxDepth=1) }}
Token{{ profiler_dump(collector.token) }}
- {% elseif collector.enabled %} -
-

There is no security token.

-
+ {% if collector.firewall %} +
+
+ {{ collector.firewall.name }} + Name +
+
+ {{ include('@WebProfiler/Icon/' ~ (collector.firewall.security_enabled ? 'yes' : 'no') ~ '.svg') }} + Security enabled +
+
+ {{ include('@WebProfiler/Icon/' ~ (collector.firewall.stateless ? 'yes' : 'no') ~ '.svg') }} + Stateless +
+
+ {{ include('@WebProfiler/Icon/' ~ (collector.firewall.allows_anonymous ? 'yes' : 'no') ~ '.svg') }} + Allows anonymous +
+
+ {% if collector.firewall.security_enabled %} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
KeyValue
provider{{ collector.firewall.provider }}
context{{ collector.firewall.context }}
entry_point{{ collector.firewall.entry_point }}
user_checker{{ collector.firewall.user_checker }}
access_denied_handler{{ collector.firewall.access_denied_handler }}
access_denied_url{{ collector.firewall.access_denied_url }}
listeners{{ collector.firewall.listeners is empty ? 'none' : profiler_dump(collector.firewall.listeners, maxDepth=1) }}
+ {% endif %} + {% elseif collector.enabled %} +
+

There is no firewall.

+
+ {% endif %} {% else %}

The security component is disabled.

diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php index a9b6818d64f50..e5a6a4b760503 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php @@ -12,10 +12,13 @@ namespace Symfony\Bundle\SecurityBundle\Tests\DataCollector; use Symfony\Bundle\SecurityBundle\DataCollector\SecurityDataCollector; +use Symfony\Bundle\SecurityBundle\Security\FirewallConfig; +use Symfony\Bundle\SecurityBundle\Security\FirewallMap; use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorage; use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; use Symfony\Component\Security\Core\Role\Role; use Symfony\Component\Security\Core\Role\RoleHierarchy; +use Symfony\Component\Security\Http\FirewallMapInterface; class SecurityDataCollectorTest extends \PHPUnit_Framework_TestCase { @@ -32,6 +35,7 @@ public function testCollectWhenSecurityIsDisabled() $this->assertCount(0, $collector->getRoles()); $this->assertCount(0, $collector->getInheritedRoles()); $this->assertEmpty($collector->getUser()); + $this->assertNull($collector->getFirewall()); } public function testCollectWhenAuthenticationTokenIsNull() @@ -47,6 +51,7 @@ public function testCollectWhenAuthenticationTokenIsNull() $this->assertCount(0, $collector->getRoles()); $this->assertCount(0, $collector->getInheritedRoles()); $this->assertEmpty($collector->getUser()); + $this->assertNull($collector->getFirewall()); } /** @dataProvider provideRoles */ @@ -71,6 +76,70 @@ public function testCollectAuthenticationTokenAndRoles(array $roles, array $norm $this->assertSame('hhamon', $collector->getUser()); } + public function testGetFirewall() + { + $firewallConfig = new FirewallConfig('dummy', 'security.request_matcher.dummy'); + $request = $this->getRequest(); + + $firewallMap = $this + ->getMockBuilder(FirewallMap::class) + ->disableOriginalConstructor() + ->getMock(); + $firewallMap + ->expects($this->once()) + ->method('getFirewallConfig') + ->with($request) + ->willReturn($firewallConfig); + + $collector = new SecurityDataCollector(null, null, null, null, $firewallMap); + $collector->collect($request, $this->getResponse()); + $collected = $collector->getFirewall(); + + $this->assertSame($firewallConfig->getName(), $collected['name']); + $this->assertSame($firewallConfig->allowsAnonymous(), $collected['allows_anonymous']); + $this->assertSame($firewallConfig->getRequestMatcher(), $collected['request_matcher']); + $this->assertSame($firewallConfig->isSecurityEnabled(), $collected['security_enabled']); + $this->assertSame($firewallConfig->isStateless(), $collected['stateless']); + $this->assertSame($firewallConfig->getProvider(), $collected['provider']); + $this->assertSame($firewallConfig->getContext(), $collected['context']); + $this->assertSame($firewallConfig->getEntryPoint(), $collected['entry_point']); + $this->assertSame($firewallConfig->getAccessDeniedHandler(), $collected['access_denied_handler']); + $this->assertSame($firewallConfig->getAccessDeniedUrl(), $collected['access_denied_url']); + $this->assertSame($firewallConfig->getUserChecker(), $collected['user_checker']); + $this->assertSame($firewallConfig->getListeners(), $collected['listeners']->getRawData()[0][0]); + } + + public function testGetFirewallReturnsNull() + { + $request = $this->getRequest(); + $response = $this->getResponse(); + + // Don't inject any firewall map + $collector = new SecurityDataCollector(); + $collector->collect($request, $response); + $this->assertNull($collector->getFirewall()); + + // Inject an instance that is not context aware + $firewallMap = $this + ->getMockBuilder(FirewallMapInterface::class) + ->disableOriginalConstructor() + ->getMock(); + + $collector = new SecurityDataCollector(null, null, null, null, $firewallMap); + $collector->collect($request, $response); + $this->assertNull($collector->getFirewall()); + + // Null config + $firewallMap = $this + ->getMockBuilder(FirewallMap::class) + ->disableOriginalConstructor() + ->getMock(); + + $collector = new SecurityDataCollector(null, null, null, null, $firewallMap); + $collector->collect($request, $response); + $this->assertNull($collector->getFirewall()); + } + public function provideRoles() { return array( From 22d4e156344727877d94e9ea792e6ccd9ca6ff16 Mon Sep 17 00:00:00 2001 From: Dariusz Ruminski Date: Sun, 30 Oct 2016 10:34:06 +0100 Subject: [PATCH 038/113] CS: apply rules --- .../Doctrine/Form/Type/DoctrineType.php | 1 - .../DoctrineExtensionTest.php | 2 +- .../Bridge/Twig/Command/DebugCommand.php | 2 +- .../Bridge/Twig/Command/LintCommand.php | 2 +- .../Command/ConfigDebugCommand.php | 2 +- .../Command/EventDispatcherDebugCommand.php | 2 +- .../Command/ServerStartCommand.php | 2 +- .../Command/ServerStopCommand.php | 2 +- .../Command/TranslationDebugCommand.php | 2 +- .../Command/YamlLintCommand.php | 2 +- .../views/Form/number_widget.html.php | 2 +- .../views/Form/password_widget.html.php | 2 +- .../views/Form/percent_widget.html.php | 2 +- .../views/Form/reset_widget.html.php | 2 +- .../views/Form/search_widget.html.php | 2 +- .../views/Form/submit_widget.html.php | 2 +- .../Resources/views/Form/url_widget.html.php | 2 +- .../Bundle/FrameworkBundle/Routing/Router.php | 1 - .../Tests/Command/RouterMatchCommandTest.php | 1 - .../Command/TranslationDebugCommandTest.php | 4 +- .../Command/TranslationUpdateCommandTest.php | 4 +- .../Descriptor/AbstractDescriptorTest.php | 1 + .../Console/Descriptor/ObjectsProvider.php | 2 + .../Resources/views/translation.html.php | 2 +- .../DataCollector/SecurityDataCollector.php | 2 +- .../Factory/SecurityFactoryInterface.php | 4 +- .../Controller/PreviewErrorControllerTest.php | 1 - .../Dumper/XmlReferenceDumperTest.php | 2 +- .../Tests/Helper/LegacyTableHelperTest.php | 4 +- .../Tests/Helper/ProcessHelperTest.php | 12 +++--- .../Console/Tests/Helper/ProgressBarTest.php | 3 -- .../Console/Tests/Helper/TableTest.php | 40 +++++++++---------- .../Component/CssSelector/Parser/Reader.php | 2 - .../Debug/Resources/ext/tests/001.phpt | 26 ++++++------ .../Debug/Resources/ext/tests/002.phpt | 3 +- .../Debug/Resources/ext/tests/002_1.phpt | 3 +- .../Debug/Resources/ext/tests/003.phpt | 2 +- .../Compiler/ExtensionCompilerPass.php | 2 +- .../Tests/ContainerBuilderTest.php | 11 +++-- .../Tests/Fixtures/includes/createphar.php | 4 +- src/Symfony/Component/DomCrawler/Crawler.php | 2 +- .../Component/DomCrawler/Tests/FormTest.php | 3 +- .../Debug/TraceableEventDispatcherTest.php | 14 +++---- .../Tests/Node/NodeTest.php | 2 +- .../Tests/Iterator/PathFilterIteratorTest.php | 1 - .../Tests/Iterator/SortableIteratorTest.php | 6 +-- .../Extension/Core/Type/FormTypeTest.php | 2 - .../Component/Form/Tests/SimpleFormTest.php | 26 ++++++------ .../HttpFoundation/Tests/RequestTest.php | 1 - .../DateFormatter/IntlDateFormatterTest.php | 4 +- .../Tests/Encoder/XmlEncoderTest.php | 6 +-- .../Tests/Normalizer/ObjectNormalizerTest.php | 28 ++++++------- .../Translation/Dumper/IcuResFileDumper.php | 2 +- .../Component/Translation/Translator.php | 6 +-- .../Validator/ConstraintValidator.php | 2 +- .../Validator/Constraints/IsbnValidator.php | 14 +++---- .../Validator/Constraints/IssnValidator.php | 14 +++---- .../Validator/Constraints/LuhnValidator.php | 4 +- .../Validator/Constraints/UuidValidator.php | 20 +++++----- .../Constraints/CallbackValidatorTest.php | 6 --- .../Component/Validator/Util/PropertyPath.php | 2 +- .../RecursiveContextualValidator.php | 1 + .../Component/VarDumper/Dumper/CliDumper.php | 2 +- .../Component/VarDumper/Dumper/HtmlDumper.php | 2 +- .../VarDumper/Tests/CliDumperTest.php | 12 +++--- .../VarDumper/Tests/HtmlDumperTest.php | 2 +- .../Component/Yaml/Tests/ParserTest.php | 30 +++++++------- src/Symfony/Component/Yaml/Unescaper.php | 2 +- 68 files changed, 185 insertions(+), 200 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php index 324611fba1ced..2dd139750c7bd 100644 --- a/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php +++ b/src/Symfony/Bridge/Doctrine/Form/Type/DoctrineType.php @@ -138,7 +138,6 @@ public function configureOptions(OptionsResolver $resolver) $type = $this; $choiceLoader = function (Options $options) use ($choiceListFactory, &$choiceLoaders, $type) { - // Unless the choices are given explicitly, load them on demand if (null === $options['choices']) { $hash = null; diff --git a/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/DoctrineExtensionTest.php b/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/DoctrineExtensionTest.php index 760c0fada0fab..f917f73eaa15b 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/DoctrineExtensionTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/DependencyInjection/DoctrineExtensionTest.php @@ -44,7 +44,7 @@ protected function setUp() $this->extension->expects($this->any()) ->method('getObjectManagerElementName') ->will($this->returnCallback(function ($name) { - return 'doctrine.orm.'.$name; + return 'doctrine.orm.'.$name; })); } diff --git a/src/Symfony/Bridge/Twig/Command/DebugCommand.php b/src/Symfony/Bridge/Twig/Command/DebugCommand.php index 898e0e2233bb6..39b910d6b4f61 100644 --- a/src/Symfony/Bridge/Twig/Command/DebugCommand.php +++ b/src/Symfony/Bridge/Twig/Command/DebugCommand.php @@ -60,7 +60,7 @@ protected function configure() new InputOption('format', null, InputOption::VALUE_REQUIRED, 'The output format (text or json)', 'text'), )) ->setDescription('Shows a list of twig functions, filters, globals and tests') - ->setHelp(<<setHelp(<<<'EOF' The %command.name% command outputs a list of twig functions, filters, globals and tests. Output can be filtered with an optional argument. diff --git a/src/Symfony/Bridge/Twig/Command/LintCommand.php b/src/Symfony/Bridge/Twig/Command/LintCommand.php index df603f93fddda..e2880f9e4b67d 100644 --- a/src/Symfony/Bridge/Twig/Command/LintCommand.php +++ b/src/Symfony/Bridge/Twig/Command/LintCommand.php @@ -61,7 +61,7 @@ protected function configure() ->setDescription('Lints a template and outputs encountered errors') ->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt') ->addArgument('filename', InputArgument::IS_ARRAY) - ->setHelp(<<setHelp(<<<'EOF' The %command.name% command lints a template and outputs to STDOUT the first encountered syntax error. diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php index 20deffcc3339f..9059905e04f54 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ConfigDebugCommand.php @@ -39,7 +39,7 @@ protected function configure() new InputArgument('name', InputArgument::OPTIONAL, 'The bundle name or the extension alias'), )) ->setDescription('Dumps the current configuration for an extension') - ->setHelp(<<setHelp(<<<'EOF' The %command.name% command dumps the current configuration for an extension/bundle. diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/EventDispatcherDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/EventDispatcherDebugCommand.php index f30b59cf62ac8..f9bc810d0fa27 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/EventDispatcherDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/EventDispatcherDebugCommand.php @@ -38,7 +38,7 @@ protected function configure() new InputOption('raw', null, InputOption::VALUE_NONE, 'To output raw description'), )) ->setDescription('Displays configured listeners for an application') - ->setHelp(<<setHelp(<<<'EOF' The %command.name% command displays all configured listeners: php %command.full_name% diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ServerStartCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ServerStartCommand.php index 04906317fa944..2c45de91680f9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ServerStartCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ServerStartCommand.php @@ -39,7 +39,7 @@ protected function configure() )) ->setName('server:start') ->setDescription('Starts PHP built-in web server in the background') - ->setHelp(<<setHelp(<<<'EOF' The %command.name% runs PHP's built-in web server: php %command.full_name% diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/ServerStopCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/ServerStopCommand.php index 9b0656c220b66..84ed54c41e7a6 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/ServerStopCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/ServerStopCommand.php @@ -33,7 +33,7 @@ protected function configure() )) ->setName('server:stop') ->setDescription('Stops PHP\'s built-in web server that was started with the server:start command') - ->setHelp(<<setHelp(<<<'EOF' The %command.name% stops PHP's built-in web server: php %command.full_name% diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php index 30d44493d4c4b..64beda52656b3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php @@ -50,7 +50,7 @@ protected function configure() new InputOption('only-unused', null, InputOption::VALUE_NONE, 'Displays only unused messages'), )) ->setDescription('Displays translation messages information') - ->setHelp(<<setHelp(<<<'EOF' The %command.name% command helps finding unused or missing translation messages and comparing them with the fallback ones by inspecting the templates and translation files of a given bundle or the app folder. diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/YamlLintCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/YamlLintCommand.php index b41f5f3479ebe..ca39257462dd3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/YamlLintCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/YamlLintCommand.php @@ -34,7 +34,7 @@ protected function configure() ->setDescription('Lints a file and outputs encountered errors') ->addArgument('filename', null, 'A file or a directory or STDIN') ->addOption('format', null, InputOption::VALUE_REQUIRED, 'The output format', 'txt') - ->setHelp(<<setHelp(<<<'EOF' The %command.name% command lints a YAML file and outputs to STDOUT the first encountered syntax error. diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/number_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/number_widget.html.php index 324eb4782c2cc..bf4a4c478502b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/number_widget.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/number_widget.html.php @@ -1 +1 @@ -block($form, 'form_widget_simple', array('type' => isset($type) ? $type : 'text')) ?> +block($form, 'form_widget_simple', array('type' => isset($type) ? $type : 'text')) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/password_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/password_widget.html.php index 4390687a69330..ec96cfb46b24c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/password_widget.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/password_widget.html.php @@ -1 +1 @@ -block($form, 'form_widget_simple', array('type' => isset($type) ? $type : 'password')) ?> +block($form, 'form_widget_simple', array('type' => isset($type) ? $type : 'password')) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_widget.html.php index 59b29f4cbcfaa..8519da429b188 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_widget.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/percent_widget.html.php @@ -1 +1 @@ -block($form, 'form_widget_simple', array('type' => isset($type) ? $type : 'text')) ?> % +block($form, 'form_widget_simple', array('type' => isset($type) ? $type : 'text')) ?> % diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/reset_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/reset_widget.html.php index 1575e8292801e..e8fa18e488df8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/reset_widget.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/reset_widget.html.php @@ -1 +1 @@ -block($form, 'button_widget', array('type' => isset($type) ? $type : 'reset')) ?> +block($form, 'button_widget', array('type' => isset($type) ? $type : 'reset')) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/search_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/search_widget.html.php index 4e442f6ef47ae..48a33f4aa2dbc 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/search_widget.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/search_widget.html.php @@ -1 +1 @@ -block($form, 'form_widget_simple', array('type' => isset($type) ? $type : 'search')) ?> +block($form, 'form_widget_simple', array('type' => isset($type) ? $type : 'search')) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/submit_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/submit_widget.html.php index d42bb2a78ffe9..6bf71f5a1e1c9 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/submit_widget.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/submit_widget.html.php @@ -1 +1 @@ -block($form, 'button_widget', array('type' => isset($type) ? $type : 'submit')) ?> +block($form, 'button_widget', array('type' => isset($type) ? $type : 'submit')) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/url_widget.html.php b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/url_widget.html.php index 0ce4ed2ca79fd..9e26318497b3c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/url_widget.html.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/views/Form/url_widget.html.php @@ -1 +1 @@ -block($form, 'form_widget_simple', array('type' => isset($type) ? $type : 'url')) ?> +block($form, 'form_widget_simple', array('type' => isset($type) ? $type : 'url')) ?> diff --git a/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php b/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php index c0b68a2d17a46..4ef5f0a4bd1c4 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php +++ b/src/Symfony/Bundle/FrameworkBundle/Routing/Router.php @@ -164,7 +164,6 @@ private function resolve($value) gettype($resolved) ) ); - }, $value); return str_replace('%%', '%', $escapedValue); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/RouterMatchCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/RouterMatchCommandTest.php index 93c2468dc15ae..fc7e2155537fe 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/RouterMatchCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/RouterMatchCommandTest.php @@ -88,7 +88,6 @@ private function getContainer() ->will($this->returnValueMap(array( array('router', 1, $router), array('controller_name_converter', 1, $loader), - ))); return $container; diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationDebugCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationDebugCommandTest.php index c99c0ace2ac77..27f61c4383f24 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationDebugCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationDebugCommandTest.php @@ -136,7 +136,7 @@ private function getContainer($extractedMessages = array(), $loadedMessages = ar ->method('extract') ->will( $this->returnCallback(function ($path, $catalogue) use ($extractedMessages) { - $catalogue->add($extractedMessages); + $catalogue->add($extractedMessages); }) ); @@ -146,7 +146,7 @@ private function getContainer($extractedMessages = array(), $loadedMessages = ar ->method('loadMessages') ->will( $this->returnCallback(function ($path, $catalogue) use ($loadedMessages) { - $catalogue->add($loadedMessages); + $catalogue->add($loadedMessages); }) ); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php index a04a0cccad77c..24a4f625f6db5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Command/TranslationUpdateCommandTest.php @@ -74,7 +74,7 @@ private function getContainer($extractedMessages = array(), $loadedMessages = ar ->method('extract') ->will( $this->returnCallback(function ($path, $catalogue) use ($extractedMessages) { - $catalogue->add($extractedMessages); + $catalogue->add($extractedMessages); }) ); @@ -84,7 +84,7 @@ private function getContainer($extractedMessages = array(), $loadedMessages = ar ->method('loadMessages') ->will( $this->returnCallback(function ($path, $catalogue) use ($loadedMessages) { - $catalogue->add($loadedMessages); + $catalogue->add($loadedMessages); }) ); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php index 192ba44bf737c..46249c8e7c153 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/AbstractDescriptorTest.php @@ -141,6 +141,7 @@ public function getDescribeCallableTestData() } abstract protected function getDescriptor(); + abstract protected function getFormat(); private function assertDescription($expectedDescription, $describedObject, array $options = array()) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php index 52a6665416923..d6fc8b24ad264 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Console/Descriptor/ObjectsProvider.php @@ -191,9 +191,11 @@ class CallableClass public function __invoke() { } + public static function staticMethod() { } + public function method() { } 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 04df261863f48..c0ae6ec5c6604 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 @@ -1,7 +1,7 @@ This template is used for translation message extraction tests trans('single-quoted key') ?> trans('double-quoted key') ?> -trans(<<trans(<<<'EOF' heredoc key EOF ) ?> diff --git a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php index bd81d4927142b..092c627fa9862 100644 --- a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php +++ b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php @@ -81,7 +81,7 @@ public function collect(Request $request, Response $response, \Exception $except 'authenticated' => $token->isAuthenticated(), 'token_class' => get_class($token), 'user' => $token->getUsername(), - 'roles' => array_map(function (RoleInterface $role) { return $role->getRole();}, $assignedRoles), + 'roles' => array_map(function (RoleInterface $role) { return $role->getRole(); }, $assignedRoles), 'inherited_roles' => array_map(function (RoleInterface $role) { return $role->getRole(); }, $inheritedRoles), 'supports_role_hierarchy' => null !== $this->roleHierarchy, ); diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SecurityFactoryInterface.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SecurityFactoryInterface.php index 2b3310c61aae4..028e885246f61 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SecurityFactoryInterface.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/Security/Factory/SecurityFactoryInterface.php @@ -25,7 +25,7 @@ interface SecurityFactoryInterface * Configures the container services required to use the authentication listener. * * @param ContainerBuilder $container - * @param string $id The unique id of the firewall + * @param string $id The unique id of the firewall * @param array $config The options array for the listener * @param string $userProvider The service id of the user provider * @param string $defaultEntryPoint @@ -48,7 +48,7 @@ public function getPosition(); /** * Defines the configuration key used to reference the provider * in the firewall configuration. - * + * * @return string */ public function getKey(); diff --git a/src/Symfony/Bundle/TwigBundle/Tests/Controller/PreviewErrorControllerTest.php b/src/Symfony/Bundle/TwigBundle/Tests/Controller/PreviewErrorControllerTest.php index 7bef647a7e283..e4a47a07694b5 100644 --- a/src/Symfony/Bundle/TwigBundle/Tests/Controller/PreviewErrorControllerTest.php +++ b/src/Symfony/Bundle/TwigBundle/Tests/Controller/PreviewErrorControllerTest.php @@ -34,7 +34,6 @@ public function testForwardRequestToConfiguredController() ->method('handle') ->with( $this->callback(function (Request $request) use ($self, $logicalControllerName, $code) { - $self->assertEquals($logicalControllerName, $request->attributes->get('_controller')); $exception = $request->attributes->get('exception'); diff --git a/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php b/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php index ff043f1862382..42207b0399e37 100644 --- a/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/Dumper/XmlReferenceDumperTest.php @@ -34,7 +34,7 @@ public function testNamespaceDumper() private function getConfigurationAsString() { - return str_replace("\n", PHP_EOL, << diff --git a/src/Symfony/Component/Console/Tests/Helper/LegacyTableHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/LegacyTableHelperTest.php index cf9ad13a78080..4875f79285f36 100644 --- a/src/Symfony/Component/Console/Tests/Helper/LegacyTableHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/LegacyTableHelperTest.php @@ -112,7 +112,7 @@ public function testRenderProvider() array('ISBN', 'Title', 'Author'), $books, TableHelper::LAYOUT_COMPACT, -<<42';" OUT 42 RES Command ran successfully EOT; - $successOutputProcessDebug = <<getOutputStream()); @@ -588,7 +586,6 @@ public function testAnsiColorsAndEmojis() rewind($output->getStream()); $this->assertEquals( - " \033[44;37m Starting the demo... fingers crossed \033[0m\n". ' 0/15 '.$progress.str_repeat($empty, 26)." 0%\n". " \xf0\x9f\x8f\x81 < 1 sec \033[44;37m 0 B \033[0m" diff --git a/src/Symfony/Component/Console/Tests/Helper/TableTest.php b/src/Symfony/Component/Console/Tests/Helper/TableTest.php index 9628bc36faaee..a691405c6b30f 100644 --- a/src/Symfony/Component/Console/Tests/Helper/TableTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/TableTest.php @@ -96,7 +96,7 @@ public function testRenderProvider() array('ISBN', 'Title', 'Author'), $books, 'default', -<<
Charles Dickens'), ), 'default', -<<
render(); $expected = -<<
render(); $expected = -<<
render(); $expected = -<<
position += $length; } - /** - */ public function moveToEnd() { $this->position = $this->length; diff --git a/src/Symfony/Component/Debug/Resources/ext/tests/001.phpt b/src/Symfony/Component/Debug/Resources/ext/tests/001.phpt index 4d41417b436e3..15e183a70615c 100644 --- a/src/Symfony/Component/Debug/Resources/ext/tests/001.phpt +++ b/src/Symfony/Component/Debug/Resources/ext/tests/001.phpt @@ -1,14 +1,14 @@ --TEST-- Test symfony_zval_info API --SKIPIF-- - + --FILE-- $int, - 'float' => $float, - 'str' => $str, - 'object' => $object, - 'array' => $array, - 'resource' => $resource, - 'null' => $null, - 'bool' => $bool, - 'refcount' => &$refcount2); +$var = array( + 'int' => $int, + 'float' => $float, + 'str' => $str, + 'object' => $object, + 'array' => $array, + 'resource' => $resource, + 'null' => $null, + 'bool' => $bool, + 'refcount' => &$refcount2, +); var_dump(symfony_zval_info('int', $var)); var_dump(symfony_zval_info('float', $var)); diff --git a/src/Symfony/Component/Debug/Resources/ext/tests/002.phpt b/src/Symfony/Component/Debug/Resources/ext/tests/002.phpt index ebe2f32d8f303..2bc6d71274d82 100644 --- a/src/Symfony/Component/Debug/Resources/ext/tests/002.phpt +++ b/src/Symfony/Component/Debug/Resources/ext/tests/002.phpt @@ -1,7 +1,7 @@ --TEST-- Test symfony_debug_backtrace in case of fatal error --SKIPIF-- - + --FILE-- + --FILE-- + --FILE-- diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index 6b49b1e34fb85..eab8fccbdfcaa 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -756,12 +756,11 @@ public function testLazyLoadedService() { $loader = new ClosureLoader($container = new ContainerBuilder()); $loader->load(function (ContainerBuilder $container) { - $container->set('a', new \BazClass()); - $definition = new Definition('BazClass'); - $definition->setLazy(true); - $container->setDefinition('a', $definition); - } - ); + $container->set('a', new \BazClass()); + $definition = new Definition('BazClass'); + $definition->setLazy(true); + $container->setDefinition('a', $definition); + }); $container->setResourceTracking(true); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/createphar.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/createphar.php index 5fa06a0eb50e6..c675478fd639c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/createphar.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/createphar.php @@ -6,7 +6,7 @@ } $phar = new Phar($file, 0, 'ProjectWithXsdExtensionInPhar.phar'); -$phar->addFromString('ProjectWithXsdExtensionInPhar.php', <<addFromString('ProjectWithXsdExtensionInPhar.php', <<<'EOT' addFromString('schema/project-1.0.xsd', <<addFromString('schema/project-1.0.xsd', <<<'EOT' createForm('
'.$form.''); $this->assertEquals( $values, - array_map(function ($field) { + array_map( + function ($field) { $class = get_class($field); return array(substr($class, strrpos($class, '\\') + 1), $field->getValue()); diff --git a/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php index 4aa6226e49297..9717099bf9dd6 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php @@ -25,7 +25,7 @@ public function testAddRemoveListener() $dispatcher = new EventDispatcher(); $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); - $tdispatcher->addListener('foo', $listener = function () {; }); + $tdispatcher->addListener('foo', $listener = function () { }); $listeners = $dispatcher->getListeners('foo'); $this->assertCount(1, $listeners); $this->assertSame($listener, $listeners[0]); @@ -39,7 +39,7 @@ public function testGetListeners() $dispatcher = new EventDispatcher(); $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); - $tdispatcher->addListener('foo', $listener = function () {; }); + $tdispatcher->addListener('foo', $listener = function () { }); $this->assertSame($dispatcher->getListeners('foo'), $tdispatcher->getListeners('foo')); } @@ -51,7 +51,7 @@ public function testHasListeners() $this->assertFalse($dispatcher->hasListeners('foo')); $this->assertFalse($tdispatcher->hasListeners('foo')); - $tdispatcher->addListener('foo', $listener = function () {; }); + $tdispatcher->addListener('foo', $listener = function () { }); $this->assertTrue($dispatcher->hasListeners('foo')); $this->assertTrue($tdispatcher->hasListeners('foo')); } @@ -76,7 +76,7 @@ public function testGetCalledListeners() { $dispatcher = new EventDispatcher(); $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); - $tdispatcher->addListener('foo', $listener = function () {; }); + $tdispatcher->addListener('foo', $listener = function () { }); $this->assertEquals(array(), $tdispatcher->getCalledListeners()); $this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure')), $tdispatcher->getNotCalledListeners()); @@ -107,8 +107,8 @@ public function testLogger() $dispatcher = new EventDispatcher(); $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger); - $tdispatcher->addListener('foo', $listener1 = function () {; }); - $tdispatcher->addListener('foo', $listener2 = function () {; }); + $tdispatcher->addListener('foo', $listener1 = function () { }); + $tdispatcher->addListener('foo', $listener2 = function () { }); $logger->expects($this->at(0))->method('debug')->with('Notified event "foo" to listener "closure".'); $logger->expects($this->at(1))->method('debug')->with('Notified event "foo" to listener "closure".'); @@ -123,7 +123,7 @@ public function testLoggerWithStoppedEvent() $dispatcher = new EventDispatcher(); $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger); $tdispatcher->addListener('foo', $listener1 = function (Event $event) { $event->stopPropagation(); }); - $tdispatcher->addListener('foo', $listener2 = function () {; }); + $tdispatcher->addListener('foo', $listener2 = function () { }); $logger->expects($this->at(0))->method('debug')->with('Notified event "foo" to listener "closure".'); $logger->expects($this->at(1))->method('debug')->with('Listener "closure" stopped propagation of the event "foo".'); diff --git a/src/Symfony/Component/ExpressionLanguage/Tests/Node/NodeTest.php b/src/Symfony/Component/ExpressionLanguage/Tests/Node/NodeTest.php index 6063c27ba4809..6901329a5e711 100644 --- a/src/Symfony/Component/ExpressionLanguage/Tests/Node/NodeTest.php +++ b/src/Symfony/Component/ExpressionLanguage/Tests/Node/NodeTest.php @@ -20,7 +20,7 @@ public function testToString() { $node = new Node(array(new ConstantNode('foo'))); - $this->assertEquals(<<assertEquals(<<<'EOF' Node( ConstantNode(value: 'foo') ) diff --git a/src/Symfony/Component/Finder/Tests/Iterator/PathFilterIteratorTest.php b/src/Symfony/Component/Finder/Tests/Iterator/PathFilterIteratorTest.php index 579beed2ed444..6e10550c06e44 100644 --- a/src/Symfony/Component/Finder/Tests/Iterator/PathFilterIteratorTest.php +++ b/src/Symfony/Component/Finder/Tests/Iterator/PathFilterIteratorTest.php @@ -77,7 +77,6 @@ public function getTestFilterData() array($inner, array('copy/A'), array(), array('abc.dat.copy', 'ab.dat.copy', 'a.dat.copy')), array($inner, array('copy/A/B'), array(), array('abc.dat.copy', 'ab.dat.copy')), array($inner, array('copy/A/B/C'), array(), array('abc.dat.copy')), - ); } } diff --git a/src/Symfony/Component/Finder/Tests/Iterator/SortableIteratorTest.php b/src/Symfony/Component/Finder/Tests/Iterator/SortableIteratorTest.php index 6a3124d352a90..4750f250d736c 100644 --- a/src/Symfony/Component/Finder/Tests/Iterator/SortableIteratorTest.php +++ b/src/Symfony/Component/Finder/Tests/Iterator/SortableIteratorTest.php @@ -32,7 +32,7 @@ public function testAccept($mode, $expected) { if (!is_callable($mode)) { switch ($mode) { - case SortableIterator::SORT_BY_ACCESSED_TIME : + case SortableIterator::SORT_BY_ACCESSED_TIME: if ('\\' === DIRECTORY_SEPARATOR) { touch(self::toAbsolute('.git')); } else { @@ -41,12 +41,12 @@ public function testAccept($mode, $expected) sleep(1); file_get_contents(self::toAbsolute('.bar')); break; - case SortableIterator::SORT_BY_CHANGED_TIME : + case SortableIterator::SORT_BY_CHANGED_TIME: file_put_contents(self::toAbsolute('test.php'), 'foo'); sleep(1); file_put_contents(self::toAbsolute('test.py'), 'foo'); break; - case SortableIterator::SORT_BY_MODIFIED_TIME : + case SortableIterator::SORT_BY_MODIFIED_TIME: file_put_contents(self::toAbsolute('test.php'), 'foo'); sleep(1); file_put_contents(self::toAbsolute('test.py'), 'foo'); diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php index 2b4b255b0daab..d00b8d4233506 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FormTypeTest.php @@ -436,7 +436,6 @@ public function testSubformCallsSettersIfReferenceIsScalar() $builder->get('referenceCopy')->addViewTransformer(new CallbackTransformer( function () {}, function ($value) { // reverseTransform - return 'foobar'; } )); @@ -462,7 +461,6 @@ public function testSubformAlwaysInsertsIntoArrays() $builder->get('referenceCopy')->addViewTransformer(new CallbackTransformer( function () {}, function ($value) use ($ref2) { // reverseTransform - return $ref2; } )); diff --git a/src/Symfony/Component/Form/Tests/SimpleFormTest.php b/src/Symfony/Component/Form/Tests/SimpleFormTest.php index ae174f045d773..8774ad0468e4d 100644 --- a/src/Symfony/Component/Form/Tests/SimpleFormTest.php +++ b/src/Symfony/Component/Form/Tests/SimpleFormTest.php @@ -641,10 +641,10 @@ public function testEmptyDataCreatedBeforeTransforming() $form = $this->getBuilder() ->setEmptyData('foo') ->addViewTransformer(new FixedDataTransformer(array( - '' => '', - // direction is reversed! - 'bar' => 'foo', - ))) + '' => '', + // direction is reversed! + 'bar' => 'foo', + ))) ->getForm(); $form->submit(''); @@ -657,17 +657,17 @@ public function testEmptyDataFromClosure() $test = $this; $form = $this->getBuilder() ->setEmptyData(function ($form) use ($test) { - // the form instance is passed to the closure to allow use - // of form data when creating the empty value - $test->assertInstanceOf('Symfony\Component\Form\FormInterface', $form); + // the form instance is passed to the closure to allow use + // of form data when creating the empty value + $test->assertInstanceOf('Symfony\Component\Form\FormInterface', $form); - return 'foo'; - }) + return 'foo'; + }) ->addViewTransformer(new FixedDataTransformer(array( - '' => '', - // direction is reversed! - 'bar' => 'foo', - ))) + '' => '', + // direction is reversed! + 'bar' => 'foo', + ))) ->getForm(); $form->submit(''); diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index 0c54c16b29cfc..2fa72d9aacfed 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -1090,7 +1090,6 @@ public function provideOverloadedMethods() array('put'), array('delete'), array('patch'), - ); } diff --git a/src/Symfony/Component/Intl/Tests/DateFormatter/IntlDateFormatterTest.php b/src/Symfony/Component/Intl/Tests/DateFormatter/IntlDateFormatterTest.php index fde3bcde558de..1a2c35ffb7513 100644 --- a/src/Symfony/Component/Intl/Tests/DateFormatter/IntlDateFormatterTest.php +++ b/src/Symfony/Component/Intl/Tests/DateFormatter/IntlDateFormatterTest.php @@ -222,7 +222,7 @@ protected function isIntlFailure($errorCode) private function notImplemented(array $dataSets) { return array_map(function ($row) { - return array($row[0], $row[1], 0); - }, $dataSets); + return array($row[0], $row[1], 0); + }, $dataSets); } } diff --git a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php index 5742b0c70acc7..256ed2fc90f9c 100644 --- a/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php +++ b/src/Symfony/Component/Serializer/Tests/Encoder/XmlEncoderTest.php @@ -141,7 +141,7 @@ public function testEncodeXmlAttributes() public function testContext() { $array = array('person' => array('name' => 'George Abitbol')); - $expected = << @@ -255,7 +255,7 @@ public function testEncodeTraversableWhenNormalizable() $serializer = new Serializer(array(new CustomNormalizer()), array('xml' => new XmlEncoder())); $this->encoder->setSerializer($serializer); - $expected = << normalizedFoonormalizedBar @@ -366,7 +366,7 @@ public function testDecodeArray() public function testDecodeIgnoreWhiteSpace() { - $source = << diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php index 398a579b9fa75..e3780e55c0bf4 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/ObjectNormalizerTest.php @@ -343,8 +343,8 @@ public function provideCallbacks() array( array( 'bar' => function ($bar) { - return 'baz'; - }, + return 'baz'; + }, ), 'baz', array('foo' => '', 'bar' => 'baz', 'baz' => true), @@ -353,8 +353,8 @@ public function provideCallbacks() array( array( 'bar' => function ($bar) { - return; - }, + return; + }, ), 'baz', array('foo' => '', 'bar' => null, 'baz' => true), @@ -363,8 +363,8 @@ public function provideCallbacks() array( array( 'bar' => function ($bar) { - return $bar->format('d-m-Y H:i:s'); - }, + return $bar->format('d-m-Y H:i:s'); + }, ), new \DateTime('2011-09-10 06:30:00'), array('foo' => '', 'bar' => '10-09-2011 06:30:00', 'baz' => true), @@ -373,13 +373,13 @@ public function provideCallbacks() array( array( 'bar' => function ($bars) { - $foos = ''; - foreach ($bars as $bar) { - $foos .= $bar->getFoo(); - } + $foos = ''; + foreach ($bars as $bar) { + $foos .= $bar->getFoo(); + } - return $foos; - }, + return $foos; + }, ), array(new ObjectConstructorDummy('baz', '', false), new ObjectConstructorDummy('quux', '', false)), array('foo' => '', 'bar' => 'bazquux', 'baz' => true), @@ -388,8 +388,8 @@ public function provideCallbacks() array( array( 'bar' => function ($bars) { - return count($bars); - }, + return count($bars); + }, ), array(new ObjectConstructorDummy('baz', '', false), new ObjectConstructorDummy('quux', '', false)), array('foo' => '', 'bar' => 2, 'baz' => true), diff --git a/src/Symfony/Component/Translation/Dumper/IcuResFileDumper.php b/src/Symfony/Component/Translation/Dumper/IcuResFileDumper.php index 126e9b7e8ac64..0fd5b35ae333b 100644 --- a/src/Symfony/Component/Translation/Dumper/IcuResFileDumper.php +++ b/src/Symfony/Component/Translation/Dumper/IcuResFileDumper.php @@ -34,7 +34,7 @@ public function format(MessageCatalogue $messages, $domain = 'messages') foreach ($messages->all($domain) as $source => $target) { $indexes .= pack('v', strlen($data) + 28); - $data .= $source."\0"; + $data .= $source."\0"; } $data .= $this->writePadding($data); diff --git a/src/Symfony/Component/Translation/Translator.php b/src/Symfony/Component/Translation/Translator.php index 1369e9783bd68..48a801d375446 100644 --- a/src/Symfony/Component/Translation/Translator.php +++ b/src/Symfony/Component/Translation/Translator.php @@ -376,9 +376,9 @@ private function getFallbackContent(MessageCatalogue $catalogue) $fallbackSuffix = ucfirst(preg_replace($replacementPattern, '_', $fallback)); $currentSuffix = ucfirst(preg_replace($replacementPattern, '_', $current)); - $fallbackContent .= sprintf(<<addFallbackCatalogue(\$catalogue%s); + $fallbackContent .= sprintf(<<<'EOF' +$catalogue%s = new MessageCatalogue('%s', %s); +$catalogue%s->addFallbackCatalogue($catalogue%s); EOF , diff --git a/src/Symfony/Component/Validator/ConstraintValidator.php b/src/Symfony/Component/Validator/ConstraintValidator.php index c0db7e29eff5c..b156c6dde9a16 100644 --- a/src/Symfony/Component/Validator/ConstraintValidator.php +++ b/src/Symfony/Component/Validator/ConstraintValidator.php @@ -119,7 +119,7 @@ protected function formatTypeOf($value) * (i.e. "false" for false, "1" for 1 etc.). Strings are always wrapped * in double quotes ("). Objects, arrays and resources are formatted as * "object", "array" and "resource". If the $format bitmask contains - * the PRETTY_DATE bit, then {@link \DateTime} objects will be formatted + * the PRETTY_DATE bit, then {@link \DateTime} objects will be formatted * as RFC-3339 dates ("Y-m-d H:i:s"). * * Be careful when passing message parameters to a constraint violation diff --git a/src/Symfony/Component/Validator/Constraints/IsbnValidator.php b/src/Symfony/Component/Validator/Constraints/IsbnValidator.php index aaf52dc561c3c..6ca8488a5c725 100644 --- a/src/Symfony/Component/Validator/Constraints/IsbnValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IsbnValidator.php @@ -144,14 +144,14 @@ protected function validateIsbn10($isbn) // If we test the length before the loop, we get an ERROR_TOO_SHORT // when actually an ERROR_INVALID_CHARACTERS is wanted, e.g. for // "0-45122_5244" (typo) - if (!isset($isbn{$i})) { + if (!isset($isbn[$i])) { return Isbn::TOO_SHORT_ERROR; } - if ('X' === $isbn{$i}) { + if ('X' === $isbn[$i]) { $digit = 10; - } elseif (ctype_digit($isbn{$i})) { - $digit = $isbn{$i}; + } elseif (ctype_digit($isbn[$i])) { + $digit = $isbn[$i]; } else { return Isbn::INVALID_CHARACTERS_ERROR; } @@ -159,7 +159,7 @@ protected function validateIsbn10($isbn) $checkSum += $digit * (10 - $i); } - if (isset($isbn{$i})) { + if (isset($isbn[$i])) { return Isbn::TOO_LONG_ERROR; } @@ -190,11 +190,11 @@ protected function validateIsbn13($isbn) $checkSum = 0; for ($i = 0; $i < 13; $i += 2) { - $checkSum += $isbn{$i}; + $checkSum += $isbn[$i]; } for ($i = 1; $i < 12; $i += 2) { - $checkSum += $isbn{$i} + $checkSum += $isbn[$i] * 3; } diff --git a/src/Symfony/Component/Validator/Constraints/IssnValidator.php b/src/Symfony/Component/Validator/Constraints/IssnValidator.php index 000af74f282fa..1405acfc7099a 100644 --- a/src/Symfony/Component/Validator/Constraints/IssnValidator.php +++ b/src/Symfony/Component/Validator/Constraints/IssnValidator.php @@ -48,7 +48,7 @@ public function validate($value, Constraint $constraint) // 1234-567X // ^ - if (isset($canonical{4}) && '-' === $canonical{4}) { + if (isset($canonical[4]) && '-' === $canonical[4]) { // remove hyphen $canonical = substr($canonical, 0, 4).substr($canonical, 5); } elseif ($constraint->requireHyphen) { @@ -121,7 +121,7 @@ public function validate($value, Constraint $constraint) // 1234567X // ^ digit, x or X - if (!ctype_digit($canonical{7}) && 'x' !== $canonical{7} && 'X' !== $canonical{7}) { + if (!ctype_digit($canonical[7]) && 'x' !== $canonical[7] && 'X' !== $canonical[7]) { if ($this->context instanceof ExecutionContextInterface) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) @@ -139,7 +139,7 @@ public function validate($value, Constraint $constraint) // 1234567X // ^ case-sensitive? - if ($constraint->caseSensitive && 'x' === $canonical{7}) { + if ($constraint->caseSensitive && 'x' === $canonical[7]) { if ($this->context instanceof ExecutionContextInterface) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) @@ -156,14 +156,14 @@ public function validate($value, Constraint $constraint) } // Calculate a checksum. "X" equals 10. - $checkSum = 'X' === $canonical{7} - || 'x' === $canonical{7} + $checkSum = 'X' === $canonical[7] + || 'x' === $canonical[7] ? 10 - : $canonical{7}; + : $canonical[7]; for ($i = 0; $i < 7; ++$i) { // Multiply the first digit by 8, the second by 7, etc. - $checkSum += (8 - $i) * $canonical{$i}; + $checkSum += (8 - $i) * $canonical[$i]; } if (0 !== $checkSum % 11) { diff --git a/src/Symfony/Component/Validator/Constraints/LuhnValidator.php b/src/Symfony/Component/Validator/Constraints/LuhnValidator.php index 31d4497d6e3a4..e971ab153db5a 100644 --- a/src/Symfony/Component/Validator/Constraints/LuhnValidator.php +++ b/src/Symfony/Component/Validator/Constraints/LuhnValidator.php @@ -81,7 +81,7 @@ public function validate($value, Constraint $constraint) // ^ ^ ^ ^ ^ ^ // = 7 + 9 + 7 + 9 + 7 + 3 for ($i = $length - 1; $i >= 0; $i -= 2) { - $checkSum += $value{$i}; + $checkSum += $value[$i]; } // Starting with the second last digit and walking left, double every @@ -91,7 +91,7 @@ public function validate($value, Constraint $constraint) // ^ ^ ^ ^ ^ // = 1+8 + 4 + 6 + 1+6 + 2 for ($i = $length - 2; $i >= 0; $i -= 2) { - $checkSum += array_sum(str_split($value{$i} * 2)); + $checkSum += array_sum(str_split($value[$i] * 2)); } if (0 === $checkSum || 0 !== $checkSum % 10) { diff --git a/src/Symfony/Component/Validator/Constraints/UuidValidator.php b/src/Symfony/Component/Validator/Constraints/UuidValidator.php index 02ec0b23f59f5..d025a560d28aa 100644 --- a/src/Symfony/Component/Validator/Constraints/UuidValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UuidValidator.php @@ -118,7 +118,7 @@ private function validateLoose($value, Uuid $constraint) for ($i = 0; $i < $l; ++$i) { // Check length - if (!isset($trimmed{$i})) { + if (!isset($trimmed[$i])) { if ($this->context instanceof ExecutionContextInterface) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) @@ -137,7 +137,7 @@ private function validateLoose($value, Uuid $constraint) // Hyphens must occur every fifth position // xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx-xxxx // ^ ^ ^ ^ ^ ^ ^ - if ('-' === $trimmed{$i}) { + if ('-' === $trimmed[$i]) { if ($i !== $h) { if ($this->context instanceof ExecutionContextInterface) { $this->context->buildViolation($constraint->message) @@ -166,7 +166,7 @@ private function validateLoose($value, Uuid $constraint) } // Check characters - if (!ctype_xdigit($trimmed{$i})) { + if (!ctype_xdigit($trimmed[$i])) { if ($this->context instanceof ExecutionContextInterface) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) @@ -184,7 +184,7 @@ private function validateLoose($value, Uuid $constraint) } // Check length again - if (isset($trimmed{$i})) { + if (isset($trimmed[$i])) { if ($this->context instanceof ExecutionContextInterface) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) @@ -213,7 +213,7 @@ private function validateStrict($value, Uuid $constraint) for ($i = 0; $i < self::STRICT_LENGTH; ++$i) { // Check length - if (!isset($value{$i})) { + if (!isset($value[$i])) { if ($this->context instanceof ExecutionContextInterface) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) @@ -232,7 +232,7 @@ private function validateStrict($value, Uuid $constraint) // Check hyphen placement // xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx // ^ ^ ^ ^ - if ('-' === $value{$i}) { + if ('-' === $value[$i]) { if ($i !== $h) { if ($this->context instanceof ExecutionContextInterface) { $this->context->buildViolation($constraint->message) @@ -259,7 +259,7 @@ private function validateStrict($value, Uuid $constraint) } // Check characters - if (!ctype_xdigit($value{$i})) { + if (!ctype_xdigit($value[$i])) { if ($this->context instanceof ExecutionContextInterface) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) @@ -294,7 +294,7 @@ private function validateStrict($value, Uuid $constraint) } // Check length again - if (isset($value{$i})) { + if (isset($value[$i])) { if ($this->context instanceof ExecutionContextInterface) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) @@ -309,7 +309,7 @@ private function validateStrict($value, Uuid $constraint) } // Check version - if (!in_array($value{self::STRICT_VERSION_POSITION}, $constraint->versions)) { + if (!in_array($value[self::STRICT_VERSION_POSITION], $constraint->versions)) { if ($this->context instanceof ExecutionContextInterface) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) @@ -327,7 +327,7 @@ private function validateStrict($value, Uuid $constraint) // 0b10xx // & 0b1100 (12) // = 0b1000 (8) - if ((hexdec($value{self::STRICT_VARIANT_POSITION}) & 12) !== 8) { + if ((hexdec($value[self::STRICT_VARIANT_POSITION]) & 12) !== 8) { if ($this->context instanceof ExecutionContextInterface) { $this->context->buildViolation($constraint->message) ->setParameter('{{ value }}', $this->formatValue($value)) diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CallbackValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CallbackValidatorTest.php index 5ad8276563344..6bd7735f0d7d5 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CallbackValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CallbackValidatorTest.php @@ -185,7 +185,6 @@ public function testArrayCallableExplicitName() ->assertRaised(); } - // BC with Symfony < 2.4 /** * @group legacy */ @@ -201,7 +200,6 @@ public function testLegacySingleMethodBc() ->assertRaised(); } - // BC with Symfony < 2.4 /** * @group legacy */ @@ -217,7 +215,6 @@ public function testLegacySingleMethodBcExplicitName() ->assertRaised(); } - // BC with Symfony < 2.4 /** * @group legacy */ @@ -235,7 +232,6 @@ public function testLegacyMultipleMethodsBc() ->assertRaised(); } - // BC with Symfony < 2.4 /** * @group legacy */ @@ -255,7 +251,6 @@ public function testLegacyMultipleMethodsBcExplicitName() ->assertRaised(); } - // BC with Symfony < 2.4 /** * @group legacy */ @@ -273,7 +268,6 @@ public function testLegacySingleStaticMethodBc() ->assertRaised(); } - // BC with Symfony < 2.4 /** * @group legacy */ diff --git a/src/Symfony/Component/Validator/Util/PropertyPath.php b/src/Symfony/Component/Validator/Util/PropertyPath.php index 52546c5ea9df0..4108a02c24f25 100644 --- a/src/Symfony/Component/Validator/Util/PropertyPath.php +++ b/src/Symfony/Component/Validator/Util/PropertyPath.php @@ -37,7 +37,7 @@ class PropertyPath public static function append($basePath, $subPath) { if ('' !== (string) $subPath) { - if ('[' === $subPath{0}) { + if ('[' === $subPath[0]) { return $basePath.$subPath; } diff --git a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php index ebbc6a38837c9..6bcf44cb538b0 100644 --- a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php +++ b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php @@ -314,6 +314,7 @@ protected function normalizeGroups($groups) return array($groups); } + /** * Validates an object against the constraints defined for its class. * diff --git a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php index a529cd4dfb26e..59ba119e42914 100644 --- a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php @@ -59,7 +59,7 @@ public function __construct($output = null, $charset = null) parent::__construct($output, $charset); if ('\\' === DIRECTORY_SEPARATOR && 'ON' !== @getenv('ConEmuANSI') && 'xterm' !== @getenv('TERM')) { - // Use only the base 16 xterm colors when using ANSICON or standard Windows 10 CLI + // Use only the base 16 xterm colors when using ANSICON or standard Windows 10 CLI $this->setStyles(array( 'default' => '31', 'num' => '1;34', diff --git a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php index bd69f2eddf371..4f572caea3f8c 100644 --- a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php @@ -441,7 +441,7 @@ function ($m) { if (0xF0 <= $m[$i]) { $c = (($m[$i++] - 0xF0) << 18) + (($m[$i++] - 0x80) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; } elseif (0xE0 <= $m[$i]) { - $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; + $c = (($m[$i++] - 0xE0) << 12) + (($m[$i++] - 0x80) << 6) + $m[$i++] - 0x80; } else { $c = (($m[$i++] - 0xC0) << 6) + $m[$i++] - 0x80; } diff --git a/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php b/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php index cfbfa82684796..519e6a126b7dc 100644 --- a/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php @@ -120,7 +120,7 @@ public function testXmlResource() $var = xml_parser_create(); $this->assertDumpMatchesFormat( - <<assertDumpMatchesFormat( - << {} "1" => &1 null @@ -161,7 +161,7 @@ public function testObjectCast() $var->{1} = 2; $this->assertDumpMatchesFormat( - <<getSpecialVars(); $this->assertDumpEquals( - << array:1 [ 0 => &1 array:1 [ @@ -342,7 +342,7 @@ public function testGlobalsNoExt() $dumper->dump($data); $this->assertSame( - << array:1 [ "GLOBALS" => &1 array:1 [ @@ -384,7 +384,7 @@ public function testBuggyRefs() }); $this->assertSame( - << array:1 [ 0 => array:1 [ diff --git a/src/Symfony/Component/VarDumper/Tests/HtmlDumperTest.php b/src/Symfony/Component/VarDumper/Tests/HtmlDumperTest.php index 30495f7c40580..e6fd489448bd0 100644 --- a/src/Symfony/Component/VarDumper/Tests/HtmlDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/HtmlDumperTest.php @@ -135,7 +135,7 @@ public function testCharset() $out = stream_get_contents($out, -1, 0); $this->assertStringMatchesFormat( - <<b"Словарь" diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index 1b6193a6926ba..42b764e03e7f5 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -444,7 +444,7 @@ public function testObjectSupportDisabledButNoExceptions($input) public function testObjectForMapEnabledWithMapping() { - $yaml = << @@ -1011,7 +1011,7 @@ public function getCommentLikeStringInScalarBlockData() public function testBlankLinesAreParsedAsNewLinesInFoldedBlocks() { - $yaml = <<

A heading

@@ -1023,7 +1023,7 @@ public function testBlankLinesAreParsedAsNewLinesInFoldedBlocks() $this->assertSame( array( - 'test' => << <<<'EOT'

A heading

  • a list
  • may be a good example
EOT @@ -1035,7 +1035,7 @@ public function testBlankLinesAreParsedAsNewLinesInFoldedBlocks() public function testAdditionallyIndentedLinesAreParsedAsNewLinesInFoldedBlocks() { - $yaml = <<

A heading

@@ -1047,7 +1047,7 @@ public function testAdditionallyIndentedLinesAreParsedAsNewLinesInFoldedBlocks() $this->assertSame( array( - 'test' => << <<<'EOT'

A heading

  • a list
  • @@ -1080,7 +1080,7 @@ public function parserThrowsExceptionWithCorrectLineNumberProvider() return array( array( 4, - << Date: Thu, 3 Nov 2016 08:46:56 +0100 Subject: [PATCH 039/113] Remove trailing space --- .../Bundle/TwigBundle/Tests/Loader/FilesystemLoaderTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/TwigBundle/Tests/Loader/FilesystemLoaderTest.php b/src/Symfony/Bundle/TwigBundle/Tests/Loader/FilesystemLoaderTest.php index 132893e23b1d4..64ba490388f9f 100644 --- a/src/Symfony/Bundle/TwigBundle/Tests/Loader/FilesystemLoaderTest.php +++ b/src/Symfony/Bundle/TwigBundle/Tests/Loader/FilesystemLoaderTest.php @@ -115,7 +115,7 @@ public function testTwigErrorIfTemplateDoesNotExist() $method->setAccessible(true); $method->invoke($loader, 'name.format.engine'); } - + public function testTwigSoftErrorIfTemplateDoesNotExist() { $parser = $this->getMock('Symfony\Component\Templating\TemplateNameParserInterface'); From 4eb003b653377de7aa9598cff6b8f04105628064 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 3 Nov 2016 08:49:30 +0100 Subject: [PATCH 040/113] CS fixes --- .../Tests/Debug/TraceableEventDispatcherTest.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php index 9717099bf9dd6..25a9533da4ece 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/Debug/TraceableEventDispatcherTest.php @@ -25,7 +25,7 @@ public function testAddRemoveListener() $dispatcher = new EventDispatcher(); $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); - $tdispatcher->addListener('foo', $listener = function () { }); + $tdispatcher->addListener('foo', $listener = function () {}); $listeners = $dispatcher->getListeners('foo'); $this->assertCount(1, $listeners); $this->assertSame($listener, $listeners[0]); @@ -39,7 +39,7 @@ public function testGetListeners() $dispatcher = new EventDispatcher(); $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); - $tdispatcher->addListener('foo', $listener = function () { }); + $tdispatcher->addListener('foo', $listener = function () {}); $this->assertSame($dispatcher->getListeners('foo'), $tdispatcher->getListeners('foo')); } @@ -51,7 +51,7 @@ public function testHasListeners() $this->assertFalse($dispatcher->hasListeners('foo')); $this->assertFalse($tdispatcher->hasListeners('foo')); - $tdispatcher->addListener('foo', $listener = function () { }); + $tdispatcher->addListener('foo', $listener = function () {}); $this->assertTrue($dispatcher->hasListeners('foo')); $this->assertTrue($tdispatcher->hasListeners('foo')); } @@ -76,7 +76,7 @@ public function testGetCalledListeners() { $dispatcher = new EventDispatcher(); $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch()); - $tdispatcher->addListener('foo', $listener = function () { }); + $tdispatcher->addListener('foo', $listener = function () {}); $this->assertEquals(array(), $tdispatcher->getCalledListeners()); $this->assertEquals(array('foo.closure' => array('event' => 'foo', 'type' => 'Closure', 'pretty' => 'closure')), $tdispatcher->getNotCalledListeners()); @@ -107,8 +107,8 @@ public function testLogger() $dispatcher = new EventDispatcher(); $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger); - $tdispatcher->addListener('foo', $listener1 = function () { }); - $tdispatcher->addListener('foo', $listener2 = function () { }); + $tdispatcher->addListener('foo', $listener1 = function () {}); + $tdispatcher->addListener('foo', $listener2 = function () {}); $logger->expects($this->at(0))->method('debug')->with('Notified event "foo" to listener "closure".'); $logger->expects($this->at(1))->method('debug')->with('Notified event "foo" to listener "closure".'); @@ -123,7 +123,7 @@ public function testLoggerWithStoppedEvent() $dispatcher = new EventDispatcher(); $tdispatcher = new TraceableEventDispatcher($dispatcher, new Stopwatch(), $logger); $tdispatcher->addListener('foo', $listener1 = function (Event $event) { $event->stopPropagation(); }); - $tdispatcher->addListener('foo', $listener2 = function () { }); + $tdispatcher->addListener('foo', $listener2 = function () {}); $logger->expects($this->at(0))->method('debug')->with('Notified event "foo" to listener "closure".'); $logger->expects($this->at(1))->method('debug')->with('Listener "closure" stopped propagation of the event "foo".'); From 2b0cec528a19bb9ec22b46ccba95a93bfaf3e4c7 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 3 Nov 2016 09:05:06 +0100 Subject: [PATCH 041/113] Remove trailing space --- .../Component/Translation/Catalogue/TargetOperation.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Translation/Catalogue/TargetOperation.php b/src/Symfony/Component/Translation/Catalogue/TargetOperation.php index e081e139a33fa..f3b0a29dfb996 100644 --- a/src/Symfony/Component/Translation/Catalogue/TargetOperation.php +++ b/src/Symfony/Component/Translation/Catalogue/TargetOperation.php @@ -17,7 +17,7 @@ * all = intersection ∪ (target ∖ intersection) = target * new = all ∖ source = {x: x ∈ target ∧ x ∉ source} * obsolete = source ∖ all = source ∖ target = {x: x ∈ source ∧ x ∉ target} - * Basically, the result contains messages from the target catalogue. + * Basically, the result contains messages from the target catalogue. * * @author Michael Lee */ @@ -34,12 +34,12 @@ protected function processDomain($domain) 'obsolete' => array(), ); - // For 'all' messages, the code can't be simplified as ``$this->messages[$domain]['all'] = $target->all($domain);``, + // For 'all' messages, the code can't be simplified as ``$this->messages[$domain]['all'] = $target->all($domain);``, // because doing so will drop messages like {x: x ∈ source ∧ x ∉ target.all ∧ x ∈ target.fallback} // // For 'new' messages, the code can't be simplied as ``array_diff_assoc($this->target->all($domain), $this->source->all($domain));`` // because doing so will not exclude messages like {x: x ∈ target ∧ x ∉ source.all ∧ x ∈ source.fallback} - // + // // For 'obsolete' messages, the code can't be simplifed as ``array_diff_assoc($this->source->all($domain), $this->target->all($domain))`` // because doing so will not exclude messages like {x: x ∈ source ∧ x ∉ target.all ∧ x ∈ target.fallback} From 310e31dd47c58f637748e1457fb2343eb671f1c8 Mon Sep 17 00:00:00 2001 From: Maxime STEINHAUSSER Date: Thu, 3 Nov 2016 09:22:19 +0100 Subject: [PATCH 042/113] [SecurityBundle] Fix case sensitive use --- .../SecurityBundle/DataCollector/SecurityDataCollector.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php index 77f46ae283b01..544e1de1921af 100644 --- a/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php +++ b/src/Symfony/Bundle/SecurityBundle/DataCollector/SecurityDataCollector.php @@ -22,7 +22,7 @@ use Symfony\Component\Security\Core\Authorization\DebugAccessDecisionManager; use Symfony\Component\VarDumper\Cloner\Data; use Symfony\Component\Security\Http\FirewallMapInterface; -use Symfony\Bundle\SecurityBundle\Security\FirewallMAp; +use Symfony\Bundle\SecurityBundle\Security\FirewallMap; /** * SecurityDataCollector. From cdbbd9da367004ab71fe0b197b8408c73240c935 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Thu, 3 Nov 2016 09:36:43 +0100 Subject: [PATCH 043/113] Tweaked the new firewall config in the security profiler panel --- .../views/Collector/security.html.twig | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) 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 31ffe3c9d23b6..9e5a7ddecffe2 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig +++ b/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig @@ -145,6 +145,7 @@ Allows anonymous + {% if collector.firewall.security_enabled %}
@@ -156,38 +157,38 @@ - + - + - + - + - + - + - +
provider{{ collector.firewall.provider }}{{ collector.firewall.provider ?: '(none)' }}
context{{ collector.firewall.context }}{{ collector.firewall.context ?: '(none)' }}
entry_point{{ collector.firewall.entry_point }}{{ collector.firewall.entry_point ?: '(none)' }}
user_checker{{ collector.firewall.user_checker }}{{ collector.firewall.user_checker ?: '(none)' }}
access_denied_handler{{ collector.firewall.access_denied_handler }}{{ collector.firewall.access_denied_handler ?: '(none)' }}
access_denied_url{{ collector.firewall.access_denied_url }}{{ collector.firewall.access_denied_url ?: '(none)' }}
listeners{{ collector.firewall.listeners is empty ? 'none' : profiler_dump(collector.firewall.listeners, maxDepth=1) }}{{ collector.firewall.listeners is empty ? '(none)' : profiler_dump(collector.firewall.listeners, maxDepth=1) }}
{% endif %} {% elseif collector.enabled %}
-

There is no firewall.

+

This request was not covered by any firewall.

{% endif %} {% else %} From e64de1eac65779f1aa3c9c9c4203ea2e64558907 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Tue, 1 Nov 2016 20:56:21 +0100 Subject: [PATCH 044/113] =?UTF-8?q?[Console]=C2=A0Fix=20infinite=20loop=20?= =?UTF-8?q?on=20missing=20input?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [Console] Use console exception for missing input Backport Console RuntimeException in 2.7 --- .../Console/Exception/RuntimeException.php | 19 ++++++++++++ .../Console/Helper/QuestionHelper.php | 9 ++++-- .../Tests/Helper/QuestionHelperTest.php | 31 +++++++++++++++++++ .../Helper/SymfonyQuestionHelperTest.php | 12 +++++++ 4 files changed, 68 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Component/Console/Exception/RuntimeException.php diff --git a/src/Symfony/Component/Console/Exception/RuntimeException.php b/src/Symfony/Component/Console/Exception/RuntimeException.php new file mode 100644 index 0000000000000..1324558a7b912 --- /dev/null +++ b/src/Symfony/Component/Console/Exception/RuntimeException.php @@ -0,0 +1,19 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Console\Exception; + +/** + * @author Jérôme Tamarelle + */ +class RuntimeException extends \RuntimeException +{ +} diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php index 6d6850d1ae826..90055b8a7029e 100644 --- a/src/Symfony/Component/Console/Helper/QuestionHelper.php +++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php @@ -17,6 +17,7 @@ use Symfony\Component\Console\Formatter\OutputFormatterStyle; use Symfony\Component\Console\Question\Question; use Symfony\Component\Console\Question\ChoiceQuestion; +use Symfony\Component\Console\Exception\RuntimeException; /** * The QuestionHelper class provides helpers to interact with the user. @@ -134,7 +135,7 @@ public function doAsk(OutputInterface $output, Question $question) if (false === $ret) { $ret = fgets($inputStream, 4096); if (false === $ret) { - throw new \RuntimeException('Aborted'); + throw new RuntimeException('Aborted'); } $ret = trim($ret); } @@ -354,7 +355,7 @@ private function getHiddenResponse(OutputInterface $output, $inputStream) shell_exec(sprintf('stty %s', $sttyMode)); if (false === $value) { - throw new \RuntimeException('Aborted'); + throw new RuntimeException('Aborted'); } $value = trim($value); @@ -372,7 +373,7 @@ private function getHiddenResponse(OutputInterface $output, $inputStream) return $value; } - throw new \RuntimeException('Unable to hide the response.'); + throw new RuntimeException('Unable to hide the response.'); } /** @@ -397,6 +398,8 @@ private function validateAttempts($interviewer, OutputInterface $output, Questio try { return call_user_func($question->getValidator(), $interviewer()); + } catch (RuntimeException $e) { + throw $e; } catch (\Exception $error) { } } diff --git a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php index 6a4f8aceae9fe..86ad446c1b396 100644 --- a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php @@ -402,6 +402,37 @@ public function testChoiceOutputFormattingQuestionForUtf8Keys() $dialog->ask($this->createInputInterfaceMock(), $output, $question); } + /** + * @expectedException \Symfony\Component\Console\Exception\RuntimeException + * @expectedExceptionMessage Aborted + */ + public function testAskThrowsExceptionOnMissingInput() + { + $dialog = new QuestionHelper(); + $dialog->setInputStream($this->getInputStream('')); + + $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), new Question('What\'s your name?')); + } + + /** + * @expectedException \Symfony\Component\Console\Exception\RuntimeException + * @expectedExceptionMessage Aborted + */ + public function testAskThrowsExceptionOnMissingInputWithValidator() + { + $dialog = new QuestionHelper(); + $dialog->setInputStream($this->getInputStream('')); + + $question = new Question('What\'s your name?'); + $question->setValidator(function () { + if (!$value) { + throw new \Exception('A value is required.'); + } + }); + + $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question); + } + protected function getInputStream($input) { $stream = fopen('php://memory', 'r+', false); diff --git a/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php index 91f51245acd7e..f57d65070e076 100644 --- a/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php @@ -101,6 +101,18 @@ public function testAskEscapeLabel() $this->assertOutputContains('Do you want a \?', $output); } + /** + * @expectedException \Symfony\Component\Console\Exception\RuntimeException + * @expectedExceptionMessage Aborted + */ + public function testAskThrowsExceptionOnMissingInput() + { + $dialog = new SymfonyQuestionHelper(); + + $dialog->setInputStream($this->getInputStream('')); + $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), new Question('What\'s your name?')); + } + protected function getInputStream($input) { $stream = fopen('php://memory', 'r+', false); From 4ccfce6106baf5cf483484856802bf4f1aef2b5b Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 17 Oct 2016 21:00:48 -0700 Subject: [PATCH 045/113] [DependencyInjection] fixed ini file values conversion --- .../Loader/IniFileLoader.php | 36 +++++++- .../Tests/Fixtures/ini/almostvalid.ini | 2 + .../Tests/Fixtures/ini/types.ini | 27 ++++++ .../Tests/Loader/IniFileLoaderTest.php | 82 +++++++++++++++++-- .../Tests/Loader/XmlFileLoaderTest.php | 1 + .../Tests/Loader/YamlFileLoaderTest.php | 1 + 6 files changed, 139 insertions(+), 10 deletions(-) create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/ini/almostvalid.ini create mode 100644 src/Symfony/Component/DependencyInjection/Tests/Fixtures/ini/types.ini diff --git a/src/Symfony/Component/DependencyInjection/Loader/IniFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/IniFileLoader.php index 16ddf87f85112..9fea56be1b22d 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/IniFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/IniFileLoader.php @@ -12,6 +12,7 @@ namespace Symfony\Component\DependencyInjection\Loader; use Symfony\Component\Config\Resource\FileResource; +use Symfony\Component\Config\Util\XmlUtils; use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; /** @@ -30,14 +31,18 @@ public function load($resource, $type = null) $this->container->addResource(new FileResource($path)); + // first pass to catch parsing errors $result = parse_ini_file($path, true); if (false === $result || array() === $result) { throw new InvalidArgumentException(sprintf('The "%s" file is not valid.', $resource)); } + // real raw parsing + $result = parse_ini_file($path, true, INI_SCANNER_RAW); + if (isset($result['parameters']) && is_array($result['parameters'])) { foreach ($result['parameters'] as $key => $value) { - $this->container->setParameter($key, $value); + $this->container->setParameter($key, $this->phpize($value)); } } } @@ -49,4 +54,33 @@ public function supports($resource, $type = null) { return is_string($resource) && 'ini' === pathinfo($resource, PATHINFO_EXTENSION); } + + /** + * Note that the following features are not supported: + * * strings with escaped quotes are not supported "foo\"bar"; + * * string concatenation ("foo" "bar"). + */ + private function phpize($value) + { + // trim on the right as comments removal keep whitespaces + $value = rtrim($value); + $lowercaseValue = strtolower($value); + + switch (true) { + case defined($value): + return constant($value); + case 'yes' === $lowercaseValue || 'on' === $lowercaseValue: + return true; + case 'no' === $lowercaseValue || 'off' === $lowercaseValue || 'none' === $lowercaseValue: + return false; + case isset($value[1]) && ( + ("'" === $value[0] && "'" === $value[strlen($value) - 1]) || + ('"' === $value[0] && '"' === $value[strlen($value) - 1]) + ): + // quoted string + return substr($value, 1, -1); + default: + return XmlUtils::phpize($value); + } + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/ini/almostvalid.ini b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/ini/almostvalid.ini new file mode 100644 index 0000000000000..9fdef85580a6b --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/ini/almostvalid.ini @@ -0,0 +1,2 @@ +foo = ' +bar = bar diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/ini/types.ini b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/ini/types.ini new file mode 100644 index 0000000000000..19cc5b3b31e42 --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/ini/types.ini @@ -0,0 +1,27 @@ +[parameters] + true = true + true_comment = true ; comment + false = false + null = null + on = on + off = off + yes = yes + no = no + none = none + constant = PHP_VERSION + 12 = 12 + 12_string = '12' + 12_comment = 12 ; comment + 12_string_comment = '12' ; comment + 12_string_comment_again = "12" ; comment + -12 = -12 + 0 = 0 + 1 = 1 + 0b0110 = 0b0110 + 11112222333344445555 = 1111,2222,3333,4444,5555 + 0777 = 0777 + 255 = 0xFF + 100.0 = 1e2 + -120.0 = -1.2E2 + -10100.1 = -10100.1 + -10,100.1 = -10,100.1 diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/IniFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/IniFileLoaderTest.php index cab44b20c74cc..5dc3c6deefa0f 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/IniFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/IniFileLoaderTest.php @@ -17,20 +17,13 @@ class IniFileLoaderTest extends \PHPUnit_Framework_TestCase { - protected static $fixturesPath; - protected $container; protected $loader; - public static function setUpBeforeClass() - { - self::$fixturesPath = realpath(__DIR__.'/../Fixtures/'); - } - protected function setUp() { $this->container = new ContainerBuilder(); - $this->loader = new IniFileLoader($this->container, new FileLocator(self::$fixturesPath.'/ini')); + $this->loader = new IniFileLoader($this->container, new FileLocator(realpath(__DIR__.'/../Fixtures/').'/ini')); } public function testIniFileCanBeLoaded() @@ -39,6 +32,68 @@ public function testIniFileCanBeLoaded() $this->assertEquals(array('foo' => 'bar', 'bar' => '%foo%'), $this->container->getParameterBag()->all(), '->load() takes a single file name as its first argument'); } + /** + * @dataProvider getTypeConversions + */ + public function testTypeConversions($key, $value, $supported) + { + $this->loader->load('types.ini'); + $parameters = $this->container->getParameterBag()->all(); + $this->assertSame($value, $parameters[$key], '->load() converts values to PHP types'); + } + + /** + * @dataProvider getTypeConversions + * @requires PHP 5.6.1 + * This test illustrates where our conversions differs from INI_SCANNER_TYPED introduced in PHP 5.6.1 + */ + public function testTypeConversionsWithNativePhp($key, $value, $supported) + { + if (defined('HHVM_VERSION_ID')) { + return $this->markTestSkipped(); + } + + if (!$supported) { + return; + } + + $this->loader->load('types.ini'); + $expected = parse_ini_file(__DIR__.'/../Fixtures/ini/types.ini', true, INI_SCANNER_TYPED); + $this->assertSame($value, $expected['parameters'][$key], '->load() converts values to PHP types'); + } + + public function getTypeConversions() + { + return array( + array('true_comment', true, true), + array('true', true, true), + array('false', false, true), + array('on', true, true), + array('off', false, true), + array('yes', true, true), + array('no', false, true), + array('none', false, true), + array('null', null, true), + array('constant', PHP_VERSION, true), + array('12', 12, true), + array('12_string', '12', true), + array('12_comment', 12, true), + array('12_string_comment', '12', true), + array('12_string_comment_again', '12', true), + array('-12', -12, true), + array('1', 1, true), + array('0', 0, true), + array('0b0110', bindec('0b0110'), false), // not supported by INI_SCANNER_TYPED + array('11112222333344445555', '1111,2222,3333,4444,5555', true), + array('0777', 0777, false), // not supported by INI_SCANNER_TYPED + array('255', 0xFF, false), // not supported by INI_SCANNER_TYPED + array('100.0', 1e2, false), // not supported by INI_SCANNER_TYPED + array('-120.0', -1.2E2, false), // not supported by INI_SCANNER_TYPED + array('-10100.1', -10100.1, false), // not supported by INI_SCANNER_TYPED + array('-10,100.1', '-10,100.1', true), + ); + } + /** * @expectedException \InvalidArgumentException * @expectedExceptionMessage The file "foo.ini" does not exist (in: @@ -49,7 +104,7 @@ public function testExceptionIsRaisedWhenIniFileDoesNotExist() } /** - * @expectedException \InvalidArgumentException + * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException * @expectedExceptionMessage The "nonvalid.ini" file is not valid. */ public function testExceptionIsRaisedWhenIniFileCannotBeParsed() @@ -57,6 +112,15 @@ public function testExceptionIsRaisedWhenIniFileCannotBeParsed() @$this->loader->load('nonvalid.ini'); } + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException + * @expectedExceptionMessage The "almostvalid.ini" file is not valid. + */ + public function testExceptionIsRaisedWhenIniFileIsAlmostValid() + { + @$this->loader->load('almostvalid.ini'); + } + public function testSupports() { $loader = new IniFileLoader(new ContainerBuilder(), new FileLocator()); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index 9cf528d5ca9c9..7d5f95df14889 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -164,6 +164,7 @@ public function testLoadImports() ); $this->assertEquals(array_keys($expected), array_keys($actual), '->load() imports and merges imported files'); + $this->assertTrue($actual['imported_from_ini']); // Bad import throws no exception due to ignore_errors value. $loader->load('services4_bad_import.xml'); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index 13308a94a014a..dccce3ac2e17a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -115,6 +115,7 @@ public function testLoadImports() $actual = $container->getParameterBag()->all(); $expected = array('foo' => 'bar', 'values' => array(true, false, PHP_INT_MAX), 'bar' => '%foo%', 'escape' => '@escapeme', 'foo_bar' => new Reference('foo_bar'), 'mixedcase' => array('MixedCaseKey' => 'value'), 'imported_from_ini' => true, 'imported_from_xml' => true); $this->assertEquals(array_keys($expected), array_keys($actual), '->load() imports and merges imported files'); + $this->assertTrue($actual['imported_from_ini']); // Bad import throws no exception due to ignore_errors value. $loader->load('services4_bad_import.yml'); From cb6c7035ff377b7950157ca7ea2f94234352cabb Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 4 Nov 2016 09:25:13 +0100 Subject: [PATCH 046/113] [Security] improve some firewall config comments --- .../Resources/config/security.xml | 2 +- .../Security/FirewallConfig.php | 26 +++++++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml index 244e75dea0921..8eb3aec447c86 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml @@ -122,9 +122,9 @@ - + diff --git a/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php b/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php index 4cc5ce17baaa4..b720bf9caddbe 100644 --- a/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php +++ b/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php @@ -28,6 +28,19 @@ class FirewallConfig private $userChecker; private $listeners; + /** + * @param string $name + * @param string $requestMatcher + * @param bool $securityEnabled + * @param bool $stateless + * @param string|null $provider + * @param string|null $context + * @param string|null $entryPoint + * @param string|null $accessDeniedHandler + * @param string|null $accessDeniedUrl + * @param string|null $userChecker + * @param string[] $listeners + */ public function __construct($name, $requestMatcher, $securityEnabled = true, $stateless = false, $provider = null, $context = null, $entryPoint = null, $accessDeniedHandler = null, $accessDeniedUrl = null, $userChecker = null, $listeners = array()) { $this->name = $name; @@ -72,7 +85,7 @@ public function isStateless() } /** - * @return string The provider service id + * @return string|null The provider service id */ public function getProvider() { @@ -80,7 +93,7 @@ public function getProvider() } /** - * @return string The context key + * @return string|null The context key (will be null if the firewall is stateless) */ public function getContext() { @@ -88,7 +101,7 @@ public function getContext() } /** - * @return string The entry_point service id + * @return string|null The entry_point service id if configured, null otherwise */ public function getEntryPoint() { @@ -104,20 +117,23 @@ public function getUserChecker() } /** - * @return string The access_denied_handler service id + * @return string|null The access_denied_handler service id if configured, null otherwise */ public function getAccessDeniedHandler() { return $this->accessDeniedHandler; } + /** + * @return string|null The access_denied_handler URL if configured, null otherwise + */ public function getAccessDeniedUrl() { return $this->accessDeniedUrl; } /** - * @return array An array of listener keys + * @return string[] An array of listener keys */ public function getListeners() { From ad54d83c902a80367d27d946b00b6f3808e1e26b Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 4 Nov 2016 11:57:19 +0100 Subject: [PATCH 047/113] [Yaml] set arguments depending on the PHP version --- src/Symfony/Component/Yaml/Tests/InlineTest.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php index e414abd38bf12..83d20cc96c82a 100644 --- a/src/Symfony/Component/Yaml/Tests/InlineTest.php +++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php @@ -507,7 +507,12 @@ public function testParseTimestampAsDateTimeObject($yaml, $year, $month, $day, $ $expected = new \DateTime($yaml); $expected->setTimeZone(new \DateTimeZone('UTC')); $expected->setDate($year, $month, $day); - @$expected->setTime($hour, $minute, $second, 1000000 * ($second - (int) $second)); + + if (PHP_VERSION_ID >= 70100) { + $expected->setTime($hour, $minute, $second, 1000000 * ($second - (int) $second)); + } else { + $expected->setTime($hour, $minute, $second); + } $this->assertEquals($expected, Inline::parse($yaml, Yaml::PARSE_DATETIME)); } From 5963627d06dec4074e001edc38a7cf3b3d5529fd Mon Sep 17 00:00:00 2001 From: Maxime STEINHAUSSER Date: Fri, 4 Nov 2016 13:57:00 +0100 Subject: [PATCH 048/113] [SecurityBundle] Make the FirewallConfig class final --- .../Bundle/SecurityBundle/Security/FirewallConfig.php | 2 +- .../SecurityBundle/Tests/Security/FirewallContextTest.php | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php b/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php index 4cc5ce17baaa4..56f43b31e8d6c 100644 --- a/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php +++ b/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php @@ -14,7 +14,7 @@ /** * @author Robin Chalas */ -class FirewallConfig +final class FirewallConfig { private $name; private $requestMatcher; diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallContextTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallContextTest.php index 86aecc1aa2d3e..cce2a5b47fde5 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallContextTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallContextTest.php @@ -20,10 +20,7 @@ class FirewallContextTest extends \PHPUnit_Framework_TestCase { public function testGetters() { - $config = $this - ->getMockBuilder(FirewallConfig::class) - ->disableOriginalConstructor() - ->getMock(); + $config = new FirewallConfig('main', 'request_matcher'); $exceptionListener = $this ->getMockBuilder(ExceptionListener::class) From c0e880e277fba48b51c25e077ecef477c57e7bac Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 4 Nov 2016 14:53:25 +0100 Subject: [PATCH 049/113] [DI] Add missing deprecation in ContainerBuilder::addCompilerPass --- .../Component/DependencyInjection/ContainerBuilder.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index c778f52d99037..bf4f2937a6f0c 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -316,6 +316,13 @@ public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig: if (func_num_args() >= 3) { $priority = func_get_arg(2); } else { + if (__CLASS__ !== get_class($this)) { + $r = new \ReflectionMethod($this, __FUNCTION__); + if (__CLASS__ !== $r->getDeclaringClass()->getName()) { + @trigger_error(sprintf('Method %s() will have a third `$priority = 0` argument in version 4.0. Not defining it is deprecated since 3.2.', get_class($this), __FUNCTION__), E_USER_DEPRECATED); + } + } + $priority = 0; } From 6754af242be82e0d15f61eb56b588fe752bf129c Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Fri, 4 Nov 2016 11:46:56 +0100 Subject: [PATCH 050/113] [SecurityBundle] FirewallConfig's user_checker should be mandatory --- .../DependencyInjection/SecurityExtension.php | 16 ++++++++-------- .../SecurityBundle/Resources/config/security.xml | 2 +- .../SecurityBundle/Security/FirewallConfig.php | 8 ++++---- .../DataCollector/SecurityDataCollectorTest.php | 2 +- .../CompleteConfigurationTest.php | 7 ++++--- .../Tests/Security/FirewallConfigTest.php | 2 +- .../Tests/Security/FirewallContextTest.php | 2 +- 7 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index 6ac5c63338279..5c88548bcff1d 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -280,14 +280,15 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a } $config->replaceArgument(1, (string) $matcher); - $config->replaceArgument(2, $firewall['security']); + $config->replaceArgument(2, $firewall['user_checker']); + $config->replaceArgument(3, $firewall['security']); // Security disabled? if (false === $firewall['security']) { return array($matcher, array(), null); } - $config->replaceArgument(3, $firewall['stateless']); + $config->replaceArgument(4, $firewall['stateless']); // Provider id (take the first registered provider if none defined) if (isset($firewall['provider'])) { @@ -296,7 +297,7 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a $defaultProvider = reset($providerIds); } - $config->replaceArgument(4, $defaultProvider); + $config->replaceArgument(5, $defaultProvider); // Register listeners $listeners = array(); @@ -312,7 +313,7 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a $contextKey = $firewall['context']; } - $config->replaceArgument(5, $contextKey); + $config->replaceArgument(6, $contextKey); $listeners[] = new Reference($this->createContextListener($container, $contextKey)); } @@ -382,7 +383,7 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a // Authentication listeners list($authListeners, $defaultEntryPoint) = $this->createAuthenticationListeners($container, $id, $firewall, $authenticationProviders, $defaultProvider, $configuredEntryPoint); - $config->replaceArgument(6, $configuredEntryPoint ?: $defaultEntryPoint); + $config->replaceArgument(7, $configuredEntryPoint ?: $defaultEntryPoint); $listeners = array_merge($listeners, $authListeners); @@ -399,14 +400,13 @@ private function createFirewall(ContainerBuilder $container, $id, $firewall, &$a $exceptionListener = new Reference($this->createExceptionListener($container, $firewall, $id, $configuredEntryPoint ?: $defaultEntryPoint, $firewall['stateless'])); if (isset($firewall['access_denied_handler'])) { - $config->replaceArgument(7, $firewall['access_denied_handler']); + $config->replaceArgument(8, $firewall['access_denied_handler']); } if (isset($firewall['access_denied_url'])) { - $config->replaceArgument(8, $firewall['access_denied_url']); + $config->replaceArgument(9, $firewall['access_denied_url']); } $container->setAlias(new Alias('security.user_checker.'.$id, false), $firewall['user_checker']); - $config->replaceArgument(9, $firewall['user_checker']); foreach ($this->factories as $position) { foreach ($position as $factory) { diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml index 8eb3aec447c86..8def320482486 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security.xml @@ -117,6 +117,7 @@ + @@ -124,7 +125,6 @@ - diff --git a/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php b/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php index dc48c459a2153..a36ff955130d1 100644 --- a/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php +++ b/src/Symfony/Bundle/SecurityBundle/Security/FirewallConfig.php @@ -18,6 +18,7 @@ final class FirewallConfig { private $name; private $requestMatcher; + private $userChecker; private $securityEnabled; private $stateless; private $provider; @@ -25,12 +26,12 @@ final class FirewallConfig private $entryPoint; private $accessDeniedHandler; private $accessDeniedUrl; - private $userChecker; private $listeners; /** * @param string $name * @param string $requestMatcher + * @param string $userChecker * @param bool $securityEnabled * @param bool $stateless * @param string|null $provider @@ -38,13 +39,13 @@ final class FirewallConfig * @param string|null $entryPoint * @param string|null $accessDeniedHandler * @param string|null $accessDeniedUrl - * @param string|null $userChecker * @param string[] $listeners */ - public function __construct($name, $requestMatcher, $securityEnabled = true, $stateless = false, $provider = null, $context = null, $entryPoint = null, $accessDeniedHandler = null, $accessDeniedUrl = null, $userChecker = null, $listeners = array()) + public function __construct($name, $requestMatcher, $userChecker, $securityEnabled = true, $stateless = false, $provider = null, $context = null, $entryPoint = null, $accessDeniedHandler = null, $accessDeniedUrl = null, $listeners = array()) { $this->name = $name; $this->requestMatcher = $requestMatcher; + $this->userChecker = $userChecker; $this->securityEnabled = $securityEnabled; $this->stateless = $stateless; $this->provider = $provider; @@ -52,7 +53,6 @@ public function __construct($name, $requestMatcher, $securityEnabled = true, $st $this->entryPoint = $entryPoint; $this->accessDeniedHandler = $accessDeniedHandler; $this->accessDeniedUrl = $accessDeniedUrl; - $this->userChecker = $userChecker; $this->listeners = $listeners; } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php index e5a6a4b760503..2d912721ed4f4 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DataCollector/SecurityDataCollectorTest.php @@ -78,7 +78,7 @@ public function testCollectAuthenticationTokenAndRoles(array $roles, array $norm public function testGetFirewall() { - $firewallConfig = new FirewallConfig('dummy', 'security.request_matcher.dummy'); + $firewallConfig = new FirewallConfig('dummy', 'security.request_matcher.dummy', 'security.user_checker.dummy'); $request = $this->getRequest(); $firewallMap = $this diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php index 8f877de4cc870..34e3ad56114ac 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/CompleteConfigurationTest.php @@ -79,16 +79,17 @@ public function testFirewalls() array( 'simple', 'security.request_matcher.707b20193d4cb9f2718114abcbebb32af48f948484fc166a03482f49bf14f25e271f72c7', + 'security.user_checker', false, ), array( 'secure', '', + 'security.user_checker', true, true, 'security.user.provider.concrete.default', 'security.authentication.form_entry_point.secure', - 'security.user_checker', array( 'logout', 'switch_user', @@ -104,12 +105,12 @@ public function testFirewalls() array( 'host', 'security.request_matcher.dda8b565689ad8509623ee68fb2c639cd81cd4cb339d60edbaf7d67d30e6aa09bd8c63c3', + 'security.user_checker', true, false, 'security.user.provider.concrete.default', 'host', 'security.authentication.basic_entry_point.host', - 'security.user_checker', array( 'http_basic', 'anonymous', @@ -118,12 +119,12 @@ public function testFirewalls() array( 'with_user_checker', '', + 'app.user_checker', true, false, 'security.user.provider.concrete.default', 'with_user_checker', 'security.authentication.basic_entry_point.with_user_checker', - 'app.user_checker', array( 'http_basic', 'anonymous', diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallConfigTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallConfigTest.php index 8d9b0519b197e..eb6eeeb8dd588 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallConfigTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallConfigTest.php @@ -33,6 +33,7 @@ public function testGetters() $config = new FirewallConfig( 'foo_firewall', $options['request_matcher'], + $options['user_checker'], $options['security'], $options['stateless'], $options['provider'], @@ -40,7 +41,6 @@ public function testGetters() $options['entry_point'], $options['access_denied_handler'], $options['access_denied_url'], - $options['user_checker'], $listeners ); diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallContextTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallContextTest.php index cce2a5b47fde5..098e2c51f80dd 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallContextTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/Security/FirewallContextTest.php @@ -20,7 +20,7 @@ class FirewallContextTest extends \PHPUnit_Framework_TestCase { public function testGetters() { - $config = new FirewallConfig('main', 'request_matcher'); + $config = new FirewallConfig('main', 'request_matcher', 'user_checker'); $exceptionListener = $this ->getMockBuilder(ExceptionListener::class) From d81da793d3f94e2f3d26e7dba97c0356de9292d5 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Fri, 4 Nov 2016 00:00:58 +0100 Subject: [PATCH 051/113] [SecurityBundle] Display firewall in debug bar even if not authenticated --- .../views/Collector/security.html.twig | 56 ++++++++++--------- 1 file changed, 29 insertions(+), 27 deletions(-) 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 9e5a7ddecffe2..606dafa7227dd 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig +++ b/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig @@ -16,39 +16,41 @@ {% endset %} {% set text %} - {% if collector.token %} -
- Logged in as - {{ collector.user }} -
+ {% if collector.enabled %} + {% if collector.token %} +
+ Logged in as + {{ collector.user }} +
-
- Authenticated - {{ is_authenticated ? 'Yes' : 'No' }} -
+
+ Authenticated + {{ is_authenticated ? 'Yes' : 'No' }} +
- {% if collector.token != null %} -
- Token class - {{ collector.tokenClass|abbr_class }} -
+
+ Token class + {{ collector.tokenClass|abbr_class }} +
+ {% else %} +
+ You are not authenticated. +
{% endif %} + {% if collector.firewall %} -
- Firewall name - {{ collector.firewall.name }} -
+
+ Firewall name + {{ collector.firewall.name }} +
{% endif %} - {% if collector.logoutUrl %} -
- Actions - Logout -
+ + {% if collector.token and collector.logoutUrl %} +
+ Actions + Logout +
{% endif %} - {% elseif collector.enabled %} -
- You are not authenticated. -
{% else %}
The security is disabled. From d030a9d4036894a2a77af2100e3d23e597a0b65c Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Tue, 25 Oct 2016 11:20:09 +0200 Subject: [PATCH 052/113] Improved the design of the metrics in the profiler --- .../Resources/views/Collector/time.html.twig | 20 ++++++++++--------- .../views/Profiler/profiler.css.twig | 10 ++++++++-- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.html.twig index 98ea6c3265d2a..6860230243106 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.html.twig @@ -60,10 +60,19 @@ Symfony initialization
+ {% if profile.collectors.memory %} +
+ {{ '%.2f'|format(profile.collectors.memory.memory / 1024 / 1024) }} MB + Peak memory usage +
+ {% endif %} + {% if profile.children|length > 0 %} +
+
{{ profile.children|length }} - Sub-Requests + Sub-Request{{ profile.children|length > 1 ? 's' }}
{% set subrequests_time = 0 %} @@ -73,14 +82,7 @@
{{ subrequests_time }} ms - Sub-Requests time -
- {% endif %} - - {% if profile.collectors.memory %} -
- {{ '%.2f'|format(profile.collectors.memory.memory / 1024 / 1024) }} MB - Peak memory usage + Sub-Request{{ profile.children|length > 1 ? 's' }} time
{% endif %}
diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig index 4d458d3242c97..b807d0bcf9b5b 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/profiler.css.twig @@ -250,12 +250,12 @@ table tbody ul { {# Metrics ------------------------------------------------------------------------- #} .metrics { - margin: 1em 0; + margin: 1em 0 0; overflow: auto; } .metrics .metric { float: left; - margin-right: 1em; + margin: 0 1em 1em 0; } .metric { @@ -310,6 +310,12 @@ table tbody ul { vertical-align: middle; } +.metric-divider { + float: left; + margin: 0 1em; + min-height: 1px; {# required to apply 'margin' to an empty 'div' #} +} + {# Cards ------------------------------------------------------------------------- #} .card { From c3dacbb9a1418e3e7c433152439f7e6ae390706f Mon Sep 17 00:00:00 2001 From: Jan Emrich Date: Fri, 4 Nov 2016 18:49:05 +0100 Subject: [PATCH 053/113] Remove double use Statement Syntax Error in Helper/QuestionHelper.php --- src/Symfony/Component/Console/Helper/QuestionHelper.php | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php index 5244bb5fb842c..4b4e1a63f9fa0 100644 --- a/src/Symfony/Component/Console/Helper/QuestionHelper.php +++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php @@ -19,7 +19,6 @@ use Symfony\Component\Console\Formatter\OutputFormatterStyle; use Symfony\Component\Console\Question\Question; use Symfony\Component\Console\Question\ChoiceQuestion; -use Symfony\Component\Console\Exception\RuntimeException; /** * The QuestionHelper class provides helpers to interact with the user. From 1b05650962b0ee7bd07171fda6e7a9eb2f74a9bf Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Fri, 4 Nov 2016 19:04:00 +0100 Subject: [PATCH 054/113] consistent "not authenticated" output in WDT This makes the output in the toolbar when no token is present consistent with what it looks like when there is a token. --- .../Resources/views/Collector/security.html.twig | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 606dafa7227dd..3830e924a190b 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig +++ b/src/Symfony/Bundle/SecurityBundle/Resources/views/Collector/security.html.twig @@ -34,7 +34,8 @@
{% else %}
- You are not authenticated. + Authenticated + No
{% endif %} From 90ba197cefefe5ab2f3d332a5495988c34874b9b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 4 Nov 2016 14:53:25 +0100 Subject: [PATCH 055/113] [DI][Serializer] Add missing deprecations --- .../DependencyInjection/Compiler/Compiler.php | 10 ++++++++-- .../DependencyInjection/Compiler/PassConfig.php | 8 +++++++- .../DependencyInjection/ContainerBuilder.php | 3 +-- .../Serializer/Normalizer/AbstractNormalizer.php | 13 ++++++++++++- .../Normalizer/AbstractObjectNormalizerTest.php | 4 ++-- 5 files changed, 30 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php b/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php index cc5d9adc792a5..3aa252639901e 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/Compiler.php @@ -70,12 +70,18 @@ public function getLoggingFormatter() * @param string $type The type of the pass * @param int $priority Used to sort the passes */ - public function addPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION/**, $priority = 0*/) + public function addPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION/*, $priority = 0*/) { - // For BC if (func_num_args() >= 3) { $priority = func_get_arg(2); } else { + if (__CLASS__ !== get_class($this)) { + $r = new \ReflectionMethod($this, __FUNCTION__); + if (__CLASS__ !== $r->getDeclaringClass()->getName()) { + @trigger_error(sprintf('Method %s() will have a third `$priority = 0` argument in version 4.0. Not defining it is deprecated since 3.2.', get_class($this), __FUNCTION__), E_USER_DEPRECATED); + } + } + $priority = 0; } diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php index 8da6595cd9250..b95a41482983d 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php @@ -96,10 +96,16 @@ public function getPasses() */ public function addPass(CompilerPassInterface $pass, $type = self::TYPE_BEFORE_OPTIMIZATION/*, $priority = 0*/) { - // For BC if (func_num_args() >= 3) { $priority = func_get_arg(2); } else { + if (__CLASS__ !== get_class($this)) { + $r = new \ReflectionMethod($this, __FUNCTION__); + if (__CLASS__ !== $r->getDeclaringClass()->getName()) { + @trigger_error(sprintf('Method %s() will have a third `$priority = 0` argument in version 4.0. Not defining it is deprecated since 3.2.', get_class($this), __FUNCTION__), E_USER_DEPRECATED); + } + } + $priority = 0; } diff --git a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php index bf4f2937a6f0c..964f43bd8bd70 100644 --- a/src/Symfony/Component/DependencyInjection/ContainerBuilder.php +++ b/src/Symfony/Component/DependencyInjection/ContainerBuilder.php @@ -310,9 +310,8 @@ public function loadFromExtension($extension, array $values = array()) * * @return ContainerBuilder The current instance */ - public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION/**, $priority = 0*/) + public function addCompilerPass(CompilerPassInterface $pass, $type = PassConfig::TYPE_BEFORE_OPTIMIZATION/*, $priority = 0*/) { - // For BC if (func_num_args() >= 3) { $priority = func_get_arg(2); } else { diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index a1aa4250e2155..82f6e1e2a8f39 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -289,7 +289,18 @@ protected function getConstructor(array &$data, $class, array &$context, \Reflec */ protected function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes/*, $format = null*/) { - $format = func_num_args() >= 6 ? func_get_arg(5) : null; + if (func_num_args() >= 6) { + $format = func_get_arg(5); + } else { + if (__CLASS__ !== get_class($this)) { + $r = new \ReflectionMethod($this, __FUNCTION__); + if (__CLASS__ !== $r->getDeclaringClass()->getName()) { + @trigger_error(sprintf('Method %s() will have a 6th `$format = null` argument in version 4.0. Not defining it is deprecated since 3.2.', get_class($this), __FUNCTION__), E_USER_DEPRECATED); + } + } + + $format = null; + } if ( isset($context[static::OBJECT_TO_POPULATE]) && diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php index c9df3c955f031..03693fef2229e 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/AbstractObjectNormalizerTest.php @@ -59,9 +59,9 @@ protected function isAllowedAttribute($classOrObject, $attribute, $format = null return in_array($attribute, array('foo', 'baz')); } - public function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes) + public function instantiateObject(array &$data, $class, array &$context, \ReflectionClass $reflectionClass, $allowedAttributes, $format = null) { - return parent::instantiateObject($data, $class, $context, $reflectionClass, $allowedAttributes); + return parent::instantiateObject($data, $class, $context, $reflectionClass, $allowedAttributes, $format); } } From 7572a53b847af0c74ec1c23cd56087c46f9a2978 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Fri, 4 Nov 2016 21:47:40 +0100 Subject: [PATCH 056/113] [Bridge\Monolog][FrameworkBundle] Add & wire a DebugProcessor --- .../Bridge/Monolog/Handler/DebugHandler.php | 4 ++ src/Symfony/Bridge/Monolog/Logger.php | 6 ++ .../Monolog/Processor/DebugProcessor.php | 58 ++++++++++++++++++ .../Bridge/Monolog/Tests/LoggerTest.php | 59 ++++++++++++++++++- .../Compiler/AddDebugLogProcessorPass.php | 35 +++++++++++ .../FrameworkExtension.php | 7 +++ .../FrameworkBundle/FrameworkBundle.php | 2 + 7 files changed, 168 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddDebugLogProcessorPass.php diff --git a/src/Symfony/Bridge/Monolog/Handler/DebugHandler.php b/src/Symfony/Bridge/Monolog/Handler/DebugHandler.php index f1046c96a6ad1..6032750ff6422 100644 --- a/src/Symfony/Bridge/Monolog/Handler/DebugHandler.php +++ b/src/Symfony/Bridge/Monolog/Handler/DebugHandler.php @@ -11,6 +11,8 @@ namespace Symfony\Bridge\Monolog\Handler; +@trigger_error('The '.__NAMESPACE__.'\DebugHandler class is deprecated since version 3.2 and will be removed in 4.0. Use Symfony\Bridge\Monolog\Processor\DebugProcessor instead.', E_USER_DEPRECATED); + use Monolog\Logger; use Monolog\Handler\TestHandler; use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; @@ -19,6 +21,8 @@ * DebugLogger. * * @author Jordi Boggiano + * + * @deprecated since version 3.2, to be removed in 4.0. Use Symfony\Bridge\Monolog\Processor\DebugProcessor instead. */ class DebugHandler extends TestHandler implements DebugLoggerInterface { diff --git a/src/Symfony/Bridge/Monolog/Logger.php b/src/Symfony/Bridge/Monolog/Logger.php index f0e108081b59c..ec6434fe791b8 100644 --- a/src/Symfony/Bridge/Monolog/Logger.php +++ b/src/Symfony/Bridge/Monolog/Logger.php @@ -52,6 +52,12 @@ public function countErrors() */ private function getDebugLogger() { + foreach ($this->processors as $processor) { + if ($processor instanceof DebugLoggerInterface) { + return $processor; + } + } + foreach ($this->handlers as $handler) { if ($handler instanceof DebugLoggerInterface) { return $handler; diff --git a/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php b/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php new file mode 100644 index 0000000000000..22a4faac5cc9a --- /dev/null +++ b/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php @@ -0,0 +1,58 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Processor; + +use Monolog\Logger; +use Symfony\Component\HttpKernel\Log\DebugLoggerInterface; + +class DebugProcessor implements DebugLoggerInterface +{ + private $records = array(); + private $errorCount = 0; + + public function __invoke(array $record) + { + $this->records[] = array( + 'timestamp' => $record['datetime']->getTimestamp(), + 'message' => $record['message'], + 'priority' => $record['level'], + 'priorityName' => $record['level_name'], + 'context' => $record['context'], + 'channel' => isset($record['channel']) ? $record['channel'] : '', + ); + switch ($record['level']) { + case Logger::ERROR: + case Logger::CRITICAL: + case Logger::ALERT: + case Logger::EMERGENCY: + ++$this->errorCount; + } + + return $record; + } + + /** + * {@inheritdoc} + */ + public function getLogs() + { + return $this->records; + } + + /** + * {@inheritdoc} + */ + public function countErrors() + { + return $this->errorCount; + } +} diff --git a/src/Symfony/Bridge/Monolog/Tests/LoggerTest.php b/src/Symfony/Bridge/Monolog/Tests/LoggerTest.php index e685ef041f055..9597d01c96cb1 100644 --- a/src/Symfony/Bridge/Monolog/Tests/LoggerTest.php +++ b/src/Symfony/Bridge/Monolog/Tests/LoggerTest.php @@ -13,10 +13,14 @@ use Monolog\Handler\TestHandler; use Symfony\Bridge\Monolog\Handler\DebugHandler; +use Symfony\Bridge\Monolog\Processor\DebugProcessor; use Symfony\Bridge\Monolog\Logger; class LoggerTest extends \PHPUnit_Framework_TestCase { + /** + * @group legacy + */ public function testGetLogsWithDebugHandler() { $handler = new DebugHandler(); @@ -26,7 +30,7 @@ public function testGetLogsWithDebugHandler() $this->assertSame(1, count($logger->getLogs())); } - public function testGetLogsWithoutDebugHandler() + public function testGetLogsWithoutDebugProcessor() { $handler = new TestHandler(); $logger = new Logger(__METHOD__, array($handler)); @@ -35,6 +39,9 @@ public function testGetLogsWithoutDebugHandler() $this->assertSame(array(), $logger->getLogs()); } + /** + * @group legacy + */ public function testCountErrorsWithDebugHandler() { $handler = new DebugHandler(); @@ -53,7 +60,10 @@ public function testCountErrorsWithDebugHandler() $this->assertSame(4, $logger->countErrors()); } - public function testGetLogs() + /** + * @group legacy + */ + public function testGetLogsWithDebugHandler2() { $logger = new Logger('test'); $logger->pushHandler(new DebugHandler()); @@ -66,7 +76,7 @@ public function testGetLogs() $this->assertEquals(Logger::INFO, $record['priority']); } - public function testCountErrorsWithoutDebugHandler() + public function testCountErrorsWithoutDebugProcessor() { $handler = new TestHandler(); $logger = new Logger(__METHOD__, array($handler)); @@ -74,4 +84,47 @@ public function testCountErrorsWithoutDebugHandler() $this->assertTrue($logger->error('error message')); $this->assertSame(0, $logger->countErrors()); } + + public function testGetLogsWithDebugProcessor() + { + $handler = new TestHandler(); + $processor = new DebugProcessor(); + $logger = new Logger(__METHOD__, array($handler), array($processor)); + + $this->assertTrue($logger->error('error message')); + $this->assertSame(1, count($logger->getLogs())); + } + + public function testCountErrorsWithDebugProcessor() + { + $handler = new TestHandler(); + $processor = new DebugProcessor(); + $logger = new Logger(__METHOD__, array($handler), array($processor)); + + $this->assertTrue($logger->debug('test message')); + $this->assertTrue($logger->info('test message')); + $this->assertTrue($logger->notice('test message')); + $this->assertTrue($logger->warning('test message')); + + $this->assertTrue($logger->error('test message')); + $this->assertTrue($logger->critical('test message')); + $this->assertTrue($logger->alert('test message')); + $this->assertTrue($logger->emergency('test message')); + + $this->assertSame(4, $logger->countErrors()); + } + + public function testGetLogsWithDebugProcessor2() + { + $handler = new TestHandler(); + $logger = new Logger('test', array($handler)); + $logger->pushProcessor(new DebugProcessor()); + + $logger->addInfo('test'); + $this->assertCount(1, $logger->getLogs()); + list($record) = $logger->getLogs(); + + $this->assertEquals('test', $record['message']); + $this->assertEquals(Logger::INFO, $record['priority']); + } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddDebugLogProcessorPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddDebugLogProcessorPass.php new file mode 100644 index 0000000000000..4d8e5175c673a --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/AddDebugLogProcessorPass.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\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\Reference; + +class AddDebugLogProcessorPass implements CompilerPassInterface +{ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition('profiler')) { + return; + } + if (!$container->hasDefinition('monolog.logger_prototype')) { + return; + } + if (!$container->hasDefinition('debug.log_processor')) { + return; + } + + $definition = $container->getDefinition('monolog.logger_prototype'); + $definition->addMethodCall('pushProcessor', array(new Reference('debug.log_processor'))); + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index c3eab37c9ca8c..1ea7441fadd04 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -12,6 +12,7 @@ namespace Symfony\Bundle\FrameworkBundle\DependencyInjection; use Doctrine\Common\Annotations\Reader; +use Symfony\Bridge\Monolog\Processor\DebugProcessor; use Symfony\Component\Cache\Adapter\AdapterInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\ContainerInterface; @@ -468,6 +469,12 @@ private function registerDebugConfiguration(array $config, ContainerBuilder $con $definition->replaceArgument(4, $debug); $definition->replaceArgument(6, $debug); + + if ($debug && class_exists(DebugProcessor::class)) { + $definition = new Definition(DebugProcessor::class); + $definition->setPublic(false); + $container->setDefinition('debug.log_processor', $definition); + } } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 7148f56046789..a736c091a1071 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -12,6 +12,7 @@ namespace Symfony\Bundle\FrameworkBundle; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConstraintValidatorsPass; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddDebugLogProcessorPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddValidatorInitializersPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AddConsoleCommandPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\CachePoolPass; @@ -95,6 +96,7 @@ public function build(ContainerBuilder $container) $container->addCompilerPass(new CachePoolClearerPass(), PassConfig::TYPE_AFTER_REMOVING); if ($container->getParameter('kernel.debug')) { + $container->addCompilerPass(new AddDebugLogProcessorPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -1); $container->addCompilerPass(new UnusedTagsPass(), PassConfig::TYPE_AFTER_REMOVING); $container->addCompilerPass(new ContainerBuilderDebugDumpPass(), PassConfig::TYPE_AFTER_REMOVING); $container->addCompilerPass(new CompilerDebugDumpPass(), PassConfig::TYPE_AFTER_REMOVING); From 35642288faebec8b5d8ec9028494b43b78348a69 Mon Sep 17 00:00:00 2001 From: Yonel Ceruto Date: Tue, 1 Nov 2016 16:33:50 -0400 Subject: [PATCH 057/113] [Form] Fix show float values as choices values in ChoiceType --- .../Component/Form/ChoiceList/ArrayChoiceList.php | 6 +++++- .../Form/Tests/ChoiceList/ArrayChoiceListTest.php | 13 +++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php index 7f2824fab216a..4a2588ef1d475 100644 --- a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php +++ b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php @@ -236,7 +236,11 @@ private function castableToString(array $choices, array &$cache = array()) continue; } elseif (!is_scalar($choice)) { return false; - } elseif (isset($cache[$choice])) { + } + + $choice = false === $choice ? '0' : (string) $choice; + + if (isset($cache[$choice])) { return false; } diff --git a/src/Symfony/Component/Form/Tests/ChoiceList/ArrayChoiceListTest.php b/src/Symfony/Component/Form/Tests/ChoiceList/ArrayChoiceListTest.php index 09bcc9c4c2aa1..3b041eab293d1 100644 --- a/src/Symfony/Component/Form/Tests/ChoiceList/ArrayChoiceListTest.php +++ b/src/Symfony/Component/Form/Tests/ChoiceList/ArrayChoiceListTest.php @@ -34,12 +34,12 @@ protected function createChoiceList() protected function getChoices() { - return array(0, 1, '1', 'a', false, true, $this->object, null); + return array(0, 1, 1.5, '1', 'a', false, true, $this->object, null); } protected function getValues() { - return array('0', '1', '2', '3', '4', '5', '6', '7'); + return array('0', '1', '2', '3', '4', '5', '6', '7', '8'); } /** @@ -162,4 +162,13 @@ public function testGetChoicesForValuesWithContainingEmptyStringAndBooleans() $this->assertSame(array(0 => true), $choiceList->getChoicesForValues(array('1'))); $this->assertSame(array(0 => false), $choiceList->getChoicesForValues(array('0'))); } + + public function testGetChoicesForValuesWithContainingEmptyStringAndFloats() + { + $choiceList = new ArrayChoiceList(array('Empty String' => '', '1/3' => 0.3, '1/2' => 0.5)); + + $this->assertSame(array(0 => ''), $choiceList->getChoicesForValues(array(''))); + $this->assertSame(array(0 => 0.3), $choiceList->getChoicesForValues(array('0.3'))); + $this->assertSame(array(0 => 0.5), $choiceList->getChoicesForValues(array('0.5'))); + } } From eb0d6c94ca51aef6701dff88fbea2e8616e0e72d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 5 Nov 2016 23:09:07 -0700 Subject: [PATCH 058/113] removed a deprecation notice --- .../NodeVisitor/TranslationDefaultDomainNodeVisitor.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php index b226d91adfe48..e64d6eae2347d 100644 --- a/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php +++ b/src/Symfony/Bridge/Twig/NodeVisitor/TranslationDefaultDomainNodeVisitor.php @@ -49,7 +49,7 @@ protected function doEnterNode(\Twig_Node $node, \Twig_Environment $env) return $node; } else { - $var = $env->getParser()->getVarName(); + $var = $this->getVarName(); $name = new \Twig_Node_Expression_AssignName($var, $node->getTemplateLine()); $this->scope->set('domain', new \Twig_Node_Expression_Name($var, $node->getTemplateLine())); @@ -123,4 +123,9 @@ private function isNamedArguments($arguments) return false; } + + private function getVarName() + { + return sprintf('__internal_%s', hash('sha256', uniqid(mt_rand(), true), false)); + } } From 27c91e514e563e090d9f8122235cf61951cde5bd Mon Sep 17 00:00:00 2001 From: Abdellatif Ait boudad Date: Sun, 6 Nov 2016 08:05:17 +0000 Subject: [PATCH 059/113] [Translation][fallback] add missing resources in parent catalogues. --- .../Component/Translation/MessageCatalogue.php | 4 ++++ .../Translation/Tests/MessageCatalogueTest.php | 13 ++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Translation/MessageCatalogue.php b/src/Symfony/Component/Translation/MessageCatalogue.php index dd354a85aae37..73649fb6ddcaa 100644 --- a/src/Symfony/Component/Translation/MessageCatalogue.php +++ b/src/Symfony/Component/Translation/MessageCatalogue.php @@ -178,6 +178,10 @@ public function addFallbackCatalogue(MessageCatalogueInterface $catalogue) if ($c->getLocale() === $catalogue->getLocale()) { throw new \LogicException(sprintf('Circular reference detected when adding a fallback catalogue for locale "%s".', $catalogue->getLocale())); } + + foreach ($catalogue->getResources() as $resource) { + $c->addResource($resource); + } } while ($c = $c->parent); $catalogue->parent = $this; diff --git a/src/Symfony/Component/Translation/Tests/MessageCatalogueTest.php b/src/Symfony/Component/Translation/Tests/MessageCatalogueTest.php index 6f55b8cc5e8fb..e5bb9810045f0 100644 --- a/src/Symfony/Component/Translation/Tests/MessageCatalogueTest.php +++ b/src/Symfony/Component/Translation/Tests/MessageCatalogueTest.php @@ -110,18 +110,25 @@ public function testAddFallbackCatalogue() $r1 = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface'); $r1->expects($this->any())->method('__toString')->will($this->returnValue('r1')); - $catalogue = new MessageCatalogue('en_US', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar'))); + $r2 = $this->getMock('Symfony\Component\Config\Resource\ResourceInterface'); + $r2->expects($this->any())->method('__toString')->will($this->returnValue('r2')); + + $catalogue = new MessageCatalogue('fr_FR', array('domain1' => array('foo' => 'foo'), 'domain2' => array('bar' => 'bar'))); $catalogue->addResource($r); - $catalogue1 = new MessageCatalogue('en', array('domain1' => array('foo' => 'bar', 'foo1' => 'foo1'))); + $catalogue1 = new MessageCatalogue('fr', array('domain1' => array('foo' => 'bar', 'foo1' => 'foo1'))); $catalogue1->addResource($r1); + $catalogue2 = new MessageCatalogue('en'); + $catalogue2->addResource($r2); + $catalogue->addFallbackCatalogue($catalogue1); + $catalogue1->addFallbackCatalogue($catalogue2); $this->assertEquals('foo', $catalogue->get('foo', 'domain1')); $this->assertEquals('foo1', $catalogue->get('foo1', 'domain1')); - $this->assertEquals(array($r, $r1), $catalogue->getResources()); + $this->assertEquals(array($r, $r1, $r2), $catalogue->getResources()); } /** From 9043a551b2f2ebacc00564a249234f2d32df7469 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Mon, 24 Oct 2016 11:16:47 +0200 Subject: [PATCH 060/113] Properly format value in UniqueEntityValidator --- .../Doctrine/Test/DoctrineTestHelper.php | 34 ++++++-- .../Doctrine/Test/TestRepositoryFactory.php | 85 +++++++++++++++++++ .../Tests/Fixtures/SingleIntIdEntity.php | 3 + .../Constraints/UniqueEntityValidatorTest.php | 58 +++++++++++-- .../Constraints/UniqueEntityValidator.php | 2 +- 5 files changed, 166 insertions(+), 16 deletions(-) create mode 100644 src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php diff --git a/src/Symfony/Bridge/Doctrine/Test/DoctrineTestHelper.php b/src/Symfony/Bridge/Doctrine/Test/DoctrineTestHelper.php index 962099e36a7bc..e7f4555d07d2e 100644 --- a/src/Symfony/Bridge/Doctrine/Test/DoctrineTestHelper.php +++ b/src/Symfony/Bridge/Doctrine/Test/DoctrineTestHelper.php @@ -12,6 +12,8 @@ namespace Symfony\Bridge\Doctrine\Test; use Doctrine\Common\Annotations\AnnotationReader; +use Doctrine\Common\Cache\ArrayCache; +use Doctrine\ORM\Configuration; use Doctrine\ORM\Mapping\Driver\AnnotationDriver; use Doctrine\ORM\EntityManager; @@ -25,22 +27,19 @@ class DoctrineTestHelper /** * Returns an entity manager for testing. * + * @param Configuration|null $config + * * @return EntityManager */ - public static function createTestEntityManager() + public static function createTestEntityManager(Configuration $config = null) { if (!extension_loaded('pdo_sqlite')) { \PHPUnit_Framework_TestCase::markTestSkipped('Extension pdo_sqlite is required.'); } - $config = new \Doctrine\ORM\Configuration(); - $config->setEntityNamespaces(array('SymfonyTestsDoctrine' => 'Symfony\Bridge\Doctrine\Tests\Fixtures')); - $config->setAutoGenerateProxyClasses(true); - $config->setProxyDir(\sys_get_temp_dir()); - $config->setProxyNamespace('SymfonyTests\Doctrine'); - $config->setMetadataDriverImpl(new AnnotationDriver(new AnnotationReader())); - $config->setQueryCacheImpl(new \Doctrine\Common\Cache\ArrayCache()); - $config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache()); + if (null === $config) { + $config = self::createTestConfiguration(); + } $params = array( 'driver' => 'pdo_sqlite', @@ -50,6 +49,23 @@ public static function createTestEntityManager() return EntityManager::create($params, $config); } + /** + * @return Configuration + */ + public static function createTestConfiguration() + { + $config = new Configuration(); + $config->setEntityNamespaces(array('SymfonyTestsDoctrine' => 'Symfony\Bridge\Doctrine\Tests\Fixtures')); + $config->setAutoGenerateProxyClasses(true); + $config->setProxyDir(\sys_get_temp_dir()); + $config->setProxyNamespace('SymfonyTests\Doctrine'); + $config->setMetadataDriverImpl(new AnnotationDriver(new AnnotationReader())); + $config->setQueryCacheImpl(new ArrayCache()); + $config->setMetadataCacheImpl(new ArrayCache()); + + return $config; + } + /** * This class cannot be instantiated. */ diff --git a/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php b/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php new file mode 100644 index 0000000000000..b94a095f35418 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php @@ -0,0 +1,85 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Test; + +use Doctrine\Common\Persistence\ObjectRepository; +use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\Repository\RepositoryFactory; + +/** + * @author Andreas Braun + */ +final class TestRepositoryFactory implements RepositoryFactory +{ + /** + * The list of EntityRepository instances. + * + * @var ObjectRepository[] + */ + private $repositoryList = array(); + + /** + * {@inheritdoc} + */ + public function getRepository(EntityManagerInterface $entityManager, $entityName) + { + $repositoryHash = $this->getRepositoryHash($entityManager, $entityName); + + if (isset($this->repositoryList[$repositoryHash])) { + return $this->repositoryList[$repositoryHash]; + } + + return $this->repositoryList[$repositoryHash] = $this->createRepository($entityManager, $entityName); + } + + /** + * @param EntityManagerInterface $entityManager + * @param string $entityName + * @param ObjectRepository $repository + */ + public function setRepository(EntityManagerInterface $entityManager, $entityName, ObjectRepository $repository) + { + $repositoryHash = $this->getRepositoryHash($entityManager, $entityName); + + $this->repositoryList[$repositoryHash] = $repository; + } + + /** + * Create a new repository instance for an entity class. + * + * @param EntityManagerInterface $entityManager The EntityManager instance. + * @param string $entityName The name of the entity. + * + * @return ObjectRepository + */ + private function createRepository(EntityManagerInterface $entityManager, $entityName) + { + /* @var $metadata ClassMetadata */ + $metadata = $entityManager->getClassMetadata($entityName); + $repositoryClassName = $metadata->customRepositoryClassName + ?: $entityManager->getConfiguration()->getDefaultRepositoryClassName(); + + return new $repositoryClassName($entityManager, $metadata); + } + + /** + * @param EntityManagerInterface $entityManager + * @param string $entityName + * + * @return string + */ + private function getRepositoryHash(EntityManagerInterface $entityManager, $entityName) + { + return $entityManager->getClassMetadata($entityName)->getName().spl_object_hash($entityManager); + } +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleIntIdEntity.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleIntIdEntity.php index 44630a1fc51f1..6ee360e6a10aa 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleIntIdEntity.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleIntIdEntity.php @@ -24,6 +24,9 @@ class SingleIntIdEntity /** @Column(type="string", nullable=true) */ public $name; + /** @Column(type="array", nullable=true) */ + public $phoneNumbers = array(); + public function __construct($id, $name) { $this->id = $id; diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php index 7299f106b8967..2e2f2952e004e 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php @@ -16,6 +16,7 @@ use Doctrine\Common\Persistence\ObjectManager; use Doctrine\Common\Persistence\ObjectRepository; use Symfony\Bridge\Doctrine\Test\DoctrineTestHelper; +use Symfony\Bridge\Doctrine\Test\TestRepositoryFactory; use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity; use Symfony\Bridge\Doctrine\Tests\Fixtures\DoubleNameEntity; use Symfony\Bridge\Doctrine\Tests\Fixtures\AssociationEntity; @@ -48,9 +49,16 @@ class UniqueEntityValidatorTest extends AbstractConstraintValidatorTest */ protected $repository; + protected $repositoryFactory; + protected function setUp() { - $this->em = DoctrineTestHelper::createTestEntityManager(); + $this->repositoryFactory = new TestRepositoryFactory(); + + $config = DoctrineTestHelper::createTestConfiguration(); + $config->setRepositoryFactory($this->repositoryFactory); + + $this->em = DoctrineTestHelper::createTestEntityManager($config); $this->registry = $this->createRegistryMock($this->em); $this->createSchema($this->em); @@ -164,7 +172,7 @@ public function testValidateUniqueness() $this->buildViolation('myMessage') ->atPath('property.path.name') - ->setParameter('{{ value }}', 'Foo') + ->setParameter('{{ value }}', '"Foo"') ->setInvalidValue('Foo') ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); @@ -189,7 +197,7 @@ public function testValidateCustomErrorPath() $this->buildViolation('myMessage') ->atPath('property.path.bar') - ->setParameter('{{ value }}', 'Foo') + ->setParameter('{{ value }}', '"Foo"') ->setInvalidValue('Foo') ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); @@ -242,7 +250,7 @@ public function testValidateUniquenessWithIgnoreNull() $this->buildViolation('myMessage') ->atPath('property.path.name') - ->setParameter('{{ value }}', 'Foo') + ->setParameter('{{ value }}', '"Foo"') ->setInvalidValue('Foo') ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); @@ -275,7 +283,7 @@ public function testValidateUniquenessWithValidCustomErrorPath() $this->buildViolation('myMessage') ->atPath('property.path.name2') - ->setParameter('{{ value }}', 'Bar') + ->setParameter('{{ value }}', '"Bar"') ->setInvalidValue('Bar') ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); @@ -446,7 +454,7 @@ public function testValidateUniquenessNotToStringEntityWithAssociatedEntity() $this->buildViolation('myMessage') ->atPath('property.path.single') - ->setParameter('{{ value }}', $expectedValue) + ->setParameter('{{ value }}', '"'.$expectedValue.'"') ->setInvalidValue($expectedValue) ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); @@ -472,6 +480,44 @@ public function testAssociatedEntityWithNull() $this->assertNoViolation(); } + public function testValidateUniquenessWithArrayValue() + { + $repository = $this->createRepositoryMock(); + $this->repositoryFactory->setRepository($this->em, 'Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity', $repository); + + $constraint = new UniqueEntity(array( + 'message' => 'myMessage', + 'fields' => array('phoneNumbers'), + 'em' => self::EM_NAME, + 'repositoryMethod' => 'findByCustom', + )); + + $entity1 = new SingleIntIdEntity(1, 'foo'); + $entity1->phoneNumbers[] = 123; + + $repository->expects($this->once()) + ->method('findByCustom') + ->will($this->returnValue(array($entity1))) + ; + + $this->em->persist($entity1); + $this->em->flush(); + + $entity2 = new SingleIntIdEntity(2, 'bar'); + $entity2->phoneNumbers[] = 123; + $this->em->persist($entity2); + $this->em->flush(); + + $this->validator->validate($entity2, $constraint); + + $this->buildViolation('myMessage') + ->atPath('property.path.phoneNumbers') + ->setParameter('{{ value }}', 'array') + ->setInvalidValue(array(123)) + ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) + ->assertRaised(); + } + /** * @expectedException \Symfony\Component\Validator\Exception\ConstraintDefinitionException * @expectedExceptionMessage Object manager "foo" does not exist. diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php index 4fd8afff171b3..eb90b78af2f7d 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php +++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php @@ -133,7 +133,7 @@ public function validate($entity, Constraint $constraint) $this->context->buildViolation($constraint->message) ->atPath($errorPath) - ->setParameter('{{ value }}', $invalidValue) + ->setParameter('{{ value }}', $this->formatValue($invalidValue, static::OBJECT_TO_STRING | static::PRETTY_DATE)) ->setInvalidValue($invalidValue) ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->addViolation(); From ba8a12a89867e127829b774744aa95ad3fb64fdd Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 6 Nov 2016 08:20:57 -0800 Subject: [PATCH 061/113] fixed CS --- .../Doctrine/Test/TestRepositoryFactory.php | 21 +------------------ 1 file changed, 1 insertion(+), 20 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php b/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php index b94a095f35418..b7cbafa947aef 100644 --- a/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php +++ b/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php @@ -22,8 +22,6 @@ final class TestRepositoryFactory implements RepositoryFactory { /** - * The list of EntityRepository instances. - * * @var ObjectRepository[] */ private $repositoryList = array(); @@ -42,11 +40,6 @@ public function getRepository(EntityManagerInterface $entityManager, $entityName return $this->repositoryList[$repositoryHash] = $this->createRepository($entityManager, $entityName); } - /** - * @param EntityManagerInterface $entityManager - * @param string $entityName - * @param ObjectRepository $repository - */ public function setRepository(EntityManagerInterface $entityManager, $entityName, ObjectRepository $repository) { $repositoryHash = $this->getRepositoryHash($entityManager, $entityName); @@ -55,29 +48,17 @@ public function setRepository(EntityManagerInterface $entityManager, $entityName } /** - * Create a new repository instance for an entity class. - * - * @param EntityManagerInterface $entityManager The EntityManager instance. - * @param string $entityName The name of the entity. - * * @return ObjectRepository */ private function createRepository(EntityManagerInterface $entityManager, $entityName) { /* @var $metadata ClassMetadata */ $metadata = $entityManager->getClassMetadata($entityName); - $repositoryClassName = $metadata->customRepositoryClassName - ?: $entityManager->getConfiguration()->getDefaultRepositoryClassName(); + $repositoryClassName = $metadata->customRepositoryClassName ?: $entityManager->getConfiguration()->getDefaultRepositoryClassName(); return new $repositoryClassName($entityManager, $metadata); } - /** - * @param EntityManagerInterface $entityManager - * @param string $entityName - * - * @return string - */ private function getRepositoryHash(EntityManagerInterface $entityManager, $entityName) { return $entityManager->getClassMetadata($entityName)->getName().spl_object_hash($entityManager); From 38bf11939b7124cbceba2432613d28b615efb298 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 6 Nov 2016 08:25:04 -0800 Subject: [PATCH 062/113] fixed test --- .../Tests/Validator/Constraints/UniqueEntityValidatorTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php index 6d8e56534ebe9..21d3950313590 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php @@ -597,7 +597,7 @@ public function testValidateInheritanceUniqueness() ->atPath('property.path.name') ->setInvalidValue('Foo') ->setCode('23bd9dbf-6b9b-41cd-a99e-4844bcf3077f') - ->setParameters(array('{{ value }}' => 'Foo')) + ->setParameters(array('{{ value }}' => '"Foo"')) ->assertRaised(); } From a8967ba625f6dda7c707dc5a0c4568a2850861fb Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 6 Nov 2016 08:27:54 -0800 Subject: [PATCH 063/113] fixed deprecation notices --- .../Component/Console/Tests/Helper/QuestionHelperTest.php | 7 ++----- .../Console/Tests/Helper/SymfonyQuestionHelperTest.php | 4 +--- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php index 934a389ca0557..8c753cc7abf13 100644 --- a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php @@ -751,9 +751,7 @@ public function testLegacyChoiceOutputFormattingQuestionForUtf8Keys() public function testAskThrowsExceptionOnMissingInput() { $dialog = new QuestionHelper(); - $dialog->setInputStream($this->getInputStream('')); - - $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), new Question('What\'s your name?')); + $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), new Question('What\'s your name?')); } /** @@ -763,7 +761,6 @@ public function testAskThrowsExceptionOnMissingInput() public function testAskThrowsExceptionOnMissingInputWithValidator() { $dialog = new QuestionHelper(); - $dialog->setInputStream($this->getInputStream('')); $question = new Question('What\'s your name?'); $question->setValidator(function () { @@ -772,7 +769,7 @@ public function testAskThrowsExceptionOnMissingInputWithValidator() } }); - $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question); + $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), $question); } protected function getInputStream($input) diff --git a/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php index 679413c0975b2..4298dd2dff732 100644 --- a/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/SymfonyQuestionHelperTest.php @@ -108,9 +108,7 @@ public function testAskEscapeLabel() public function testAskThrowsExceptionOnMissingInput() { $dialog = new SymfonyQuestionHelper(); - - $dialog->setInputStream($this->getInputStream('')); - $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), new Question('What\'s your name?')); + $dialog->ask($this->createStreamableInputInterfaceMock($this->getInputStream('')), $this->createOutputInterface(), new Question('What\'s your name?')); } protected function getInputStream($input) From 8e70193e99c6dee7ef685bac8a0d08a1cf706c2c Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Sun, 6 Nov 2016 13:41:14 +0100 Subject: [PATCH 064/113] [HttpKernel] Removed forgotten setCacheVersionInfo() --- .../HttpKernel/DataCollector/ConfigDataCollector.php | 6 ------ .../Tests/DataCollector/ConfigDataCollectorTest.php | 1 - 2 files changed, 7 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php index 395fee3929993..13db7c4314809 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/ConfigDataCollector.php @@ -29,7 +29,6 @@ class ConfigDataCollector extends DataCollector private $kernel; private $name; private $version; - private $cacheVersionInfo = true; /** * Constructor. @@ -127,11 +126,6 @@ public function getSymfonyState() return $this->data['symfony_state']; } - public function setCacheVersionInfo($cacheVersionInfo) - { - $this->cacheVersionInfo = $cacheVersionInfo; - } - /** * Gets the PHP version. * diff --git a/src/Symfony/Component/HttpKernel/Tests/DataCollector/ConfigDataCollectorTest.php b/src/Symfony/Component/HttpKernel/Tests/DataCollector/ConfigDataCollectorTest.php index 4a0dc263b7d8a..fea95b4e2b496 100644 --- a/src/Symfony/Component/HttpKernel/Tests/DataCollector/ConfigDataCollectorTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/DataCollector/ConfigDataCollectorTest.php @@ -23,7 +23,6 @@ public function testCollect() { $kernel = new KernelForTest('test', true); $c = new ConfigDataCollector(); - $c->setCacheVersionInfo(false); $c->setKernel($kernel); $c->collect(new Request(), new Response()); From 526b8a04fd1617591c4bb27e6c415de881aa468a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 6 Nov 2016 12:19:52 -0800 Subject: [PATCH 065/113] [TwigBundle] fixed template root path --- .../Compiler/ExtensionPass.php | 15 +++++++++++++++ .../Bundle/TwigBundle/Resources/config/twig.xml | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php index 316cc665a4b94..603cbe8e22ef1 100644 --- a/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php +++ b/src/Symfony/Bundle/TwigBundle/DependencyInjection/Compiler/ExtensionPass.php @@ -66,6 +66,7 @@ public function process(ContainerBuilder $container) if (!$container->has('templating')) { $loader = $container->getDefinition('twig.loader.native_filesystem'); + $loader->replaceArgument(1, $this->getComposerRootDir($container->getParameter('kernel.root_dir'))); $loader->addTag('twig.loader'); $loader->setMethodCalls($container->getDefinition('twig.loader.filesystem')->getMethodCalls()); @@ -91,4 +92,18 @@ public function process(ContainerBuilder $container) $container->getDefinition('twig.extension.expression')->addTag('twig.extension'); } } + + private function getComposerRootDir($rootDir) + { + $dir = $rootDir; + while (!file_exists($dir.'/composer.json')) { + if ($dir === dirname($dir)) { + return $rootDir; + } + + $dir = dirname($dir); + } + + return $dir; + } } diff --git a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml index fd7575ac3fe42..c82cbafbeb953 100644 --- a/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml +++ b/src/Symfony/Bundle/TwigBundle/Resources/config/twig.xml @@ -46,7 +46,7 @@ - %kernel.root_dir% + From 1c0f572d2e97195e55ab2a1db4dcb543e56f19f3 Mon Sep 17 00:00:00 2001 From: Lesnykh Ilia Date: Mon, 7 Nov 2016 10:23:54 +0300 Subject: [PATCH 066/113] Update UPGRADE-2.7.md --- UPGRADE-2.7.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/UPGRADE-2.7.md b/UPGRADE-2.7.md index 5de67ebede36c..1cf3d3df7f4dc 100644 --- a/UPGRADE-2.7.md +++ b/UPGRADE-2.7.md @@ -40,7 +40,7 @@ Form ---- * In form types and extension overriding the "setDefaultOptions" of the - AbstractType or AbstractExtensionType has been deprecated in favor of + AbstractType or AbstractTypeExtension has been deprecated in favor of overriding the new "configureOptions" method. The method "setDefaultOptions(OptionsResolverInterface $resolver)" will From b2fa7c4f0772b0729892055fdbfaaff51e78bf6e Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Mon, 7 Nov 2016 13:32:19 +0100 Subject: [PATCH 067/113] Revert "bug #20184 [FrameworkBundle] Convert null prefix to an empty string in translation:update (chalasr)" This reverts commit 3f650f864cdd041d668336d917c6cfb2bbe4f156, reversing changes made to 962248dbd949421c9a6f66b43827395adaea4180. --- .../FrameworkBundle/Command/TranslationUpdateCommand.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php index 920c50c1d793f..f310613d10315 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php @@ -118,9 +118,8 @@ protected function execute(InputInterface $input, OutputInterface $output) // load any messages from templates $extractedCatalogue = new MessageCatalogue($input->getArgument('locale')); $output->text('Parsing templates'); - $prefix = $input->getOption('prefix'); $extractor = $this->getContainer()->get('translation.extractor'); - $extractor->setPrefix(null === $prefix ? '' : $prefix); + $extractor->setPrefix($input->getOption('prefix')); foreach ($transPaths as $path) { $path .= 'views'; if (is_dir($path)) { From a2c0a785c2eaf4425c1b79d6cd080404d34c28b1 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Sat, 22 Oct 2016 10:49:12 +0000 Subject: [PATCH 068/113] [HttpFoundation] Avoid implicit null to array conversion in request matcher --- .../HttpFoundation/RequestMatcher.php | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/RequestMatcher.php b/src/Symfony/Component/HttpFoundation/RequestMatcher.php index ca094ca16293a..aa4f67b58bb43 100644 --- a/src/Symfony/Component/HttpFoundation/RequestMatcher.php +++ b/src/Symfony/Component/HttpFoundation/RequestMatcher.php @@ -19,22 +19,22 @@ class RequestMatcher implements RequestMatcherInterface { /** - * @var string + * @var string|null */ private $path; /** - * @var string + * @var string|null */ private $host; /** - * @var array + * @var string[] */ private $methods = array(); /** - * @var string + * @var string[] */ private $ips = array(); @@ -76,13 +76,13 @@ public function __construct($path = null, $host = null, $methods = null, $ips = */ public function matchScheme($scheme) { - $this->schemes = array_map('strtolower', (array) $scheme); + $this->schemes = null !== $scheme ? array_map('strtolower', (array) $scheme) : array(); } /** * Adds a check for the URL host name. * - * @param string $regexp A Regexp + * @param string|null $regexp A Regexp */ public function matchHost($regexp) { @@ -92,7 +92,7 @@ public function matchHost($regexp) /** * Adds a check for the URL path info. * - * @param string $regexp A Regexp + * @param string|null $regexp A Regexp */ public function matchPath($regexp) { @@ -112,21 +112,21 @@ public function matchIp($ip) /** * Adds a check for the client IP. * - * @param string|string[] $ips A specific IP address or a range specified using IP/netmask like 192.168.1.0/24 + * @param string|string[]|null $ips A specific IP address or a range specified using IP/netmask like 192.168.1.0/24 */ public function matchIps($ips) { - $this->ips = (array) $ips; + $this->ips = null !== $ips ? (array) $ips : array(); } /** * Adds a check for the HTTP method. * - * @param string|string[] $method An HTTP method or an array of HTTP methods + * @param string|string[]|null $method An HTTP method or an array of HTTP methods */ public function matchMethod($method) { - $this->methods = array_map('strtoupper', (array) $method); + $this->methods = null !== $method ? array_map('strtoupper', (array) $method) : array(); } /** @@ -145,11 +145,11 @@ public function matchAttribute($key, $regexp) */ public function matches(Request $request) { - if ($this->schemes && !in_array($request->getScheme(), $this->schemes)) { + if ($this->schemes && !in_array($request->getScheme(), $this->schemes, true)) { return false; } - if ($this->methods && !in_array($request->getMethod(), $this->methods)) { + if ($this->methods && !in_array($request->getMethod(), $this->methods, true)) { return false; } From adbc529b7b355e93b00c2f8db0a1c843c5c646c5 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 7 Nov 2016 19:42:43 +0100 Subject: [PATCH 069/113] prefer getSourceContext() over getSource() --- .../Twig/Tests/Extension/TranslationExtensionTest.php | 2 +- src/Symfony/Bridge/Twig/TwigEngine.php | 4 ++-- .../Bundle/TwigBundle/Controller/ExceptionController.php | 4 ++-- .../HttpKernel/Fragment/HIncludeFragmentRenderer.php | 8 ++++++-- 4 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php index 0235c4da327a0..e96bd4f9a3bef 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/TranslationExtensionTest.php @@ -36,7 +36,7 @@ public function testTrans($template, $expected, array $variables = array()) $twig = new \Twig_Environment($loader, array('debug' => true, 'cache' => false)); $twig->addExtension(new TranslationExtension(new Translator('en', new MessageSelector()))); - echo $twig->compile($twig->parse($twig->tokenize(new \Twig_Source($twig->getLoader()->getSource('index'), 'index'))))."\n\n"; + echo $twig->compile($twig->parse($twig->tokenize($twig->getLoader()->getSourceContext('index'))))."\n\n"; $this->assertEquals($expected, $this->getTemplate($template)->render($variables)); } diff --git a/src/Symfony/Bridge/Twig/TwigEngine.php b/src/Symfony/Bridge/Twig/TwigEngine.php index 3e3257e7fa0f5..1ac9d0102e63b 100644 --- a/src/Symfony/Bridge/Twig/TwigEngine.php +++ b/src/Symfony/Bridge/Twig/TwigEngine.php @@ -75,14 +75,14 @@ public function exists($name) $loader = $this->environment->getLoader(); - if ($loader instanceof \Twig_ExistsLoaderInterface) { + if ($loader instanceof \Twig_ExistsLoaderInterface || method_exists($loader, 'exists')) { return $loader->exists((string) $name); } try { // cast possible TemplateReferenceInterface to string because the // EngineInterface supports them but Twig_LoaderInterface does not - $loader->getSource((string) $name); + $loader->getSourceContext((string) $name)->getCode(); } catch (\Twig_Error_Loader $e) { return false; } diff --git a/src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php b/src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php index 3eec8d6be92ec..b6972fc6354cd 100644 --- a/src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php +++ b/src/Symfony/Bundle/TwigBundle/Controller/ExceptionController.php @@ -131,12 +131,12 @@ protected function templateExists($template) $template = (string) $template; $loader = $this->twig->getLoader(); - if ($loader instanceof \Twig_ExistsLoaderInterface) { + if ($loader instanceof \Twig_ExistsLoaderInterface || method_exists($loader, 'exists')) { return $loader->exists($template); } try { - $loader->getSource($template); + $loader->getSourceContext($template)->getCode(); return true; } catch (\Twig_Error_Loader $e) { diff --git a/src/Symfony/Component/HttpKernel/Fragment/HIncludeFragmentRenderer.php b/src/Symfony/Component/HttpKernel/Fragment/HIncludeFragmentRenderer.php index 56c96b3ceda3f..27051cfb772ee 100644 --- a/src/Symfony/Component/HttpKernel/Fragment/HIncludeFragmentRenderer.php +++ b/src/Symfony/Component/HttpKernel/Fragment/HIncludeFragmentRenderer.php @@ -140,12 +140,16 @@ private function templateExists($template) } $loader = $this->templating->getLoader(); - if ($loader instanceof \Twig_ExistsLoaderInterface) { + if ($loader instanceof \Twig_ExistsLoaderInterface || method_exists($loader, 'exists')) { return $loader->exists($template); } try { - $loader->getSource($template); + if (method_exists($loader, 'getSourceContext')) { + $loader->getSourceContext($template); + } else { + $loader->getSource($template); + } return true; } catch (\Twig_Error_Loader $e) { From bdd3f95da64e6ed1279e530381dc51fe6eeae673 Mon Sep 17 00:00:00 2001 From: Tobias Nyholm Date: Tue, 16 Aug 2016 13:13:16 +0200 Subject: [PATCH 070/113] Make the Workflow support State Machines --- .../Compiler/ValidateWorkflowsPass.php | 77 ++++++++++++ .../DependencyInjection/Configuration.php | 4 + .../FrameworkExtension.php | 24 +++- .../FrameworkBundle/FrameworkBundle.php | 2 + .../Resources/config/workflow.xml | 6 + src/Symfony/Component/Workflow/Definition.php | 5 +- .../Workflow/Dumper/GraphvizDumper.php | 11 +- .../Exception/InvalidDefinitionException.php | 21 ++++ .../MarkingStore/ScalarMarkingStore.php | 2 +- .../UniqueTransitionOutputInterface.php | 21 ---- .../Component/Workflow/StateMachine.php | 18 +++ .../Workflow/Tests/DefinitionTest.php | 2 +- .../Component/Workflow/Tests/RegistryTest.php | 8 +- .../Workflow/Tests/StateMachineTest.php | 75 ++++++++++++ .../SinglePlaceWorkflowValidatorTest.php | 33 ++++++ .../Validator/StateMachineValidatorTest.php | 108 +++++++++++++++++ .../Component/Workflow/Tests/WorkflowTest.php | 31 +---- .../DefinitionValidatorInterface.php | 31 +++++ .../SinglePlaceWorkflowValidator.php | 41 +++++++ .../Validator/StateMachineValidator.php | 68 +++++++++++ .../Workflow/Validator/WorkflowValidator.php | 24 ++++ src/Symfony/Component/Workflow/Workflow.php | 111 +++++++++++------- 22 files changed, 619 insertions(+), 104 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ValidateWorkflowsPass.php create mode 100644 src/Symfony/Component/Workflow/Exception/InvalidDefinitionException.php delete mode 100644 src/Symfony/Component/Workflow/MarkingStore/UniqueTransitionOutputInterface.php create mode 100644 src/Symfony/Component/Workflow/StateMachine.php create mode 100644 src/Symfony/Component/Workflow/Tests/StateMachineTest.php create mode 100644 src/Symfony/Component/Workflow/Tests/Validator/SinglePlaceWorkflowValidatorTest.php create mode 100644 src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php create mode 100644 src/Symfony/Component/Workflow/Validator/DefinitionValidatorInterface.php create mode 100644 src/Symfony/Component/Workflow/Validator/SinglePlaceWorkflowValidator.php create mode 100644 src/Symfony/Component/Workflow/Validator/StateMachineValidator.php create mode 100644 src/Symfony/Component/Workflow/Validator/WorkflowValidator.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ValidateWorkflowsPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ValidateWorkflowsPass.php new file mode 100644 index 0000000000000..4f1024e2c4854 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ValidateWorkflowsPass.php @@ -0,0 +1,77 @@ + + * + * 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; +use Symfony\Component\DependencyInjection\Exception\RuntimeException; +use Symfony\Component\Workflow\Validator\DefinitionValidatorInterface; +use Symfony\Component\Workflow\Validator\SinglePlaceWorkflowValidator; +use Symfony\Component\Workflow\Validator\StateMachineValidator; +use Symfony\Component\Workflow\Validator\WorkflowValidator; + +/** + * @author Tobias Nyholm + */ +class ValidateWorkflowsPass implements CompilerPassInterface +{ + /** + * @var DefinitionValidatorInterface[] + */ + private $validators = array(); + + public function process(ContainerBuilder $container) + { + $taggedServices = $container->findTaggedServiceIds('workflow.definition'); + foreach ($taggedServices as $id => $tags) { + $definition = $container->get($id); + foreach ($tags as $tag) { + if (empty($tag['name'])) { + throw new RuntimeException(sprintf('The "name" for the tag "workflow.definition" of service "%s" must be set.', $id)); + } + if (empty($tag['type'])) { + throw new RuntimeException(sprintf('The "type" for the tag "workflow.definition" of service "%s" must be set.', $id)); + } + if (empty($tag['marking_store'])) { + throw new RuntimeException(sprintf('The "marking_store" for the tag "workflow.definition" of service "%s" must be set.', $id)); + } + + $this->getValidator($tag)->validate($definition, $tag['name']); + } + } + } + + /** + * @param array $tag + * + * @return DefinitionValidatorInterface + */ + private function getValidator($tag) + { + if ($tag['type'] === 'state_machine') { + $name = 'state_machine'; + $class = StateMachineValidator::class; + } elseif ($tag['marking_store'] === 'scalar') { + $name = 'single_place'; + $class = SinglePlaceWorkflowValidator::class; + } else { + $name = 'workflow'; + $class = WorkflowValidator::class; + } + + if (empty($this->validators[$name])) { + $this->validators[$name] = new $class(); + } + + return $this->validators[$name]; + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index c17822a3bf0ec..460e2a860f808 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -236,6 +236,10 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->useAttributeAsKey('name') ->prototype('array') ->children() + ->enumNode('type') + ->values(array('workflow', 'state_machine')) + ->defaultValue('workflow') + ->end() ->arrayNode('marking_store') ->isRequired() ->children() diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 1ea7441fadd04..3a1f0f029a483 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -404,10 +404,20 @@ private function registerWorkflowConfiguration(array $workflows, ContainerBuilde $registryDefinition = $container->getDefinition('workflow.registry'); foreach ($workflows as $name => $workflow) { + $type = $workflow['type']; + $definitionDefinition = new Definition(Workflow\Definition::class); $definitionDefinition->addMethodCall('addPlaces', array($workflow['places'])); foreach ($workflow['transitions'] as $transitionName => $transition) { - $definitionDefinition->addMethodCall('addTransition', array(new Definition(Workflow\Transition::class, array($transitionName, $transition['from'], $transition['to'])))); + if ($type === 'workflow') { + $definitionDefinition->addMethodCall('addTransition', array(new Definition(Workflow\Transition::class, array($transitionName, $transition['from'], $transition['to'])))); + } elseif ($type === 'state_machine') { + foreach ($transition['from'] as $from) { + foreach ($transition['to'] as $to) { + $definitionDefinition->addMethodCall('addTransition', array(new Definition(Workflow\Transition::class, array($transitionName, $from, $to)))); + } + } + } } if (isset($workflow['marking_store']['type'])) { @@ -419,13 +429,21 @@ private function registerWorkflowConfiguration(array $workflows, ContainerBuilde $markingStoreDefinition = new Reference($workflow['marking_store']['service']); } - $workflowDefinition = new DefinitionDecorator('workflow.abstract'); + $definitionDefinition->addTag('workflow.definition', array( + 'name' => $name, + 'type' => $type, + 'marking_store' => isset($workflow['marking_store']['type']) ? $workflow['marking_store']['type'] : null, + )); + $definitionDefinition->setPublic(false); + + $workflowDefinition = new DefinitionDecorator(sprintf('%s.abstract', $type)); $workflowDefinition->replaceArgument(0, $definitionDefinition); $workflowDefinition->replaceArgument(1, $markingStoreDefinition); $workflowDefinition->replaceArgument(3, $name); - $workflowId = 'workflow.'.$name; + $workflowId = sprintf('%s.%s', $type, $name); + $container->setDefinition(sprintf('%s.definition', $workflowId), $definitionDefinition); $container->setDefinition($workflowId, $workflowDefinition); foreach ($workflow['supports'] as $supportedClass) { diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index a736c091a1071..72873aa6e97e8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -35,6 +35,7 @@ use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\SerializerPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\UnusedTagsPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ConfigCachePass; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ValidateWorkflowsPass; use Symfony\Component\Debug\ErrorHandler; use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Compiler\PassConfig; @@ -93,6 +94,7 @@ public function build(ContainerBuilder $container) $container->addCompilerPass(new PropertyInfoPass()); $container->addCompilerPass(new ControllerArgumentValueResolverPass()); $container->addCompilerPass(new CachePoolPass()); + $container->addCompilerPass(new ValidateWorkflowsPass()); $container->addCompilerPass(new CachePoolClearerPass(), PassConfig::TYPE_AFTER_REMOVING); if ($container->getParameter('kernel.debug')) { diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml index d37b5d3e0670d..cb8c132fb014a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml @@ -11,6 +11,12 @@ + + + + + + diff --git a/src/Symfony/Component/Workflow/Definition.php b/src/Symfony/Component/Workflow/Definition.php index 11c04ef52458c..52e1d1ee4c042 100644 --- a/src/Symfony/Component/Workflow/Definition.php +++ b/src/Symfony/Component/Workflow/Definition.php @@ -46,6 +46,9 @@ public function getPlaces() return $this->places; } + /** + * @return Transition[] + */ public function getTransitions() { return $this->transitions; @@ -103,6 +106,6 @@ public function addTransition(Transition $transition) } } - $this->transitions[$name] = $transition; + $this->transitions[] = $transition; } } diff --git a/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php b/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php index 56bbef64aded4..916c4bd460622 100644 --- a/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php +++ b/src/Symfony/Component/Workflow/Dumper/GraphvizDumper.php @@ -83,9 +83,10 @@ private function findTransitions(Definition $definition) { $transitions = array(); - foreach ($definition->getTransitions() as $name => $transition) { - $transitions[$name] = array( + foreach ($definition->getTransitions() as $transition) { + $transitions[] = array( 'attributes' => array('shape' => 'box', 'regular' => true), + 'name' => $transition->getName(), ); } @@ -111,10 +112,10 @@ private function addTransitions(array $transitions) { $code = ''; - foreach ($transitions as $id => $place) { + foreach ($transitions as $place) { $code .= sprintf(" transition_%s [label=\"%s\", shape=box%s];\n", - $this->dotize($id), - $id, + $this->dotize($place['name']), + $place['name'], $this->addAttributes($place['attributes']) ); } diff --git a/src/Symfony/Component/Workflow/Exception/InvalidDefinitionException.php b/src/Symfony/Component/Workflow/Exception/InvalidDefinitionException.php new file mode 100644 index 0000000000000..1f55a49ab38ab --- /dev/null +++ b/src/Symfony/Component/Workflow/Exception/InvalidDefinitionException.php @@ -0,0 +1,21 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Workflow\Exception; + +/** + * Thrown by the DefinitionValidatorInterface when the definition is invalid. + * + * @author Tobias Nyholm + */ +class InvalidDefinitionException extends \LogicException implements ExceptionInterface +{ +} diff --git a/src/Symfony/Component/Workflow/MarkingStore/ScalarMarkingStore.php b/src/Symfony/Component/Workflow/MarkingStore/ScalarMarkingStore.php index c76fb4081c9dd..1c7a36093b518 100644 --- a/src/Symfony/Component/Workflow/MarkingStore/ScalarMarkingStore.php +++ b/src/Symfony/Component/Workflow/MarkingStore/ScalarMarkingStore.php @@ -20,7 +20,7 @@ * * @author Grégoire Pineau */ -class ScalarMarkingStore implements MarkingStoreInterface, UniqueTransitionOutputInterface +class ScalarMarkingStore implements MarkingStoreInterface { private $property; private $propertyAccessor; diff --git a/src/Symfony/Component/Workflow/MarkingStore/UniqueTransitionOutputInterface.php b/src/Symfony/Component/Workflow/MarkingStore/UniqueTransitionOutputInterface.php deleted file mode 100644 index 35c00eb58d101..0000000000000 --- a/src/Symfony/Component/Workflow/MarkingStore/UniqueTransitionOutputInterface.php +++ /dev/null @@ -1,21 +0,0 @@ - - * - * For the full copyright and license information, please view the LICENSE - * file that was distributed with this source code. - */ - -namespace Symfony\Component\Workflow\MarkingStore; - -/** - * UniqueTransitionOutputInterface. - * - * @author Grégoire Pineau - */ -interface UniqueTransitionOutputInterface -{ -} diff --git a/src/Symfony/Component/Workflow/StateMachine.php b/src/Symfony/Component/Workflow/StateMachine.php new file mode 100644 index 0000000000000..0c4e3edc0a6b5 --- /dev/null +++ b/src/Symfony/Component/Workflow/StateMachine.php @@ -0,0 +1,18 @@ + + */ +class StateMachine extends Workflow +{ + public function __construct(Definition $definition, MarkingStoreInterface $markingStore = null, EventDispatcherInterface $dispatcher = null, $name = 'unnamed') + { + parent::__construct($definition, $markingStore ?: new ScalarMarkingStore(), $dispatcher, $name); + } +} diff --git a/src/Symfony/Component/Workflow/Tests/DefinitionTest.php b/src/Symfony/Component/Workflow/Tests/DefinitionTest.php index 9693d01fa3a65..09e594233e99c 100644 --- a/src/Symfony/Component/Workflow/Tests/DefinitionTest.php +++ b/src/Symfony/Component/Workflow/Tests/DefinitionTest.php @@ -55,7 +55,7 @@ public function testAddTransition() $definition = new Definition($places, array($transition)); $this->assertCount(1, $definition->getTransitions()); - $this->assertSame($transition, $definition->getTransitions()['name']); + $this->assertSame($transition, $definition->getTransitions()[0]); } /** diff --git a/src/Symfony/Component/Workflow/Tests/RegistryTest.php b/src/Symfony/Component/Workflow/Tests/RegistryTest.php index 41bfbab8b99e3..42fa8c4ac7c11 100644 --- a/src/Symfony/Component/Workflow/Tests/RegistryTest.php +++ b/src/Symfony/Component/Workflow/Tests/RegistryTest.php @@ -18,9 +18,9 @@ protected function setUp() $this->registry = new Registry(); - $this->registry->add(new Workflow(new Definition(), $this->getMock(MarkingStoreInterface::class), $this->getMock(EventDispatcherInterface::class), 'workflow1'), Subject1::class); - $this->registry->add(new Workflow(new Definition(), $this->getMock(MarkingStoreInterface::class), $this->getMock(EventDispatcherInterface::class), 'workflow2'), Subject2::class); - $this->registry->add(new Workflow(new Definition(), $this->getMock(MarkingStoreInterface::class), $this->getMock(EventDispatcherInterface::class), 'workflow3'), Subject2::class); + $this->registry->add(new Workflow(new Definition(), $this->getMockBuilder(MarkingStoreInterface::class)->getMock(), $this->getMockBuilder(EventDispatcherInterface::class)->getMock(), 'workflow1'), Subject1::class); + $this->registry->add(new Workflow(new Definition(), $this->getMockBuilder(MarkingStoreInterface::class)->getMock(), $this->getMockBuilder(EventDispatcherInterface::class)->getMock(), 'workflow2'), Subject2::class); + $this->registry->add(new Workflow(new Definition(), $this->getMockBuilder(MarkingStoreInterface::class)->getMock(), $this->getMockBuilder(EventDispatcherInterface::class)->getMock(), 'workflow3'), Subject2::class); } protected function tearDown() @@ -55,7 +55,7 @@ public function testGetWithMultipleMatch() } /** - * @expectedException Symfony\Component\Workflow\Exception\InvalidArgumentException + * @expectedException \Symfony\Component\Workflow\Exception\InvalidArgumentException * @expectedExceptionMessage Unable to find a workflow for class "stdClass". */ public function testGetWithNoMatch() diff --git a/src/Symfony/Component/Workflow/Tests/StateMachineTest.php b/src/Symfony/Component/Workflow/Tests/StateMachineTest.php new file mode 100644 index 0000000000000..6aa3c60fc1cc6 --- /dev/null +++ b/src/Symfony/Component/Workflow/Tests/StateMachineTest.php @@ -0,0 +1,75 @@ +marking = 'a'; + $this->assertTrue($net->can($subject, 't1')); + $subject->marking = 'd'; + $this->assertTrue($net->can($subject, 't1')); + + $subject->marking = 'b'; + $this->assertFalse($net->can($subject, 't1')); + + // The graph looks like: + // + // +-------------------------------+ + // v | + // +---+ +----+ +----+ +----+ +---+ +----+ + // | a | --> | t1 | --> | b | --> | t3 | --> | d | --> | t1 | + // +---+ +----+ +----+ +----+ +---+ +----+ + // | + // | + // v + // +----+ +----+ + // | t2 | --> | c | + // +----+ +----+ + } + + public function testCanWithMultipleTransition() + { + $places = array('a', 'b', 'c'); + $transitions[] = new Transition('t1', 'a', 'b'); + $transitions[] = new Transition('t2', 'a', 'c'); + $definition = new Definition($places, $transitions); + + $net = new StateMachine($definition); + $subject = new \stdClass(); + + // If you are in place "a" you should be able to apply "t1" and "t2" + $subject->marking = 'a'; + $this->assertTrue($net->can($subject, 't1')); + $this->assertTrue($net->can($subject, 't2')); + + // The graph looks like: + // + // +----+ +----+ +---+ + // | a | --> | t1 | --> | b | + // +----+ +----+ +---+ + // | + // | + // v + // +----+ +----+ + // | t2 | --> | c | + // +----+ +----+ + } +} diff --git a/src/Symfony/Component/Workflow/Tests/Validator/SinglePlaceWorkflowValidatorTest.php b/src/Symfony/Component/Workflow/Tests/Validator/SinglePlaceWorkflowValidatorTest.php new file mode 100644 index 0000000000000..db433ff0b6dee --- /dev/null +++ b/src/Symfony/Component/Workflow/Tests/Validator/SinglePlaceWorkflowValidatorTest.php @@ -0,0 +1,33 @@ +createComplexWorkflow(); + + (new SinglePlaceWorkflowValidator())->validate($definition, 'foo'); + } + + public function testSinglePlaceWorkflowValidatorAndSimpleWorkflow() + { + $places = array('a', 'b'); + $transition = new Transition('t1', 'a', 'b'); + $definition = new Definition($places, array($transition)); + + (new SinglePlaceWorkflowValidator())->validate($definition, 'foo'); + } +} diff --git a/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php b/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php new file mode 100644 index 0000000000000..17a790f0637c7 --- /dev/null +++ b/src/Symfony/Component/Workflow/Tests/Validator/StateMachineValidatorTest.php @@ -0,0 +1,108 @@ +validate($definition, 'foo'); + + // The graph looks like: + // + // +----+ +----+ +---+ + // | a | --> | t1 | --> | b | + // +----+ +----+ +---+ + // | + // | + // v + // +----+ +----+ + // | t1 | --> | c | + // +----+ +----+ + } + + /** + * @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException + * @expectedExceptionMessage A transition in StateMachine can only have one output. + */ + public function testWithMultipleTos() + { + $places = array('a', 'b', 'c'); + $transitions[] = new Transition('t1', 'a', array('b', 'c')); + $definition = new Definition($places, $transitions); + + (new StateMachineValidator())->validate($definition, 'foo'); + + // The graph looks like: + // + // +---+ +----+ +---+ + // | a | --> | t1 | --> | b | + // +---+ +----+ +---+ + // | + // | + // v + // +----+ + // | c | + // +----+ + } + + /** + * @expectedException \Symfony\Component\Workflow\Exception\InvalidDefinitionException + * @expectedExceptionMessage A transition in StateMachine can only have one input. + */ + public function testWithMultipleFroms() + { + $places = array('a', 'b', 'c'); + $transitions[] = new Transition('t1', array('a', 'b'), 'c'); + $definition = new Definition($places, $transitions); + + (new StateMachineValidator())->validate($definition, 'foo'); + + // The graph looks like: + // + // +---+ +----+ +---+ + // | a | --> | t1 | --> | c | + // +---+ +----+ +---+ + // ^ + // | + // | + // +----+ + // | b | + // +----+ + } + + public function testValid() + { + $places = array('a', 'b', 'c'); + $transitions[] = new Transition('t1', 'a', 'b'); + $transitions[] = new Transition('t2', 'a', 'c'); + $definition = new Definition($places, $transitions); + + (new StateMachineValidator())->validate($definition, 'foo'); + + // The graph looks like: + // + // +----+ +----+ +---+ + // | a | --> | t1 | --> | b | + // +----+ +----+ +---+ + // | + // | + // v + // +----+ +----+ + // | t2 | --> | c | + // +----+ +----+ + } +} diff --git a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php index 22dc1927b8f28..6144de11661fd 100644 --- a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php +++ b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php @@ -8,32 +8,11 @@ use Symfony\Component\Workflow\Marking; use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface; use Symfony\Component\Workflow\MarkingStore\PropertyAccessorMarkingStore; -use Symfony\Component\Workflow\MarkingStore\ScalarMarkingStore; use Symfony\Component\Workflow\Transition; use Symfony\Component\Workflow\Workflow; class WorkflowTest extends \PHPUnit_Framework_TestCase { - /** - * @expectedException \Symfony\Component\Workflow\Exception\LogicException - * @expectedExceptionMessage The marking store (Symfony\Component\Workflow\MarkingStore\ScalarMarkingStore) of workflow "unnamed" can not store many places. But the transition "t1" has too many output (2). Only one is accepted. - */ - public function testConstructorWithUniqueTransitionOutputInterfaceAndComplexWorkflow() - { - $definition = $this->createComplexWorkflow(); - - new Workflow($definition, new ScalarMarkingStore()); - } - - public function testConstructorWithUniqueTransitionOutputInterfaceAndSimpleWorkflow() - { - $places = array('a', 'b'); - $transition = new Transition('t1', 'a', 'b'); - $definition = new Definition($places, array($transition)); - - new Workflow($definition, new ScalarMarkingStore()); - } - /** * @expectedException \Symfony\Component\Workflow\Exception\LogicException * @expectedExceptionMessage The value returned by the MarkingStore is not an instance of "Symfony\Component\Workflow\Marking" for workflow "unnamed". @@ -42,7 +21,7 @@ public function testGetMarkingWithInvalidStoreReturn() { $subject = new \stdClass(); $subject->marking = null; - $workflow = new Workflow(new Definition(), $this->getMock(MarkingStoreInterface::class)); + $workflow = new Workflow(new Definition(), $this->getMockBuilder(MarkingStoreInterface::class)->getMock()); $workflow->getMarking($subject); } @@ -217,16 +196,16 @@ public function testGetEnabledTransitions() $subject->marking = array('d' => true); $transitions = $workflow->getEnabledTransitions($subject); $this->assertCount(2, $transitions); - $this->assertSame('t3', $transitions['t3']->getName()); - $this->assertSame('t4', $transitions['t4']->getName()); + $this->assertSame('t3', $transitions[0]->getName()); + $this->assertSame('t4', $transitions[1]->getName()); $subject->marking = array('c' => true, 'e' => true); $transitions = $workflow->getEnabledTransitions($subject); $this->assertCount(1, $transitions); - $this->assertSame('t5', $transitions['t5']->getName()); + $this->assertSame('t5', $transitions[0]->getName()); } - private function createComplexWorkflow() + protected function createComplexWorkflow() { $definition = new Definition(); diff --git a/src/Symfony/Component/Workflow/Validator/DefinitionValidatorInterface.php b/src/Symfony/Component/Workflow/Validator/DefinitionValidatorInterface.php new file mode 100644 index 0000000000000..09fbc706c74bd --- /dev/null +++ b/src/Symfony/Component/Workflow/Validator/DefinitionValidatorInterface.php @@ -0,0 +1,31 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Workflow\Validator; + +use Symfony\Component\Workflow\Definition; +use Symfony\Component\Workflow\Exception\InvalidDefinitionException; + +/** + * @author Tobias Nyholm + */ +interface DefinitionValidatorInterface +{ + /** + * @param Definition $definition + * @param string $name + * + * @return bool + * + * @throws InvalidDefinitionException on invalid definition + */ + public function validate(Definition $definition, $name); +} diff --git a/src/Symfony/Component/Workflow/Validator/SinglePlaceWorkflowValidator.php b/src/Symfony/Component/Workflow/Validator/SinglePlaceWorkflowValidator.php new file mode 100644 index 0000000000000..6b59db507dff9 --- /dev/null +++ b/src/Symfony/Component/Workflow/Validator/SinglePlaceWorkflowValidator.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Workflow\Validator; + +use Symfony\Component\Workflow\Definition; +use Symfony\Component\Workflow\Exception\InvalidDefinitionException; + +/** + * If the marking can contain only one place, we should control the definition. + * + * @author Tobias Nyholm + */ +class SinglePlaceWorkflowValidator extends WorkflowValidator +{ + public function validate(Definition $definition, $name) + { + foreach ($definition->getTransitions() as $transition) { + if (1 < count($transition->getTos())) { + throw new InvalidDefinitionException( + sprintf( + 'The marking store of workflow "%s" can not store many places. But the transition "%s" has too many output (%d). Only one is accepted.', + $name, + $transition->getName(), + count($transition->getTos()) + ) + ); + } + } + + return parent::validate($definition, $name); + } +} diff --git a/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php b/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php new file mode 100644 index 0000000000000..57dc6322dc82a --- /dev/null +++ b/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php @@ -0,0 +1,68 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Workflow\Validator; + +use Symfony\Component\Workflow\Definition; +use Symfony\Component\Workflow\Exception\InvalidDefinitionException; + +/** + * @author Tobias Nyholm + */ +class StateMachineValidator implements DefinitionValidatorInterface +{ + public function validate(Definition $definition, $name) + { + $transitionFromNames = array(); + foreach ($definition->getTransitions() as $transition) { + // Make sure that each transition has exactly one TO + if (1 !== count($transition->getTos())) { + throw new InvalidDefinitionException( + sprintf( + 'A transition in StateMachine can only have one output. But the transition "%s" in StateMachine "%s" has %d outputs.', + $transition->getName(), + $name, + count($transition->getTos()) + ) + ); + } + + // Make sure that each transition has exactly one FROM + $froms = $transition->getFroms(); + if (1 !== count($froms)) { + throw new InvalidDefinitionException( + sprintf( + 'A transition in StateMachine can only have one input. But the transition "%s" in StateMachine "%s" has %d inputs.', + $transition->getName(), + $name, + count($transition->getTos()) + ) + ); + } + + // Enforcing uniqueness of the names of transitions starting at each node + $from = reset($froms); + if (isset($transitionFromNames[$from][$transition->getName()])) { + throw new InvalidDefinitionException( + sprintf( + 'A transition from a place/state must have an unique name. Multiple transition named "%s" from place/state "%s" where found on StateMachine "%s". ', + $transition->getName(), + $from, + $name + ) + ); + } + $transitionFromNames[$from][$transition->getName()] = true; + } + + return true; + } +} diff --git a/src/Symfony/Component/Workflow/Validator/WorkflowValidator.php b/src/Symfony/Component/Workflow/Validator/WorkflowValidator.php new file mode 100644 index 0000000000000..7d4366fdfb9c3 --- /dev/null +++ b/src/Symfony/Component/Workflow/Validator/WorkflowValidator.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\Component\Workflow\Validator; + +use Symfony\Component\Workflow\Definition; + +/** + * @author Tobias Nyholm + */ +class WorkflowValidator implements DefinitionValidatorInterface +{ + public function validate(Definition $definition, $name) + { + } +} diff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.php index 641fc9e8d80a0..4e83778cf1e69 100644 --- a/src/Symfony/Component/Workflow/Workflow.php +++ b/src/Symfony/Component/Workflow/Workflow.php @@ -16,11 +16,11 @@ use Symfony\Component\Workflow\Event\GuardEvent; use Symfony\Component\Workflow\Exception\LogicException; use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface; -use Symfony\Component\Workflow\MarkingStore\UniqueTransitionOutputInterface; /** * @author Fabien Potencier * @author Grégoire Pineau + * @author Tobias Nyholm */ class Workflow { @@ -35,15 +35,6 @@ public function __construct(Definition $definition, MarkingStoreInterface $marki $this->markingStore = $markingStore; $this->dispatcher = $dispatcher; $this->name = $name; - - // If the marking can contain only one place, we should control the definition - if ($markingStore instanceof UniqueTransitionOutputInterface) { - foreach ($definition->getTransitions() as $transition) { - if (1 < count($transition->getTos())) { - throw new LogicException(sprintf('The marking store (%s) of workflow "%s" can not store many places. But the transition "%s" has too many output (%d). Only one is accepted.', get_class($markingStore), $this->name, $transition->getName(), count($transition->getTos()))); - } - } - } } /** @@ -102,16 +93,10 @@ public function getMarking($subject) */ public function can($subject, $transitionName) { - $transitions = $this->definition->getTransitions(); - - if (!isset($transitions[$transitionName])) { - throw new LogicException(sprintf('Transition "%s" does not exist for workflow "%s".', $transitionName, $this->name)); - } - - $transition = $transitions[$transitionName]; + $transitions = $this->getTransitions($transitionName); $marking = $this->getMarking($subject); - return $this->doCan($subject, $marking, $transition); + return null !== $this->getTransitionForSubject($subject, $marking, $transitions); } /** @@ -127,15 +112,13 @@ public function can($subject, $transitionName) */ public function apply($subject, $transitionName) { - if (!$this->can($subject, $transitionName)) { + $transitions = $this->getTransitions($transitionName); + $marking = $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 "can" method already checks the Marking state - $marking = $this->markingStore->getMarking($subject); - $transition = $this->definition->getTransitions()[$transitionName]; - $this->leave($subject, $transition, $marking); $this->transition($subject, $transition, $marking); @@ -162,8 +145,8 @@ public function getEnabledTransitions($subject) $marking = $this->getMarking($subject); foreach ($this->definition->getTransitions() as $transition) { - if ($this->doCan($subject, $marking, $transition)) { - $enabled[$transition->getName()] = $transition; + if (null !== $this->getTransitionForSubject($subject, $marking, array($transition))) { + $enabled[] = $transition; } } @@ -175,21 +158,13 @@ public function getName() return $this->name; } - 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 + * @param Transition $transition + * + * @return bool|void boolean true if this transition is guarded, ie you cannot use it. + */ private function guardTransition($subject, Marking $marking, Transition $transition) { if (null === $this->dispatcher) { @@ -263,9 +238,61 @@ private function announce($subject, Transition $initialTransition, Marking $mark $event = new Event($subject, $marking, $initialTransition); foreach ($this->definition->getTransitions() as $transition) { - if ($this->doCan($subject, $marking, $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(); + + $namedTransitions = array_filter( + $transitions, + function (Transition $transition) use ($transitionName) { + return $transitionName === $transition->getName(); + } + ); + + if (empty($namedTransitions)) { + throw new LogicException( + sprintf('Transition "%s" does not exist for workflow "%s".', $transitionName, $this->name) + ); + } + + return $namedTransitions; + } + + /** + * 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; + } + } + + return; + } } From 9e491982cfa156c129b4e8f93f50c9c66c45fe9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Mon, 7 Nov 2016 18:57:54 +0100 Subject: [PATCH 071/113] [Workflow] Made the code more robbust and ease on-boarding --- .../Compiler/ValidateWorkflowsPass.php | 6 ++-- .../FrameworkExtension.php | 6 ++-- .../Resources/config/workflow.xml | 4 +-- .../Component/Workflow/Tests/WorkflowTest.php | 8 +++-- .../Validator/StateMachineValidator.php | 2 +- src/Symfony/Component/Workflow/Workflow.php | 31 ++++++++----------- 6 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ValidateWorkflowsPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ValidateWorkflowsPass.php index 4f1024e2c4854..09ad3dd60e711 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ValidateWorkflowsPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ValidateWorkflowsPass.php @@ -35,13 +35,13 @@ public function process(ContainerBuilder $container) foreach ($taggedServices as $id => $tags) { $definition = $container->get($id); foreach ($tags as $tag) { - if (empty($tag['name'])) { + if (!array_key_exists('name', $tag)) { throw new RuntimeException(sprintf('The "name" for the tag "workflow.definition" of service "%s" must be set.', $id)); } - if (empty($tag['type'])) { + if (!array_key_exists('type', $tag)) { throw new RuntimeException(sprintf('The "type" for the tag "workflow.definition" of service "%s" must be set.', $id)); } - if (empty($tag['marking_store'])) { + if (!array_key_exists('marking_store', $tag)) { throw new RuntimeException(sprintf('The "marking_store" for the tag "workflow.definition" of service "%s" must be set.', $id)); } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 3a1f0f029a483..b7cdb631dbc48 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -425,7 +425,7 @@ private function registerWorkflowConfiguration(array $workflows, ContainerBuilde foreach ($workflow['marking_store']['arguments'] as $argument) { $markingStoreDefinition->addArgument($argument); } - } else { + } elseif (isset($workflow['marking_store']['service'])) { $markingStoreDefinition = new Reference($workflow['marking_store']['service']); } @@ -438,7 +438,9 @@ private function registerWorkflowConfiguration(array $workflows, ContainerBuilde $workflowDefinition = new DefinitionDecorator(sprintf('%s.abstract', $type)); $workflowDefinition->replaceArgument(0, $definitionDefinition); - $workflowDefinition->replaceArgument(1, $markingStoreDefinition); + if (isset($markingStoreDefinition)) { + $workflowDefinition->replaceArgument(1, $markingStoreDefinition); + } $workflowDefinition->replaceArgument(3, $name); $workflowId = sprintf('%s.%s', $type, $name); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml index cb8c132fb014a..1314be8b9f316 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml @@ -7,13 +7,13 @@ - + null - + null diff --git a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php index 6144de11661fd..4a7ea56e2180b 100644 --- a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php +++ b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php @@ -113,7 +113,9 @@ public function testCanWithGuard() $subject = new \stdClass(); $subject->marking = null; $eventDispatcher = new EventDispatcher(); - $eventDispatcher->addListener('workflow.workflow_name.guard.t1', function (GuardEvent $event) { $event->setBlocked(true); }); + $eventDispatcher->addListener('workflow.workflow_name.guard.t1', function (GuardEvent $event) { + $event->setBlocked(true); + }); $workflow = new Workflow($definition, new PropertyAccessorMarkingStore(), $eventDispatcher, 'workflow_name'); $this->assertFalse($workflow->can($subject, 't1')); @@ -188,7 +190,9 @@ public function testGetEnabledTransitions() $subject = new \stdClass(); $subject->marking = null; $eventDispatcher = new EventDispatcher(); - $eventDispatcher->addListener('workflow.workflow_name.guard.t1', function (GuardEvent $event) { $event->setBlocked(true); }); + $eventDispatcher->addListener('workflow.workflow_name.guard.t1', function (GuardEvent $event) { + $event->setBlocked(true); + }); $workflow = new Workflow($definition, new PropertyAccessorMarkingStore(), $eventDispatcher, 'workflow_name'); $this->assertEmpty($workflow->getEnabledTransitions($subject)); diff --git a/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php b/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php index 57dc6322dc82a..6f34c1f2f41ab 100644 --- a/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php +++ b/src/Symfony/Component/Workflow/Validator/StateMachineValidator.php @@ -53,7 +53,7 @@ public function validate(Definition $definition, $name) if (isset($transitionFromNames[$from][$transition->getName()])) { throw new InvalidDefinitionException( sprintf( - 'A transition from a place/state must have an unique name. Multiple transition named "%s" from place/state "%s" where found on StateMachine "%s". ', + 'A transition from a place/state must have an unique name. Multiple transitions named "%s" from place/state "%s" where found on StateMachine "%s". ', $transition->getName(), $from, $name diff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.php index 4e83778cf1e69..348b3b95a9a98 100644 --- a/src/Symfony/Component/Workflow/Workflow.php +++ b/src/Symfony/Component/Workflow/Workflow.php @@ -16,6 +16,7 @@ use Symfony\Component\Workflow\Event\GuardEvent; use Symfony\Component\Workflow\Exception\LogicException; use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface; +use Symfony\Component\Workflow\MarkingStore\PropertyAccessorMarkingStore; /** * @author Fabien Potencier @@ -29,10 +30,10 @@ class Workflow private $dispatcher; private $name; - public function __construct(Definition $definition, MarkingStoreInterface $markingStore, EventDispatcherInterface $dispatcher = null, $name = 'unnamed') + public function __construct(Definition $definition, MarkingStoreInterface $markingStore = null, EventDispatcherInterface $dispatcher = null, $name = 'unnamed') { $this->definition = $definition; - $this->markingStore = $markingStore; + $this->markingStore = $markingStore ?: new PropertyAccessorMarkingStore(); $this->dispatcher = $dispatcher; $this->name = $name; } @@ -163,7 +164,7 @@ public function getName() * @param Marking $marking * @param Transition $transition * - * @return bool|void boolean true if this transition is guarded, ie you cannot use it. + * @return bool|void boolean true if this transition is guarded, ie you cannot use it */ private function guardTransition($subject, Marking $marking, Transition $transition) { @@ -253,25 +254,21 @@ private function getTransitions($transitionName) { $transitions = $this->definition->getTransitions(); - $namedTransitions = array_filter( - $transitions, - function (Transition $transition) use ($transitionName) { - return $transitionName === $transition->getName(); - } - ); + $transitions = array_filter($transitions, function (Transition $transition) use ($transitionName) { + return $transitionName === $transition->getName(); + }); - if (empty($namedTransitions)) { - throw new LogicException( - sprintf('Transition "%s" does not exist for workflow "%s".', $transitionName, $this->name) - ); + if (!$transitions) { + throw new LogicException(sprintf('Transition "%s" does not exist for workflow "%s".', $transitionName, $this->name)); } - return $namedTransitions; + 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. + * 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 @@ -292,7 +289,5 @@ private function getTransitionForSubject($subject, Marking $marking, array $tran return $transition; } } - - return; } } From b5a1584c52e08b448fc491f237698f06f04b4b20 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Mon, 7 Nov 2016 13:28:41 +0100 Subject: [PATCH 072/113] [FrameworkBundle] Add --no-prefix option to translation:update Remove ending dot from option description for consistency --- .../FrameworkBundle/Command/TranslationUpdateCommand.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php index 04c9a4d118e4b..c2083e034e32c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationUpdateCommand.php @@ -39,6 +39,7 @@ protected function configure() new InputArgument('locale', InputArgument::REQUIRED, 'The locale'), new InputArgument('bundle', InputArgument::OPTIONAL, 'The bundle name or directory where to load the messages, defaults to app/Resources folder'), new InputOption('prefix', null, InputOption::VALUE_OPTIONAL, 'Override the default prefix', '__'), + new InputOption('no-prefix', null, InputOption::VALUE_NONE, 'If set, no prefix is added to the translations'), new InputOption('output-format', null, InputOption::VALUE_OPTIONAL, 'Override the default output format', 'yml'), new InputOption('dump-messages', null, InputOption::VALUE_NONE, 'Should the messages be dumped in the console'), new InputOption('force', null, InputOption::VALUE_NONE, 'Should the update be done'), @@ -133,7 +134,7 @@ protected function execute(InputInterface $input, OutputInterface $output) $extractedCatalogue = new MessageCatalogue($input->getArgument('locale')); $io->comment('Parsing templates...'); $extractor = $this->getContainer()->get('translation.extractor'); - $extractor->setPrefix($input->getOption('prefix')); + $extractor->setPrefix($input->getOption('no-prefix') ? '' : $input->getOption('prefix')); foreach ($transPaths as $path) { $path .= 'views'; if (is_dir($path)) { From 201603137c761579eeb5b2f5e3c76608285308c3 Mon Sep 17 00:00:00 2001 From: Lesnykh Ilia Date: Tue, 8 Nov 2016 16:51:01 +0300 Subject: [PATCH 073/113] Added single quotes for upgrade guides. --- UPGRADE-2.8.md | 4 ++-- UPGRADE-3.0.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/UPGRADE-2.8.md b/UPGRADE-2.8.md index 957f35b505cff..ae87a131a9d17 100644 --- a/UPGRADE-2.8.md +++ b/UPGRADE-2.8.md @@ -628,7 +628,7 @@ HttpFoundation After: ```php - $request->query->get('foo')[bar]; + $request->query->get('foo')['bar']; ``` Routing @@ -657,4 +657,4 @@ Routing // url generated in @router service $router->generate('blog_show', array('slug' => 'my-blog-post'), UrlGeneratorInterface::ABSOLUTE_URL); - ``` \ No newline at end of file + ``` diff --git a/UPGRADE-3.0.md b/UPGRADE-3.0.md index 68e3780d8ab36..f6bd000ad129d 100644 --- a/UPGRADE-3.0.md +++ b/UPGRADE-3.0.md @@ -1750,5 +1750,5 @@ UPGRADE FROM 2.x to 3.0 After: ```php - $request->query->get('foo')[bar]; + $request->query->get('foo')['bar']; ``` From 93c25f887249ff9944ea02d1fa8aa1f41e97844e Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 8 Nov 2016 09:48:20 +0100 Subject: [PATCH 074/113] [DI] Force env params to be string|null --- .../EnvPlaceholderParameterBag.php | 22 +++++++++++++++++++ .../EnvPlaceholderParameterBagTest.php | 21 ++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/Symfony/Component/DependencyInjection/ParameterBag/EnvPlaceholderParameterBag.php b/src/Symfony/Component/DependencyInjection/ParameterBag/EnvPlaceholderParameterBag.php index be52608cbd864..0e7b116b6c9e8 100644 --- a/src/Symfony/Component/DependencyInjection/ParameterBag/EnvPlaceholderParameterBag.php +++ b/src/Symfony/Component/DependencyInjection/ParameterBag/EnvPlaceholderParameterBag.php @@ -79,4 +79,26 @@ public function mergeEnvPlaceholders(self $bag) } } } + + /** + * {@inheritdoc} + */ + public function resolve() + { + if ($this->resolved) { + return; + } + parent::resolve(); + + foreach ($this->envPlaceholders as $env => $placeholders) { + if (!isset($this->parameters[$name = strtolower("env($env)")])) { + continue; + } + if (is_numeric($default = $this->parameters[$name])) { + $this->parameters[$name] = (string) $default; + } elseif (!is_string($default)) { + throw new RuntimeException(sprintf('The default value of env parameter "%s" must be string or null, %s given.', $env, gettype($default))); + } + } + } } diff --git a/src/Symfony/Component/DependencyInjection/Tests/ParameterBag/EnvPlaceholderParameterBagTest.php b/src/Symfony/Component/DependencyInjection/Tests/ParameterBag/EnvPlaceholderParameterBagTest.php index 6b4d590e85bd9..6f055dab7debe 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ParameterBag/EnvPlaceholderParameterBagTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ParameterBag/EnvPlaceholderParameterBagTest.php @@ -109,4 +109,25 @@ public function testMergeWithDifferentIdentifiersForPlaceholders() $this->assertNotEquals($firstPlaceholder, $secondPlaceholder); $this->assertCount(2, $merged[$envName]); } + + public function testResolveEnvCastsIntToString() + { + $bag = new EnvPlaceholderParameterBag(); + $bag->get('env(INT)'); + $bag->set('env(INT)', 2); + $bag->resolve(); + $this->assertSame('2', $bag->all()['env(int)']); + } + + /** + * @expectedException \Symfony\Component\DependencyInjection\Exception\RuntimeException + * @expectedExceptionMessage The default value of env parameter "ARRAY" must be string or null, array given. + */ + public function testResolveThrowsOnBadDefaultValue() + { + $bag = new EnvPlaceholderParameterBag(); + $bag->get('env(ARRAY)'); + $bag->set('env(ARRAY)', array()); + $bag->resolve(); + } } From 4fcce4c465f64e8de3c42f1622293cdf600ccac0 Mon Sep 17 00:00:00 2001 From: HeahDude Date: Wed, 9 Nov 2016 13:53:14 +0100 Subject: [PATCH 075/113] [FrameworkBundle] Fixed WorkflowCommand to support state machines --- .../Command/WorkflowDumpCommand.php | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php index d1b4e2a766d6e..14bb2ced1a90b 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php @@ -16,6 +16,7 @@ use Symfony\Component\Console\Output\OutputInterface; use Symfony\Component\Workflow\Dumper\GraphvizDumper; use Symfony\Component\Workflow\Marking; +use Symfony\Component\Workflow\Workflow; /** * @author Grégoire Pineau @@ -55,7 +56,16 @@ protected function configure() */ protected function execute(InputInterface $input, OutputInterface $output) { - $workflow = $this->getContainer()->get('workflow.'.$input->getArgument('name')); + $container = $this->getContainer(); + $serviceId = $input->getArgument('name'); + if ($container->has('workflow.'.$serviceId)) { + $workflow = $container->get('workflow.'.$serviceId); + } elseif ($container->has('state_machine.'.$serviceId)) { + $workflow = $container->get('state_machine.'.$serviceId); + } else { + throw new \InvalidArgumentException(sprintf('No service found for "workflow.%1$s" nor "state_machine.%1$s".', $serviceId)); + } + $definition = $this->getProperty($workflow, 'definition'); $dumper = new GraphvizDumper(); @@ -70,7 +80,7 @@ protected function execute(InputInterface $input, OutputInterface $output) private function getProperty($object, $property) { - $reflectionProperty = new \ReflectionProperty(get_class($object), $property); + $reflectionProperty = new \ReflectionProperty(Workflow::class, $property); $reflectionProperty->setAccessible(true); return $reflectionProperty->getValue($object); From 6d4a658ab7a6860f1106565aa1d97f004d37dd56 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 9 Nov 2016 12:04:28 +0100 Subject: [PATCH 076/113] [Cache] Make directory hashing case insensitive --- .../DependencyInjection/Compiler/CachePoolPass.php | 2 +- .../DependencyInjection/FrameworkExtension.php | 2 +- .../DependencyInjection/Compiler/CachePoolPassTest.php | 4 ++-- src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php index 49e97b73c6402..1748862219ddf 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/CachePoolPass.php @@ -84,7 +84,7 @@ public function process(ContainerBuilder $container) private function getNamespace($namespaceSuffix, $id) { - return substr(str_replace('/', '-', base64_encode(md5($id.$namespaceSuffix, true))), 0, 10); + return substr(str_replace('/', '-', base64_encode(hash('sha256', $id.$namespaceSuffix, true))), 0, 10); } /** diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 3a2e40dcf60c3..9e9d797191a4e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -1037,7 +1037,7 @@ private function registerPropertyInfoConfiguration(array $config, ContainerBuild private function registerCacheConfiguration(array $config, ContainerBuilder $container) { - $version = substr(str_replace('/', '-', base64_encode(md5(uniqid(mt_rand(), true), true))), 0, -2); + $version = substr(str_replace('/', '-', base64_encode(hash('sha256', uniqid(mt_rand(), true), true))), 0, 22); $container->getDefinition('cache.adapter.apcu')->replaceArgument(2, $version); $container->getDefinition('cache.adapter.system')->replaceArgument(2, $version); $container->getDefinition('cache.adapter.filesystem')->replaceArgument(2, $config['directory']); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolPassTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolPassTest.php index 1f77cdd0fe60b..53cb95837f7e8 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolPassTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Compiler/CachePoolPassTest.php @@ -41,7 +41,7 @@ public function testNamespaceArgumentIsReplaced() $this->cachePoolPass->process($container); - $this->assertSame('VcRIZlUhEv', $cachePool->getArgument(0)); + $this->assertSame('kRFqMp5odS', $cachePool->getArgument(0)); } public function testArgsAreReplaced() @@ -61,7 +61,7 @@ public function testArgsAreReplaced() $this->assertInstanceOf(Reference::class, $cachePool->getArgument(0)); $this->assertSame('foobar', (string) $cachePool->getArgument(0)); - $this->assertSame('VcRIZlUhEv', $cachePool->getArgument(1)); + $this->assertSame('kRFqMp5odS', $cachePool->getArgument(1)); $this->assertSame(3, $cachePool->getArgument(2)); } diff --git a/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php b/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php index 4734f71ee2a1f..81886b4d11a54 100644 --- a/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php +++ b/src/Symfony/Component/Cache/Adapter/FilesystemAdapter.php @@ -146,13 +146,13 @@ protected function doSave(array $values, $lifetime) private function getFile($id, $mkdir = false) { - $hash = str_replace('/', '-', base64_encode(md5($id, true))); - $dir = $this->directory.$hash[0].DIRECTORY_SEPARATOR.$hash[1].DIRECTORY_SEPARATOR; + $hash = str_replace('/', '-', base64_encode(hash('sha256', $id, true))); + $dir = $this->directory.strtoupper($hash[0].DIRECTORY_SEPARATOR.$hash[1].DIRECTORY_SEPARATOR); if ($mkdir && !file_exists($dir)) { @mkdir($dir, 0777, true); } - return $dir.substr($hash, 2, -2); + return $dir.substr($hash, 2, 20); } } From ffaeba39fc0013539be4bd969e29540b1817dceb Mon Sep 17 00:00:00 2001 From: Tobias Nyholm Date: Tue, 8 Nov 2016 20:01:05 +0100 Subject: [PATCH 077/113] [Workflow] Added Definition builder --- .../Command/WorkflowDumpCommand.php | 14 +-- .../FrameworkExtension.php | 33 ++++--- src/Symfony/Component/Workflow/Definition.php | 36 ++++--- .../Component/Workflow/DefinitionBuilder.php | 93 +++++++++++++++++++ .../Workflow/Tests/DefinitionBuilderTest.php | 54 +++++++++++ .../Workflow/Tests/DefinitionTest.php | 12 +-- .../Tests/Dumper/GraphvizDumperTest.php | 36 +++---- .../Component/Workflow/Tests/RegistryTest.php | 6 +- .../Component/Workflow/Tests/WorkflowTest.php | 25 ++--- src/Symfony/Component/Workflow/Workflow.php | 8 ++ 10 files changed, 237 insertions(+), 80 deletions(-) create mode 100644 src/Symfony/Component/Workflow/DefinitionBuilder.php create mode 100644 src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php index 14bb2ced1a90b..ddfb987ff1937 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/WorkflowDumpCommand.php @@ -66,23 +66,13 @@ protected function execute(InputInterface $input, OutputInterface $output) throw new \InvalidArgumentException(sprintf('No service found for "workflow.%1$s" nor "state_machine.%1$s".', $serviceId)); } - $definition = $this->getProperty($workflow, 'definition'); - $dumper = new GraphvizDumper(); - $marking = new Marking(); + foreach ($input->getArgument('marking') as $place) { $marking->mark($place); } - $output->writeln($dumper->dump($definition, $marking)); - } - - private function getProperty($object, $property) - { - $reflectionProperty = new \ReflectionProperty(Workflow::class, $property); - $reflectionProperty->setAccessible(true); - - return $reflectionProperty->getValue($object); + $output->writeln($dumper->dump($workflow->getDefinition(), $marking)); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index b7cdb631dbc48..732106c84523c 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -406,20 +406,32 @@ private function registerWorkflowConfiguration(array $workflows, ContainerBuilde foreach ($workflows as $name => $workflow) { $type = $workflow['type']; - $definitionDefinition = new Definition(Workflow\Definition::class); - $definitionDefinition->addMethodCall('addPlaces', array($workflow['places'])); + // Create a DefinitionBuilder + $definitionBuilderDefinition = new Definition(Workflow\DefinitionBuilder::class); + $definitionBuilderDefinition->addMethodCall('addPlaces', array($workflow['places'])); foreach ($workflow['transitions'] as $transitionName => $transition) { if ($type === 'workflow') { - $definitionDefinition->addMethodCall('addTransition', array(new Definition(Workflow\Transition::class, array($transitionName, $transition['from'], $transition['to'])))); + $definitionBuilderDefinition->addMethodCall('addTransition', array(new Definition(Workflow\Transition::class, array($transitionName, $transition['from'], $transition['to'])))); } elseif ($type === 'state_machine') { foreach ($transition['from'] as $from) { foreach ($transition['to'] as $to) { - $definitionDefinition->addMethodCall('addTransition', array(new Definition(Workflow\Transition::class, array($transitionName, $from, $to)))); + $definitionBuilderDefinition->addMethodCall('addTransition', array(new Definition(Workflow\Transition::class, array($transitionName, $from, $to)))); } } } } + // Create a Definition + $definitionDefinition = new Definition(Workflow\Definition::class); + $definitionDefinition->setPublic(false); + $definitionDefinition->setFactory(array($definitionBuilderDefinition, 'build')); + $definitionDefinition->addTag('workflow.definition', array( + 'name' => $name, + 'type' => $type, + 'marking_store' => isset($workflow['marking_store']['type']) ? $workflow['marking_store']['type'] : null, + )); + + // Create MarkingStore if (isset($workflow['marking_store']['type'])) { $markingStoreDefinition = new DefinitionDecorator('workflow.marking_store.'.$workflow['marking_store']['type']); foreach ($workflow['marking_store']['arguments'] as $argument) { @@ -429,13 +441,7 @@ private function registerWorkflowConfiguration(array $workflows, ContainerBuilde $markingStoreDefinition = new Reference($workflow['marking_store']['service']); } - $definitionDefinition->addTag('workflow.definition', array( - 'name' => $name, - 'type' => $type, - 'marking_store' => isset($workflow['marking_store']['type']) ? $workflow['marking_store']['type'] : null, - )); - $definitionDefinition->setPublic(false); - + // Create Workflow $workflowDefinition = new DefinitionDecorator(sprintf('%s.abstract', $type)); $workflowDefinition->replaceArgument(0, $definitionDefinition); if (isset($markingStoreDefinition)) { @@ -443,11 +449,12 @@ private function registerWorkflowConfiguration(array $workflows, ContainerBuilde } $workflowDefinition->replaceArgument(3, $name); + // Store to container $workflowId = sprintf('%s.%s', $type, $name); - - $container->setDefinition(sprintf('%s.definition', $workflowId), $definitionDefinition); $container->setDefinition($workflowId, $workflowDefinition); + $container->setDefinition(sprintf('%s.definition', $workflowId), $definitionDefinition); + // Add workflow to Registry foreach ($workflow['supports'] as $supportedClass) { $registryDefinition->addMethodCall('add', array(new Reference($workflowId), $supportedClass)); } diff --git a/src/Symfony/Component/Workflow/Definition.php b/src/Symfony/Component/Workflow/Definition.php index 52e1d1ee4c042..6250bf57d2190 100644 --- a/src/Symfony/Component/Workflow/Definition.php +++ b/src/Symfony/Component/Workflow/Definition.php @@ -17,8 +17,9 @@ /** * @author Fabien Potencier * @author Grégoire Pineau + * @author Tobias Nyholm */ -class Definition +final class Definition { private $places = array(); private $transitions = array(); @@ -29,18 +30,28 @@ class Definition * * @param string[] $places * @param Transition[] $transitions + * @param string|null $initialPlace */ - public function __construct(array $places = array(), array $transitions = array()) + public function __construct(array $places, array $transitions, $initialPlace = null) { $this->addPlaces($places); - $this->addTransitions($transitions); + $this->setInitialPlace($initialPlace); + foreach ($transitions as $transition) { + $this->addTransition($transition); + } } + /** + * @return string|null + */ public function getInitialPlace() { return $this->initialPlace; } + /** + * @return string[] + */ public function getPlaces() { return $this->places; @@ -54,8 +65,12 @@ public function getTransitions() return $this->transitions; } - public function setInitialPlace($place) + private function setInitialPlace($place) { + if (null === $place) { + return; + } + if (!isset($this->places[$place])) { throw new LogicException(sprintf('Place "%s" cannot be the initial place as it does not exist.', $place)); } @@ -63,7 +78,7 @@ public function setInitialPlace($place) $this->initialPlace = $place; } - public function addPlace($place) + private function addPlace($place) { if (!preg_match('{^[\w\d_-]+$}', $place)) { throw new InvalidArgumentException(sprintf('The place "%s" contains invalid characters.', $place)); @@ -76,21 +91,14 @@ public function addPlace($place) $this->places[$place] = $place; } - public function addPlaces(array $places) + private function addPlaces(array $places) { foreach ($places as $place) { $this->addPlace($place); } } - public function addTransitions(array $transitions) - { - foreach ($transitions as $transition) { - $this->addTransition($transition); - } - } - - public function addTransition(Transition $transition) + private function addTransition(Transition $transition) { $name = $transition->getName(); diff --git a/src/Symfony/Component/Workflow/DefinitionBuilder.php b/src/Symfony/Component/Workflow/DefinitionBuilder.php new file mode 100644 index 0000000000000..447d67337d09f --- /dev/null +++ b/src/Symfony/Component/Workflow/DefinitionBuilder.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Workflow; + +use Symfony\Component\Workflow\Exception\InvalidArgumentException; + +/** + * Builds a definition. + * + * @author Fabien Potencier + * @author Grégoire Pineau + * @author Tobias Nyholm + */ +class DefinitionBuilder +{ + private $places = array(); + private $transitions = array(); + private $initialPlace; + + /** + * @param string[] $places + * @param Transition[] $transitions + */ + public function __construct(array $places = array(), array $transitions = array()) + { + $this->addPlaces($places); + $this->addTransitions($transitions); + } + + /** + * @return Definition + */ + public function build() + { + return new Definition($this->places, $this->transitions, $this->initialPlace); + } + + /** + * Clear all data in the builder. + */ + public function reset() + { + $this->places = array(); + $this->transitions = array(); + $this->initialPlace = null; + } + + public function setInitialPlace($place) + { + $this->initialPlace = $place; + } + + public function addPlace($place) + { + if (!preg_match('{^[\w\d_-]+$}', $place)) { + throw new InvalidArgumentException(sprintf('The place "%s" contains invalid characters.', $place)); + } + + if (!$this->places) { + $this->initialPlace = $place; + } + + $this->places[$place] = $place; + } + + public function addPlaces(array $places) + { + foreach ($places as $place) { + $this->addPlace($place); + } + } + + public function addTransitions(array $transitions) + { + foreach ($transitions as $transition) { + $this->addTransition($transition); + } + } + + public function addTransition(Transition $transition) + { + $this->transitions[] = $transition; + } +} diff --git a/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php b/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php new file mode 100644 index 0000000000000..fa4803b83dc29 --- /dev/null +++ b/src/Symfony/Component/Workflow/Tests/DefinitionBuilderTest.php @@ -0,0 +1,54 @@ +setInitialPlace('b'); + $definition = $builder->build(); + + $this->assertEquals('b', $definition->getInitialPlace()); + } + + public function testAddTransition() + { + $places = range('a', 'b'); + + $transition0 = new Transition('name0', $places[0], $places[1]); + $transition1 = new Transition('name1', $places[0], $places[1]); + $builder = new DefinitionBuilder($places, array($transition0)); + $builder->addTransition($transition1); + + $definition = $builder->build(); + + $this->assertCount(2, $definition->getTransitions()); + $this->assertSame($transition0, $definition->getTransitions()[0]); + $this->assertSame($transition1, $definition->getTransitions()[1]); + } + + public function testAddPlace() + { + $builder = new DefinitionBuilder(array('a'), array()); + $builder->addPlace('b'); + + $definition = $builder->build(); + + $this->assertCount(2, $definition->getPlaces()); + $this->assertEquals('a', $definition->getPlaces()['a']); + $this->assertEquals('b', $definition->getPlaces()['b']); + } +} diff --git a/src/Symfony/Component/Workflow/Tests/DefinitionTest.php b/src/Symfony/Component/Workflow/Tests/DefinitionTest.php index 09e594233e99c..a0e7c9ed45269 100644 --- a/src/Symfony/Component/Workflow/Tests/DefinitionTest.php +++ b/src/Symfony/Component/Workflow/Tests/DefinitionTest.php @@ -10,7 +10,7 @@ class DefinitionTest extends \PHPUnit_Framework_TestCase public function testAddPlaces() { $places = range('a', 'e'); - $definition = new Definition($places); + $definition = new Definition($places, array()); $this->assertCount(5, $definition->getPlaces()); @@ -23,15 +23,13 @@ public function testAddPlaces() public function testAddPlacesInvalidArgument() { $places = array('a"', 'e"'); - $definition = new Definition($places); + $definition = new Definition($places, array()); } public function testSetInitialPlace() { $places = range('a', 'e'); - $definition = new Definition($places); - - $definition->setInitialPlace($places[3]); + $definition = new Definition($places, array(), $places[3]); $this->assertEquals($places[3], $definition->getInitialPlace()); } @@ -42,9 +40,7 @@ public function testSetInitialPlace() */ public function testSetInitialPlaceAndPlaceIsNotDefined() { - $definition = new Definition(); - - $definition->setInitialPlace('d'); + $definition = new Definition(array(), array(), 'd'); } public function testAddTransition() diff --git a/src/Symfony/Component/Workflow/Tests/Dumper/GraphvizDumperTest.php b/src/Symfony/Component/Workflow/Tests/Dumper/GraphvizDumperTest.php index d6e9cd30f31d9..f24bb003a892a 100644 --- a/src/Symfony/Component/Workflow/Tests/Dumper/GraphvizDumperTest.php +++ b/src/Symfony/Component/Workflow/Tests/Dumper/GraphvizDumperTest.php @@ -2,7 +2,7 @@ namespace Symfony\Component\Workflow\Tests\Dumper; -use Symfony\Component\Workflow\Definition; +use Symfony\Component\Workflow\DefinitionBuilder; use Symfony\Component\Workflow\Dumper\GraphvizDumper; use Symfony\Component\Workflow\Marking; use Symfony\Component\Workflow\Transition; @@ -39,7 +39,7 @@ public function testWorkflowWithMarking($definition, $marking, $expected) public function provideWorkflowDefinitionWithMarking() { yield array( - $this->createprovideComplexWorkflowDefinition(), + $this->provideComplexWorkflowDefinition(), new Marking(array('b' => 1)), $this->createComplexWorkflowDumpWithMarking(), ); @@ -53,36 +53,36 @@ public function provideWorkflowDefinitionWithMarking() public function provideWorkflowDefinitionWithoutMarking() { - yield array($this->createprovideComplexWorkflowDefinition(), $this->provideComplexWorkflowDumpWithoutMarking()); + yield array($this->provideComplexWorkflowDefinition(), $this->provideComplexWorkflowDumpWithoutMarking()); yield array($this->provideSimpleWorkflowDefinition(), $this->provideSimpleWorkflowDumpWithoutMarking()); } - public function createprovideComplexWorkflowDefinition() + public function provideComplexWorkflowDefinition() { - $definition = new Definition(); + $builder = new DefinitionBuilder(); - $definition->addPlaces(range('a', 'g')); + $builder->addPlaces(range('a', 'g')); - $definition->addTransition(new Transition('t1', 'a', array('b', 'c'))); - $definition->addTransition(new Transition('t2', array('b', 'c'), 'd')); - $definition->addTransition(new Transition('t3', 'd', 'e')); - $definition->addTransition(new Transition('t4', 'd', 'f')); - $definition->addTransition(new Transition('t5', 'e', 'g')); - $definition->addTransition(new Transition('t6', 'f', 'g')); + $builder->addTransition(new Transition('t1', 'a', array('b', 'c'))); + $builder->addTransition(new Transition('t2', array('b', 'c'), 'd')); + $builder->addTransition(new Transition('t3', 'd', 'e')); + $builder->addTransition(new Transition('t4', 'd', 'f')); + $builder->addTransition(new Transition('t5', 'e', 'g')); + $builder->addTransition(new Transition('t6', 'f', 'g')); - return $definition; + return $builder->build(); } public function provideSimpleWorkflowDefinition() { - $definition = new Definition(); + $builder = new DefinitionBuilder(); - $definition->addPlaces(range('a', 'c')); + $builder->addPlaces(range('a', 'c')); - $definition->addTransition(new Transition('t1', 'a', 'b')); - $definition->addTransition(new Transition('t2', 'b', 'c')); + $builder->addTransition(new Transition('t1', 'a', 'b')); + $builder->addTransition(new Transition('t2', 'b', 'c')); - return $definition; + return $builder->build(); } public function createComplexWorkflowDumpWithMarking() diff --git a/src/Symfony/Component/Workflow/Tests/RegistryTest.php b/src/Symfony/Component/Workflow/Tests/RegistryTest.php index 42fa8c4ac7c11..90b537c4b99c1 100644 --- a/src/Symfony/Component/Workflow/Tests/RegistryTest.php +++ b/src/Symfony/Component/Workflow/Tests/RegistryTest.php @@ -18,9 +18,9 @@ protected function setUp() $this->registry = new Registry(); - $this->registry->add(new Workflow(new Definition(), $this->getMockBuilder(MarkingStoreInterface::class)->getMock(), $this->getMockBuilder(EventDispatcherInterface::class)->getMock(), 'workflow1'), Subject1::class); - $this->registry->add(new Workflow(new Definition(), $this->getMockBuilder(MarkingStoreInterface::class)->getMock(), $this->getMockBuilder(EventDispatcherInterface::class)->getMock(), 'workflow2'), Subject2::class); - $this->registry->add(new Workflow(new Definition(), $this->getMockBuilder(MarkingStoreInterface::class)->getMock(), $this->getMockBuilder(EventDispatcherInterface::class)->getMock(), 'workflow3'), Subject2::class); + $this->registry->add(new Workflow(new Definition(array(), array()), $this->getMockBuilder(MarkingStoreInterface::class)->getMock(), $this->getMockBuilder(EventDispatcherInterface::class)->getMock(), 'workflow1'), Subject1::class); + $this->registry->add(new Workflow(new Definition(array(), array()), $this->getMockBuilder(MarkingStoreInterface::class)->getMock(), $this->getMockBuilder(EventDispatcherInterface::class)->getMock(), 'workflow2'), Subject2::class); + $this->registry->add(new Workflow(new Definition(array(), array()), $this->getMockBuilder(MarkingStoreInterface::class)->getMock(), $this->getMockBuilder(EventDispatcherInterface::class)->getMock(), 'workflow3'), Subject2::class); } protected function tearDown() diff --git a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php index 4a7ea56e2180b..c926695270461 100644 --- a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php +++ b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php @@ -4,6 +4,7 @@ use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Workflow\Definition; +use Symfony\Component\Workflow\DefinitionBuilder; use Symfony\Component\Workflow\Event\GuardEvent; use Symfony\Component\Workflow\Marking; use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface; @@ -21,7 +22,7 @@ public function testGetMarkingWithInvalidStoreReturn() { $subject = new \stdClass(); $subject->marking = null; - $workflow = new Workflow(new Definition(), $this->getMockBuilder(MarkingStoreInterface::class)->getMock()); + $workflow = new Workflow(new Definition(array(), array()), $this->getMockBuilder(MarkingStoreInterface::class)->getMock()); $workflow->getMarking($subject); } @@ -34,7 +35,7 @@ public function testGetMarkingWithEmptyDefinition() { $subject = new \stdClass(); $subject->marking = null; - $workflow = new Workflow(new Definition(), new PropertyAccessorMarkingStore()); + $workflow = new Workflow(new Definition(array(), array()), new PropertyAccessorMarkingStore()); $workflow->getMarking($subject); } @@ -48,7 +49,7 @@ public function testGetMarkingWithImpossiblePlace() $subject = new \stdClass(); $subject->marking = null; $subject->marking = array('nope' => true); - $workflow = new Workflow(new Definition(), new PropertyAccessorMarkingStore()); + $workflow = new Workflow(new Definition(array(), array()), new PropertyAccessorMarkingStore()); $workflow->getMarking($subject); } @@ -211,18 +212,18 @@ public function testGetEnabledTransitions() protected function createComplexWorkflow() { - $definition = new Definition(); + $builder = new DefinitionBuilder(); - $definition->addPlaces(range('a', 'g')); + $builder->addPlaces(range('a', 'g')); - $definition->addTransition(new Transition('t1', 'a', array('b', 'c'))); - $definition->addTransition(new Transition('t2', array('b', 'c'), 'd')); - $definition->addTransition(new Transition('t3', 'd', 'e')); - $definition->addTransition(new Transition('t4', 'd', 'f')); - $definition->addTransition(new Transition('t5', 'e', 'g')); - $definition->addTransition(new Transition('t6', 'f', 'g')); + $builder->addTransition(new Transition('t1', 'a', array('b', 'c'))); + $builder->addTransition(new Transition('t2', array('b', 'c'), 'd')); + $builder->addTransition(new Transition('t3', 'd', 'e')); + $builder->addTransition(new Transition('t4', 'd', 'f')); + $builder->addTransition(new Transition('t5', 'e', 'g')); + $builder->addTransition(new Transition('t6', 'f', 'g')); - return $definition; + return $builder->build(); // The graph looks like: // diff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.php index 348b3b95a9a98..72dc07d73c79e 100644 --- a/src/Symfony/Component/Workflow/Workflow.php +++ b/src/Symfony/Component/Workflow/Workflow.php @@ -159,6 +159,14 @@ public function getName() return $this->name; } + /** + * @return Definition + */ + public function getDefinition() + { + return $this->definition; + } + /** * @param object $subject * @param Marking $marking From 08464c9f2c059c5292fc9bfe991d6b74437389c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Wed, 9 Nov 2016 14:38:18 +0100 Subject: [PATCH 078/113] [Workfow] Rename current MarkingStore * ScalarMarkingStore -> SingleStateMarkingStore * PropertyAccessorMarkingStore -> MultipleStateMarkingStore And I also made optionnal the `marking_store` config, to let the componant choose the best marking store depending on the type (state_machine or workflow). --- .../DependencyInjection/Configuration.php | 3 +-- .../Resources/config/workflow.xml | 4 ++-- .../Fixtures/php/workflow.php | 2 +- .../Fixtures/xml/workflow.xml | 2 +- .../Fixtures/yml/workflow.yml | 2 +- .../MarkingStore/MarkingStoreInterface.php | 6 ++++- ...tore.php => MultipleStateMarkingStore.php} | 10 +++++--- ...gStore.php => SingleStateMarkingStore.php} | 9 ++++--- .../Component/Workflow/StateMachine.php | 4 ++-- .../EventListener/AuditTrailListenerTest.php | 4 ++-- ....php => MultipleStateMarkingStoreTest.php} | 6 ++--- ...st.php => SingleStateMarkingStoreTest.php} | 6 ++--- .../Component/Workflow/Tests/WorkflowTest.php | 24 +++++++++---------- src/Symfony/Component/Workflow/Workflow.php | 4 ++-- 14 files changed, 48 insertions(+), 38 deletions(-) rename src/Symfony/Component/Workflow/MarkingStore/{PropertyAccessorMarkingStore.php => MultipleStateMarkingStore.php} (81%) rename src/Symfony/Component/Workflow/MarkingStore/{ScalarMarkingStore.php => SingleStateMarkingStore.php} (82%) rename src/Symfony/Component/Workflow/Tests/MarkingStore/{PropertyAccessorMarkingStoreTest.php => MultipleStateMarkingStoreTest.php} (75%) rename src/Symfony/Component/Workflow/Tests/MarkingStore/{ScalarMarkingStoreTest.php => SingleStateMarkingStoreTest.php} (76%) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php index 460e2a860f808..708e84ad1f766 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Configuration.php @@ -241,10 +241,9 @@ private function addWorkflowSection(ArrayNodeDefinition $rootNode) ->defaultValue('workflow') ->end() ->arrayNode('marking_store') - ->isRequired() ->children() ->enumNode('type') - ->values(array('property_accessor', 'scalar')) + ->values(array('multiple_state', 'single_state')) ->end() ->arrayNode('arguments') ->beforeNormalization() diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml index 1314be8b9f316..76592087a2260 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/workflow.xml @@ -18,8 +18,8 @@ - - + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow.php index 7f29cc385ba5b..222299a9c09ac 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/php/workflow.php @@ -6,7 +6,7 @@ 'workflows' => array( 'my_workflow' => array( 'marking_store' => array( - 'type' => 'property_accessor', + 'type' => 'multiple_state', ), 'supports' => array( FrameworkExtensionTest::class, diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow.xml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow.xml index add799b82fd44..447b390f24be7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/xml/workflow.xml @@ -10,7 +10,7 @@ - property_accessor + multiple_state a a diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow.yml index e9eb8e1977a9d..2bd071e568437 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow.yml +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/Fixtures/yml/workflow.yml @@ -2,7 +2,7 @@ framework: workflows: my_workflow: marking_store: - type: property_accessor + type: multiple_state supports: - Symfony\Bundle\FrameworkBundle\Tests\DependencyInjection\FrameworkExtensionTest places: diff --git a/src/Symfony/Component/Workflow/MarkingStore/MarkingStoreInterface.php b/src/Symfony/Component/Workflow/MarkingStore/MarkingStoreInterface.php index e73c9eb596c62..76df9cc0d2160 100644 --- a/src/Symfony/Component/Workflow/MarkingStore/MarkingStoreInterface.php +++ b/src/Symfony/Component/Workflow/MarkingStore/MarkingStoreInterface.php @@ -14,7 +14,11 @@ use Symfony\Component\Workflow\Marking; /** - * MarkingStoreInterface. + * MarkingStoreInterface is the interface between the Workflow Component and a + * plain old PHP object: the subject. + * + * It converts the Marking into something understandable by the subject and vice + * versa. * * @author Grégoire Pineau */ diff --git a/src/Symfony/Component/Workflow/MarkingStore/PropertyAccessorMarkingStore.php b/src/Symfony/Component/Workflow/MarkingStore/MultipleStateMarkingStore.php similarity index 81% rename from src/Symfony/Component/Workflow/MarkingStore/PropertyAccessorMarkingStore.php rename to src/Symfony/Component/Workflow/MarkingStore/MultipleStateMarkingStore.php index 8972b69b6c2e4..42fd65bb2c5d5 100644 --- a/src/Symfony/Component/Workflow/MarkingStore/PropertyAccessorMarkingStore.php +++ b/src/Symfony/Component/Workflow/MarkingStore/MultipleStateMarkingStore.php @@ -16,17 +16,21 @@ use Symfony\Component\Workflow\Marking; /** - * PropertyAccessorMarkingStore. + * MultipleStateMarkingStore stores the marking into a property of the + * subject. + * + * This store deals with a "multiple state" Marking. It means a subject can be + * in many state at the same time. * * @author Grégoire Pineau */ -class PropertyAccessorMarkingStore implements MarkingStoreInterface +class MultipleStateMarkingStore implements MarkingStoreInterface { private $property; private $propertyAccessor; /** - * PropertyAccessorMarkingStore constructor. + * MultipleStateMarkingStore constructor. * * @param string $property * @param PropertyAccessorInterface|null $propertyAccessor diff --git a/src/Symfony/Component/Workflow/MarkingStore/ScalarMarkingStore.php b/src/Symfony/Component/Workflow/MarkingStore/SingleStateMarkingStore.php similarity index 82% rename from src/Symfony/Component/Workflow/MarkingStore/ScalarMarkingStore.php rename to src/Symfony/Component/Workflow/MarkingStore/SingleStateMarkingStore.php index 1c7a36093b518..bbd2b74b6350e 100644 --- a/src/Symfony/Component/Workflow/MarkingStore/ScalarMarkingStore.php +++ b/src/Symfony/Component/Workflow/MarkingStore/SingleStateMarkingStore.php @@ -16,17 +16,20 @@ use Symfony\Component\Workflow\Marking; /** - * ScalarMarkingStore. + * SingleStateMarkingStore stores the marking into a property of the subject. + * + * This store deals with a "single state" Marking. It means a subject can be in + * one and only state at the same time. * * @author Grégoire Pineau */ -class ScalarMarkingStore implements MarkingStoreInterface +class SingleStateMarkingStore implements MarkingStoreInterface { private $property; private $propertyAccessor; /** - * ScalarMarkingStore constructor. + * SingleStateMarkingStore constructor. * * @param string $property * @param PropertyAccessorInterface|null $propertyAccessor diff --git a/src/Symfony/Component/Workflow/StateMachine.php b/src/Symfony/Component/Workflow/StateMachine.php index 0c4e3edc0a6b5..00cfdac7d493a 100644 --- a/src/Symfony/Component/Workflow/StateMachine.php +++ b/src/Symfony/Component/Workflow/StateMachine.php @@ -4,7 +4,7 @@ use Symfony\Component\EventDispatcher\EventDispatcherInterface; use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface; -use Symfony\Component\Workflow\MarkingStore\ScalarMarkingStore; +use Symfony\Component\Workflow\MarkingStore\SingleStateMarkingStore; /** * @author Tobias Nyholm @@ -13,6 +13,6 @@ class StateMachine extends Workflow { public function __construct(Definition $definition, MarkingStoreInterface $markingStore = null, EventDispatcherInterface $dispatcher = null, $name = 'unnamed') { - parent::__construct($definition, $markingStore ?: new ScalarMarkingStore(), $dispatcher, $name); + parent::__construct($definition, $markingStore ?: new SingleStateMarkingStore(), $dispatcher, $name); } } diff --git a/src/Symfony/Component/Workflow/Tests/EventListener/AuditTrailListenerTest.php b/src/Symfony/Component/Workflow/Tests/EventListener/AuditTrailListenerTest.php index 319a9119f5e02..c3982f1787608 100644 --- a/src/Symfony/Component/Workflow/Tests/EventListener/AuditTrailListenerTest.php +++ b/src/Symfony/Component/Workflow/Tests/EventListener/AuditTrailListenerTest.php @@ -6,7 +6,7 @@ use Symfony\Component\EventDispatcher\EventDispatcher; use Symfony\Component\Workflow\Definition; use Symfony\Component\Workflow\EventListener\AuditTrailListener; -use Symfony\Component\Workflow\MarkingStore\PropertyAccessorMarkingStore; +use Symfony\Component\Workflow\MarkingStore\MultipleStateMarkingStore; use Symfony\Component\Workflow\Transition; use Symfony\Component\Workflow\Workflow; @@ -29,7 +29,7 @@ public function testItWorks() $ed = new EventDispatcher(); $ed->addSubscriber(new AuditTrailListener($logger)); - $workflow = new Workflow($definition, new PropertyAccessorMarkingStore(), $ed); + $workflow = new Workflow($definition, new MultipleStateMarkingStore(), $ed); $workflow->apply($object, 't1'); diff --git a/src/Symfony/Component/Workflow/Tests/MarkingStore/PropertyAccessorMarkingStoreTest.php b/src/Symfony/Component/Workflow/Tests/MarkingStore/MultipleStateMarkingStoreTest.php similarity index 75% rename from src/Symfony/Component/Workflow/Tests/MarkingStore/PropertyAccessorMarkingStoreTest.php rename to src/Symfony/Component/Workflow/Tests/MarkingStore/MultipleStateMarkingStoreTest.php index 557a241689ece..7e324c530eff8 100644 --- a/src/Symfony/Component/Workflow/Tests/MarkingStore/PropertyAccessorMarkingStoreTest.php +++ b/src/Symfony/Component/Workflow/Tests/MarkingStore/MultipleStateMarkingStoreTest.php @@ -3,16 +3,16 @@ namespace Symfony\Component\Workflow\Tests\MarkingStore; use Symfony\Component\Workflow\Marking; -use Symfony\Component\Workflow\MarkingStore\PropertyAccessorMarkingStore; +use Symfony\Component\Workflow\MarkingStore\MultipleStateMarkingStore; -class PropertyAccessorMarkingStoreTest extends \PHPUnit_Framework_TestCase +class MultipleStateMarkingStoreTest extends \PHPUnit_Framework_TestCase { public function testGetSetMarking() { $subject = new \stdClass(); $subject->myMarks = null; - $markingStore = new PropertyAccessorMarkingStore('myMarks'); + $markingStore = new MultipleStateMarkingStore('myMarks'); $marking = $markingStore->getMarking($subject); diff --git a/src/Symfony/Component/Workflow/Tests/MarkingStore/ScalarMarkingStoreTest.php b/src/Symfony/Component/Workflow/Tests/MarkingStore/SingleStateMarkingStoreTest.php similarity index 76% rename from src/Symfony/Component/Workflow/Tests/MarkingStore/ScalarMarkingStoreTest.php rename to src/Symfony/Component/Workflow/Tests/MarkingStore/SingleStateMarkingStoreTest.php index df8d748a0d927..ad3fae189aca5 100644 --- a/src/Symfony/Component/Workflow/Tests/MarkingStore/ScalarMarkingStoreTest.php +++ b/src/Symfony/Component/Workflow/Tests/MarkingStore/SingleStateMarkingStoreTest.php @@ -3,16 +3,16 @@ namespace Symfony\Component\Workflow\Tests\MarkingStore; use Symfony\Component\Workflow\Marking; -use Symfony\Component\Workflow\MarkingStore\ScalarMarkingStore; +use Symfony\Component\Workflow\MarkingStore\SingleStateMarkingStore; -class ScalarMarkingStoreTest extends \PHPUnit_Framework_TestCase +class SingleStateMarkingStoreTest extends \PHPUnit_Framework_TestCase { public function testGetSetMarking() { $subject = new \stdClass(); $subject->myMarks = null; - $markingStore = new ScalarMarkingStore('myMarks'); + $markingStore = new SingleStateMarkingStore('myMarks'); $marking = $markingStore->getMarking($subject); diff --git a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php index c926695270461..f5141c0fffba1 100644 --- a/src/Symfony/Component/Workflow/Tests/WorkflowTest.php +++ b/src/Symfony/Component/Workflow/Tests/WorkflowTest.php @@ -8,7 +8,7 @@ use Symfony\Component\Workflow\Event\GuardEvent; use Symfony\Component\Workflow\Marking; use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface; -use Symfony\Component\Workflow\MarkingStore\PropertyAccessorMarkingStore; +use Symfony\Component\Workflow\MarkingStore\MultipleStateMarkingStore; use Symfony\Component\Workflow\Transition; use Symfony\Component\Workflow\Workflow; @@ -35,7 +35,7 @@ public function testGetMarkingWithEmptyDefinition() { $subject = new \stdClass(); $subject->marking = null; - $workflow = new Workflow(new Definition(array(), array()), new PropertyAccessorMarkingStore()); + $workflow = new Workflow(new Definition(array(), array()), new MultipleStateMarkingStore()); $workflow->getMarking($subject); } @@ -49,7 +49,7 @@ public function testGetMarkingWithImpossiblePlace() $subject = new \stdClass(); $subject->marking = null; $subject->marking = array('nope' => true); - $workflow = new Workflow(new Definition(array(), array()), new PropertyAccessorMarkingStore()); + $workflow = new Workflow(new Definition(array(), array()), new MultipleStateMarkingStore()); $workflow->getMarking($subject); } @@ -59,7 +59,7 @@ public function testGetMarkingWithEmptyInitialMarking() $definition = $this->createComplexWorkflow(); $subject = new \stdClass(); $subject->marking = null; - $workflow = new Workflow($definition, new PropertyAccessorMarkingStore()); + $workflow = new Workflow($definition, new MultipleStateMarkingStore()); $marking = $workflow->getMarking($subject); @@ -74,7 +74,7 @@ public function testGetMarkingWithExistingMarking() $subject = new \stdClass(); $subject->marking = null; $subject->marking = array('b' => 1, 'c' => 1); - $workflow = new Workflow($definition, new PropertyAccessorMarkingStore()); + $workflow = new Workflow($definition, new MultipleStateMarkingStore()); $marking = $workflow->getMarking($subject); @@ -92,7 +92,7 @@ public function testCanWithUnexistingTransition() $definition = $this->createComplexWorkflow(); $subject = new \stdClass(); $subject->marking = null; - $workflow = new Workflow($definition, new PropertyAccessorMarkingStore()); + $workflow = new Workflow($definition, new MultipleStateMarkingStore()); $workflow->can($subject, 'foobar'); } @@ -102,7 +102,7 @@ public function testCan() $definition = $this->createComplexWorkflow(); $subject = new \stdClass(); $subject->marking = null; - $workflow = new Workflow($definition, new PropertyAccessorMarkingStore()); + $workflow = new Workflow($definition, new MultipleStateMarkingStore()); $this->assertTrue($workflow->can($subject, 't1')); $this->assertFalse($workflow->can($subject, 't2')); @@ -117,7 +117,7 @@ public function testCanWithGuard() $eventDispatcher->addListener('workflow.workflow_name.guard.t1', function (GuardEvent $event) { $event->setBlocked(true); }); - $workflow = new Workflow($definition, new PropertyAccessorMarkingStore(), $eventDispatcher, 'workflow_name'); + $workflow = new Workflow($definition, new MultipleStateMarkingStore(), $eventDispatcher, 'workflow_name'); $this->assertFalse($workflow->can($subject, 't1')); } @@ -131,7 +131,7 @@ public function testApplyWithImpossibleTransition() $definition = $this->createComplexWorkflow(); $subject = new \stdClass(); $subject->marking = null; - $workflow = new Workflow($definition, new PropertyAccessorMarkingStore()); + $workflow = new Workflow($definition, new MultipleStateMarkingStore()); $workflow->apply($subject, 't2'); } @@ -141,7 +141,7 @@ public function testApply() $definition = $this->createComplexWorkflow(); $subject = new \stdClass(); $subject->marking = null; - $workflow = new Workflow($definition, new PropertyAccessorMarkingStore()); + $workflow = new Workflow($definition, new MultipleStateMarkingStore()); $marking = $workflow->apply($subject, 't1'); @@ -157,7 +157,7 @@ public function testApplyWithEventDispatcher() $subject = new \stdClass(); $subject->marking = null; $eventDispatcher = new EventDispatcherMock(); - $workflow = new Workflow($definition, new PropertyAccessorMarkingStore(), $eventDispatcher, 'workflow_name'); + $workflow = new Workflow($definition, new MultipleStateMarkingStore(), $eventDispatcher, 'workflow_name'); $eventNameExpected = array( 'workflow.guard', @@ -194,7 +194,7 @@ public function testGetEnabledTransitions() $eventDispatcher->addListener('workflow.workflow_name.guard.t1', function (GuardEvent $event) { $event->setBlocked(true); }); - $workflow = new Workflow($definition, new PropertyAccessorMarkingStore(), $eventDispatcher, 'workflow_name'); + $workflow = new Workflow($definition, new MultipleStateMarkingStore(), $eventDispatcher, 'workflow_name'); $this->assertEmpty($workflow->getEnabledTransitions($subject)); diff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.php index 72dc07d73c79e..84cd9945d49cd 100644 --- a/src/Symfony/Component/Workflow/Workflow.php +++ b/src/Symfony/Component/Workflow/Workflow.php @@ -16,7 +16,7 @@ use Symfony\Component\Workflow\Event\GuardEvent; use Symfony\Component\Workflow\Exception\LogicException; use Symfony\Component\Workflow\MarkingStore\MarkingStoreInterface; -use Symfony\Component\Workflow\MarkingStore\PropertyAccessorMarkingStore; +use Symfony\Component\Workflow\MarkingStore\MultipleStateMarkingStore; /** * @author Fabien Potencier @@ -33,7 +33,7 @@ class Workflow public function __construct(Definition $definition, MarkingStoreInterface $markingStore = null, EventDispatcherInterface $dispatcher = null, $name = 'unnamed') { $this->definition = $definition; - $this->markingStore = $markingStore ?: new PropertyAccessorMarkingStore(); + $this->markingStore = $markingStore ?: new MultipleStateMarkingStore(); $this->dispatcher = $dispatcher; $this->name = $name; } From 5a1bf6aa6e4eff880c376fe32f425942da357af8 Mon Sep 17 00:00:00 2001 From: Karim Miladi Date: Mon, 7 Nov 2016 18:16:01 +0100 Subject: [PATCH 079/113] [Command] Fixed method comments as phpDoc syntax --- src/Symfony/Component/Console/Command/Command.php | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/Symfony/Component/Console/Command/Command.php b/src/Symfony/Component/Console/Command/Command.php index dcda54b637953..0948d42b5755d 100644 --- a/src/Symfony/Component/Console/Command/Command.php +++ b/src/Symfony/Component/Console/Command/Command.php @@ -202,8 +202,6 @@ protected function initialize(InputInterface $input, OutputInterface $output) * * @return int The command exit code * - * @throws \Exception - * * @see setCode() * @see execute() */ From 51dad72a0693e04918df56d03df5724dce7f9d76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Wed, 9 Nov 2016 17:43:55 +0100 Subject: [PATCH 080/113] [Workflow] Set the marking then announce enabled transition It allows to auto-apply some transition from a listener. The feature was asked here: https://twitter.com/gaetanbuellet/status/796387741420441600 And It has been implemented in userland here: https://github.com/lyrixx/SFLive-Paris2016-Workflow/tree/auto-apply --- src/Symfony/Component/Workflow/Workflow.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Workflow/Workflow.php b/src/Symfony/Component/Workflow/Workflow.php index 84cd9945d49cd..b66cc85f51d90 100644 --- a/src/Symfony/Component/Workflow/Workflow.php +++ b/src/Symfony/Component/Workflow/Workflow.php @@ -126,10 +126,10 @@ public function apply($subject, $transitionName) $this->enter($subject, $transition, $marking); - $this->announce($subject, $transition, $marking); - $this->markingStore->setMarking($subject, $marking); + $this->announce($subject, $transition, $marking); + return $marking; } From dd47295c15b5644dadad5d8cb6c81eea37a8ec62 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Mon, 7 Nov 2016 22:01:27 +0100 Subject: [PATCH 081/113] fixed phpdoc --- src/Symfony/Component/Yaml/Inline.php | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index 7f2a75b8c70b5..624088fbba767 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -28,7 +28,7 @@ class Inline private static $objectForMap = false; /** - * Converts a YAML string to a PHP array. + * Converts a YAML string to a PHP value. * * @param string $value A YAML string * @param bool $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise @@ -36,7 +36,7 @@ class Inline * @param bool $objectForMap true if maps should return a stdClass instead of array() * @param array $references Mapping of variable names to values * - * @return array A PHP array representing the YAML string + * @return mixed A PHP value * * @throws ParseException */ @@ -90,7 +90,7 @@ public static function parse($value, $exceptionOnInvalidType = false, $objectSup * @param bool $exceptionOnInvalidType true if an exception must be thrown on invalid types (a PHP resource or object), false otherwise * @param bool $objectSupport true if object support is enabled, false otherwise * - * @return string The YAML string representing the PHP array + * @return string The YAML string representing the PHP value * * @throws DumpException When trying to dump PHP resource */ @@ -210,7 +210,7 @@ private static function dumpArray($value, $exceptionOnInvalidType, $objectSuppor } /** - * Parses a scalar to a YAML string. + * Parses a YAML scalar. * * @param string $scalar * @param string $delimiters @@ -219,7 +219,7 @@ private static function dumpArray($value, $exceptionOnInvalidType, $objectSuppor * @param bool $evaluate * @param array $references * - * @return string A YAML string + * @return string * * @throws ParseException When malformed inline YAML string is parsed */ @@ -261,12 +261,12 @@ public static function parseScalar($scalar, $delimiters = null, $stringDelimiter } /** - * Parses a quoted scalar to YAML. + * Parses a YAML quoted scalar. * * @param string $scalar * @param int &$i * - * @return string A YAML string + * @return string * * @throws ParseException When malformed inline YAML string is parsed */ @@ -291,13 +291,13 @@ private static function parseQuotedScalar($scalar, &$i) } /** - * Parses a sequence to a YAML string. + * Parses a YAML sequence. * * @param string $sequence * @param int &$i * @param array $references * - * @return string A YAML string + * @return array * * @throws ParseException When malformed inline YAML string is parsed */ @@ -350,13 +350,13 @@ private static function parseSequence($sequence, &$i = 0, $references = array()) } /** - * Parses a mapping to a YAML string. + * Parses a YAML mapping. * * @param string $mapping * @param int &$i * @param array $references * - * @return string A YAML string + * @return array|\stdClass * * @throws ParseException When malformed inline YAML string is parsed */ From cd8b9d962b4b72bcdbee0d165f34988d2ce50532 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Wed, 9 Nov 2016 19:33:39 +0100 Subject: [PATCH 082/113] fix merge --- .../Component/Cache/Tests/Adapter/MaxIdLengthAdapterTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Cache/Tests/Adapter/MaxIdLengthAdapterTest.php b/src/Symfony/Component/Cache/Tests/Adapter/MaxIdLengthAdapterTest.php index 8c96e7f969a7c..2414f22dc82aa 100644 --- a/src/Symfony/Component/Cache/Tests/Adapter/MaxIdLengthAdapterTest.php +++ b/src/Symfony/Component/Cache/Tests/Adapter/MaxIdLengthAdapterTest.php @@ -25,7 +25,7 @@ public function testLongKey() $cache->expects($this->exactly(2)) ->method('doHave') ->withConsecutive( - array($this->equalTo('----------:nWfzGiCgLczv3SSUzXL3kg:')), + array($this->equalTo('----------:0GTYWa9n4ed8vqNlOT2iEr:')), array($this->equalTo('----------:---------------------------------------')) ); From bac217dd833a60269e5a49f6a4c0be433aa389ae Mon Sep 17 00:00:00 2001 From: Abdellatif Ait boudad Date: Wed, 9 Nov 2016 19:27:17 +0000 Subject: [PATCH 083/113] [Translation] fixed nested fallback catalogue using multiple locales. --- .../Component/Translation/Tests/TranslatorTest.php | 10 ++++++++++ src/Symfony/Component/Translation/Translator.php | 4 ++-- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Translation/Tests/TranslatorTest.php b/src/Symfony/Component/Translation/Tests/TranslatorTest.php index ac5aaf9ec12a2..8756844b467c7 100644 --- a/src/Symfony/Component/Translation/Tests/TranslatorTest.php +++ b/src/Symfony/Component/Translation/Tests/TranslatorTest.php @@ -273,6 +273,16 @@ public function testWhenAResourceHasNoRegisteredLoader() $translator->trans('foo'); } + public function testNestedFallbackCatalogueWhenUsingMultipleLocales() + { + $translator = new Translator('fr'); + $translator->setFallbackLocales(array('ru', 'en')); + + $translator->getCatalogue('fr'); + + $this->assertNotNull($translator->getCatalogue('ru')->getFallbackCatalogue()); + } + public function testFallbackCatalogueResources() { $translator = new Translator('en_GB', new MessageSelector()); diff --git a/src/Symfony/Component/Translation/Translator.php b/src/Symfony/Component/Translation/Translator.php index 48a801d375446..ed80a5e49f0fd 100644 --- a/src/Symfony/Component/Translation/Translator.php +++ b/src/Symfony/Component/Translation/Translator.php @@ -159,7 +159,7 @@ public function getLocale() * * @throws \InvalidArgumentException If a locale contains invalid characters * - * @deprecated since version 2.3, to be removed in 3.0. Use setFallbackLocales() instead. + * @deprecated since version 2.3, to be removed in 3.0. Use setFallbackLocales() instead */ public function setFallbackLocale($locales) { @@ -420,7 +420,7 @@ private function loadFallbackCatalogues($locale) foreach ($this->computeFallbackLocales($locale) as $fallback) { if (!isset($this->catalogues[$fallback])) { - $this->doLoadCatalogue($fallback); + $this->loadCatalogue($fallback); } $fallbackCatalogue = new MessageCatalogue($fallback, $this->catalogues[$fallback]->all()); From 31deea1d3dff2dd3b4ea8786776ea90288d832e0 Mon Sep 17 00:00:00 2001 From: Abdellatif Ait boudad Date: Wed, 9 Nov 2016 20:23:10 +0000 Subject: [PATCH 084/113] [TranslationDebug] workaround for getFallbackLocales. --- .../Command/TranslationDebugCommand.php | 4 +++- .../Translation/DataCollectorTranslator.php | 14 ++++++++++++++ .../Component/Translation/LoggingTranslator.php | 14 ++++++++++++++ 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php index 64beda52656b3..be4696adfd806 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/TranslationDebugCommand.php @@ -19,6 +19,8 @@ use Symfony\Component\Console\Input\InputOption; use Symfony\Component\Translation\MessageCatalogue; use Symfony\Component\Translation\Translator; +use Symfony\Component\Translation\DataCollectorTranslator; +use Symfony\Component\Translation\LoggingTranslator; /** * Helps finding unused or missing translation messages in a given locale @@ -157,7 +159,7 @@ protected function execute(InputInterface $input, OutputInterface $output) // Load the fallback catalogues $fallbackCatalogues = array(); $translator = $this->getContainer()->get('translator'); - if ($translator instanceof Translator) { + if ($translator instanceof Translator || $translator instanceof DataCollectorTranslator || $translator instanceof LoggingTranslator) { foreach ($translator->getFallbackLocales() as $fallbackLocale) { if ($fallbackLocale === $locale) { continue; diff --git a/src/Symfony/Component/Translation/DataCollectorTranslator.php b/src/Symfony/Component/Translation/DataCollectorTranslator.php index f88a467a1d12c..b2049d47511ce 100644 --- a/src/Symfony/Component/Translation/DataCollectorTranslator.php +++ b/src/Symfony/Component/Translation/DataCollectorTranslator.php @@ -88,6 +88,20 @@ public function getCatalogue($locale = null) return $this->translator->getCatalogue($locale); } + /** + * Gets the fallback locales. + * + * @return array $locales The fallback locales + */ + public function getFallbackLocales() + { + if ($this->translator instanceof Translator) { + return $this->translator->getFallbackLocales(); + } + + return array(); + } + /** * Passes through all unknown calls onto the translator object. */ diff --git a/src/Symfony/Component/Translation/LoggingTranslator.php b/src/Symfony/Component/Translation/LoggingTranslator.php index fa5c5cc5b5ffd..b259df5e0aa49 100644 --- a/src/Symfony/Component/Translation/LoggingTranslator.php +++ b/src/Symfony/Component/Translation/LoggingTranslator.php @@ -88,6 +88,20 @@ public function getCatalogue($locale = null) return $this->translator->getCatalogue($locale); } + /** + * Gets the fallback locales. + * + * @return array $locales The fallback locales + */ + public function getFallbackLocales() + { + if ($this->translator instanceof Translator) { + return $this->translator->getFallbackLocales(); + } + + return array(); + } + /** * Passes through all unknown calls onto the translator object. */ From 9c154e7e8af35ffb358446b42144dc54c16fcfb4 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 10 Nov 2016 10:59:23 +0100 Subject: [PATCH 085/113] [Workflow] improve docblocks --- .../Workflow/MarkingStore/MultipleStateMarkingStore.php | 4 +--- .../Workflow/MarkingStore/SingleStateMarkingStore.php | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Workflow/MarkingStore/MultipleStateMarkingStore.php b/src/Symfony/Component/Workflow/MarkingStore/MultipleStateMarkingStore.php index 42fd65bb2c5d5..874d1fb5134a5 100644 --- a/src/Symfony/Component/Workflow/MarkingStore/MultipleStateMarkingStore.php +++ b/src/Symfony/Component/Workflow/MarkingStore/MultipleStateMarkingStore.php @@ -20,7 +20,7 @@ * subject. * * This store deals with a "multiple state" Marking. It means a subject can be - * in many state at the same time. + * in many states at the same time. * * @author Grégoire Pineau */ @@ -30,8 +30,6 @@ class MultipleStateMarkingStore implements MarkingStoreInterface private $propertyAccessor; /** - * MultipleStateMarkingStore constructor. - * * @param string $property * @param PropertyAccessorInterface|null $propertyAccessor */ diff --git a/src/Symfony/Component/Workflow/MarkingStore/SingleStateMarkingStore.php b/src/Symfony/Component/Workflow/MarkingStore/SingleStateMarkingStore.php index bbd2b74b6350e..99adf1671bab1 100644 --- a/src/Symfony/Component/Workflow/MarkingStore/SingleStateMarkingStore.php +++ b/src/Symfony/Component/Workflow/MarkingStore/SingleStateMarkingStore.php @@ -19,7 +19,7 @@ * SingleStateMarkingStore stores the marking into a property of the subject. * * This store deals with a "single state" Marking. It means a subject can be in - * one and only state at the same time. + * one and only one state at the same time. * * @author Grégoire Pineau */ @@ -29,8 +29,6 @@ class SingleStateMarkingStore implements MarkingStoreInterface private $propertyAccessor; /** - * SingleStateMarkingStore constructor. - * * @param string $property * @param PropertyAccessorInterface|null $propertyAccessor */ From 8eed2aa7eaca31498623472e7d4ac8f7fe64b576 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gr=C3=A9goire=20Pineau?= Date: Thu, 10 Nov 2016 11:39:59 +0100 Subject: [PATCH 086/113] [Workflow] Fixed PHPDocs --- src/Symfony/Component/Workflow/Definition.php | 2 -- src/Symfony/Component/Workflow/Event/Event.php | 2 -- src/Symfony/Component/Workflow/Transition.php | 2 -- 3 files changed, 6 deletions(-) diff --git a/src/Symfony/Component/Workflow/Definition.php b/src/Symfony/Component/Workflow/Definition.php index 6250bf57d2190..db177459750c8 100644 --- a/src/Symfony/Component/Workflow/Definition.php +++ b/src/Symfony/Component/Workflow/Definition.php @@ -26,8 +26,6 @@ final class Definition private $initialPlace; /** - * Definition constructor. - * * @param string[] $places * @param Transition[] $transitions * @param string|null $initialPlace diff --git a/src/Symfony/Component/Workflow/Event/Event.php b/src/Symfony/Component/Workflow/Event/Event.php index 8a307d731a3cb..dce6a6f5df8fb 100644 --- a/src/Symfony/Component/Workflow/Event/Event.php +++ b/src/Symfony/Component/Workflow/Event/Event.php @@ -26,8 +26,6 @@ class Event extends BaseEvent private $transition; /** - * Event constructor. - * * @param object $subject * @param Marking $marking * @param Transition $transition diff --git a/src/Symfony/Component/Workflow/Transition.php b/src/Symfony/Component/Workflow/Transition.php index 7e44f0b315a89..fb4786c88a267 100644 --- a/src/Symfony/Component/Workflow/Transition.php +++ b/src/Symfony/Component/Workflow/Transition.php @@ -24,8 +24,6 @@ class Transition private $tos; /** - * Transition constructor. - * * @param string $name * @param string|string[] $froms * @param string|string[] $tos From c546857957c6d3e5477046cf13df97bf0516b56b Mon Sep 17 00:00:00 2001 From: Tobias Nyholm Date: Thu, 10 Nov 2016 15:55:12 +0100 Subject: [PATCH 087/113] Removed private Definition::addPlaces There is no need for this method --- src/Symfony/Component/Workflow/Definition.php | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Workflow/Definition.php b/src/Symfony/Component/Workflow/Definition.php index 6250bf57d2190..a30a1fc89ab3a 100644 --- a/src/Symfony/Component/Workflow/Definition.php +++ b/src/Symfony/Component/Workflow/Definition.php @@ -34,11 +34,15 @@ final class Definition */ public function __construct(array $places, array $transitions, $initialPlace = null) { - $this->addPlaces($places); - $this->setInitialPlace($initialPlace); + foreach ($places as $place) { + $this->addPlace($place); + } + foreach ($transitions as $transition) { $this->addTransition($transition); } + + $this->setInitialPlace($initialPlace); } /** @@ -91,13 +95,6 @@ private function addPlace($place) $this->places[$place] = $place; } - private function addPlaces(array $places) - { - foreach ($places as $place) { - $this->addPlace($place); - } - } - private function addTransition(Transition $transition) { $name = $transition->getName(); From caa3d6ffb37b7092c19a0b6ae336a31b5f885eec Mon Sep 17 00:00:00 2001 From: Tobias Nyholm Date: Thu, 10 Nov 2016 15:52:21 +0100 Subject: [PATCH 088/113] [Workflow] Removed definition builder --- .../DependencyInjection/FrameworkExtension.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index 3151bd8e8d26b..666ba03b0e54e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -406,16 +406,14 @@ private function registerWorkflowConfiguration(array $workflows, ContainerBuilde foreach ($workflows as $name => $workflow) { $type = $workflow['type']; - // Create a DefinitionBuilder - $definitionBuilderDefinition = new Definition(Workflow\DefinitionBuilder::class); - $definitionBuilderDefinition->addMethodCall('addPlaces', array($workflow['places'])); + $transitions = array(); foreach ($workflow['transitions'] as $transitionName => $transition) { if ($type === 'workflow') { - $definitionBuilderDefinition->addMethodCall('addTransition', array(new Definition(Workflow\Transition::class, array($transitionName, $transition['from'], $transition['to'])))); + $transitions[] = new Definition(Workflow\Transition::class, array($transitionName, $transition['from'], $transition['to'])); } elseif ($type === 'state_machine') { foreach ($transition['from'] as $from) { foreach ($transition['to'] as $to) { - $definitionBuilderDefinition->addMethodCall('addTransition', array(new Definition(Workflow\Transition::class, array($transitionName, $from, $to)))); + $transitions[] = new Definition(Workflow\Transition::class, array($transitionName, $from, $to)); } } } @@ -424,7 +422,8 @@ private function registerWorkflowConfiguration(array $workflows, ContainerBuilde // Create a Definition $definitionDefinition = new Definition(Workflow\Definition::class); $definitionDefinition->setPublic(false); - $definitionDefinition->setFactory(array($definitionBuilderDefinition, 'build')); + $definitionDefinition->addArgument($workflow['places']); + $definitionDefinition->addArgument($transitions); $definitionDefinition->addTag('workflow.definition', array( 'name' => $name, 'type' => $type, From f3fede2e833c1f42ee378ff542fb6cc0ceebcaad Mon Sep 17 00:00:00 2001 From: Tobias Nyholm Date: Thu, 10 Nov 2016 16:29:44 +0100 Subject: [PATCH 089/113] [Validator] Added missing swedish translation --- .../Validator/Resources/translations/validators.sv.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf index 693f12b5b1998..879c0a5c559d0 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sv.xlf @@ -310,6 +310,10 @@ This value does not match the expected {{ charset }} charset. Detta värde har inte den förväntade teckenkodningen {{ charset }}. + + This is not a valid Business Identifier Code (BIC). + Detta är inte en giltig BIC-kod. + From 5dc5dc84750f192b5867cc624461e4d22b085f8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Mon, 24 Oct 2016 11:05:30 +0200 Subject: [PATCH 090/113] [Serializer] Fix DataUriNormalizer's regex --- .../Component/Serializer/Normalizer/DataUriNormalizer.php | 2 +- .../Serializer/Tests/Normalizer/DataUriNormalizerTest.php | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php index 9cf3c38b64ce9..988a491b7c800 100644 --- a/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/DataUriNormalizer.php @@ -85,7 +85,7 @@ public function supportsNormalization($data, $format = null) */ public function denormalize($data, $class, $format = null, array $context = array()) { - if (!preg_match('/^data:([a-z0-9]+\/[a-z0-9]+(;[a-z0-9\-]+\=[a-z0-9\-]+)?)?(;base64)?,[a-z0-9\!\$\&\\\'\,\(\)\*\+\,\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i', $data)) { + if (!preg_match('/^data:([a-z0-9][a-z0-9\!\#\$\&\-\^\_\+\.]{0,126}\/[a-z0-9][a-z0-9\!\#\$\&\-\^\_\+\.]{0,126}(;[a-z0-9\-]+\=[a-z0-9\-]+)?)?(;base64)?,[a-z0-9\!\$\&\\\'\,\(\)\*\+\,\;\=\-\.\_\~\:\@\/\?\%\s]*\s*$/i', $data)) { throw new UnexpectedValueException('The provided "data:" URI is not valid.'); } diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/DataUriNormalizerTest.php b/src/Symfony/Component/Serializer/Tests/Normalizer/DataUriNormalizerTest.php index f8cfe6944807b..79fafcb26a41f 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/DataUriNormalizerTest.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/DataUriNormalizerTest.php @@ -163,6 +163,9 @@ public function validUriProvider() array('data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E'), array('data:,A%20brief%20note'), array('data:text/html;charset=US-ASCII,%3Ch1%3EHello!%3C%2Fh1%3E'), + array('data:application/ld+json;base64,eyJAaWQiOiAiL2ZvbyJ9'), + array('data:application/vnd.ms-word.document.macroenabled.12;base64,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ABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/MvQB/9T+6v4Kf8ka+En/AGTLwH/6iulUAem0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH8y9AH/1f7q/gp/yRr4Sf8AZMvAf/qK6VQB6bQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAfzL0Af/W/ur+Cn/JGvhJ/wBky8B/+orpVAHptABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/MvQB/9f+6v4Kf8ka+En/AGTLwH/6iulUAem0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH8y9AH/0P7q/gp/yRr4Sf8AZMvAf/qK6VQB6bQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAfzL0Af/R/ur+Cn/JGvhJ/wBky8B/+orpVAHptABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/MvQB/9L+6v4Kf8ka+En/AGTLwH/6iulUAem0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH8y9AH/0/7q/gp/yRr4Sf8AZMvAf/qK6VQB6bQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAfzL0Af/U/ur+Cn/JGvhJ/wBky8B/+orpVAHptABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/MvQB/9X+6v4Kf8ka+En/AGTLwH/6iulUAem0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH8y9AH/1v7q/gp/yRr4Sf8AZMvAf/qK6VQB6bQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAfzL0Af/X/ur+Cn/JGvhJ/wBky8B/+orpVAHptABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/MvQB/9D+6v4Kf8ka+En/AGTLwH/6iulUAem0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH8y9AH/0f7q/gp/yRr4Sf8AZMvAf/qK6VQB6bQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAfzL0Af/S/ur+Cn/JGvhJ/wBky8B/+orpVAHptABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/MvQB/9P+6v4Kf8ka+En/AGTLwH/6iulUAem0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH8y9AH/1P7q/gp/yRr4Sf8AZMvAf/qK6VQB6bQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAfzL0Af/V/ur+Cn/JGvhJ/wBky8B/+orpVAHptABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/MvQB/9b+6v4Kf8ka+En/AGTLwH/6iulUAem0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH8y9AH/1/7q/gp/yRr4Sf8AZMvAf/qK6VQB6bQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAfzL0Af/Q/ur+Cn/JGvhJ/wBky8B/+orpVAHptABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/MvQB/9H+6v4Kf8ka+En/AGTLwH/6iulUAem0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH8y9AH/0v7q/gp/yRr4Sf8AZMvAf/qK6VQB6bQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAfzL0Af/T/ur+Cn/JGvhJ/wBky8B/+orpVAHptABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/MvQB/9T+6v4Kf8ka+En/AGTLwH/6iulUAem0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH8y9AH/1f7q/gp/yRr4Sf8AZMvAf/qK6VQB6bQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAfzL0Af/W/ur+Cn/JGvhJ/wBky8B/+orpVAHptABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/MvQB/9f+6v4Kf8ka+En/AGTLwH/6iulUAem0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH8y9AH/0P7q/gp/yRr4Sf8AZMvAf/qK6VQB6bQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAfzL0Af/R/ur+Cn/JGvhJ/wBky8B/+orpVAHptABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/MvQB/9L+6v4Kf8ka+En/AGTLwH/6iulUAem0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH8y9AH/0/7q/gp/yRr4Sf8AZMvAf/qK6VQB6bQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAfzL0Af/U/ur+Cn/JGvhJ/wBky8B/+orpVAHptABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/MvQB/9X+6v4Kf8ka+En/AGTLwH/6iulUAem0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH8y9AH/1v7q/gp/yRr4Sf8AZMvAf/qK6VQB6bQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAfzL0Af/X/ur+Cn/JGvhJ/wBky8B/+orpVAHptABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/MvQB/9D+6v4Kf8ka+En/AGTLwH/6iulUAem0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH8y9AH/0f7q/gp/yRr4Sf8AZMvAf/qK6VQB6bQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAfzL0Af/S/ur+Cn/JGvhJ/wBky8B/+orpVAHptABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/MvQB/9P+6v4Kf8ka+En/AGTLwH/6iulUAem0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFAH8y9AH/1P7q/gp/yRr4Sf8AZMvAf/qK6VQB6bQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAfzL0Af/V/ur+Cn/JGvhJ/wBky8B/+orpVAHptABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQB/MvQB/9b+6v4Kf8ka+En/AGTLwH/6iulUAem0AFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAFABQAUAF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'), + array('data:a!b#c&d-e^f_g+h.i/a!b#c&d-e^f_g+h.i;base64,foobar'), ); if (!defined('HHVM_VERSION')) { From 2eedafc2313c6cb1d9fe9f3717efb8281b89b3e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dunglas?= Date: Thu, 10 Nov 2016 11:06:30 +0100 Subject: [PATCH 091/113] [FrameworkBundle] Register the ArrayDenormalizer --- .../Resources/config/serializer.xml | 7 ++- .../Tests/Functional/SerializerTest.php | 58 +++++++++++++++++++ .../Functional/app/Serializer/bundles.php | 16 +++++ .../Functional/app/Serializer/config.yml | 6 ++ 4 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SerializerTest.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/bundles.php create mode 100644 src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml index 370b364cd9e78..c96e42c6084cb 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/serializer.xml @@ -23,10 +23,15 @@ - + + + + + + diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SerializerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SerializerTest.php new file mode 100644 index 0000000000000..ee79850c47dfb --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/SerializerTest.php @@ -0,0 +1,58 @@ + + * + * 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\Serializer\Normalizer\DataUriNormalizer; + +/** + * @author Kévin Dunglas + */ +class SerializerTest extends WebTestCase +{ + public function testDeserializeArrayOfObject() + { + if (!class_exists(DataUriNormalizer::class)) { + $this->markTestSkipped('This test is only applicable when using the Symfony Serializer Component version 3.1 or superior.'); + } + + static::bootKernel(array('test_case' => 'Serializer')); + $container = static::$kernel->getContainer(); + + $result = $container->get('serializer')->deserialize('{"bars": [{"id": 1}, {"id": 2}]}', Foo::class, 'json'); + + $bar1 = new Bar(); + $bar1->id = 1; + $bar2 = new Bar(); + $bar2->id = 2; + + $expected = new Foo(); + $expected->bars = array($bar1, $bar2); + + $this->assertEquals($expected, $result); + } +} + +class Foo +{ + /** + * @var Bar[] + */ + public $bars; +} + +class Bar +{ + /** + * @var int + */ + public $id; +} diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/bundles.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/bundles.php new file mode 100644 index 0000000000000..144db90236034 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/bundles.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +use Symfony\Bundle\FrameworkBundle\FrameworkBundle; + +return array( + new FrameworkBundle(), +); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml new file mode 100644 index 0000000000000..cac135c315d00 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/app/Serializer/config.yml @@ -0,0 +1,6 @@ +imports: + - { resource: ../config/default.yml } + +framework: + serializer: { enabled: true } + property_info: { enabled: true } From bcb03e0a395f8e862fc5ac6be87e7d920cc2da8c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luis=20Ram=C3=ADrez=20+Deimos+?= Date: Wed, 26 Oct 2016 03:27:22 -0500 Subject: [PATCH 092/113] [Form] Fix Date\TimeType marked as invalid on request with single_text and zero seconds --- .../Form/Extension/Core/Type/TimeType.php | 13 +++++++++++++ .../Tests/Extension/Core/Type/TimeTypeTest.php | 16 ++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php b/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php index 8232170278502..b482f079ebfbc 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/TimeType.php @@ -12,6 +12,8 @@ namespace Symfony\Component\Form\Extension\Core\Type; use Symfony\Component\Form\AbstractType; +use Symfony\Component\Form\FormEvent; +use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\ReversedTransformer; @@ -49,6 +51,17 @@ public function buildForm(FormBuilderInterface $builder, array $options) if ('single_text' === $options['widget']) { $builder->addViewTransformer(new DateTimeToStringTransformer($options['model_timezone'], $options['view_timezone'], $format)); + + // handle seconds ignored by user's browser when with_seconds enabled + // https://codereview.chromium.org/450533009/ + if ($options['with_seconds']) { + $builder->addEventListener(FormEvents::PRE_SUBMIT, function (FormEvent $e) { + $data = $e->getData(); + if ($data && preg_match('/^\d{2}:\d{2}$/', $data)) { + $e->setData($data.':00'); + } + }); + } } else { $hourOptions = $minuteOptions = $secondOptions = array( 'error_bubbling' => true, diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php index e8b95312b4a80..3a60d079887d3 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/TimeTypeTest.php @@ -221,6 +221,22 @@ public function testSubmitStringSingleTextWithoutMinutes() $this->assertEquals('03', $form->getViewData()); } + public function testSubmitWithSecondsAndBrowserOmissionSeconds() + { + $form = $this->factory->create('time', null, array( + 'model_timezone' => 'UTC', + 'view_timezone' => 'UTC', + 'input' => 'string', + 'widget' => 'single_text', + 'with_seconds' => true, + )); + + $form->submit('03:04'); + + $this->assertEquals('03:04:00', $form->getData()); + $this->assertEquals('03:04:00', $form->getViewData()); + } + public function testSetDataWithoutMinutes() { $form = $this->factory->create('time', null, array( From 0801f9723bb84b8f2fb9fec0c50f4605dda34cc6 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Sat, 12 Nov 2016 16:48:22 +0100 Subject: [PATCH 093/113] Tag the FormFieldRegistry as being internal --- src/Symfony/Component/DomCrawler/FormFieldRegistry.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Symfony/Component/DomCrawler/FormFieldRegistry.php b/src/Symfony/Component/DomCrawler/FormFieldRegistry.php index dbd08ff720765..7dd3d3e7a3229 100644 --- a/src/Symfony/Component/DomCrawler/FormFieldRegistry.php +++ b/src/Symfony/Component/DomCrawler/FormFieldRegistry.php @@ -15,6 +15,8 @@ /** * This is an internal class that must not be used directly. + * + * @internal */ class FormFieldRegistry { From b8f7614388ad567b647f64650271bc51e7a9c624 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 10 Nov 2016 14:30:48 -0800 Subject: [PATCH 094/113] bumped min version of Twig to 1.28 --- composer.json | 2 +- src/Symfony/Bridge/Twig/composer.json | 2 +- src/Symfony/Bundle/SecurityBundle/composer.json | 2 +- src/Symfony/Bundle/TwigBundle/composer.json | 2 +- .../WebProfilerBundle/Controller/ProfilerController.php | 4 ++-- .../Bundle/WebProfilerBundle/Profiler/TemplateManager.php | 6 ++++-- .../Resources/views/Profiler/layout.html.twig | 6 +++++- .../Resources/views/Profiler/toolbar.html.twig | 7 ++++--- 8 files changed, 19 insertions(+), 12 deletions(-) diff --git a/composer.json b/composer.json index 1a2e8c26b586f..34dfa896e3b45 100644 --- a/composer.json +++ b/composer.json @@ -21,7 +21,7 @@ "paragonie/random_compat": "~1.0", "symfony/polyfill-apcu": "~1.1", "symfony/polyfill-mbstring": "~1.1", - "twig/twig": "~1.27|~2.0", + "twig/twig": "~1.28|~2.0", "psr/log": "~1.0" }, "replace": { diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index b83dc34c7fb8f..74c98e93a50e8 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -17,7 +17,7 @@ ], "require": { "php": ">=5.3.9", - "twig/twig": "~1.27|~2.0" + "twig/twig": "~1.28|~2.0" }, "require-dev": { "symfony/asset": "~2.7", diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index ee1faf659a260..64dfae228be08 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -37,7 +37,7 @@ "symfony/yaml": "~2.0,>=2.0.5", "symfony/expression-language": "~2.6", "doctrine/doctrine-bundle": "~1.2", - "twig/twig": "~1.27|~2.0", + "twig/twig": "~1.28|~2.0", "ircmaxell/password-compat": "~1.0" }, "autoload": { diff --git a/src/Symfony/Bundle/TwigBundle/composer.json b/src/Symfony/Bundle/TwigBundle/composer.json index 4714ddb2e06fc..8c4947db65f27 100644 --- a/src/Symfony/Bundle/TwigBundle/composer.json +++ b/src/Symfony/Bundle/TwigBundle/composer.json @@ -19,7 +19,7 @@ "php": ">=5.3.9", "symfony/asset": "~2.7", "symfony/twig-bridge": "~2.7", - "twig/twig": "~1.27|~2.0", + "twig/twig": "~1.28|~2.0", "symfony/http-foundation": "~2.5", "symfony/http-kernel": "~2.7" }, diff --git a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php index 2748910a19ae8..24c83d5e1d8c6 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Controller/ProfilerController.php @@ -106,7 +106,7 @@ public function panelAction(Request $request, $token) 'panel' => $panel, 'page' => $page, 'request' => $request, - 'templates' => $this->getTemplateManager()->getTemplates($profile), + 'templates' => $this->getTemplateManager()->getNames($profile), 'is_ajax' => $request->isXmlHttpRequest(), )), 200, array('Content-Type' => 'text/html')); } @@ -200,7 +200,7 @@ public function toolbarAction(Request $request, $token) return new Response($this->twig->render('@WebProfiler/Profiler/toolbar.html.twig', array( 'position' => $position, 'profile' => $profile, - 'templates' => $this->getTemplateManager()->getTemplates($profile), + 'templates' => $this->getTemplateManager()->getNames($profile), 'profiler_url' => $url, 'token' => $token, )), 200, array('Content-Type' => 'text/html')); diff --git a/src/Symfony/Bundle/WebProfilerBundle/Profiler/TemplateManager.php b/src/Symfony/Bundle/WebProfilerBundle/Profiler/TemplateManager.php index 415034a9f80c6..91938e9be5395 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Profiler/TemplateManager.php +++ b/src/Symfony/Bundle/WebProfilerBundle/Profiler/TemplateManager.php @@ -67,7 +67,9 @@ public function getName(Profile $profile, $panel) * * @param Profile $profile * - * @return array + * @return Twig_Template[] + * + * @deprecated not used anymore internally */ public function getTemplates(Profile $profile) { @@ -88,7 +90,7 @@ public function getTemplates(Profile $profile) * * @throws \UnexpectedValueException */ - protected function getNames(Profile $profile) + public function getNames(Profile $profile) { $templates = array(); diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig index 6be34406e6196..bcf97ddcbfb46 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/layout.html.twig @@ -36,7 +36,11 @@ {% if templates is defined %}