diff --git a/CHANGELOG-2.7.md b/CHANGELOG-2.7.md index ed61259f28..86a2e43266 100644 --- a/CHANGELOG-2.7.md +++ b/CHANGELOG-2.7.md @@ -7,6 +7,27 @@ 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.3 (2015-07-31) + + * bug #15413 Fix the return value on error for intl methods returning arrays (stof) + * bug #15392 Fix missing _route parameter notice in RouterListener logging case (Haehnchen) + * bug #15390 [php7] Fix for substr() always returning a string (nicolas-grekas) + * bug #15386 [php7] Fix for substr() always returning a string (nicolas-grekas) + * bug #15355 [Security] Do not save the target path in the session for a stateless firewall (lyrixx) + * bug #15306 [HttpKernel] [HttpCache] Fix deprecated error in HttpCache#getSurrogate (m14t) + * bug #15369 [TwigBridge] type-dependent path discovery (marcosdsanchez, xabbuh) + * bug #15361 [Yaml] throw a ParseException on invalid data type (xabbuh) + * bug #15345 [Twig+FrameworkBundle] Fix forward compat with Form 2.8 (nicolas-grekas) + * bug #15330 [Console] Fix console output with closed stdout (jakzal) + * bug #15339 [Serializer] Fix 2 bugs regarding private setters (dunglas) + * bug #15326 [Security] fix check for empty usernames (xabbuh) + * bug #15291 [HttpFoundation] Fix Response::closeOutputBuffers() for HHVM 3.3 (nicolas-grekas) + * bug #15249 [HttpFoundation] [PSR-7] Allow to use resources as content body and to return resources from string content (dunglas) + * bug #15282 [HttpFoundation] Behaviour change in PHP7 for substr (Nicofuma) + * bug #15277 [Form] Fix a BC break in the entity (jakzal) + * bug #15271 fix broken ChoiceQuestion (sstok) + * bug #15250 [PropertyAccess] BC Break since 2.6.5 (Nicolas Macherey) + * 2.7.2 (2015-07-13) * bug #15248 Added 'default' color (jaytaph) diff --git a/src/Symfony/Component/Debug/ExceptionHandler.php b/src/Symfony/Component/Debug/ExceptionHandler.php index c883f15469..027b66c052 100644 --- a/src/Symfony/Component/Debug/ExceptionHandler.php +++ b/src/Symfony/Component/Debug/ExceptionHandler.php @@ -38,7 +38,7 @@ class ExceptionHandler public function __construct($debug = true, $charset = null, $fileLinkFormat = null) { - if (false !== strpos($charset, '%') xor false === strpos($fileLinkFormat, '%')) { + if (false !== strpos($charset, '%')) { // Swap $charset and $fileLinkFormat for BC reasons $pivot = $fileLinkFormat; $fileLinkFormat = $charset; @@ -153,19 +153,22 @@ class ExceptionHandler * it will fallback to plain PHP functions. * * @param \Exception $exception An \Exception instance - * - * @see sendPhpResponse() - * @see createResponse() */ private function failSafeHandle(\Exception $exception) { - if (class_exists('Symfony\Component\HttpFoundation\Response', false)) { + if (class_exists('Symfony\Component\HttpFoundation\Response', false) + && __CLASS__ !== get_class($this) + && ($reflector = new \ReflectionMethod($this, 'createResponse')) + && __CLASS__ !== $reflector->class + ) { $response = $this->createResponse($exception); $response->sendHeaders(); $response->sendContent(); - } else { - $this->sendPhpResponse($exception); + + return; } + + $this->sendPhpResponse($exception); } /** diff --git a/src/Symfony/Component/Debug/Tests/ExceptionHandlerTest.php b/src/Symfony/Component/Debug/Tests/ExceptionHandlerTest.php index 26f889288f..d4b93c0838 100644 --- a/src/Symfony/Component/Debug/Tests/ExceptionHandlerTest.php +++ b/src/Symfony/Component/Debug/Tests/ExceptionHandlerTest.php @@ -13,71 +13,97 @@ namespace Symfony\Component\Debug\Tests; use Symfony\Component\Debug\ExceptionHandler; use Symfony\Component\Debug\Exception\OutOfMemoryException; -use Symfony\Component\HttpFoundation\Response; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException; +require_once __DIR__.'/HeaderMock.php'; + class ExceptionHandlerTest extends \PHPUnit_Framework_TestCase { + protected function setUp() + { + testHeader(); + } + + protected function tearDown() + { + testHeader(); + } + public function testDebug() { $handler = new ExceptionHandler(false); - $response = $handler->createResponse(new \RuntimeException('Foo')); - $this->assertContains('

