diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 3af6c2a83bc18..e51cf88761451 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,6 @@ | Q | A | ------------- | --- -| Branch? | master / 2.7, 2.8, 3.3, or 3.4 +| Branch? | master for features / 2.7 up to 4.0 for bug fixes | Bug fix? | yes/no | New feature? | yes/no | BC breaks? | yes/no @@ -14,6 +14,5 @@ - Bug fixes must be submitted against the lowest branch where they apply (lowest branches are regularly merged to upper ones so they get the fixes too). - Features and deprecations must be submitted against the master branch. -- Please fill in this template according to the PR you're about to submit. - Replace this comment by a description of what your PR is solving. --> diff --git a/CHANGELOG-2.7.md b/CHANGELOG-2.7.md index 7ac65a77371f6..916ce96ddb47b 100644 --- a/CHANGELOG-2.7.md +++ b/CHANGELOG-2.7.md @@ -7,6 +7,20 @@ 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.39 (2017-12-04) + + * bug #25278 Fix for missing whitespace control modifier in form layout (kubawerlos) + * bug #25236 [Form][TwigBridge] Fix collision between view properties and form fields (yceruto) + * bug #25258 [link] Prevent warnings when running link with 2.7 (dunglas) + * bug #24750 [Validator] ExpressionValidator should use OBJECT_TO_STRING (Simperfit) + * bug #25182 [HttpFoundation] AutExpireFlashBag should not clear new flashes (Simperfit, sroze) + * bug #25152 [Form] Don't rely on `Symfony\Component\HttpFoundation\File\File` if http-foundation isn't in FileType (issei-m) + * bug #24987 [Console] Fix global console flag when used in chain (Simperfit) + * bug #25043 [Yaml] added ability for substitute aliases when mapping is on single line (Michał Strzelecki, xabbuh) + * bug #25102 [Form] Fixed ContextErrorException in FileType (chihiro-adachi) + * bug #25130 [DI] Fix handling of inlined definitions by ContainerBuilder (nicolas-grekas) + * bug #24956 Fix ambiguous pattern (weltling) + * 2.7.38 (2017-11-16) * security #24995 Validate redirect targets using the session cookie domain (nicolas-grekas) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 0f3e9c22adf2d..30d8ae3f828ed 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -14,8 +14,8 @@ Symfony is the result of the work of many people who made the code better - Victor Berchet (victor) - Johannes S (johannes) - Jakub Zalas (jakubzalas) - - Kris Wallsmith (kriswallsmith) - Kévin Dunglas (dunglas) + - Kris Wallsmith (kriswallsmith) - Ryan Weaver (weaverryan) - Javier Eguiluz (javier.eguiluz) - Maxime Steinhausser (ogizanagi) @@ -29,8 +29,8 @@ Symfony is the result of the work of many people who made the code better - Joseph Bielawski (stloyd) - Karma Dordrak (drak) - Lukas Kahwe Smith (lsmith) - - Martin Hasoň (hason) - Roland Franssen (ro0) + - Martin Hasoň (hason) - Jeremy Mikola (jmikola) - Jean-François Simon (jfsimon) - Benjamin Eberlei (beberlei) @@ -52,24 +52,24 @@ Symfony is the result of the work of many people who made the code better - Peter Rehm (rpet) - Saša Stamenković (umpirsky) - Henrik Bjørnskov (henrikbjorn) + - Yonel Ceruto (yonelceruto) - Miha Vrhovnik - Matthias Pigulla (mpdude) - Diego Saint Esteben (dii3g0) - Konstantin Kudryashov (everzet) - Bilal Amarni (bamarni) - - Yonel Ceruto (yonelceruto) - - Dany Maillard (maidmaid) - Kevin Bond (kbond) + - Dany Maillard (maidmaid) + - Pierre du Plessis (pierredup) - Florin Patan (florinpatan) - Jérémy DERUSSÉ (jderusse) - - Pierre du Plessis (pierredup) - Gábor Egyed (1ed) - Michel Weimerskirch (mweimerskirch) - Andrej Hudec (pulzarraider) + - Alexander M. Turek (derrabus) - Eric Clemmons (ericclemmons) - Jáchym Toušek (enumag) - Charles Sarrazin (csarrazi) - - Alexander M. Turek (derrabus) - Konstantin Myakshin (koc) - Christian Raue - Arnout Boks (aboks) @@ -79,6 +79,7 @@ Symfony is the result of the work of many people who made the code better - Titouan Galopin (tgalopin) - Douglas Greenshields (shieldo) - Tobias Nyholm (tobias) + - Issei Murasawa (issei_m) - Lee McDermott - Brandon Turner - Luis Cordova (cordoval) @@ -91,13 +92,14 @@ Symfony is the result of the work of many people who made the code better - John Wards (johnwards) - Dariusz Ruminski - Fran Moreno (franmomu) - - Issei Murasawa (issei_m) - Antoine Hérault (herzult) - Paráda József (paradajozsef) - Arnaud Le Blanc (arnaud-lb) - Maxime STEINHAUSSER - Michal Piotrowski (eventhorizon) + - Samuel ROZE (sroze) - Tim Nagel (merk) + - Amrouche Hamza (simperfit) - Brice BERNARD (brikou) - Baptiste Clavié (talus) - Vladimir Reznichenko (kalessil) @@ -126,6 +128,7 @@ Symfony is the result of the work of many people who made the code better - Sebastiaan Stok (sstok) - Stefano Sala (stefano.sala) - Evgeniy (ewgraf) + - Grégoire Paris (greg0ire) - Vincent AUBERT (vincent) - Juti Noppornpitak (shiroyuki) - Tigran Azatyan (tigranazatyan) @@ -135,7 +138,6 @@ Symfony is the result of the work of many people who made the code better - Guilherme Blanco (guilhermeblanco) - Pablo Godel (pgodel) - Jérémie Augustin (jaugustin) - - Grégoire Paris (greg0ire) - Andréia Bohner (andreia) - Rafael Dohms (rdohms) - Arnaud Kleinpeter (nanocom) @@ -149,6 +151,7 @@ Symfony is the result of the work of many people who made the code better - Vyacheslav Pavlov - Richard van Laak (rvanlaak) - Javier Spagnoletti (phansys) + - Julien Falque (julienfalque) - Richard Shank (iampersistent) - Thomas Rabaix (rande) - Rouven Weßling (realityking) @@ -160,7 +163,6 @@ Symfony is the result of the work of many people who made the code better - Matthieu Ouellette-Vachon (maoueh) - Michał Pipa (michal.pipa) - Dawid Nowak - - Julien Falque (julienfalque) - Amal Raghav (kertz) - Jonathan Ingram (jonathaningram) - Artur Kotyrba @@ -171,8 +173,6 @@ Symfony is the result of the work of many people who made the code better - Warnar Boekkooi (boekkooi) - Dmitrii Chekaliuk (lazyhammer) - Clément JOBEILI (dator) - - Amrouche Hamza - - Samuel ROZE (sroze) - Daniel Espendiller - Possum - Dorian Villet (gnutix) @@ -190,6 +190,7 @@ Symfony is the result of the work of many people who made the code better - Stepan Anchugov (kix) - bronze1man - sun (sun) + - Valentin Udaltsov (vudaltsov) - Larry Garfield (crell) - Martin Schuhfuß (usefulthink) - apetitpa @@ -248,7 +249,6 @@ Symfony is the result of the work of many people who made the code better - Pierre-Yves LEBECQ (pylebecq) - Jordan Samouh (jordansamouh) - Jakub Kucharovic (jkucharovic) - - Valentin Udaltsov (vudaltsov) - Uwe Jäger (uwej711) - Eugene Leonovich (rybakit) - Filippo Tessarotto @@ -261,6 +261,7 @@ Symfony is the result of the work of many people who made the code better - Nikolay Labinskiy (e-moe) - Leo Feyer - Chekote + - gadelat (gadelat) - Thomas Adam - Albert Casademont (acasademont) - Jhonny Lidfors (jhonne) @@ -299,8 +300,8 @@ Symfony is the result of the work of many people who made the code better - Thomas Tourlourat (armetiz) - Andrey Esaulov (andremaha) - Grégoire Passault (gregwar) + - Jerzy Zawadzki (jzawadzki) - Ismael Ambrosi (iambrosi) - - gadelat (gadelat) - Baptiste Lafontaine - Aurelijus Valeiša (aurelijus) - Victor Bocharsky (bocharsky_bw) @@ -345,6 +346,7 @@ Symfony is the result of the work of many people who made the code better - Yaroslav Kiliba - Terje Bråten - Robbert Klarenbeek (robbertkl) + - Edi Modrić (emodric) - Thomas Calvet (fancyweb) - Niels Keurentjes (curry684) - JhonnyL @@ -364,7 +366,6 @@ Symfony is the result of the work of many people who made the code better - Loïc Chardonnet (gnusat) - Marek Kalnik (marekkalnik) - Vyacheslav Salakhutdinov (megazoll) - - Jerzy Zawadzki (jzawadzki) - Hassan Amouhzi - Tamas Szijarto - Pavel Volokitin (pvolok) @@ -375,6 +376,7 @@ Symfony is the result of the work of many people who made the code better - Tobias Naumann (tna) - Daniel Beyer - Shein Alexey + - Alex Rock Ancelet (pierstoval) - Romain Gautier (mykiwi) - Joe Lencioni - Daniel Tschinder @@ -434,7 +436,6 @@ Symfony is the result of the work of many people who made the code better - cedric lombardot (cedriclombardot) - Jonas Flodén (flojon) - Thomas Perez (scullwm) - - Edi Modrić (emodric) - Marcin Sikoń (marphi) - Dominik Zogg (dominik.zogg) - Marek Pietrzak @@ -446,6 +447,7 @@ Symfony is the result of the work of many people who made the code better - Rob Bast - Zander Baldwin - Adam Harvey + - Anton Bakai - Maxime Veber (nek-) - Alex Bakhturin - Yanick Witschi (toflar) @@ -495,7 +497,6 @@ Symfony is the result of the work of many people who made the code better - Arjen van der Meijden - Michele Locati - Dariusz Ruminski - - Alex Rock Ancelet (pierstoval) - Erik Trapman (eriktrapman) - De Cock Xavier (xdecock) - Almog Baku (almogbaku) @@ -619,7 +620,6 @@ Symfony is the result of the work of many people who made the code better - Catalin Dan - Stephan Vock - Benjamin Zikarsky (bzikarsky) - - Anton Bakai - Simon Schick (simonsimcity) - redstar504 - Tristan Roussel @@ -711,8 +711,10 @@ Symfony is the result of the work of many people who made the code better - Nikita Nefedov (nikita2206) - cgonzalez - Ben + - Mathieu Lechat - Vincent Composieux (eko) - Jayson Xu (superjavason) + - Christopher Hertel (chertel) - Hubert Lenoir (hubert_lenoir) - Jaik Dean (jaikdean) - fago @@ -733,6 +735,7 @@ Symfony is the result of the work of many people who made the code better - Pierre Vanliefland (pvanliefland) - Sofiane HADDAG (sofhad) - frost-nzcr4 + - Bozhidar Hristov - Abhoryo - Fabian Vogler (fabian) - Korvin Szanto @@ -763,6 +766,7 @@ Symfony is the result of the work of many people who made the code better - Fabien LUCAS (flucas2) - Jörn Lang (j.lang) - Omar Yepez (oyepez003) + - Gawain Lynch (gawain) - mwsaz - Jelle Kapitein - Benoît Bourgeois @@ -925,6 +929,7 @@ Symfony is the result of the work of many people who made the code better - Christian - Denis Golubovskiy (bukashk0zzz) - Sergii Smertin (nfx) + - Michał Strzelecki - hugofonseca (fonsecas72) - Martynas Narbutas - Bailey Parker @@ -1002,6 +1007,7 @@ Symfony is the result of the work of many people who made the code better - Brooks Boyd - Roger Webb - Dmitriy Simushev + - pkowalczyk - Max Voloshin (maxvoloshin) - Nicolas Fabre (nfabre) - Raul Rodriguez (raul782) @@ -1127,6 +1133,7 @@ Symfony is the result of the work of many people who made the code better - Max Summe - WedgeSama - Felds Liscia + - Chihiro Adachi (chihiro-adachi) - Sullivan SENECHAL - Tadcka - Beth Binkovitz @@ -1283,6 +1290,7 @@ Symfony is the result of the work of many people who made the code better - nuncanada - flack - František Bereň + - Jeremiah VALERIE - Mike Francis - Christoph Nissle (derstoffel) - Ionel Scutelnicu (ionelscutelnicu) @@ -1305,6 +1313,7 @@ Symfony is the result of the work of many people who made the code better - Andrew Zhilin (zhil) - Oleksii Zhurbytskyi - Andy Stanberry + - Felix Marezki - Luiz “Felds” Liscia - Thomas Rothe - nietonfir @@ -1352,7 +1361,6 @@ Symfony is the result of the work of many people who made the code better - Nicole Cordes - Martin Kirilov - Bram Van der Sype (brammm) - - Christopher Hertel (chertel) - Guile (guile) - Julien Moulin (lizjulien) - Mauro Foti (skler) @@ -1386,7 +1394,6 @@ Symfony is the result of the work of many people who made the code better - Bertalan Attila - Yannick Bensacq (cibou) - Freek Van der Herten (freekmurze) - - Gawain Lynch (gawain) - Luca Genuzio (genuzio) - Hans Nilsson (hansnilsson) - Andrew Marcinkevičius (ifdattic) @@ -1444,6 +1451,7 @@ Symfony is the result of the work of many people who made the code better - David Windell - Gabriel Birke - skafandri + - Derek Bonner - Alan Chen - Maerlyn - Even André Fiskvik @@ -1487,6 +1495,7 @@ Symfony is the result of the work of many people who made the code better - Ian Jenkins (jenkoian) - Jorge Martin (jorgemartind) - Joeri Verdeyen (jverdeyen) + - Dmitrii Poddubnyi (karser) - Kevin Verschaeve (keversc) - Kevin Herrera (kherge) - Luis Ramón López López (lrlopez) @@ -1500,6 +1509,7 @@ Symfony is the result of the work of many people who made the code better - Jimmy Leger (redpanda) - Marcin Szepczynski (szepczynski) - Cyrille Jouineau (tuxosaurus) + - Vladimir Chernyshev (volch) - Yorkie Chadwick (yorkie76) - GuillaumeVerdon - Ondrej Mirtes @@ -1582,9 +1592,11 @@ Symfony is the result of the work of many people who made the code better - Michael Schneider - Cédric Bertolini - n-aleha + - Anatol Belski - Şəhriyar İmanov - Kaipi Yann - Sam Williams + - Guillaume Aveline - Adrian Philipp - James Michael DuPont - Kasperki @@ -1744,6 +1756,7 @@ Symfony is the result of the work of many people who made the code better - Schuyler Jager (sjager) - Pascal Luna (skalpa) - Volker (skydiablo) + - Serkan Yildiz (srknyldz) - Julien Sanchez (sumbobyboys) - Guillermo Gisinger (t3chn0r) - Markus Tacker (tacker) diff --git a/composer.json b/composer.json index f067b4bbe20b2..f263c15d45324 100644 --- a/composer.json +++ b/composer.json @@ -80,7 +80,7 @@ "monolog/monolog": "~1.11", "ircmaxell/password-compat": "~1.0", "ocramius/proxy-manager": "~0.4|~1.0|~2.0", - "symfony/phpunit-bridge": "~3.2", + "symfony/phpunit-bridge": "~3.4|~4.0", "egulias/email-validator": "~1.2,>=1.2.1", "sensio/framework-extra-bundle": "^3.0.2" }, diff --git a/link b/link new file mode 100755 index 0000000000000..a5030d0683379 --- /dev/null +++ b/link @@ -0,0 +1,66 @@ +#!/usr/bin/env php + +* +* For the full copyright and license information, please view the LICENSE +* file that was distributed with this source code. +*/ + +require __DIR__.'/src/Symfony/Component/Filesystem/Exception/ExceptionInterface.php'; +require __DIR__.'/src/Symfony/Component/Filesystem/Exception/IOExceptionInterface.php'; +require __DIR__.'/src/Symfony/Component/Filesystem/Exception/IOException.php'; +require __DIR__.'/src/Symfony/Component/Filesystem/Filesystem.php'; + +use Symfony\Component\Filesystem\Filesystem; + +/** + * Links dependencies to components to a local clone of the main symfony/symfony GitHub repository. + * + * @author Kévin Dunglas + */ + +if (2 !== $argc) { + echo 'Link dependencies to components to a local clone of the main symfony/symfony GitHub repository.'.PHP_EOL.PHP_EOL; + echo "Usage: $argv[0] /path/to/the/project".PHP_EOL; + exit(1); +} + +if (!is_dir("$argv[1]/vendor/symfony")) { + echo "The directory \"$argv[1]\" does not exist or the dependencies are not installed, did you forget to run \"composer install\" in your project?".PHP_EOL; + exit(1); +} + +$sfPackages = array('symfony/symfony' => __DIR__); + +$filesystem = new Filesystem(); +foreach (glob(__DIR__.'/src/Symfony/{Bundle,Bridge,Component,Component/Security}/*', GLOB_BRACE | GLOB_ONLYDIR | GLOB_NOSORT) as $dir) { + if ($filesystem->exists($composer = "$dir/composer.json")) { + $sfPackages[json_decode(file_get_contents($composer))->name] = $dir; + } +} + +foreach (glob("$argv[1]/vendor/symfony/*", GLOB_ONLYDIR | GLOB_NOSORT) as $dir) { + $package = 'symfony/'.basename($dir); + if (is_link($dir)) { + echo "\"$package\" is already a symlink, skipping.".PHP_EOL; + continue; + } + + if (!isset($sfPackages[$package])) { + continue; + } + + $sfDir = '\\' === DIRECTORY_SEPARATOR ? $sfPackages[$package] : $filesystem->makePathRelative($sfPackages[$package], dirname(realpath($dir))); + + $filesystem->remove($dir); + $filesystem->symlink($sfDir, $dir); + echo "\"$package\" has been linked to \"$sfPackages[$package]\".".PHP_EOL; +} + +foreach (glob("$argv[1]/var/cache/*") as $cacheDir) { + $filesystem->remove($cacheDir); +} diff --git a/phpunit b/phpunit index 53e1a8dc31dbf..c0ffe8ddef9e9 100755 --- a/phpunit +++ b/phpunit @@ -1,7 +1,7 @@ #!/usr/bin/env php value === $selectedValue; } + /** + * @internal + */ + public function isRootForm(FormView $formView) + { + return null === $formView->parent; + } + /** * {@inheritdoc} */ diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig index 2efc0c4d4a213..e3c76349648e5 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/bootstrap_3_layout.html.twig @@ -238,12 +238,12 @@ {% block form_errors -%} {% if errors|length > 0 -%} - {% if form.parent %}{% else %}
{% endif %} + {% if form is not rootform %}{% else %}
{% endif %}
    {%- for error in errors -%}
  • {{ error.message }}
  • {%- endfor -%}
