diff --git a/.github/travis.php b/.github/travis.php index 1d036d4f4295c..695c69604fe67 100644 --- a/.github/travis.php +++ b/.github/travis.php @@ -46,8 +46,8 @@ $versions = file_get_contents('https://packagist.org/packages/'.$package->name.'.json'); $versions = json_decode($versions); - foreach ($versions->package->versions as $version => $package) { - $packages[$package->name] += array($version => $package); + foreach ($versions->package->versions as $v => $package) { + $packages[$package->name] += array($v => $package); } } diff --git a/.travis.yml b/.travis.yml index 76e38fcb1beb7..500da3ee9387d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,8 +26,9 @@ matrix: - php: 5.4 - php: 5.5 - php: 5.6 - env: deps=high - php: 7.0 + env: deps=high + - php: 7.1 env: deps=low fast_finish: true @@ -50,13 +51,12 @@ before_install: - if [[ ! $skip ]]; then echo session.gc_probability = 0 >> $INI_FILE; fi - if [[ ! $skip && $PHP = 5.* ]]; then echo extension = mongo.so >> $INI_FILE; fi - if [[ ! $skip && $PHP = 5.* ]]; then echo extension = memcache.so >> $INI_FILE; fi - - if [[ ! $skip && $PHP = 5.* ]]; then (echo yes | pecl install -f apcu-4.0.10 && echo apc.enable_cli = 1 >> $INI_FILE); fi - - if [[ ! $skip && $PHP = 7.* ]]; then (echo yes | pecl install -f apcu-5.1.2 && echo apc.enable_cli = 1 >> $INI_FILE); fi + - if [[ ! $skip && $PHP = 5.* ]]; then (echo yes | pecl install -f apcu-4.0.11 && echo apc.enable_cli = 1 >> $INI_FILE); fi + - if [[ ! $skip && $PHP = 7.0 ]]; then (echo yes | pecl install -f apcu-5.1.5 && echo apc.enable_cli = 1 >> $INI_FILE); fi - if [[ ! $deps && $PHP = 5.* ]]; then (cd src/Symfony/Component/Debug/Resources/ext && phpize && ./configure && make && echo extension = $(pwd)/modules/symfony_debug.so >> $INI_FILE); fi - if [[ ! $skip && $PHP = 5.* ]]; then pecl install -f memcached-2.1.0; fi - if [[ ! $skip && ! $PHP = hhvm* ]]; then echo extension = ldap.so >> $INI_FILE; fi - - if [[ ! $skip && ! $PHP = hhvm* ]]; then phpenv config-rm xdebug.ini; fi - - if [[ ! $skip ]]; then composer self-update --stable; fi + - if [[ ! $skip && ! $PHP = hhvm* ]]; then phpenv config-rm xdebug.ini || echo "xdebug not available"; fi - if [[ ! $skip ]]; then cp .composer/* ~/.composer/; fi - if [[ ! $skip ]]; then ./phpunit install; fi - if [[ ! $skip ]]; then export PHPUNIT=$(readlink -f ./phpunit); fi diff --git a/CHANGELOG-2.7.md b/CHANGELOG-2.7.md index 235f166764c2d..b4ec507066540 100644 --- a/CHANGELOG-2.7.md +++ b/CHANGELOG-2.7.md @@ -7,6 +7,36 @@ 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.15 (2016-06-30) + + * bug #19217 [HttpKernel] Inline ValidateRequestListener logic into HttpKernel (nicolas-grekas) + * bug #18688 [HttpFoundation] Warning when request has both Forwarded and X-Forwarded-For (magnusnordlander) + * bug #19173 [Console] Decouple SymfonyStyle from TableCell (ro0NL) + * bug #17822 [WIP] [Form] fix `empty_data` option in expanded `ChoiceType` (HeahDude) + * bug #19134 Distinguish between first and subsequent progress bar displays (rquadling) + * bug #19061 [FORM] fix post_max_size_message translation (alt. 2) (David Badura) + * bug #19100 [Console] Fixed SymfonyQuestionHelper multi-choice with defaults (sstok) + * bug #18924 [DoctrineBridge] Don't use object IDs in DoctrineChoiceLoader when passing a value closure (webmozart) + * bug #19138 [DomCrawler] No more exception on field name with strange format (guiled, fabpot) + * bug #18935 [Form] Consider a violation even if the form is not submitted (egeloen) + * bug #19127 [Form] Add exception to FormRenderer about non-unique block names (enumag) + * bug #19118 [Process] Fix pipes cleaning on Windows (nicolas-grekas) + * bug #19128 Avoid phpunit 5.4 warnings on getMock (2.7+) (iltar) + * bug #19114 [HttpKernel] Dont close the reponse stream in debug (nicolas-grekas) + * bug #19101 [Session] fix PDO transaction aborted under PostgreSQL (Tobion) + * bug #18501 [HttpFoundation] changed MERGE queries (hjkl) + * bug #19062 [HttpFoundation] Fix UPSERT for PgSql >= 9.5 (nicolas-grekas) + * bug #18548 [Form] minor fixes in DateTime transformers (HeahDude) + * bug #18732 [PropertyAccess][DX] Enhance exception that say that some methods are missing if they don't (nykopol) + * bug #19048 [HttpFoundation] Use UPSERT for sessions stored in PgSql >= 9.5 (nicolas-grekas) + * bug #19038 Fix feature detection for IE (Alsciende) + * bug #18915 [DependencyInjection] force enabling the external XML entity loaders (xabbuh) + * bug #19020 [Form] Fixed collapsed choice attributes (HeahDude) + * bug #19028 [Yaml] properly count skipped comment lines (xabbuh) + * bug #17733 [Yaml] Fix wrong line number when comments are inserted in the middle of a block. (paradajozsef) + * bug #18911 Fixed singular of committee (peterrehm) + * bug #18971 Do not inject web debug toolbar on attachments (peterrehm) + * 2.7.14 (2016-06-06) * bug #18908 [DependencyInjection] force enabling the external XML entity loaders (xabbuh) diff --git a/CHANGELOG-2.8.md b/CHANGELOG-2.8.md index 27060f7527791..f3c89cff979bb 100644 --- a/CHANGELOG-2.8.md +++ b/CHANGELOG-2.8.md @@ -7,6 +7,37 @@ 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.9 (2016-07-30) + + * bug #19470 undefined offset fix (#19406) (ReenExe) + * bug #19300 [HttpKernel] Use flock() for HttpCache's lock files (mpdude) + * bug #19428 [Process] Fix write access check for pipes on Windows (nicolas-grekas) + * bug #19439 [DependencyInjection] Fixed deprecated default message template with XML (jeremyFreeAgent) + * bug #19397 [HttpFoundation] HttpCache refresh stale responses containing an ETag (maennchen) + * bug #19426 [Form] Fix the money form type render with Bootstrap3 (Th3Mouk) + * bug #19422 [DomCrawler] Inherit the namespace cache in subcrawlers (stof) + * bug #19425 [BrowserKit] Uppercase the "GET" method in redirects (jakzal) + * bug #19384 Fix PHP 7.1 related failures (nicolas-grekas) + * bug #19379 [VarDumper] Fix for PHP 7.1 (nicolas-grekas) + * bug #19342 Added class existence check if is_subclass_of() fails in compiler passes (SCIF) + * bug #19369 Fix the DBAL session handler version check for Postgresql (stof) + * bug #19368 [VarDumper] Fix dumping jsons casted as arrays (nicolas-grekas) + * bug #19334 [Security] Fix the retrieval of the last username when using forwarding (stof) + * bug #19321 [HttpFoundation] Add OPTIONS and TRACE to the list of safe methods (dunglas) + * bug #19317 [BrowserKit] Update Client::getAbsoluteUri() for query string only URIs (georaldc) + * bug #19298 [ClassLoader] Fix declared classes being computed when not needed (nicolas-grekas) + * bug #19316 [Validator] Added additional MasterCard range to the CardSchemeValidator (Dennis Væversted) + * bug #19290 [HttpKernel] fixed internal subrequests having an if-modified-since-header (MalteWunsch) + * bug #19307 [Security] Fix deprecated usage of DigestAuthenticationEntryPoint::getKey() in DigestAuthenticationListener (Maxime STEINHAUSSER) + * bug #19309 [DoctrineBridge] added missing error code for constraint. (Koc) + * bug #19306 [Form] fixed bug - name in ButtonBuilder (cheprasov) + * bug #19292 [varDumper] Fix missing usage of ExceptionCaster::$traceArgs (nicolas-grekas) + * bug #19288 [VarDumper] Fix indentation trimming in ExceptionCaster (nicolas-grekas) + * bug #19267 [Validator] UuidValidator must accept a Uuid constraint. (hhamon) + * bug #19186 Fix for #19183 to add support for new PHP MongoDB extension in sessions. (omanizer) + * bug #19253 [Console] Fix block() padding formatting after #19189 (chalasr) + * bug #19218 [Security][Guard] check if session exist before using it (pasdeloup) + * 2.8.8 (2016-06-30) * bug #19217 [HttpKernel] Inline ValidateRequestListener logic into HttpKernel (nicolas-grekas) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 5fc732e26ff90..6f73ccb150471 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -8,8 +8,8 @@ Symfony is the result of the work of many people who made the code better - Nicolas Grekas (nicolas-grekas) - Bernhard Schussek (bschussek) - Tobias Schultze (tobion) - - Christophe Coevoet (stof) - Christian Flothmann (xabbuh) + - Christophe Coevoet (stof) - Jordi Boggiano (seldaek) - Victor Berchet (victor) - Johannes S (johannes) @@ -17,12 +17,12 @@ Symfony is the result of the work of many people who made the code better - Jakub Zalas (jakubzalas) - Ryan Weaver (weaverryan) - Javier Eguiluz (javier.eguiluz) - - Hugo Hamon (hhamon) - Kévin Dunglas (dunglas) + - Hugo Hamon (hhamon) - Abdellatif Ait boudad (aitboudad) - Pascal Borreli (pborreli) - - Joseph Bielawski (stloyd) - Wouter De Jong (wouterj) + - Joseph Bielawski (stloyd) - Romain Neutron (romain) - Karma Dordrak (drak) - Lukas Kahwe Smith (lsmith) @@ -34,16 +34,16 @@ Symfony is the result of the work of many people who made the code better - Grégoire Pineau (lyrixx) - Eriksen Costa (eriksencosta) - Sarah Khalil (saro0h) + - Jules Pietri (heah) - Jonathan Wage (jwage) - - Diego Saint Esteben (dosten) - Maxime Steinhausser (ogizanagi) + - Diego Saint Esteben (dosten) - Alexandre Salomé (alexandresalome) - William Durand (couac) - - Jules Pietri (heah) - ornicar + - Francis Besset (francisbesset) - stealth35 ‏ (stealth35) - Alexander Mols (asm89) - - Francis Besset (francisbesset) - Bulat Shakirzyanov (avalanche123) - Saša Stamenković (umpirsky) - Henrik Bjørnskov (henrikbjorn) @@ -52,21 +52,21 @@ Symfony is the result of the work of many people who made the code better - Konstantin Kudryashov (everzet) - Bilal Amarni (bamarni) - Florin Patan (florinpatan) - - Kevin Bond (kbond) - Peter Rehm (rpet) + - Kevin Bond (kbond) - Gábor Egyed (1ed) + - Ener-Getick (energetick) - Michel Weimerskirch (mweimerskirch) - Eric Clemmons (ericclemmons) + - Iltar van der Berg (kjarli) - Andrej Hudec (pulzarraider) - Christian Raue + - Charles Sarrazin (csarrazi) - Matthias Pigulla (mpdude) - Deni - Henrik Westphal (snc) - Dariusz Górecki (canni) - Arnout Boks (aboks) - - Iltar van der Berg (kjarli) - - Charles Sarrazin (csarrazi) - - Ener-Getick (energetick) - Douglas Greenshields (shieldo) - Lee McDermott - Brandon Turner @@ -82,49 +82,50 @@ Symfony is the result of the work of many people who made the code better - Antoine Hérault (herzult) - Arnaud Le Blanc (arnaud-lb) - Jérôme Tamarelle (gromnan) + - Paráda József (paradajozsef) - Michal Piotrowski (eventhorizon) - Tim Nagel (merk) - - Paráda József (paradajozsef) - Brice BERNARD (brikou) + - Robin Chalas (chalas_r) - Alexander M. Turek (derrabus) - Dariusz Ruminski - marc.weistroff - Issei Murasawa (issei_m) - lenar - Włodzimierz Gajda (gajdaw) + - Konstantin Myakshin (koc) + - Baptiste Clavié (talus) - Alexander Schwenn (xelaris) - Florian Voutzinos (florianv) - - Konstantin Myakshin (koc) - Colin Frei - Adrien Brault (adrienbrault) - Joshua Thijssen - - Baptiste Clavié (talus) - Peter Kokot (maastermedia) - excelwebzone - Jacob Dreesen (jdreesen) + - Jáchym Toušek (enumag) - Jérémy DERUSSÉ (jderusse) - Vladimir Reznichenko (kalessil) + - Tomáš Votruba (tomas_votruba) - Fabien Pennequin (fabienpennequin) - Gordon Franke (gimler) + - Eric GELOEN (gelo) - David Buchmann (dbu) - - Tomáš Votruba (tomas_votruba) - - Jáchym Toušek - Robert Schönthal (digitalkaoz) - Florian Lonqueu-Brochard (florianlb) - - Eric GELOEN (gelo) - Stefano Sala (stefano.sala) - Juti Noppornpitak (shiroyuki) + - Titouan Galopin (tgalopin) - Tigran Azatyan (tigranazatyan) - Sebastian Hörl (blogsh) - Daniel Gomes (danielcsgomes) - Hidenori Goto (hidenorigoto) + - Sebastiaan Stok (sstok) - Evgeniy (ewgraf) + - Tugdual Saunier (tucksaun) - Guilherme Blanco (guilhermeblanco) - Pablo Godel (pgodel) - - Titouan Galopin (tgalopin) - Jérémie Augustin (jaugustin) - - Sebastiaan Stok (sstok) - - Tugdual Saunier (tucksaun) - Andréia Bohner (andreia) - Rafael Dohms (rdohms) - Arnaud Kleinpeter (nanocom) @@ -141,6 +142,7 @@ Symfony is the result of the work of many people who made the code better - Richard van Laak (rvanlaak) - Matthieu Ouellette-Vachon (maoueh) - Michał Pipa (michal.pipa) + - Javier Spagnoletti (phansys) - Amal Raghav (kertz) - Jonathan Ingram (jonathaningram) - Artur Kotyrba @@ -150,7 +152,6 @@ Symfony is the result of the work of many people who made the code better - Daniel Wehner - Possum - Dorian Villet (gnutix) - - Javier Spagnoletti (phansys) - Richard Miller (mr_r_miller) - Mario A. Alvarez Garcia (nomack84) - Dennis Benkert (denderello) @@ -179,6 +180,7 @@ Symfony is the result of the work of many people who made the code better - Sven Paulus (subsven) - Lars Strojny (lstrojny) - Rui Marinho (ruimarinho) + - Daniel Espendiller - Eugene Wissner - Julien Brochet (mewt) - Sergey Linnik (linniksa) @@ -212,9 +214,7 @@ Symfony is the result of the work of many people who made the code better - Kristen Gilden (kgilden) - Dawid Nowak - Pierre-Yves LEBECQ (pylebecq) - - Daniel Espendiller - Jakub Kucharovic (jkucharovic) - - Robin Chalas (chalas_r) - Eugene Leonovich (rybakit) - Filippo Tessarotto - Joseph Rouff (rouffj) @@ -238,6 +238,7 @@ Symfony is the result of the work of many people who made the code better - Roumen Damianoff (roumen) - Antonio J. García Lagar (ajgarlag) - Kim Hemsø Rasmussen (kimhemsoe) + - Christian Schmidt - Wouter Van Hecke - Peter Kruithof (pkruithof) - Michael Holm (hollo) @@ -245,6 +246,7 @@ Symfony is the result of the work of many people who made the code better - Hidde Wieringa (hiddewie) - Chris Smith (cs278) - Florian Klein (docteurklein) + - Oleg Voronkovich - Manuel Kiessling (manuelkiessling) - Daniel Wehner - Atsuhiro KUBO (iteman) @@ -294,7 +296,6 @@ Symfony is the result of the work of many people who made the code better - Inal DJAFAR (inalgnu) - Christian Gärtner (dagardner) - Tomasz Kowalczyk (thunderer) - - Christian Schmidt - François-Xavier de Guillebon (de-gui_f) - Damien Alexandre (damienalexandre) - Felix Labrecque @@ -322,6 +323,7 @@ Symfony is the result of the work of many people who made the code better - Endre Fejes - Tobias Naumann (tna) - Daniel Beyer + - Jhonny Lidfors (jhonne) - Shein Alexey - Baptiste Lafontaine - Joe Lencioni @@ -335,7 +337,6 @@ Symfony is the result of the work of many people who made the code better - Ivan Kurnosov - Xavier HAUSHERR - Albert Jessurum (ajessu) - - Oleg Voronkovich - Laszlo Korte - Pavel Batanov (scaytrase) - Miha Vrhovnik @@ -355,6 +356,7 @@ Symfony is the result of the work of many people who made the code better - Brian King - Michel Salib (michelsalib) - geoffrey + - Steffen Roßkamp - Valentin Jonovs (valentins-jonovs) - Jeanmonod David (jeanmonod) - Jan Schumann @@ -364,6 +366,7 @@ Symfony is the result of the work of many people who made the code better - Mihai Stancu - Olivier Dolbeau (odolbeau) - Jan Rosier (rosier) + - Magnus Nordlander (magnusnordlander) - vagrant - EdgarPE - Florian Pfitzer (marmelatze) @@ -379,6 +382,7 @@ Symfony is the result of the work of many people who made the code better - Christian Schmidt - Marek Štípek (maryo) - Marcin Sikoń (marphi) + - Roland Franssen (ro0) - Dominik Zogg (dominik.zogg) - Marek Pietrzak - Chad Sikorra (chadsikorra) @@ -390,6 +394,7 @@ Symfony is the result of the work of many people who made the code better - Zander Baldwin - Adam Harvey - Alex Bakhturin + - Alexander Obuhovich (aik099) - boombatower - Fabrice Bernhard (fabriceb) - Jérôme Macias (jeromemacias) @@ -412,10 +417,12 @@ Symfony is the result of the work of many people who made the code better - ondrowan - Barry vd. Heuvel (barryvdh) - Jerzy Zawadzki (jzawadzki) + - Théo FIDRY (theofidry) - Evan S Kaufman (evanskaufman) - mcben - Jérôme Vieilledent (lolautruche) - Maks Slesarenko + - Filip Procházka (fprochazka) - mmoreram - Markus Lanthaler (lanthaler) - Vicent Soria Durá (vicentgodella) @@ -440,7 +447,6 @@ Symfony is the result of the work of many people who made the code better - Benjamin Leveque (benji07) - Nate (frickenate) - jhonnyL - - Jhonny Lidfors (jhonne) - sasezaki - Dawid Pakuła (zulusx) - Florian Rey (nervo) @@ -503,6 +509,7 @@ Symfony is the result of the work of many people who made the code better - Maxime Douailin - Javier López (loalf) - Reinier Kip + - Geoffrey Brier (geoffrey-brier) - Dustin Dobervich (dustin10) - dantleech - Anne-Sophie Bachelard (annesophie) @@ -535,9 +542,11 @@ Symfony is the result of the work of many people who made the code better - Arturs Vonda - Sascha Grossenbacher - Szijarto Tamas + - David Badura (davidbadura) - Catalin Dan - Stephan Vock - Benjamin Zikarsky (bzikarsky) + - Anton Bakai - Simon Schick (simonsimcity) - redstar504 - Tristan Roussel @@ -556,7 +565,7 @@ Symfony is the result of the work of many people who made the code better - Richard van den Brand (ricbra) - develop - Mark Sonnabaum - - Alexander Obuhovich (aik099) + - Richard Quadling - jochenvdv - Arturas Smorgun (asarturas) - Alexander Volochnev (exelenz) @@ -573,6 +582,7 @@ Symfony is the result of the work of many people who made the code better - Baldur Rensch (brensch) - Vladyslav Petrovych - Alex Xandra Albert Sim + - Carson Full - Trent Steel (trsteel88) - Yuen-Chi Lian - Besnik Br @@ -589,6 +599,7 @@ Symfony is the result of the work of many people who made the code better - Leevi Graham (leevigraham) - Casper Valdemar Poulsen - Josiah (josiah) + - Joschi Kuphal - John Bohn (jbohn) - Marc Morera (mmoreram) - Andrew Hilobok (hilobok) @@ -618,7 +629,6 @@ Symfony is the result of the work of many people who made the code better - Adrien Lucas (adrienlucas) - James Michael DuPont - Tom Klingenberg - - Filip Procházka (fprochazka) - Christopher Hall (mythmakr) - Paul Kamer (pkamer) - Rafał Wrzeszcz (rafalwrzeszcz) @@ -637,7 +647,6 @@ Symfony is the result of the work of many people who made the code better - Neil Ferreira - Nathanael Noblet (gnat) - Dmitry Parnas (parnas) - - Théo FIDRY (theofidry) - Paul LE CORRE - DQNEO - Emanuele Iannone @@ -652,7 +661,6 @@ Symfony is the result of the work of many people who made the code better - Matt Robinson (inanimatt) - Aleksey Podskrebyshev - Calin Mihai Pristavu - - Steffen Roßkamp - David Marín Carreño (davefx) - Jörn Lang (j.lang) - Omar Yepez (oyepez003) @@ -677,6 +685,7 @@ Symfony is the result of the work of many people who made the code better - Don Pinkster - Maksim Muruev - Emil Einarsson + - Thomas Landauer - Thibault Duplessis - Marc Abramowitz - Martijn Evers @@ -697,7 +706,6 @@ Symfony is the result of the work of many people who made the code better - David Lima - Jérôme Vasseur - Brunet Laurent (lbrunet) - - Magnus Nordlander (magnusnordlander) - Mikhail Yurasov (mym) - LOUARDI Abdeltif (ouardisoft) - Robert Gruendler (pulse00) @@ -709,6 +717,7 @@ Symfony is the result of the work of many people who made the code better - Raul Fraile (raulfraile) - sensio - Patrick Kaufmann + - Piotr Stankowski - Reece Fowell (reecefowell) - Mátyás Somfai (smatyas) - stefan.r @@ -728,6 +737,7 @@ Symfony is the result of the work of many people who made the code better - Pieter - Michael Tibben - Sander Marechal + - Andre Rømcke (andrerom) - Radosław Benkel - ttomor - Mei Gwilym (meigwilym) @@ -743,6 +753,7 @@ Symfony is the result of the work of many people who made the code better - Danilo Silva - Zachary Tong (polyfractal) - Hryhorii Hrebiniuk + - Dennis Fridrich (dfridrich) - mcfedr (mcfedr) - hamza - dantleech @@ -752,6 +763,7 @@ Symfony is the result of the work of many people who made the code better - Guillaume Royer - Artem (digi) - boite + - MGDSoft - Vadim Tyukov (vatson) - Sortex - chispita @@ -804,10 +816,12 @@ Symfony is the result of the work of many people who made the code better - Benoit Garret - Thomas Royer (cydonia7) - DerManoMann + - Olaf Klischat - Jhonny Lidfors (jhonny) - Julien Bianchi (jubianchi) + - Robert Meijers - Marcin Chwedziak - - Roland Franssen (ro0) + - hjkl - Tony Cosentino (tony-co) - Rodrigo Díez Villamuera (rodrigodiez) - e-ivanov @@ -815,6 +829,7 @@ Symfony is the result of the work of many people who made the code better - Jeremy Bush - wizhippo - Viacheslav Sychov + - Carlos Ortega Huetos - rpg600 - Péter Buri (burci) - Davide Borsatto (davide.borsatto) @@ -834,6 +849,7 @@ Symfony is the result of the work of many people who made the code better - spdionis - Eduardo García Sanz (coma) - James Gilliland + - Rhodri Pugh (rodnaph) - David de Boer (ddeboer) - Gilles Doge (gido) - abulford @@ -855,7 +871,6 @@ Symfony is the result of the work of many people who made the code better - Juan Traverso - Philipp Strube - Christian Sciberras - - Anton Bakai - Clement Herreman (clemherreman) - Dan Ionut Dumitriu (danionut90) - Nyro (nyro) @@ -893,7 +908,6 @@ Symfony is the result of the work of many people who made the code better - azine - Dawid Sajdak - Ludek Stepan - - Geoffrey Brier - Aaron Stephens (astephens) - Craig Menning (cmenning) - Balázs Benyó (duplabe) @@ -917,6 +931,7 @@ Symfony is the result of the work of many people who made the code better - Cédric Lahouste (rapotor) - Samuel Vogel (samuelvogel) - Berat Doğan + - Juanmi Rodriguez Cerón - Anthony Ferrara - Klaas Cuvelier (kcuvelier) - Steve Frécinaux @@ -934,6 +949,7 @@ Symfony is the result of the work of many people who made the code better - Philip Frank - Lance McNearney - Giorgio Premi + - Ian Carroll - caponica - Matt Daum (daum) - Alberto Pirovano (geezmo) @@ -945,6 +961,7 @@ Symfony is the result of the work of many people who made the code better - Max Summe - WedgeSama - Felds Liscia + - Ahmed TAILOULOUTE (ahmedtai) - James Halsall (jaitsu) - Maxime Veber (nek-) - Sullivan SENECHAL @@ -968,6 +985,7 @@ Symfony is the result of the work of many people who made the code better - Max Romanovsky (maxromanovsky) - Mathieu Morlon - Daniel Tschinder + - Nykopol (nykopol) - Rafał Muszyński (rafmus90) - Timothy Anido (xanido) - Rick Prent @@ -1006,6 +1024,7 @@ Symfony is the result of the work of many people who made the code better - Konrad Mohrfeldt - Lance Chen - Andrey Astakhov (aast) + - Nikolay Labinskiy (e-moe) - kor3k kor3k (kor3k) - Stelian Mocanita (stelian) - Flavian (2much) @@ -1015,6 +1034,7 @@ Symfony is the result of the work of many people who made the code better - Hoffmann András - Olivier - pscheit + - Zdeněk Drahoš - Dan Harper - moldcraft - Ramon Kleiss (akathos) @@ -1137,6 +1157,7 @@ Symfony is the result of the work of many people who made the code better - Daan van Renterghem - Nicole Cordes - Bram Van der Sype (brammm) + - Guile (guile) - Julien Moulin (lizjulien) - Nikita Nefedov (nikita2206) - Mauro Foti (skler) @@ -1209,7 +1230,6 @@ Symfony is the result of the work of many people who made the code better - Haritz - Matthieu Prat - Grummfy - - Thomas Landauer - Filipe Guerra - Gerben Wijnja - Rowan Manning @@ -1260,6 +1280,7 @@ Symfony is the result of the work of many people who made the code better - Muriel (metalmumu) - Michael Pohlers (mick_the_big) - Cayetano Soriano Gallego (neoshadybeat) + - Jean Pasdeloup (pasdeloup) - Patrick McDougle (patrick-mcdougle) - Pablo Monterde Perez (plebs) - Jimmy Leger (redpanda) @@ -1298,7 +1319,6 @@ Symfony is the result of the work of many people who made the code better - Mantas Urnieža - Cas - Dusan Kasan - - Carson Full - Myke79 - Brian Debuire - Piers Warmers @@ -1332,6 +1352,7 @@ Symfony is the result of the work of many people who made the code better - Andras Ratz - andreabreu98 - Michael Schneider + - Cédric Bertolini - n-aleha - Şəhriyar İmanov - Kaipi Yann @@ -1358,6 +1379,7 @@ Symfony is the result of the work of many people who made the code better - Jon Cave - Sébastien HOUZE - Abdulkadir N. A. + - Ivan Menshykov - Yevgen Kovalienia - Lebnik - Sema @@ -1385,8 +1407,8 @@ Symfony is the result of the work of many people who made the code better - Oncle Tom - Christian Stocker - Dawid Nowak - - Richard Quadling - Karolis Daužickas + - Sergio Santoro - tirnanog06 - phc - Дмитрий Пацура @@ -1412,7 +1434,6 @@ Symfony is the result of the work of many people who made the code better - Loïc Vernet (coil) - Christoph Schaefer (cvschaefer) - Damon Jones (damon__jones) - - David Badura (davidbadura) - Daniel Londero (dlondero) - Sebastian Landwehr (dword123) - Adel ELHAIBA (eadel) @@ -1420,6 +1441,7 @@ Symfony is the result of the work of many people who made the code better - Elliot Anderson (elliot) - Sergey Zolotov (enleur) - Fabien D. (fabd) + - Carsten Eilers (fnc) - Sorin Gitlan (forapathy) - Yohan Giarelli (frequence-web) - Gerry Vandermaesen (gerryvdm) diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php index 876ab1d5949e0..534d762e73f11 100644 --- a/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php +++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/AbstractDoctrineExtension.php @@ -314,10 +314,10 @@ protected function loadObjectManagerCacheDriver(array $objectManager, ContainerB /** * Loads a cache driver. * - * @param string $cacheDriverServiceId The cache driver name - * @param string $objectManagerName The object manager name - * @param array $cacheDriver The cache driver mapping - * @param \Symfony\Component\DependencyInjection\ContainerBuilder $container The ContainerBuilder instance + * @param string $cacheName The cache driver name + * @param string $objectManagerName The object manager name + * @param array $cacheDriver The cache driver mapping + * @param ContainerBuilder $container The ContainerBuilder instance * * @return string * diff --git a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterMappingsPass.php b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterMappingsPass.php index 5620740a52082..e37e4f66c29aa 100644 --- a/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterMappingsPass.php +++ b/src/Symfony/Bridge/Doctrine/DependencyInjection/CompilerPass/RegisterMappingsPass.php @@ -111,15 +111,13 @@ abstract class RegisterMappingsPass implements CompilerPassInterface * @param string[] $managerParameters List of container parameters that could * hold the manager name. * @param string $driverPattern Pattern for the metadata driver service name - * @param string $enabledParameter Service container parameter that must be + * @param string|false $enabledParameter Service container parameter that must be * present to enable the mapping. Set to false * to not do any check, optional. * @param string $configurationPattern Pattern for the Configuration service name * @param string $registerAliasMethodName Name of Configuration class method to * register alias. * @param string[] $aliasMap Map of alias to namespace - * - * @since Support for bundle alias was added in Symfony 2.6 */ public function __construct($driver, array $namespaces, array $managerParameters, $driverPattern, $enabledParameter = false, $configurationPattern = '', $registerAliasMethodName = '', array $aliasMap = array()) { diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php index 1f2d1e9e1ed73..cd966ea986f79 100644 --- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php +++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php @@ -18,8 +18,6 @@ /** * A utility for reading object IDs. * - * @since 1.0 - * * @author Bernhard Schussek * * @internal This class is meant for internal use only. diff --git a/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandler.php b/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandler.php index 92c7b6bf40afd..d819ff0a6c51e 100644 --- a/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandler.php +++ b/src/Symfony/Bridge/Doctrine/HttpFoundation/DbalSessionHandler.php @@ -13,6 +13,7 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Driver\DriverException; +use Doctrine\DBAL\Driver\ServerInfoAwareConnection; use Doctrine\DBAL\Platforms\SQLServer2008Platform; /** @@ -241,9 +242,33 @@ private function getMergeSql() "WHEN MATCHED THEN UPDATE SET $this->dataCol = :data, $this->timeCol = :time;"; case 'sqlite' === $platform: return "INSERT OR REPLACE INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time)"; - case 'postgresql' === $platform && version_compare($this->con->getServerVersion(), '9.5', '>='): + case 'postgresql' === $platform && version_compare($this->getServerVersion(), '9.5', '>='): return "INSERT INTO $this->table ($this->idCol, $this->dataCol, $this->timeCol) VALUES (:id, :data, :time) ". "ON CONFLICT ($this->idCol) DO UPDATE SET ($this->dataCol, $this->timeCol) = (EXCLUDED.$this->dataCol, EXCLUDED.$this->timeCol)"; } } + + private function getServerVersion() + { + $params = $this->con->getParams(); + + // Explicit platform version requested (supersedes auto-detection), so we respect it. + if (isset($params['serverVersion'])) { + return $params['serverVersion']; + } + + $wrappedConnection = $this->con->getWrappedConnection(); + + if ($wrappedConnection instanceof ServerInfoAwareConnection) { + return $wrappedConnection->getServerVersion(); + } + + // Support DBAL 2.4 by accessing it directly when using PDO PgSQL + if ($wrappedConnection instanceof \PDO) { + return $wrappedConnection->getAttribute(\PDO::ATTR_SERVER_VERSION); + } + + // If we cannot guess the version, the empty string will mean we won't use the code for newer versions when doing version checks. + return ''; + } } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/LegacyUniqueEntityValidatorLegacyApiTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/LegacyUniqueEntityValidatorLegacyApiTest.php index cde865cc1d87a..91c57118d91a7 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/LegacyUniqueEntityValidatorLegacyApiTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/LegacyUniqueEntityValidatorLegacyApiTest.php @@ -14,8 +14,6 @@ use Symfony\Component\Validator\Validation; /** - * @since 2.5.4 - * * @author Bernhard Schussek * @group legacy */ diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php index 33e484320a56a..95b0589fc93e5 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php @@ -167,6 +167,7 @@ public function testValidateUniqueness() $this->buildViolation('myMessage') ->atPath('property.path.name') ->setInvalidValue('Foo') + ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); } @@ -190,6 +191,7 @@ public function testValidateCustomErrorPath() $this->buildViolation('myMessage') ->atPath('property.path.bar') ->setInvalidValue('Foo') + ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); } @@ -241,6 +243,7 @@ public function testValidateUniquenessWithIgnoreNull() $this->buildViolation('myMessage') ->atPath('property.path.name') ->setInvalidValue('Foo') + ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); } @@ -272,6 +275,7 @@ public function testValidateUniquenessWithValidCustomErrorPath() $this->buildViolation('myMessage') ->atPath('property.path.name2') ->setInvalidValue('Bar') + ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); } @@ -404,6 +408,7 @@ public function testAssociatedEntity() $this->buildViolation('myMessage') ->atPath('property.path.single') ->setInvalidValue($entity1) + ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->assertRaised(); } diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php index fc6e213bd772e..315b1654e8f7e 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php +++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntity.php @@ -23,6 +23,8 @@ */ class UniqueEntity extends Constraint { + const NOT_UNIQUE_ERROR = '23bd9dbf-6b9b-41cd-a99e-4844bcf3077f'; + public $message = 'This value is already used.'; public $service = 'doctrine.orm.validator.unique'; public $em = null; @@ -31,6 +33,10 @@ class UniqueEntity extends Constraint public $errorPath = null; public $ignoreNull = true; + protected static $errorNames = array( + self::NOT_UNIQUE_ERROR => 'NOT_UNIQUE_ERROR', + ); + public function getRequiredOptions() { return array('fields'); diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php index f4c8671abae9a..94b40f980abc8 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php +++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php @@ -132,11 +132,13 @@ public function validate($entity, Constraint $constraint) $this->context->buildViolation($constraint->message) ->atPath($errorPath) ->setInvalidValue($invalidValue) + ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->addViolation(); } else { $this->buildViolation($constraint->message) ->atPath($errorPath) ->setInvalidValue($invalidValue) + ->setCode(UniqueEntity::NOT_UNIQUE_ERROR) ->addViolation(); } } diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_structure.txt b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_structure.txt index e2775cfa5f3d3..a0e3642f4949e 100644 --- a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_structure.txt +++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/php/lazy_service_structure.txt @@ -23,5 +23,5 @@ class ProjectServiceContainer extends Container } } -class stdClass_%s extends \stdClass implements \ProxyManager\%s -{%a}%A \ No newline at end of file +class stdClass_%s extends %SstdClass implements \ProxyManager\%s +{%a}%A diff --git a/src/Symfony/Bridge/Twig/Extension/LogoutUrlExtension.php b/src/Symfony/Bridge/Twig/Extension/LogoutUrlExtension.php index 7fc278758eb38..ea105e8d955e4 100644 --- a/src/Symfony/Bridge/Twig/Extension/LogoutUrlExtension.php +++ b/src/Symfony/Bridge/Twig/Extension/LogoutUrlExtension.php @@ -11,7 +11,6 @@ namespace Symfony\Bridge\Twig\Extension; -use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Http\Logout\LogoutUrlGenerator; /** @@ -48,7 +47,7 @@ public function getFunctions() */ public function getLogoutPath($key = null) { - return $this->generator->getLogoutPath($key, UrlGeneratorInterface::ABSOLUTE_PATH); + return $this->generator->getLogoutPath($key); } /** @@ -60,7 +59,7 @@ public function getLogoutPath($key = null) */ public function getLogoutUrl($key = null) { - return $this->generator->getLogoutUrl($key, UrlGeneratorInterface::ABSOLUTE_URL); + return $this->generator->getLogoutUrl($key); } /** 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 ef2035ab43f04..3e9f133d37b46 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 @@ -21,12 +21,12 @@ {% block money_widget -%}
- {% set prepend = '{{' == money_pattern[0:2] %} - {% if not prepend %} + {% set append = money_pattern starts with '{{' %} + {% if not append %} {{ money_pattern|replace({ '{{ widget }}':''}) }} {% endif %} {{- block('form_widget_simple') -}} - {% if prepend %} + {% if append %} {{ money_pattern|replace({ '{{ widget }}':''}) }} {% endif %}
diff --git a/src/Symfony/Bridge/Twig/Tests/Extension/ExpressionExtensionTest.php b/src/Symfony/Bridge/Twig/Tests/Extension/ExpressionExtensionTest.php index 0c7cc1bd4168c..6d457e395b07e 100644 --- a/src/Symfony/Bridge/Twig/Tests/Extension/ExpressionExtensionTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Extension/ExpressionExtensionTest.php @@ -12,7 +12,6 @@ namespace Symfony\Bridge\Twig\Tests\Extension; use Symfony\Bridge\Twig\Extension\ExpressionExtension; -use Symfony\Component\ExpressionLanguage\Expression; class ExpressionExtensionTest extends \PHPUnit_Framework_TestCase { diff --git a/src/Symfony/Bridge/Twig/composer.json b/src/Symfony/Bridge/Twig/composer.json index 2a10d4e35665d..d22e396756451 100644 --- a/src/Symfony/Bridge/Twig/composer.json +++ b/src/Symfony/Bridge/Twig/composer.json @@ -33,7 +33,7 @@ "symfony/security-acl": "~2.6|~3.0.0", "symfony/stopwatch": "~2.2|~3.0.0", "symfony/console": "~2.8|~3.0.0", - "symfony/var-dumper": "~2.6|~3.0.0", + "symfony/var-dumper": "~2.7.16|~2.8.9|~3.0.9", "symfony/expression-language": "~2.4|~3.0.0" }, "suggest": { diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/AbstractConfigCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/AbstractConfigCommand.php index 5560748c0b129..c5b1e5d41cea7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/AbstractConfigCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/AbstractConfigCommand.php @@ -45,7 +45,7 @@ protected function listBundles($output) } else { $output->writeln('Available registered bundles with their extension alias if available:'); $table = new Table($output); - $table->setHeaders($headers)->setRows($rows)->render($output); + $table->setHeaders($headers)->setRows($rows)->render(); } } diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php index cdf49f81f0ba2..59a7855ad87ca 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/FrameworkExtension.php @@ -23,7 +23,6 @@ use Symfony\Component\Finder\Finder; use Symfony\Component\HttpKernel\DependencyInjection\Extension; use Symfony\Component\Config\FileLocator; -use Symfony\Component\Validator\Validation; /** * FrameworkExtension. @@ -836,10 +835,10 @@ private function getValidatorMappingFiles(ContainerBuilder $container) 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->getRealPath(); } foreach (Finder::create()->files()->in($dir)->name('*.yml') as $file) { - $files[1][] = $file->getRealpath(); + $files[1][] = $file->getRealPath(); } $container->addResource(new DirectoryResource($dir)); @@ -964,13 +963,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->getRealPath())); $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->getRealPath())); $definition->setPublic(false); $serializerLoaders[] = $definition; diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php index 81a87d4d2be18..0bb45eb5c2f16 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTest.php @@ -18,7 +18,6 @@ use Symfony\Component\DependencyInjection\Loader\ClosureLoader; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag; use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\Validator\Validation; abstract class FrameworkExtensionTest extends TestCase { diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SessionController.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SessionController.php index bf22e63370139..735178320fa95 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SessionController.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Functional/Bundle/TestBundle/Controller/SessionController.php @@ -42,7 +42,7 @@ public function welcomeAction(Request $request, $name = null) public function logoutAction(Request $request) { - $request->getSession('session')->invalidate(); + $request->getSession()->invalidate(); return new Response('Session cleared.'); } diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/DelegatingEngineTest.php b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/DelegatingEngineTest.php index c5d2d8bbebede..0f887218137d3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/DelegatingEngineTest.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/Templating/DelegatingEngineTest.php @@ -38,7 +38,7 @@ public function testGetExistingEngine() $delegatingEngine = new DelegatingEngine($container, array('engine.first', 'engine.second')); - $this->assertSame($secondEngine, $delegatingEngine->getEngine('template.php', array('foo' => 'bar'))); + $this->assertSame($secondEngine, $delegatingEngine->getEngine('template.php')); } /** @@ -55,7 +55,7 @@ public function testGetInvalidEngine() )); $delegatingEngine = new DelegatingEngine($container, array('engine.first', 'engine.second')); - $delegatingEngine->getEngine('template.php', array('foo' => 'bar')); + $delegatingEngine->getEngine('template.php'); } public function testRenderResponseWithFrameworkEngine() diff --git a/src/Symfony/Bundle/FrameworkBundle/Translation/TranslationLoader.php b/src/Symfony/Bundle/FrameworkBundle/Translation/TranslationLoader.php index 0a00cf2b1958a..b6377863afe48 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Translation/TranslationLoader.php +++ b/src/Symfony/Bundle/FrameworkBundle/Translation/TranslationLoader.php @@ -58,7 +58,7 @@ public function loadMessages($directory, MessageCatalogue $catalogue) $extension = $catalogue->getLocale().'.'.$format; $files = $finder->files()->name('*.'.$extension)->in($directory); foreach ($files as $file) { - $domain = substr($file->getFileName(), 0, -1 * strlen($extension) - 1); + $domain = substr($file->getFilename(), 0, -1 * strlen($extension) - 1); $catalogue->addCatalogue($loader->load($file->getPathname(), $catalogue->getLocale(), $domain)); } } diff --git a/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php b/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php index 5d1a245e508e7..7151175d938e7 100644 --- a/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php +++ b/src/Symfony/Bundle/SecurityBundle/Command/UserPasswordEncoderCommand.php @@ -105,7 +105,7 @@ protected function execute(InputInterface $input, OutputInterface $output) return 1; } - $passwordQuestion = $this->createPasswordQuestion($input, $output); + $passwordQuestion = $this->createPasswordQuestion(); $password = $io->askQuestion($passwordQuestion); } diff --git a/src/Symfony/Bundle/TwigBundle/Tests/Loader/FilesystemLoaderTest.php b/src/Symfony/Bundle/TwigBundle/Tests/Loader/FilesystemLoaderTest.php index 0ee259fb7b23b..269e029a0858b 100644 --- a/src/Symfony/Bundle/TwigBundle/Tests/Loader/FilesystemLoaderTest.php +++ b/src/Symfony/Bundle/TwigBundle/Tests/Loader/FilesystemLoaderTest.php @@ -48,7 +48,7 @@ public function testExists() ; $loader = new FilesystemLoader($locator, $parser); - return $this->assertTrue($loader->exists($template)); + $this->assertTrue($loader->exists($template)); } /** 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 14afbfca9590f..98ea6c3265d2a 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.html.twig @@ -160,7 +160,7 @@ /** * Query an element with a CSS selector. * - * @param string selector a CSS-selector-compatible query string + * @param {string} selector - a CSS-selector-compatible query string * * @return DOMElement|null */ diff --git a/src/Symfony/Component/Asset/Tests/PackagesTest.php b/src/Symfony/Component/Asset/Tests/PackagesTest.php index 81db37b996f2c..0a78a8b4fa6e4 100644 --- a/src/Symfony/Component/Asset/Tests/PackagesTest.php +++ b/src/Symfony/Component/Asset/Tests/PackagesTest.php @@ -14,8 +14,6 @@ use Symfony\Component\Asset\Package; use Symfony\Component\Asset\Packages; use Symfony\Component\Asset\VersionStrategy\StaticVersionStrategy; -use Symfony\Component\Asset\Exception\InvalidArgumentException; -use Symfony\Component\Asset\Exception\LogicException; class PackagesTest extends \PHPUnit_Framework_TestCase { @@ -57,7 +55,7 @@ public function testGetUrl() } /** - * @expectedException LogicException + * @expectedException \Symfony\Component\Asset\Exception\LogicException */ public function testNoDefaultPackage() { @@ -66,7 +64,7 @@ public function testNoDefaultPackage() } /** - * @expectedException InvalidArgumentException + * @expectedException \Symfony\Component\Asset\Exception\InvalidArgumentException */ public function testUndefinedPackage() { diff --git a/src/Symfony/Component/BrowserKit/Client.php b/src/Symfony/Component/BrowserKit/Client.php index 858acba9570c6..278a767bf0216 100644 --- a/src/Symfony/Component/BrowserKit/Client.php +++ b/src/Symfony/Component/BrowserKit/Client.php @@ -475,7 +475,7 @@ public function followRedirect() $request = $this->internalRequest; if (in_array($this->internalResponse->getStatus(), array(302, 303))) { - $method = 'get'; + $method = 'GET'; $files = array(); $content = null; } else { @@ -484,7 +484,7 @@ public function followRedirect() $content = $request->getContent(); } - if ('get' === strtolower($method)) { + if ('GET' === strtoupper($method)) { // Don't forward parameters for GET request as it should reach the redirection URI $parameters = array(); } else { @@ -542,9 +542,9 @@ protected function getAbsoluteUri($uri) return parse_url($currentUri, PHP_URL_SCHEME).':'.$uri; } - // anchor? - if (!$uri || '#' == $uri[0]) { - return preg_replace('/#.*?$/', '', $currentUri).$uri; + // anchor or query string parameters? + if (!$uri || '#' == $uri[0] || '?' == $uri[0]) { + return preg_replace('/[#?].*?$/', '', $currentUri).$uri; } if ('/' !== $uri[0]) { diff --git a/src/Symfony/Component/BrowserKit/Tests/ClientTest.php b/src/Symfony/Component/BrowserKit/Tests/ClientTest.php index 132d4bc51e43d..e57cc4c06a6b2 100644 --- a/src/Symfony/Component/BrowserKit/Tests/ClientTest.php +++ b/src/Symfony/Component/BrowserKit/Tests/ClientTest.php @@ -212,6 +212,15 @@ public function testRequestURIConversion() $client->request('GET', 'http://www.example.com/'); $client->request('GET', 'http'); $this->assertEquals('http://www.example.com/http', $client->getRequest()->getUri(), '->request() uses the previous request for relative URLs'); + + $client = new TestClient(); + $client->request('GET', 'http://www.example.com/foo'); + $client->request('GET', '?'); + $this->assertEquals('http://www.example.com/foo?', $client->getRequest()->getUri(), '->request() uses the previous request for ?'); + $client->request('GET', '?'); + $this->assertEquals('http://www.example.com/foo?', $client->getRequest()->getUri(), '->request() uses the previous request for ?'); + $client->request('GET', '?foo=bar'); + $this->assertEquals('http://www.example.com/foo?foo=bar', $client->getRequest()->getUri(), '->request() uses the previous request for ?'); } public function testRequestReferer() @@ -401,7 +410,7 @@ public function testFollowRedirectWithMaxRedirects() $client->setNextResponse(new Response('', 302, array('Location' => 'http://www.example.com/redirected'))); $client->request('POST', 'http://www.example.com/foo/foobar', array('name' => 'bar')); - $this->assertEquals('get', $client->getRequest()->getMethod(), '->followRedirect() uses a get for 302'); + $this->assertEquals('GET', $client->getRequest()->getMethod(), '->followRedirect() uses a GET for 302'); $this->assertEquals(array(), $client->getRequest()->getParameters(), '->followRedirect() does not submit parameters when changing the method'); } @@ -480,6 +489,26 @@ public function testGetMaxRedirects() $this->assertEquals(3, $client->getMaxRedirects(), '->getMaxRedirects() returns assigned value'); } + public function testFollowRedirectWithPostMethod() + { + $parameters = array('foo' => 'bar'); + $files = array('myfile.foo' => 'baz'); + $server = array('X_TEST_FOO' => 'bazbar'); + $content = 'foobarbaz'; + + $client = new TestClient(); + + $client->setNextResponse(new Response('', 307, array('Location' => 'http://www.example.com/redirected'))); + $client->request('POST', 'http://www.example.com/foo/foobar', $parameters, $files, $server, $content); + + $this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect with POST method'); + $this->assertArrayHasKey('foo', $client->getRequest()->getParameters(), '->followRedirect() keeps parameters with POST method'); + $this->assertArrayHasKey('myfile.foo', $client->getRequest()->getFiles(), '->followRedirect() keeps files with POST method'); + $this->assertArrayHasKey('X_TEST_FOO', $client->getRequest()->getServer(), '->followRedirect() keeps $_SERVER with POST method'); + $this->assertEquals($content, $client->getRequest()->getContent(), '->followRedirect() keeps content with POST method'); + $this->assertEquals('POST', $client->getRequest()->getMethod(), '->followRedirect() keeps request method'); + } + public function testBack() { $client = new TestClient(); diff --git a/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php b/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php index 8046579685ac9..b695b9272f28c 100644 --- a/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php +++ b/src/Symfony/Component/ClassLoader/ClassCollectionLoader.php @@ -43,12 +43,12 @@ public static function load($classes, $cacheDir, $name, $autoReload, $adaptive = self::$loaded[$name] = true; - $declared = array_merge(get_declared_classes(), get_declared_interfaces()); - if (function_exists('get_declared_traits')) { - $declared = array_merge($declared, get_declared_traits()); - } - if ($adaptive) { + $declared = array_merge(get_declared_classes(), get_declared_interfaces()); + if (function_exists('get_declared_traits')) { + $declared = array_merge($declared, get_declared_traits()); + } + // don't include already declared classes $classes = array_diff($classes, $declared); @@ -87,11 +87,17 @@ public static function load($classes, $cacheDir, $name, $autoReload, $adaptive = } } - if (!$reload && is_file($cache)) { + if (!$reload && file_exists($cache)) { require_once $cache; return; } + if (!$adaptive) { + $declared = array_merge(get_declared_classes(), get_declared_interfaces()); + if (function_exists('get_declared_traits')) { + $declared = array_merge($declared, get_declared_traits()); + } + } $files = array(); $content = ''; diff --git a/src/Symfony/Component/Config/Tests/Definition/Builder/ArrayNodeDefinitionTest.php b/src/Symfony/Component/Config/Tests/Definition/Builder/ArrayNodeDefinitionTest.php index e75ed34f469a4..b07f6079ebd90 100644 --- a/src/Symfony/Component/Config/Tests/Definition/Builder/ArrayNodeDefinitionTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/Builder/ArrayNodeDefinitionTest.php @@ -185,6 +185,48 @@ public function testTrueEnableEnabledNode($expected, $config, $message) ); } + public function testCanBeDisabled() + { + $node = new ArrayNodeDefinition('root'); + $node->canBeDisabled(); + + $this->assertTrue($this->getField($node, 'addDefaults')); + $this->assertEquals(array('enabled' => false), $this->getField($node, 'falseEquivalent')); + $this->assertEquals(array('enabled' => true), $this->getField($node, 'trueEquivalent')); + $this->assertEquals(array('enabled' => true), $this->getField($node, 'nullEquivalent')); + + $nodeChildren = $this->getField($node, 'children'); + $this->assertArrayHasKey('enabled', $nodeChildren); + + $enabledNode = $nodeChildren['enabled']; + $this->assertTrue($this->getField($enabledNode, 'default')); + $this->assertTrue($this->getField($enabledNode, 'defaultValue')); + } + + public function testIgnoreExtraKeys() + { + $node = new ArrayNodeDefinition('root'); + + $this->assertFalse($this->getField($node, 'ignoreExtraKeys')); + + $result = $node->ignoreExtraKeys(); + + $this->assertEquals($node, $result); + $this->assertTrue($this->getField($node, 'ignoreExtraKeys')); + } + + public function testNormalizeKeys() + { + $node = new ArrayNodeDefinition('root'); + + $this->assertTrue($this->getField($node, 'normalizeKeys')); + + $result = $node->normalizeKeys(false); + + $this->assertEquals($node, $result); + $this->assertFalse($this->getField($node, 'normalizeKeys')); + } + public function getEnableableNodeFixtures() { return array( diff --git a/src/Symfony/Component/Config/Tests/Definition/Builder/ExprBuilderTest.php b/src/Symfony/Component/Config/Tests/Definition/Builder/ExprBuilderTest.php index 147bf1324c884..ebb766eed63d8 100644 --- a/src/Symfony/Component/Config/Tests/Definition/Builder/ExprBuilderTest.php +++ b/src/Symfony/Component/Config/Tests/Definition/Builder/ExprBuilderTest.php @@ -150,6 +150,26 @@ public function testThenUnsetExpression() $this->assertEquals(array(), $this->finalizeTestBuilder($test)); } + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage You must specify an if part. + */ + public function testEndIfPartNotSpecified() + { + $this->getTestBuilder()->end(); + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage You must specify a then part. + */ + public function testEndThenPartNotSpecified() + { + $builder = $this->getTestBuilder(); + $builder->ifPart = 'test'; + $builder->end(); + } + /** * Create a test treebuilder with a variable node, and init the validation. * diff --git a/src/Symfony/Component/Config/Util/XmlUtils.php b/src/Symfony/Component/Config/Util/XmlUtils.php index d8d4eaa3b17a1..25d9b0a0abe5d 100644 --- a/src/Symfony/Component/Config/Util/XmlUtils.php +++ b/src/Symfony/Component/Config/Util/XmlUtils.php @@ -123,7 +123,7 @@ public static function loadFile($file, $schemaOrCallable = null) * * @return array A PHP array */ - public static function convertDomElementToArray(\DomElement $element, $checkPrefix = true) + public static function convertDomElementToArray(\DOMElement $element, $checkPrefix = true) { $prefix = (string) $element->prefix; $empty = true; diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index db6e814c6b4cb..5c91a9c7d6bce 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -216,7 +216,7 @@ public function getHelperSet() } /** - * Set an input definition set to be used with this application. + * Set an input definition to be used with this application. * * @param InputDefinition $definition The input definition */ @@ -338,6 +338,8 @@ public function register($name) /** * Adds an array of command objects. * + * If a Command is not enabled it will not be added. + * * @param Command[] $commands An array of commands */ public function addCommands(array $commands) @@ -351,10 +353,11 @@ public function addCommands(array $commands) * Adds a command object. * * If a command with the same name already exists, it will be overridden. + * If the command is not enabled it will not be added. * * @param Command $command A Command object * - * @return Command The registered command + * @return Command|null The registered command if enabled or null */ public function add(Command $command) { @@ -423,9 +426,9 @@ public function has($name) /** * Returns an array of all unique namespaces used by currently registered commands. * - * It does not returns the global namespace which always exists. + * It does not return the global namespace which always exists. * - * @return array An array of namespaces + * @return string[] An array of namespaces */ public function getNamespaces() { @@ -965,7 +968,7 @@ private function getSttyColumns() /** * Runs and parses mode CON if it's available, suppressing any error output. * - * @return string x or null if it could not be parsed + * @return string|null x or null if it could not be parsed */ private function getConsoleMode() { @@ -1024,7 +1027,7 @@ public function extractNamespace($name, $limit = null) * @param string $name The string * @param array|\Traversable $collection The collection * - * @return array A sorted array of similar string + * @return string[] A sorted array of similar string */ private function findAlternatives($name, $collection) { @@ -1123,7 +1126,7 @@ private function splitStringByWidth($string, $width) * * @param string $name The full name of the command * - * @return array The namespaces of the command + * @return string[] The namespaces of the command */ private function extractAllNamespaces($name) { diff --git a/src/Symfony/Component/Console/Helper/SymfonyQuestionHelper.php b/src/Symfony/Component/Console/Helper/SymfonyQuestionHelper.php index b17482556ee44..aeddb760e077d 100644 --- a/src/Symfony/Component/Console/Helper/SymfonyQuestionHelper.php +++ b/src/Symfony/Component/Console/Helper/SymfonyQuestionHelper.php @@ -67,7 +67,7 @@ protected function writePrompt(OutputInterface $output, Question $question) break; - case $question instanceof ChoiceQuestion && $question->isMultiSelect(): + case $question instanceof ChoiceQuestion && $question->isMultiselect(): $choices = $question->getChoices(); $default = explode(',', $default); diff --git a/src/Symfony/Component/Console/Helper/Table.php b/src/Symfony/Component/Console/Helper/Table.php index 13e4c3cf6b519..04aa98d5b41f3 100644 --- a/src/Symfony/Component/Console/Helper/Table.php +++ b/src/Symfony/Component/Console/Helper/Table.php @@ -108,11 +108,11 @@ public static function getStyleDefinition($name) self::$styles = self::initStyles(); } - if (!self::$styles[$name]) { - throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); + if (isset(self::$styles[$name])) { + return self::$styles[$name]; } - return self::$styles[$name]; + throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); } /** @@ -124,13 +124,7 @@ public static function getStyleDefinition($name) */ public function setStyle($name) { - if ($name instanceof TableStyle) { - $this->style = $name; - } elseif (isset(self::$styles[$name])) { - $this->style = self::$styles[$name]; - } else { - throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); - } + $this->style = $this->resolveStyle($name); return $this; } @@ -157,13 +151,7 @@ public function setColumnStyle($columnIndex, $name) { $columnIndex = intval($columnIndex); - if ($name instanceof TableStyle) { - $this->columnStyles[$columnIndex] = $name; - } elseif (isset(self::$styles[$name])) { - $this->columnStyles[$columnIndex] = self::$styles[$name]; - } else { - throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); - } + $this->columnStyles[$columnIndex] = $this->resolveStyle($name); return $this; } @@ -448,7 +436,7 @@ private function fillNextRows($rows, $line) } // create a two dimensional array (rowspan x colspan) - $unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, ''), $unmergedRows); + $unmergedRows = array_replace_recursive(array_fill($line + 1, $nbLines, array()), $unmergedRows); foreach ($unmergedRows as $unmergedRowKey => $unmergedRow) { $value = isset($lines[$unmergedRowKey - $line]) ? $lines[$unmergedRowKey - $line] : ''; $unmergedRows[$unmergedRowKey][$column] = new TableCell($value, array('colspan' => $cell->getColspan())); @@ -660,4 +648,17 @@ private static function initStyles() 'symfony-style-guide' => $styleGuide, ); } + + private function resolveStyle($name) + { + if ($name instanceof TableStyle) { + return $name; + } + + if (isset(self::$styles[$name])) { + return self::$styles[$name]; + } + + throw new InvalidArgumentException(sprintf('Style "%s" is not defined.', $name)); + } } diff --git a/src/Symfony/Component/Console/Input/ArgvInput.php b/src/Symfony/Component/Console/Input/ArgvInput.php index 0bd6db29e73bb..fbb01c35645be 100644 --- a/src/Symfony/Component/Console/Input/ArgvInput.php +++ b/src/Symfony/Component/Console/Input/ArgvInput.php @@ -176,7 +176,12 @@ private function parseArgument($token) // unexpected argument } else { - throw new RuntimeException('Too many arguments.'); + $all = $this->definition->getArguments(); + if (count($all)) { + throw new RuntimeException(sprintf('Too many arguments, expected arguments "%s".', implode('" "', array_keys($all)))); + } + + throw new RuntimeException(sprintf('No arguments expected, got "%s".', $token)); } } diff --git a/src/Symfony/Component/Console/Style/SymfonyStyle.php b/src/Symfony/Component/Console/Style/SymfonyStyle.php index 59c5bbf87ed9c..a9c57443427b3 100644 --- a/src/Symfony/Component/Console/Style/SymfonyStyle.php +++ b/src/Symfony/Component/Console/Style/SymfonyStyle.php @@ -410,9 +410,16 @@ private function createBlock($messages, $type = null, $style = null, $prefix = ' } } + $firstLineIndex = 0; + if ($padding && $this->isDecorated()) { + $firstLineIndex = 1; + array_unshift($lines, ''); + $lines[] = ''; + } + foreach ($lines as $i => &$line) { if (null !== $type) { - $line = 0 === $i ? $type.$line : $lineIndentation.$line; + $line = $firstLineIndex === $i ? $type.$line : $lineIndentation.$line; } $line = $prefix.$line; @@ -423,11 +430,6 @@ private function createBlock($messages, $type = null, $style = null, $prefix = ' } } - if ($padding && $this->isDecorated()) { - array_unshift($lines, ''); - $lines[] = ''; - } - return $lines; } } diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index 927fa0bd820e8..a4779af6bef44 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -425,7 +425,7 @@ public function testFindAlternativeNamespace() $application->add(new \FooCommand()); $application->add(new \Foo1Command()); $application->add(new \Foo2Command()); - $application->add(new \foo3Command()); + $application->add(new \Foo3Command()); try { $application->find('Unknown-namespace:Unknown-command'); diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_16.php b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_16.php new file mode 100644 index 0000000000000..f21fc10d9c71d --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/command/command_16.php @@ -0,0 +1,15 @@ +setDecorated(true); + $output = new SymfonyStyleWithForcedLineLength($input, $output); + $output->success( + 'Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum', + 'TEST' + ); +}; diff --git a/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_16.txt b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_16.txt new file mode 100644 index 0000000000000..a0d180165b879 --- /dev/null +++ b/src/Symfony/Component/Console/Tests/Fixtures/Style/SymfonyStyle/output/output_16.txt @@ -0,0 +1,8 @@ + +  + [OK] Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore  + magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo  + consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.  + Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum  +  + diff --git a/src/Symfony/Component/Console/Tests/Helper/LegacyDialogHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/LegacyDialogHelperTest.php index 97bf77565a520..6436c7b1ea637 100644 --- a/src/Symfony/Component/Console/Tests/Helper/LegacyDialogHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/LegacyDialogHelperTest.php @@ -249,11 +249,6 @@ protected function getConsoleOutput($stderr) return $output; } - private function hasStderrSupport() - { - return false === $this->isRunningOS400(); - } - private function hasSttyAvailable() { exec('stty 2>&1', $output, $exitcode); diff --git a/src/Symfony/Component/Console/Tests/Helper/TableTest.php b/src/Symfony/Component/Console/Tests/Helper/TableTest.php index 9ecb381a80090..c3182329caf56 100644 --- a/src/Symfony/Component/Console/Tests/Helper/TableTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/TableTest.php @@ -631,6 +631,25 @@ public function testColumnStyle() $this->assertEquals($expected, $this->getOutputContent($output)); } + /** + * @expectedException Symfony\Component\Console\Exception\InvalidArgumentException + * @expectedExceptionMessage Style "absent" is not defined. + */ + public function testIsNotDefinedStyleException() + { + $table = new Table($this->getOutputStream()); + $table->setStyle('absent'); + } + + /** + * @expectedException \Symfony\Component\Console\Exception\InvalidArgumentException + * @expectedExceptionMessage Style "absent" is not defined. + */ + public function testGetStyleDefinition() + { + Table::getStyleDefinition('absent'); + } + protected function getOutputStream() { return new StreamOutput($this->stream, StreamOutput::VERBOSITY_NORMAL, false); diff --git a/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php b/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php index d2c540e6fe418..3b0dc3f231659 100644 --- a/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php +++ b/src/Symfony/Component/Console/Tests/Input/ArgvInputTest.php @@ -183,7 +183,17 @@ public function provideInvalidInput() array( array('cli.php', 'foo', 'bar'), new InputDefinition(), - 'Too many arguments.', + 'No arguments expected, got "foo".', + ), + array( + array('cli.php', 'foo', 'bar'), + new InputDefinition(array(new InputArgument('number'))), + 'Too many arguments, expected arguments "number".', + ), + array( + array('cli.php', 'foo', 'bar', 'zzz'), + new InputDefinition(array(new InputArgument('number'), new InputArgument('county'))), + 'Too many arguments, expected arguments "number" "county".', ), array( array('cli.php', '--foo'), diff --git a/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php b/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php index 96554d8507577..30fb35bf7a715 100644 --- a/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php +++ b/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php @@ -13,7 +13,6 @@ use Symfony\Component\Debug\DebugClassLoader; use Symfony\Component\Debug\ErrorHandler; -use Symfony\Component\Debug\Exception\ContextErrorException; class DebugClassLoaderTest extends \PHPUnit_Framework_TestCase { diff --git a/src/Symfony/Component/Debug/Tests/MockExceptionHandler.php b/src/Symfony/Component/Debug/Tests/MockExceptionHandler.php index a85d2d15e7131..2d6ce564d23a4 100644 --- a/src/Symfony/Component/Debug/Tests/MockExceptionHandler.php +++ b/src/Symfony/Component/Debug/Tests/MockExceptionHandler.php @@ -13,7 +13,7 @@ use Symfony\Component\Debug\ExceptionHandler; -class MockExceptionHandler extends Exceptionhandler +class MockExceptionHandler extends ExceptionHandler { public $e; diff --git a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php index ffb8c01f0f762..cc6e0e71b3652 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/PassConfig.php @@ -153,9 +153,9 @@ public function getRemovingPasses() } /** - * Gets all passes for the Merge pass. + * Gets the Merge pass. * - * @return array An array of passes + * @return CompilerPassInterface The merge pass */ public function getMergePass() { diff --git a/src/Symfony/Component/DependencyInjection/Compiler/ResolveReferencesToAliasesPass.php b/src/Symfony/Component/DependencyInjection/Compiler/ResolveReferencesToAliasesPass.php index 8114b880f1321..c200cb4d9138a 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/ResolveReferencesToAliasesPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/ResolveReferencesToAliasesPass.php @@ -12,7 +12,6 @@ namespace Symfony\Component\DependencyInjection\Compiler; use Symfony\Component\DependencyInjection\Alias; -use Symfony\Component\DependencyInjection\Definition; use Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\ContainerBuilder; diff --git a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php index 96b0b597053c3..c47821922cbf3 100644 --- a/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php +++ b/src/Symfony/Component/DependencyInjection/Loader/XmlFileLoader.php @@ -187,7 +187,7 @@ private function parseDefinition(\DOMElement $service, $file) } if ($deprecated = $this->getChildren($service, 'deprecated')) { - $definition->setDeprecated(true, $deprecated[0]->nodeValue); + $definition->setDeprecated(true, $deprecated[0]->nodeValue ?: null); } $definition->setArguments($this->getArgumentsAsPhp($service, 'argument')); @@ -587,7 +587,7 @@ private function loadFromExtensions(\DOMDocument $xml) * * @return array A PHP array */ - public static function convertDomElementToArray(\DomElement $element) + public static function convertDomElementToArray(\DOMElement $element) { return XmlUtils::convertDomElementToArray($element); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php index 7cb63c6613663..1b2ec6bd7604b 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Compiler/ReplaceAliasByActualDefinitionPassTest.php @@ -51,7 +51,7 @@ public function testProcess() $this->assertSame('b_alias', $aDefinition->getFactoryService(false)); $this->assertTrue($container->has('container')); - $resolvedFactory = $aDefinition->getFactory(false); + $resolvedFactory = $aDefinition->getFactory(); $this->assertSame('b_alias', (string) $resolvedFactory[0]); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php index f9f6aabe73282..b93190afd0651 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/ContainerBuilderTest.php @@ -60,6 +60,9 @@ public function testDefinitions() } } + /** + * @requires function Symfony\Bridge\PhpUnit\ErrorAssert::assertDeprecationsAreTriggered + */ public function testCreateDeprecatedService() { ErrorAssert::assertDeprecationsAreTriggered('The "deprecated_foo" service is deprecated. You should stop using it, as it will soon be removed.', function () { @@ -112,7 +115,7 @@ public function testGet() try { @$builder->get('baz'); $this->fail('->get() throws a ServiceCircularReferenceException if the service has a circular reference to itself'); - } catch (\Symfony\Component\DependencyInjection\Exception\ServiceCircularReferenceException $e) { + } catch (ServiceCircularReferenceException $e) { $this->assertEquals('Circular reference detected for service "baz", path: "baz".', $e->getMessage(), '->get() throws a LogicException if the service has a circular reference to itself'); } diff --git a/src/Symfony/Component/DependencyInjection/Tests/CrossCheckTest.php b/src/Symfony/Component/DependencyInjection/Tests/CrossCheckTest.php index 7905e7f3c6b9c..423c5db2ec96a 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/CrossCheckTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/CrossCheckTest.php @@ -34,7 +34,7 @@ public function testCrossCheck($fixture, $type) $loaderClass = 'Symfony\\Component\\DependencyInjection\\Loader\\'.ucfirst($type).'FileLoader'; $dumperClass = 'Symfony\\Component\\DependencyInjection\\Dumper\\'.ucfirst($type).'Dumper'; - $tmp = tempnam('sf_service_container', 'sf'); + $tmp = tempnam(sys_get_temp_dir(), 'sf'); file_put_contents($tmp, file_get_contents(self::$fixturesPath.'/'.$type.'/'.$fixture)); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php index a6b92c53698e9..3e32a2bcb017c 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/PhpDumperTest.php @@ -100,7 +100,7 @@ public function provideInvalidParameters() { return array( array(array('foo' => new Definition('stdClass'))), - array(array('foo' => new Expression('service("foo").foo() ~ (container.hasparameter("foo") ? parameter("foo") : "default")'))), + array(array('foo' => new Expression('service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default")'))), array(array('foo' => new Reference('foo'))), array(array('foo' => new Variable('foo'))), ); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php index 96f334fdd153f..89475f1fd077b 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/container9.php @@ -49,7 +49,7 @@ ->addMethodCall('setBar', array(new Reference('foo2', ContainerInterface::NULL_ON_INVALID_REFERENCE))) ->addMethodCall('setBar', array(new Reference('foo3', ContainerInterface::IGNORE_ON_INVALID_REFERENCE))) ->addMethodCall('setBar', array(new Reference('foobaz', ContainerInterface::IGNORE_ON_INVALID_REFERENCE))) - ->addMethodCall('setBar', array(new Expression('service("foo").foo() ~ (container.hasparameter("foo") ? parameter("foo") : "default")'))) + ->addMethodCall('setBar', array(new Expression('service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default")'))) ; $container ->register('foo_with_inline', 'Foo') diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/legacy-container9.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/legacy-container9.php index 22dc44a4e4312..9ac477b77ac73 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/legacy-container9.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/containers/legacy-container9.php @@ -4,7 +4,6 @@ use Symfony\Component\DependencyInjection\ContainerBuilder; use Symfony\Component\DependencyInjection\Reference; -use Symfony\Component\ExpressionLanguage\Expression; $container = new ContainerBuilder(); $container-> diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9.php index e30b809c67a29..19a4cb9c2aebf 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9.php @@ -266,7 +266,7 @@ protected function getMethodCall1Service() if ($this->has('foobaz')) { $instance->setBar($this->get('foobaz', ContainerInterface::NULL_ON_INVALID_REFERENCE)); } - $instance->setBar(($this->get("foo")->foo() . (($this->hasparameter("foo")) ? ($this->getParameter("foo")) : ("default")))); + $instance->setBar(($this->get("foo")->foo() . (($this->hasParameter("foo")) ? ($this->getParameter("foo")) : ("default")))); return $instance; } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php index b774c0db91df5..03c4500b70c5e 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/php/services9_compiled.php @@ -264,7 +264,7 @@ protected function getMethodCall1Service() $instance->setBar($this->get('foo')); $instance->setBar(NULL); - $instance->setBar(($this->get("foo")->foo() . (($this->hasparameter("foo")) ? ($this->getParameter("foo")) : ("default")))); + $instance->setBar(($this->get("foo")->foo() . (($this->hasParameter("foo")) ? ($this->getParameter("foo")) : ("default")))); return $instance; } diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services6.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services6.xml index 4595c668c73df..11b2993844342 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services6.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services6.xml @@ -30,7 +30,7 @@ - service("foo").foo() ~ (container.hasparameter("foo") ? parameter("foo") : "default") + service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default") diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml index 4ddb8655c55f2..72224fe56f65b 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services9.xml @@ -56,7 +56,7 @@ - service("foo").foo() ~ (container.hasparameter("foo") ? parameter("foo") : "default") + service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default") diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_deprecated.xml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_deprecated.xml new file mode 100644 index 0000000000000..c19a47adf517f --- /dev/null +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/xml/services_deprecated.xml @@ -0,0 +1,11 @@ + + + + + + + + The "%service_id%" service is deprecated. + + + diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services6.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services6.yml index baa0b5df05fdf..d723f6b254b90 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services6.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services6.yml @@ -12,7 +12,7 @@ services: calls: - [ setBar, [] ] - [ setBar ] - - [ setBar, ['@=service("foo").foo() ~ (container.hasparameter("foo") ? parameter("foo") : "default")'] ] + - [ setBar, ['@=service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default")'] ] method_call2: class: FooClass calls: diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml index 6efeb37e747d4..1afd15c5307d9 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml +++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services9.yml @@ -36,7 +36,7 @@ services: - [setBar, ['@?foo2']] - [setBar, ['@?foo3']] - [setBar, ['@?foobaz']] - - [setBar, ['@=service("foo").foo() ~ (container.hasparameter("foo") ? parameter("foo") : "default")']] + - [setBar, ['@=service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default")']] foo_with_inline: class: Foo diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php index 7322298a79a50..a3e2e20bb8903 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/XmlFileLoaderTest.php @@ -13,7 +13,6 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\DependencyInjection\ContainerBuilder; -use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException; use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; use Symfony\Component\DependencyInjection\Loader\YamlFileLoader; @@ -261,7 +260,7 @@ public function testLoadServices() $this->assertEquals('sc_configure', $services['configurator1']->getConfigurator(), '->load() parses the configurator tag'); $this->assertEquals(array(new Reference('baz', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false), 'configure'), $services['configurator2']->getConfigurator(), '->load() parses the configurator tag'); $this->assertEquals(array('BazClass', 'configureStatic'), $services['configurator3']->getConfigurator(), '->load() parses the configurator tag'); - $this->assertEquals(array(array('setBar', array()), array('setBar', array(new Expression('service("foo").foo() ~ (container.hasparameter("foo") ? parameter("foo") : "default")')))), $services['method_call1']->getMethodCalls(), '->load() parses the method_call tag'); + $this->assertEquals(array(array('setBar', array()), array('setBar', array(new Expression('service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default")')))), $services['method_call1']->getMethodCalls(), '->load() parses the method_call tag'); $this->assertEquals(array(array('setBar', array('foo', new Reference('foo'), array(true, false)))), $services['method_call2']->getMethodCalls(), '->load() parses the method_call tag'); $this->assertEquals('factory', $services['new_factory1']->getFactory(), '->load() parses the factory tag'); $this->assertEquals(array(new Reference('baz', ContainerInterface::EXCEPTION_ON_INVALID_REFERENCE, false), 'getClass'), $services['new_factory2']->getFactory(), '->load() parses the factory tag'); @@ -324,6 +323,21 @@ public function testParseTagWithEmptyNameThrowsException() $loader->load('tag_with_empty_name.xml'); } + public function testDeprecated() + { + $container = new ContainerBuilder(); + $loader = new XmlFileLoader($container, new FileLocator(self::$fixturesPath.'/xml')); + $loader->load('services_deprecated.xml'); + + $this->assertTrue($container->getDefinition('foo')->isDeprecated()); + $message = 'The "foo" service is deprecated. You should stop using it, as it will soon be removed.'; + $this->assertSame($message, $container->getDefinition('foo')->getDeprecationMessage('foo')); + + $this->assertTrue($container->getDefinition('bar')->isDeprecated()); + $message = 'The "bar" service is deprecated.'; + $this->assertSame($message, $container->getDefinition('bar')->getDeprecationMessage('bar')); + } + public function testConvertDomElementToArray() { $doc = new \DOMDocument('1.0'); diff --git a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php index a2e099a08fb61..5e1b1d0bc558d 100644 --- a/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php +++ b/src/Symfony/Component/DependencyInjection/Tests/Loader/YamlFileLoaderTest.php @@ -158,7 +158,7 @@ public function testLoadServices() $this->assertEquals('sc_configure', $services['configurator1']->getConfigurator(), '->load() parses the configurator tag'); $this->assertEquals(array(new Reference('baz'), 'configure'), $services['configurator2']->getConfigurator(), '->load() parses the configurator tag'); $this->assertEquals(array('BazClass', 'configureStatic'), $services['configurator3']->getConfigurator(), '->load() parses the configurator tag'); - $this->assertEquals(array(array('setBar', array()), array('setBar', array()), array('setBar', array(new Expression('service("foo").foo() ~ (container.hasparameter("foo") ? parameter("foo") : "default")')))), $services['method_call1']->getMethodCalls(), '->load() parses the method_call tag'); + $this->assertEquals(array(array('setBar', array()), array('setBar', array()), array('setBar', array(new Expression('service("foo").foo() ~ (container.hasParameter("foo") ? parameter("foo") : "default")')))), $services['method_call1']->getMethodCalls(), '->load() parses the method_call tag'); $this->assertEquals(array(array('setBar', array('foo', new Reference('foo'), array(true, false)))), $services['method_call2']->getMethodCalls(), '->load() parses the method_call tag'); $this->assertEquals('factory', $services['new_factory1']->getFactory(), '->load() parses the factory tag'); $this->assertEquals(array(new Reference('baz'), 'getClass'), $services['new_factory2']->getFactory(), '->load() parses the factory tag'); diff --git a/src/Symfony/Component/DependencyInjection/composer.json b/src/Symfony/Component/DependencyInjection/composer.json index db30f65a710a1..2506690ca6997 100644 --- a/src/Symfony/Component/DependencyInjection/composer.json +++ b/src/Symfony/Component/DependencyInjection/composer.json @@ -19,7 +19,7 @@ "php": ">=5.3.9" }, "require-dev": { - "symfony/yaml": "~2.1|~3.0.0", + "symfony/yaml": "~2.3.42|~2.7.14|~2.8.7|~3.0.7", "symfony/config": "~2.2|~3.0.0", "symfony/expression-language": "~2.6|~3.0.0" }, diff --git a/src/Symfony/Component/DomCrawler/Crawler.php b/src/Symfony/Component/DomCrawler/Crawler.php index 9e8b0cbc038ff..60f27f8cd7251 100644 --- a/src/Symfony/Component/DomCrawler/Crawler.php +++ b/src/Symfony/Component/DomCrawler/Crawler.php @@ -1151,6 +1151,7 @@ private function createSubCrawler($nodes) $crawler = new static($nodes, $this->uri, $this->baseHref); $crawler->isHtml = $this->isHtml; $crawler->document = $this->document; + $crawler->namespaces = $this->namespaces; return $crawler; } diff --git a/src/Symfony/Component/DomCrawler/Tests/FormTest.php b/src/Symfony/Component/DomCrawler/Tests/FormTest.php index 3035e8d371d96..91e87cc25dbe3 100644 --- a/src/Symfony/Component/DomCrawler/Tests/FormTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/FormTest.php @@ -13,7 +13,6 @@ use Symfony\Component\DomCrawler\Form; use Symfony\Component\DomCrawler\FormFieldRegistry; -use Symfony\Component\DomCrawler\Field; class FormTest extends \PHPUnit_Framework_TestCase { diff --git a/src/Symfony/Component/EventDispatcher/DependencyInjection/RegisterListenersPass.php b/src/Symfony/Component/EventDispatcher/DependencyInjection/RegisterListenersPass.php index ebfe435f87126..326bfd184f497 100644 --- a/src/Symfony/Component/EventDispatcher/DependencyInjection/RegisterListenersPass.php +++ b/src/Symfony/Component/EventDispatcher/DependencyInjection/RegisterListenersPass.php @@ -97,9 +97,13 @@ public function process(ContainerBuilder $container) // We must assume that the class value has been correctly filled, even if the service is created by a factory $class = $container->getParameterBag()->resolveValue($def->getClass()); - $interface = 'Symfony\Component\EventDispatcher\EventSubscriberInterface'; + if (!is_subclass_of($class, $interface)) { + if (!class_exists($class, false)) { + throw new \InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + } + throw new \InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface)); } diff --git a/src/Symfony/Component/EventDispatcher/Tests/AbstractEventDispatcherTest.php b/src/Symfony/Component/EventDispatcher/Tests/AbstractEventDispatcherTest.php index 0169ede0b0f3c..5e165326431af 100644 --- a/src/Symfony/Component/EventDispatcher/Tests/AbstractEventDispatcherTest.php +++ b/src/Symfony/Component/EventDispatcher/Tests/AbstractEventDispatcherTest.php @@ -142,7 +142,7 @@ public function testDispatch() public function testLegacyDispatch() { $event = new Event(); - $return = $this->dispatcher->dispatch(self::preFoo, $event); + $this->dispatcher->dispatch(self::preFoo, $event); $this->assertEquals('pre.foo', $event->getName()); } diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index 7390783de6e5a..e1d62fa427e0f 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -491,7 +491,7 @@ public function tempnam($dir, $prefix) // If no scheme or scheme is "file" or "gs" (Google Cloud) create temp file in local filesystem if (null === $scheme || 'file' === $scheme || 'gs' === $scheme) { - $tmpFile = tempnam($hierarchy, $prefix); + $tmpFile = @tempnam($hierarchy, $prefix); // If tempnam failed or no scheme return the filename otherwise prepend the scheme if (false !== $tmpFile) { diff --git a/src/Symfony/Component/Finder/Tests/Shell/CommandTest.php b/src/Symfony/Component/Finder/Tests/Shell/CommandTest.php index d1205591fa8df..8345111cecd24 100644 --- a/src/Symfony/Component/Finder/Tests/Shell/CommandTest.php +++ b/src/Symfony/Component/Finder/Tests/Shell/CommandTest.php @@ -151,7 +151,7 @@ public function testExecute() $this->assertInternalType('array', $result); $this->assertNotEmpty($result); - $this->assertRegexp('/PHP|HipHop/', $result[0]); + $this->assertRegExp('/PHP|HipHop/', $result[0]); } public function testCastToString() diff --git a/src/Symfony/Component/Form/ButtonBuilder.php b/src/Symfony/Component/Form/ButtonBuilder.php index 1eaed6a826292..89cad51530224 100644 --- a/src/Symfony/Component/Form/ButtonBuilder.php +++ b/src/Symfony/Component/Form/ButtonBuilder.php @@ -62,11 +62,12 @@ class ButtonBuilder implements \IteratorAggregate, FormBuilderInterface */ public function __construct($name, array $options = array()) { - if (empty($name) && 0 != $name) { + $name = (string) $name; + if ('' === $name) { throw new InvalidArgumentException('Buttons cannot have empty names.'); } - $this->name = (string) $name; + $this->name = $name; $this->options = $options; } diff --git a/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/CsrfProviderAdapter.php b/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/CsrfProviderAdapter.php index 2a55069692f8a..011d34a680111 100644 --- a/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/CsrfProviderAdapter.php +++ b/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/CsrfProviderAdapter.php @@ -21,8 +21,6 @@ * Adapter for using old CSRF providers where the new {@link CsrfTokenManagerInterface} * is expected. * - * @since 2.4 - * * @author Bernhard Schussek * * @deprecated since version 2.4, to be removed in 3.0. diff --git a/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/CsrfTokenManagerAdapter.php b/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/CsrfTokenManagerAdapter.php index b246a616b03ed..93ed3147143d2 100644 --- a/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/CsrfTokenManagerAdapter.php +++ b/src/Symfony/Component/Form/Extension/Csrf/CsrfProvider/CsrfTokenManagerAdapter.php @@ -17,8 +17,6 @@ /** * Adapter for using the new token generator with the old interface. * - * @since 2.4 - * * @author Bernhard Schussek * * @deprecated since version 2.4, to be removed in 3.0. diff --git a/src/Symfony/Component/Form/Extension/DataCollector/DataCollectorExtension.php b/src/Symfony/Component/Form/Extension/DataCollector/DataCollectorExtension.php index 70b347fa9af3a..2f2e51c0901c7 100644 --- a/src/Symfony/Component/Form/Extension/DataCollector/DataCollectorExtension.php +++ b/src/Symfony/Component/Form/Extension/DataCollector/DataCollectorExtension.php @@ -17,8 +17,6 @@ /** * Extension for collecting data of the forms on a page. * - * @since 2.4 - * * @author Robert Schönthal * @author Bernhard Schussek */ diff --git a/src/Symfony/Component/Form/Extension/DataCollector/EventListener/DataCollectorListener.php b/src/Symfony/Component/Form/Extension/DataCollector/EventListener/DataCollectorListener.php index 8fd70f09b1796..0bd33d36a5d1f 100644 --- a/src/Symfony/Component/Form/Extension/DataCollector/EventListener/DataCollectorListener.php +++ b/src/Symfony/Component/Form/Extension/DataCollector/EventListener/DataCollectorListener.php @@ -20,8 +20,6 @@ * Listener that invokes a data collector for the {@link FormEvents::POST_SET_DATA} * and {@link FormEvents::POST_SUBMIT} events. * - * @since 2.4 - * * @author Bernhard Schussek */ class DataCollectorListener implements EventSubscriberInterface diff --git a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php index d1375df8894b8..a408dde2306c9 100644 --- a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php +++ b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollector.php @@ -20,8 +20,6 @@ /** * Data collector for {@link FormInterface} instances. * - * @since 2.4 - * * @author Robert Schönthal * @author Bernhard Schussek */ diff --git a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollectorInterface.php b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollectorInterface.php index a57693a995241..ee004a09f30b4 100644 --- a/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollectorInterface.php +++ b/src/Symfony/Component/Form/Extension/DataCollector/FormDataCollectorInterface.php @@ -18,8 +18,6 @@ /** * Collects and structures information about forms. * - * @since 2.4 - * * @author Bernhard Schussek */ interface FormDataCollectorInterface extends DataCollectorInterface diff --git a/src/Symfony/Component/Form/Extension/DataCollector/FormDataExtractor.php b/src/Symfony/Component/Form/Extension/DataCollector/FormDataExtractor.php index 1c678ac665d09..71f07b5fe069f 100644 --- a/src/Symfony/Component/Form/Extension/DataCollector/FormDataExtractor.php +++ b/src/Symfony/Component/Form/Extension/DataCollector/FormDataExtractor.php @@ -19,8 +19,6 @@ /** * Default implementation of {@link FormDataExtractorInterface}. * - * @since 2.4 - * * @author Bernhard Schussek */ class FormDataExtractor implements FormDataExtractorInterface diff --git a/src/Symfony/Component/Form/Extension/DataCollector/FormDataExtractorInterface.php b/src/Symfony/Component/Form/Extension/DataCollector/FormDataExtractorInterface.php index a5bb7d0ef30a1..e0bc6dc0caccc 100644 --- a/src/Symfony/Component/Form/Extension/DataCollector/FormDataExtractorInterface.php +++ b/src/Symfony/Component/Form/Extension/DataCollector/FormDataExtractorInterface.php @@ -17,8 +17,6 @@ /** * Extracts arrays of information out of forms. * - * @since 2.4 - * * @author Bernhard Schussek */ interface FormDataExtractorInterface diff --git a/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php b/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php index 65430f1d222b0..11a0f92c90e25 100644 --- a/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php +++ b/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeDataCollectorProxy.php @@ -21,8 +21,6 @@ /** * Proxy that invokes a data collector when creating a form and its view. * - * @since 2.4 - * * @author Bernhard Schussek */ class ResolvedTypeDataCollectorProxy implements ResolvedFormTypeInterface diff --git a/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeFactoryDataCollectorProxy.php b/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeFactoryDataCollectorProxy.php index f5f4ed2e2095c..5051d0bb6390a 100644 --- a/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeFactoryDataCollectorProxy.php +++ b/src/Symfony/Component/Form/Extension/DataCollector/Proxy/ResolvedTypeFactoryDataCollectorProxy.php @@ -20,8 +20,6 @@ * Proxy that wraps resolved types into {@link ResolvedTypeDataCollectorProxy} * instances. * - * @since 2.4 - * * @author Bernhard Schussek */ class ResolvedTypeFactoryDataCollectorProxy implements ResolvedFormTypeFactoryInterface diff --git a/src/Symfony/Component/Form/Extension/DataCollector/Type/DataCollectorTypeExtension.php b/src/Symfony/Component/Form/Extension/DataCollector/Type/DataCollectorTypeExtension.php index e124031422964..966cb8503d521 100644 --- a/src/Symfony/Component/Form/Extension/DataCollector/Type/DataCollectorTypeExtension.php +++ b/src/Symfony/Component/Form/Extension/DataCollector/Type/DataCollectorTypeExtension.php @@ -19,8 +19,6 @@ /** * Type extension for collecting data of a form with this type. * - * @since 2.4 - * * @author Robert Schönthal * @author Bernhard Schussek */ diff --git a/src/Symfony/Component/Form/FormErrorIterator.php b/src/Symfony/Component/Form/FormErrorIterator.php index 113de435d5ede..41a1297d30f57 100644 --- a/src/Symfony/Component/Form/FormErrorIterator.php +++ b/src/Symfony/Component/Form/FormErrorIterator.php @@ -27,8 +27,6 @@ * flatten the recursive structure into a flat list of errors. * * @author Bernhard Schussek - * - * @since 2.5 */ class FormErrorIterator implements \RecursiveIterator, \SeekableIterator, \ArrayAccess, \Countable { diff --git a/src/Symfony/Component/Form/FormInterface.php b/src/Symfony/Component/Form/FormInterface.php index 13b03f5118c1c..9de802847ee8e 100644 --- a/src/Symfony/Component/Form/FormInterface.php +++ b/src/Symfony/Component/Form/FormInterface.php @@ -102,9 +102,6 @@ public function all(); * * @return FormErrorIterator An iterator over the {@link FormError} * instances that where added to this form - * - * @since 2.5 Since version 2.5 this method returns a - * {@link FormErrorIterator} instance instead of an array */ public function getErrors($deep = false, $flatten = true); diff --git a/src/Symfony/Component/Form/Test/FormPerformanceTestCase.php b/src/Symfony/Component/Form/Test/FormPerformanceTestCase.php index 090eb8bc4f5a9..75ddba621278f 100644 --- a/src/Symfony/Component/Form/Test/FormPerformanceTestCase.php +++ b/src/Symfony/Component/Form/Test/FormPerformanceTestCase.php @@ -62,8 +62,6 @@ public function setMaxRunningTime($maxRunningTime) } /** - * @since Method available since Release 2.3.0 - * * @return int */ public function getMaxRunningTime() diff --git a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php index 7eeaf53decd09..cab932316e408 100644 --- a/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php +++ b/src/Symfony/Component/Form/Tests/AbstractLayoutTest.php @@ -47,7 +47,7 @@ protected function tearDown() parent::tearDown(); } - protected function assertXpathNodeValue(\DomElement $element, $expression, $nodeValue) + protected function assertXpathNodeValue(\DOMElement $element, $expression, $nodeValue) { $xpath = new \DOMXPath($element->ownerDocument); $nodeList = $xpath->evaluate($expression); diff --git a/src/Symfony/Component/Form/Tests/ButtonBuilderTest.php b/src/Symfony/Component/Form/Tests/ButtonBuilderTest.php new file mode 100644 index 0000000000000..dc5d38b744860 --- /dev/null +++ b/src/Symfony/Component/Form/Tests/ButtonBuilderTest.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Tests; + +use Symfony\Component\Form\ButtonBuilder; + +/** + * @author Alexander Cheprasov + */ +class ButtonBuilderTest extends \PHPUnit_Framework_TestCase +{ + public function getValidNames() + { + return array( + array('reset'), + array('submit'), + array('foo'), + array('0'), + array(0), + array('button[]'), + ); + } + + /** + * @dataProvider getValidNames + */ + public function testValidNames($name) + { + $this->assertInstanceOf('\Symfony\Component\Form\ButtonBuilder', new ButtonBuilder($name)); + } + + public function getInvalidNames() + { + return array( + array(''), + array(false), + array(null), + ); + } + + /** + * @dataProvider getInvalidNames + */ + public function testInvalidNames($name) + { + $this->setExpectedException( + '\Symfony\Component\Form\Exception\InvalidArgumentException', + 'Buttons cannot have empty names.' + ); + new ButtonBuilder($name); + } +} diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php index b02fef221ed12..9e75f73024ec8 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/CollectionTypeTest.php @@ -11,7 +11,6 @@ namespace Symfony\Component\Form\Tests\Extension\Core\Type; -use Symfony\Component\Form\Form; use Symfony\Component\Form\Tests\Fixtures\Author; class CollectionTypeTest extends \Symfony\Component\Form\Test\TypeTestCase diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/LegacyFormValidatorLegacyApiTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/LegacyFormValidatorLegacyApiTest.php index 7ea58b7cef2fc..b756a92b49f04 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/LegacyFormValidatorLegacyApiTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/LegacyFormValidatorLegacyApiTest.php @@ -14,8 +14,6 @@ use Symfony\Component\Validator\Validation; /** - * @since 2.5.3 - * * @author Bernhard Schussek * @group legacy */ diff --git a/src/Symfony/Component/Form/Util/OrderedHashMap.php b/src/Symfony/Component/Form/Util/OrderedHashMap.php index 3aaa7d0451f1f..78687032feac6 100644 --- a/src/Symfony/Component/Form/Util/OrderedHashMap.php +++ b/src/Symfony/Component/Form/Util/OrderedHashMap.php @@ -63,8 +63,6 @@ * } * * @author Bernhard Schussek - * - * @since 2.2.6 */ class OrderedHashMap implements \ArrayAccess, \IteratorAggregate, \Countable { @@ -93,8 +91,6 @@ class OrderedHashMap implements \ArrayAccess, \IteratorAggregate, \Countable * Creates a new map. * * @param array $elements The elements to insert initially - * - * @since 2.2.6 */ public function __construct(array $elements = array()) { @@ -104,8 +100,6 @@ public function __construct(array $elements = array()) /** * {@inheritdoc} - * - * @since 2.2.6 */ public function offsetExists($key) { @@ -114,8 +108,6 @@ public function offsetExists($key) /** * {@inheritdoc} - * - * @since 2.2.6 */ public function offsetGet($key) { @@ -128,8 +120,6 @@ public function offsetGet($key) /** * {@inheritdoc} - * - * @since 2.2.6 */ public function offsetSet($key, $value) { @@ -140,7 +130,7 @@ public function offsetSet($key, $value) ? 0 // Imitate PHP's behavior of generating a key that equals // the highest existing integer key + 1 - : max($this->orderedKeys) + 1; + : 1 + (int) max($this->orderedKeys); } $this->orderedKeys[] = $key; @@ -151,8 +141,6 @@ public function offsetSet($key, $value) /** * {@inheritdoc} - * - * @since 2.2.6 */ public function offsetUnset($key) { @@ -170,8 +158,6 @@ public function offsetUnset($key) /** * {@inheritdoc} - * - * @since 2.2.6 */ public function getIterator() { @@ -180,8 +166,6 @@ public function getIterator() /** * {@inheritdoc} - * - * @since 2.2.6 */ public function count() { diff --git a/src/Symfony/Component/Form/Util/OrderedHashMapIterator.php b/src/Symfony/Component/Form/Util/OrderedHashMapIterator.php index f606626814895..32f591c860698 100644 --- a/src/Symfony/Component/Form/Util/OrderedHashMapIterator.php +++ b/src/Symfony/Component/Form/Util/OrderedHashMapIterator.php @@ -17,8 +17,6 @@ * This class is internal and should not be used. * * @author Bernhard Schussek - * - * @since 2.2.6 */ class OrderedHashMapIterator implements \Iterator { @@ -69,8 +67,6 @@ class OrderedHashMapIterator implements \Iterator * This array is managed by the corresponding * {@link OrderedHashMap} instance to support * recognizing the deletion of elements. - * - * @since 2.2.6 */ public function __construct(array &$elements, array &$orderedKeys, array &$managedCursors) { @@ -85,8 +81,6 @@ public function __construct(array &$elements, array &$orderedKeys, array &$manag /** * Removes the iterator's cursors from the managed cursors of the * corresponding {@link OrderedHashMap} instance. - * - * @since 2.2.6 */ public function __destruct() { @@ -96,9 +90,7 @@ public function __destruct() } /** - *{@inheritdoc} - * - * @since 2.2.6 + * {@inheritdoc} */ public function current() { @@ -107,8 +99,6 @@ public function current() /** * {@inheritdoc} - * - * @since 2.2.6 */ public function next() { @@ -124,9 +114,7 @@ public function next() } /** - *{@inheritdoc} - * - * @since 2.2.6 + * {@inheritdoc} */ public function key() { @@ -134,9 +122,7 @@ public function key() } /** - *{@inheritdoc} - * - * @since 2.2.6 + * {@inheritdoc} */ public function valid() { @@ -144,9 +130,7 @@ public function valid() } /** - *{@inheritdoc} - * - * @since 2.2.6 + * {@inheritdoc} */ public function rewind() { diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 16a9375e91b2e..3d53f64a7b813 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1476,7 +1476,7 @@ public function isMethod($method) */ public function isMethodSafe() { - return in_array($this->getMethod(), array('GET', 'HEAD')); + return in_array($this->getMethod(), array('GET', 'HEAD', 'OPTIONS', 'TRACE')); } /** diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php index bc3ab23de2f2e..009ce65f8a118 100644 --- a/src/Symfony/Component/HttpFoundation/Response.php +++ b/src/Symfony/Component/HttpFoundation/Response.php @@ -373,6 +373,12 @@ public function send() $this->sendHeaders(); $this->sendContent(); + if (function_exists('fastcgi_finish_request')) { + fastcgi_finish_request(); + } elseif ('cli' !== PHP_SAPI) { + static::closeOutputBuffers(0, true); + } + return $this; } diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php index f1df25d0a629b..7efc1348c8027 100644 --- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php +++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MongoDbSessionHandler.php @@ -19,7 +19,7 @@ class MongoDbSessionHandler implements \SessionHandlerInterface { /** - * @var \Mongo + * @var \Mongo|\MongoClient|\MongoDB\Client */ private $mongo; @@ -61,15 +61,15 @@ class MongoDbSessionHandler implements \SessionHandlerInterface * If you use such an index, you can drop `gc_probability` to 0 since * no garbage-collection is required. * - * @param \Mongo|\MongoClient $mongo A MongoClient or Mongo instance - * @param array $options An associative array of field options + * @param \Mongo|\MongoClient|\MongoDB\Client $mongo A MongoDB\Client, MongoClient or Mongo instance + * @param array $options An associative array of field options * * @throws \InvalidArgumentException When MongoClient or Mongo instance not provided * @throws \InvalidArgumentException When "database" or "collection" not provided */ public function __construct($mongo, array $options) { - if (!($mongo instanceof \MongoClient || $mongo instanceof \Mongo)) { + if (!($mongo instanceof \MongoDB\Client || $mongo instanceof \MongoClient || $mongo instanceof \Mongo)) { throw new \InvalidArgumentException('MongoClient or Mongo instance required'); } @@ -108,7 +108,9 @@ public function close() */ public function destroy($sessionId) { - $this->getCollection()->remove(array( + $methodName = $this->mongo instanceof \MongoDB\Client ? 'deleteOne' : 'remove'; + + $this->getCollection()->$methodName(array( $this->options['id_field'] => $sessionId, )); @@ -120,8 +122,10 @@ public function destroy($sessionId) */ public function gc($maxlifetime) { - $this->getCollection()->remove(array( - $this->options['expiry_field'] => array('$lt' => new \MongoDate()), + $methodName = $this->mongo instanceof \MongoDB\Client ? 'deleteOne' : 'remove'; + + $this->getCollection()->$methodName(array( + $this->options['expiry_field'] => array('$lt' => $this->createDateTime()), )); return true; @@ -132,18 +136,28 @@ public function gc($maxlifetime) */ public function write($sessionId, $data) { - $expiry = new \MongoDate(time() + (int) ini_get('session.gc_maxlifetime')); + $expiry = $this->createDateTime(time() + (int) ini_get('session.gc_maxlifetime')); $fields = array( - $this->options['data_field'] => new \MongoBinData($data, \MongoBinData::BYTE_ARRAY), - $this->options['time_field'] => new \MongoDate(), + $this->options['time_field'] => $this->createDateTime(), $this->options['expiry_field'] => $expiry, ); - $this->getCollection()->update( + $options = array('upsert' => true); + + if ($this->mongo instanceof \MongoDB\Client) { + $fields[$this->options['data_field']] = new \MongoDB\BSON\Binary($data, \MongoDB\BSON\Binary::TYPE_OLD_BINARY); + } else { + $fields[$this->options['data_field']] = new \MongoBinData($data, \MongoBinData::BYTE_ARRAY); + $options['multiple'] = false; + } + + $methodName = $this->mongo instanceof \MongoDB\Client ? 'updateOne' : 'update'; + + $this->getCollection()->$methodName( array($this->options['id_field'] => $sessionId), array('$set' => $fields), - array('upsert' => true, 'multiple' => false) + $options ); return true; @@ -156,10 +170,18 @@ public function read($sessionId) { $dbData = $this->getCollection()->findOne(array( $this->options['id_field'] => $sessionId, - $this->options['expiry_field'] => array('$gte' => new \MongoDate()), + $this->options['expiry_field'] => array('$gte' => $this->createDateTime()), )); - return null === $dbData ? '' : $dbData[$this->options['data_field']]->bin; + if (null === $dbData) { + return ''; + } + + if ($dbData[$this->options['data_field']] instanceof \MongoDB\BSON\Binary) { + return $dbData[$this->options['data_field']]->getData(); + } + + return $dbData[$this->options['data_field']]->bin; } /** @@ -179,10 +201,30 @@ private function getCollection() /** * Return a Mongo instance. * - * @return \Mongo + * @return \Mongo|\MongoClient|\MongoDB\Client */ protected function getMongo() { return $this->mongo; } + + /** + * Create a date object using the class appropriate for the current mongo connection. + * + * Return an instance of a MongoDate or \MongoDB\BSON\UTCDateTime + * + * @param int $seconds An integer representing UTC seconds since Jan 1 1970. Defaults to now. + */ + private function createDateTime($seconds = null) + { + if (null === $seconds) { + $seconds = time(); + } + + if ($this->mongo instanceof \MongoDB\Client) { + return new \MongoDB\BSON\UTCDateTime($seconds * 1000); + } + + return new \MongoDate($seconds); + } } diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index 1edc48c1b62db..8540cad6630ee 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -1912,6 +1912,32 @@ public function getLongHostNames() array(str_repeat(':', 101)), ); } + + /** + * @dataProvider methodSafeProvider + */ + public function testMethodSafe($method, $safe) + { + $request = new Request(); + $request->setMethod($method); + $this->assertEquals($safe, $request->isMethodSafe()); + } + + public function methodSafeProvider() + { + return array( + array('HEAD', true), + array('GET', true), + array('POST', false), + array('PUT', false), + array('PATCH', false), + array('DELETE', false), + array('PURGE', false), + array('OPTIONS', true), + array('TRACE', true), + array('CONNECT', false), + ); + } } class RequestContentProxy extends Request diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/LegacyPdoSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/LegacyPdoSessionHandlerTest.php index 4efb33cd09cca..f8497f53ec7dc 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/LegacyPdoSessionHandlerTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/LegacyPdoSessionHandlerTest.php @@ -58,7 +58,7 @@ public function testWrongTableOptionsRead() { $storage = new LegacyPdoSessionHandler($this->pdo, array('db_table' => 'bad_name')); $this->setExpectedException('RuntimeException'); - $storage->read('foo', 'bar'); + $storage->read('foo'); } public function testWriteRead() diff --git a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php index 556f26a33c403..0ae0d4b2f7366 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/Session/Storage/Handler/MongoDbSessionHandlerTest.php @@ -15,7 +15,6 @@ /** * @author Markus Bachmann - * @requires extension mongo * @group time-sensitive */ class MongoDbSessionHandlerTest extends \PHPUnit_Framework_TestCase @@ -31,7 +30,15 @@ protected function setUp() { parent::setUp(); - $mongoClass = version_compare(phpversion('mongo'), '1.3.0', '<') ? 'Mongo' : 'MongoClient'; + if (!extension_loaded('mongo') && !extension_loaded('mongodb')) { + $this->markTestSkipped('The Mongo or MongoDB extension is required.'); + } + + if (phpversion('mongodb')) { + $mongoClass = 'MongoDB\Client'; + } else { + $mongoClass = version_compare(phpversion('mongo'), '1.3.0', '<') ? 'Mongo' : 'MongoClient'; + } $this->mongo = $this->getMockBuilder($mongoClass) ->disableOriginalConstructor() @@ -98,14 +105,28 @@ public function testRead() $that->assertArrayHasKey($that->options['expiry_field'], $criteria); $that->assertArrayHasKey('$gte', $criteria[$that->options['expiry_field']]); - $that->assertInstanceOf('MongoDate', $criteria[$that->options['expiry_field']]['$gte']); - $that->assertGreaterThanOrEqual($criteria[$that->options['expiry_field']]['$gte']->sec, $testTimeout); - return array( + if (phpversion('mongodb')) { + $that->assertInstanceOf('MongoDB\BSON\UTCDateTime', $criteria[$that->options['expiry_field']]['$gte']); + $that->assertGreaterThanOrEqual(round(intval((string) $criteria[$that->options['expiry_field']]['$gte']) / 1000), $testTimeout); + } else { + $that->assertInstanceOf('MongoDate', $criteria[$that->options['expiry_field']]['$gte']); + $that->assertGreaterThanOrEqual($criteria[$that->options['expiry_field']]['$gte']->sec, $testTimeout); + } + + $fields = array( $that->options['id_field'] => 'foo', - $that->options['data_field'] => new \MongoBinData('bar', \MongoBinData::BYTE_ARRAY), - $that->options['id_field'] => new \MongoDate(), ); + + if (phpversion('mongodb')) { + $fields[$that->options['data_field']] = new \MongoDB\BSON\Binary('bar', \MongoDB\BSON\Binary::TYPE_OLD_BINARY); + $fields[$that->options['id_field']] = new \MongoDB\BSON\UTCDateTime(time() * 1000); + } else { + $fields[$that->options['data_field']] = new \MongoBinData('bar', \MongoBinData::BYTE_ARRAY); + $fields[$that->options['id_field']] = new \MongoDate(); + } + + return $fields; })); $this->assertEquals('bar', $this->storage->read('foo')); @@ -123,11 +144,18 @@ public function testWrite() $that = $this; $data = array(); + $methodName = phpversion('mongodb') ? 'updateOne' : 'update'; + $collection->expects($this->once()) - ->method('update') + ->method($methodName) ->will($this->returnCallback(function ($criteria, $updateData, $options) use ($that, &$data) { $that->assertEquals(array($that->options['id_field'] => 'foo'), $criteria); - $that->assertEquals(array('upsert' => true, 'multiple' => false), $options); + + if (phpversion('mongodb')) { + $that->assertEquals(array('upsert' => true), $options); + } else { + $that->assertEquals(array('upsert' => true, 'multiple' => false), $options); + } $data = $updateData['$set']; })); @@ -135,10 +163,17 @@ public function testWrite() $expectedExpiry = time() + (int) ini_get('session.gc_maxlifetime'); $this->assertTrue($this->storage->write('foo', 'bar')); - $this->assertEquals('bar', $data[$this->options['data_field']]->bin); - $that->assertInstanceOf('MongoDate', $data[$this->options['time_field']]); - $this->assertInstanceOf('MongoDate', $data[$this->options['expiry_field']]); - $this->assertGreaterThanOrEqual($expectedExpiry, $data[$this->options['expiry_field']]->sec); + if (phpversion('mongodb')) { + $that->assertEquals('bar', $data[$that->options['data_field']]->getData()); + $that->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$that->options['time_field']]); + $that->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$that->options['expiry_field']]); + $that->assertGreaterThanOrEqual($expectedExpiry, round(intval((string) $data[$that->options['expiry_field']]) / 1000)); + } else { + $that->assertEquals('bar', $data[$that->options['data_field']]->bin); + $that->assertInstanceOf('MongoDate', $data[$that->options['time_field']]); + $that->assertInstanceOf('MongoDate', $data[$that->options['expiry_field']]); + $that->assertGreaterThanOrEqual($expectedExpiry, $data[$that->options['expiry_field']]->sec); + } } public function testWriteWhenUsingExpiresField() @@ -164,20 +199,33 @@ public function testWriteWhenUsingExpiresField() $that = $this; $data = array(); + $methodName = phpversion('mongodb') ? 'updateOne' : 'update'; + $collection->expects($this->once()) - ->method('update') + ->method($methodName) ->will($this->returnCallback(function ($criteria, $updateData, $options) use ($that, &$data) { $that->assertEquals(array($that->options['id_field'] => 'foo'), $criteria); - $that->assertEquals(array('upsert' => true, 'multiple' => false), $options); + + if (phpversion('mongodb')) { + $that->assertEquals(array('upsert' => true), $options); + } else { + $that->assertEquals(array('upsert' => true, 'multiple' => false), $options); + } $data = $updateData['$set']; })); $this->assertTrue($this->storage->write('foo', 'bar')); - $this->assertEquals('bar', $data[$this->options['data_field']]->bin); - $that->assertInstanceOf('MongoDate', $data[$this->options['time_field']]); - $that->assertInstanceOf('MongoDate', $data[$this->options['expiry_field']]); + if (phpversion('mongodb')) { + $that->assertEquals('bar', $data[$that->options['data_field']]->getData()); + $that->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$that->options['time_field']]); + $that->assertInstanceOf('MongoDB\BSON\UTCDateTime', $data[$that->options['expiry_field']]); + } else { + $that->assertEquals('bar', $data[$that->options['data_field']]->bin); + $that->assertInstanceOf('MongoDate', $data[$that->options['time_field']]); + $that->assertInstanceOf('MongoDate', $data[$that->options['expiry_field']]); + } } public function testReplaceSessionData() @@ -191,8 +239,10 @@ public function testReplaceSessionData() $data = array(); + $methodName = phpversion('mongodb') ? 'updateOne' : 'update'; + $collection->expects($this->exactly(2)) - ->method('update') + ->method($methodName) ->will($this->returnCallback(function ($criteria, $updateData, $options) use (&$data) { $data = $updateData; })); @@ -200,7 +250,11 @@ public function testReplaceSessionData() $this->storage->write('foo', 'bar'); $this->storage->write('foo', 'foobar'); - $this->assertEquals('foobar', $data['$set'][$this->options['data_field']]->bin); + if (phpversion('mongodb')) { + $this->assertEquals('foobar', $data['$set'][$this->options['data_field']]->getData()); + } else { + $this->assertEquals('foobar', $data['$set'][$this->options['data_field']]->bin); + } } public function testDestroy() @@ -212,8 +266,10 @@ public function testDestroy() ->with($this->options['database'], $this->options['collection']) ->will($this->returnValue($collection)); + $methodName = phpversion('mongodb') ? 'deleteOne' : 'remove'; + $collection->expects($this->once()) - ->method('remove') + ->method($methodName) ->with(array($this->options['id_field'] => 'foo')); $this->assertTrue($this->storage->destroy('foo')); @@ -230,19 +286,45 @@ public function testGc() $that = $this; + $methodName = phpversion('mongodb') ? 'deleteOne' : 'remove'; + $collection->expects($this->once()) - ->method('remove') + ->method($methodName) ->will($this->returnCallback(function ($criteria) use ($that) { - $that->assertInstanceOf('MongoDate', $criteria[$that->options['expiry_field']]['$lt']); - $that->assertGreaterThanOrEqual(time() - 1, $criteria[$that->options['expiry_field']]['$lt']->sec); + if (phpversion('mongodb')) { + $that->assertInstanceOf('MongoDB\BSON\UTCDateTime', $criteria[$that->options['expiry_field']]['$lt']); + $that->assertGreaterThanOrEqual(time() - 1, round(intval((string) $criteria[$that->options['expiry_field']]['$lt']) / 1000)); + } else { + $that->assertInstanceOf('MongoDate', $criteria[$that->options['expiry_field']]['$lt']); + $that->assertGreaterThanOrEqual(time() - 1, $criteria[$that->options['expiry_field']]['$lt']->sec); + } })); $this->assertTrue($this->storage->gc(1)); } + public function testGetConnection() + { + $method = new \ReflectionMethod($this->storage, 'getMongo'); + $method->setAccessible(true); + + if (phpversion('mongodb')) { + $mongoClass = 'MongoDB\Client'; + } else { + $mongoClass = version_compare(phpversion('mongo'), '1.3.0', '<') ? 'Mongo' : 'MongoClient'; + } + + $this->assertInstanceOf($mongoClass, $method->invoke($this->storage)); + } + private function createMongoCollectionMock() { - $collection = $this->getMockBuilder('MongoCollection') + $collectionClass = 'MongoCollection'; + if (phpversion('mongodb')) { + $collectionClass = 'MongoDB\Collection'; + } + + $collection = $this->getMockBuilder($collectionClass) ->disableOriginalConstructor() ->getMock(); diff --git a/src/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmer.php b/src/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmer.php index 948b3ffd141c1..dba35a639a46c 100644 --- a/src/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmer.php +++ b/src/Symfony/Component/HttpKernel/CacheWarmer/CacheWarmer.php @@ -20,7 +20,7 @@ abstract class CacheWarmer implements CacheWarmerInterface { protected function writeCacheFile($file, $content) { - $tmpFile = tempnam(dirname($file), basename($file)); + $tmpFile = @tempnam(dirname($file), basename($file)); if (false !== @file_put_contents($tmpFile, $content) && @rename($tmpFile, $file)) { @chmod($file, 0666 & ~umask()); diff --git a/src/Symfony/Component/HttpKernel/DependencyInjection/FragmentRendererPass.php b/src/Symfony/Component/HttpKernel/DependencyInjection/FragmentRendererPass.php index 3187e943c94f4..0c4cecef66423 100644 --- a/src/Symfony/Component/HttpKernel/DependencyInjection/FragmentRendererPass.php +++ b/src/Symfony/Component/HttpKernel/DependencyInjection/FragmentRendererPass.php @@ -54,7 +54,12 @@ public function process(ContainerBuilder $container) $class = $container->getParameterBag()->resolveValue($def->getClass()); $interface = 'Symfony\Component\HttpKernel\Fragment\FragmentRendererInterface'; + if (!is_subclass_of($class, $interface)) { + if (!class_exists($class, false)) { + throw new \InvalidArgumentException(sprintf('Class "%s" used for service "%s" cannot be found.', $class, $id)); + } + throw new \InvalidArgumentException(sprintf('Service "%s" must implement interface "%s".', $id, $interface)); } diff --git a/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php b/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php index a6ab82ea28efa..a61b239c158b9 100644 --- a/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php +++ b/src/Symfony/Component/HttpKernel/Fragment/InlineFragmentRenderer.php @@ -129,6 +129,8 @@ protected function createSubRequest($uri, Request $request) } $server['REMOTE_ADDR'] = '127.0.0.1'; + unset($server['HTTP_IF_MODIFIED_SINCE']); + unset($server['HTTP_IF_NONE_MATCH']); $subRequest = Request::create($uri, 'get', array(), $cookies, array(), $server); if ($request->headers->has('Surrogate-Capability')) { diff --git a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php index f794d94e29d45..1b86ddd3c0c58 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/HttpCache.php @@ -600,6 +600,9 @@ protected function lock(Request $request, Response $entry) */ protected function store(Request $request, Response $response) { + if (!$response->headers->has('Date')) { + $response->setDate(\DateTime::createFromFormat('U', time())); + } try { $this->store->write($request, $response); diff --git a/src/Symfony/Component/HttpKernel/HttpCache/Store.php b/src/Symfony/Component/HttpKernel/HttpCache/Store.php index 433b0ef29b4e2..b57d4a774d5c2 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/Store.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/Store.php @@ -38,7 +38,7 @@ class Store implements StoreInterface public function __construct($root) { $this->root = $root; - if (!is_dir($this->root) && !@mkdir($this->root, 0777, true) && !is_dir($this->root)) { + if (!file_exists($this->root) && !@mkdir($this->root, 0777, true) && !is_dir($this->root)) { throw new \RuntimeException(sprintf('Unable to create the store directory (%s).', $this->root)); } $this->keyCache = new \SplObjectStorage(); @@ -52,22 +52,15 @@ public function cleanup() { // unlock everything foreach ($this->locks as $lock) { - if (file_exists($lock)) { - @unlink($lock); - } + flock($lock, LOCK_UN); + fclose($lock); } - $error = error_get_last(); - if (1 === $error['type'] && false === headers_sent()) { - // send a 503 - header('HTTP/1.0 503 Service Unavailable'); - header('Retry-After: 10'); - echo '503 Service Unavailable'; - } + $this->locks = array(); } /** - * Locks the cache for a given Request. + * Tries to lock the cache for a given Request, without blocking. * * @param Request $request A Request instance * @@ -75,21 +68,24 @@ public function cleanup() */ public function lock(Request $request) { - $path = $this->getPath($this->getCacheKey($request).'.lck'); - if (!is_dir(dirname($path)) && false === @mkdir(dirname($path), 0777, true) && !is_dir(dirname($path))) { - return false; - } + $key = $this->getCacheKey($request); - $lock = @fopen($path, 'x'); - if (false !== $lock) { - fclose($lock); + if (!isset($this->locks[$key])) { + $path = $this->getPath($key); + if (!file_exists(dirname($path)) && false === @mkdir(dirname($path), 0777, true) && !is_dir(dirname($path))) { + return $path; + } + $h = fopen($path, 'cb'); + if (!flock($h, LOCK_EX | LOCK_NB)) { + fclose($h); - $this->locks[] = $path; + return $path; + } - return true; + $this->locks[$key] = $h; } - return !file_exists($path) ?: $path; + return true; } /** @@ -101,17 +97,37 @@ public function lock(Request $request) */ public function unlock(Request $request) { - $file = $this->getPath($this->getCacheKey($request).'.lck'); + $key = $this->getCacheKey($request); + + if (isset($this->locks[$key])) { + flock($this->locks[$key], LOCK_UN); + fclose($this->locks[$key]); + unset($this->locks[$key]); + + return true; + } - return is_file($file) ? @unlink($file) : false; + return false; } public function isLocked(Request $request) { - $path = $this->getPath($this->getCacheKey($request).'.lck'); - clearstatcache(true, $path); + $key = $this->getCacheKey($request); + + if (isset($this->locks[$key])) { + return true; // shortcut if lock held by this process + } + + if (!file_exists($path = $this->getPath($key))) { + return false; + } - return is_file($path); + $h = fopen($path, 'rb'); + flock($h, LOCK_EX | LOCK_NB, $wouldBlock); + flock($h, LOCK_UN); // release the lock we just acquired + fclose($h); + + return (bool) $wouldBlock; } /** @@ -144,7 +160,7 @@ public function lookup(Request $request) } list($req, $headers) = $match; - if (is_file($body = $this->getPath($headers['x-content-digest'][0]))) { + if (file_exists($body = $this->getPath($headers['x-content-digest'][0]))) { return $this->restoreResponse($headers, $body); } @@ -291,7 +307,7 @@ private function requestsMatch($vary, $env1, $env2) */ private function getMetadata($key) { - if (false === $entries = $this->load($key)) { + if (!$entries = $this->load($key)) { return array(); } @@ -307,7 +323,15 @@ private function getMetadata($key) */ public function purge($url) { - if (is_file($path = $this->getPath($this->getCacheKey(Request::create($url))))) { + $key = $this->getCacheKey(Request::create($url)); + + if (isset($this->locks[$key])) { + flock($this->locks[$key], LOCK_UN); + fclose($this->locks[$key]); + unset($this->locks[$key]); + } + + if (file_exists($path = $this->getPath($key))) { unlink($path); return true; @@ -327,7 +351,7 @@ private function load($key) { $path = $this->getPath($key); - return is_file($path) ? file_get_contents($path) : false; + return file_exists($path) ? file_get_contents($path) : false; } /** @@ -341,23 +365,36 @@ private function load($key) private function save($key, $data) { $path = $this->getPath($key); - if (!is_dir(dirname($path)) && false === @mkdir(dirname($path), 0777, true) && !is_dir(dirname($path))) { - return false; - } - $tmpFile = tempnam(dirname($path), basename($path)); - if (false === $fp = @fopen($tmpFile, 'wb')) { - return false; - } - @fwrite($fp, $data); - @fclose($fp); + if (isset($this->locks[$key])) { + $fp = $this->locks[$key]; + @ftruncate($fp, 0); + @fseek($fp, 0); + $len = @fwrite($fp, $data); + if (strlen($data) !== $len) { + @ftruncate($fp, 0); - if ($data != file_get_contents($tmpFile)) { - return false; - } + return false; + } + } else { + if (!file_exists(dirname($path)) && false === @mkdir(dirname($path), 0777, true) && !is_dir(dirname($path))) { + return false; + } - if (false === @rename($tmpFile, $path)) { - return false; + $tmpFile = tempnam(dirname($path), basename($path)); + if (false === $fp = @fopen($tmpFile, 'wb')) { + return false; + } + @fwrite($fp, $data); + @fclose($fp); + + if ($data != file_get_contents($tmpFile)) { + return false; + } + + if (false === @rename($tmpFile, $path)) { + return false; + } } @chmod($path, 0666 & ~umask()); diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 2032b56120a58..e8dd596cad1e2 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,11 +59,11 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.8.8'; - const VERSION_ID = 20808; + const VERSION = '2.8.9'; + const VERSION_ID = 20809; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; - const RELEASE_VERSION = 8; + const RELEASE_VERSION = 9; const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '11/2018'; @@ -150,14 +150,6 @@ public function terminate(Request $request, Response $response) } if ($this->getHttpKernel() instanceof TerminableInterface) { - if (!$this->debug) { - if (function_exists('fastcgi_finish_request')) { - fastcgi_finish_request(); - } elseif ('cli' !== PHP_SAPI) { - Response::closeOutputBuffers(0, true); - } - } - $this->getHttpKernel()->terminate($request, $response); } } diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php index fe6eb2b425fdb..a23268ca1de78 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/LocaleListenerTest.php @@ -11,7 +11,6 @@ namespace Symfony\Component\HttpKernel\Tests\EventListener; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\EventListener\LocaleListener; use Symfony\Component\HttpKernel\HttpKernelInterface; diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php index c3b7705bf146f..9eb1ec96ce028 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php @@ -11,7 +11,6 @@ namespace Symfony\Component\HttpKernel\Tests\EventListener; -use Symfony\Component\HttpFoundation\RequestStack; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpKernel\EventListener\RouterListener; use Symfony\Component\HttpKernel\HttpKernelInterface; diff --git a/src/Symfony/Component/HttpKernel/Tests/Fixtures/ExtensionPresentBundle/Command/BarCommand.php b/src/Symfony/Component/HttpKernel/Tests/Fixtures/ExtensionPresentBundle/Command/BarCommand.php index f3fd14b55de8b..977976b75f88b 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fixtures/ExtensionPresentBundle/Command/BarCommand.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fixtures/ExtensionPresentBundle/Command/BarCommand.php @@ -3,7 +3,6 @@ namespace Symfony\Component\HttpKernel\Tests\Fixtures\ExtensionPresentBundle\Command; use Symfony\Component\Console\Command\Command; -use Symfony\Component\HttpKernel\Bundle; /** * This command has a required parameter on the constructor and will be ignored by the default Bundle implementation. diff --git a/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php b/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php index 4e487a478a600..d14ebb0d12c33 100644 --- a/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/Fragment/InlineFragmentRendererTest.php @@ -197,6 +197,19 @@ public function testESIHeaderIsKeptInSubrequestWithTrustedHeaderDisabled() Request::setTrustedHeaderName(Request::HEADER_CLIENT_IP, $trustedHeaderName); } + + public function testHeadersPossiblyResultingIn304AreNotAssignedToSubrequest() + { + $expectedSubRequest = Request::create('/'); + if (Request::getTrustedHeaderName(Request::HEADER_CLIENT_IP)) { + $expectedSubRequest->headers->set('x-forwarded-for', array('127.0.0.1')); + $expectedSubRequest->server->set('HTTP_X_FORWARDED_FOR', '127.0.0.1'); + } + + $strategy = new InlineFragmentRenderer($this->getKernelExpectingRequest($expectedSubRequest)); + $request = Request::create('/', 'GET', array(), array(), array(), array('HTTP_IF_MODIFIED_SINCE' => 'Fri, 01 Jan 2016 00:00:00 GMT', 'HTTP_IF_NONE_MATCH' => '*')); + $strategy->render('/', $request); + } } class Bar diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php index b6164dd6782fb..4eb14371448fa 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php @@ -181,6 +181,31 @@ public function testRespondsWith304OnlyIfIfNoneMatchAndIfModifiedSinceBothMatch( $this->assertEquals(304, $this->response->getStatusCode()); } + public function testIncrementsMaxAgeWhenNoDateIsSpecifiedEventWhenUsingETag() + { + $this->setNextResponse( + 200, + array( + 'ETag' => '1234', + 'Cache-Control' => 'public, s-maxage=60', + ) + ); + + $this->request('GET', '/'); + $this->assertHttpKernelIsCalled(); + $this->assertEquals(200, $this->response->getStatusCode()); + $this->assertTraceContains('miss'); + $this->assertTraceContains('store'); + + sleep(2); + + $this->request('GET', '/'); + $this->assertHttpKernelIsNotCalled(); + $this->assertEquals(200, $this->response->getStatusCode()); + $this->assertTraceContains('fresh'); + $this->assertEquals(2, $this->response->headers->get('Age')); + } + public function testValidatesPrivateResponsesCachedOnTheClient() { $this->setNextResponse(200, array(), '', function ($request, $response) { diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php index 1fcd2107519bd..722e98760f111 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTestCase.php @@ -50,6 +50,9 @@ protected function setUp() protected function tearDown() { + if ($this->cache) { + $this->cache->getStore()->cleanup(); + } $this->kernel = null; $this->cache = null; $this->caches = null; diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php index 4198ce4031340..bf4239beaea61 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/StoreTest.php @@ -19,6 +19,10 @@ class StoreTest extends \PHPUnit_Framework_TestCase { protected $request; protected $response; + + /** + * @var Store + */ protected $store; protected function setUp() diff --git a/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php b/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php index 9eb786844269c..e424b715fce4e 100644 --- a/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php +++ b/src/Symfony/Component/Intl/Tests/NumberFormatter/AbstractNumberFormatterTest.php @@ -656,7 +656,7 @@ public function testParseTypeInt32($value, $expected, $message = '') { $formatter = $this->getNumberFormatter('en', NumberFormatter::DECIMAL); $parsedValue = $formatter->parse($value, NumberFormatter::TYPE_INT32); - $this->assertSame($expected, $parsedValue); + $this->assertSame($expected, $parsedValue, $message); } public function parseTypeInt32Provider() diff --git a/src/Symfony/Component/Intl/Util/IntlTestHelper.php b/src/Symfony/Component/Intl/Util/IntlTestHelper.php index cefb8db9919e6..ecd5ed6b660d6 100644 --- a/src/Symfony/Component/Intl/Util/IntlTestHelper.php +++ b/src/Symfony/Component/Intl/Util/IntlTestHelper.php @@ -31,7 +31,7 @@ class IntlTestHelper * * @param \PhpUnit_Framework_TestCase $testCase */ - public static function requireIntl(\PhpUnit_Framework_TestCase $testCase) + public static function requireIntl(\PHPUnit_Framework_TestCase $testCase) { // We only run tests if the version is *one specific version*. // This condition is satisfied if @@ -63,7 +63,7 @@ public static function requireIntl(\PhpUnit_Framework_TestCase $testCase) * * @param \PhpUnit_Framework_TestCase $testCase */ - public static function requireFullIntl(\PhpUnit_Framework_TestCase $testCase) + public static function requireFullIntl(\PHPUnit_Framework_TestCase $testCase) { // We only run tests if the intl extension is loaded... if (!Intl::isExtensionLoaded()) { @@ -92,7 +92,7 @@ public static function requireFullIntl(\PhpUnit_Framework_TestCase $testCase) * * @param \PhpUnit_Framework_TestCase $testCase */ - public static function require32Bit(\PhpUnit_Framework_TestCase $testCase) + public static function require32Bit(\PHPUnit_Framework_TestCase $testCase) { if (4 !== PHP_INT_SIZE) { $testCase->markTestSkipped('PHP 32 bit is required.'); @@ -104,7 +104,7 @@ public static function require32Bit(\PhpUnit_Framework_TestCase $testCase) * * @param \PhpUnit_Framework_TestCase $testCase */ - public static function require64Bit(\PhpUnit_Framework_TestCase $testCase) + public static function require64Bit(\PHPUnit_Framework_TestCase $testCase) { if (8 !== PHP_INT_SIZE) { $testCase->markTestSkipped('PHP 64 bit is required.'); diff --git a/src/Symfony/Component/Process/Pipes/WindowsPipes.php b/src/Symfony/Component/Process/Pipes/WindowsPipes.php index 071dd0334a74f..db66c672a7dae 100644 --- a/src/Symfony/Component/Process/Pipes/WindowsPipes.php +++ b/src/Symfony/Component/Process/Pipes/WindowsPipes.php @@ -52,27 +52,30 @@ public function __construct($disableOutput, $input) Process::STDERR => Process::ERR, ); $tmpDir = sys_get_temp_dir(); - if (!@fopen($file = $tmpDir.'\\sf_proc_00.check', 'wb')) { - throw new RuntimeException('A temporary file could not be opened to write the process output to, verify that your TEMP environment variable is writable'); - } - @unlink($file); + $error = 'unknown reason'; + set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; }); for ($i = 0;; ++$i) { foreach ($pipes as $pipe => $name) { $file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name); - if (file_exists($file) && !@unlink($file)) { + if (file_exists($file) && !unlink($file)) { continue 2; } - $h = @fopen($file, 'xb'); + $h = fopen($file, 'xb'); + if (!$h && false === strpos($error, 'File exists')) { + restore_error_handler(); + throw new RuntimeException(sprintf('A temporary file could not be opened to write the process output: %s', $error)); + } if (!$h || !$this->fileHandles[$pipe] = fopen($file, 'rb')) { continue 2; } if (isset($this->files[$pipe])) { - @unlink($this->files[$pipe]); + unlink($this->files[$pipe]); } $this->files[$pipe] = $file; } break; } + restore_error_handler(); } parent::__construct($input); diff --git a/src/Symfony/Component/Process/Tests/ProcessTest.php b/src/Symfony/Component/Process/Tests/ProcessTest.php index f06b135e26821..0fcedccf8bf07 100644 --- a/src/Symfony/Component/Process/Tests/ProcessTest.php +++ b/src/Symfony/Component/Process/Tests/ProcessTest.php @@ -1229,7 +1229,7 @@ private function getProcess($commandline, $cwd = null, array $env = null, $input } catch (RuntimeException $e) { $this->assertSame('This PHP has been compiled with --enable-sigchild. You must use setEnhanceSigchildCompatibility() to use this method.', $e->getMessage()); if ($enhance) { - $process->setEnhanceSigChildCompatibility(true); + $process->setEnhanceSigchildCompatibility(true); } else { self::$notEnhancedSigchild = true; } diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorArrayAccessTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorArrayAccessTest.php index a253d4030f1ef..07f44f19d8a11 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorArrayAccessTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorArrayAccessTest.php @@ -81,6 +81,6 @@ public function testIsReadable($collection, $path) */ public function testIsWritable($collection, $path) { - $this->assertTrue($this->propertyAccessor->isWritable($collection, $path, 'Updated')); + $this->assertTrue($this->propertyAccessor->isWritable($collection, $path)); } } diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorCollectionTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorCollectionTest.php index 17518468ebad8..ad87687bc0561 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorCollectionTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorCollectionTest.php @@ -166,33 +166,25 @@ public function testSetValueFailsIfNoAdderNorRemoverFound() public function testIsWritableReturnsTrueIfAdderAndRemoverExists() { $car = $this->getMock(__CLASS__.'_Car'); - $axes = $this->getContainer(array(1 => 'first', 2 => 'second', 3 => 'third')); - - $this->assertTrue($this->propertyAccessor->isWritable($car, 'axes', $axes)); + $this->assertTrue($this->propertyAccessor->isWritable($car, 'axes')); } public function testIsWritableReturnsFalseIfOnlyAdderExists() { $car = $this->getMock(__CLASS__.'_CarOnlyAdder'); - $axes = $this->getContainer(array(1 => 'first', 2 => 'second', 3 => 'third')); - - $this->assertFalse($this->propertyAccessor->isWritable($car, 'axes', $axes)); + $this->assertFalse($this->propertyAccessor->isWritable($car, 'axes')); } public function testIsWritableReturnsFalseIfOnlyRemoverExists() { $car = $this->getMock(__CLASS__.'_CarOnlyRemover'); - $axes = $this->getContainer(array(1 => 'first', 2 => 'second', 3 => 'third')); - - $this->assertFalse($this->propertyAccessor->isWritable($car, 'axes', $axes)); + $this->assertFalse($this->propertyAccessor->isWritable($car, 'axes')); } public function testIsWritableReturnsFalseIfNoAdderNorRemoverExists() { $car = $this->getMock(__CLASS__.'_CarNoAdderAndRemover'); - $axes = $this->getContainer(array(1 => 'first', 2 => 'second', 3 => 'third')); - - $this->assertFalse($this->propertyAccessor->isWritable($car, 'axes', $axes)); + $this->assertFalse($this->propertyAccessor->isWritable($car, 'axes')); } /** diff --git a/src/Symfony/Component/Security/Core/Tests/Validator/Constraints/LegacyUserPasswordValidatorTest.php b/src/Symfony/Component/Security/Core/Tests/Validator/Constraints/LegacyUserPasswordValidatorTest.php index 8053732beecad..f7da8c0bf672b 100644 --- a/src/Symfony/Component/Security/Core/Tests/Validator/Constraints/LegacyUserPasswordValidatorTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Validator/Constraints/LegacyUserPasswordValidatorTest.php @@ -14,8 +14,6 @@ use Symfony\Component\Validator\Validation; /** - * @since 2.5.4 - * * @author Bernhard Schussek * @group legacy */ diff --git a/src/Symfony/Component/Security/Csrf/CsrfTokenManagerInterface.php b/src/Symfony/Component/Security/Csrf/CsrfTokenManagerInterface.php index bccabe6c9c0f1..5936b6440e4d0 100644 --- a/src/Symfony/Component/Security/Csrf/CsrfTokenManagerInterface.php +++ b/src/Symfony/Component/Security/Csrf/CsrfTokenManagerInterface.php @@ -14,8 +14,6 @@ /** * Manages CSRF tokens. * - * @since 2.4 - * * @author Bernhard Schussek */ interface CsrfTokenManagerInterface diff --git a/src/Symfony/Component/Security/Csrf/TokenGenerator/TokenGeneratorInterface.php b/src/Symfony/Component/Security/Csrf/TokenGenerator/TokenGeneratorInterface.php index 1405b84f03322..0ec2881774b93 100644 --- a/src/Symfony/Component/Security/Csrf/TokenGenerator/TokenGeneratorInterface.php +++ b/src/Symfony/Component/Security/Csrf/TokenGenerator/TokenGeneratorInterface.php @@ -14,8 +14,6 @@ /** * Generates CSRF tokens. * - * @since 2.4 - * * @author Bernhard Schussek */ interface TokenGeneratorInterface diff --git a/src/Symfony/Component/Security/Csrf/TokenGenerator/UriSafeTokenGenerator.php b/src/Symfony/Component/Security/Csrf/TokenGenerator/UriSafeTokenGenerator.php index fa5a72245f254..432adf265fbfe 100644 --- a/src/Symfony/Component/Security/Csrf/TokenGenerator/UriSafeTokenGenerator.php +++ b/src/Symfony/Component/Security/Csrf/TokenGenerator/UriSafeTokenGenerator.php @@ -16,8 +16,6 @@ /** * Generates CSRF tokens. * - * @since 2.4 - * * @author Bernhard Schussek */ class UriSafeTokenGenerator implements TokenGeneratorInterface diff --git a/src/Symfony/Component/Security/Csrf/TokenStorage/NativeSessionTokenStorage.php b/src/Symfony/Component/Security/Csrf/TokenStorage/NativeSessionTokenStorage.php index 2620156f369a6..71151fa831813 100644 --- a/src/Symfony/Component/Security/Csrf/TokenStorage/NativeSessionTokenStorage.php +++ b/src/Symfony/Component/Security/Csrf/TokenStorage/NativeSessionTokenStorage.php @@ -16,8 +16,6 @@ /** * Token storage that uses PHP's native session handling. * - * @since 2.4 - * * @author Bernhard Schussek */ class NativeSessionTokenStorage implements TokenStorageInterface diff --git a/src/Symfony/Component/Security/Csrf/TokenStorage/SessionTokenStorage.php b/src/Symfony/Component/Security/Csrf/TokenStorage/SessionTokenStorage.php index a6a6ea389426e..37b33e6f2161b 100644 --- a/src/Symfony/Component/Security/Csrf/TokenStorage/SessionTokenStorage.php +++ b/src/Symfony/Component/Security/Csrf/TokenStorage/SessionTokenStorage.php @@ -15,9 +15,7 @@ use Symfony\Component\Security\Csrf\Exception\TokenNotFoundException; /** - * Token storage that uses a Symfony2 Session object. - * - * @since 2.4 + * Token storage that uses a Symfony Session object. * * @author Bernhard Schussek */ diff --git a/src/Symfony/Component/Security/Csrf/TokenStorage/TokenStorageInterface.php b/src/Symfony/Component/Security/Csrf/TokenStorage/TokenStorageInterface.php index 5efe72f694d4b..92386fbbda34f 100644 --- a/src/Symfony/Component/Security/Csrf/TokenStorage/TokenStorageInterface.php +++ b/src/Symfony/Component/Security/Csrf/TokenStorage/TokenStorageInterface.php @@ -14,8 +14,6 @@ /** * Stores CSRF tokens. * - * @since 2.4 - * * @author Bernhard Schussek */ interface TokenStorageInterface diff --git a/src/Symfony/Component/Security/Guard/Authenticator/AbstractFormLoginAuthenticator.php b/src/Symfony/Component/Security/Guard/Authenticator/AbstractFormLoginAuthenticator.php index b3c6bd73a0a9b..6d6d14edb5d1d 100644 --- a/src/Symfony/Component/Security/Guard/Authenticator/AbstractFormLoginAuthenticator.php +++ b/src/Symfony/Component/Security/Guard/Authenticator/AbstractFormLoginAuthenticator.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Security\Guard\Authenticator; +use Symfony\Component\HttpFoundation\Session\SessionInterface; use Symfony\Component\Security\Guard\AbstractGuardAuthenticator; use Symfony\Component\HttpFoundation\RedirectResponse; use Symfony\Component\HttpFoundation\Request; @@ -52,7 +53,10 @@ abstract protected function getDefaultSuccessRedirectUrl(); */ public function onAuthenticationFailure(Request $request, AuthenticationException $exception) { - $request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception); + if ($request->getSession() instanceof SessionInterface) { + $request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception); + } + $url = $this->getLoginUrl(); return new RedirectResponse($url); @@ -69,9 +73,13 @@ public function onAuthenticationFailure(Request $request, AuthenticationExceptio */ public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) { + $targetPath = null; + // if the user hit a secure page and start() was called, this was // the URL they were on, and probably where you want to redirect to - $targetPath = $request->getSession()->get('_security.'.$providerKey.'.target_path'); + if ($request->getSession() instanceof SessionInterface) { + $targetPath = $request->getSession()->get('_security.'.$providerKey.'.target_path'); + } if (!$targetPath) { $targetPath = $this->getDefaultSuccessRedirectUrl(); diff --git a/src/Symfony/Component/Security/Guard/Tests/Authenticator/FormLoginAuthenticatorTest.php b/src/Symfony/Component/Security/Guard/Tests/Authenticator/FormLoginAuthenticatorTest.php new file mode 100644 index 0000000000000..3dbbf845c5226 --- /dev/null +++ b/src/Symfony/Component/Security/Guard/Tests/Authenticator/FormLoginAuthenticatorTest.php @@ -0,0 +1,212 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Security\Guard\Tests\Authenticator; + +use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Core\User\UserInterface; +use Symfony\Component\Security\Core\User\UserProviderInterface; +use Symfony\Component\Security\Guard\Authenticator\AbstractFormLoginAuthenticator; + +/** + * @author Jean Pasdeloup + */ +class FormLoginAuthenticatorTest extends \PHPUnit_Framework_TestCase +{ + private $requestWithoutSession; + private $requestWithSession; + private $authenticator; + + const LOGIN_URL = 'http://login'; + const DEFAULT_SUCCESS_URL = 'http://defaultsuccess'; + const CUSTOM_SUCCESS_URL = 'http://customsuccess'; + + public function testAuthenticationFailureWithoutSession() + { + $failureResponse = $this->authenticator->onAuthenticationFailure($this->requestWithoutSession, new AuthenticationException()); + + $this->assertInstanceOf('Symfony\\Component\\HttpFoundation\\RedirectResponse', $failureResponse); + $this->assertEquals(self::LOGIN_URL, $failureResponse->getTargetUrl()); + } + + public function testAuthenticationFailureWithSession() + { + $this->requestWithSession->getSession() + ->expects($this->once()) + ->method('set'); + + $failureResponse = $this->authenticator->onAuthenticationFailure($this->requestWithSession, new AuthenticationException()); + + $this->assertInstanceOf('Symfony\\Component\\HttpFoundation\\RedirectResponse', $failureResponse); + $this->assertEquals(self::LOGIN_URL, $failureResponse->getTargetUrl()); + } + + public function testAuthenticationSuccessWithoutSession() + { + $token = $this->getMockBuilder('Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface') + ->disableOriginalConstructor() + ->getMock(); + + $redirectResponse = $this->authenticator->onAuthenticationSuccess($this->requestWithoutSession, $token, 'providerkey'); + + $this->assertInstanceOf('Symfony\\Component\\HttpFoundation\\RedirectResponse', $redirectResponse); + $this->assertEquals(self::DEFAULT_SUCCESS_URL, $redirectResponse->getTargetUrl()); + } + + public function testAuthenticationSuccessWithSessionButEmpty() + { + $token = $this->getMockBuilder('Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->requestWithSession->getSession() + ->expects($this->once()) + ->method('get') + ->will($this->returnValue(null)); + + $redirectResponse = $this->authenticator->onAuthenticationSuccess($this->requestWithSession, $token, 'providerkey'); + + $this->assertInstanceOf('Symfony\\Component\\HttpFoundation\\RedirectResponse', $redirectResponse); + $this->assertEquals(self::DEFAULT_SUCCESS_URL, $redirectResponse->getTargetUrl()); + } + + public function testAuthenticationSuccessWithSessionAndTarget() + { + $token = $this->getMockBuilder('Symfony\\Component\\Security\\Core\\Authentication\\Token\\TokenInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->requestWithSession->getSession() + ->expects($this->once()) + ->method('get') + ->will($this->returnValue(self::CUSTOM_SUCCESS_URL)); + + $redirectResponse = $this->authenticator->onAuthenticationSuccess($this->requestWithSession, $token, 'providerkey'); + + $this->assertInstanceOf('Symfony\\Component\\HttpFoundation\\RedirectResponse', $redirectResponse); + $this->assertEquals(self::CUSTOM_SUCCESS_URL, $redirectResponse->getTargetUrl()); + } + + public function testRememberMe() + { + $doSupport = $this->authenticator->supportsRememberMe(); + + $this->assertTrue($doSupport); + } + + public function testStartWithoutSession() + { + $failureResponse = $this->authenticator->start($this->requestWithoutSession, new AuthenticationException()); + + $this->assertInstanceOf('Symfony\\Component\\HttpFoundation\\RedirectResponse', $failureResponse); + $this->assertEquals(self::LOGIN_URL, $failureResponse->getTargetUrl()); + } + + public function testStartWithSession() + { + $failureResponse = $this->authenticator->start($this->requestWithSession, new AuthenticationException()); + + $this->assertInstanceOf('Symfony\\Component\\HttpFoundation\\RedirectResponse', $failureResponse); + $this->assertEquals(self::LOGIN_URL, $failureResponse->getTargetUrl()); + } + + protected function setUp() + { + $this->requestWithoutSession = new Request(array(), array(), array(), array(), array(), array()); + $this->requestWithSession = new Request(array(), array(), array(), array(), array(), array()); + + $session = $this->getMockBuilder('Symfony\\Component\\HttpFoundation\\Session\\SessionInterface') + ->disableOriginalConstructor() + ->getMock(); + $this->requestWithSession->setSession($session); + + $this->authenticator = new TestFormLoginAuthenticator(); + $this->authenticator + ->setLoginUrl(self::LOGIN_URL) + ->setDefaultSuccessRedirectUrl(self::DEFAULT_SUCCESS_URL) + ; + } + + protected function tearDown() + { + $this->request = null; + $this->requestWithSession = null; + } +} + +class TestFormLoginAuthenticator extends AbstractFormLoginAuthenticator +{ + private $loginUrl; + private $defaultSuccessRedirectUrl; + + /** + * @param mixed $defaultSuccessRedirectUrl + * + * @return TestFormLoginAuthenticator + */ + public function setDefaultSuccessRedirectUrl($defaultSuccessRedirectUrl) + { + $this->defaultSuccessRedirectUrl = $defaultSuccessRedirectUrl; + + return $this; + } + + /** + * @param mixed $loginUrl + * + * @return TestFormLoginAuthenticator + */ + public function setLoginUrl($loginUrl) + { + $this->loginUrl = $loginUrl; + + return $this; + } + + /** + * {@inheritdoc} + */ + protected function getLoginUrl() + { + return $this->loginUrl; + } + + /** + * {@inheritdoc} + */ + protected function getDefaultSuccessRedirectUrl() + { + return $this->defaultSuccessRedirectUrl; + } + + /** + * {@inheritdoc} + */ + public function getCredentials(Request $request) + { + return 'credentials'; + } + + /** + * {@inheritdoc} + */ + public function getUser($credentials, UserProviderInterface $userProvider) + { + return $userProvider->loadUserByUsername($credentials); + } + + /** + * {@inheritdoc} + */ + public function checkCredentials($credentials, UserInterface $user) + { + return true; + } +} diff --git a/src/Symfony/Component/Security/Http/Authentication/AuthenticationUtils.php b/src/Symfony/Component/Security/Http/Authentication/AuthenticationUtils.php index 4d5c71aa5c485..c6397e8ca1e3b 100644 --- a/src/Symfony/Component/Security/Http/Authentication/AuthenticationUtils.php +++ b/src/Symfony/Component/Security/Http/Authentication/AuthenticationUtils.php @@ -65,7 +65,13 @@ public function getLastAuthenticationError($clearSession = true) */ public function getLastUsername() { - $session = $this->getRequest()->getSession(); + $request = $this->getRequest(); + + if ($request->attributes->has(Security::LAST_USERNAME)) { + return $request->attributes->get(Security::LAST_USERNAME); + } + + $session = $request->getSession(); return null === $session ? '' : $session->get(Security::LAST_USERNAME); } diff --git a/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php b/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php index d8d71fbdd1943..71bdf6ca3899a 100644 --- a/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/DigestAuthenticationListener.php @@ -78,7 +78,7 @@ public function handle(GetResponseEvent $event) } try { - $digestAuth->validateAndDecode($this->authenticationEntryPoint->getKey(), $this->authenticationEntryPoint->getRealmName()); + $digestAuth->validateAndDecode($this->authenticationEntryPoint->getSecret(), $this->authenticationEntryPoint->getRealmName()); } catch (BadCredentialsException $e) { $this->fail($event, $request, $e); diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/DigestAuthenticationListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/DigestAuthenticationListenerTest.php new file mode 100644 index 0000000000000..80b2dc41343a8 --- /dev/null +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/DigestAuthenticationListenerTest.php @@ -0,0 +1,79 @@ +calculateServerDigest($username, $realm, $password, $nc, $nonce, $cnonce, $qop, 'GET', $uri); + + $digestData = + 'username="'.$username.'", realm="'.$realm.'", nonce="'.$nonce.'", '. + 'uri="'.$uri.'", cnonce="'.$cnonce.'", nc='.$nc.', qop="'.$qop.'", '. + 'response="'.$serverDigest.'"' + ; + + $request = new Request(array(), array(), array(), array(), array(), array('PHP_AUTH_DIGEST' => $digestData)); + + $entryPoint = new DigestAuthenticationEntryPoint($realm, $secret); + + $user = $this->getMock('Symfony\Component\Security\Core\User\UserInterface'); + $user->method('getPassword')->willReturn($password); + + $providerKey = 'TheProviderKey'; + + $tokenStorage = $this->getMock('Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface'); + $tokenStorage + ->expects($this->once()) + ->method('getToken') + ->will($this->returnValue(null)) + ; + $tokenStorage + ->expects($this->once()) + ->method('setToken') + ->with($this->equalTo(new UsernamePasswordToken($user, $password, $providerKey))) + ; + + $userProvider = $this->getMock('Symfony\Component\Security\Core\User\UserProviderInterface'); + $userProvider->method('loadUserByUsername')->willReturn($user); + + $listener = new DigestAuthenticationListener($tokenStorage, $userProvider, $providerKey, $entryPoint); + + $event = $this->getMock('Symfony\Component\HttpKernel\Event\GetResponseEvent', array(), array(), '', false); + $event + ->expects($this->any()) + ->method('getRequest') + ->will($this->returnValue($request)) + ; + + $listener->handle($event); + } + + private function calculateServerDigest($username, $realm, $password, $nc, $nonce, $cnonce, $qop, $method, $uri) + { + $response = md5( + md5($username.':'.$realm.':'.$password).':'.$nonce.':'.$nc.':'.$cnonce.':'.$qop.':'.md5($method.':'.$uri) + ); + + return sprintf('username="%s", realm="%s", nonce="%s", uri="%s", cnonce="%s", nc=%s, qop="%s", response="%s"', + $username, $realm, $nonce, $uri, $cnonce, $nc, $qop, $response + ); + } +} diff --git a/src/Symfony/Component/Templating/Tests/DelegatingEngineTest.php b/src/Symfony/Component/Templating/Tests/DelegatingEngineTest.php index 368723c884a57..e9cb5fc472066 100644 --- a/src/Symfony/Component/Templating/Tests/DelegatingEngineTest.php +++ b/src/Symfony/Component/Templating/Tests/DelegatingEngineTest.php @@ -121,7 +121,7 @@ public function testGetInvalidEngine() $secondEngine = $this->getEngineMock('template.php', false); $delegatingEngine = new DelegatingEngine(array($firstEngine, $secondEngine)); - $delegatingEngine->getEngine('template.php', array('foo' => 'bar')); + $delegatingEngine->getEngine('template.php'); } private function getEngineMock($template, $supports) diff --git a/src/Symfony/Component/Translation/DataCollectorTranslator.php b/src/Symfony/Component/Translation/DataCollectorTranslator.php index d507cdea629b5..2446723358060 100644 --- a/src/Symfony/Component/Translation/DataCollectorTranslator.php +++ b/src/Symfony/Component/Translation/DataCollectorTranslator.php @@ -126,14 +126,14 @@ private function collectMessage($locale, $domain, $id, $translation, $parameters } elseif ($catalogue->has($id, $domain)) { $state = self::MESSAGE_EQUALS_FALLBACK; - $fallbackCatalogue = $catalogue->getFallBackCatalogue(); + $fallbackCatalogue = $catalogue->getFallbackCatalogue(); while ($fallbackCatalogue) { if ($fallbackCatalogue->defines($id, $domain)) { $locale = $fallbackCatalogue->getLocale(); break; } - $fallbackCatalogue = $fallbackCatalogue->getFallBackCatalogue(); + $fallbackCatalogue = $fallbackCatalogue->getFallbackCatalogue(); } } else { $state = self::MESSAGE_MISSING; diff --git a/src/Symfony/Component/Translation/Tests/PluralizationRulesTest.php b/src/Symfony/Component/Translation/Tests/PluralizationRulesTest.php index 8ce2c58defb9e..78bbc87eece40 100644 --- a/src/Symfony/Component/Translation/Tests/PluralizationRulesTest.php +++ b/src/Symfony/Component/Translation/Tests/PluralizationRulesTest.php @@ -37,7 +37,7 @@ class PluralizationRulesTest extends \PHPUnit_Framework_TestCase */ public function testFailedLangcodes($nplural, $langCodes) { - $matrix = $this->generateTestData($nplural, $langCodes); + $matrix = $this->generateTestData($langCodes); $this->validateMatrix($nplural, $matrix, false); } @@ -46,7 +46,7 @@ public function testFailedLangcodes($nplural, $langCodes) */ public function testLangcodes($nplural, $langCodes) { - $matrix = $this->generateTestData($nplural, $langCodes); + $matrix = $this->generateTestData($langCodes); $this->validateMatrix($nplural, $matrix); } @@ -108,7 +108,7 @@ protected function validateMatrix($nplural, $matrix, $expectSuccess = true) } } - protected function generateTestData($plural, $langCodes) + protected function generateTestData($langCodes) { $matrix = array(); foreach ($langCodes as $langCode) { diff --git a/src/Symfony/Component/Validator/Constraint.php b/src/Symfony/Component/Validator/Constraint.php index 61def982a836d..4d6ab3eaac1db 100644 --- a/src/Symfony/Component/Validator/Constraint.php +++ b/src/Symfony/Component/Validator/Constraint.php @@ -207,8 +207,6 @@ public function __set($option, $value) * @throws InvalidOptionsException If an invalid option name is given * * @internal This method should not be used or overwritten in userland code. - * - * @since 2.6 */ public function __get($option) { @@ -296,8 +294,6 @@ public function getTargets() * @internal This method may be replaced by an implementation of * {@link \Serializable} in the future. Please don't use or * overwrite it. - * - * @since 2.6 */ public function __sleep() { diff --git a/src/Symfony/Component/Validator/Constraints/AbstractComparisonValidator.php b/src/Symfony/Component/Validator/Constraints/AbstractComparisonValidator.php index ce0487403ba8a..ca0c3aa71d45f 100644 --- a/src/Symfony/Component/Validator/Constraints/AbstractComparisonValidator.php +++ b/src/Symfony/Component/Validator/Constraints/AbstractComparisonValidator.php @@ -44,7 +44,7 @@ public function validate($value, Constraint $constraint) // the DateTime constructor: // http://php.net/manual/en/datetime.formats.php if (is_string($comparedValue)) { - if ($value instanceof \DatetimeImmutable) { + if ($value instanceof \DateTimeImmutable) { // If $value is immutable, convert the compared value to a // DateTimeImmutable too $comparedValue = new \DatetimeImmutable($comparedValue); diff --git a/src/Symfony/Component/Validator/Constraints/Callback.php b/src/Symfony/Component/Validator/Constraints/Callback.php index 7e4ccd47b540c..36e6087e1e98e 100644 --- a/src/Symfony/Component/Validator/Constraints/Callback.php +++ b/src/Symfony/Component/Validator/Constraints/Callback.php @@ -23,8 +23,6 @@ class Callback extends Constraint { /** * @var string|callable - * - * @since 2.4 */ public $callback; diff --git a/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php b/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php index 229e0d2c18997..be54a0cf477bd 100644 --- a/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php +++ b/src/Symfony/Component/Validator/Constraints/CardSchemeValidator.php @@ -74,8 +74,10 @@ class CardSchemeValidator extends ConstraintValidator '/^6[0-9]{11,18}$/', ), // All MasterCard numbers start with the numbers 51 through 55. All have 16 digits. + // October 2016 MasterCard numbers can also start with 222100 through 272099. 'MASTERCARD' => array( '/^5[1-5][0-9]{14}$/', + '/^2(22[1-9][0-9]{12}|2[3-9][0-9]{13}|[3-6][0-9]{14}|7[0-1][0-9]{13}|720[0-9]{12})$/', ), // All Visa card numbers start with a 4. New cards have 16 digits. Old cards have 13. 'VISA' => array( diff --git a/src/Symfony/Component/Validator/Constraints/Composite.php b/src/Symfony/Component/Validator/Constraints/Composite.php index 90c98620f0055..ab8466bcfcbc4 100644 --- a/src/Symfony/Component/Validator/Constraints/Composite.php +++ b/src/Symfony/Component/Validator/Constraints/Composite.php @@ -24,8 +24,6 @@ * let {@link getCompositeOption()} return the name of the property which * contains the nested constraints. * - * @since 2.6 - * * @author Bernhard Schussek */ abstract class Composite extends Constraint diff --git a/src/Symfony/Component/Validator/Constraints/File.php b/src/Symfony/Component/Validator/Constraints/File.php index 24c7495fae5cb..341fbaf440775 100644 --- a/src/Symfony/Component/Validator/Constraints/File.php +++ b/src/Symfony/Component/Validator/Constraints/File.php @@ -88,20 +88,22 @@ public function __get($option) private function normalizeBinaryFormat($maxSize) { + $sizeInt = (int) $maxSize; + if (ctype_digit((string) $maxSize)) { - $this->maxSize = (int) $maxSize; + $this->maxSize = $sizeInt; $this->binaryFormat = null === $this->binaryFormat ? false : $this->binaryFormat; } elseif (preg_match('/^\d++k$/i', $maxSize)) { - $this->maxSize = $maxSize * 1000; + $this->maxSize = $sizeInt * 1000; $this->binaryFormat = null === $this->binaryFormat ? false : $this->binaryFormat; } elseif (preg_match('/^\d++M$/i', $maxSize)) { - $this->maxSize = $maxSize * 1000000; + $this->maxSize = $sizeInt * 1000000; $this->binaryFormat = null === $this->binaryFormat ? false : $this->binaryFormat; } elseif (preg_match('/^\d++Ki$/i', $maxSize)) { - $this->maxSize = $maxSize << 10; + $this->maxSize = $sizeInt << 10; $this->binaryFormat = null === $this->binaryFormat ? true : $this->binaryFormat; } elseif (preg_match('/^\d++Mi$/i', $maxSize)) { - $this->maxSize = $maxSize << 20; + $this->maxSize = $sizeInt << 20; $this->binaryFormat = null === $this->binaryFormat ? true : $this->binaryFormat; } else { throw new ConstraintDefinitionException(sprintf('"%s" is not a valid maximum size', $this->maxSize)); diff --git a/src/Symfony/Component/Validator/Constraints/Traverse.php b/src/Symfony/Component/Validator/Constraints/Traverse.php index 5811ad770ad6f..9d8bc126d1888 100644 --- a/src/Symfony/Component/Validator/Constraints/Traverse.php +++ b/src/Symfony/Component/Validator/Constraints/Traverse.php @@ -17,8 +17,6 @@ /** * @Annotation * - * @since 2.5 - * * @author Bernhard Schussek */ class Traverse extends Constraint diff --git a/src/Symfony/Component/Validator/Constraints/UuidValidator.php b/src/Symfony/Component/Validator/Constraints/UuidValidator.php index 08f9e27b736c8..02ec0b23f59f5 100644 --- a/src/Symfony/Component/Validator/Constraints/UuidValidator.php +++ b/src/Symfony/Component/Validator/Constraints/UuidValidator.php @@ -81,6 +81,10 @@ public function validate($value, Constraint $constraint) return; } + if (!$constraint instanceof Uuid) { + throw new UnexpectedTypeException($constraint, __NAMESPACE__.'\Uuid'); + } + if (!is_scalar($value) && !(is_object($value) && method_exists($value, '__toString'))) { throw new UnexpectedTypeException($value, 'string'); } @@ -232,20 +236,14 @@ private function validateStrict($value, Uuid $constraint) if ($i !== $h) { if ($this->context instanceof ExecutionContextInterface) { $this->context->buildViolation($constraint->message) - ->setParameter( - '{{ value }}', - $this->formatValue($value) - ) - ->setCode(Uuid::INVALID_HYPHEN_PLACEMENT_ERROR) - ->addViolation(); + ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Uuid::INVALID_HYPHEN_PLACEMENT_ERROR) + ->addViolation(); } else { $this->buildViolation($constraint->message) - ->setParameter( - '{{ value }}', - $this->formatValue($value) - ) - ->setCode(Uuid::INVALID_HYPHEN_PLACEMENT_ERROR) - ->addViolation(); + ->setParameter('{{ value }}', $this->formatValue($value)) + ->setCode(Uuid::INVALID_HYPHEN_PLACEMENT_ERROR) + ->addViolation(); } return; diff --git a/src/Symfony/Component/Validator/Context/ExecutionContext.php b/src/Symfony/Component/Validator/Context/ExecutionContext.php index 722bcc947d2f4..dce975c2038e6 100644 --- a/src/Symfony/Component/Validator/Context/ExecutionContext.php +++ b/src/Symfony/Component/Validator/Context/ExecutionContext.php @@ -27,8 +27,6 @@ /** * The context used and created by {@link ExecutionContextFactory}. * - * @since 2.5 - * * @author Bernhard Schussek * * @see ExecutionContextInterface diff --git a/src/Symfony/Component/Validator/Context/ExecutionContextFactory.php b/src/Symfony/Component/Validator/Context/ExecutionContextFactory.php index f4f01d926e0f7..8182c41f8c1ca 100644 --- a/src/Symfony/Component/Validator/Context/ExecutionContextFactory.php +++ b/src/Symfony/Component/Validator/Context/ExecutionContextFactory.php @@ -17,8 +17,6 @@ /** * Creates new {@link ExecutionContext} instances. * - * @since 2.5 - * * @author Bernhard Schussek * * @internal You should not instantiate or use this class. Code against diff --git a/src/Symfony/Component/Validator/Context/ExecutionContextFactoryInterface.php b/src/Symfony/Component/Validator/Context/ExecutionContextFactoryInterface.php index e4af667d2da6a..f3ab3dd68a740 100644 --- a/src/Symfony/Component/Validator/Context/ExecutionContextFactoryInterface.php +++ b/src/Symfony/Component/Validator/Context/ExecutionContextFactoryInterface.php @@ -19,8 +19,6 @@ * You can use a custom factory if you want to customize the execution context * that is passed through the validation run. * - * @since 2.5 - * * @author Bernhard Schussek */ interface ExecutionContextFactoryInterface diff --git a/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php b/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php index 9c28bde9ea631..d38d33747a752 100644 --- a/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php +++ b/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php @@ -56,8 +56,6 @@ * cannot store a context and expect that the methods still return the same * results later on. * - * @since 2.5 - * * @author Bernhard Schussek */ interface ExecutionContextInterface extends LegacyExecutionContextInterface diff --git a/src/Symfony/Component/Validator/Context/LegacyExecutionContext.php b/src/Symfony/Component/Validator/Context/LegacyExecutionContext.php index f52b359fb39ca..37ca2a1d102b3 100644 --- a/src/Symfony/Component/Validator/Context/LegacyExecutionContext.php +++ b/src/Symfony/Component/Validator/Context/LegacyExecutionContext.php @@ -20,8 +20,6 @@ /** * An execution context that is compatible with the legacy API (< 2.5). * - * @since 2.5 - * * @author Bernhard Schussek * * @deprecated since version 2.5, to be removed in 3.0. diff --git a/src/Symfony/Component/Validator/Context/LegacyExecutionContextFactory.php b/src/Symfony/Component/Validator/Context/LegacyExecutionContextFactory.php index c110644e99c1b..757eb72a5bda2 100644 --- a/src/Symfony/Component/Validator/Context/LegacyExecutionContextFactory.php +++ b/src/Symfony/Component/Validator/Context/LegacyExecutionContextFactory.php @@ -22,8 +22,6 @@ * * Implemented for backward compatibility with Symfony < 2.5. * - * @since 2.5 - * * @author Bernhard Schussek * * @deprecated since version 2.5, to be removed in 3.0. diff --git a/src/Symfony/Component/Validator/Exception/UnsupportedMetadataException.php b/src/Symfony/Component/Validator/Exception/UnsupportedMetadataException.php index 97cc5ffe5d92a..aff569b957502 100644 --- a/src/Symfony/Component/Validator/Exception/UnsupportedMetadataException.php +++ b/src/Symfony/Component/Validator/Exception/UnsupportedMetadataException.php @@ -12,8 +12,6 @@ namespace Symfony\Component\Validator\Exception; /** - * @since 2.5 - * * @author Bernhard Schussek */ class UnsupportedMetadataException extends InvalidArgumentException diff --git a/src/Symfony/Component/Validator/Mapping/CascadingStrategy.php b/src/Symfony/Component/Validator/Mapping/CascadingStrategy.php index 2b97bdd4ca90a..c78fb42ad46cb 100644 --- a/src/Symfony/Component/Validator/Mapping/CascadingStrategy.php +++ b/src/Symfony/Component/Validator/Mapping/CascadingStrategy.php @@ -27,8 +27,6 @@ * Although the constants currently represent a boolean switch, they are * implemented as bit mask in order to allow future extensions. * - * @since 2.5 - * * @author Bernhard Schussek * * @see TraversalStrategy diff --git a/src/Symfony/Component/Validator/Mapping/ClassMetadataInterface.php b/src/Symfony/Component/Validator/Mapping/ClassMetadataInterface.php index 577440d61d8c7..d8c3d843bd4c1 100644 --- a/src/Symfony/Component/Validator/Mapping/ClassMetadataInterface.php +++ b/src/Symfony/Component/Validator/Mapping/ClassMetadataInterface.php @@ -24,8 +24,6 @@ * by a group sequence for that class and whether instances of that class * should be traversed or not. * - * @since 2.5 - * * @author Bernhard Schussek * * @see MetadataInterface diff --git a/src/Symfony/Component/Validator/Mapping/Factory/MetadataFactoryInterface.php b/src/Symfony/Component/Validator/Mapping/Factory/MetadataFactoryInterface.php index 6e55e771dd1aa..438ef9871c25f 100644 --- a/src/Symfony/Component/Validator/Mapping/Factory/MetadataFactoryInterface.php +++ b/src/Symfony/Component/Validator/Mapping/Factory/MetadataFactoryInterface.php @@ -16,8 +16,6 @@ /** * Returns {@link \Symfony\Component\Validator\Mapping\MetadataInterface} instances for values. * - * @since 2.5 - * * @author Bernhard Schussek */ interface MetadataFactoryInterface extends LegacyMetadataFactoryInterface diff --git a/src/Symfony/Component/Validator/Mapping/GenericMetadata.php b/src/Symfony/Component/Validator/Mapping/GenericMetadata.php index 3459074fcabf7..458ad34fca6cd 100644 --- a/src/Symfony/Component/Validator/Mapping/GenericMetadata.php +++ b/src/Symfony/Component/Validator/Mapping/GenericMetadata.php @@ -23,8 +23,6 @@ * * This class supports serialization and cloning. * - * @since 2.5 - * * @author Bernhard Schussek */ class GenericMetadata implements MetadataInterface diff --git a/src/Symfony/Component/Validator/Mapping/MetadataInterface.php b/src/Symfony/Component/Validator/Mapping/MetadataInterface.php index e5f09e17edc82..1e9d3c8929bf7 100644 --- a/src/Symfony/Component/Validator/Mapping/MetadataInterface.php +++ b/src/Symfony/Component/Validator/Mapping/MetadataInterface.php @@ -24,8 +24,6 @@ * against their class' metadata and whether traversable objects should be * traversed or not. * - * @since 2.5 - * * @author Bernhard Schussek * * @see CascadingStrategy diff --git a/src/Symfony/Component/Validator/Mapping/PropertyMetadata.php b/src/Symfony/Component/Validator/Mapping/PropertyMetadata.php index 9a2a4aac1428b..ac71be828541d 100644 --- a/src/Symfony/Component/Validator/Mapping/PropertyMetadata.php +++ b/src/Symfony/Component/Validator/Mapping/PropertyMetadata.php @@ -39,7 +39,7 @@ class PropertyMetadata extends MemberMetadata public function __construct($class, $name) { if (!property_exists($class, $name)) { - throw new ValidatorException(sprintf('Property %s does not exist in class %s', $name, $class)); + throw new ValidatorException(sprintf('Property "%s" does not exist in class "%s"', $name, $class)); } parent::__construct($class, $name, $name); diff --git a/src/Symfony/Component/Validator/Mapping/PropertyMetadataInterface.php b/src/Symfony/Component/Validator/Mapping/PropertyMetadataInterface.php index 8a77aa83faba5..d7a4114d44f14 100644 --- a/src/Symfony/Component/Validator/Mapping/PropertyMetadataInterface.php +++ b/src/Symfony/Component/Validator/Mapping/PropertyMetadataInterface.php @@ -24,8 +24,6 @@ * should be validated against their class' metadata and whether traversable * objects should be traversed or not. * - * @since 2.5 - * * @author Bernhard Schussek * * @see MetadataInterface diff --git a/src/Symfony/Component/Validator/Mapping/TraversalStrategy.php b/src/Symfony/Component/Validator/Mapping/TraversalStrategy.php index ae76857aa443f..164992b2eab4f 100644 --- a/src/Symfony/Component/Validator/Mapping/TraversalStrategy.php +++ b/src/Symfony/Component/Validator/Mapping/TraversalStrategy.php @@ -23,8 +23,6 @@ * * The traversal strategy is ignored for arrays. Arrays are always iterated. * - * @since 2.1 - * * @author Bernhard Schussek * * @see CascadingStrategy diff --git a/src/Symfony/Component/Validator/Tests/Constraints/AbstractConstraintValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/AbstractConstraintValidatorTest.php index 5a5fa51a0af48..9d292fbc7bd84 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/AbstractConstraintValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/AbstractConstraintValidatorTest.php @@ -24,8 +24,6 @@ use Symfony\Component\Validator\Validation; /** - * @since 2.5.3 - * * @author Bernhard Schussek */ abstract class AbstractConstraintValidatorTest extends \PHPUnit_Framework_TestCase diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php index 162563e09574c..dbe5166451a15 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CardSchemeValidatorTest.php @@ -102,6 +102,12 @@ public function getValidNumbers() array('MAESTRO', '6594371785970435599'), array('MASTERCARD', '5555555555554444'), array('MASTERCARD', '5105105105105100'), + array('MASTERCARD', '2221005555554444'), + array('MASTERCARD', '2230000000000000'), + array('MASTERCARD', '2300000000000000'), + array('MASTERCARD', '2699999999999999'), + array('MASTERCARD', '2709999999999999'), + array('MASTERCARD', '2720995105105100'), array('VISA', '4111111111111111'), array('VISA', '4012888888881881'), array('VISA', '4222222222222'), @@ -129,6 +135,8 @@ public function getInvalidNumbers() array('AMEX', '000000000000', CardScheme::INVALID_FORMAT_ERROR), // a lone number array('DINERS', '3056930', CardScheme::INVALID_FORMAT_ERROR), // only first part of the number array('DISCOVER', '1117', CardScheme::INVALID_FORMAT_ERROR), // only last 4 digits + array('MASTERCARD', '2721001234567890', CardScheme::INVALID_FORMAT_ERROR), // Not assigned yet + array('MASTERCARD', '2220991234567890', CardScheme::INVALID_FORMAT_ERROR), // Not assigned yet ); } } diff --git a/src/Symfony/Component/Validator/Tests/Constraints/CompositeTest.php b/src/Symfony/Component/Validator/Tests/Constraints/CompositeTest.php index eab15ed3bb848..002b1336aab3f 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/CompositeTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/CompositeTest.php @@ -32,8 +32,6 @@ public function getDefaultOption() } /** - * @since 2.6 - * * @author Bernhard Schussek */ class CompositeTest extends \PHPUnit_Framework_TestCase diff --git a/src/Symfony/Component/Validator/Tests/Constraints/UuidValidatorTest.php b/src/Symfony/Component/Validator/Tests/Constraints/UuidValidatorTest.php index 0abda39f02942..05a60684c2589 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/UuidValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/UuidValidatorTest.php @@ -44,6 +44,16 @@ public function testEmptyStringIsValid() $this->assertNoViolation(); } + /** + * @expectedException \Symfony\Component\Validator\Exception\UnexpectedTypeException + */ + public function testExpectsUuidConstraintCompatibleType() + { + $constraint = $this->getMockForAbstractClass('Symfony\\Component\\Validator\\Constraint'); + + $this->validator->validate('216fff40-98d9-11e3-a5e2-0800200c9a66', $constraint); + } + /** * @expectedException \Symfony\Component\Validator\Exception\UnexpectedTypeException */ diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/StubGlobalExecutionContext.php b/src/Symfony/Component/Validator/Tests/Fixtures/StubGlobalExecutionContext.php index 84c5a80bf2d16..bd2f5c94e7a96 100644 --- a/src/Symfony/Component/Validator/Tests/Fixtures/StubGlobalExecutionContext.php +++ b/src/Symfony/Component/Validator/Tests/Fixtures/StubGlobalExecutionContext.php @@ -16,8 +16,6 @@ use Symfony\Component\Validator\ValidationVisitorInterface; /** - * @since 2.5.3 - * * @author Bernhard Schussek * * @deprecated since version 2.5, to be removed in 3.0 diff --git a/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php b/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php index 6995d25817988..e85177ef59b24 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/Abstract2Dot5ApiTest.php @@ -29,8 +29,6 @@ /** * Verifies that a validator satisfies the API of Symfony 2.5+. * - * @since 2.5 - * * @author Bernhard Schussek */ abstract class Abstract2Dot5ApiTest extends AbstractValidatorTest diff --git a/src/Symfony/Component/Validator/Tests/Validator/AbstractLegacyApiTest.php b/src/Symfony/Component/Validator/Tests/Validator/AbstractLegacyApiTest.php index d78b67bee7e9a..cbbaecfcddcad 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/AbstractLegacyApiTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/AbstractLegacyApiTest.php @@ -23,8 +23,6 @@ /** * Verifies that a validator satisfies the API of Symfony < 2.5. * - * @since 2.5 - * * @author Bernhard Schussek * @group legacy */ diff --git a/src/Symfony/Component/Validator/Tests/Validator/AbstractValidatorTest.php b/src/Symfony/Component/Validator/Tests/Validator/AbstractValidatorTest.php index 678a3252a5a0b..7359348432b59 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/AbstractValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/AbstractValidatorTest.php @@ -23,8 +23,6 @@ use Symfony\Component\Validator\Tests\Fixtures\Reference; /** - * @since 2.5 - * * @author Bernhard Schussek */ abstract class AbstractValidatorTest extends \PHPUnit_Framework_TestCase diff --git a/src/Symfony/Component/Validator/Util/PropertyPath.php b/src/Symfony/Component/Validator/Util/PropertyPath.php index 3ef8a8b1dc5da..52546c5ea9df0 100644 --- a/src/Symfony/Component/Validator/Util/PropertyPath.php +++ b/src/Symfony/Component/Validator/Util/PropertyPath.php @@ -16,8 +16,6 @@ * * For more extensive functionality, use Symfony's PropertyAccess component. * - * @since 2.5 - * * @author Bernhard Schussek */ class PropertyPath diff --git a/src/Symfony/Component/Validator/Validator/ContextualValidatorInterface.php b/src/Symfony/Component/Validator/Validator/ContextualValidatorInterface.php index 048d6c7545f84..7d7ebe73b0814 100644 --- a/src/Symfony/Component/Validator/Validator/ContextualValidatorInterface.php +++ b/src/Symfony/Component/Validator/Validator/ContextualValidatorInterface.php @@ -17,8 +17,6 @@ /** * A validator in a specific execution context. * - * @since 2.5 - * * @author Bernhard Schussek */ interface ContextualValidatorInterface diff --git a/src/Symfony/Component/Validator/Validator/LegacyValidator.php b/src/Symfony/Component/Validator/Validator/LegacyValidator.php index e35f4c91401b3..588baa90135e0 100644 --- a/src/Symfony/Component/Validator/Validator/LegacyValidator.php +++ b/src/Symfony/Component/Validator/Validator/LegacyValidator.php @@ -16,8 +16,6 @@ /** * A validator that supports both the API of Symfony < 2.5 and Symfony 2.5+. * - * @since 2.5 - * * @author Bernhard Schussek * * @see \Symfony\Component\Validator\ValidatorInterface diff --git a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php index e27f6f637fc36..ebbc6a38837c9 100644 --- a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php +++ b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php @@ -33,8 +33,6 @@ /** * Recursive implementation of {@link ContextualValidatorInterface}. * - * @since 2.5 - * * @author Bernhard Schussek */ class RecursiveContextualValidator implements ContextualValidatorInterface diff --git a/src/Symfony/Component/Validator/Validator/RecursiveValidator.php b/src/Symfony/Component/Validator/Validator/RecursiveValidator.php index e4dc0fb057d29..abd29087bc08a 100644 --- a/src/Symfony/Component/Validator/Validator/RecursiveValidator.php +++ b/src/Symfony/Component/Validator/Validator/RecursiveValidator.php @@ -24,8 +24,6 @@ /** * Recursive implementation of {@link ValidatorInterface}. * - * @since 2.5 - * * @author Bernhard Schussek */ class RecursiveValidator implements ValidatorInterface, LegacyValidatorInterface diff --git a/src/Symfony/Component/Validator/Validator/ValidatorInterface.php b/src/Symfony/Component/Validator/Validator/ValidatorInterface.php index 1cc9c6dd55940..e9576f5eceb37 100644 --- a/src/Symfony/Component/Validator/Validator/ValidatorInterface.php +++ b/src/Symfony/Component/Validator/Validator/ValidatorInterface.php @@ -19,8 +19,6 @@ /** * Validates PHP values against constraints. * - * @since 2.5 - * * @author Bernhard Schussek */ interface ValidatorInterface extends MetadataFactoryInterface diff --git a/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilder.php b/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilder.php index d7d3877aed283..bf887a08ec2b8 100644 --- a/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilder.php +++ b/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilder.php @@ -20,8 +20,6 @@ /** * Default implementation of {@link ConstraintViolationBuilderInterface}. * - * @since 2.5 - * * @author Bernhard Schussek * * @internal You should not instantiate or use this class. Code against @@ -199,7 +197,7 @@ public function addViolation() $this->message, $this->plural, $this->parameters, - $this->translationDomain# + $this->translationDomain ); } catch (\InvalidArgumentException $e) { $translatedMessage = $this->translator->trans( diff --git a/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilderInterface.php b/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilderInterface.php index e02d61b432d13..60a654f793689 100644 --- a/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilderInterface.php +++ b/src/Symfony/Component/Validator/Violation/ConstraintViolationBuilderInterface.php @@ -19,8 +19,6 @@ * Finally, call {@link addViolation()} to add the violation to the current * execution context. * - * @since 2.5 - * * @author Bernhard Schussek */ interface ConstraintViolationBuilderInterface diff --git a/src/Symfony/Component/Validator/composer.json b/src/Symfony/Component/Validator/composer.json index 496d9e9dfccfd..f68d6e957c241 100644 --- a/src/Symfony/Component/Validator/composer.json +++ b/src/Symfony/Component/Validator/composer.json @@ -21,7 +21,7 @@ "symfony/translation": "~2.4|~3.0.0" }, "require-dev": { - "symfony/http-foundation": "~2.1|~3.0.0", + "symfony/http-foundation": "~2.3|~3.0.0", "symfony/intl": "~2.7.4|~2.8|~3.0.0", "symfony/yaml": "~2.0,>=2.0.5|~3.0.0", "symfony/config": "~2.2|~3.0.0", diff --git a/src/Symfony/Component/VarDumper/Caster/AmqpCaster.php b/src/Symfony/Component/VarDumper/Caster/AmqpCaster.php index 98eede22d55d4..6a6fc9297082b 100644 --- a/src/Symfony/Component/VarDumper/Caster/AmqpCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/AmqpCaster.php @@ -131,7 +131,7 @@ public static function castEnvelope(\AMQPEnvelope $c, array $a, Stub $stub, $isN $prefix.'contentType' => $c->getContentType(), $prefix.'contentEncoding' => $c->getContentEncoding(), $prefix.'type' => $c->getType(), - $prefix.'timestamp' => $c->getTimestamp(), + $prefix.'timestamp' => $c->getTimeStamp(), $prefix.'priority' => $c->getPriority(), $prefix.'expiration' => $c->getExpiration(), $prefix.'userId' => $c->getUserId(), diff --git a/src/Symfony/Component/VarDumper/Caster/Caster.php b/src/Symfony/Component/VarDumper/Caster/Caster.php index 4312e59352f1d..db052c8498a15 100644 --- a/src/Symfony/Component/VarDumper/Caster/Caster.php +++ b/src/Symfony/Component/VarDumper/Caster/Caster.php @@ -45,6 +45,8 @@ public static function castObject($obj, \ReflectionClass $reflector) { if ($reflector->hasMethod('__debugInfo')) { $a = $obj->__debugInfo(); + } elseif ($obj instanceof \Closure) { + $a = array(); } else { $a = (array) $obj; } @@ -52,7 +54,7 @@ public static function castObject($obj, \ReflectionClass $reflector) if ($a) { $p = array_keys($a); foreach ($p as $i => $k) { - if (!isset($k[0]) || ("\0" !== $k[0] && !$reflector->hasProperty($k))) { + if (isset($k[0]) && "\0" !== $k[0] && !$reflector->hasProperty($k)) { $p[$i] = self::PREFIX_DYNAMIC.$k; } elseif (isset($k[16]) && "\0" === $k[16] && 0 === strpos($k, "\0class@anonymous\0")) { $p[$i] = "\0".$reflector->getParentClass().'@anonymous'.strrchr($k, "\0"); diff --git a/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php b/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php index 51c70dd5db9a8..513352e374aa2 100644 --- a/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ExceptionCaster.php @@ -234,7 +234,7 @@ private static function filterExceptionArray($xClass, array $a, $xPrefix, $filte 'file' => $a[Caster::PREFIX_PROTECTED.'file'], 'line' => $a[Caster::PREFIX_PROTECTED.'line'], )); - $a[$xPrefix.'trace'] = new TraceStub($trace); + $a[$xPrefix.'trace'] = new TraceStub($trace, self::$traceArgs); } if (empty($a[$xPrefix.'previous'])) { unset($a[$xPrefix.'previous']); @@ -253,19 +253,24 @@ private static function extractSource(array $srcArray, $line, $srcContext) } $ltrim = 0; - while (' ' === $src[0][$ltrim] || "\t" === $src[0][$ltrim]) { - $i = $srcContext << 1; - while ($i > 0 && $src[0][$ltrim] === $src[$i][$ltrim]) { - --$i; - } - if ($i) { - break; + do { + $pad = null; + for ($i = $srcContext << 1; $i >= 0; --$i) { + if (isset($src[$i][$ltrim]) && "\r" !== ($c = $src[$i][$ltrim]) && "\n" !== $c) { + if (null === $pad) { + $pad = $c; + } + if ((' ' !== $c && "\t" !== $c) || $pad !== $c) { + break; + } + } } ++$ltrim; - } - if ($ltrim) { + } while (0 > $i && null !== $pad); + + if (--$ltrim) { foreach ($src as $i => $line) { - $src[$i] = substr($line, $ltrim); + $src[$i] = isset($line[$ltrim]) && "\r" !== $line[$ltrim] ? substr($line, $ltrim) : ltrim($line, " \t"); } } diff --git a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php index bb395a156f724..a29bd1bc93fb1 100644 --- a/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php +++ b/src/Symfony/Component/VarDumper/Caster/ReflectionCaster.php @@ -69,7 +69,7 @@ public static function castClosure(\Closure $c, array $a, Stub $stub, $isNested) } $prefix = Caster::PREFIX_DYNAMIC; - unset($a['name'], $a[$prefix.'0'], $a[$prefix.'this'], $a[$prefix.'parameter'], $a[Caster::PREFIX_VIRTUAL.'extra']); + unset($a['name'], $a[$prefix.'this'], $a[$prefix.'parameter'], $a[Caster::PREFIX_VIRTUAL.'extra']); return $a; } diff --git a/src/Symfony/Component/VarDumper/Cloner/VarCloner.php b/src/Symfony/Component/VarDumper/Cloner/VarCloner.php index b5fc1cb6681f5..65096393bb19c 100644 --- a/src/Symfony/Component/VarDumper/Cloner/VarCloner.php +++ b/src/Symfony/Component/VarDumper/Cloner/VarCloner.php @@ -28,7 +28,7 @@ protected function doClone($var) $i = 0; // Current iteration position in $queue $len = 1; // Length of $queue $pos = 0; // Number of cloned items past the first level - $refs = 0; // Hard references counter + $refsCounter = 0; // Hard references counter $queue = array(array($var)); // This breadth-first queue is the return value $arrayRefs = array(); // Map of queue indexes to stub array objects $hardRefs = array(); // Map of original zval hashes to stub objects @@ -60,27 +60,32 @@ protected function doClone($var) for ($i = 0; $i < $len; ++$i) { $indexed = true; // Whether the currently iterated array is numerically indexed or not $j = -1; // Position in the currently iterated array - $step = $queue[$i]; // Copy of the currently iterated array used for hard references detection - foreach ($step as $k => $v) { + $fromObjCast = array_keys($queue[$i]); + $fromObjCast = array_keys(array_flip($fromObjCast)) !== $fromObjCast; + $refs = $vals = $fromObjCast ? array_values($queue[$i]) : $queue[$i]; + foreach ($queue[$i] as $k => $v) { // $k is the original key // $v is the original value or a stub object in case of hard references - if ($indexed && $k !== ++$j) { + if ($k !== ++$j) { $indexed = false; } + if ($fromObjCast) { + $k = $j; + } if ($useExt) { - $zval = symfony_zval_info($k, $step); + $zval = symfony_zval_info($k, $refs); } else { - $step[$k] = $cookie; - if ($zval['zval_isref'] = $queue[$i][$k] === $cookie) { + $refs[$k] = $cookie; + if ($zval['zval_isref'] = $vals[$k] === $cookie) { $zval['zval_hash'] = $v instanceof Stub ? spl_object_hash($v) : null; } $zval['type'] = gettype($v); } if ($zval['zval_isref']) { - $queue[$i][$k] = &$stub; // Break hard references to make $queue completely + $vals[$k] = &$stub; // Break hard references to make $queue completely unset($stub); // independent from the original structure if (isset($hardRefs[$zval['zval_hash']])) { - $queue[$i][$k] = $useExt ? ($v = $hardRefs[$zval['zval_hash']]) : ($step[$k] = $v); + $vals[$k] = $useExt ? ($v = $hardRefs[$zval['zval_hash']]) : ($refs[$k] = $v); if ($v->value instanceof Stub && (Stub::TYPE_OBJECT === $v->value->type || Stub::TYPE_RESOURCE === $v->value->type)) { ++$v->value->refCount; } @@ -204,18 +209,18 @@ protected function doClone($var) if (isset($stub)) { if ($zval['zval_isref']) { if ($useExt) { - $queue[$i][$k] = $hardRefs[$zval['zval_hash']] = $v = new Stub(); + $vals[$k] = $hardRefs[$zval['zval_hash']] = $v = new Stub(); $v->value = $stub; } else { - $step[$k] = new Stub(); - $step[$k]->value = $stub; - $h = spl_object_hash($step[$k]); - $queue[$i][$k] = $hardRefs[$h] = &$step[$k]; + $refs[$k] = new Stub(); + $refs[$k]->value = $stub; + $h = spl_object_hash($refs[$k]); + $vals[$k] = $hardRefs[$h] = &$refs[$k]; $values[$h] = $v; } - $queue[$i][$k]->handle = ++$refs; + $vals[$k]->handle = ++$refsCounter; } else { - $queue[$i][$k] = $stub; + $vals[$k] = $stub; } if ($a) { @@ -243,19 +248,38 @@ protected function doClone($var) $stub = $a = null; } elseif ($zval['zval_isref']) { if ($useExt) { - $queue[$i][$k] = $hardRefs[$zval['zval_hash']] = new Stub(); - $queue[$i][$k]->value = $v; + $vals[$k] = $hardRefs[$zval['zval_hash']] = new Stub(); + $vals[$k]->value = $v; } else { - $step[$k] = $queue[$i][$k] = new Stub(); - $step[$k]->value = $v; - $h = spl_object_hash($step[$k]); - $hardRefs[$h] = &$step[$k]; + $refs[$k] = $vals[$k] = new Stub(); + $refs[$k]->value = $v; + $h = spl_object_hash($refs[$k]); + $hardRefs[$h] = &$refs[$k]; $values[$h] = $v; } - $queue[$i][$k]->handle = ++$refs; + $vals[$k]->handle = ++$refsCounter; + } + } + + if ($fromObjCast) { + $refs = $vals; + $vals = array(); + $j = -1; + foreach ($queue[$i] as $k => $v) { + foreach (array($k => $v) as $a => $v) { + } + if ($a !== $k) { + $vals = (object) $vals; + $vals->{$k} = $refs[++$j]; + $vals = (array) $vals; + } else { + $vals[$k] = $refs[++$j]; + } } } + $queue[$i] = $vals; + if (isset($arrayRefs[$i])) { if ($indexed) { $arrayRefs[$i]->class = Stub::ARRAY_INDEXED; @@ -291,7 +315,7 @@ private static function initHashMask() if (!empty($frame['line'])) { ob_start(); debug_zval_dump($obj); - self::$hashMask = substr(ob_get_clean(), 17); + self::$hashMask = (int) substr(ob_get_clean(), 17); } } diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php index 52eae49fb01f9..a716bbabd6eec 100644 --- a/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php +++ b/src/Symfony/Component/VarDumper/Tests/Caster/ReflectionCasterTest.php @@ -208,8 +208,8 @@ public function testGenerator() executing: { Symfony\Component\VarDumper\Tests\Fixtures\GeneratorDemo::foo(): { %sGeneratorDemo.php:10: """ - yield 1;\n - }\n + yield 1;\n + }\n \n """ } diff --git a/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php b/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php index b00c0d435bf0f..7c92e344d310d 100644 --- a/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/CliDumperTest.php @@ -133,6 +133,45 @@ public function testXmlResource() ); } + public function testJsonCast() + { + $var = (array) json_decode('{"0":{},"1":null}'); + foreach ($var as &$v) { + } + $var[] = &$v; + $var[''] = 2; + + $this->assertDumpMatchesFormat( + << {} + "1" => &1 null + 0 => &1 null + "" => 2 +] +EOTXT + , + $var + ); + } + + public function testObjectCast() + { + $var = (object) array(1 => 1); + $var->{1} = 2; + + $this->assertDumpMatchesFormat( + << 2); } } -/* foo bar*/ +/* foo bar*/ /* twig source*/ /* */ diff --git a/src/Symfony/Component/VarDumper/Tests/VarClonerTest.php b/src/Symfony/Component/VarDumper/Tests/VarClonerTest.php index 31e3a40ae04b5..1184f2c76a255 100644 --- a/src/Symfony/Component/VarDumper/Tests/VarClonerTest.php +++ b/src/Symfony/Component/VarDumper/Tests/VarClonerTest.php @@ -135,6 +135,72 @@ public function testClone() $this->assertStringMatchesFormat($expected, print_r($clone, true)); } + public function testJsonCast() + { + $data = (array) json_decode('{"1":{}}'); + + $cloner = new VarCloner(); + $clone = $cloner->cloneVar($data); + + $expected = <<<'EOTXT' +object(Symfony\Component\VarDumper\Cloner\Data)#%i (4) { + ["data":"Symfony\Component\VarDumper\Cloner\Data":private]=> + array(2) { + [0]=> + array(1) { + [0]=> + object(Symfony\Component\VarDumper\Cloner\Stub)#%i (7) { + ["type"]=> + string(5) "array" + ["class"]=> + string(5) "assoc" + ["value"]=> + int(1) + ["cut"]=> + int(0) + ["handle"]=> + int(0) + ["refCount"]=> + int(0) + ["position"]=> + int(1) + } + } + [1]=> + array(1) { + ["1"]=> + object(Symfony\Component\VarDumper\Cloner\Stub)#%i (7) { + ["type"]=> + string(6) "object" + ["class"]=> + string(8) "stdClass" + ["value"]=> + NULL + ["cut"]=> + int(0) + ["handle"]=> + int(%i) + ["refCount"]=> + int(0) + ["position"]=> + int(0) + } + } + } + ["maxDepth":"Symfony\Component\VarDumper\Cloner\Data":private]=> + int(20) + ["maxItemsPerDepth":"Symfony\Component\VarDumper\Cloner\Data":private]=> + int(-1) + ["useRefHandles":"Symfony\Component\VarDumper\Cloner\Data":private]=> + int(-1) +} + +EOTXT; + ob_start(); + var_dump($clone); + $this->assertStringMatchesFormat($expected, ob_get_clean()); + } + public function testCaster() { $cloner = new VarCloner(array( diff --git a/src/Symfony/Component/Yaml/Tests/ParserTest.php b/src/Symfony/Component/Yaml/Tests/ParserTest.php index 7b3681953558b..9e9a715ad167c 100644 --- a/src/Symfony/Component/Yaml/Tests/ParserTest.php +++ b/src/Symfony/Component/Yaml/Tests/ParserTest.php @@ -928,6 +928,7 @@ public function testFloatKeys() /** * @group legacy * throw ParseException in Symfony 3.0 + * @requires function Symfony\Bridge\PhpUnit\ErrorAssert::assertDeprecationsAreTriggered */ public function testColonInMappingValueException() { diff --git a/src/Symfony/Component/Yaml/Yaml.php b/src/Symfony/Component/Yaml/Yaml.php index d5fbbeeccf7f5..6fc4e9273d50b 100644 --- a/src/Symfony/Component/Yaml/Yaml.php +++ b/src/Symfony/Component/Yaml/Yaml.php @@ -73,20 +73,20 @@ public static function parse($input, $exceptionOnInvalidType = false, $objectSup } /** - * Dumps a PHP array to a YAML string. + * Dumps a PHP value to a YAML string. * * The dump method, when supplied with an array, will do its best * to convert the array into friendly YAML. * - * @param array $array PHP array + * @param mixed $input The PHP value * @param int $inline The level where you switch to inline YAML * @param int $indent The amount of spaces to use for indentation of nested nodes * @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 A YAML string representing the original PHP array + * @return string A YAML string representing the original PHP value */ - public static function dump($array, $inline = 2, $indent = 4, $exceptionOnInvalidType = false, $objectSupport = false) + public static function dump($input, $inline = 2, $indent = 4, $exceptionOnInvalidType = false, $objectSupport = false) { if ($indent < 1) { throw new \InvalidArgumentException('The indentation must be greater than zero.'); @@ -95,6 +95,6 @@ public static function dump($array, $inline = 2, $indent = 4, $exceptionOnInvali $yaml = new Dumper(); $yaml->setIndentation($indent); - return $yaml->dump($array, $inline, 0, $exceptionOnInvalidType, $objectSupport); + return $yaml->dump($input, $inline, 0, $exceptionOnInvalidType, $objectSupport); } }