diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md
index cb9b8a69c1638..1bad363eca810 100644
--- a/.github/PULL_REQUEST_TEMPLATE.md
+++ b/.github/PULL_REQUEST_TEMPLATE.md
@@ -1,6 +1,6 @@
| Q | A
| ------------- | ---
-| Branch? | 3.4 or master / 2.7, 2.8, 3.2 or 3.3
+| Branch? | 3.4 or master / 2.7, 2.8 or 3.3
| Bug fix? | yes/no
| New feature? | yes/no
| BC breaks? | yes/no
diff --git a/.travis.yml b/.travis.yml
index af674057da4b8..b7ce58bd8ffbb 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -51,15 +51,38 @@ before_install:
export PHPUNIT_X="$PHPUNIT --exclude-group tty,benchmark,intl-data"
export COMPOSER_UP='composer update --no-progress --no-suggest --ansi'
+ nanoseconds() {
+ local cmd="date"
+ local format="+%s%N"
+ local os=$(uname)
+ if hash gdate > /dev/null 2>&1; then
+ cmd="gdate"
+ elif [[ "$os" = Darwin ]]; then
+ format="+%s000000000"
+ fi
+ $cmd -u $format
+ }
+ export -f nanoseconds
+
# tfold is a helper to create folded reports
tfold () {
- title=$1
- fold=$(echo $title | sed -r 's/[^-_A-Za-z\d]+/./g')
+ local title=$1
+ local fold=$(echo $title | sed -r 's/[^-_A-Za-z0-9]+/./g')
shift
- echo -e "travis_fold:start:$fold\\n\\e[1;34m$title\\e[0m"
- bash -xc "$*" 2>&1 &&
+ local id=$(printf %08x $(( RANDOM * RANDOM )))
+ local start=$(nanoseconds)
+ echo -e "travis_fold:start:$fold"
+ echo -e "travis_time:start:$id"
+ echo -e "\\e[1;34m$title\\e[0m"
+
+ bash -xc "$*" 2>&1
+ local ok=$?
+ local end=$(nanoseconds)
+ echo -e "\\ntravis_time:end:$id:start=$start,finish=$end,duration=$(($end-$start))"
+ (exit $ok) &&
echo -e "\\e[32mOK\\e[0m $title\\n\\ntravis_fold:end:$fold" ||
- ( echo -e "\\e[41mKO\\e[0m $title\\n" && exit 1 )
+ echo -e "\\e[41mKO\\e[0m $title\\n"
+ (exit $ok)
}
export -f tfold
diff --git a/CHANGELOG-2.7.md b/CHANGELOG-2.7.md
index d08766327bc5e..f742ca8ea0385 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.34 (2017-08-28)
+
+ * bug #23989 [Debug] Remove false-positive check in DebugClassLoader (nicolas-grekas)
+ * bug #23982 [VarDumper] Strengthen dumped JS (nicolas-grekas)
+ * bug #23925 [Validator] Fix use of GroupSequenceProvider in child classes (linniksa)
+ * bug #23945 [Validator] Fix Greek translation (azhurb)
+ * bug #23909 [Console] Initialize lazily to render exceptions properly (nicolas-grekas)
+ * bug #23856 [DI] Fix dumping abstract with YamlDumper (nicolas-grekas)
+ * bug #23752 Ignore memcached missing key error on session destroy (jderusse)
+ * bug #23658 [HttpFoundation] Generate safe fallback filename for wrongly encoded filename (xelaris)
+ * bug #23783 Avoid infinite loops when profiler data is malformed (javiereguiluz)
+ * bug #23729 [Bridge\ProxyManager] Dont call __destruct() on non-instantiated services (nicolas-grekas)
+
* 2.7.33 (2017-08-01)
* bug #22244 [Console] Fix passing options with defaultCommand (Jakub Sacha)
diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md
index 1b059f5012cb7..ced9b18126294 100644
--- a/CONTRIBUTORS.md
+++ b/CONTRIBUTORS.md
@@ -7,8 +7,8 @@ Symfony is the result of the work of many people who made the code better
- Fabien Potencier (fabpot)
- Nicolas Grekas (nicolas-grekas)
- Bernhard Schussek (bschussek)
- - Tobias Schultze (tobion)
- Christian Flothmann (xabbuh)
+ - Tobias Schultze (tobion)
- Christophe Coevoet (stof)
- Jordi Boggiano (seldaek)
- Victor Berchet (victor)
@@ -37,8 +37,8 @@ Symfony is the result of the work of many people who made the code better
- Roland Franssen (ro0)
- Eriksen Costa (eriksencosta)
- Jules Pietri (heah)
- - Sarah Khalil (saro0h)
- Guilhem Niot (energetick)
+ - Sarah Khalil (saro0h)
- Jonathan Wage (jwage)
- Diego Saint Esteben (dosten)
- Alexandre Salomé (alexandresalome)
@@ -65,20 +65,20 @@ Symfony is the result of the work of many people who made the code better
- Michel Weimerskirch (mweimerskirch)
- Eric Clemmons (ericclemmons)
- Charles Sarrazin (csarrazi)
- - Christian Raue
- Konstantin Myakshin (koc)
+ - Christian Raue
+ - Dany Maillard (maidmaid)
- Arnout Boks (aboks)
+ - Jérémy DERUSSÉ (jderusse)
- Deni
- Henrik Westphal (snc)
- Dariusz Górecki (canni)
- Jáchym Toušek (enumag)
- Titouan Galopin (tgalopin)
- Douglas Greenshields (shieldo)
- - Dany Maillard (maidmaid)
- Lee McDermott
- Brandon Turner
- Luis Cordova (cordoval)
- - Jérémy DERUSSÉ (jderusse)
- Graham Campbell (graham)
- Daniel Holmes (dholmes)
- Toni Uebernickel (havvg)
@@ -87,24 +87,24 @@ Symfony is the result of the work of many people who made the code better
- Jérôme Tamarelle (gromnan)
- John Wards (johnwards)
- Dariusz Ruminski
+ - Alexander M. Turek (derrabus)
- Fran Moreno (franmomu)
- Antoine Hérault (herzult)
+ - Tobias Nyholm (tobias)
- Paráda József (paradajozsef)
- Issei Murasawa (issei_m)
- Arnaud Le Blanc (arnaud-lb)
- Maxime STEINHAUSSER
- - Alexander M. Turek (derrabus)
- Michal Piotrowski (eventhorizon)
- - Tim Nagel (merk)
- Yonel Ceruto González (yonelceruto)
+ - Tim Nagel (merk)
- Brice BERNARD (brikou)
- Baptiste Clavié (talus)
- Vladimir Reznichenko (kalessil)
- marc.weistroff
- lenar
- - Tobias Nyholm (tobias)
- - Włodzimierz Gajda (gajdaw)
- Alexander Schwenn (xelaris)
+ - Włodzimierz Gajda (gajdaw)
- Jacob Dreesen (jdreesen)
- Florian Voutzinos (florianv)
- Colin Frei
@@ -152,7 +152,9 @@ Symfony is the result of the work of many people who made the code better
- Rouven Weßling (realityking)
- Teoh Han Hui (teohhanhui)
- Clemens Tolboom
+ - Oleg Voronkovich
- Helmer Aaviksoo
+ - Lars Strojny (lstrojny)
- Hiromi Hishida (77web)
- Matthieu Ouellette-Vachon (maoueh)
- Michał Pipa (michal.pipa)
@@ -166,7 +168,6 @@ Symfony is the result of the work of many people who made the code better
- Warnar Boekkooi (boekkooi)
- Dmitrii Chekaliuk (lazyhammer)
- Clément JOBEILI (dator)
- - Lars Strojny (lstrojny)
- Possum
- Dorian Villet (gnutix)
- Richard Miller (mr_r_miller)
@@ -183,7 +184,6 @@ Symfony is the result of the work of many people who made the code better
- Daniel Espendiller
- sun (sun)
- Larry Garfield (crell)
- - Oleg Voronkovich
- Martin Schuhfuß (usefulthink)
- apetitpa
- Matthieu Bontemps (mbontemps)
@@ -334,9 +334,11 @@ Symfony is the result of the work of many people who made the code better
- Damien Alexandre (damienalexandre)
- Felix Labrecque
- Yaroslav Kiliba
+ - Amrouche Hamza
- Terje Bråten
- Robbert Klarenbeek (robbertkl)
- Thomas Calvet (fancyweb)
+ - Valentin Udaltsov (vudaltsov)
- Niels Keurentjes (curry684)
- JhonnyL
- David Badura (davidbadura)
@@ -387,6 +389,7 @@ Symfony is the result of the work of many people who made the code better
- Karel Souffriau
- Christophe L. (christophelau)
- Anthon Pang (robocoder)
+ - Jérôme Parmentier (lctrs)
- Emanuele Gaspari (inmarelibero)
- Sébastien Santoro (dereckson)
- Brian King
@@ -421,7 +424,6 @@ Symfony is the result of the work of many people who made the code better
- Dirk Pahl (dirkaholic)
- cedric lombardot (cedriclombardot)
- Jonas Flodén (flojon)
- - Amrouche Hamza
- Marcin Sikoń (marphi)
- Dominik Zogg (dominik.zogg)
- Marek Pietrzak
@@ -432,6 +434,7 @@ Symfony is the result of the work of many people who made the code better
- Zander Baldwin
- Adam Harvey
- Maxime Veber (nek-)
+ - Sanpi
- Alex Bakhturin
- Alexander Obuhovich (aik099)
- boombatower
@@ -512,6 +515,7 @@ Symfony is the result of the work of many people who made the code better
- Dave Hulbert (dave1010)
- Ivan Rey (ivanrey)
- Marcin Chyłek (songoq)
+ - Ben Scott
- Ned Schwartz
- Ziumin
- Jeremy Benoist
@@ -520,7 +524,6 @@ Symfony is the result of the work of many people who made the code better
- Benjamin Laugueux (yzalis)
- Zach Badgett (zachbadgett)
- Aurélien Fredouelle
- - Jérôme Parmentier (lctrs)
- Pavel Campr (pcampr)
- Johnny Robeson (johnny)
- Disquedur
@@ -592,7 +595,6 @@ Symfony is the result of the work of many people who made the code better
- Ulumuddin Yunus (joenoez)
- Luc Vieillescazes (iamluc)
- Johann Saunier (prophet777)
- - Valentin Udaltsov (vudaltsov)
- Michael Devery (mickadoo)
- Antoine Corcy
- Artur Eshenbrener
@@ -671,9 +673,11 @@ Symfony is the result of the work of many people who made the code better
- Andrew Hilobok (hilobok)
- Noah Heck (myesain)
- Christian Soronellas (theunic)
+ - Adam Szaraniec (mimol)
- Yosmany Garcia (yosmanyga)
- Wouter de Wild
- Degory Valentine
+ - izzyp
- Benoit Lévêque (benoit_leveque)
- Jeroen Fiege (fieg)
- Krzysiek Łabuś
@@ -709,7 +713,6 @@ Symfony is the result of the work of many people who made the code better
- Pierre Vanliefland (pvanliefland)
- Sofiane HADDAG (sofhad)
- frost-nzcr4
- - Sanpi
- Abhoryo
- Fabian Vogler (fabian)
- Korvin Szanto
@@ -742,7 +745,6 @@ Symfony is the result of the work of many people who made the code better
- Omar Yepez (oyepez003)
- mwsaz
- Jelle Kapitein
- - Ben Scott
- Benoît Bourgeois
- mantulo
- corphi
@@ -877,6 +879,7 @@ Symfony is the result of the work of many people who made the code better
- Boris Vujicic (boris.vujicic)
- Max Beutel
- Antanas Arvasevicius
+ - Maximilian Berghoff (electricmaxxx)
- nacho
- Piotr Antosik (antek88)
- Artem Lopata
@@ -910,6 +913,7 @@ Symfony is the result of the work of many people who made the code better
- Matteo Giachino (matteosister)
- Alex Demchenko (pilot)
- Tadas Gliaubicas (tadcka)
+ - Thanos Polymeneas (thanos)
- Benoit Garret
- Jakub Sacha
- DerManoMann
@@ -1098,7 +1102,6 @@ Symfony is the result of the work of many people who made the code better
- Tomaz Ahlin
- Marcus Stöhr (dafish)
- Emmanuel Vella (emmanuel.vella)
- - Adam Szaraniec (mimol)
- Carsten Nielsen (phreaknerd)
- Mathieu Rochette
- Jay Severson
@@ -1171,6 +1174,7 @@ Symfony is the result of the work of many people who made the code better
- César Suárez (csuarez)
- Nicolas Badey (nico-b)
- Shane Preece (shane)
+ - Johannes Goslar
- Geoff
- georaldc
- Malte Wunsch
@@ -1204,6 +1208,7 @@ Symfony is the result of the work of many people who made the code better
- catch
- Alexandre Segura
- Josef Cech
+ - Harold Iedema
- Arnau González (arnaugm)
- Simon Bouland (bouland)
- Matthew Foster (mfoster)
@@ -1236,7 +1241,6 @@ Symfony is the result of the work of many people who made the code better
- Dennis Væversted
- nuncanada
- flack
- - izzyp
- František Bereň
- Mike Francis
- Christoph Nissle (derstoffel)
@@ -1477,6 +1481,7 @@ Symfony is the result of the work of many people who made the code better
- Ismail Asci (ismailasci)
- Simon CONSTANS (kosssi)
- Kristof Van Cauwenbergh (kristofvc)
+ - Paulius Jarmalavičius (pjarmalavicius)
- Ramon Henrique Ornelas (ramonornela)
- Markus S. (staabm)
- Till Klampaeckel (till)
@@ -1569,11 +1574,13 @@ Symfony is the result of the work of many people who made the code better
- Matt Janssen
- Peter Gribanov
- Ben Johnson
+ - Florent Mata
- kwiateusz
- David Soria Parra
- Sergiy Sokolenko
- dinitrol
- Penny Leach
+ - Yurii K
- Richard Trebichavský
- g123456789l
- Jonathan Vollebregt
@@ -1651,6 +1658,7 @@ Symfony is the result of the work of many people who made the code better
- samuel laulhau (lalop)
- Laurent Bachelier (laurentb)
- Florent Viel (luxifer)
+ - Matthieu Mota (matthieumota)
- Matthieu Moquet (mattketmo)
- Moritz Borgmann (mborgmann)
- Michal Čihař (mcihar)
diff --git a/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/LazyLoadingValueHolderFactoryV1.php b/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/LazyLoadingValueHolderFactoryV1.php
new file mode 100644
index 0000000000000..3298b84d46278
--- /dev/null
+++ b/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/LazyLoadingValueHolderFactoryV1.php
@@ -0,0 +1,31 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bridge\ProxyManager\LazyProxy\Instantiator;
+
+use ProxyManager\Factory\LazyLoadingValueHolderFactory as BaseFactory;
+use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\LazyLoadingValueHolderGenerator;
+
+/**
+ * @internal
+ */
+class LazyLoadingValueHolderFactoryV1 extends BaseFactory
+{
+ private $generatorV1;
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getGenerator()
+ {
+ return $this->generatorV1 ?: $this->generatorV1 = new LazyLoadingValueHolderGenerator();
+ }
+}
diff --git a/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/LazyLoadingValueHolderFactoryV2.php b/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/LazyLoadingValueHolderFactoryV2.php
new file mode 100644
index 0000000000000..f41fc20b5d523
--- /dev/null
+++ b/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/LazyLoadingValueHolderFactoryV2.php
@@ -0,0 +1,32 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bridge\ProxyManager\LazyProxy\Instantiator;
+
+use ProxyManager\ProxyGenerator\ProxyGeneratorInterface;
+use ProxyManager\Factory\LazyLoadingValueHolderFactory as BaseFactory;
+use Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper\LazyLoadingValueHolderGenerator;
+
+/**
+ * @internal
+ */
+class LazyLoadingValueHolderFactoryV2 extends BaseFactory
+{
+ private $generator;
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function getGenerator(): ProxyGeneratorInterface
+ {
+ return $this->generator ?: $this->generator = new LazyLoadingValueHolderGenerator();
+ }
+}
diff --git a/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/RuntimeInstantiator.php b/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/RuntimeInstantiator.php
index 0101026794c7c..33fc49e1012d9 100644
--- a/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/RuntimeInstantiator.php
+++ b/src/Symfony/Bridge/ProxyManager/LazyProxy/Instantiator/RuntimeInstantiator.php
@@ -36,7 +36,11 @@ public function __construct()
$config = new Configuration();
$config->setGeneratorStrategy(new EvaluatingGeneratorStrategy());
- $this->factory = new LazyLoadingValueHolderFactory($config);
+ if (method_exists('ProxyManager\Version', 'getVersion')) {
+ $this->factory = new LazyLoadingValueHolderFactoryV2($config);
+ } else {
+ $this->factory = new LazyLoadingValueHolderFactoryV1($config);
+ }
}
/**
diff --git a/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/LazyLoadingValueHolderGenerator.php b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/LazyLoadingValueHolderGenerator.php
new file mode 100644
index 0000000000000..1d9432f622b41
--- /dev/null
+++ b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/LazyLoadingValueHolderGenerator.php
@@ -0,0 +1,41 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Bridge\ProxyManager\LazyProxy\PhpDumper;
+
+use ProxyManager\ProxyGenerator\LazyLoadingValueHolderGenerator as BaseGenerator;
+use Zend\Code\Generator\ClassGenerator;
+
+/**
+ * @internal
+ */
+class LazyLoadingValueHolderGenerator extends BaseGenerator
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function generate(\ReflectionClass $originalClass, ClassGenerator $classGenerator)
+ {
+ parent::generate($originalClass, $classGenerator);
+
+ if ($classGenerator->hasMethod('__destruct')) {
+ $destructor = $classGenerator->getMethod('__destruct');
+ $body = $destructor->getBody();
+ $newBody = preg_replace('/^(\$this->initializer[a-zA-Z0-9]++) && .*;\n\nreturn (\$this->valueHolder)/', '$1 || $2', $body);
+
+ if ($body === $newBody) {
+ throw new \UnexpectedValueException(sprintf('Unexpected lazy-proxy format generated for method %s::__destruct()', $originalClass->name));
+ }
+
+ $destructor->setBody($newBody);
+ }
+ }
+}
diff --git a/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php
index eb72a7d5d83cb..40791358500a0 100644
--- a/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php
+++ b/src/Symfony/Bridge/ProxyManager/LazyProxy/PhpDumper/ProxyDumper.php
@@ -13,7 +13,6 @@
use ProxyManager\Generator\ClassGenerator;
use ProxyManager\GeneratorStrategy\BaseGeneratorStrategy;
-use ProxyManager\ProxyGenerator\LazyLoadingValueHolderGenerator;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\DependencyInjection\Definition;
diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/ContainerBuilderTest.php b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/ContainerBuilderTest.php
index b634a69488a34..858e9d76b64c9 100644
--- a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/ContainerBuilderTest.php
+++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/ContainerBuilderTest.php
@@ -39,6 +39,9 @@ public function testCreateProxyServiceWithRuntimeInstantiator()
/* @var $foo1 \ProxyManager\Proxy\LazyLoadingInterface|\ProxyManager\Proxy\ValueHolderInterface */
$foo1 = $builder->get('foo1');
+ $foo1->__destruct();
+ $this->assertSame(0, $foo1::$destructorCount);
+
$this->assertSame($foo1, $builder->get('foo1'), 'The same proxy is retrieved on multiple subsequent calls');
$this->assertInstanceOf('\ProxyManagerBridgeFooClass', $foo1);
$this->assertInstanceOf('\ProxyManager\Proxy\LazyLoadingInterface', $foo1);
@@ -50,5 +53,8 @@ public function testCreateProxyServiceWithRuntimeInstantiator()
$this->assertTrue($foo1->isProxyInitialized());
$this->assertInstanceOf('\ProxyManagerBridgeFooClass', $foo1->getWrappedValueHolderValue());
$this->assertNotInstanceOf('\ProxyManager\Proxy\LazyLoadingInterface', $foo1->getWrappedValueHolderValue());
+
+ $foo1->__destruct();
+ $this->assertSame(1, $foo1::$destructorCount);
}
}
diff --git a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/includes/foo.php b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/includes/foo.php
index 16c898a370845..8ffc5be9af40a 100644
--- a/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/includes/foo.php
+++ b/src/Symfony/Bridge/ProxyManager/Tests/LazyProxy/Fixtures/includes/foo.php
@@ -2,6 +2,8 @@
class ProxyManagerBridgeFooClass
{
+ public static $destructorCount = 0;
+
public $foo;
public $moo;
@@ -38,4 +40,9 @@ public function setBar($value = null)
{
$this->bar = $value;
}
+
+ public function __destruct()
+ {
+ ++self::$destructorCount;
+ }
}
diff --git a/src/Symfony/Bundle/DebugBundle/DebugBundle.php b/src/Symfony/Bundle/DebugBundle/DebugBundle.php
index 335ec5abd2541..b00c06af78289 100644
--- a/src/Symfony/Bundle/DebugBundle/DebugBundle.php
+++ b/src/Symfony/Bundle/DebugBundle/DebugBundle.php
@@ -27,8 +27,10 @@ public function boot()
$container = $this->container;
// This code is here to lazy load the dump stack. This default
- // configuration for CLI mode is overridden in HTTP mode on
- // 'kernel.request' event
+ // configuration is overridden in CLI mode on 'console.command' event.
+ // The dump data collector is used by default, so dump output is sent to
+ // the WDT. In a CLI context, if dump is used too soon, the data collector
+ // will buffer it, and release it at the end of the script.
VarDumper::setHandler(function ($var) use ($container) {
$dumper = $container->get('data_collector.dump');
$cloner = $container->get('var_dumper.cloner');
diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php
index 2c57de4af3e9e..873b09e808729 100644
--- a/src/Symfony/Component/Console/Application.php
+++ b/src/Symfony/Component/Console/Application.php
@@ -72,6 +72,7 @@ class Application
private $dispatcher;
private $terminalDimensions;
private $defaultCommand;
+ private $initialized;
/**
* Constructor.
@@ -84,12 +85,6 @@ public function __construct($name = 'UNKNOWN', $version = 'UNKNOWN')
$this->name = $name;
$this->version = $version;
$this->defaultCommand = 'list';
- $this->helperSet = $this->getDefaultHelperSet();
- $this->definition = $this->getDefaultInputDefinition();
-
- foreach ($this->getDefaultCommands() as $command) {
- $this->add($command);
- }
}
public function setDispatcher(EventDispatcherInterface $dispatcher)
@@ -189,10 +184,11 @@ public function doRun(InputInterface $input, OutputInterface $output)
if (!$name) {
$name = $this->defaultCommand;
- $this->definition->setArguments(array_merge(
- $this->definition->getArguments(),
+ $definition = $this->getDefinition();
+ $definition->setArguments(array_merge(
+ $definition->getArguments(),
array(
- 'command' => new InputArgument('command', InputArgument::OPTIONAL, $this->definition->getArgument('command')->getDescription(), $name),
+ 'command' => new InputArgument('command', InputArgument::OPTIONAL, $definition->getArgument('command')->getDescription(), $name),
)
));
}
@@ -225,6 +221,10 @@ public function setHelperSet(HelperSet $helperSet)
*/
public function getHelperSet()
{
+ if (!$this->helperSet) {
+ $this->helperSet = $this->getDefaultHelperSet();
+ }
+
return $this->helperSet;
}
@@ -245,6 +245,10 @@ public function setDefinition(InputDefinition $definition)
*/
public function getDefinition()
{
+ if (!$this->definition) {
+ $this->definition = $this->getDefaultInputDefinition();
+ }
+
return $this->definition;
}
@@ -374,6 +378,8 @@ public function addCommands(array $commands)
*/
public function add(Command $command)
{
+ $this->init();
+
$command->setApplication($this);
if (!$command->isEnabled()) {
@@ -406,6 +412,8 @@ public function add(Command $command)
*/
public function get($name)
{
+ $this->init();
+
if (!isset($this->commands[$name])) {
throw new \InvalidArgumentException(sprintf('The command "%s" does not exist.', $name));
}
@@ -433,6 +441,8 @@ public function get($name)
*/
public function has($name)
{
+ $this->init();
+
return isset($this->commands[$name]);
}
@@ -510,6 +520,8 @@ public function findNamespace($namespace)
*/
public function find($name)
{
+ $this->init();
+
$allCommands = array_keys($this->commands);
$expr = preg_replace_callback('{([^:]+|)}', function ($matches) { return preg_quote($matches[1]).'[^:]*'; }, $name);
$commands = preg_grep('{^'.$expr.'}', $allCommands);
@@ -565,6 +577,8 @@ public function find($name)
*/
public function all($namespace = null)
{
+ $this->init();
+
if (null === $namespace) {
return $this->commands;
}
@@ -1151,4 +1165,16 @@ private function extractAllNamespaces($name)
return $namespaces;
}
+
+ private function init()
+ {
+ if ($this->initialized) {
+ return;
+ }
+ $this->initialized = true;
+
+ foreach ($this->getDefaultCommands() as $command) {
+ $this->add($command);
+ }
+ }
}
diff --git a/src/Symfony/Component/Debug/DebugClassLoader.php b/src/Symfony/Component/Debug/DebugClassLoader.php
index 8ca836bd74a2d..2094a85c4cd6a 100644
--- a/src/Symfony/Component/Debug/DebugClassLoader.php
+++ b/src/Symfony/Component/Debug/DebugClassLoader.php
@@ -26,6 +26,7 @@ class DebugClassLoader
{
private $classLoader;
private $isFinder;
+ private $loaded = array();
private $wasFinder;
private static $caseCheck;
private static $deprecated = array();
@@ -164,9 +165,10 @@ public function loadClass($class)
ErrorHandler::stackErrors();
try {
- if ($this->isFinder) {
+ if ($this->isFinder && !isset($this->loaded[$class])) {
+ $this->loaded[$class] = true;
if ($file = $this->classLoader[0]->findFile($class)) {
- require_once $file;
+ require $file;
}
} else {
call_user_func($this->classLoader, $class);
diff --git a/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php b/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php
index 133ca28e546b7..1843418e919c9 100644
--- a/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php
+++ b/src/Symfony/Component/Debug/Tests/DebugClassLoaderTest.php
@@ -59,6 +59,23 @@ public function testIdempotence()
$this->fail('DebugClassLoader did not register');
}
+ /**
+ * @expectedException \Exception
+ * @expectedExceptionMessage boo
+ */
+ public function testThrowingClass()
+ {
+ try {
+ class_exists(__NAMESPACE__.'\Fixtures\Throwing');
+ $this->fail('Exception expected');
+ } catch (\Exception $e) {
+ $this->assertSame('boo', $e->getMessage());
+ }
+
+ // the second call also should throw
+ class_exists(__NAMESPACE__.'\Fixtures\Throwing');
+ }
+
public function testUnsilencing()
{
if (\PHP_VERSION_ID >= 70000) {
@@ -128,6 +145,7 @@ class ChildTestingStacking extends TestingStacking { function foo($bar) {} }
/**
* @expectedException \RuntimeException
+ * @expectedExceptionMessage Case mismatch between loaded and declared class names
*/
public function testNameCaseMismatch()
{
@@ -149,6 +167,7 @@ class_exists(__NAMESPACE__.'\Fixtures\CaseMismatch', true);
/**
* @expectedException \RuntimeException
+ * @expectedExceptionMessage Case mismatch between loaded and declared class names
*/
public function testPsr4CaseMismatch()
{
diff --git a/src/Symfony/Component/Debug/Tests/Fixtures/Throwing.php b/src/Symfony/Component/Debug/Tests/Fixtures/Throwing.php
new file mode 100644
index 0000000000000..21e0aba17d358
--- /dev/null
+++ b/src/Symfony/Component/Debug/Tests/Fixtures/Throwing.php
@@ -0,0 +1,3 @@
+properties = $properties;
@@ -264,11 +271,24 @@ public function setProperties(array $properties)
return $this;
}
+ /**
+ * Gets the properties to define when creating the service.
+ *
+ * @return array
+ */
public function getProperties()
{
return $this->properties;
}
+ /**
+ * Sets a specific property.
+ *
+ * @param string $name
+ * @param mixed $value
+ *
+ * @return $this
+ */
public function setProperty($name, $value)
{
$this->properties[$name] = $value;
@@ -291,7 +311,7 @@ public function addArgument($argument)
}
/**
- * Sets a specific argument.
+ * Replaces a specific argument.
*
* @param int $index
* @param mixed $argument
diff --git a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php
index 810e7539fe1bd..9125a97836b6f 100644
--- a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php
+++ b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php
@@ -104,6 +104,10 @@ private function addService($id, $definition)
$code .= sprintf(" factory_class: %s\n", $this->dumper->dump($definition->getFactoryClass(false)));
}
+ if ($definition->isAbstract()) {
+ $code .= " abstract: true\n";
+ }
+
if ($definition->isLazy()) {
$code .= " lazy: true\n";
}
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php
index f19a2f5cb8346..81bbd5316c444 100644
--- a/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php
+++ b/src/Symfony/Component/DependencyInjection/Tests/Dumper/YamlDumperTest.php
@@ -12,8 +12,10 @@
namespace Symfony\Component\DependencyInjection\Tests\Dumper;
use PHPUnit\Framework\TestCase;
+use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Dumper\YamlDumper;
+use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\Yaml\Yaml;
class YamlDumperTest extends TestCase
@@ -77,6 +79,16 @@ public function testAddService()
}
}
+ public function testDumpLoad()
+ {
+ $container = new ContainerBuilder();
+ $loader = new YamlFileLoader($container, new FileLocator(self::$fixturesPath.'/yaml'));
+ $loader->load('services_dump_load.yml');
+
+ $dumper = new YamlDumper($container);
+ $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services_dump_load.yml', $dumper->dump());
+ }
+
private function assertEqualYamlStructure($yaml, $expected, $message = '')
{
$this->assertEquals(Yaml::parse($expected), Yaml::parse($yaml), $message);
diff --git a/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_dump_load.yml b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_dump_load.yml
new file mode 100644
index 0000000000000..bcf8f31b36115
--- /dev/null
+++ b/src/Symfony/Component/DependencyInjection/Tests/Fixtures/yaml/services_dump_load.yml
@@ -0,0 +1,4 @@
+
+services:
+ foo:
+ abstract: true
diff --git a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php
index bfd9527a05c83..495a4a9d14a34 100644
--- a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php
+++ b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php
@@ -353,7 +353,7 @@ public function testText()
public function testHtml()
{
$this->assertEquals('', $this->createTestCrawler()->filterXPath('//a[5]')->html());
- $this->assertEquals('', trim($this->createTestCrawler()->filterXPath('//form[@id="FooFormId"]')->html()));
+ $this->assertEquals('', trim(preg_replace('~>\s+<~', '><', $this->createTestCrawler()->filterXPath('//form[@id="FooFormId"]')->html())));
try {
$this->createTestCrawler()->filterXPath('//ol')->html();
diff --git a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php
index 0314621907356..177b708e8f054 100644
--- a/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php
+++ b/src/Symfony/Component/HttpFoundation/BinaryFileResponse.php
@@ -150,7 +150,7 @@ public function setAutoEtag()
* Sets the Content-Disposition header with the given filename.
*
* @param string $disposition ResponseHeaderBag::DISPOSITION_INLINE or ResponseHeaderBag::DISPOSITION_ATTACHMENT
- * @param string $filename Optionally use this filename instead of the real name of the file
+ * @param string $filename Optionally use this UTF-8 encoded filename instead of the real name of the file
* @param string $filenameFallback A fallback filename, containing only ASCII characters. Defaults to an automatically encoded filename
*
* @return $this
@@ -162,7 +162,7 @@ public function setContentDisposition($disposition, $filename = '', $filenameFal
}
if ('' === $filenameFallback && (!preg_match('/^[\x20-\x7e]*$/', $filename) || false !== strpos($filename, '%'))) {
- $encoding = mb_detect_encoding($filename, null, true);
+ $encoding = mb_detect_encoding($filename, null, true) ?: '8bit';
for ($i = 0, $filenameLength = mb_strlen($filename, $encoding); $i < $filenameLength; ++$i) {
$char = mb_substr($filename, $i, 1, $encoding);
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandler.php
index 962a3878d9767..4e490a05d4ce0 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandler.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandler.php
@@ -95,7 +95,9 @@ public function write($sessionId, $data)
*/
public function destroy($sessionId)
{
- return $this->memcache->delete($this->prefix.$sessionId);
+ $this->memcache->delete($this->prefix.$sessionId);
+
+ return true;
}
/**
diff --git a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php
index 76b08e2db944c..67a49ad6f5e2a 100644
--- a/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php
+++ b/src/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php
@@ -101,7 +101,9 @@ public function write($sessionId, $data)
*/
public function destroy($sessionId)
{
- return $this->memcached->delete($this->prefix.$sessionId);
+ $result = $this->memcached->delete($this->prefix.$sessionId);
+
+ return $result || $this->memcached->getResultCode() == \Memcached::RES_NOTFOUND;
}
/**
diff --git a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php
index e4607201a2151..e41a2372b9df8 100644
--- a/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php
+++ b/src/Symfony/Component/HttpFoundation/Tests/BinaryFileResponseTest.php
@@ -68,6 +68,17 @@ public function testSetContentDispositionGeneratesSafeFallbackFilename()
$this->assertSame('attachment; filename="f__.html"; filename*=utf-8\'\'f%C3%B6%C3%B6.html', $response->headers->get('Content-Disposition'));
}
+ public function testSetContentDispositionGeneratesSafeFallbackFilenameForWronglyEncodedFilename()
+ {
+ $response = new BinaryFileResponse(__FILE__);
+
+ $iso88591EncodedFilename = utf8_decode('föö.html');
+ $response->setContentDisposition(ResponseHeaderBag::DISPOSITION_ATTACHMENT, $iso88591EncodedFilename);
+
+ // the parameter filename* is invalid in this case (rawurldecode('f%F6%F6') does not provide a UTF-8 string but an ISO-8859-1 encoded one)
+ $this->assertSame('attachment; filename="f__.html"; filename*=utf-8\'\'f%F6%F6.html', $response->headers->get('Content-Disposition'));
+ }
+
/**
* @dataProvider provideRanges
*/
diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php
index 60ced9c9d646e..c14964609235c 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.33';
- const VERSION_ID = 20733;
+ const VERSION = '2.7.34';
+ const VERSION_ID = 20734;
const MAJOR_VERSION = 2;
const MINOR_VERSION = 7;
- const RELEASE_VERSION = 33;
+ const RELEASE_VERSION = 34;
const EXTRA_VERSION = '';
const END_OF_MAINTENANCE = '05/2018';
diff --git a/src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php b/src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php
index 29da4abf32ccf..045058991063d 100644
--- a/src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php
+++ b/src/Symfony/Component/HttpKernel/Profiler/FileProfilerStorage.php
@@ -144,11 +144,19 @@ public function write(Profile $profile)
}
}
+ $profileToken = $profile->getToken();
+ // when there are errors in sub-requests, the parent and/or children tokens
+ // may equal the profile token, resulting in infinite loops
+ $parentToken = $profile->getParentToken() !== $profileToken ? $profile->getParentToken() : null;
+ $childrenToken = array_filter(array_map(function ($p) use ($profileToken) {
+ return $profileToken !== $p->getToken() ? $p->getToken() : null;
+ }, $profile->getChildren()));
+
// Store profile
$data = array(
- 'token' => $profile->getToken(),
- 'parent' => $profile->getParentToken(),
- 'children' => array_map(function ($p) { return $p->getToken(); }, $profile->getChildren()),
+ 'token' => $profileToken,
+ 'parent' => $parentToken,
+ 'children' => $childrenToken,
'data' => $profile->getCollectors(),
'ip' => $profile->getIp(),
'method' => $profile->getMethod(),
diff --git a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php
index dad52401daf39..a6d6285481015 100644
--- a/src/Symfony/Component/HttpKernel/Tests/KernelTest.php
+++ b/src/Symfony/Component/HttpKernel/Tests/KernelTest.php
@@ -13,6 +13,7 @@
use PHPUnit\Framework\TestCase;
use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\HttpKernel\Bundle\BundleInterface;
use Symfony\Component\HttpKernel\Config\EnvParametersResource;
use Symfony\Component\HttpKernel\Kernel;
@@ -25,6 +26,12 @@
class KernelTest extends TestCase
{
+ public static function tearDownAfterClass()
+ {
+ $fs = new Filesystem();
+ $fs->remove(__DIR__.'/Fixtures/cache');
+ }
+
public function testConstructor()
{
$env = 'test_env';
diff --git a/src/Symfony/Component/Intl/Data/Bundle/Reader/JsonBundleReader.php b/src/Symfony/Component/Intl/Data/Bundle/Reader/JsonBundleReader.php
index 84644b9fe7f2c..90012a7ad64ab 100644
--- a/src/Symfony/Component/Intl/Data/Bundle/Reader/JsonBundleReader.php
+++ b/src/Symfony/Component/Intl/Data/Bundle/Reader/JsonBundleReader.php
@@ -32,17 +32,15 @@ public function read($path, $locale)
if (!file_exists($fileName)) {
throw new ResourceBundleNotFoundException(sprintf(
- 'The resource bundle "%s/%s.json" does not exist.',
- $path,
- $locale
+ 'The resource bundle "%s" does not exist.',
+ $fileName
));
}
if (!is_file($fileName)) {
throw new RuntimeException(sprintf(
- 'The resource bundle "%s/%s.json" is not a file.',
- $path,
- $locale
+ 'The resource bundle "%s" is not a file.',
+ $fileName
));
}
@@ -50,9 +48,8 @@ public function read($path, $locale)
if (null === $data) {
throw new RuntimeException(sprintf(
- 'The resource bundle "%s/%s.json" contains invalid JSON: %s',
- $path,
- $locale,
+ 'The resource bundle "%s" contains invalid JSON: %s',
+ $fileName,
self::getLastJsonError()
));
}
diff --git a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php
index 50ee30a217da1..ce03e9f5d6642 100644
--- a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php
+++ b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php
@@ -355,9 +355,9 @@ public function formatCurrency($value, $currency)
/**
* Format a number.
*
- * @param number $value The value to format
- * @param int $type Type of the formatting, one of the format type constants
- * Only type NumberFormatter::TYPE_DEFAULT is currently supported.
+ * @param int|float $value The value to format
+ * @param int $type Type of the formatting, one of the format type constants
+ * Only type NumberFormatter::TYPE_DEFAULT is currently supported.
*
* @return bool|string The formatted value or false on error
*
diff --git a/src/Symfony/Component/Security/Http/SecurityEvents.php b/src/Symfony/Component/Security/Http/SecurityEvents.php
index 46c8257f18e74..3bd80723d1ef5 100644
--- a/src/Symfony/Component/Security/Http/SecurityEvents.php
+++ b/src/Symfony/Component/Security/Http/SecurityEvents.php
@@ -14,8 +14,11 @@
final class SecurityEvents
{
/**
- * The INTERACTIVE_LOGIN event occurs after a user is logged in
- * interactively for authentication based on http, cookies or X509.
+ * The INTERACTIVE_LOGIN event occurs after a user has actively logged
+ * into your website. It is important to distinguish this action from
+ * non-interactive authentication methods, such as:
+ * - authentication based on your session.
+ * - authentication using a HTTP basic or HTTP digest header.
*
* The event listener method receives a
* Symfony\Component\Security\Http\Event\InteractiveLoginEvent instance.
diff --git a/src/Symfony/Component/Validator/Constraints/File.php b/src/Symfony/Component/Validator/Constraints/File.php
index b9c06bfdb142c..7756978b35216 100644
--- a/src/Symfony/Component/Validator/Constraints/File.php
+++ b/src/Symfony/Component/Validator/Constraints/File.php
@@ -18,6 +18,8 @@
* @Annotation
* @Target({"PROPERTY", "METHOD", "ANNOTATION"})
*
+ * @property int $maxSize
+ *
* @author Bernhard Schussek
*/
class File extends Constraint
diff --git a/src/Symfony/Component/Validator/Mapping/ClassMetadata.php b/src/Symfony/Component/Validator/Mapping/ClassMetadata.php
index f895ad40402dc..5b82cf6d5d9d6 100644
--- a/src/Symfony/Component/Validator/Mapping/ClassMetadata.php
+++ b/src/Symfony/Component/Validator/Mapping/ClassMetadata.php
@@ -381,6 +381,10 @@ public function addGetterMethodConstraints($property, $method, array $constraint
*/
public function mergeConstraints(ClassMetadata $source)
{
+ if ($source->isGroupSequenceProvider()) {
+ $this->setGroupSequenceProvider(true);
+ }
+
foreach ($source->getConstraints() as $constraint) {
$this->addConstraint(clone $constraint);
}
diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf
index 4fa0d42220500..a3199bcc9d79e 100644
--- a/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf
+++ b/src/Symfony/Component/Validator/Resources/translations/validators.el.xlf
@@ -100,7 +100,7 @@
This value is not valid.
- Αυτή η τιμή δεν είναι έκγυρη.
+ Αυτή η τιμή δεν είναι έγκυρη.This value is not a valid time.
@@ -136,11 +136,11 @@
This is not a valid IP address.
- Αυτό δεν είναι μια έκγυρη διεύθυνση IP.
+ Αυτό δεν είναι μια έγκυρη διεύθυνση IP.This value is not a valid language.
- Αυτή η τιμή δεν αντιστοιχεί σε μια έκγυρη γλώσσα.
+ Αυτή η τιμή δεν αντιστοιχεί σε μια έγκυρη γλώσσα.This value is not a valid locale.
@@ -148,7 +148,7 @@
This value is not a valid country.
- Αυτή η τιμή δεν αντιστοιχεί σε μια έκγυρη χώρα.
+ Αυτή η τιμή δεν αντιστοιχεί σε μια έγκυρη χώρα.This value is already used.
diff --git a/src/Symfony/Component/Validator/Tests/Fixtures/GroupSequenceProviderChildEntity.php b/src/Symfony/Component/Validator/Tests/Fixtures/GroupSequenceProviderChildEntity.php
new file mode 100644
index 0000000000000..be7191f9b6e1d
--- /dev/null
+++ b/src/Symfony/Component/Validator/Tests/Fixtures/GroupSequenceProviderChildEntity.php
@@ -0,0 +1,16 @@
+
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace Symfony\Component\Validator\Tests\Fixtures;
+
+class GroupSequenceProviderChildEntity extends GroupSequenceProviderEntity
+{
+}
diff --git a/src/Symfony/Component/Validator/Tests/Mapping/ClassMetadataTest.php b/src/Symfony/Component/Validator/Tests/Mapping/ClassMetadataTest.php
index 9a23e8cf355a0..a3f8a8c1ec8a3 100644
--- a/src/Symfony/Component/Validator/Tests/Mapping/ClassMetadataTest.php
+++ b/src/Symfony/Component/Validator/Tests/Mapping/ClassMetadataTest.php
@@ -24,6 +24,7 @@ class ClassMetadataTest extends TestCase
const CLASSNAME = 'Symfony\Component\Validator\Tests\Fixtures\Entity';
const PARENTCLASS = 'Symfony\Component\Validator\Tests\Fixtures\EntityParent';
const PROVIDERCLASS = 'Symfony\Component\Validator\Tests\Fixtures\GroupSequenceProviderEntity';
+ const PROVIDERCHILDCLASS = 'Symfony\Component\Validator\Tests\Fixtures\GroupSequenceProviderChildEntity';
protected $metadata;
@@ -301,6 +302,17 @@ public function testGroupSequenceProvider()
$this->assertTrue($metadata->isGroupSequenceProvider());
}
+ public function testMergeConstraintsMergesGroupSequenceProvider()
+ {
+ $parent = new ClassMetadata(self::PROVIDERCLASS);
+ $parent->setGroupSequenceProvider(true);
+
+ $metadata = new ClassMetadata(self::PROVIDERCHILDCLASS);
+ $metadata->mergeConstraints($parent);
+
+ $this->assertTrue($metadata->isGroupSequenceProvider());
+ }
+
/**
* https://github.com/symfony/symfony/issues/11604.
*/
@@ -309,13 +321,3 @@ public function testGetPropertyMetadataReturnsEmptyArrayWithoutConfiguredMetadat
$this->assertCount(0, $this->metadata->getPropertyMetadata('foo'), '->getPropertyMetadata() returns an empty collection if no metadata is configured for the given property');
}
}
-
-class ParentClass
-{
- public $example = 0;
-}
-
-class ChildClass extends ParentClass
-{
- public $example = 1; // overrides parent property of same name
-}
diff --git a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php
index abbe9629540ba..cd892a9687e0c 100644
--- a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php
+++ b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php
@@ -160,7 +160,8 @@ public function dump(Data $data, $output = null)
/**
* Dumps the current line.
*
- * @param int $depth The recursive depth in the dumped structure for the line being dumped
+ * @param int $depth The recursive depth in the dumped structure for the line being dumped,
+ * or -1 to signal the end-of-dump to the line dumper callable
*/
protected function dumpLine($depth)
{
diff --git a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php
index 4f572caea3f8c..28596bf83d1ce 100644
--- a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php
+++ b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php
@@ -132,10 +132,10 @@ protected function getDumpHeader()
function toggle(a, recursive) {
var s = a.nextSibling || {}, oldClass = s.className, arrow, newClass;
- if ('sf-dump-compact' == oldClass) {
+ if (/\bsf-dump-compact\b/.test(oldClass)) {
arrow = '▼';
newClass = 'sf-dump-expanded';
- } else if ('sf-dump-expanded' == oldClass) {
+ } else if (/\bsf-dump-expanded\b/.test(oldClass)) {
arrow = '▶';
newClass = 'sf-dump-compact';
} else {
@@ -143,13 +143,13 @@ function toggle(a, recursive) {
}
a.lastChild.innerHTML = arrow;
- s.className = newClass;
+ s.className = s.className.replace(/\bsf-dump-(compact|expanded)\b/, newClass);
if (recursive) {
try {
a = s.querySelectorAll('.'+oldClass);
for (s = 0; s < a.length; ++s) {
- if (a[s].className !== newClass) {
+ if (-1 == a[s].className.indexOf(newClass)) {
a[s].className = newClass;
a[s].previousSibling.lastChild.innerHTML = arrow;
}
@@ -205,7 +205,7 @@ function isCtrlKey(e) {
if (f && t && f[0] !== t[0]) {
r.innerHTML = r.innerHTML.replace(new RegExp('^'+f[0].replace(rxEsc, '\\$1'), 'mg'), t[0]);
}
- if ('sf-dump-compact' == r.className) {
+ if (/\bsf-dump-compact\b/.test(r.className)) {
toggle(s, isCtrlKey(e));
}
}
@@ -255,10 +255,10 @@ function isCtrlKey(e) {
a.title = (a.title ? a.title+'\n[' : '[')+keyHint+'+click] Expand all children';
a.innerHTML += '▼';
a.className += ' sf-dump-toggle';
- if ('sf-dump' != elt.parentNode.className) {
+ if (!/\bsf-dump\b/.test(elt.parentNode.className)) {
toggle(a);
}
- } else if ("sf-dump-ref" == elt.className && (a = elt.getAttribute('href'))) {
+ } else if (/\bsf-dump-ref\b/.test(elt.className) && (a = elt.getAttribute('href'))) {
a = a.substr(1);
elt.className += ' '+a;