- {% if form.parent %}{% else %}
{% endif %} + {% if form is not rootform %}
{% else %}
{% endif %} {%- endif %} {%- endblock form_errors %} diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig index a27c81dd495ae..7df55bc4d3879 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_div_layout.html.twig @@ -15,7 +15,7 @@ {%- block form_widget_compound -%}
- {%- if form.parent is empty -%} + {%- if form is rootform -%} {{ form_errors(form) }} {%- endif -%} {{- block('form_rows') -}} @@ -301,9 +301,9 @@ {% if not child.rendered %} {{- form_row(child) -}} {% endif %} - {%- endfor %} + {%- endfor -%} - {% if not form.methodRendered and form.parent is null %} + {% if not form.methodRendered and form is rootform %} {%- do form.setMethodRendered() -%} {% set method = method|upper %} {%- if method in ["GET", "POST"] -%} @@ -315,7 +315,7 @@ {%- if form_method != method -%} {%- endif -%} - {% endif %} + {% endif -%} {% endblock form_rest %} {# Support #} diff --git a/src/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig b/src/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig index c7b3a4365b51b..39274c6c8d058 100644 --- a/src/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig +++ b/src/Symfony/Bridge/Twig/Resources/views/Form/form_table_layout.html.twig @@ -31,7 +31,7 @@ {%- block form_widget_compound -%} - {%- if form.parent is empty and errors|length > 0 -%} + {%- if form is rootform and errors|length > 0 -%}
{{- form_errors(form) -}} diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php index e2fbb48ce0339..e11daf1831349 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/FormExtensionDivLayoutTest.php @@ -146,6 +146,22 @@ public function testIsChoiceSelected($expected, $choice, $value) $this->assertSame($expected, $this->extension->isSelectedChoice($choice, $value)); } + public function isRootFormProvider() + { + return array( + array(true, new FormView()), + array(false, new FormView(new FormView())), + ); + } + + /** + * @dataProvider isRootFormProvider + */ + public function testIsRootForm($expected, FormView $formView) + { + $this->assertSame($expected, $this->extension->isRootForm($formView)); + } + protected function renderForm(FormView $view, array $vars = array()) { return (string) $this->extension->renderer->renderBlock($view, 'form', $vars); diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php index 14b6e4428e550..c4d6d837c6a7a 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Controller/RedirectControllerTest.php @@ -290,7 +290,7 @@ private function createRedirectController($httpPort = null, $httpsPort = null) return $controller; } - public function assertRedirectUrl(Response $returnResponse, $expectedUrl) + private function assertRedirectUrl(Response $returnResponse, $expectedUrl) { $this->assertTrue($returnResponse->isRedirect($expectedUrl), "Expected: $expectedUrl\nGot: ".$returnResponse->headers->get('Location')); } diff --git a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/AddSessionDomainConstraintPassTest.php b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/AddSessionDomainConstraintPassTest.php index f476b5ef7313e..7d49ad3dd4ec6 100644 --- a/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/AddSessionDomainConstraintPassTest.php +++ b/src/Symfony/Bundle/SecurityBundle/Tests/DependencyInjection/Compiler/AddSessionDomainConstraintPassTest.php @@ -124,7 +124,8 @@ private function createContainer($sessionStorageOptions) $ext = new SecurityExtension(); $ext->load($config, $container); - (new AddSessionDomainConstraintPass())->process($container); + $pass = new AddSessionDomainConstraintPass(); + $pass->process($container); return $container; } diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 8964f10789bec..6ab9f011ac757 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -113,11 +113,10 @@ public function run(InputInterface $input = null, OutputInterface $output = null $e = null; $exitCode = $this->doRun($input, $output); } catch (\Exception $e) { - } catch (\Throwable $e) { } if (null !== $e) { - if (!$this->catchExceptions || !$e instanceof \Exception) { + if (!$this->catchExceptions) { throw $e; } @@ -1015,8 +1014,8 @@ public function extractNamespace($name, $limit = null) * Finds alternative of $name among $collection, * if nothing is found in $collection, try in $abbrevs. * - * @param string $name The string - * @param array|\Traversable $collection The collection + * @param string $name The string + * @param iterable $collection The collection * * @return string[] A sorted array of similar string */ diff --git a/src/Symfony/Component/Console/Input/ArgvInput.php b/src/Symfony/Component/Console/Input/ArgvInput.php index c2f533eb36798..4493a5bafc3b9 100644 --- a/src/Symfony/Component/Console/Input/ArgvInput.php +++ b/src/Symfony/Component/Console/Input/ArgvInput.php @@ -282,6 +282,14 @@ public function hasParameterOption($values) if ($token === $value || 0 === strpos($token, $value.'=')) { return true; } + + if (0 === strpos($token, '-') && 0 !== strpos($token, '--')) { + $searchableToken = str_replace('-', '', $token); + $searchableValue = str_replace('-', '', $value); + if ('' !== $searchableToken && '' !== $searchableValue && false !== strpos($searchableToken, $searchableValue)) { + return true; + } + } } } diff --git a/src/Symfony/Component/Console/Question/Question.php b/src/Symfony/Component/Console/Question/Question.php index bece3e59752ad..d94836b85b785 100644 --- a/src/Symfony/Component/Console/Question/Question.php +++ b/src/Symfony/Component/Console/Question/Question.php @@ -114,7 +114,7 @@ public function setHiddenFallback($fallback) /** * Gets values for the autocompleter. * - * @return null|array|\Traversable + * @return null|iterable */ public function getAutocompleterValues() { @@ -124,7 +124,7 @@ public function getAutocompleterValues() /** * Sets values for the autocompleter. * - * @param null|array|\Traversable $values + * @param null|iterable $values * * @return $this * diff --git a/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php b/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php index 1fe21d0f6c1a8..85fb533715b62 100644 --- a/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php +++ b/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php @@ -296,6 +296,9 @@ public function testHasParameterOption() $input = new ArgvInput(array('cli.php', '-f', 'foo')); $this->assertTrue($input->hasParameterOption('-f'), '->hasParameterOption() returns true if the given short option is in the raw input'); + $input = new ArgvInput(array('cli.php', '-fh')); + $this->assertTrue($input->hasParameterOption('-fh'), '->hasParameterOption() returns true if the given short option is in the raw input'); + $input = new ArgvInput(array('cli.php', '--foo', 'foo')); $this->assertTrue($input->hasParameterOption('--foo'), '->hasParameterOption() returns true if the given short option is in the raw input'); diff --git a/src/Symfony/Component/Debug/Tests/Fixtures/Throwing.php b/src/Symfony/Component/Debug/Tests/Fixtures/Throwing.php index d338ca9d5752b..21e0aba17d358 100644 --- a/src/Symfony/Component/Debug/Tests/Fixtures/Throwing.php +++ b/src/Symfony/Component/Debug/Tests/Fixtures/Throwing.php @@ -1,5 +1,3 @@ loading[$id] = true; try { - $service = $this->createService($definition, $id); + $service = $this->createService($definition, new \SplObjectStorage(), $id); } catch (\Exception $e) { unset($this->loading[$id]); @@ -827,8 +827,12 @@ public function findDefinition($id) * * @internal this method is public because of PHP 5.3 limitations, do not use it explicitly in your code */ - public function createService(Definition $definition, $id, $tryProxy = true) + public function createService(Definition $definition, \SplObjectStorage $inlinedDefinitions, $id = null, $tryProxy = true) { + if (null === $id && isset($inlinedDefinitions[$definition])) { + return $inlinedDefinitions[$definition]; + } + if ($definition instanceof DefinitionDecorator) { throw new RuntimeException(sprintf('Constructing service "%s" from a parent definition is not supported at build time.', $id)); } @@ -845,11 +849,11 @@ public function createService(Definition $definition, $id, $tryProxy = true) ->instantiateProxy( $container, $definition, - $id, function () use ($definition, $id, $container) { - return $container->createService($definition, $id, false); + $id, function () use ($definition, $inlinedDefinitions, $id, $container) { + return $container->createService($definition, $inlinedDefinitions, $id, false); } ); - $this->shareService($definition, $proxy, $id); + $this->shareService($definition, $proxy, $id, $inlinedDefinitions); return $proxy; } @@ -860,11 +864,11 @@ public function createService(Definition $definition, $id, $tryProxy = true) require_once $parameterBag->resolveValue($definition->getFile()); } - $arguments = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments()))); + $arguments = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getArguments())), $inlinedDefinitions); if (null !== $factory = $definition->getFactory()) { if (is_array($factory)) { - $factory = array($this->resolveServices($parameterBag->resolveValue($factory[0])), $factory[1]); + $factory = array($this->doResolveServices($parameterBag->resolveValue($factory[0]), $inlinedDefinitions), $factory[1]); } elseif (!is_string($factory)) { throw new RuntimeException(sprintf('Cannot create service "%s" because of invalid factory', $id)); } @@ -888,16 +892,16 @@ public function createService(Definition $definition, $id, $tryProxy = true) if ($tryProxy || !$definition->isLazy()) { // share only if proxying failed, or if not a proxy - $this->shareService($definition, $service, $id); + $this->shareService($definition, $service, $id, $inlinedDefinitions); } - $properties = $this->resolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties()))); + $properties = $this->doResolveServices($parameterBag->unescapeValue($parameterBag->resolveValue($definition->getProperties())), $inlinedDefinitions); foreach ($properties as $name => $value) { $service->$name = $value; } foreach ($definition->getMethodCalls() as $call) { - $this->callMethod($service, $call); + $this->callMethod($service, $call, $inlinedDefinitions); } if ($callable = $definition->getConfigurator()) { @@ -907,7 +911,7 @@ public function createService(Definition $definition, $id, $tryProxy = true) if ($callable[0] instanceof Reference) { $callable[0] = $this->get((string) $callable[0], $callable[0]->getInvalidBehavior()); } elseif ($callable[0] instanceof Definition) { - $callable[0] = $this->createService($callable[0], null); + $callable[0] = $this->createService($callable[0], $inlinedDefinitions); } } @@ -930,15 +934,20 @@ public function createService(Definition $definition, $id, $tryProxy = true) * the real service instances and all expressions evaluated */ public function resolveServices($value) + { + return $this->doResolveServices($value, new \SplObjectStorage()); + } + + private function doResolveServices($value, \SplObjectStorage $inlinedDefinitions) { if (is_array($value)) { foreach ($value as $k => $v) { - $value[$k] = $this->resolveServices($v); + $value[$k] = $this->doResolveServices($v, $inlinedDefinitions); } } elseif ($value instanceof Reference) { $value = $this->get((string) $value, $value->getInvalidBehavior()); } elseif ($value instanceof Definition) { - $value = $this->createService($value, null); + $value = $this->createService($value, $inlinedDefinitions); } elseif ($value instanceof Expression) { $value = $this->getExpressionLanguage()->evaluate($value, array('container' => $this)); } @@ -1065,14 +1074,14 @@ private function synchronize($id) foreach ($definition->getMethodCalls() as $call) { foreach ($call[1] as $argument) { if ($argument instanceof Reference && $id == (string) $argument) { - $this->callMethod($this->get($definitionId), $call); + $this->callMethod($this->get($definitionId), $call, new \SplObjectStorage()); } } } } } - private function callMethod($service, $call) + private function callMethod($service, $call, \SplObjectStorage $inlinedDefinitions) { $services = self::getServiceConditionals($call[1]); @@ -1082,7 +1091,7 @@ private function callMethod($service, $call) } } - call_user_func_array(array($service, $call[0]), $this->resolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])))); + call_user_func_array(array($service, $call[0]), $this->doResolveServices($this->getParameterBag()->unescapeValue($this->getParameterBag()->resolveValue($call[1])), $inlinedDefinitions)); } /** @@ -1094,9 +1103,14 @@ private function callMethod($service, $call) * * @throws InactiveScopeException */ - private function shareService(Definition $definition, $service, $id) + private function shareService(Definition $definition, $service, $id, \SplObjectStorage $inlinedDefinitions) { - if (null !== $id && self::SCOPE_PROTOTYPE !== $scope = $definition->getScope()) { + if (self::SCOPE_PROTOTYPE === $scope = $definition->getScope()) { + return; + } + if (null === $id) { + $inlinedDefinitions[$definition] = $service; + } else { if (self::SCOPE_CONTAINER !== $scope && !isset($this->scopedServices[$scope])) { throw new InactiveScopeException($id, $scope); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index f4274b80a4443..32e1b99adb255 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -827,6 +827,28 @@ public function testLazyLoadedService() $this->assertTrue($classInList); } + public function testInlinedDefinitions() + { + $container = new ContainerBuilder(); + + $definition = new Definition('BarClass'); + + $container->register('bar_user', 'BarUserClass') + ->addArgument($definition) + ->setProperty('foo', $definition); + + $container->register('bar', 'BarClass') + ->setProperty('foo', $definition) + ->addMethodCall('setBaz', array($definition)); + + $barUser = $container->get('bar_user'); + $bar = $container->get('bar'); + + $this->assertSame($barUser->foo, $barUser->bar); + $this->assertSame($bar->foo, $bar->getBaz()); + $this->assertNotSame($bar->foo, $barUser->foo); + } + public function testInitializePropertiesBeforeMethodCalls() { $container = new ContainerBuilder(); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/classes.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/classes.php index 0ecdea3fbfb89..92db8f3c5ebfb 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/classes.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/includes/classes.php @@ -8,7 +8,7 @@ function sc_configure($instance) $instance->configure(); } -class BarClass +class BarClass extends BazClass { protected $baz; public $foo = 'foo'; diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index 1c10366cee414..40371d9307cd2 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -83,8 +83,8 @@ public function copy($originFile, $targetFile, $overwriteNewerFiles = false) /** * Creates a directory recursively. * - * @param string|array|\Traversable $dirs The directory path - * @param int $mode The directory mode + * @param string|iterable $dirs The directory path + * @param int $mode The directory mode * * @throws IOException On any directory creation failure */ @@ -111,7 +111,7 @@ public function mkdir($dirs, $mode = 0777) /** * Checks the existence of files or directories. * - * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to check + * @param string|iterable $files A filename, an array of files, or a \Traversable instance to check * * @return bool true if the file exists, false otherwise */ @@ -135,9 +135,9 @@ public function exists($files) /** * Sets access and modification time of file. * - * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to create - * @param int $time The touch time as a Unix timestamp - * @param int $atime The access time as a Unix timestamp + * @param string|iterable $files A filename, an array of files, or a \Traversable instance to create + * @param int $time The touch time as a Unix timestamp + * @param int $atime The access time as a Unix timestamp * * @throws IOException When touch fails */ @@ -154,7 +154,7 @@ public function touch($files, $time = null, $atime = null) /** * Removes files or directories. * - * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to remove + * @param string|iterable $files A filename, an array of files, or a \Traversable instance to remove * * @throws IOException When removal fails */ @@ -190,10 +190,10 @@ public function remove($files) /** * Change mode for an array of files or directories. * - * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change mode - * @param int $mode The new mode (octal) - * @param int $umask The mode mask (octal) - * @param bool $recursive Whether change the mod recursively or not + * @param string|iterable $files A filename, an array of files, or a \Traversable instance to change mode + * @param int $mode The new mode (octal) + * @param int $umask The mode mask (octal) + * @param bool $recursive Whether change the mod recursively or not * * @throws IOException When the change fail */ @@ -212,9 +212,9 @@ public function chmod($files, $mode, $umask = 0000, $recursive = false) /** * Change the owner of an array of files or directories. * - * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change owner - * @param string $user The new owner user name - * @param bool $recursive Whether change the owner recursively or not + * @param string|iterable $files A filename, an array of files, or a \Traversable instance to change owner + * @param string $user The new owner user name + * @param bool $recursive Whether change the owner recursively or not * * @throws IOException When the change fail */ @@ -239,9 +239,9 @@ public function chown($files, $user, $recursive = false) /** * Change the group of an array of files or directories. * - * @param string|array|\Traversable $files A filename, an array of files, or a \Traversable instance to change group - * @param string $group The group name - * @param bool $recursive Whether change the group recursively or not + * @param string|iterable $files A filename, an array of files, or a \Traversable instance to change group + * @param string $group The group name + * @param bool $recursive Whether change the group recursively or not * * @throws IOException When the change fail */ diff --git a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php index 676987e641216..418aa3200cc17 100644 --- a/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php +++ b/src/Symfony/Component/Form/ChoiceList/ArrayChoiceList.php @@ -58,11 +58,11 @@ class ArrayChoiceList implements ChoiceListInterface * * The given choice array must have the same array keys as the value array. * - * @param array|\Traversable $choices The selectable choices - * @param callable|null $value The callable for creating the value - * for a choice. If `null` is passed, - * incrementing integers are used as - * values + * @param iterable $choices The selectable choices + * @param callable|null $value The callable for creating the value + * for a choice. If `null` is passed, + * incrementing integers are used as + * values */ public function __construct($choices, $value = null) { diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/ChoiceListFactoryInterface.php b/src/Symfony/Component/Form/ChoiceList/Factory/ChoiceListFactoryInterface.php index 7933dd91d48d7..c66ce0f028d37 100644 --- a/src/Symfony/Component/Form/ChoiceList/Factory/ChoiceListFactoryInterface.php +++ b/src/Symfony/Component/Form/ChoiceList/Factory/ChoiceListFactoryInterface.php @@ -31,9 +31,9 @@ interface ChoiceListFactoryInterface * The callable receives the choice as first and the array key as the second * argument. * - * @param array|\Traversable $choices The choices - * @param null|callable $value The callable generating the choice - * values + * @param iterable $choices The choices + * @param null|callable $value The callable generating the choice + * values * * @return ChoiceListInterface The choice list */ diff --git a/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php b/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php index 82b2082f33e1f..42f7b916f6ed6 100644 --- a/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php +++ b/src/Symfony/Component/Form/ChoiceList/Factory/PropertyAccessDecorator.php @@ -63,7 +63,7 @@ public function getDecoratedFactory() /** * {@inheritdoc} * - * @param array|\Traversable $choices The choices + * @param iterable $choices The choices * @param null|callable|string|PropertyPath $value The callable or path for * generating the choice values * diff --git a/src/Symfony/Component/Form/Extension/Core/Type/FileType.php b/src/Symfony/Component/Form/Extension/Core/Type/FileType.php index fc5b1aae68329..7d84512d9b3c7 100644 --- a/src/Symfony/Component/Form/Extension/Core/Type/FileType.php +++ b/src/Symfony/Component/Form/Extension/Core/Type/FileType.php @@ -34,8 +34,13 @@ public function buildForm(FormBuilderInterface $builder, array $options) if ($options['multiple']) { $data = array(); + $files = $event->getData(); - foreach ($event->getData() as $file) { + if (!is_array($files)) { + $files = array(); + } + + foreach ($files as $file) { if ($requestHandler->isFileUpload($file)) { $data[] = $file; } @@ -87,9 +92,12 @@ public function finishView(FormView $view, FormInterface $form, array $options) */ public function configureOptions(OptionsResolver $resolver) { - $dataClass = function (Options $options) { - return $options['multiple'] ? null : 'Symfony\Component\HttpFoundation\File\File'; - }; + $dataClass = null; + if (class_exists('Symfony\Component\HttpFoundation\File\File')) { + $dataClass = function (Options $options) { + return $options['multiple'] ? null : 'Symfony\Component\HttpFoundation\File\File'; + }; + } $emptyData = function (Options $options) { return $options['multiple'] ? array() : null; diff --git a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php index 368a5a80a1481..571db0eb41dfc 100644 --- a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php +++ b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php @@ -108,6 +108,9 @@ public function handleRequest(FormInterface $form, $request = null) $form->submit($data, 'PATCH' !== $method); } + /** + * {@inheritdoc} + */ public function isFileUpload($data) { return $data instanceof File; diff --git a/src/Symfony/Component/Form/FormConfigBuilder.php b/src/Symfony/Component/Form/FormConfigBuilder.php index f51881a092c97..243ef89f312cf 100644 --- a/src/Symfony/Component/Form/FormConfigBuilder.php +++ b/src/Symfony/Component/Form/FormConfigBuilder.php @@ -32,7 +32,7 @@ class FormConfigBuilder implements FormConfigBuilderInterface * * @var NativeRequestHandler */ - private static $nativeRequestProcessor; + private static $nativeRequestHandler; /** * The accepted request methods. @@ -511,10 +511,10 @@ public function getMethod() public function getRequestHandler() { if (null === $this->requestHandler) { - if (null === self::$nativeRequestProcessor) { - self::$nativeRequestProcessor = new NativeRequestHandler(); + if (null === self::$nativeRequestHandler) { + self::$nativeRequestHandler = new NativeRequestHandler(); } - $this->requestHandler = self::$nativeRequestProcessor; + $this->requestHandler = self::$nativeRequestHandler; } return $this->requestHandler; diff --git a/src/Symfony/Component/Form/NativeRequestHandler.php b/src/Symfony/Component/Form/NativeRequestHandler.php index f68efe25cfe54..37e1c99a74505 100644 --- a/src/Symfony/Component/Form/NativeRequestHandler.php +++ b/src/Symfony/Component/Form/NativeRequestHandler.php @@ -118,6 +118,9 @@ public function handleRequest(FormInterface $form, $request = null) $form->submit($data, 'PATCH' !== $method); } + /** + * {@inheritdoc} + */ public function isFileUpload($data) { // POST data will always be strings or arrays of strings. Thus, we can be sure diff --git a/src/Symfony/Component/Form/RequestHandlerInterface.php b/src/Symfony/Component/Form/RequestHandlerInterface.php index e6360e449889f..3d7b45d5064af 100644 --- a/src/Symfony/Component/Form/RequestHandlerInterface.php +++ b/src/Symfony/Component/Form/RequestHandlerInterface.php @@ -27,7 +27,9 @@ interface RequestHandlerInterface public function handleRequest(FormInterface $form, $request = null); /** - * @param mixed $data + * Returns true if the given data is a file upload. + * + * @param mixed $data The form field data * * @return bool */ diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php index 5d6fe1e20d668..646470ff5abf9 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/FileTypeTest.php @@ -158,6 +158,24 @@ public function testMultipleSubmittedFilePathsAreDropped(RequestHandlerInterface $this->assertCount(1, $form->getData()); } + /** + * @dataProvider requestHandlerProvider + */ + public function testSubmitNonArrayValueWhenMultiple(RequestHandlerInterface $requestHandler) + { + $form = $this->factory + ->createBuilder(static::TESTED_TYPE, null, array( + 'multiple' => true, + )) + ->setRequestHandler($requestHandler) + ->getForm(); + $form->submit(null); + + $this->assertSame(array(), $form->getData()); + $this->assertSame(array(), $form->getNormData()); + $this->assertSame(array(), $form->getViewData()); + } + public function requestHandlerProvider() { return array( diff --git a/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php b/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php index 59ba309005b38..0ed6600974371 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php +++ b/src/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php @@ -106,7 +106,7 @@ public function get($type, array $default = array()) public function all() { $return = $this->flashes['display']; - $this->flashes = array('new' => array(), 'display' => array()); + $this->flashes['display'] = array(); return $return; } diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Flash/AutoExpireFlashBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Flash/AutoExpireFlashBagTest.php index 18b71a5021fbb..0e0724a3249a4 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Flash/AutoExpireFlashBagTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Flash/AutoExpireFlashBagTest.php @@ -150,4 +150,12 @@ public function testClear() { $this->assertEquals(array('notice' => array('A previous flash message')), $this->bag->clear()); } + + public function testDoNotRemoveTheNewFlashesWhenDisplayingTheExistingOnes() + { + $this->bag->add('success', 'Something'); + $this->bag->all(); + + $this->assertEquals(array('new' => array('success' => array('Something')), 'display' => array()), $this->array); + } } diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index b1ba60fd65ed1..47c3fd69c73f1 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -58,11 +58,11 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.7.38'; - const VERSION_ID = 20738; + const VERSION = '2.7.39'; + const VERSION_ID = 20739; const MAJOR_VERSION = 2; const MINOR_VERSION = 7; - const RELEASE_VERSION = 38; + const RELEASE_VERSION = 39; const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '05/2018'; diff --git a/src/Symfony/Component/Intl/Data/Bundle/Writer/TextBundleWriter.php b/src/Symfony/Component/Intl/Data/Bundle/Writer/TextBundleWriter.php index 3a444fd350edb..20fad5347aed2 100644 --- a/src/Symfony/Component/Intl/Data/Bundle/Writer/TextBundleWriter.php +++ b/src/Symfony/Component/Intl/Data/Bundle/Writer/TextBundleWriter.php @@ -195,11 +195,11 @@ private function writeArray($file, array $value, $indentation) /** * Writes a "table" node. * - * @param resource $file The file handle to write to - * @param array|\Traversable $value The value of the node - * @param int $indentation The number of levels to indent - * @param bool $fallback Whether the table should be merged - * with the fallback locale + * @param resource $file The file handle to write to + * @param iterable $value The value of the node + * @param int $indentation The number of levels to indent + * @param bool $fallback Whether the table should be merged + * with the fallback locale * * @throws UnexpectedTypeException when $value is not an array and not a * \Traversable instance diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 4ce814a538479..233a6fe2f3fe7 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -611,11 +611,11 @@ private function writeProperty($zval, $property, $value) /** * Adjusts a collection-valued property by calling add*() and remove*() methods. * - * @param array $zval The array containing the object to write to - * @param string $property The property to write - * @param array|\Traversable $collection The collection to write - * @param string $addMethod The add*() method - * @param string $removeMethod The remove*() method + * @param array $zval The array containing the object to write to + * @param string $property The property to write + * @param iterable $collection The collection to write + * @param string $addMethod The add*() method + * @param string $removeMethod The remove*() method */ private function writeCollection($zval, $property, $collection, $addMethod, $removeMethod) { diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/validresource.php b/src/Symfony/Component/Routing/Tests/Fixtures/validresource.php index f59a234d6589a..482c80b29e919 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/validresource.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/validresource.php @@ -1,8 +1,5 @@ import('validpattern.php'); diff --git a/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php b/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php index 360ec5a8d9e8d..96761f51f2c2a 100644 --- a/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php +++ b/src/Symfony/Component/Validator/Constraints/ExpressionValidator.php @@ -78,11 +78,11 @@ public function validate($value, Constraint $constraint) if (!$this->getExpressionLanguage()->evaluate($constraint->expression, $variables)) { if ($this->context instanceof ExecutionContextInterface) { $this->context->buildViolation($constraint->message) - ->setParameter('{{ value }}', $this->formatValue($value)) + ->setParameter('{{ value }}', $this->formatValue($value, self::OBJECT_TO_STRING)) ->addViolation(); } else { $this->buildViolation($constraint->message) - ->setParameter('{{ value }}', $this->formatValue($value)) + ->setParameter('{{ value }}', $this->formatValue($value, self::OBJECT_TO_STRING)) ->addViolation(); } } diff --git a/src/Symfony/Component/Validator/Constraints/UrlValidator.php b/src/Symfony/Component/Validator/Constraints/UrlValidator.php index 56857de63c49a..4498bd167ca79 100644 --- a/src/Symfony/Component/Validator/Constraints/UrlValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UrlValidator.php @@ -25,7 +25,7 @@ class UrlValidator extends ConstraintValidator (%s):// # protocol (([\.\pL\pN-]+:)?([\.\pL\pN-]+)@)? # basic auth ( - ([\pL\pN\pS-\.])+(\.?([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?) # a domain name + ([\pL\pN\pS\-\.])+(\.?([\pL\pN]|xn\-\-[\pL\pN-]+)+\.?) # a domain name | # or \d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3} # an IP address | # or diff --git a/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php index 3b6de4d412582..be15967dcbd88 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/ExpressionValidatorTest.php @@ -15,6 +15,7 @@ use Symfony\Component\Validator\Constraints\Expression; use Symfony\Component\Validator\Constraints\ExpressionValidator; use Symfony\Component\Validator\Tests\Fixtures\Entity; +use Symfony\Component\Validator\Tests\Fixtures\ToString; use Symfony\Component\Validator\Validation; class ExpressionValidatorTest extends AbstractConstraintValidatorTest @@ -90,6 +91,39 @@ public function testFailingExpressionAtObjectLevel() ->assertRaised(); } + public function testSucceedingExpressionAtObjectLevelWithToString() + { + $constraint = new Expression('this.data == 1'); + + $object = new ToString(); + $object->data = '1'; + + $this->setObject($object); + + $this->validator->validate($object, $constraint); + + $this->assertNoViolation(); + } + + public function testFailingExpressionAtObjectLevelWithToString() + { + $constraint = new Expression(array( + 'expression' => 'this.data == 1', + 'message' => 'myMessage', + )); + + $object = new ToString(); + $object->data = '2'; + + $this->setObject($object); + + $this->validator->validate($object, $constraint); + + $this->buildViolation('myMessage') + ->setParameter('{{ value }}', 'toString') + ->assertRaised(); + } + public function testSucceedingExpressionAtPropertyLevel() { $constraint = new Expression('value == this.data'); diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/ToString.php b/src/Symfony/Component/Validator/Tests/Fixtures/ToString.php new file mode 100644 index 0000000000000..714fdb9e98f5f --- /dev/null +++ b/src/Symfony/Component/Validator/Tests/Fixtures/ToString.php @@ -0,0 +1,22 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Validator\Tests\Fixtures; + +class ToString +{ + public $data; + + public function __toString() + { + return 'toString'; + } +} diff --git a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php index acb43283967ca..00c1c4d6e480a 100644 --- a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php +++ b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php @@ -378,7 +378,7 @@ private function validateObject($object, $propertyPath, array $groups, $traversa * objects are iterated as well. Nested arrays are always iterated, * regardless of the value of $recursive. * - * @param array|\Traversable $collection The collection + * @param iterable $collection The collection * @param string $propertyPath The current property path * @param string[] $groups The validated groups * @param bool $stopRecursion Whether to disable diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php index 9ff9b89c1c123..31a0514fd4972 100644 --- a/src/Symfony/Component/Yaml/Inline.php +++ b/src/Symfony/Component/Yaml/Inline.php @@ -365,6 +365,7 @@ private static function parseMapping($mapping, &$i = 0, $references = array()) $output = array(); $len = strlen($mapping); ++$i; + $allowOverwrite = false; // {foo: bar, bar:foo, ...} while ($i < $len) { @@ -384,6 +385,10 @@ private static function parseMapping($mapping, &$i = 0, $references = array()) // key $key = self::parseScalar($mapping, array(':', ' '), array('"', "'"), $i, false); + if ('<<' === $key) { + $allowOverwrite = true; + } + // value $done = false; @@ -395,7 +400,12 @@ private static function parseMapping($mapping, &$i = 0, $references = array()) // Spec: Keys MUST be unique; first one wins. // Parser cannot abort this mapping earlier, since lines // are processed sequentially. - if (!isset($output[$key])) { + // But overwriting is allowed when a merge node is used in current block. + if ('<<' === $key) { + foreach ($value as $parsedValue) { + $output += $parsedValue; + } + } elseif ($allowOverwrite || !isset($output[$key])) { $output[$key] = $value; } $done = true; @@ -406,7 +416,10 @@ private static function parseMapping($mapping, &$i = 0, $references = array()) // Spec: Keys MUST be unique; first one wins. // Parser cannot abort this mapping earlier, since lines // are processed sequentially. - if (!isset($output[$key])) { + // But overwriting is allowed when a merge node is used in current block. + if ('<<' === $key) { + $output += $value; + } elseif ($allowOverwrite || !isset($output[$key])) { $output[$key] = $value; } $done = true; @@ -419,7 +432,10 @@ private static function parseMapping($mapping, &$i = 0, $references = array()) // Spec: Keys MUST be unique; first one wins. // Parser cannot abort this mapping earlier, since lines // are processed sequentially. - if (!isset($output[$key])) { + // But overwriting is allowed when a merge node is used in current block. + if ('<<' === $key) { + $output += $value; + } elseif ($allowOverwrite || !isset($output[$key])) { $output[$key] = $value; } $done = true; diff --git a/src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml b/src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml index 59f612514170a..499446c10cb76 100644 --- a/src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml +++ b/src/Symfony/Component/Yaml/Tests/Fixtures/sfMergeKey.yml @@ -22,6 +22,7 @@ yaml: | foo: bar foo: ignore bar: foo + bar_inline: {a: before, d: other, <<: *foo, b: new, x: Oren, c: { foo: bar, foo: ignore, bar: foo}} duplicate: foo: bar foo: ignore @@ -46,15 +47,20 @@ yaml: | p: 12345 z: <<: *nestedref + head_inline: &head_inline { <<: [ *foo , *dong , *foo2 ] } + recursive_inline: { <<: *head_inline, c: { <<: *foo2 } } php: | array( 'foo' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull'), 'bar' => array('a' => 'before', 'd' => 'other', 'e' => null, 'b' => 'new', 'c' => array('foo' => 'bar', 'bar' => 'foo'), 'x' => 'Oren'), + 'bar_inline' => array('a' => 'before', 'd' => 'other', 'b' => 'new', 'c' => array('foo' => 'bar', 'bar' => 'foo'), 'e' => 'notnull', 'x' => 'Oren'), 'duplicate' => array('foo' => 'bar'), 'foo2' => array('a' => 'Ballmer'), 'ding' => array('fi', 'fei', 'fo', 'fam'), 'check' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam', 'isit' => 'tested'), 'head' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'), 'taz' => array('a' => 'Steve', 'w' => array('p' => 1234)), - 'nested' => array('a' => 'Steve', 'w' => array('p' => 12345), 'd' => 'Doug', 'z' => array('p' => 12345)) + 'nested' => array('a' => 'Steve', 'w' => array('p' => 12345), 'd' => 'Doug', 'z' => array('p' => 12345)), + 'head_inline' => array('a' => 'Steve', 'b' => 'Clark', 'c' => 'Brian', 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'), + 'recursive_inline' => array('a' => 'Steve', 'b' => 'Clark', 'c' => array('a' => 'Ballmer'), 'e' => 'notnull', 'fi', 'fei', 'fo', 'fam'), ) diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index 9be278f67ec92..97ce0cac0f770 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -1207,6 +1207,18 @@ public function testParseReferencesOnMergeKeys() $this->assertSame($expected, $this->parser->parse($yaml)); } + + /** + * @expectedException \Symfony\Component\Yaml\Exception\ParseException + * @expectedExceptionMessage Reference "foo" does not exist + */ + public function testEvalRefException() + { + $yaml = <<parser->parse($yaml); + } } class B