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 335dfd82e4186..d08766327bc5e 100644 --- a/CHANGELOG-2.7.md +++ b/CHANGELOG-2.7.md @@ -7,6 +7,17 @@ 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.33 (2017-08-01) + + * bug #22244 [Console] Fix passing options with defaultCommand (Jakub Sacha) + * bug #23684 [Debug] Missing escape in debug output (c960657) + * bug #23662 [VarDumper] Adapt to php 7.2 changes (nicolas-grekas) + * bug #23649 [Form][TwigBridge] Don't render _method in form_rest() for a child form (fmarchalemisys) + * bug #23619 [Validator] Fix IbanValidator for ukrainian IBANs (paroe) + * bug #23238 [Security] ensure the 'route' index is set before attempting to use it (gsdevme) + * bug #23580 Fix login redirect when referer contains a query string (fabpot) + * bug #23574 [VarDumper] Move locale sniffing to dump() time (nicolas-grekas) + * 2.7.32 (2017-07-17) * security #23507 [Security] validate empty passwords again (xabbuh) diff --git a/CHANGELOG-2.8.md b/CHANGELOG-2.8.md index 5fdc52f111daa..abb1235519a77 100644 --- a/CHANGELOG-2.8.md +++ b/CHANGELOG-2.8.md @@ -7,6 +7,19 @@ in 2.8 minor versions. To get the diff for a specific change, go to https://github.com/symfony/symfony/commit/XXX where XXX is the change hash To get the diff between two versions, go to https://github.com/symfony/symfony/compare/v2.8.0...v2.8.1 +* 2.8.27 (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.8.26 (2017-08-01) * bug #22244 [Console] Fix passing options with defaultCommand (Jakub Sacha) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 47a6cf9986dcf..1b059f5012cb7 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -20,11 +20,11 @@ Symfony is the result of the work of many people who made the code better - Javier Eguiluz (javier.eguiluz) - Hugo Hamon (hhamon) - Maxime Steinhausser (ogizanagi) - - Abdellatif Ait boudad (aitboudad) - Robin Chalas (chalas_r) + - Abdellatif Ait boudad (aitboudad) + - Grégoire Pineau (lyrixx) - Romain Neutron (romain) - Pascal Borreli (pborreli) - - Grégoire Pineau (lyrixx) - Wouter De Jong (wouterj) - Joseph Bielawski (stloyd) - Karma Dordrak (drak) @@ -34,8 +34,8 @@ Symfony is the result of the work of many people who made the code better - Jean-François Simon (jfsimon) - Benjamin Eberlei (beberlei) - Igor Wiedler (igorw) - - Eriksen Costa (eriksencosta) - Roland Franssen (ro0) + - Eriksen Costa (eriksencosta) - Jules Pietri (heah) - Sarah Khalil (saro0h) - Guilhem Niot (energetick) @@ -66,6 +66,7 @@ Symfony is the result of the work of many people who made the code better - Eric Clemmons (ericclemmons) - Charles Sarrazin (csarrazi) - Christian Raue + - Konstantin Myakshin (koc) - Arnout Boks (aboks) - Deni - Henrik Westphal (snc) @@ -73,7 +74,7 @@ Symfony is the result of the work of many people who made the code better - Jáchym Toušek (enumag) - Titouan Galopin (tgalopin) - Douglas Greenshields (shieldo) - - Konstantin Myakshin (koc) + - Dany Maillard (maidmaid) - Lee McDermott - Brandon Turner - Luis Cordova (cordoval) @@ -89,23 +90,22 @@ Symfony is the result of the work of many people who made the code better - Fran Moreno (franmomu) - Antoine Hérault (herzult) - Paráda József (paradajozsef) + - Issei Murasawa (issei_m) - Arnaud Le Blanc (arnaud-lb) - Maxime STEINHAUSSER - Alexander M. Turek (derrabus) - Michal Piotrowski (eventhorizon) - - Dany Maillard (maidmaid) - - Issei Murasawa (issei_m) - Tim Nagel (merk) + - Yonel Ceruto González (yonelceruto) - Brice BERNARD (brikou) - Baptiste Clavié (talus) - Vladimir Reznichenko (kalessil) - marc.weistroff - - Yonel Ceruto González (yonelceruto) - lenar + - Tobias Nyholm (tobias) - Włodzimierz Gajda (gajdaw) - Alexander Schwenn (xelaris) - Jacob Dreesen (jdreesen) - - Tobias Nyholm (tobias) - Florian Voutzinos (florianv) - Colin Frei - Adrien Brault (adrienbrault) @@ -132,13 +132,13 @@ Symfony is the result of the work of many people who made the code better - Daniel Gomes (danielcsgomes) - Hidenori Goto (hidenorigoto) - Guilherme Blanco (guilhermeblanco) + - David Maicher (dmaicher) - Pablo Godel (pgodel) - Jérémie Augustin (jaugustin) - Andréia Bohner (andreia) - Rafael Dohms (rdohms) - Arnaud Kleinpeter (nanocom) - jwdeitch - - David Maicher (dmaicher) - Mikael Pajunen - Joel Wurtz (brouznouf) - Jérôme Vasseur (jvasseur) @@ -175,6 +175,7 @@ Symfony is the result of the work of many people who made the code better - Dennis Benkert (denderello) - Benjamin Dulau (dbenjamin) - Mathieu Lemoine (lemoinem) + - Christian Schmidt - Andreas Hucks (meandmymonkey) - Noel Guilbert (noel) - Stepan Anchugov (kix) @@ -200,7 +201,6 @@ Symfony is the result of the work of many people who made the code better - John Kary (johnkary) - Justin Hileman (bobthecow) - Blanchon Vincent (blanchonvincent) - - Christian Schmidt - Michele Orselli (orso) - Tom Van Looy (tvlooy) - Sven Paulus (subsven) @@ -236,6 +236,7 @@ Symfony is the result of the work of many people who made the code better - Katsuhiro OGAWA - Patrick McDougle (patrick-mcdougle) - Alif Rachmawadi + - Alessandro Chitolina - Kristen Gilden (kgilden) - Pierre-Yves LEBECQ (pylebecq) - Jordan Samouh (jordansamouh) @@ -261,6 +262,8 @@ Symfony is the result of the work of many people who made the code better - Pavel Batanov (scaytrase) - Nikita Konstantinov - Wodor Wodorski + - Rob Frawley 2nd (robfrawley) + - Gregor Harlan (gharlan) - Thomas Lallement (raziel057) - Giorgio Premi - Matthieu Napoli (mnapoli) @@ -276,7 +279,6 @@ Symfony is the result of the work of many people who made the code better - Marc Weistroff (futurecat) - Christian Schmidt - Hidde Wieringa (hiddewie) - - Alessandro Chitolina - Chad Sikorra (chadsikorra) - Chris Smith (cs278) - Florian Klein (docteurklein) @@ -313,7 +315,6 @@ Symfony is the result of the work of many people who made the code better - Thierry Thuon (lepiaf) - Ricard Clau (ricardclau) - Mark Challoner (markchalloner) - - Gregor Harlan (gharlan) - Gennady Telegin (gtelegin) - Ben Davies (bendavies) - Erin Millard @@ -322,7 +323,6 @@ Symfony is the result of the work of many people who made the code better - Magnus Nordlander (magnusnordlander) - alquerci - Francesco Levorato - - Rob Frawley 2nd (robfrawley) - Vitaliy Zakharov (zakharovvi) - Tobias Sjösten (tobiassjosten) - Gyula Sallai (salla) @@ -339,6 +339,7 @@ Symfony is the result of the work of many people who made the code better - Thomas Calvet (fancyweb) - Niels Keurentjes (curry684) - JhonnyL + - David Badura (davidbadura) - hossein zolfi (ocean) - Clément Gautier (clementgautier) - Eduardo Gulias (egulias) @@ -428,7 +429,6 @@ Symfony is the result of the work of many people who made the code better - Christian Wahler - Gintautas Miselis - Rob Bast - - David Badura (davidbadura) - Zander Baldwin - Adam Harvey - Maxime Veber (nek-) @@ -543,6 +543,7 @@ Symfony is the result of the work of many people who made the code better - Max Rath (drak3) - Stéphane Escandell (sescandell) - Konstantin S. M. Möllers (ksmmoellers) + - James Johnston - Sinan Eldem - Alexandre Dupuy (satchette) - Andre Rømcke (andrerom) @@ -591,6 +592,7 @@ 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 @@ -909,6 +911,7 @@ Symfony is the result of the work of many people who made the code better - Alex Demchenko (pilot) - Tadas Gliaubicas (tadcka) - Benoit Garret + - Jakub Sacha - DerManoMann - Olaf Klischat - orlovv @@ -1173,6 +1176,7 @@ Symfony is the result of the work of many people who made the code better - Malte Wunsch - wusuopu - povilas + - Gavin Staniforth - Alessandro Tagliapietra (alex88) - Biji (biji) - Gunnar Lium (gunnarlium) @@ -1234,6 +1238,7 @@ Symfony is the result of the work of many people who made the code better - flack - izzyp - František Bereň + - Mike Francis - Christoph Nissle (derstoffel) - Ionel Scutelnicu (ionelscutelnicu) - Nicolas Tallefourtané (nicolab) @@ -1244,6 +1249,7 @@ Symfony is the result of the work of many people who made the code better - jjanvier - Julius Beckmann - Romain Dorgueil + - Christopher Parotat - Grayson Koonce (breerly) - Fabien LUCAS (flucas2) - Indra Gunawan (indragunawan) @@ -1535,11 +1541,13 @@ Symfony is the result of the work of many people who made the code better - Ladislav Tánczos - Brian Freytag - Skorney + - fmarchalemisys - mieszko4 - Steve Preston - Neophy7e - bokonet - Arrilot + - Shaun Simmons - Markus Staab - Pierre-Louis LAUNAY - djama @@ -1568,6 +1576,7 @@ Symfony is the result of the work of many people who made the code better - Penny Leach - Richard Trebichavský - g123456789l + - Jonathan Vollebregt - oscartv - DanSync - Peter Zwosta @@ -1680,7 +1689,6 @@ Symfony is the result of the work of many people who made the code better - Moritz Kraft (userfriendly) - Víctor Mateo (victormateo) - Vincent (vincent1870) - - Valentin Udaltsov (vudaltsov) - Eugene Babushkin (warl) - Wouter Sioen (wouter_sioen) - Xavier Amado (xamado) @@ -1702,6 +1710,7 @@ Symfony is the result of the work of many people who made the code better - Sergey Fedotov - Michael - fh-github@fholzhauer.de + - AbdElKader Bouadjadja - Jan Emrich - Mark Topper - Xavier REN diff --git a/UPGRADE-2.8.md b/UPGRADE-2.8.md index 1d299af3e63a4..64a31dde75600 100644 --- a/UPGRADE-2.8.md +++ b/UPGRADE-2.8.md @@ -547,6 +547,95 @@ Security * The `VoterInterface::supportsClass` and `supportsAttribute` methods were deprecated and will be removed from the interface in 3.0. + * The `key` setting of `anonymous`, `remember_me` and `http_digest` is + deprecated, and will be removed in 3.0. Use `secret` instead. + + Before: + + ```yaml + security: + # ... + firewalls: + default: + # ... + anonymous: { key: "%secret%" } + remember_me: + key: "%secret%" + http_digest: + key: "%secret%" + ``` + + ```xml + + + + + + + + + + + + + ``` + + ```php + // ... + $container->loadFromExtension('security', array( + // ... + 'firewalls' => array( + // ... + 'anonymous' => array('key' => '%secret%'), + 'remember_me' => array('key' => '%secret%'), + 'http_digest' => array('key' => '%secret%'), + ), + )); + ``` + + After: + + ```yaml + security: + # ... + firewalls: + default: + # ... + anonymous: { secret: "%secret%" } + remember_me: + secret: "%secret%" + http_digest: + secret: "%secret%" + ``` + + ```xml + + + + + + + + + + + + + ``` + + ```php + // ... + $container->loadFromExtension('security', array( + // ... + 'firewalls' => array( + // ... + 'anonymous' => array('secret' => '%secret%'), + 'remember_me' => array('secret' => '%secret%'), + 'http_digest' => array('secret' => '%secret%'), + ), + )); + ``` + * The `intention` option is deprecated for all the authentication listeners, and will be removed in 3.0. Use the `csrf_token_id` option instead. 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 417d94e47215e..3db1ac7ebae75 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 6dfa571a31822..f110f815478cf 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -75,6 +75,7 @@ class Application private $dispatcher; private $terminalDimensions; private $defaultCommand; + private $initialized; /** * Constructor. @@ -87,12 +88,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) @@ -192,10 +187,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), ) )); } @@ -228,6 +224,10 @@ public function setHelperSet(HelperSet $helperSet) */ public function getHelperSet() { + if (!$this->helperSet) { + $this->helperSet = $this->getDefaultHelperSet(); + } + return $this->helperSet; } @@ -248,6 +248,10 @@ public function setDefinition(InputDefinition $definition) */ public function getDefinition() { + if (!$this->definition) { + $this->definition = $this->getDefaultInputDefinition(); + } + return $this->definition; } @@ -377,6 +381,8 @@ public function addCommands(array $commands) */ public function add(Command $command) { + $this->init(); + $command->setApplication($this); if (!$command->isEnabled()) { @@ -409,6 +415,8 @@ public function add(Command $command) */ public function get($name) { + $this->init(); + if (!isset($this->commands[$name])) { throw new CommandNotFoundException(sprintf('The command "%s" does not exist.', $name)); } @@ -436,6 +444,8 @@ public function get($name) */ public function has($name) { + $this->init(); + return isset($this->commands[$name]); } @@ -513,6 +523,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); @@ -568,6 +580,8 @@ public function find($name) */ public function all($namespace = null) { + $this->init(); + if (null === $namespace) { return $this->commands; } @@ -1157,4 +1171,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 a6a5cd7af09d3..8b6b4b7f2e750 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 196b92c884598..c82c07543a404 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; @@ -272,11 +279,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; @@ -299,7 +319,7 @@ public function addArgument($argument) } /** - * Sets a specific argument. + * Replaces a specific argument. * * @param int $index * @param mixed $argument @@ -854,7 +874,7 @@ public function isAutowired() } /** - * Sets autowired. + * Enables/disables autowiring. * * @param bool $autowired * diff --git a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php index f966b823486fd..9e59ba32e28c6 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/YamlDumper.php @@ -120,6 +120,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 43734f7216df7..e61eca1d0151d 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 @@ -84,6 +86,16 @@ public function testDumpAutowireData() $this->assertStringEqualsFile(self::$fixturesPath.'/yaml/services24.yml', $dumper->dump()); } + 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 827570fb60e48..f002627ef5942 100644 --- a/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php +++ b/src/Symfony/Component/DomCrawler/Tests/CrawlerTest.php @@ -373,7 +373,7 @@ public function testText() public function testHtml() { $this->assertEquals('Bar', $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 118d67aaec835..89aaa72cf9a35 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,11 +59,11 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.8.26'; - const VERSION_ID = 20826; + const VERSION = '2.8.27'; + const VERSION_ID = 20827; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; - const RELEASE_VERSION = 26; + const RELEASE_VERSION = 27; const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '11/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 84b20abf77ee8..4521b06d43936 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, json_last_error_msg() )); } diff --git a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php index 11d09363c5a9f..4ed96cee9accb 100644 --- a/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php +++ b/src/Symfony/Component/Intl/NumberFormatter/NumberFormatter.php @@ -357,9 +357,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/Guard/GuardAuthenticatorInterface.php b/src/Symfony/Component/Security/Guard/GuardAuthenticatorInterface.php index fef4a04fb9702..307d70f9e973e 100644 --- a/src/Symfony/Component/Security/Guard/GuardAuthenticatorInterface.php +++ b/src/Symfony/Component/Security/Guard/GuardAuthenticatorInterface.php @@ -153,6 +153,7 @@ public function onAuthenticationSuccess(Request $request, TokenInterface $token, * done by having a _remember_me checkbox in your form, but * can be configured by the "always_remember_me" and "remember_me_parameter" * parameters under the "remember_me" firewall key + * D) The onAuthenticationSuccess method returns a Response object * * @return bool */ 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 341fbaf440775..c4147f853728a 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 d5a9c2c9ebc1c..b6f3f6e2de63c 100644 --- a/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/AbstractDumper.php @@ -139,7 +139,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 55d199ebe1ddd..acc27b96d6ef1 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; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy