diff --git a/CHANGELOG-2.7.md b/CHANGELOG-2.7.md
index 6c8ff11ea85cb..2f6ece9b92809 100644
--- a/CHANGELOG-2.7.md
+++ b/CHANGELOG-2.7.md
@@ -7,6 +7,19 @@ 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.46 (2018-04-27)
+
+ * bug #26831 [Bridge/Doctrine] count(): Parameter must be an array or an object that implements Countable (gpenverne)
+ * bug #27044 [Security] Skip user checks if not implementing UserInterface (chalasr)
+ * bug #26910 Use new PHP7.2 functions in hasColorSupport (johnstevenson)
+ * bug #26999 [VarDumper] Fix dumping of SplObjectStorage (corphi)
+ * bug #26886 Don't assume that file binary exists on *nix OS (teohhanhui)
+ * bug #26643 Fix that ESI/SSI processing can turn a "private" response "public" (mpdude)
+ * bug #26932 [Form] Fixed trimming choice values (HeahDude)
+ * bug #26875 [Console] Don't go past exact matches when autocompleting (nicolas-grekas)
+ * bug #26823 [Validator] Fix LazyLoadingMetadataFactory with PSR6Cache for non classname if tested values isn't existing class (Pascal Montoya, pmontoya)
+ * bug #26834 [Yaml] Throw parse error on unfinished inline map (nicolas-grekas)
+
* 2.7.45 (2018-04-06)
* bug #26763 [Finder] Remove duplicate slashes in filenames (helhum)
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 57bd22e5c521d..bc4ebf6f78139 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -13,8 +13,8 @@ Symfony is the result of the work of many people who made the code better
- Jordi Boggiano (seldaek)
- Victor Berchet (victor)
- Kévin Dunglas (dunglas)
- - Johannes S (johannes)
- Robin Chalas (chalas_r)
+ - Johannes S (johannes)
- Jakub Zalas (jakubzalas)
- Kris Wallsmith (kriswallsmith)
- Ryan Weaver (weaverryan)
@@ -26,8 +26,8 @@ Symfony is the result of the work of many people who made the code better
- Romain Neutron (romain)
- Pascal Borreli (pborreli)
- Wouter De Jong (wouterj)
- - Joseph Bielawski (stloyd)
- Roland Franssen (ro0)
+ - Joseph Bielawski (stloyd)
- Karma Dordrak (drak)
- Lukas Kahwe Smith (lsmith)
- Martin Hasoň (hason)
@@ -39,32 +39,32 @@ Symfony is the result of the work of many people who made the code better
- Eriksen Costa (eriksencosta)
- Guilhem Niot (energetick)
- Sarah Khalil (saro0h)
+ - Samuel ROZE (sroze)
- Jonathan Wage (jwage)
- Hamza Amrouche (simperfit)
- Diego Saint Esteben (dosten)
+ - Yonel Ceruto (yonelceruto)
- Alexandre Salomé (alexandresalome)
+ - Iltar van der Berg (kjarli)
- William Durand (couac)
- ornicar
- Francis Besset (francisbesset)
- - Iltar van der Berg (kjarli)
- stealth35 (stealth35)
- Alexander Mols (asm89)
- - Samuel ROZE (sroze)
- - Yonel Ceruto (yonelceruto)
- Bulat Shakirzyanov (avalanche123)
- Peter Rehm (rpet)
- - Saša Stamenković (umpirsky)
- Matthias Pigulla (mpdude)
+ - Saša Stamenković (umpirsky)
- Pierre du Plessis (pierredup)
- Henrik Bjørnskov (henrikbjorn)
- Dany Maillard (maidmaid)
- Miha Vrhovnik
- Tobias Nyholm (tobias)
- Diego Saint Esteben (dii3g0)
- - Konstantin Kudryashov (everzet)
- Kevin Bond (kbond)
- - Bilal Amarni (bamarni)
+ - Konstantin Kudryashov (everzet)
- Alexander M. Turek (derrabus)
+ - Bilal Amarni (bamarni)
- Jérémy DERUSSÉ (jderusse)
- Florin Patan (florinpatan)
- Mathieu Piot (mpiot)
@@ -88,28 +88,28 @@ Symfony is the result of the work of many people who made the code better
- Luis Cordova (cordoval)
- Graham Campbell (graham)
- Daniel Holmes (dholmes)
+ - David Maicher (dmaicher)
- Dariusz Ruminski
- Toni Uebernickel (havvg)
- Bart van den Burg (burgov)
- Jordan Alliot (jalliot)
- Jérôme Tamarelle (gromnan)
- John Wards (johnwards)
- - David Maicher (dmaicher)
- Fran Moreno (franmomu)
+ - Vladimir Reznichenko (kalessil)
- Antoine Hérault (herzult)
- Paráda József (paradajozsef)
- - Vladimir Reznichenko (kalessil)
- Arnaud Le Blanc (arnaud-lb)
- Maxime STEINHAUSSER
- Michal Piotrowski (eventhorizon)
- Tim Nagel (merk)
- Brice BERNARD (brikou)
- Baptiste Clavié (talus)
+ - Grégoire Paris (greg0ire)
- marc.weistroff
- lenar
- Alexander Schwenn (xelaris)
- Włodzimierz Gajda (gajdaw)
- - Grégoire Paris (greg0ire)
- Jacob Dreesen (jdreesen)
- Florian Voutzinos (florianv)
- Colin Frei
@@ -122,17 +122,17 @@ Symfony is the result of the work of many people who made the code better
- Fabien Pennequin (fabienpennequin)
- Gordon Franke (gimler)
- Eric GELOEN (gelo)
+ - Lars Strojny (lstrojny)
- Daniel Wehner (dawehner)
- Tugdual Saunier (tucksaun)
+ - Javier Spagnoletti (phansys)
- Théo FIDRY (theofidry)
- Robert Schönthal (digitalkaoz)
- Florian Lonqueu-Brochard (florianlb)
- Sebastiaan Stok (sstok)
- Stefano Sala (stefano.sala)
- Evgeniy (ewgraf)
- - Lars Strojny (lstrojny)
- Alex Pott
- - Javier Spagnoletti (phansys)
- Vincent AUBERT (vincent)
- Juti Noppornpitak (shiroyuki)
- Tigran Azatyan (tigranazatyan)
@@ -150,6 +150,7 @@ Symfony is the result of the work of many people who made the code better
- Arnaud Kleinpeter (nanocom)
- gadelat (gadelat)
- jwdeitch
+ - Teoh Han Hui (teohhanhui)
- Mikael Pajunen
- Joel Wurtz (brouznouf)
- Valentin Udaltsov (vudaltsov)
@@ -160,7 +161,6 @@ Symfony is the result of the work of many people who made the code better
- Richard Shank (iampersistent)
- Thomas Rabaix (rande)
- Rouven Weßling (realityking)
- - Teoh Han Hui (teohhanhui)
- Clemens Tolboom
- Helmer Aaviksoo
- Hiromi Hishida (77web)
@@ -186,6 +186,7 @@ Symfony is the result of the work of many people who made the code better
- Gabriel Ostrolucký
- Mario A. Alvarez Garcia (nomack84)
- Dennis Benkert (denderello)
+ - DQNEO
- SpacePossum
- Benjamin Dulau (dbenjamin)
- Mathieu Lemoine (lemoinem)
@@ -223,6 +224,7 @@ Symfony is the result of the work of many people who made the code better
- Niels Keurentjes (curry684)
- Eugene Wissner
- Julien Brochet (mewt)
+ - Leo Feyer
- Tristan Darricau (nicofuma)
- Michaël Perrin (michael.perrin)
- Marcel Beerta (mazen)
@@ -269,7 +271,6 @@ Symfony is the result of the work of many people who made the code better
- Ray
- Tyson Andre
- Nikolay Labinskiy (e-moe)
- - Leo Feyer
- Chekote
- Thomas Adam
- Albert Casademont (acasademont)
@@ -277,7 +278,6 @@ Symfony is the result of the work of many people who made the code better
- Jhonny Lidfors (jhonne)
- Diego Agulló (aeoris)
- Andreas Schempp (aschempp)
- - DQNEO
- jdhoek
- Pavel Batanov (scaytrase)
- Bob den Otter (bopp)
@@ -300,6 +300,7 @@ Symfony is the result of the work of many people who made the code better
- Michael Holm (hollo)
- Marc Weistroff (futurecat)
- Christian Schmidt
+ - Maxime Veber (nek-)
- Edi Modrić (emodric)
- Chad Sikorra (chadsikorra)
- Chris Smith (cs278)
@@ -327,6 +328,7 @@ Symfony is the result of the work of many people who made the code better
- John Bafford (jbafford)
- Adrian Rudnik (kreischweide)
- Francesc Rosàs (frosas)
+ - Romain Pierre (romain-pierre)
- Massimiliano Arione (garak)
- Julien Galenski (ruian)
- Bongiraud Dominique
@@ -357,8 +359,8 @@ Symfony is the result of the work of many people who made the code better
- Damien Alexandre (damienalexandre)
- Felix Labrecque
- Yaroslav Kiliba
- - Maxime Veber (nek-)
- Terje Bråten
+ - Mathieu Lechat
- Robbert Klarenbeek (robbertkl)
- JhonnyL
- David Badura (davidbadura)
@@ -372,6 +374,7 @@ Symfony is the result of the work of many people who made the code better
- Philipp Kräutli (pkraeutli)
- Kirill chEbba Chebunin (chebba)
- Greg Thornton (xdissent)
+ - Gary PEGEOT (gary-p)
- Costin Bereveanu (schniper)
- Loïc Chardonnet (gnusat)
- Marek Kalnik (marekkalnik)
@@ -421,9 +424,11 @@ Symfony is the result of the work of many people who made the code better
- Jeanmonod David (jeanmonod)
- Christopher Davis (chrisguitarguy)
- Jan Schumann
+ - Christian Schmidt
- Niklas Fiekas
- Markus Bachmann (baachi)
- lancergr
+ - Zan Baldwin
- Mihai Stancu
- Olivier Dolbeau (odolbeau)
- Jan Rosier (rosier)
@@ -438,6 +443,7 @@ Symfony is the result of the work of many people who made the code better
- Andreas Braun
- Boris Vujicic (boris.vujicic)
- Chris Sedlmayr (catchamonkey)
+ - Mateusz Sip (mateusz_sip)
- Seb Koelen
- Christoph Mewes (xrstf)
- Vitaliy Tverdokhlib (vitaliytv)
@@ -458,6 +464,7 @@ Symfony is the result of the work of many people who made the code better
- Adam Harvey
- Anton Bakai
- Alex Bakhturin
+ - insekticid
- Alexander Obuhovich (aik099)
- boombatower
- Fabrice Bernhard (fabriceb)
@@ -503,7 +510,6 @@ Symfony is the result of the work of many people who made the code better
- alexpods
- Arjen van der Meijden
- Dariusz Ruminski
- - Mathieu Lechat
- Erik Trapman (eriktrapman)
- De Cock Xavier (xdecock)
- Almog Baku (almogbaku)
@@ -552,7 +558,6 @@ Symfony is the result of the work of many people who made the code better
- Disquedur
- Michiel Boeckaert (milio)
- Geoffrey Tran (geoff)
- - Romain Pierre (romain-pierre)
- David Prévot
- Jan Behrens
- Mantas Var (mvar)
@@ -566,7 +571,6 @@ Symfony is the result of the work of many people who made the code better
- aubx
- Marvin Butkereit
- Ricky Su (ricky)
- - Zan Baldwin
- Gildas Quéméner (gquemener)
- Charles-Henri Bruyand
- Max Rath (drak3)
@@ -579,6 +583,7 @@ Symfony is the result of the work of many people who made the code better
- Andre Rømcke (andrerom)
- Nahuel Cuesta (ncuesta)
- Chris Boden (cboden)
+ - Christophe Villeger (seragan)
- Stefan Gehrig (sgehrig)
- Hany el-Kerdany
- Wang Jingyu
@@ -590,13 +595,13 @@ Symfony is the result of the work of many people who made the code better
- Javier López (loalf)
- Reinier Kip
- Geoffrey Brier (geoffrey-brier)
+ - Vladimir Tsykun
- Dustin Dobervich (dustin10)
- dantleech
- Anne-Sophie Bachelard (annesophie)
- Sebastian Marek (proofek)
- Erkhembayar Gantulga (erheme318)
- Michal Trojanowski
- - Mateusz Sip
- David Fuhr
- Kamil Kokot (pamil)
- Aurimas Niekis (gcds)
@@ -673,7 +678,6 @@ Symfony is the result of the work of many people who made the code better
- twifty
- Indra Gunawan (guind)
- Peter Ward
- - insekticid
- Julien DIDIER (juliendidier)
- Dominik Ritter (dritter)
- Sebastian Grodzicki (sgrodzicki)
@@ -880,6 +884,7 @@ Symfony is the result of the work of many people who made the code better
- Sander Marechal
- Radosław Benkel
- jean pasqualini (darkilliant)
+ - Ross Motley (rossmotley)
- ttomor
- Mei Gwilym (meigwilym)
- Michael H. Arieli (excelwebzone)
@@ -899,6 +904,7 @@ Symfony is the result of the work of many people who made the code better
- Zachary Tong (polyfractal)
- Ashura
- Hryhorii Hrebiniuk
+ - johnstevenson
- Dennis Fridrich (dfridrich)
- hamza
- dantleech
@@ -942,6 +948,7 @@ Symfony is the result of the work of many people who made the code better
- mlazovla
- Max Beutel
- Antanas Arvasevicius
+ - Thomas
- Maximilian Berghoff (electricmaxxx)
- nacho
- Piotr Antosik (antek88)
@@ -1085,6 +1092,7 @@ Symfony is the result of the work of many people who made the code better
- Tobias Stöckler
- Mario Young
- Ilia (aliance)
+ - Grégoire Penverne (gpenverne)
- Mo Di (modi)
- Pablo Schläpfer
- Jelte Steijaert (jelte)
@@ -1105,6 +1113,7 @@ Symfony is the result of the work of many people who made the code better
- Lars Ambrosius Wallenborn (larsborn)
- Oriol Mangas Abellan (oriolman)
- Sebastian Göttschkes (sgoettschkes)
+ - Sergey (upyx)
- Tatsuya Tsuruoka
- Ross Tuck
- Kévin Gomez (kevin)
@@ -1128,6 +1137,7 @@ Symfony is the result of the work of many people who made the code better
- Grzegorz Zdanowski (kiler129)
- sl_toto (sl_toto)
- Walter Dal Mut (wdalmut)
+ - abluchet
- Matthieu
- Albin Kerouaton
- Sébastien HOUZÉ
@@ -1144,6 +1154,7 @@ Symfony is the result of the work of many people who made the code better
- Andy Raines
- Anthony Ferrara
- Klaas Cuvelier (kcuvelier)
+ - Mathieu TUDISCO (mathieutu)
- markusu49
- Steve Frécinaux
- Jules Lamur
@@ -1186,6 +1197,7 @@ Symfony is the result of the work of many people who made the code better
- Tadcka
- Beth Binkovitz
- Gonzalo Míguez
+ - Philipp Cordes
- Pierre Rineau
- Romain Geissler
- Adrien Moiruad
@@ -1198,6 +1210,7 @@ Symfony is the result of the work of many people who made the code better
- Jay Severson
- René Kerner
- Nathaniel Catchpole
+ -
- Adrien Samson (adriensamson)
- Samuel Gordalina (gordalina)
- Max Romanovsky (maxromanovsky)
@@ -1246,6 +1259,7 @@ Symfony is the result of the work of many people who made the code better
- Simon Neidhold
- Valentin VALCIU
- Jeremiah VALERIE
+ - Julien Menth
- Kevin Dew
- James Cowgill
- 1ma (jautenim)
@@ -1302,7 +1316,6 @@ Symfony is the result of the work of many people who made the code better
- ryunosuke
- zenmate
- victoria
- - Christian Schmidt
- Francisco Facioni (fran6co)
- Iwan van Staveren (istaveren)
- Povilas S. (povilas)
@@ -1379,10 +1392,13 @@ Symfony is the result of the work of many people who made the code better
- Oleksii Zhurbytskyi
- Andy Stanberry
- Felix Marezki
+ - Normunds
- Luiz “Felds” Liscia
- Thomas Rothe
- nietonfir
- alefranz
+ - David Barratt
+ - Pavel.Batanov
- avi123
- alsar
- Aarón Nieves Fernández
@@ -1612,6 +1628,7 @@ Symfony is the result of the work of many people who made the code better
- Gabriel Moreira
- Alexey Popkov
- ChS
+ - Alexis MARQUIS
- Joseph Deray
- Damian Sromek
- Ben
@@ -1654,12 +1671,12 @@ Symfony is the result of the work of many people who made the code better
- jc
- BenjaminBeck
- Aurelijus Rožėnas
- - Vladimir Tsykun
- Jordan Hoff
- znerol
- Christian Eikermann
- Kai Eichinger
- Antonio Angelino
+ - Pascal Montoya
- Matt Fields
- Niklas Keller
- Vladimir Sazhin
@@ -1814,6 +1831,7 @@ Symfony is the result of the work of many people who made the code better
- Arash Tabriziyan (ghost098)
- ibasaw (ibasaw)
- Vladislav Krupenkin (ideea)
+ - Peter Orosz (ill_logical)
- Imangazaliev Muhammad (imangazaliev)
- j0k (j0k)
- joris de wit (jdewit)
@@ -1862,7 +1880,6 @@ Symfony is the result of the work of many people who made the code better
- scourgen hung (scourgen)
- Sébastien Alfaiate (seb33300)
- Sebastian Busch (sebu)
- - Christophe Villeger (seragan)
- André Filipe Gonçalves Neves (seven)
- Bruno Ziegler (sfcoder)
- Andrea Giuliano (shark)
@@ -1908,6 +1925,7 @@ Symfony is the result of the work of many people who made the code better
- Zander Baldwin
- Philipp Scheit
- max
+ - Ahmad Mayahi (ahmadmayahi)
- Mohamed Karnichi (amiral)
- Andrew Carter (andrewcarteruk)
- Adam Elsodaney (archfizz)
diff --git a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php
index ee8ec2ddaba71..1d881849267d7 100644
--- a/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php
+++ b/src/Symfony/Bridge/Doctrine/Form/ChoiceList/IdReader.php
@@ -95,10 +95,7 @@ public function getIdValue($object)
}
if (!$this->om->contains($object)) {
- throw new RuntimeException(
- 'Entities passed to the choice field must be managed. Maybe '.
- 'persist them in the entity manager?'
- );
+ throw new RuntimeException(sprintf('Entity of type "%s" passed to the choice field must be managed. Maybe you forget to persist it in the entity manager?', get_class($object)));
}
$this->om->initializeObject($object);
diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php
index 61131e47045aa..510c0f227afcc 100644
--- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php
+++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php
@@ -517,4 +517,32 @@ public function testEntityManagerNullObject()
$this->validator->validate($entity, $constraint);
}
+
+ public function testValidateUniquenessOnNullResult()
+ {
+ $repository = $this->createRepositoryMock();
+ $repository
+ ->method('find')
+ ->will($this->returnValue(null))
+ ;
+
+ $this->em = $this->createEntityManagerMock($repository);
+ $this->registry = $this->createRegistryMock($this->em);
+ $this->validator = $this->createValidator();
+ $this->validator->initialize($this->context);
+
+ $constraint = new UniqueEntity(array(
+ 'message' => 'myMessage',
+ 'fields' => array('name'),
+ 'em' => self::EM_NAME,
+ ));
+
+ $entity = new SingleIntIdEntity(1, null);
+
+ $this->em->persist($entity);
+ $this->em->flush();
+
+ $this->validator->validate($entity, $constraint);
+ $this->assertNoViolation();
+ }
}
diff --git a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php
index 8c7876eae342d..3effc89ca09af 100644
--- a/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php
+++ b/src/Symfony/Bridge/Doctrine/Validator/Constraints/UniqueEntityValidator.php
@@ -133,15 +133,23 @@ public function validate($entity, Constraint $constraint)
*/
if ($result instanceof \Iterator) {
$result->rewind();
- } elseif (is_array($result)) {
+ if ($result instanceof \Countable && 1 < \count($result)) {
+ $result = array($result->current(), $result->current());
+ } else {
+ $result = $result->current();
+ $result = null === $result ? array() : array($result);
+ }
+ } elseif (\is_array($result)) {
reset($result);
+ } else {
+ $result = null === $result ? array() : array($result);
}
/* If no entity matched the query criteria or a single entity matched,
* which is the same as the entity being validated, the criteria is
* unique.
*/
- if (0 === count($result) || (1 === count($result) && $entity === ($result instanceof \Iterator ? $result->current() : current($result)))) {
+ if (!$result || (1 === \count($result) && current($result) === $entity)) {
return;
}
diff --git a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
index b0f241c862496..2b5c734c54c03 100644
--- a/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
+++ b/src/Symfony/Bridge/PhpUnit/DeprecationErrorHandler.php
@@ -178,17 +178,38 @@ public static function register($mode = false)
}
}
+ /**
+ * Returns true if STDOUT is defined and supports colorization.
+ *
+ * Reference: Composer\XdebugHandler\Process::supportsColor
+ * https://github.com/composer/xdebug-handler
+ *
+ * @return bool
+ */
private static function hasColorSupport()
{
- if ('\\' === DIRECTORY_SEPARATOR) {
- return
- defined('STDOUT') && function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support(STDOUT)
- || '10.0.10586' === PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD
+ if (!defined('STDOUT')) {
+ return false;
+ }
+
+ if (DIRECTORY_SEPARATOR === '\\') {
+ return (function_exists('sapi_windows_vt100_support')
+ && sapi_windows_vt100_support(STDOUT))
|| false !== getenv('ANSICON')
|| 'ON' === getenv('ConEmuANSI')
|| 'xterm' === getenv('TERM');
}
- return defined('STDOUT') && function_exists('posix_isatty') && @posix_isatty(STDOUT);
+ if (function_exists('stream_isatty')) {
+ return stream_isatty(STDOUT);
+ }
+
+ if (function_exists('posix_isatty')) {
+ return posix_isatty(STDOUT);
+ }
+
+ $stat = fstat(STDOUT);
+ // Check if formatted mode is S_IFCHR
+ return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
}
}
diff --git a/src/Symfony/Bridge/Twig/README.md b/src/Symfony/Bridge/Twig/README.md
index eb084147c37f8..602f5a54c3dd6 100644
--- a/src/Symfony/Bridge/Twig/README.md
+++ b/src/Symfony/Bridge/Twig/README.md
@@ -1,7 +1,7 @@
Twig Bridge
===========
-Provides integration for [Twig](http://twig.sensiolabs.org/) with various
+Provides integration for [Twig](https://twig.symfony.com/) with various
Symfony components.
Resources
diff --git a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TemplateFinder.php b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TemplateFinder.php
index d68fa7ce77674..e49bf22a35627 100644
--- a/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TemplateFinder.php
+++ b/src/Symfony/Bundle/FrameworkBundle/CacheWarmer/TemplateFinder.php
@@ -96,11 +96,10 @@ private function findTemplatesInFolder($dir)
private function findTemplatesInBundle(BundleInterface $bundle)
{
$name = $bundle->getName();
- $templates = array_merge(
+ $templates = array_unique(array_merge(
$this->findTemplatesInFolder($bundle->getPath().'/Resources/views'),
$this->findTemplatesInFolder($this->rootDir.'/'.$name.'/views')
- );
- $templates = array_unique($templates);
+ ));
foreach ($templates as $i => $template) {
$templates[$i] = $template->set('bundle', $name);
diff --git a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/CodeHelper.php b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/CodeHelper.php
index 7390144dc8dd9..7a1eb9700aad4 100644
--- a/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/CodeHelper.php
+++ b/src/Symfony/Bundle/FrameworkBundle/Templating/Helper/CodeHelper.php
@@ -160,7 +160,7 @@ public function formatFile($file, $line, $text = null)
$file = trim($file);
$fileStr = $file;
if (0 === strpos($fileStr, $this->rootDir)) {
- $fileStr = str_replace($this->rootDir, '', str_replace('\\', '/', $fileStr));
+ $fileStr = str_replace(array('\\', $this->rootDir), array('/', ''), $fileStr);
$fileStr = htmlspecialchars($fileStr, $flags, $this->charset);
$fileStr = sprintf('kernel.root_dir/%s', htmlspecialchars($this->rootDir, $flags, $this->charset), $fileStr);
}
diff --git a/src/Symfony/Component/Console/Descriptor/JsonDescriptor.php b/src/Symfony/Component/Console/Descriptor/JsonDescriptor.php
index 51c4d2ef0e619..0a22274b3508d 100644
--- a/src/Symfony/Component/Console/Descriptor/JsonDescriptor.php
+++ b/src/Symfony/Component/Console/Descriptor/JsonDescriptor.php
@@ -109,7 +109,7 @@ private function getInputOptionData(InputOption $option)
{
return array(
'name' => '--'.$option->getName(),
- 'shortcut' => $option->getShortcut() ? '-'.implode('|-', explode('|', $option->getShortcut())) : '',
+ 'shortcut' => $option->getShortcut() ? '-'.str_replace('|', '|-', $option->getShortcut()) : '',
'accept_value' => $option->acceptValue(),
'is_value_required' => $option->isValueRequired(),
'is_multiple' => $option->isArray(),
diff --git a/src/Symfony/Component/Console/Descriptor/MarkdownDescriptor.php b/src/Symfony/Component/Console/Descriptor/MarkdownDescriptor.php
index c2d6243e280cc..76399cae7d40a 100644
--- a/src/Symfony/Component/Console/Descriptor/MarkdownDescriptor.php
+++ b/src/Symfony/Component/Console/Descriptor/MarkdownDescriptor.php
@@ -50,7 +50,7 @@ protected function describeInputOption(InputOption $option, array $options = arr
$this->write(
'**'.$option->getName().':**'."\n\n"
.'* Name: `--'.$option->getName().'`'."\n"
- .'* Shortcut: '.($option->getShortcut() ? '`-'.implode('|-', explode('|', $option->getShortcut())).'`' : '')."\n"
+ .'* Shortcut: '.($option->getShortcut() ? '`-'.str_replace('|', '|-', $option->getShortcut()).'`' : '')."\n"
.'* Accept value: '.($option->acceptValue() ? 'yes' : 'no')."\n"
.'* Is value required: '.($option->isValueRequired() ? 'yes' : 'no')."\n"
.'* Is multiple: '.($option->isArray() ? 'yes' : 'no')."\n"
diff --git a/src/Symfony/Component/Console/Descriptor/XmlDescriptor.php b/src/Symfony/Component/Console/Descriptor/XmlDescriptor.php
index 177a054cc18d1..c42fa429dcf6e 100644
--- a/src/Symfony/Component/Console/Descriptor/XmlDescriptor.php
+++ b/src/Symfony/Component/Console/Descriptor/XmlDescriptor.php
@@ -223,7 +223,7 @@ private function getInputOptionDocument(InputOption $option)
$pos = strpos($option->getShortcut(), '|');
if (false !== $pos) {
$objectXML->setAttribute('shortcut', '-'.substr($option->getShortcut(), 0, $pos));
- $objectXML->setAttribute('shortcuts', '-'.implode('|-', explode('|', $option->getShortcut())));
+ $objectXML->setAttribute('shortcuts', '-'.str_replace('|', '|-', $option->getShortcut()));
} else {
$objectXML->setAttribute('shortcut', $option->getShortcut() ? '-'.$option->getShortcut() : '');
}
diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php
index bce0534ed0991..36187f8cea486 100644
--- a/src/Symfony/Component/Console/Helper/QuestionHelper.php
+++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php
@@ -284,7 +284,7 @@ private function autocomplete(OutputInterface $output, Question $question, $inpu
foreach ($autocomplete as $value) {
// If typed characters match the beginning chunk of value (e.g. [AcmeDe]moBundle)
- if (0 === strpos($value, $ret) && $i !== strlen($value)) {
+ if (0 === strpos($value, $ret)) {
$matches[$numMatches++] = $value;
}
}
diff --git a/src/Symfony/Component/Console/Input/InputOption.php b/src/Symfony/Component/Console/Input/InputOption.php
index e6ca45aa42c56..c2b57c7c27a3e 100644
--- a/src/Symfony/Component/Console/Input/InputOption.php
+++ b/src/Symfony/Component/Console/Input/InputOption.php
@@ -192,7 +192,7 @@ public function getDescription()
*
* @return bool
*/
- public function equals(InputOption $option)
+ public function equals(self $option)
{
return $option->getName() === $this->getName()
&& $option->getShortcut() === $this->getShortcut()
diff --git a/src/Symfony/Component/Console/Output/StreamOutput.php b/src/Symfony/Component/Console/Output/StreamOutput.php
index 182622a29a5c8..b0897b206f70c 100644
--- a/src/Symfony/Component/Console/Output/StreamOutput.php
+++ b/src/Symfony/Component/Console/Output/StreamOutput.php
@@ -81,31 +81,34 @@ protected function doWrite($message, $newline)
*
* Colorization is disabled if not supported by the stream:
*
- * - the stream is redirected (eg php file.php >log)
- * - Windows without VT100 support, Ansicon, ConEmu, Mintty
- * - non tty consoles
+ * This is tricky on Windows, because Cygwin, Msys2 etc emulate pseudo
+ * terminals via named pipes, so we can only check the environment.
+ *
+ * Reference: Composer\XdebugHandler\Process::supportsColor
+ * https://github.com/composer/xdebug-handler
*
* @return bool true if the stream supports colorization, false otherwise
*/
protected function hasColorSupport()
{
- if (function_exists('stream_isatty') && !@stream_isatty($this->stream)) {
- return false;
- }
if (DIRECTORY_SEPARATOR === '\\') {
- if (function_exists('sapi_windows_vt100_support')) {
- $vt100Enabled = @sapi_windows_vt100_support($this->stream);
- } else {
- $vt100Enabled = '10.0.10586' === PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD;
- }
-
- return
- $vt100Enabled
+ return (function_exists('sapi_windows_vt100_support')
+ && @sapi_windows_vt100_support($this->stream))
|| false !== getenv('ANSICON')
|| 'ON' === getenv('ConEmuANSI')
|| 'xterm' === getenv('TERM');
}
- return function_exists('posix_isatty') && @posix_isatty($this->stream);
+ if (function_exists('stream_isatty')) {
+ return @stream_isatty($this->stream);
+ }
+
+ if (function_exists('posix_isatty')) {
+ return @posix_isatty($this->stream);
+ }
+
+ $stat = @fstat($this->stream);
+ // Check if formatted mode is S_IFCHR
+ return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
}
}
diff --git a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php
index d9bdb606ac340..9f837d0f9ed49 100644
--- a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php
+++ b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php
@@ -160,6 +160,30 @@ public function testAskWithAutocompleteWithNonSequentialKeys()
$this->assertEquals('AsseticBundle', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
}
+ public function testAskWithAutocompleteWithExactMatch()
+ {
+ if (!$this->hasSttyAvailable()) {
+ $this->markTestSkipped('`stty` is required to test autocomplete functionality');
+ }
+
+ $inputStream = $this->getInputStream("b\n");
+
+ $possibleChoices = array(
+ 'a' => 'berlin',
+ 'b' => 'copenhagen',
+ 'c' => 'amsterdam',
+ );
+
+ $dialog = new QuestionHelper();
+ $dialog->setInputStream($inputStream);
+ $dialog->setHelperSet(new HelperSet(array(new FormatterHelper())));
+
+ $question = new ChoiceQuestion('Please select a city', $possibleChoices);
+ $question->setMaxAttempts(1);
+
+ $this->assertSame('b', $dialog->ask($this->createInputInterfaceMock(), $this->createOutputInterface(), $question));
+ }
+
public function testAutocompleteWithTrailingBackslash()
{
if (!$this->hasSttyAvailable()) {
diff --git a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
index 601583b7839f8..19f1d62e4f371 100644
--- a/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
+++ b/src/Symfony/Component/Form/Extension/Core/Type/ChoiceType.php
@@ -413,6 +413,7 @@ public function configureOptions(OptionsResolver $resolver)
// See https://github.com/symfony/symfony/pull/5582
'data_class' => null,
'choice_translation_domain' => true,
+ 'trim' => false,
));
$resolver->setNormalizer('choices', $choicesNormalizer);
diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php
index 842136e14c677..875a0ba0f60b4 100644
--- a/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php
+++ b/src/Symfony/Component/Form/Tests/Extension/Core/Type/ChoiceTypeTest.php
@@ -2421,4 +2421,59 @@ public function invalidNestedValueTestMatrix()
'multiple, expanded' => array(true, true, array(array())),
);
}
+
+ /**
+ * @dataProvider provideTrimCases
+ */
+ public function testTrimIsDisabled($multiple, $expanded)
+ {
+ $form = $this->factory->create(static::TESTED_TYPE, null, array(
+ 'multiple' => $multiple,
+ 'expanded' => $expanded,
+ 'choices' => array(
+ 'a' => '1',
+ ),
+ 'choices_as_values' => true,
+ ));
+
+ $submittedData = ' 1';
+
+ $form->submit($multiple ? (array) $submittedData : $submittedData);
+
+ // When the choice does not exist the transformation fails
+ $this->assertFalse($form->isSynchronized());
+ $this->assertNull($form->getData());
+ }
+
+ /**
+ * @dataProvider provideTrimCases
+ */
+ public function testSubmitValueWithWhiteSpace($multiple, $expanded)
+ {
+ $valueWhitWhiteSpace = '1 ';
+
+ $form = $this->factory->create(static::TESTED_TYPE, null, array(
+ 'multiple' => $multiple,
+ 'expanded' => $expanded,
+ 'choices' => array(
+ 'a' => $valueWhitWhiteSpace,
+ ),
+ 'choices_as_values' => true,
+ ));
+
+ $form->submit($multiple ? (array) $valueWhitWhiteSpace : $valueWhitWhiteSpace);
+
+ $this->assertTrue($form->isSynchronized());
+ $this->assertSame($multiple ? (array) $valueWhitWhiteSpace : $valueWhitWhiteSpace, $form->getData());
+ }
+
+ public function provideTrimCases()
+ {
+ return array(
+ 'Simple' => array(false, false),
+ 'Multiple' => array(true, false),
+ 'Simple expanded' => array(false, true),
+ 'Multiple expanded' => array(true, true),
+ );
+ }
}
diff --git a/src/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php b/src/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php
index c2ac6768c3013..3c358104651b8 100644
--- a/src/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php
+++ b/src/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php
@@ -43,7 +43,21 @@ public function __construct($cmd = 'file -b --mime %s 2>/dev/null')
*/
public static function isSupported()
{
- return '\\' !== DIRECTORY_SEPARATOR && function_exists('passthru') && function_exists('escapeshellarg');
+ static $supported = null;
+
+ if (null !== $supported) {
+ return $supported;
+ }
+
+ if ('\\' === DIRECTORY_SEPARATOR || !function_exists('passthru') || !function_exists('escapeshellarg')) {
+ return $supported = false;
+ }
+
+ ob_start();
+ passthru('command -v file', $exitStatus);
+ $binPath = trim(ob_get_clean());
+
+ return $supported = 0 === $exitStatus && '' !== $binPath;
}
/**
diff --git a/src/Symfony/Component/HttpFoundation/Response.php b/src/Symfony/Component/HttpFoundation/Response.php
index a7459224c2a95..13b85b15d4e81 100644
--- a/src/Symfony/Component/HttpFoundation/Response.php
+++ b/src/Symfony/Component/HttpFoundation/Response.php
@@ -21,6 +21,7 @@ class Response
const HTTP_CONTINUE = 100;
const HTTP_SWITCHING_PROTOCOLS = 101;
const HTTP_PROCESSING = 102; // RFC2518
+ const HTTP_EARLY_HINTS = 103; // RFC8297
const HTTP_OK = 200;
const HTTP_CREATED = 201;
const HTTP_ACCEPTED = 202;
@@ -507,13 +508,19 @@ public function getCharset()
}
/**
- * Returns true if the response is worth caching under any circumstance.
+ * Returns true if the response may safely be kept in a shared (surrogate) cache.
*
* Responses marked "private" with an explicit Cache-Control directive are
* considered uncacheable.
*
* Responses with neither a freshness lifetime (Expires, max-age) nor cache
- * validator (Last-Modified, ETag) are considered uncacheable.
+ * validator (Last-Modified, ETag) are considered uncacheable because there is
+ * no way to tell when or how to remove them from the cache.
+ *
+ * Note that RFC 7231 and RFC 7234 possibly allow for a more permissive implementation,
+ * for example "status codes that are defined as cacheable by default [...]
+ * can be reused by a cache with heuristic expiration unless otherwise indicated"
+ * (https://tools.ietf.org/html/rfc7231#section-6.1)
*
* @return bool true if the response is worth caching, false otherwise
*/
diff --git a/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php b/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php
index 027b2b1761334..672cc893feb6d 100644
--- a/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php
+++ b/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php
@@ -72,7 +72,7 @@ public function update(Response $response)
$response->setLastModified(null);
}
- if (!$response->isFresh()) {
+ if (!$response->isFresh() || !$response->isCacheable()) {
$this->cacheable = false;
}
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index ca42a5e29958f..43a441fbe25d5 100644
--- a/src/Symfony/Component/HttpKernel/Kernel.php
+++ b/src/Symfony/Component/HttpKernel/Kernel.php
@@ -58,11 +58,11 @@ abstract class Kernel implements KernelInterface, TerminableInterface
protected $startTime;
protected $loadClassCache;
- const VERSION = '2.7.45';
- const VERSION_ID = 20745;
+ const VERSION = '2.7.46';
+ const VERSION_ID = 20746;
const MAJOR_VERSION = 2;
const MINOR_VERSION = 7;
- const RELEASE_VERSION = 45;
+ const RELEASE_VERSION = 46;
const EXTRA_VERSION = '';
const END_OF_MAINTENANCE = '05/2018';
diff --git a/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php b/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php
index 2dbb799109708..4c7cd9a51c0e9 100644
--- a/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/DataCollector/DumpDataCollectorTest.php
@@ -67,7 +67,7 @@ public function testCollectDefault()
ob_start();
$collector->collect(new Request(), new Response());
- $output = ob_get_clean();
+ $output = preg_replace("/\033\[[^m]*m/", '', ob_get_clean());
if (\PHP_VERSION_ID >= 50400) {
$this->assertSame("DumpDataCollectorTest.php on line {$line}:\n123\n", $output);
@@ -125,10 +125,11 @@ public function testFlush()
ob_start();
$collector->__destruct();
+ $output = preg_replace("/\033\[[^m]*m/", '', ob_get_clean());
if (\PHP_VERSION_ID >= 50400) {
- $this->assertSame("DumpDataCollectorTest.php on line {$line}:\n456\n", ob_get_clean());
+ $this->assertSame("DumpDataCollectorTest.php on line {$line}:\n456\n", $output);
} else {
- $this->assertSame("\"DumpDataCollectorTest.php on line {$line}:\"\n456\n", ob_get_clean());
+ $this->assertSame("\"DumpDataCollectorTest.php on line {$line}:\"\n456\n", $output);
}
}
@@ -141,10 +142,11 @@ public function testFlushNothingWhenDataDumperIsProvided()
ob_start();
$collector->dump($data);
$line = __LINE__ - 1;
+ $output = preg_replace("/\033\[[^m]*m/", '', ob_get_clean());
if (\PHP_VERSION_ID >= 50400) {
- $this->assertSame("DumpDataCollectorTest.php on line {$line}:\n456\n", ob_get_clean());
+ $this->assertSame("DumpDataCollectorTest.php on line {$line}:\n456\n", $output);
} else {
- $this->assertSame("\"DumpDataCollectorTest.php on line {$line}:\"\n456\n", ob_get_clean());
+ $this->assertSame("\"DumpDataCollectorTest.php on line {$line}:\"\n456\n", $output);
}
ob_start();
diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php
index 5e4c322223eb3..6d67a177398c2 100644
--- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/ResponseCacheStrategyTest.php
@@ -175,8 +175,26 @@ public function testEmbeddingPrivateResponseMakesMainResponsePrivate()
$cacheStrategy->update($masterResponse);
$this->assertTrue($masterResponse->headers->hasCacheControlDirective('private'));
- // Not sure if we should pass "max-age: 60" in this case, as long as the response is private and
- // that's the more conservative of both the master and embedded response...?
+ $this->assertFalse($masterResponse->headers->hasCacheControlDirective('public'));
+ }
+
+ public function testEmbeddingPublicResponseDoesNotMakeMainResponsePublic()
+ {
+ $cacheStrategy = new ResponseCacheStrategy();
+
+ $masterResponse = new Response();
+ $masterResponse->setPrivate(); // this is the default, but let's be explicit
+ $masterResponse->setMaxAge(100);
+
+ $embeddedResponse = new Response();
+ $embeddedResponse->setPublic();
+ $embeddedResponse->setSharedMaxAge(100);
+
+ $cacheStrategy->add($embeddedResponse);
+ $cacheStrategy->update($masterResponse);
+
+ $this->assertTrue($masterResponse->headers->hasCacheControlDirective('private'));
+ $this->assertFalse($masterResponse->headers->hasCacheControlDirective('public'));
}
public function testResponseIsExiprableWhenEmbeddedResponseCombinesExpiryAndValidation()
diff --git a/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php b/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php
index a82fb7eea4279..b4bdbf40c097d 100644
--- a/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php
+++ b/src/Symfony/Component/Security/Core/Authentication/Provider/SimpleAuthenticationProvider.php
@@ -13,6 +13,7 @@
use Symfony\Component\Security\Core\User\UserChecker;
use Symfony\Component\Security\Core\User\UserCheckerInterface;
+use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface;
@@ -45,6 +46,11 @@ public function authenticate(TokenInterface $token)
}
$user = $authToken->getUser();
+
+ if (!$user instanceof UserInterface) {
+ return $authToken;
+ }
+
$this->userChecker->checkPreAuth($user);
$this->userChecker->checkPostAuth($user);
diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/SimpleAuthenticationProviderTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/SimpleAuthenticationProviderTest.php
index 1e7069c1fa0bb..35247abe99c49 100644
--- a/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/SimpleAuthenticationProviderTest.php
+++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Provider/SimpleAuthenticationProviderTest.php
@@ -15,6 +15,7 @@
use Symfony\Component\Security\Core\Exception\DisabledException;
use Symfony\Component\Security\Core\Authentication\Provider\SimpleAuthenticationProvider;
use Symfony\Component\Security\Core\Exception\LockedException;
+use Symfony\Component\Security\Core\User\UserChecker;
class SimpleAuthenticationProviderTest extends TestCase
{
@@ -72,6 +73,20 @@ public function testAuthenticateWhenPostChecksFails()
$provider->authenticate($token);
}
+ public function testAuthenticateSkipsUserChecksForNonUserInterfaceObjects()
+ {
+ $token = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\Token\TokenInterface')->getMock();
+ $token->expects($this->any())
+ ->method('getUser')
+ ->will($this->returnValue('string-user'));
+ $authenticator = $this->getMockBuilder('Symfony\Component\Security\Core\Authentication\SimpleAuthenticatorInterface')->getMock();
+ $authenticator->expects($this->once())
+ ->method('authenticateToken')
+ ->will($this->returnValue($token));
+
+ $this->assertSame($token, $this->getProvider($authenticator, null, new UserChecker())->authenticate($token));
+ }
+
protected function getProvider($simpleAuthenticator = null, $userProvider = null, $userChecker = null, $key = 'test')
{
if (null === $userChecker) {
diff --git a/src/Symfony/Component/Validator/Mapping/Factory/LazyLoadingMetadataFactory.php b/src/Symfony/Component/Validator/Mapping/Factory/LazyLoadingMetadataFactory.php
index 1a4f3074b6e4f..cb253f844ba78 100644
--- a/src/Symfony/Component/Validator/Mapping/Factory/LazyLoadingMetadataFactory.php
+++ b/src/Symfony/Component/Validator/Mapping/Factory/LazyLoadingMetadataFactory.php
@@ -90,6 +90,10 @@ public function getMetadataFor($value)
return $this->loadedClasses[$class];
}
+ if (!class_exists($class) && !interface_exists($class, false)) {
+ throw new NoSuchMetadataException(sprintf('The class or interface "%s" does not exist.', $class));
+ }
+
if (null !== $this->cache && false !== ($metadata = $this->cache->read($class))) {
// Include constraints from the parent class
$this->mergeConstraints($metadata);
@@ -97,10 +101,6 @@ public function getMetadataFor($value)
return $this->loadedClasses[$class] = $metadata;
}
- if (!class_exists($class) && !interface_exists($class)) {
- throw new NoSuchMetadataException(sprintf('The class or interface "%s" does not exist.', $class));
- }
-
$metadata = new ClassMetadata($class);
if (null !== $this->loader) {
@@ -162,10 +162,6 @@ public function hasMetadataFor($value)
$class = ltrim(is_object($value) ? get_class($value) : $value, '\\');
- if (class_exists($class) || interface_exists($class)) {
- return true;
- }
-
- return false;
+ return class_exists($class) || interface_exists($class, false);
}
}
diff --git a/src/Symfony/Component/Validator/Tests/Mapping/Factory/LazyLoadingMetadataFactoryTest.php b/src/Symfony/Component/Validator/Tests/Mapping/Factory/LazyLoadingMetadataFactoryTest.php
index b5d1a9dc84d4d..de6852271e17f 100644
--- a/src/Symfony/Component/Validator/Tests/Mapping/Factory/LazyLoadingMetadataFactoryTest.php
+++ b/src/Symfony/Component/Validator/Tests/Mapping/Factory/LazyLoadingMetadataFactoryTest.php
@@ -149,6 +149,21 @@ public function testReadMetadataFromCache()
$this->assertEquals($metadata, $factory->getMetadataFor(self::PARENT_CLASS));
}
+ /**
+ * @expectedException \Symfony\Component\Validator\Exception\NoSuchMetadataException
+ */
+ public function testNonClassNameStringValues()
+ {
+ $testedValue = 'error@example.com';
+ $loader = $this->getMockBuilder('Symfony\Component\Validator\Mapping\Loader\LoaderInterface')->getMock();
+ $cache = $this->getMockBuilder('Symfony\Component\Validator\Mapping\Cache\CacheInterface')->getMock();
+ $factory = new LazyLoadingMetadataFactory($loader, $cache);
+ $cache
+ ->expects($this->never())
+ ->method('read');
+ $factory->getMetadataFor($testedValue);
+ }
+
public function testMetadataCacheWithRuntimeConstraint()
{
$cache = $this->getMockBuilder('Symfony\Component\Validator\Mapping\Cache\CacheInterface')->getMock();
diff --git a/src/Symfony/Component/VarDumper/Caster/SplCaster.php b/src/Symfony/Component/VarDumper/Caster/SplCaster.php
index 835837266128e..f3fcf9748fb18 100644
--- a/src/Symfony/Component/VarDumper/Caster/SplCaster.php
+++ b/src/Symfony/Component/VarDumper/Caster/SplCaster.php
@@ -86,10 +86,11 @@ public static function castObjectStorage(\SplObjectStorage $c, array $a, Stub $s
$storage = array();
unset($a[Caster::PREFIX_DYNAMIC."\0gcdata"]); // Don't hit https://bugs.php.net/65967
- foreach (clone $c as $obj) {
+ $clone = clone $c;
+ foreach ($clone as $obj) {
$storage[spl_object_hash($obj)] = array(
'object' => $obj,
- 'info' => $c->getInfo(),
+ 'info' => $clone->getInfo(),
);
}
diff --git a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php
index 689ada77c2460..bc80e9f65b9af 100644
--- a/src/Symfony/Component/VarDumper/Dumper/CliDumper.php
+++ b/src/Symfony/Component/VarDumper/Dumper/CliDumper.php
@@ -58,7 +58,7 @@ public function __construct($output = null, $charset = null)
{
parent::__construct($output, $charset);
- if ('\\' === DIRECTORY_SEPARATOR && 'ON' !== @getenv('ConEmuANSI') && 'xterm' !== @getenv('TERM')) {
+ if ('\\' === DIRECTORY_SEPARATOR && !$this->isWindowsTrueColor()) {
// Use only the base 16 xterm colors when using ANSICON or standard Windows 10 CLI
$this->setStyles(array(
'default' => '31',
@@ -420,7 +420,7 @@ protected function style($style, $value, $attr = array())
protected function supportsColors()
{
if ($this->outputStream !== static::$defaultOutput) {
- return @(is_resource($this->outputStream) && function_exists('posix_isatty') && posix_isatty($this->outputStream));
+ return $this->hasColorSupport($this->outputStream);
}
if (null !== static::$defaultColors) {
return static::$defaultColors;
@@ -448,23 +448,10 @@ protected function supportsColors()
}
}
- if ('\\' === DIRECTORY_SEPARATOR) {
- static::$defaultColors = @(
- function_exists('sapi_windows_vt100_support') && sapi_windows_vt100_support($this->outputStream)
- || '10.0.10586' === PHP_WINDOWS_VERSION_MAJOR.'.'.PHP_WINDOWS_VERSION_MINOR.'.'.PHP_WINDOWS_VERSION_BUILD
- || false !== getenv('ANSICON')
- || 'ON' === getenv('ConEmuANSI')
- || 'xterm' === getenv('TERM')
- );
- } elseif (function_exists('posix_isatty')) {
- $h = stream_get_meta_data($this->outputStream) + array('wrapper_type' => null);
- $h = 'Output' === $h['stream_type'] && 'PHP' === $h['wrapper_type'] ? fopen('php://stdout', 'wb') : $this->outputStream;
- static::$defaultColors = @posix_isatty($h);
- } else {
- static::$defaultColors = false;
- }
+ $h = stream_get_meta_data($this->outputStream) + array('wrapper_type' => null);
+ $h = 'Output' === $h['stream_type'] && 'PHP' === $h['wrapper_type'] ? fopen('php://stdout', 'wb') : $this->outputStream;
- return static::$defaultColors;
+ return static::$defaultColors = $this->hasColorSupport($h);
}
/**
@@ -477,4 +464,69 @@ protected function dumpLine($depth, $endOfValue = false)
}
parent::dumpLine($depth);
}
+
+ /**
+ * Returns true if the stream supports colorization.
+ *
+ * Reference: Composer\XdebugHandler\Process::supportsColor
+ * https://github.com/composer/xdebug-handler
+ *
+ * @param mixed $stream A CLI output stream
+ *
+ * @return bool
+ */
+ private function hasColorSupport($stream)
+ {
+ if (!is_resource($stream) || 'stream' !== get_resource_type($stream)) {
+ return false;
+ }
+
+ if (DIRECTORY_SEPARATOR === '\\') {
+ return (function_exists('sapi_windows_vt100_support')
+ && @sapi_windows_vt100_support($stream))
+ || false !== getenv('ANSICON')
+ || 'ON' === getenv('ConEmuANSI')
+ || 'xterm' === getenv('TERM');
+ }
+
+ if (function_exists('stream_isatty')) {
+ return @stream_isatty($stream);
+ }
+
+ if (function_exists('posix_isatty')) {
+ return @posix_isatty($stream);
+ }
+
+ $stat = @fstat($stream);
+ // Check if formatted mode is S_IFCHR
+ return $stat ? 0020000 === ($stat['mode'] & 0170000) : false;
+ }
+
+ /**
+ * Returns true if the Windows terminal supports true color.
+ *
+ * Note that this does not check an output stream, but relies on environment
+ * variables from known implementations, or a PHP and Windows version that
+ * supports true color.
+ *
+ * @return bool
+ */
+ private function isWindowsTrueColor()
+ {
+ $result = 183 <= getenv('ANSICON_VER')
+ || 'ON' === getenv('ConEmuANSI')
+ || 'xterm' === getenv('TERM');
+
+ if (!$result && PHP_VERSION_ID >= 70200) {
+ $version = sprintf(
+ '%s.%s.%s',
+ PHP_WINDOWS_VERSION_MAJOR,
+ PHP_WINDOWS_VERSION_MINOR,
+ PHP_WINDOWS_VERSION_BUILD
+ );
+ $result = $version >= '10.0.15063';
+ }
+
+ return $result;
+ }
}
diff --git a/src/Symfony/Component/VarDumper/Tests/Caster/SplCasterTest.php b/src/Symfony/Component/VarDumper/Tests/Caster/SplCasterTest.php
index 96e0307385fb6..ece69424943a6 100644
--- a/src/Symfony/Component/VarDumper/Tests/Caster/SplCasterTest.php
+++ b/src/Symfony/Component/VarDumper/Tests/Caster/SplCasterTest.php
@@ -40,4 +40,23 @@ public function provideCastSplDoublyLinkedList()
array(\SplDoublyLinkedList::IT_MODE_LIFO | \SplDoublyLinkedList::IT_MODE_DELETE, 'IT_MODE_LIFO | IT_MODE_DELETE'),
);
}
+
+ public function testCastObjectStorageIsntModified()
+ {
+ $var = new \SplObjectStorage();
+ $var->attach(new \stdClass());
+ $var->rewind();
+ $current = $var->current();
+
+ $this->assertDumpMatchesFormat('%A', $var);
+ $this->assertSame($current, $var->current());
+ }
+
+ public function testCastObjectStorageDumpsInfo()
+ {
+ $var = new \SplObjectStorage();
+ $var->attach(new \stdClass(), new \DateTime());
+
+ $this->assertDumpMatchesFormat('%ADateTime%A', $var);
+ }
}
diff --git a/src/Symfony/Component/Yaml/Inline.php b/src/Symfony/Component/Yaml/Inline.php
index 31a0514fd4972..5e5b1a1767ee2 100644
--- a/src/Symfony/Component/Yaml/Inline.php
+++ b/src/Symfony/Component/Yaml/Inline.php
@@ -231,6 +231,9 @@ public static function parseScalar($scalar, $delimiters = null, $stringDelimiter
if (null !== $delimiters) {
$tmp = ltrim(substr($scalar, $i), ' ');
+ if ('' === $tmp) {
+ throw new ParseException(sprintf('Unexpected end of line, expected one of "%s".', implode($delimiters)));
+ }
if (!in_array($tmp[0], $delimiters)) {
throw new ParseException(sprintf('Unexpected characters (%s).', substr($scalar, $i)));
}
diff --git a/src/Symfony/Component/Yaml/Tests/InlineTest.php b/src/Symfony/Component/Yaml/Tests/InlineTest.php
index f28f360489f66..418c7876a13c9 100644
--- a/src/Symfony/Component/Yaml/Tests/InlineTest.php
+++ b/src/Symfony/Component/Yaml/Tests/InlineTest.php
@@ -432,4 +432,13 @@ public function testTheEmptyStringIsAValidMappingKey()
{
$this->assertSame(array('' => 'foo'), Inline::parse('{ "": foo }'));
}
+
+ /**
+ * @expectedException \Symfony\Component\Yaml\Exception\ParseException
+ * @expectedExceptionMessage Unexpected end of line, expected one of ",}".
+ */
+ public function testUnfinishedInlineMap()
+ {
+ Inline::parse("{abc: 'def'");
+ }
}