Whoops, looks like something went wrong.

', $response->getContent()); - $this->assertNotContains('

', $response->getContent()); + ob_start(); + $handler->sendPhpResponse(new \RuntimeException('Foo')); + $response = ob_get_clean(); + + $this->assertContains('

Whoops, looks like something went wrong.

', $response); + $this->assertNotContains('

', $response); $handler = new ExceptionHandler(true); - $response = $handler->createResponse(new \RuntimeException('Foo')); - $this->assertContains('

Whoops, looks like something went wrong.

', $response->getContent()); - $this->assertContains('

', $response->getContent()); + ob_start(); + $handler->sendPhpResponse(new \RuntimeException('Foo')); + $response = ob_get_clean(); + + $this->assertContains('

Whoops, looks like something went wrong.

', $response); + $this->assertContains('

', $response); } public function testStatusCode() { - $handler = new ExceptionHandler(false); + $handler = new ExceptionHandler(false, 'iso8859-1'); - $response = $handler->createResponse(new \RuntimeException('Foo')); - $this->assertEquals('500', $response->getStatusCode()); - $this->assertContains('Whoops, looks like something went wrong.', $response->getContent()); + ob_start(); + $handler->sendPhpResponse(new NotFoundHttpException('Foo')); + $response = ob_get_clean(); - $response = $handler->createResponse(new NotFoundHttpException('Foo')); - $this->assertEquals('404', $response->getStatusCode()); - $this->assertContains('Sorry, the page you are looking for could not be found.', $response->getContent()); + $this->assertContains('Sorry, the page you are looking for could not be found.', $response); + + $expectedHeaders = array( + array('HTTP/1.0 404', true, null), + array('Content-Type: text/html; charset=iso8859-1', true, null), + ); + + $this->assertSame($expectedHeaders, testHeader()); } public function testHeaders() { - $handler = new ExceptionHandler(false); + $handler = new ExceptionHandler(false, 'iso8859-1'); - $response = $handler->createResponse(new MethodNotAllowedHttpException(array('POST'))); - $this->assertEquals('405', $response->getStatusCode()); - $this->assertEquals('POST', $response->headers->get('Allow')); + ob_start(); + $handler->sendPhpResponse(new MethodNotAllowedHttpException(array('POST'))); + $response = ob_get_clean(); + + $expectedHeaders = array( + array('HTTP/1.0 405', true, null), + array('Allow: POST', false, null), + array('Content-Type: text/html; charset=iso8859-1', true, null), + ); + + $this->assertSame($expectedHeaders, testHeader()); } public function testNestedExceptions() { $handler = new ExceptionHandler(true); - $response = $handler->createResponse(new \RuntimeException('Foo', 0, new \RuntimeException('Bar'))); + ob_start(); + $handler->sendPhpResponse(new \RuntimeException('Foo', 0, new \RuntimeException('Bar'))); + $response = ob_get_clean(); + + $this->assertStringMatchesFormat('%AFoo%ABar%A', $response); } public function testHandle() { $exception = new \Exception('foo'); - if (class_exists('Symfony\Component\HttpFoundation\Response')) { - $handler = $this->getMock('Symfony\Component\Debug\ExceptionHandler', array('createResponse')); - $handler - ->expects($this->exactly(2)) - ->method('createResponse') - ->will($this->returnValue(new Response())); - } else { - $handler = $this->getMock('Symfony\Component\Debug\ExceptionHandler', array('sendPhpResponse')); - $handler - ->expects($this->exactly(2)) - ->method('sendPhpResponse'); - } + $handler = $this->getMock('Symfony\Component\Debug\ExceptionHandler', array('sendPhpResponse')); + $handler + ->expects($this->exactly(2)) + ->method('sendPhpResponse'); $handler->handle($exception); @@ -93,18 +119,10 @@ class ExceptionHandlerTest extends \PHPUnit_Framework_TestCase { $exception = new OutOfMemoryException('foo', 0, E_ERROR, __FILE__, __LINE__); - if (class_exists('Symfony\Component\HttpFoundation\Response')) { - $handler = $this->getMock('Symfony\Component\Debug\ExceptionHandler', array('createResponse')); - $handler - ->expects($this->once()) - ->method('createResponse') - ->will($this->returnValue(new Response())); - } else { - $handler = $this->getMock('Symfony\Component\Debug\ExceptionHandler', array('sendPhpResponse')); - $handler - ->expects($this->once()) - ->method('sendPhpResponse'); - } + $handler = $this->getMock('Symfony\Component\Debug\ExceptionHandler', array('sendPhpResponse')); + $handler + ->expects($this->once()) + ->method('sendPhpResponse'); $that = $this; $handler->setHandler(function ($e) use ($that) { diff --git a/src/Symfony/Component/Debug/Tests/HeaderMock.php b/src/Symfony/Component/Debug/Tests/HeaderMock.php new file mode 100644 index 0000000000..65d0b58855 --- /dev/null +++ b/src/Symfony/Component/Debug/Tests/HeaderMock.php @@ -0,0 +1,38 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Debug; + +function headers_sent() +{ + return false; +} + +function header($str, $replace = true, $status = null) +{ + Tests\testHeader($str, $replace, $status); +} + +namespace Symfony\Component\Debug\Tests; + +function testHeader() +{ + static $headers = array(); + + if (!$h = func_get_args()) { + $h = $headers; + $headers = array(); + + return $h; + } + + $headers[] = func_get_args(); +} diff --git a/src/Symfony/Component/Debug/composer.json b/src/Symfony/Component/Debug/composer.json index 17c56460cb..6e89d6d48a 100644 --- a/src/Symfony/Component/Debug/composer.json +++ b/src/Symfony/Component/Debug/composer.json @@ -25,12 +25,7 @@ "require-dev": { "symfony/phpunit-bridge": "~2.7|~3.0.0", "symfony/class-loader": "~2.2|~3.0.0", - "symfony/http-kernel": "~2.3.24|~2.5.9|~2.6,>=2.6.2|~3.0.0", - "symfony/http-foundation": "~2.1|~3.0.0" - }, - "suggest": { - "symfony/http-foundation": "", - "symfony/http-kernel": "" + "symfony/http-kernel": "~2.3.24|~2.5.9|~2.6,>=2.6.2|~3.0.0" }, "autoload": { "psr-4": { "Symfony\\Component\\Debug\\": "" } diff --git a/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php b/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php index 00dc60ca3f..297aab6fa1 100644 --- a/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php +++ b/src/Symfony/Component/HttpKernel/EventListener/RouterListener.php @@ -140,7 +140,7 @@ class RouterListener implements EventSubscriberInterface } if (null !== $this->logger) { - $this->logger->info(sprintf('Matched route "%s".', $parameters['_route']), array( + $this->logger->info(sprintf('Matched route "%s".', isset($parameters['_route']) ? $parameters['_route'] : 'n/a'), array( 'route_parameters' => $parameters, 'request_uri' => $request->getUri(), )); diff --git a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php index d6e5b45ba1..245b53acea 100644 --- a/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/EventListener/RouterListenerTest.php @@ -128,4 +128,34 @@ class RouterListenerTest extends \PHPUnit_Framework_TestCase $this->assertEquals('GET', $context->getMethod()); } + + /** + * @dataProvider getLoggingParameterData + */ + public function testLoggingParameter($parameter, $log) + { + $requestMatcher = $this->getMock('Symfony\Component\Routing\Matcher\RequestMatcherInterface'); + $requestMatcher->expects($this->once()) + ->method('matchRequest') + ->will($this->returnValue($parameter)); + + $logger = $this->getMock('Psr\Log\LoggerInterface'); + $logger->expects($this->once()) + ->method('info') + ->with($this->equalTo($log)); + + $kernel = $this->getMock('Symfony\Component\HttpKernel\HttpKernelInterface'); + $request = Request::create('http://localhost/'); + + $listener = new RouterListener($requestMatcher, new RequestContext(), $logger, $this->requestStack); + $listener->onKernelRequest(new GetResponseEvent($kernel, $request, HttpKernelInterface::MASTER_REQUEST)); + } + + public function getLoggingParameterData() + { + return array( + array(array('_route' => 'foo'), 'Matched route "foo".'), + array(array(), 'Matched route "n/a".'), + ); + } } diff --git a/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundle.php b/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundle.php index 38254fa036..5a4b35519f 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundle.php +++ b/src/Symfony/Component/Intl/ResourceBundle/CurrencyBundle.php @@ -76,7 +76,7 @@ class CurrencyBundle extends CurrencyDataProvider implements CurrencyBundleInter try { return $this->getNames($displayLocale); } catch (MissingResourceException $e) { - return; + return array(); } } @@ -112,7 +112,7 @@ class CurrencyBundle extends CurrencyDataProvider implements CurrencyBundleInter try { return $this->localeProvider->getLocales(); } catch (MissingResourceException $e) { - return; + return array(); } } } diff --git a/src/Symfony/Component/Intl/ResourceBundle/LanguageBundle.php b/src/Symfony/Component/Intl/ResourceBundle/LanguageBundle.php index bb393d2063..cfe82ca3c3 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/LanguageBundle.php +++ b/src/Symfony/Component/Intl/ResourceBundle/LanguageBundle.php @@ -80,7 +80,7 @@ class LanguageBundle extends LanguageDataProvider implements LanguageBundleInter try { return $this->getNames($displayLocale); } catch (MissingResourceException $e) { - return; + return array(); } } @@ -104,7 +104,7 @@ class LanguageBundle extends LanguageDataProvider implements LanguageBundleInter try { return $this->scriptProvider->getNames($displayLocale); } catch (MissingResourceException $e) { - return; + return array(); } } @@ -116,7 +116,7 @@ class LanguageBundle extends LanguageDataProvider implements LanguageBundleInter try { return $this->localeProvider->getLocales(); } catch (MissingResourceException $e) { - return; + return array(); } } } diff --git a/src/Symfony/Component/Intl/ResourceBundle/LocaleBundle.php b/src/Symfony/Component/Intl/ResourceBundle/LocaleBundle.php index 22c9aecfb3..b14048a40f 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/LocaleBundle.php +++ b/src/Symfony/Component/Intl/ResourceBundle/LocaleBundle.php @@ -31,7 +31,7 @@ class LocaleBundle extends LocaleDataProvider implements LocaleBundleInterface try { return parent::getLocales(); } catch (MissingResourceException $e) { - return; + return array(); } } @@ -55,7 +55,7 @@ class LocaleBundle extends LocaleDataProvider implements LocaleBundleInterface try { return $this->getNames($displayLocale); } catch (MissingResourceException $e) { - return; + return array(); } } } diff --git a/src/Symfony/Component/Intl/ResourceBundle/RegionBundle.php b/src/Symfony/Component/Intl/ResourceBundle/RegionBundle.php index 126d62ac04..29697d6883 100644 --- a/src/Symfony/Component/Intl/ResourceBundle/RegionBundle.php +++ b/src/Symfony/Component/Intl/ResourceBundle/RegionBundle.php @@ -64,7 +64,7 @@ class RegionBundle extends RegionDataProvider implements RegionBundleInterface try { return $this->getNames($displayLocale); } catch (MissingResourceException $e) { - return; + return array(); } } @@ -76,7 +76,7 @@ class RegionBundle extends RegionDataProvider implements RegionBundleInterface try { return $this->localeProvider->getLocales(); } catch (MissingResourceException $e) { - return; + return array(); } } } diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf index 63eecc0e19..a58f5b8d8c 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf @@ -175,7 +175,7 @@ 画像の高さが小さすぎます({{ height }}ピクセル)。{{ min_height }}ピクセル以上にしてください。 - This value should be the user current password. + This value should be the user's current password. ユーザーの現在のパスワードでなければなりません。 diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.th.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.th.xlf index 0237a308ac..d5b57031b9 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.th.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.th.xlf @@ -175,7 +175,7 @@ ความสูงของภาพไม่ได้ขนาด ({{ height }}px) อนุญาตให้สูงอย่างน้อยที่สุด {{ min_height }}px - This value should be the user current password. + This value should be the user's current password. ค่านี้ควรจะเป็นรหัสผ่านปัจจุบันของผู้ใช้