From 63cd219a5c5339218c73485d9ebe9fc6ff55ec14 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Sun, 25 Nov 2018 16:28:24 +0100 Subject: [PATCH 01/22] =?UTF-8?q?[Console]=C2=A0Move=20back=20root=20excep?= =?UTF-8?q?tion=20to=20stack=20trace=20in=20verbose=20mode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Symfony/Component/Console/Application.php | 7 +++++++ .../Component/Console/Tests/ApplicationTest.php | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Symfony/Component/Console/Application.php b/src/Symfony/Component/Console/Application.php index 1d415636fc3d8..680036041019b 100644 --- a/src/Symfony/Component/Console/Application.php +++ b/src/Symfony/Component/Console/Application.php @@ -783,6 +783,13 @@ protected function doRenderException(\Exception $e, OutputInterface $output) // exception related properties $trace = $e->getTrace(); + array_unshift($trace, array( + 'function' => '', + 'file' => $e->getFile() ?: 'n/a', + 'line' => $e->getLine() ?: 'n/a', + 'args' => array(), + )); + for ($i = 0, $count = \count($trace); $i < $count; ++$i) { $class = isset($trace[$i]['class']) ? $trace[$i]['class'] : ''; $type = isset($trace[$i]['type']) ? $trace[$i]['type'] : ''; diff --git a/src/Symfony/Component/Console/Tests/ApplicationTest.php b/src/Symfony/Component/Console/Tests/ApplicationTest.php index faa98e5f5fac6..7922ce273bbd6 100644 --- a/src/Symfony/Component/Console/Tests/ApplicationTest.php +++ b/src/Symfony/Component/Console/Tests/ApplicationTest.php @@ -776,6 +776,20 @@ public function testRenderExceptionLineBreaks() $this->assertStringMatchesFormatFile(self::$fixturesPath.'/application_renderexception_linebreaks.txt', $tester->getDisplay(true), '->renderException() keep multiple line breaks'); } + public function testRenderExceptionStackTraceContainsRootException() + { + $application = new Application(); + $application->setAutoExit(false); + $application->register('foo')->setCode(function () { + throw new \Exception('Verbose exception'); + }); + + $tester = new ApplicationTester($application); + $tester->run(array('command' => 'foo'), array('decorated' => false, 'verbosity' => Output::VERBOSITY_VERBOSE)); + + $this->assertContains(sprintf('() at %s:', __FILE__), $tester->getDisplay()); + } + public function testRun() { $application = new Application(); From 1c548442858d083e68fcc4a8163ef9168f14f273 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 26 Nov 2018 14:20:12 +0100 Subject: [PATCH 02/22] updated CHANGELOG for 2.8.48 --- CHANGELOG-2.8.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG-2.8.md b/CHANGELOG-2.8.md index 358b477b1467b..aa884108b6dd5 100644 --- a/CHANGELOG-2.8.md +++ b/CHANGELOG-2.8.md @@ -7,6 +7,21 @@ 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.48 (2018-11-26) + + * bug #28917 [DoctrineBridge] catch errors while converting to db values in data collector (alekitto) + * bug #27314 [DoctrineBridge] fix case sensitivity issue in RememberMe\DoctrineTokenProvider (PF4Public) + * bug #29308 [Translation] Use XLIFF source rather than resname when there's no target (thewilkybarkid) + * bug #26244 [BrowserKit] fixed BC Break for HTTP_HOST header (brizzz) + * bug #28147 [DomCrawler] exclude fields inside "template" tags (Gorjunov) + * bug #29271 [HttpFoundation] Fix trailing space for mime-type with parameters (Sascha Dens) + * bug #29223 [Validator] Added the missing constraints instance checks (thomasbisignani) + * bug #29182 [Form] Fixed empty data for compound date types (HeahDude) + * bug #29185 [Form] Fixed keeping hash of equal \DateTimeInterface on submit (HeahDude) + * bug #28731 [Form] invalidate forms on transformation failures (xabbuh) + * bug #29152 [Config] Unset key during normalization (ro0NL) + * bug #29057 [HttpFoundation] replace any preexisting Content-Type headers (nicolas-grekas) + * 2.8.47 (2018-11-03) * bug #29020 Fix ini_get() for boolean values (deguif) From a84a4488646ced1f468838fabad0c57bc2d1b973 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 26 Nov 2018 14:20:17 +0100 Subject: [PATCH 03/22] update CONTRIBUTORS for 2.8.48 --- CONTRIBUTORS.md | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 969c6a424cefc..1c329f2146c3e 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -14,9 +14,9 @@ Symfony is the result of the work of many people who made the code better - Victor Berchet (victor) - Robin Chalas (chalas_r) - Kévin Dunglas (dunglas) + - Maxime Steinhausser (ogizanagi) - Jakub Zalas (jakubzalas) - Johannes S (johannes) - - Maxime Steinhausser (ogizanagi) - Kris Wallsmith (kriswallsmith) - Ryan Weaver (weaverryan) - Javier Eguiluz (javier.eguiluz) @@ -37,8 +37,8 @@ Symfony is the result of the work of many people who made the code better - Benjamin Eberlei (beberlei) - Igor Wiedler (igorw) - Jules Pietri (heah) - - Eriksen Costa (eriksencosta) - Yonel Ceruto (yonelceruto) + - Eriksen Costa (eriksencosta) - Guilhem Niot (energetick) - Sarah Khalil (saro0h) - Jonathan Wage (jwage) @@ -70,6 +70,7 @@ Symfony is the result of the work of many people who made the code better - Gábor Egyed (1ed) - Mathieu Piot (mpiot) - Titouan Galopin (tgalopin) + - Vladimir Reznichenko (kalessil) - Michel Weimerskirch (mweimerskirch) - Andrej Hudec (pulzarraider) - Konstantin Myakshin (koc) @@ -77,7 +78,6 @@ Symfony is the result of the work of many people who made the code better - Jáchym Toušek (enumag) - Charles Sarrazin (csarrazi) - David Maicher (dmaicher) - - Vladimir Reznichenko (kalessil) - Christian Raue - Issei Murasawa (issei_m) - Arnout Boks (aboks) @@ -86,13 +86,13 @@ Symfony is the result of the work of many people who made the code better - Dariusz Górecki (canni) - Douglas Greenshields (shieldo) - Dariusz Ruminski + - Grégoire Paris (greg0ire) - Lee McDermott - Brandon Turner - Luis Cordova (cordoval) - Graham Campbell (graham) - Daniel Holmes (dholmes) - Toni Uebernickel (havvg) - - Grégoire Paris (greg0ire) - Bart van den Burg (burgov) - Jordan Alliot (jalliot) - Jérôme Tamarelle (gromnan) @@ -113,12 +113,12 @@ Symfony is the result of the work of many people who made the code better - lenar - Alexander Schwenn (xelaris) - Włodzimierz Gajda (gajdaw) + - Tomáš Votruba (tomas_votruba) - Peter Kokot (maastermedia) - Jacob Dreesen (jdreesen) - Florian Voutzinos (florianv) - Colin Frei - Adrien Brault (adrienbrault) - - Tomáš Votruba (tomas_votruba) - Joshua Thijssen - excelwebzone - Gordon Franke (gimler) @@ -179,6 +179,7 @@ Symfony is the result of the work of many people who made the code better - jeremyFreeAgent (Jérémy Romey) (jeremyfreeagent) - James Halsall (jaitsu) - Matthieu Napoli (mnapoli) + - Florent Mata (fmata) - Warnar Boekkooi (boekkooi) - Alessandro Chitolina (alekitto) - Dmitrii Chekaliuk (lazyhammer) @@ -193,7 +194,6 @@ Symfony is the result of the work of many people who made the code better - Dennis Benkert (denderello) - DQNEO - Benjamin Dulau (dbenjamin) - - Florent Mata (fmata) - Mathieu Lemoine (lemoinem) - Thomas Calvet (fancyweb) - Christian Schmidt @@ -258,6 +258,7 @@ Symfony is the result of the work of many people who made the code better - Benoît Burnichon (bburnichon) - Roman Marintšenko (inori) - Xavier Montaña Carreras (xmontana) + - François-Xavier de Guillebon (de-gui_f) - Mickaël Andrieu (mickaelandrieu) - Maxime Veber (nek-) - Xavier Perez @@ -294,7 +295,9 @@ Symfony is the result of the work of many people who made the code better - Thomas Lallement (raziel057) - mcfedr (mcfedr) - Colin O'Dell (colinodell) + - Fabien Bourigault (fbourigault) - Giorgio Premi + - Jan Schädlich (jschaedl) - Beau Simensen (simensen) - Michael Hirschler (mvhirsch) - Robert Kiss (kepten) @@ -305,8 +308,8 @@ Symfony is the result of the work of many people who made the code better - Jérôme Parmentier (lctrs) - Michael Babker (mbabker) - Peter Kruithof (pkruithof) - - François-Xavier de Guillebon (de-gui_f) - Michael Holm (hollo) + - Remon van de Kamp (rpkamp) - Marc Weistroff (futurecat) - Christian Schmidt - MatTheCat @@ -350,8 +353,6 @@ Symfony is the result of the work of many people who made the code better - Ricard Clau (ricardclau) - Mark Challoner (markchalloner) - Gennady Telegin (gtelegin) - - Jan Schädlich (jschaedl) - - Fabien Bourigault (fbourigault) - Ben Davies (bendavies) - Erin Millard - Artur Melo (restless) @@ -445,6 +446,7 @@ Symfony is the result of the work of many people who made the code better - lancergr - Zan Baldwin - Mihai Stancu + - Ivan Nikolaev (destillat) - Olivier Dolbeau (odolbeau) - Jan Rosier (rosier) - Alessandro Lai (jean85) @@ -461,7 +463,6 @@ Symfony is the result of the work of many people who made the code better - Boris Vujicic (boris.vujicic) - Chris Sedlmayr (catchamonkey) - Mateusz Sip (mateusz_sip) - - Remon van de Kamp - Kamil Kokot (pamil) - Seb Koelen - Christoph Mewes (xrstf) @@ -470,6 +471,7 @@ 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) + - Gonzalo Vilaseca (gonzalovilaseca) - Marcin Sikoń (marphi) - Dominik Zogg (dominik.zogg) - Marek Pietrzak @@ -643,7 +645,6 @@ Symfony is the result of the work of many people who made the code better - adev - Stefan Warman - Arkadius Stefanski (arkadius) - - Gonzalo Vilaseca (gonzalovilaseca) - Tristan Maindron (tmaindron) - Wesley Lancel - Ke WANG (yktd26) @@ -665,6 +666,7 @@ Symfony is the result of the work of many people who made the code better - Sergey (upyx) - Michael Devery (mickadoo) - Antoine Corcy + - Dmitrii Poddubnyi (karser) - Sascha Grossenbacher - Szijarto Tamas - Robin Lehrmann (robinlehrmann) @@ -804,7 +806,6 @@ Symfony is the result of the work of many people who made the code better - Sofiane HADDAG (sofhad) - frost-nzcr4 - Bozhidar Hristov - - Ivan Nikolaev (destillat) - Laurent Bassin (lbassin) - andrey1s - Abhoryo @@ -989,6 +990,7 @@ Symfony is the result of the work of many people who made the code better - Mathieu Santostefano - Arjan Keeman - Máximo Cuadros (mcuadros) + - Lukas Mencl - tamirvs - julien.galenski - Christian Neff @@ -1290,6 +1292,7 @@ Symfony is the result of the work of many people who made the code better - Adrien Samson (adriensamson) - Samuel Gordalina (gordalina) - Max Romanovsky (maxromanovsky) + - Nicolas Eeckeloo (neeckeloo) - Mathieu Morlon - Daniel Tschinder - Arnaud CHASSEUX @@ -1351,6 +1354,7 @@ Symfony is the result of the work of many people who made the code better - Andrew (drew) - kor3k kor3k (kor3k) - Stelian Mocanita (stelian) + - Thomas Bisignani (toma) - Justin (wackymole) - Flavian (2much) - Gautier Deuette @@ -1448,6 +1452,7 @@ Symfony is the result of the work of many people who made the code better - Phobetor - Andreas - Markus + - Daniel Gorgan - Thomas Chmielowiec - shdev - Andrey Ryaguzov @@ -1499,6 +1504,7 @@ Symfony is the result of the work of many people who made the code better - David Barratt - Pavel.Batanov - avi123 + - Pavel Prischepa - alsar - downace - Aarón Nieves Fernández @@ -1613,6 +1619,7 @@ Symfony is the result of the work of many people who made the code better - David Zuelke - Adrian - Oleg Andreyev + - neFAST - Pierre Rineau - Maxim Lovchikov - adenkejawen @@ -1710,7 +1717,6 @@ Symfony is the result of the work of many people who made the code better - Giovanni Albero (johntree) - Jorge Martin (jorgemartind) - Joeri Verdeyen (jverdeyen) - - Dmitrii Poddubnyi (karser) - Kevin Verschaeve (keversc) - Kevin Herrera (kherge) - Luis Ramón López López (lrlopez) @@ -1872,6 +1878,7 @@ Symfony is the result of the work of many people who made the code better - zorn - Yuriy Potemkin - Emilie Lorenzo + - Edvin Hultberg - Benjamin Long - Matt Janssen - Ben Miller @@ -1992,6 +1999,7 @@ Symfony is the result of the work of many people who made the code better - Alex Carol (picard89) - Daniel Perez Pinazo (pitiflautico) - Phil Taylor (prazgod) + - Maxim Pustynnikov (pustynnikov) - Brayden Williams (redstar504) - Rich Sage (richsage) - Rokas Mikalkėnas (rokasm) From a1a21f97a2189944b3b1907ac8b733df01a4132a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 26 Nov 2018 14:20:43 +0100 Subject: [PATCH 04/22] updated VERSION for 2.8.48 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index e91c1d7d4712a..b35ddef8b1cc4 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -59,12 +59,12 @@ abstract class Kernel implements KernelInterface, TerminableInterface protected $startTime; protected $loadClassCache; - const VERSION = '2.8.48-DEV'; + const VERSION = '2.8.48'; const VERSION_ID = 20848; const MAJOR_VERSION = 2; const MINOR_VERSION = 8; const RELEASE_VERSION = 48; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '11/2018'; const END_OF_LIFE = '11/2019'; From 70e05c643fe1a982e412a3e4ac0b3b35283ffba2 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 26 Nov 2018 15:04:35 +0100 Subject: [PATCH 05/22] updated CHANGELOG for 3.4.19 --- CHANGELOG-3.4.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/CHANGELOG-3.4.md b/CHANGELOG-3.4.md index 1f2a2de81d321..dcd1c3bf06293 100644 --- a/CHANGELOG-3.4.md +++ b/CHANGELOG-3.4.md @@ -7,6 +7,44 @@ in 3.4 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/v3.4.0...v3.4.1 +* 3.4.19 (2018-11-26) + + * bug #29318 [Console] Move back root exception to stack trace in verbose mode (chalasr) + * bug #29332 [PropertyAccess] make cache keys encoding bijective (nicolas-grekas) + * bug #29297 [Routing] fix trailing slash redirection when using RedirectableUrlMatcher (nicolas-grekas) + * bug #29313 [PropertyAccessor] fix encoding of cache keys (nicolas-grekas) + * bug #28917 [DoctrineBridge] catch errors while converting to db values in data collector (alekitto) + * bug #29317 [WebProfiler] Detect non-file paths in file viewer (ro0NL) + * bug #29305 [EventDispatcher] Unwrap wrapped listeners internally (ro0NL) + * bug #27314 [DoctrineBridge] fix case sensitivity issue in RememberMe\DoctrineTokenProvider (PF4Public) + * bug #29308 [Translation] Use XLIFF source rather than resname when there's no target (thewilkybarkid) + * bug #26244 [BrowserKit] fixed BC Break for HTTP_HOST header (brizzz) + * bug #28147 [DomCrawler] exclude fields inside "template" tags (Gorjunov) + * bug #29222 [Dotenv] properly parse backslashes in unquoted env vars (xabbuh) + * bug #29256 [HttpFoundation] Fixed absolute Request URI with default port (thomasbisignani) + * bug #29274 [Routing] Remove duplicate schemes and methods for invokable controllers (claudusd) + * bug #29271 [HttpFoundation] Fix trailing space for mime-type with parameters (Sascha Dens) + * bug #29243 [Cache] fix optimizing Psr6Cache for AdapterInterface pools (nicolas-grekas) + * bug #29247 [DI] fix taking lazy services into account when dumping the container (nicolas-grekas) + * bug #29249 [Form] Fixed empty data for compound date interval (HeahDude) + * bug #29265 [Bridge/PhpUnit] Use composer to download phpunit (nicolas-grekas) + * bug #28769 [FrameworkBundle] deal with explicitly enabled workflow nodes (xabbuh) + * bug #29223 [Validator] Added the missing constraints instance checks (thomasbisignani) + * bug #28966 [PropertyAccessor] Fix unable to write to singular property using setter while plural adder/remover exist (karser) + * bug #29182 [Form] Fixed empty data for compound date types (HeahDude) + * bug #29185 [Form] Fixed keeping hash of equal \DateTimeInterface on submit (HeahDude) + * bug #29137 [Workflow][FrameworkBundle] fixed guard event names for transitions (destillat, lyrixx) + * bug #28731 [Form] invalidate forms on transformation failures (xabbuh) + * bug #29152 [Config] Unset key during normalization (ro0NL) + * bug #29165 [DI] align IniFileLoader to PHP bugfix #76965 (nicolas-grekas) + * bug #29115 Change button_widget class to btn-primary (neFAST) + * bug #29131 [Dotenv] dont use getenv() to read SYMFONY_DOTENV_VARS (nicolas-grekas) + * bug #29057 [HttpFoundation] replace any preexisting Content-Type headers (nicolas-grekas) + * bug #29104 [DI] fix dumping inlined services (nicolas-grekas) + * bug #29054 [VarDumper] fix dump of closures created from callables (nicolas-grekas) + * bug #29102 [DI] fix GraphvizDumper ignoring inline definitions (nicolas-grekas) + * bug #29107 [DI] dont track classes/interfaces used to compute autowiring error messages (nicolas-grekas) + * 3.4.18 (2018-11-03) * bug #28820 [DependencyInjection] Fix tags on multiple decorated service (Soner Sayakci) From ecb09280ef60a513e9955351fd601675a9fc3223 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 26 Nov 2018 15:04:48 +0100 Subject: [PATCH 06/22] updated VERSION for 3.4.19 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 6b80158cf2407..bfc961f50511f 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -67,12 +67,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '3.4.19-DEV'; + const VERSION = '3.4.19'; const VERSION_ID = 30419; const MAJOR_VERSION = 3; const MINOR_VERSION = 4; const RELEASE_VERSION = 19; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '11/2020'; const END_OF_LIFE = '11/2021'; From acce087074962ea214f0384546d7c720432153cd Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 26 Nov 2018 15:50:31 +0100 Subject: [PATCH 07/22] bumped Symfony version to 3.4.20 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index bfc961f50511f..375e26ee0f5e1 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -67,12 +67,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '3.4.19'; - const VERSION_ID = 30419; + const VERSION = '3.4.20-DEV'; + const VERSION_ID = 30420; const MAJOR_VERSION = 3; const MINOR_VERSION = 4; - const RELEASE_VERSION = 19; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 20; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '11/2020'; const END_OF_LIFE = '11/2021'; From 43cb7cfb23a8d3920ad2e118fd8ce6d521dfee49 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 26 Nov 2018 15:52:06 +0100 Subject: [PATCH 08/22] updated CHANGELOG for 4.1.8 --- CHANGELOG-4.1.md | 43 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/CHANGELOG-4.1.md b/CHANGELOG-4.1.md index 60b848a532545..ad6a91cdd0b1b 100644 --- a/CHANGELOG-4.1.md +++ b/CHANGELOG-4.1.md @@ -7,6 +7,49 @@ in 4.1 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/v4.1.0...v4.1.1 +* 4.1.8 (2018-11-26) + + * bug #29318 [Console] Move back root exception to stack trace in verbose mode (chalasr) + * bug #29332 [PropertyAccess] make cache keys encoding bijective (nicolas-grekas) + * bug #29298 [Routing] fix trailing slash redirection when using RedirectableUrlMatcher (nicolas-grekas) + * bug #29297 [Routing] fix trailing slash redirection when using RedirectableUrlMatcher (nicolas-grekas) + * bug #29313 [PropertyAccessor] fix encoding of cache keys (nicolas-grekas) + * bug #28917 [DoctrineBridge] catch errors while converting to db values in data collector (alekitto) + * bug #29317 [WebProfiler] Detect non-file paths in file viewer (ro0NL) + * bug #29305 [EventDispatcher] Unwrap wrapped listeners internally (ro0NL) + * bug #27314 [DoctrineBridge] fix case sensitivity issue in RememberMe\DoctrineTokenProvider (PF4Public) + * bug #29310 [MonologBridge] Return empty list for unknown requests (ro0NL) + * bug #29308 [Translation] Use XLIFF source rather than resname when there's no target (thewilkybarkid) + * bug #26244 [BrowserKit] fixed BC Break for HTTP_HOST header (brizzz) + * bug #28147 [DomCrawler] exclude fields inside "template" tags (Gorjunov) + * bug #29222 [Dotenv] properly parse backslashes in unquoted env vars (xabbuh) + * bug #29256 [HttpFoundation] Fixed absolute Request URI with default port (thomasbisignani) + * bug #29274 [Routing] Remove duplicate schemes and methods for invokable controllers (claudusd) + * bug #29271 [HttpFoundation] Fix trailing space for mime-type with parameters (Sascha Dens) + * bug #29243 [Cache] fix optimizing Psr6Cache for AdapterInterface pools (nicolas-grekas) + * bug #29247 [DI] fix taking lazy services into account when dumping the container (nicolas-grekas) + * bug #29249 [Form] Fixed empty data for compound date interval (HeahDude) + * bug #29265 [Bridge/PhpUnit] Use composer to download phpunit (nicolas-grekas) + * bug #28769 [FrameworkBundle] deal with explicitly enabled workflow nodes (xabbuh) + * bug #29223 [Validator] Added the missing constraints instance checks (thomasbisignani) + * bug #28966 [PropertyAccessor] Fix unable to write to singular property using setter while plural adder/remover exist (karser) + * bug #29182 [Form] Fixed empty data for compound date types (HeahDude) + * bug #29191 [Routing] generate(null) should throw an exception (nicolas-grekas) + * bug #29185 [Form] Fixed keeping hash of equal \DateTimeInterface on submit (HeahDude) + * bug #29141 [Workflow] Fixed bug of buildTransitionBlockerList when many transition are enabled (Tetragramat, lyrixx) + * bug #29137 [Workflow][FrameworkBundle] fixed guard event names for transitions (destillat, lyrixx) + * bug #28731 [Form] invalidate forms on transformation failures (xabbuh) + * bug #29152 [Config] Unset key during normalization (ro0NL) + * bug #29165 [DI] align IniFileLoader to PHP bugfix #76965 (nicolas-grekas) + * bug #29115 Change button_widget class to btn-primary (neFAST) + * bug #29131 [Dotenv] dont use getenv() to read SYMFONY_DOTENV_VARS (nicolas-grekas) + * bug #29057 [HttpFoundation] replace any preexisting Content-Type headers (nicolas-grekas) + * bug #29076 [Serializer] Allow null values when denormalizing with constructor missing data (danut007ro) + * bug #29104 [DI] fix dumping inlined services (nicolas-grekas) + * bug #29054 [VarDumper] fix dump of closures created from callables (nicolas-grekas) + * bug #29102 [DI] fix GraphvizDumper ignoring inline definitions (nicolas-grekas) + * bug #29107 [DI] dont track classes/interfaces used to compute autowiring error messages (nicolas-grekas) + * 4.1.7 (2018-11-03) * bug #28820 [DependencyInjection] Fix tags on multiple decorated service (Soner Sayakci) From 63201c518c6baacd884f70961377e5c4311e5669 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 26 Nov 2018 15:52:15 +0100 Subject: [PATCH 09/22] updated VERSION for 4.1.8 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index f5042995320d7..244f664a6454c 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -63,12 +63,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '4.1.8-DEV'; + const VERSION = '4.1.8'; const VERSION_ID = 40108; const MAJOR_VERSION = 4; const MINOR_VERSION = 1; const RELEASE_VERSION = 8; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '01/2019'; const END_OF_LIFE = '07/2019'; From 9fba843a2a3f6c543051bad5d66d632808d6c5b8 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Mon, 26 Nov 2018 16:00:55 +0100 Subject: [PATCH 10/22] bumped Symfony version to 4.1.9 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 244f664a6454c..0a3909dff51c1 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -63,12 +63,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '4.1.8'; - const VERSION_ID = 40108; + const VERSION = '4.1.9-DEV'; + const VERSION_ID = 40109; const MAJOR_VERSION = 4; const MINOR_VERSION = 1; - const RELEASE_VERSION = 8; - const EXTRA_VERSION = ''; + const RELEASE_VERSION = 9; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '01/2019'; const END_OF_LIFE = '07/2019'; From 45c3de044e5fb31d74d8ac1899edf8a74a1da08a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Delprat?= Date: Tue, 27 Nov 2018 13:52:28 +0900 Subject: [PATCH 11/22] Fixes sprintf(): Too few arguments in Translator Fixes the log produced when the method is called : Before : "sprintf(): Too few arguments" After : "The "Symfony\Component\Translation\Translator::transChoice()" method is deprecated since Symfony 4.2, use the trans() one instead with a "%count%" parameter." Reference : http://php.net/manual/function.sprintf.php --- src/Symfony/Component/Translation/Translator.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Translation/Translator.php b/src/Symfony/Component/Translation/Translator.php index 864db835c77a3..7fcb77853d5e1 100644 --- a/src/Symfony/Component/Translation/Translator.php +++ b/src/Symfony/Component/Translation/Translator.php @@ -226,7 +226,7 @@ public function trans($id, array $parameters = array(), $domain = null, $locale */ public function transChoice($id, $number, array $parameters = array(), $domain = null, $locale = null) { - @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the trans() one instead with a "%count%" parameter.', __METHOD__), E_USER_DEPRECATED); + @trigger_error(sprintf('The "%s()" method is deprecated since Symfony 4.2, use the trans() one instead with a "%%count%%" parameter.', __METHOD__), E_USER_DEPRECATED); if (!$this->formatter instanceof ChoiceMessageFormatterInterface) { throw new LogicException(sprintf('The formatter "%s" does not support plural translations.', \get_class($this->formatter))); From 53f28bf34ceec93a3a2751d2217a8691d8116970 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 27 Nov 2018 08:29:59 +0100 Subject: [PATCH 12/22] Update PR template --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index b6f39741d9dbc..ac82d7063d015 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,6 @@ | Q | A | ------------- | --- -| Branch? | master for features / 2.8 up to 4.1 for bug fixes +| Branch? | master for features / 3.4 up to 4.2 for bug fixes | Bug fix? | yes/no | New feature? | yes/no | BC breaks? | no From e2b4c8d3c9cc5d2b1b152f99b2a8b8904948ae35 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 27 Nov 2018 11:58:55 +0100 Subject: [PATCH 13/22] [Debug] workaround opcache bug mutating "$this" !?! --- phpunit | 2 +- src/Symfony/Component/Debug/DebugClassLoader.php | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/phpunit b/phpunit index f4b80ed064121..9975195309a81 100755 --- a/phpunit +++ b/phpunit @@ -1,7 +1,7 @@ #!/usr/bin/env php isFinder && !isset($this->loaded[$class])) { $this->loaded[$class] = true; - if ($file = $this->classLoader[0]->findFile($class) ?: false) { - $wasCached = \function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file); - + if (!$file = $this->classLoader[0]->findFile($class) ?: false) { + // no-op + } elseif (\function_exists('opcache_is_script_cached') && @opcache_is_script_cached($file)) { require $file; - if ($wasCached) { - return; - } + return; + } else { + require $file; } } else { \call_user_func($this->classLoader, $class); From d903dcbac565bde4598b29dc445e74401c533f88 Mon Sep 17 00:00:00 2001 From: Michael Hudson-Doyle Date: Tue, 27 Nov 2018 11:41:07 +1300 Subject: [PATCH 14/22] [Form] Handle all case variants of "nan" when parsing a number Fixes #29321 --- .../Core/DataTransformer/NumberToLocalizedStringTransformer.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php index 9e03606a3ec70..3e125bc82be36 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/NumberToLocalizedStringTransformer.php @@ -146,7 +146,7 @@ public function reverseTransform($value) return; } - if ('NaN' === $value) { + if (\in_array($value, array('NaN', 'NAN', 'nan'), true)) { throw new TransformationFailedException('"NaN" is not a valid number'); } From 85af682834a56ff0b7775d4dd1078b748db0cf52 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Wed, 28 Nov 2018 11:07:27 +0100 Subject: [PATCH 15/22] add a test case --- .../NumberToLocalizedStringTransformerTest.php | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php index d6a4662102232..176d3a9a58f9e 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/NumberToLocalizedStringTransformerTest.php @@ -514,24 +514,24 @@ public function testReverseTransformExpectsValidNumber() /** * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException + * @dataProvider nanRepresentationProvider * * @see https://github.com/symfony/symfony/issues/3161 */ - public function testReverseTransformDisallowsNaN() + public function testReverseTransformDisallowsNaN($nan) { $transformer = new NumberToLocalizedStringTransformer(); - $transformer->reverseTransform('NaN'); + $transformer->reverseTransform($nan); } - /** - * @expectedException \Symfony\Component\Form\Exception\TransformationFailedException - */ - public function testReverseTransformDisallowsNaN2() + public function nanRepresentationProvider() { - $transformer = new NumberToLocalizedStringTransformer(); - - $transformer->reverseTransform('nan'); + return array( + array('nan'), + array('NaN'), // see https://github.com/symfony/symfony/issues/3161 + array('NAN'), + ); } /** From 3cd4477563f6f56760c03a6864e38f5328534c19 Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Wed, 28 Nov 2018 16:00:13 +0100 Subject: [PATCH 16/22] [Messenger] Mention HandleTrait in UPGRADE-4.2.md file --- UPGRADE-4.2.md | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/UPGRADE-4.2.md b/UPGRADE-4.2.md index bdf2ab0cececf..a2fadabc95b14 100644 --- a/UPGRADE-4.2.md +++ b/UPGRADE-4.2.md @@ -199,7 +199,10 @@ Messenger --------- * The `MiddlewareInterface::handle()` and `SenderInterface::send()` methods must now return an `Envelope` instance. - * The return value of handlers is ignored. If you used to return a value, e.g in query bus handlers, you can either: + * The return value of handlers isn't forwarded anymore by middleware and buses. + If you used to return a value, e.g in query bus handlers, you can either: + - get the result from the `HandledStamp` in the envelope returned by the bus. + - use the `HandleTrait` to leverage a message bus, expecting a single, synchronous message handling and returning its result. - make your `Query` mutable to allow setting & getting a result: ```php // When dispatching: @@ -209,15 +212,6 @@ Messenger // In your handler: $query->setResult($yourResult); ``` - - define a callable on your `Query` to be called in your handler: - ```php - // When dispatching: - $bus->dispatch(new Query([$this, 'onResult'])); - - // In your handler: - $query->executeCallback($yourResult); - ``` - * The `EnvelopeAwareInterface` was removed and the `MiddlewareInterface::handle()` method now requires an `Envelope` object as first argument. When using built-in middleware with the provided `MessageBus`, you will not have to do anything. If you use your own `MessageBusInterface` implementation, you must wrap the message in an `Envelope` before passing it to middleware. From 0d0be12e07b1e04e4d87286dbeb1c64302dccbfa Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 27 Nov 2018 11:55:51 +0100 Subject: [PATCH 17/22] [DI] fix combinatorial explosion when analyzing the service graph --- .../Compiler/InlineServiceDefinitionsPass.php | 12 +++- .../DependencyInjection/Dumper/PhpDumper.php | 66 +++++++++++++------ 2 files changed, 57 insertions(+), 21 deletions(-) diff --git a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php index 05eb72d9746f4..65da0b9ac7ecb 100644 --- a/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php +++ b/src/Symfony/Component/DependencyInjection/Compiler/InlineServiceDefinitionsPass.php @@ -127,13 +127,19 @@ private function isInlineableDefinition($id, Definition $definition, ServiceRefe } $ids = array(); + $isReferencedByConstructor = false; foreach ($graph->getNode($id)->getInEdges() as $edge) { + $isReferencedByConstructor = $isReferencedByConstructor || $edge->isReferencedByConstructor(); if ($edge->isWeak()) { return false; } $ids[] = $edge->getSourceNode()->getId(); } + if (!$ids) { + return true; + } + if (\count(array_unique($ids)) > 1) { return false; } @@ -142,6 +148,10 @@ private function isInlineableDefinition($id, Definition $definition, ServiceRefe return false; } - return !$ids || $this->container->getDefinition($ids[0])->isShared(); + if ($isReferencedByConstructor && $this->container->getDefinition($ids[0])->isLazy() && ($definition->getProperties() || $definition->getMethodCalls() || $definition->getConfigurator())) { + return false; + } + + return $this->container->getDefinition($ids[0])->isShared(); } } diff --git a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php index fd7eec05759b7..95a98c6aaacae 100644 --- a/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php +++ b/src/Symfony/Component/DependencyInjection/Dumper/PhpDumper.php @@ -155,17 +155,18 @@ public function dump(array $options = array()) } (new AnalyzeServiceReferencesPass(false, !$this->getProxyDumper() instanceof NullDumper))->process($this->container); + $checkedNodes = array(); $this->circularReferences = array(); - foreach (array(true, false) as $byConstructor) { - foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) { - if (!$node->getValue() instanceof Definition) { - continue; - } - $currentPath = array($id => true); - $this->analyzeCircularReferences($node->getOutEdges(), $currentPath, $id, $byConstructor); + foreach ($this->container->getCompiler()->getServiceReferenceGraph()->getNodes() as $id => $node) { + if (!$node->getValue() instanceof Definition) { + continue; + } + if (!isset($checkedNodes[$id])) { + $this->analyzeCircularReferences($id, $node->getOutEdges(), $checkedNodes); } } $this->container->getCompiler()->getServiceReferenceGraph()->clear(); + $checkedNodes = array(); $this->docStar = $options['debug'] ? '*' : ''; @@ -301,12 +302,12 @@ private function getProxyDumper() return $this->proxyDumper; } - private function analyzeCircularReferences(array $edges, &$currentPath, $sourceId, $byConstructor) + private function analyzeCircularReferences($sourceId, array $edges, &$checkedNodes, &$currentPath = array()) { + $checkedNodes[$sourceId] = true; + $currentPath[$sourceId] = $sourceId; + foreach ($edges as $edge) { - if ($byConstructor && !$edge->isReferencedByConstructor()) { - continue; - } $node = $edge->getDestNode(); $id = $node->getId(); @@ -315,20 +316,42 @@ private function analyzeCircularReferences(array $edges, &$currentPath, $sourceI } elseif (isset($currentPath[$id])) { $currentId = $id; foreach (array_reverse($currentPath) as $parentId) { - if (!isset($this->circularReferences[$parentId][$currentId])) { - $this->circularReferences[$parentId][$currentId] = $byConstructor; + $this->circularReferences[$parentId][$currentId] = $currentId; + if ($parentId === $id) { + break; } + $currentId = $parentId; + } + } elseif (!isset($checkedNodes[$id])) { + $this->analyzeCircularReferences($id, $node->getOutEdges(), $checkedNodes, $currentPath); + } elseif (isset($this->circularReferences[$id])) { + $this->connectCircularReferences($id, $currentPath); + } + } + unset($currentPath[$sourceId]); + } + + private function connectCircularReferences($sourceId, &$currentPath, &$subPath = array()) + { + $subPath[$sourceId] = $sourceId; + $currentPath[$sourceId] = $sourceId; + + foreach ($this->circularReferences[$sourceId] as $id) { + if (isset($currentPath[$id])) { + $currentId = $id; + foreach (array_reverse($currentPath) as $parentId) { + $this->circularReferences[$parentId][$currentId] = $currentId; if ($parentId === $id) { break; } $currentId = $parentId; } - } else { - $currentPath[$id] = $id; - $this->analyzeCircularReferences($node->getOutEdges(), $currentPath, $id, $byConstructor); - unset($currentPath[$id]); + } elseif (!isset($subPath[$id]) && isset($this->circularReferences[$id])) { + $this->connectCircularReferences($id, $currentPath, $subPath); } } + unset($currentPath[$sourceId]); + unset($subPath[$sourceId]); } private function collectLineage($class, array &$lineage) @@ -569,8 +592,11 @@ private function addServiceConfigurator(Definition $definition, $variableName = if (\is_array($callable)) { if ($callable[0] instanceof Reference - || ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0]))) { - return sprintf(" %s->%s(\$%s);\n", $this->dumpValue($callable[0]), $callable[1], $variableName); + || ($callable[0] instanceof Definition && $this->definitionVariables->contains($callable[0])) + ) { + $callable[0] = $this->dumpValue($callable[0]); + + return sprintf(' '.('$' === $callable[0][0] ? '%s' : '(%s)')."->%s(\$%s);\n", $callable[0], $callable[1], $variableName); } $class = $this->dumpValue($callable[0]); @@ -724,7 +750,7 @@ private function addInlineReference($id, Definition $definition, $targetId, $for $hasSelfRef = isset($this->circularReferences[$id][$targetId]); $forConstructor = $forConstructor && !isset($this->definitionVariables[$definition]); - $code = $hasSelfRef && $this->circularReferences[$id][$targetId] && !$forConstructor ? $this->addInlineService($id, $definition, $definition) : ''; + $code = $hasSelfRef && !$forConstructor ? $this->addInlineService($id, $definition, $definition) : ''; if (isset($this->referenceVariables[$targetId]) || (2 > $callCount && (!$hasSelfRef || !$forConstructor))) { return $code; From 977a007e3ac99224564dfeead8ec4d32270bc885 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Thu, 29 Nov 2018 09:33:43 +0100 Subject: [PATCH 18/22] typo --- .../Component/Validator/Context/ExecutionContextInterface.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php b/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php index 544c82f6c074b..e4f7df1757da6 100644 --- a/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php +++ b/src/Symfony/Component/Validator/Context/ExecutionContextInterface.php @@ -112,7 +112,7 @@ public function getValidator(); * Returns the currently validated object. * * If the validator is currently validating a class constraint, the - * object of that class is returned. If it is a validating a property or + * object of that class is returned. If it is validating a property or * getter constraint, the object that the property/getter belongs to is * returned. * From fa234378ffa9a361dbf429cb4d6464d8a6db1f35 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 27 Nov 2018 11:31:37 +0100 Subject: [PATCH 19/22] calculate cache keys for property setters depending on the value --- .../PropertyAccess/PropertyAccessor.php | 51 ++++++++++++------- .../Tests/PropertyAccessorTest.php | 24 ++++++++- .../Tests/TestPluralAdderRemoverAndSetter.php | 37 ++++++++++++++ ...rRemoverAndSetterSameSingularAndPlural.php | 28 ++++++++++ 4 files changed, 121 insertions(+), 19 deletions(-) create mode 100644 src/Symfony/Component/PropertyAccess/Tests/TestPluralAdderRemoverAndSetter.php create mode 100644 src/Symfony/Component/PropertyAccess/Tests/TestPluralAdderRemoverAndSetterSameSingularAndPlural.php diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 90e4c234fb1dd..2e358f458600b 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -687,7 +687,8 @@ private function writeCollection($zval, $property, $collection, $addMethod, $rem */ private function getWriteAccessInfo($class, $property, $value) { - $key = str_replace('\\', '.', $class).'..'.$property; + $useAdderAndRemover = \is_array($value) || $value instanceof \Traversable; + $key = str_replace('\\', '.', $class).'..'.$property.'..'.(int) $useAdderAndRemover; if (isset($this->writePropertyCache[$key])) { return $this->writePropertyCache[$key]; @@ -707,6 +708,16 @@ private function getWriteAccessInfo($class, $property, $value) $camelized = $this->camelize($property); $singulars = (array) Inflector::singularize($camelized); + if ($useAdderAndRemover) { + $methods = $this->findAdderAndRemover($reflClass, $singulars); + + if (null !== $methods) { + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_ADDER_AND_REMOVER; + $access[self::ACCESS_ADDER] = $methods[0]; + $access[self::ACCESS_REMOVER] = $methods[1]; + } + } + if (!isset($access[self::ACCESS_TYPE])) { $setter = 'set'.$camelized; $getsetter = lcfirst($camelized); // jQuery style, e.g. read: last(), write: last($item) @@ -728,22 +739,16 @@ private function getWriteAccessInfo($class, $property, $value) $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_MAGIC; $access[self::ACCESS_NAME] = $setter; } elseif (null !== $methods = $this->findAdderAndRemover($reflClass, $singulars)) { - if (\is_array($value) || $value instanceof \Traversable) { - $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_ADDER_AND_REMOVER; - $access[self::ACCESS_ADDER] = $methods[0]; - $access[self::ACCESS_REMOVER] = $methods[1]; - } else { - $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_NOT_FOUND; - $access[self::ACCESS_NAME] = sprintf( - 'The property "%s" in class "%s" can be defined with the methods "%s()" but '. - 'the new value must be an array or an instance of \Traversable, '. - '"%s" given.', - $property, - $reflClass->name, - implode('()", "', $methods), - \is_object($value) ? \get_class($value) : \gettype($value) - ); - } + $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_NOT_FOUND; + $access[self::ACCESS_NAME] = sprintf( + 'The property "%s" in class "%s" can be defined with the methods "%s()" but '. + 'the new value must be an array or an instance of \Traversable, '. + '"%s" given.', + $property, + $reflClass->name, + implode('()", "', $methods), + \is_object($value) ? \get_class($value) : \gettype($value) + ); } else { $access[self::ACCESS_TYPE] = self::ACCESS_TYPE_NOT_FOUND; $access[self::ACCESS_NAME] = sprintf( @@ -783,6 +788,18 @@ private function isPropertyWritable($object, $property) $access = $this->getWriteAccessInfo(\get_class($object), $property, array()); + $isWritable = self::ACCESS_TYPE_METHOD === $access[self::ACCESS_TYPE] + || self::ACCESS_TYPE_PROPERTY === $access[self::ACCESS_TYPE] + || self::ACCESS_TYPE_ADDER_AND_REMOVER === $access[self::ACCESS_TYPE] + || (!$access[self::ACCESS_HAS_PROPERTY] && property_exists($object, $property)) + || self::ACCESS_TYPE_MAGIC === $access[self::ACCESS_TYPE]; + + if ($isWritable) { + return true; + } + + $access = $this->getWriteAccessInfo(\get_class($object), $property, ''); + return self::ACCESS_TYPE_METHOD === $access[self::ACCESS_TYPE] || self::ACCESS_TYPE_PROPERTY === $access[self::ACCESS_TYPE] || self::ACCESS_TYPE_ADDER_AND_REMOVER === $access[self::ACCESS_TYPE] diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php index cf6152380d1f2..894fbd5c0df0e 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php @@ -719,7 +719,27 @@ public function testWriteToPluralPropertyWhileSingularOneExists() $this->propertyAccessor->isWritable($object, 'emails'); //cache access info $this->propertyAccessor->setValue($object, 'emails', array('test@email.com')); - self::assertEquals(array('test@email.com'), $object->getEmails()); - self::assertNull($object->getEmail()); + $this->assertEquals(array('test@email.com'), $object->getEmails()); + $this->assertNull($object->getEmail()); + } + + public function testAdderAndRemoverArePreferredOverSetter() + { + $object = new TestPluralAdderRemoverAndSetter(); + + $this->propertyAccessor->isWritable($object, 'emails'); //cache access info + $this->propertyAccessor->setValue($object, 'emails', array('test@email.com')); + + $this->assertEquals(array('test@email.com'), $object->getEmails()); + } + + public function testAdderAndRemoverArePreferredOverSetterForSameSingularAndPlural() + { + $object = new TestPluralAdderRemoverAndSetterSameSingularAndPlural(); + + $this->propertyAccessor->isWritable($object, 'aircraft'); //cache access info + $this->propertyAccessor->setValue($object, 'aircraft', array('aeroplane')); + + $this->assertEquals(array('aeroplane'), $object->getAircraft()); } } diff --git a/src/Symfony/Component/PropertyAccess/Tests/TestPluralAdderRemoverAndSetter.php b/src/Symfony/Component/PropertyAccess/Tests/TestPluralAdderRemoverAndSetter.php new file mode 100644 index 0000000000000..ecb3f9b4a9d32 --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/Tests/TestPluralAdderRemoverAndSetter.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\PropertyAccess\Tests; + +class TestPluralAdderRemoverAndSetter +{ + private $emails = array(); + + public function getEmails() + { + return $this->emails; + } + + public function setEmails(array $emails) + { + $this->emails = array('foo@email.com'); + } + + public function addEmail($email) + { + $this->emails[] = $email; + } + + public function removeEmail($email) + { + $this->emails = array_diff($this->emails, array($email)); + } +} diff --git a/src/Symfony/Component/PropertyAccess/Tests/TestPluralAdderRemoverAndSetterSameSingularAndPlural.php b/src/Symfony/Component/PropertyAccess/Tests/TestPluralAdderRemoverAndSetterSameSingularAndPlural.php new file mode 100644 index 0000000000000..bb3b4f4688dc5 --- /dev/null +++ b/src/Symfony/Component/PropertyAccess/Tests/TestPluralAdderRemoverAndSetterSameSingularAndPlural.php @@ -0,0 +1,28 @@ +aircraft; + } + + public function setAircraft(array $aircraft) + { + $this->aircraft = array('plane'); + } + + public function addAircraft($aircraft) + { + $this->aircraft[] = $aircraft; + } + + public function removeAircraft($aircraft) + { + $this->aircraft = array_diff($this->aircraft, array($aircraft)); + } +} From fbaba23023fa1e13005120c41306dea71abcfb16 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 29 Nov 2018 12:01:52 +0100 Subject: [PATCH 20/22] [Routing] fix trailing slash redirection --- .../Matcher/Dumper/PhpMatcherDumper.php | 10 ++++++++-- .../Component/Routing/Matcher/UrlMatcher.php | 9 +++++++-- .../Tests/Fixtures/dumper/url_matcher1.php | 18 ++++++++++++++---- .../Tests/Fixtures/dumper/url_matcher10.php | 9 +++++++-- .../Tests/Fixtures/dumper/url_matcher11.php | 9 +++++++-- .../Tests/Fixtures/dumper/url_matcher12.php | 9 +++++++-- .../Tests/Fixtures/dumper/url_matcher2.php | 18 ++++++++++++++---- .../Tests/Fixtures/dumper/url_matcher3.php | 18 ++++++++++++++---- .../Tests/Fixtures/dumper/url_matcher4.php | 9 +++++++-- .../Tests/Fixtures/dumper/url_matcher5.php | 18 ++++++++++++++---- .../Tests/Fixtures/dumper/url_matcher6.php | 18 ++++++++++++++---- .../Tests/Fixtures/dumper/url_matcher7.php | 18 ++++++++++++++---- .../Tests/Fixtures/dumper/url_matcher8.php | 9 +++++++-- .../Routing/Tests/Matcher/UrlMatcherTest.php | 9 +++++++++ 14 files changed, 143 insertions(+), 38 deletions(-) diff --git a/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php b/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php index 4cb1c7429bb10..c33b7d06c56f4 100644 --- a/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php +++ b/src/Symfony/Component/Routing/Matcher/Dumper/PhpMatcherDumper.php @@ -550,9 +550,15 @@ private function compileStaticPrefixCollection(StaticPrefixCollection $tree, \st private function compileSwitchDefault(bool $hasVars, bool $matchHost): string { $code = sprintf(" - if ('/' !== \$pathinfo && \$hasTrailingSlash !== ('/' === \$pathinfo[-1])) { - %s; + if ('/' !== \$pathinfo) { + if (!\$hasTrailingSlash && '/' === \$pathinfo[-1]%s) { + %s; + } + if (\$hasTrailingSlash && '/' !== \$pathinfo[-1]) { + %2\$s; + } }\n", + $hasVars ? ' && preg_match($regex, substr($pathinfo, 0, -1), $n) && $m === (int) $n[\'MARK\']' : '', $this->supportsRedirections ? 'return null' : 'break' ); diff --git a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php index f2b353dfeb140..13b231bf96fdb 100644 --- a/src/Symfony/Component/Routing/Matcher/UrlMatcher.php +++ b/src/Symfony/Component/Routing/Matcher/UrlMatcher.php @@ -160,8 +160,13 @@ protected function matchCollection($pathinfo, RouteCollection $routes) continue; } - if ($supportsTrailingSlash && $hasTrailingSlash !== ('/' === $pathinfo[-1])) { - return; + if ($supportsTrailingSlash) { + if (!$hasTrailingSlash && '/' === $pathinfo[-1] && preg_match($regex, substr($pathinfo, 0, -1))) { + return; + } + if ($hasTrailingSlash && '/' !== $pathinfo[-1]) { + return; + } } $hostMatches = array(); diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php index 531d1ecabae75..472b96a35cdc7 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher1.php @@ -54,8 +54,13 @@ public function match($rawPathinfo) } list($ret, $requiredHost, $requiredMethods, $requiredSchemes, $hasTrailingSlash) = $routes[$trimmedPathinfo]; - if ('/' !== $pathinfo && $hasTrailingSlash !== ('/' === $pathinfo[-1])) { - break; + if ('/' !== $pathinfo) { + if (!$hasTrailingSlash && '/' === $pathinfo[-1]) { + break; + } + if ($hasTrailingSlash && '/' !== $pathinfo[-1]) { + break; + } } if ($requiredHost) { @@ -232,8 +237,13 @@ public function match($rawPathinfo) list($ret, $vars, $requiredMethods, $requiredSchemes, $hasTrailingSlash) = $routes[$m]; - if ('/' !== $pathinfo && $hasTrailingSlash !== ('/' === $pathinfo[-1])) { - break; + if ('/' !== $pathinfo) { + if (!$hasTrailingSlash && '/' === $pathinfo[-1] && preg_match($regex, substr($pathinfo, 0, -1), $n) && $m === (int) $n['MARK']) { + break; + } + if ($hasTrailingSlash && '/' !== $pathinfo[-1]) { + break; + } } foreach ($vars as $i => $v) { diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher10.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher10.php index eee7e080d89fd..956a8bad689d3 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher10.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher10.php @@ -2793,8 +2793,13 @@ public function match($rawPathinfo) list($ret, $vars, $requiredMethods, $requiredSchemes, $hasTrailingSlash) = $routes[$m]; - if ('/' !== $pathinfo && $hasTrailingSlash !== ('/' === $pathinfo[-1])) { - break; + if ('/' !== $pathinfo) { + if (!$hasTrailingSlash && '/' === $pathinfo[-1] && preg_match($regex, substr($pathinfo, 0, -1), $n) && $m === (int) $n['MARK']) { + break; + } + if ($hasTrailingSlash && '/' !== $pathinfo[-1]) { + break; + } } foreach ($vars as $i => $v) { diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher11.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher11.php index 8f3f0599f2eb4..3cc68ed9931fb 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher11.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher11.php @@ -118,8 +118,13 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a list($ret, $vars, $requiredMethods, $requiredSchemes, $hasTrailingSlash) = $routes[$m]; - if ('/' !== $pathinfo && $hasTrailingSlash !== ('/' === $pathinfo[-1])) { - return null; + if ('/' !== $pathinfo) { + if (!$hasTrailingSlash && '/' === $pathinfo[-1] && preg_match($regex, substr($pathinfo, 0, -1), $n) && $m === (int) $n['MARK']) { + return null; + } + if ($hasTrailingSlash && '/' !== $pathinfo[-1]) { + return null; + } } foreach ($vars as $i => $v) { diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher12.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher12.php index 406e13336a6cb..8b446a2fc2dd8 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher12.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher12.php @@ -63,8 +63,13 @@ public function match($rawPathinfo) list($ret, $vars, $requiredMethods, $requiredSchemes, $hasTrailingSlash) = $routes[$m]; - if ('/' !== $pathinfo && $hasTrailingSlash !== ('/' === $pathinfo[-1])) { - break; + if ('/' !== $pathinfo) { + if (!$hasTrailingSlash && '/' === $pathinfo[-1] && preg_match($regex, substr($pathinfo, 0, -1), $n) && $m === (int) $n['MARK']) { + break; + } + if ($hasTrailingSlash && '/' !== $pathinfo[-1]) { + break; + } } foreach ($vars as $i => $v) { diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php index fc08f2b73e946..c4bf167f302cc 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher2.php @@ -91,8 +91,13 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a } list($ret, $requiredHost, $requiredMethods, $requiredSchemes, $hasTrailingSlash) = $routes[$trimmedPathinfo]; - if ('/' !== $pathinfo && $hasTrailingSlash !== ('/' === $pathinfo[-1])) { - return null; + if ('/' !== $pathinfo) { + if (!$hasTrailingSlash && '/' === $pathinfo[-1]) { + return null; + } + if ($hasTrailingSlash && '/' !== $pathinfo[-1]) { + return null; + } } if ($requiredHost) { @@ -269,8 +274,13 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a list($ret, $vars, $requiredMethods, $requiredSchemes, $hasTrailingSlash) = $routes[$m]; - if ('/' !== $pathinfo && $hasTrailingSlash !== ('/' === $pathinfo[-1])) { - return null; + if ('/' !== $pathinfo) { + if (!$hasTrailingSlash && '/' === $pathinfo[-1] && preg_match($regex, substr($pathinfo, 0, -1), $n) && $m === (int) $n['MARK']) { + return null; + } + if ($hasTrailingSlash && '/' !== $pathinfo[-1]) { + return null; + } } foreach ($vars as $i => $v) { diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php index 291be1475760a..16ea1ad4e5dab 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher3.php @@ -46,8 +46,13 @@ public function match($rawPathinfo) } list($ret, $requiredHost, $requiredMethods, $requiredSchemes, $hasTrailingSlash) = $routes[$trimmedPathinfo]; - if ('/' !== $pathinfo && $hasTrailingSlash !== ('/' === $pathinfo[-1])) { - break; + if ('/' !== $pathinfo) { + if (!$hasTrailingSlash && '/' === $pathinfo[-1]) { + break; + } + if ($hasTrailingSlash && '/' !== $pathinfo[-1]) { + break; + } } $hasRequiredScheme = !$requiredSchemes || isset($requiredSchemes[$context->getScheme()]); @@ -82,8 +87,13 @@ public function match($rawPathinfo) list($ret, $vars, $requiredMethods, $requiredSchemes, $hasTrailingSlash) = $routes[$m]; - if ('/' !== $pathinfo && $hasTrailingSlash !== ('/' === $pathinfo[-1])) { - break; + if ('/' !== $pathinfo) { + if (!$hasTrailingSlash && '/' === $pathinfo[-1] && preg_match($regex, substr($pathinfo, 0, -1), $n) && $m === (int) $n['MARK']) { + break; + } + if ($hasTrailingSlash && '/' !== $pathinfo[-1]) { + break; + } } foreach ($vars as $i => $v) { diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher4.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher4.php index 6bec91e309735..5e370d834506f 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher4.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher4.php @@ -66,8 +66,13 @@ public function match($rawPathinfo) } list($ret, $requiredHost, $requiredMethods, $requiredSchemes, $hasTrailingSlash) = $routes[$trimmedPathinfo]; - if ('/' !== $pathinfo && $hasTrailingSlash !== ('/' === $pathinfo[-1])) { - break; + if ('/' !== $pathinfo) { + if (!$hasTrailingSlash && '/' === $pathinfo[-1]) { + break; + } + if ($hasTrailingSlash && '/' !== $pathinfo[-1]) { + break; + } } $hasRequiredScheme = !$requiredSchemes || isset($requiredSchemes[$context->getScheme()]); diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher5.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher5.php index dee606f0a9bfa..6c01afb098f39 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher5.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher5.php @@ -83,8 +83,13 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a } list($ret, $requiredHost, $requiredMethods, $requiredSchemes, $hasTrailingSlash) = $routes[$trimmedPathinfo]; - if ('/' !== $pathinfo && $hasTrailingSlash !== ('/' === $pathinfo[-1])) { - return null; + if ('/' !== $pathinfo) { + if (!$hasTrailingSlash && '/' === $pathinfo[-1]) { + return null; + } + if ($hasTrailingSlash && '/' !== $pathinfo[-1]) { + return null; + } } $hasRequiredScheme = !$requiredSchemes || isset($requiredSchemes[$context->getScheme()]); @@ -121,8 +126,13 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a list($ret, $vars, $requiredMethods, $requiredSchemes, $hasTrailingSlash) = $routes[$m]; - if ('/' !== $pathinfo && $hasTrailingSlash !== ('/' === $pathinfo[-1])) { - return null; + if ('/' !== $pathinfo) { + if (!$hasTrailingSlash && '/' === $pathinfo[-1] && preg_match($regex, substr($pathinfo, 0, -1), $n) && $m === (int) $n['MARK']) { + return null; + } + if ($hasTrailingSlash && '/' !== $pathinfo[-1]) { + return null; + } } foreach ($vars as $i => $v) { diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher6.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher6.php index 839481ba2db2d..746082cbbe8c3 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher6.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher6.php @@ -44,8 +44,13 @@ public function match($rawPathinfo) } list($ret, $requiredHost, $requiredMethods, $requiredSchemes, $hasTrailingSlash) = $routes[$trimmedPathinfo]; - if ('/' !== $pathinfo && $hasTrailingSlash !== ('/' === $pathinfo[-1])) { - break; + if ('/' !== $pathinfo) { + if (!$hasTrailingSlash && '/' === $pathinfo[-1]) { + break; + } + if ($hasTrailingSlash && '/' !== $pathinfo[-1]) { + break; + } } $hasRequiredScheme = !$requiredSchemes || isset($requiredSchemes[$context->getScheme()]); @@ -98,8 +103,13 @@ public function match($rawPathinfo) list($ret, $vars, $requiredMethods, $requiredSchemes, $hasTrailingSlash) = $routes[$m]; - if ('/' !== $pathinfo && $hasTrailingSlash !== ('/' === $pathinfo[-1])) { - break; + if ('/' !== $pathinfo) { + if (!$hasTrailingSlash && '/' === $pathinfo[-1] && preg_match($regex, substr($pathinfo, 0, -1), $n) && $m === (int) $n['MARK']) { + break; + } + if ($hasTrailingSlash && '/' !== $pathinfo[-1]) { + break; + } } foreach ($vars as $i => $v) { diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher7.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher7.php index 07c8af66697ef..68547bf3913f6 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher7.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher7.php @@ -79,8 +79,13 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a } list($ret, $requiredHost, $requiredMethods, $requiredSchemes, $hasTrailingSlash) = $routes[$trimmedPathinfo]; - if ('/' !== $pathinfo && $hasTrailingSlash !== ('/' === $pathinfo[-1])) { - return null; + if ('/' !== $pathinfo) { + if (!$hasTrailingSlash && '/' === $pathinfo[-1]) { + return null; + } + if ($hasTrailingSlash && '/' !== $pathinfo[-1]) { + return null; + } } $hasRequiredScheme = !$requiredSchemes || isset($requiredSchemes[$context->getScheme()]); @@ -133,8 +138,13 @@ private function doMatch(string $rawPathinfo, array &$allow = array(), array &$a list($ret, $vars, $requiredMethods, $requiredSchemes, $hasTrailingSlash) = $routes[$m]; - if ('/' !== $pathinfo && $hasTrailingSlash !== ('/' === $pathinfo[-1])) { - return null; + if ('/' !== $pathinfo) { + if (!$hasTrailingSlash && '/' === $pathinfo[-1] && preg_match($regex, substr($pathinfo, 0, -1), $n) && $m === (int) $n['MARK']) { + return null; + } + if ($hasTrailingSlash && '/' !== $pathinfo[-1]) { + return null; + } } foreach ($vars as $i => $v) { diff --git a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher8.php b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher8.php index ec5127e7b3a89..e8e71e427bc12 100644 --- a/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher8.php +++ b/src/Symfony/Component/Routing/Tests/Fixtures/dumper/url_matcher8.php @@ -51,8 +51,13 @@ public function match($rawPathinfo) list($ret, $vars, $requiredMethods, $requiredSchemes, $hasTrailingSlash) = $routes[$m]; - if ('/' !== $pathinfo && $hasTrailingSlash !== ('/' === $pathinfo[-1])) { - break; + if ('/' !== $pathinfo) { + if (!$hasTrailingSlash && '/' === $pathinfo[-1] && preg_match($regex, substr($pathinfo, 0, -1), $n) && $m === (int) $n['MARK']) { + break; + } + if ($hasTrailingSlash && '/' !== $pathinfo[-1]) { + break; + } } foreach ($vars as $i => $v) { diff --git a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php index c1add96271dc2..1816ba197d982 100644 --- a/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php +++ b/src/Symfony/Component/Routing/Tests/Matcher/UrlMatcherTest.php @@ -680,6 +680,15 @@ public function testHostWithDot() $this->assertEquals('b', $matcher->match('/bar/abc.123')['_route']); } + public function testSlashVariant() + { + $coll = new RouteCollection(); + $coll->add('a', new Route('/foo/{bar}', array(), array('bar' => '.*'))); + + $matcher = $this->getUrlMatcher($coll); + $this->assertEquals('a', $matcher->match('/foo/')['_route']); + } + protected function getUrlMatcher(RouteCollection $routes, RequestContext $context = null) { return new UrlMatcher($routes, $context ?: new RequestContext()); From a1e683b7ceadd22e1cd6a38bd233941d0ed6ab1b Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 30 Nov 2018 10:14:07 +0100 Subject: [PATCH 21/22] updated CHANGELOG for 4.2.0 --- CHANGELOG-4.2.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG-4.2.md b/CHANGELOG-4.2.md index d273a257a51dd..5e748a7913537 100644 --- a/CHANGELOG-4.2.md +++ b/CHANGELOG-4.2.md @@ -7,6 +7,16 @@ in 4.2 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/v4.2.0...v4.2.1 +* 4.2.0 (2018-11-30) + + * bug #29343 [Form] Handle all case variants of "nan" when parsing a number (mwhudson, xabbuh) + * bug #29373 [Routing] fix trailing slash redirection (nicolas-grekas) + * bug #29355 [PropertyAccess] calculate cache keys for property setters depending on the value (xabbuh) + * bug #29369 [DI] fix combinatorial explosion when analyzing the service graph (nicolas-grekas) + * bug #29349 [Debug] workaround opcache bug mutating "$this" !?! (nicolas-grekas) + * bug #29344 Fixes sprintf(): Too few arguments in Translator (stephanedelprat) + * bug #29318 [Console] Move back root exception to stack trace in verbose mode (chalasr) + * 4.2.0-RC1 (2018-11-26) * bug #29332 [PropertyAccess] make cache keys encoding bijective (nicolas-grekas) From 887b0f13d753e342f5d22c1c1555fda28660c222 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 30 Nov 2018 10:16:14 +0100 Subject: [PATCH 22/22] updated VERSION for 4.2.0 --- src/Symfony/Component/HttpKernel/Kernel.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 7116b7015c465..225a047d141f3 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -73,12 +73,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private $requestStackSize = 0; private $resetServices = false; - const VERSION = '4.2.0-DEV'; + const VERSION = '4.2.0'; const VERSION_ID = 40200; const MAJOR_VERSION = 4; const MINOR_VERSION = 2; const RELEASE_VERSION = 0; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '07/2019'; const END_OF_LIFE = '01/2020'; 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