From c951bb6e970a41bcd2dd81a70558f560c0199659 Mon Sep 17 00:00:00 2001 From: Matteo Beccati Date: Fri, 5 Aug 2016 12:25:39 +0200 Subject: [PATCH 1/9] Fix #19531 [Form] DateType fails parsing when midnight is not a valid time --- .../DateTimeToLocalizedStringTransformer.php | 43 ++++++++++++++++--- ...teTimeToLocalizedStringTransformerTest.php | 20 +++++++++ 2 files changed, 57 insertions(+), 6 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php index cac50e16c7..352b7c85ff 100644 --- a/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php +++ b/src/Symfony/Component/Form/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformer.php @@ -117,20 +117,29 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer return; } - $timestamp = $this->getIntlDateFormatter()->parse($value); + // date-only patterns require parsing to be done in UTC, as midnight might not exist in the local timezone due + // to DST changes + $dateOnly = $this->isPatternDateOnly(); + + $timestamp = $this->getIntlDateFormatter($dateOnly)->parse($value); if (intl_get_error_code() != 0) { throw new TransformationFailedException(intl_get_error_message()); } try { - // read timestamp into DateTime object - the formatter delivers in UTC - $dateTime = new \DateTime(sprintf('@%s', $timestamp)); + if ($dateOnly) { + // we only care about year-month-date, which has been delivered as a timestamp pointing to UTC midnight + return new \DateTime(gmdate('Y-m-d', $timestamp), new \DateTimeZone($this->inputTimezone)); + } + + // read timestamp into DateTime object - the formatter delivers a timestamp + $dateTime = new \DateTime(sprintf('@%s', $timestamp), new \DateTimeZone($this->outputTimezone)); } catch (\Exception $e) { throw new TransformationFailedException($e->getMessage(), $e->getCode(), $e); } - if ('UTC' !== $this->inputTimezone) { + if ($this->outputTimezone !== $this->inputTimezone) { $dateTime->setTimezone(new \DateTimeZone($this->inputTimezone)); } @@ -140,15 +149,17 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer /** * Returns a preconfigured IntlDateFormatter instance. * + * @param bool $ignoreTimezone Use UTC regardless of the configured timezone. + * * @return \IntlDateFormatter * * @throws TransformationFailedException in case the date formatter can not be constructed. */ - protected function getIntlDateFormatter() + protected function getIntlDateFormatter($ignoreTimezone = false) { $dateFormat = $this->dateFormat; $timeFormat = $this->timeFormat; - $timezone = $this->outputTimezone; + $timezone = $ignoreTimezone ? 'UTC' : $this->outputTimezone; $calendar = $this->calendar; $pattern = $this->pattern; @@ -163,4 +174,24 @@ class DateTimeToLocalizedStringTransformer extends BaseDateTimeTransformer return $intlDateFormatter; } + + /** + * Checks if the pattern contains only a date. + * + * @param string $pattern The input pattern + * + * @return bool + */ + protected function isPatternDateOnly() + { + if (null === $this->pattern) { + return false; + } + + // strip escaped text + $pattern = preg_replace("#'(.*?)'#", '', $this->pattern); + + // check for the absence of time-related placeholders + return 0 === preg_match('#[ahHkKmsSAzZOvVxX]#', $pattern); + } } diff --git a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php index 96dd4a3cd1..444cdd4582 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Core/DataTransformer/DateTimeToLocalizedStringTransformerTest.php @@ -230,6 +230,26 @@ class DateTimeToLocalizedStringTransformerTest extends DateTimeTestCase $this->assertDateTimeEquals($this->dateTime, $transformer->reverseTransform('02*2010*03 04|05|06')); } + public function testReverseTransformDateOnlyWithDstIssue() + { + $transformer = new DateTimeToLocalizedStringTransformer('Europe/Rome', 'Europe/Rome', \IntlDateFormatter::FULL, \IntlDateFormatter::FULL, \IntlDateFormatter::GREGORIAN, 'dd/MM/yyyy'); + + $this->assertDateTimeEquals( + new \DateTime('1978-05-28', new \DateTimeZone('Europe/Rome')), + $transformer->reverseTransform('28/05/1978') + ); + } + + public function testReverseTransformDateOnlyWithDstIssueAndEscapedText() + { + $transformer = new DateTimeToLocalizedStringTransformer('Europe/Rome', 'Europe/Rome', \IntlDateFormatter::FULL, \IntlDateFormatter::FULL, \IntlDateFormatter::GREGORIAN, "'day': dd 'month': MM 'year': yyyy"); + + $this->assertDateTimeEquals( + new \DateTime('1978-05-28', new \DateTimeZone('Europe/Rome')), + $transformer->reverseTransform('day: 28 month: 05 year: 1978') + ); + } + public function testReverseTransformEmpty() { $transformer = new DateTimeToLocalizedStringTransformer(); From a7a2d16511f6f932007f54e187d84572b87c8909 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 9 Aug 2016 16:15:57 +0200 Subject: [PATCH 2/9] [Process] Strengthen Windows pipe files opening (again...) --- src/Symfony/Component/Process/Pipes/WindowsPipes.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Process/Pipes/WindowsPipes.php b/src/Symfony/Component/Process/Pipes/WindowsPipes.php index db66c672a7..7b2e5b4b23 100644 --- a/src/Symfony/Component/Process/Pipes/WindowsPipes.php +++ b/src/Symfony/Component/Process/Pipes/WindowsPipes.php @@ -51,9 +51,10 @@ class WindowsPipes extends AbstractPipes Process::STDOUT => Process::OUT, Process::STDERR => Process::ERR, ); + $tmpCheck = false; $tmpDir = sys_get_temp_dir(); - $error = 'unknown reason'; - set_error_handler(function ($type, $msg) use (&$error) { $error = $msg; }); + $lastError = 'unknown reason'; + set_error_handler(function ($type, $msg) use (&$lastError) { $lastError = $msg; }); for ($i = 0;; ++$i) { foreach ($pipes as $pipe => $name) { $file = sprintf('%s\\sf_proc_%02X.%s', $tmpDir, $i, $name); @@ -61,7 +62,11 @@ class WindowsPipes extends AbstractPipes continue 2; } $h = fopen($file, 'xb'); - if (!$h && false === strpos($error, 'File exists')) { + if (!$h) { + $error = $lastError; + if ($tmpCheck || $tmpCheck = unlink(tempnam(false, 'sf_check_'))) { + continue; + } restore_error_handler(); throw new RuntimeException(sprintf('A temporary file could not be opened to write the process output: %s', $error)); } From 3265932cc7af83add2be9b2073e8db8fc648fec6 Mon Sep 17 00:00:00 2001 From: Maxime Steinhausser Date: Sat, 13 Aug 2016 20:12:16 +0200 Subject: [PATCH 3/9] Remove 3.0 from branch suggestions for fixes in 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 71c775edb8..99ba8e0021 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,6 +1,6 @@ | Q | A | ------------- | --- -| Branch? | "master" for new features / 2.7, 2.8, 3.0 or 3.1 for fixes +| Branch? | "master" for new features / 2.7, 2.8 or 3.1 for fixes | Bug fix? | yes/no | New feature? | yes/no | BC breaks? | yes/no From 359204f056b20b5833c18b483e401c0516a3c425 Mon Sep 17 00:00:00 2001 From: Roland Franssen Date: Sun, 7 Aug 2016 19:36:18 +0000 Subject: [PATCH 4/9] fixes --- .../Resources/translations/validators.nl.xlf | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf index fe3346973e..8cc972cc5f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf @@ -4,7 +4,7 @@ This value should be false. - Deze waarde mag niet waar zijn. + Deze waarde moet onwaar zijn. This value should be true. @@ -36,7 +36,7 @@ This field was not expected. - Dit veld was niet verwacht. + Dit veld werd niet verwacht. This field is missing. @@ -56,7 +56,7 @@ The file could not be found. - Het bestand is niet gevonden. + Het bestand kon niet gevonden worden. The file is not readable. @@ -100,7 +100,7 @@ This value is not valid. - Deze waarde is ongeldig. + Deze waarde is niet geldig. This value is not a valid time. @@ -124,7 +124,7 @@ The file could not be uploaded. - Het bestand kon niet geüpload worden. + Het bestand kon niet worden geüpload. This value should be a valid number. @@ -140,15 +140,15 @@ This value is not a valid language. - Deze waarde representeert geen geldige taal. + Deze waarde is geen geldige taal. This value is not a valid locale. - Deze waarde representeert geen geldige lokalisering. + Deze waarde is geen geldige locale. This value is not a valid country. - Deze waarde representeert geen geldig land. + Deze waarde is geen geldig land. This value is already used. @@ -184,7 +184,7 @@ The file was only partially uploaded. - Het bestand is niet geheel geüpload. + Het bestand is slechts gedeeltelijk geüpload. No file was uploaded. From 4e8bfc65afc2bb652296cfaac86b2fcec94b4576 Mon Sep 17 00:00:00 2001 From: Leo Feyer Date: Mon, 8 Aug 2016 09:03:44 +0200 Subject: [PATCH 5/9] Enhance the phpDoc return types so IDEs can handle the configuration tree. --- src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php | 2 +- .../Component/Config/Definition/Builder/NodeDefinition.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php b/src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php index b2b63368e2..2a063f1bd9 100644 --- a/src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php +++ b/src/Symfony/Component/Config/Definition/Builder/NodeBuilder.php @@ -138,7 +138,7 @@ class NodeBuilder implements NodeParentInterface /** * Returns the parent node. * - * @return ParentNodeDefinitionInterface The parent node + * @return ParentNodeDefinitionInterface|NodeDefinition The parent node */ public function end() { diff --git a/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php b/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php index f7f84bc071..4633dc7d2a 100644 --- a/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php +++ b/src/Symfony/Component/Config/Definition/Builder/NodeDefinition.php @@ -107,7 +107,7 @@ abstract class NodeDefinition implements NodeParentInterface /** * Returns the parent node. * - * @return NodeParentInterface|null The builder of the parent node + * @return NodeParentInterface|NodeBuilder|NodeDefinition|null The builder of the parent node */ public function end() { From 289531f0d0f57ed6f82b5665df7d861b21271477 Mon Sep 17 00:00:00 2001 From: James Halsall Date: Sun, 17 Jul 2016 15:16:09 +0100 Subject: [PATCH 6/9] [Form] Skip CSRF validation on form when POST max size is exceeded --- .../Resources/config/form_csrf.xml | 1 + .../EventListener/CsrfValidationListener.php | 12 ++++++++-- .../Csrf/Type/FormTypeCsrfExtension.php | 12 ++++++++-- .../HttpFoundationRequestHandler.php | 5 +---- .../Component/Form/NativeRequestHandler.php | 5 +---- .../CsrfValidationListenerTest.php | 22 +++++++++++++++++++ .../Component/Form/Util/ServerParams.php | 13 +++++++++++ 7 files changed, 58 insertions(+), 12 deletions(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form_csrf.xml b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form_csrf.xml index f20552ed18..5da44c464e 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/form_csrf.xml +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/form_csrf.xml @@ -16,6 +16,7 @@ %form.type_extension.csrf.field_name% %validator.translation_domain% + diff --git a/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php b/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php index 64378336e9..034f30612d 100644 --- a/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php +++ b/src/Symfony/Component/Form/Extension/Csrf/EventListener/CsrfValidationListener.php @@ -18,6 +18,7 @@ use Symfony\Component\Form\Extension\Csrf\CsrfProvider\CsrfProviderInterface; use Symfony\Component\Form\FormEvents; use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormEvent; +use Symfony\Component\Form\Util\ServerParams; use Symfony\Component\Security\Csrf\CsrfToken; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; use Symfony\Component\Translation\TranslatorInterface; @@ -68,6 +69,11 @@ class CsrfValidationListener implements EventSubscriberInterface */ private $translationDomain; + /** + * @var ServerParams + */ + private $serverParams; + public static function getSubscribedEvents() { return array( @@ -75,7 +81,7 @@ class CsrfValidationListener implements EventSubscriberInterface ); } - public function __construct($fieldName, $tokenManager, $tokenId, $errorMessage, TranslatorInterface $translator = null, $translationDomain = null) + public function __construct($fieldName, $tokenManager, $tokenId, $errorMessage, TranslatorInterface $translator = null, $translationDomain = null, ServerParams $serverParams = null) { if ($tokenManager instanceof CsrfProviderInterface) { $tokenManager = new CsrfProviderAdapter($tokenManager); @@ -89,13 +95,15 @@ class CsrfValidationListener implements EventSubscriberInterface $this->errorMessage = $errorMessage; $this->translator = $translator; $this->translationDomain = $translationDomain; + $this->serverParams = $serverParams ?: new ServerParams(); } public function preSubmit(FormEvent $event) { $form = $event->getForm(); + $postRequestSizeExceeded = $form->getConfig()->getMethod() === 'POST' && $this->serverParams->hasPostMaxSizeBeenExceeded(); - if ($form->isRoot() && $form->getConfig()->getOption('compound')) { + if ($form->isRoot() && $form->getConfig()->getOption('compound') && !$postRequestSizeExceeded) { $data = $event->getData(); if (!isset($data[$this->fieldName]) || !$this->tokenManager->isTokenValid(new CsrfToken($this->tokenId, $data[$this->fieldName]))) { diff --git a/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php b/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php index 35d8648215..2a34ef0e9e 100644 --- a/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php +++ b/src/Symfony/Component/Form/Extension/Csrf/Type/FormTypeCsrfExtension.php @@ -20,6 +20,7 @@ use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormView; use Symfony\Component\Form\FormInterface; +use Symfony\Component\Form\Util\ServerParams; use Symfony\Component\OptionsResolver\Options; use Symfony\Component\OptionsResolver\OptionsResolver; use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface; @@ -55,7 +56,12 @@ class FormTypeCsrfExtension extends AbstractTypeExtension */ private $translationDomain; - public function __construct($defaultTokenManager, $defaultEnabled = true, $defaultFieldName = '_token', TranslatorInterface $translator = null, $translationDomain = null) + /** + * @var ServerParams + */ + private $serverParams; + + public function __construct($defaultTokenManager, $defaultEnabled = true, $defaultFieldName = '_token', TranslatorInterface $translator = null, $translationDomain = null, ServerParams $serverParams = null) { if ($defaultTokenManager instanceof CsrfProviderInterface) { $defaultTokenManager = new CsrfProviderAdapter($defaultTokenManager); @@ -68,6 +74,7 @@ class FormTypeCsrfExtension extends AbstractTypeExtension $this->defaultFieldName = $defaultFieldName; $this->translator = $translator; $this->translationDomain = $translationDomain; + $this->serverParams = $serverParams; } /** @@ -89,7 +96,8 @@ class FormTypeCsrfExtension extends AbstractTypeExtension $options['csrf_token_id'] ?: ($builder->getName() ?: get_class($builder->getType()->getInnerType())), $options['csrf_message'], $this->translator, - $this->translationDomain + $this->translationDomain, + $this->serverParams )) ; } diff --git a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php index 98bbd4b9ce..d1e5eece7b 100644 --- a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php +++ b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php @@ -73,10 +73,7 @@ class HttpFoundationRequestHandler implements RequestHandlerInterface // Mark the form with an error if the uploaded size was too large // This is done here and not in FormValidator because $_POST is // empty when that error occurs. Hence the form is never submitted. - $contentLength = $this->serverParams->getContentLength(); - $maxContentLength = $this->serverParams->getPostMaxSize(); - - if (!empty($maxContentLength) && $contentLength > $maxContentLength) { + if ($this->serverParams->hasPostMaxSizeBeenExceeded()) { // Submit the form, but don't clear the default values $form->submit(null, false); diff --git a/src/Symfony/Component/Form/NativeRequestHandler.php b/src/Symfony/Component/Form/NativeRequestHandler.php index 36a7d7cff2..5541e96ad5 100644 --- a/src/Symfony/Component/Form/NativeRequestHandler.php +++ b/src/Symfony/Component/Form/NativeRequestHandler.php @@ -81,10 +81,7 @@ class NativeRequestHandler implements RequestHandlerInterface // Mark the form with an error if the uploaded size was too large // This is done here and not in FormValidator because $_POST is // empty when that error occurs. Hence the form is never submitted. - $contentLength = $this->serverParams->getContentLength(); - $maxContentLength = $this->serverParams->getPostMaxSize(); - - if (!empty($maxContentLength) && $contentLength > $maxContentLength) { + if ($this->serverParams->hasPostMaxSizeBeenExceeded()) { // Submit the form, but don't clear the default values $form->submit(null, false); diff --git a/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php b/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php index 7206ceede7..4904b679dd 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Csrf/EventListener/CsrfValidationListenerTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Form\Tests\Extension\Csrf\EventListener; +use Symfony\Component\Form\Form; use Symfony\Component\Form\FormBuilder; use Symfony\Component\Form\FormEvent; use Symfony\Component\Form\Extension\Csrf\EventListener\CsrfValidationListener; @@ -72,4 +73,25 @@ class CsrfValidationListenerTest extends \PHPUnit_Framework_TestCase // Validate accordingly $this->assertSame($data, $event->getData()); } + + public function testMaxPostSizeExceeded() + { + $serverParams = $this + ->getMockBuilder('\Symfony\Component\Form\Util\ServerParams') + ->disableOriginalConstructor() + ->getMock() + ; + + $serverParams + ->expects($this->once()) + ->method('hasPostMaxSizeBeenExceeded') + ->willReturn(true) + ; + + $event = new FormEvent($this->form, array('csrf' => 'token')); + $validation = new CsrfValidationListener('csrf', $this->tokenManager, 'unknown', 'Error message', null, null, $serverParams); + + $validation->preSubmit($event); + $this->assertEmpty($this->form->getErrors()); + } } diff --git a/src/Symfony/Component/Form/Util/ServerParams.php b/src/Symfony/Component/Form/Util/ServerParams.php index c4da49db84..b9f5aaff55 100644 --- a/src/Symfony/Component/Form/Util/ServerParams.php +++ b/src/Symfony/Component/Form/Util/ServerParams.php @@ -25,6 +25,19 @@ class ServerParams $this->requestStack = $requestStack; } + /** + * Returns true if the POST max size has been exceeded in the request. + * + * @return bool + */ + public function hasPostMaxSizeBeenExceeded() + { + $contentLength = $this->getContentLength(); + $maxContentLength = $this->getPostMaxSize(); + + return $maxContentLength && $contentLength > $maxContentLength; + } + /** * Returns maximum post size in bytes. * From c42ac660cbf4e944fdb942fb5737b22b978552dc Mon Sep 17 00:00:00 2001 From: Marcel Hernandez Date: Fri, 5 Aug 2016 15:48:20 +0200 Subject: [PATCH 7/9] [HttpFoundation] fixed Request::getContent() reusage bug --- src/Symfony/Component/HttpFoundation/Request.php | 2 +- .../HttpFoundation/Tests/RequestTest.php | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/Request.php b/src/Symfony/Component/HttpFoundation/Request.php index 125be18bbb..dc32f4a39a 100644 --- a/src/Symfony/Component/HttpFoundation/Request.php +++ b/src/Symfony/Component/HttpFoundation/Request.php @@ -1516,7 +1516,7 @@ class Request return stream_get_contents($this->content); } - if (null === $this->content) { + if (null === $this->content || false === $this->content) { $this->content = file_get_contents('php://input'); } diff --git a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php index 8540cad663..f90a368775 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/RequestTest.php @@ -1042,8 +1042,16 @@ class RequestTest extends \PHPUnit_Framework_TestCase $req->getContent($second); } + public function getContentCantBeCalledTwiceWithResourcesProvider() + { + return array( + 'Resource then fetch' => array(true, false), + 'Resource then resource' => array(true, true), + ); + } + /** - * @dataProvider getContentCantBeCalledTwiceWithResourcesProvider + * @dataProvider getContentCanBeCalledTwiceWithResourcesProvider * @requires PHP 5.6 */ public function testGetContentCanBeCalledTwiceWithResources($first, $second) @@ -1060,12 +1068,14 @@ class RequestTest extends \PHPUnit_Framework_TestCase $b = stream_get_contents($b); } - $this->assertEquals($a, $b); + $this->assertSame($a, $b); } - public function getContentCantBeCalledTwiceWithResourcesProvider() + public function getContentCanBeCalledTwiceWithResourcesProvider() { return array( + 'Fetch then fetch' => array(false, false), + 'Fetch then resource' => array(false, true), 'Resource then fetch' => array(true, false), 'Resource then resource' => array(true, true), ); From da96719b94fae82ab7fc1c783256f53f47f50975 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 16 Aug 2016 10:16:14 +0200 Subject: [PATCH 8/9] [VarDumper] Fix dumping continuations --- .../DataCollector/DumpDataCollector.php | 3 +- .../Component/VarDumper/Dumper/HtmlDumper.php | 16 ++--------- .../VarDumper/Tests/HtmlDumperTest.php | 28 +++++++++++++++++-- 3 files changed, 29 insertions(+), 18 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php b/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php index c50bf7a135..635402e160 100644 --- a/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php +++ b/src/Symfony/Component/HttpKernel/DataCollector/DumpDataCollector.php @@ -211,8 +211,7 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface // getLimitedClone is @deprecated, to be removed in 3.0 $dumper->dump($dump['data']->getLimitedClone($maxDepthLimit, $maxItemsPerDepth)); } - rewind($data); - $dump['data'] = stream_get_contents($data); + $dump['data'] = stream_get_contents($data, -1, 0); ftruncate($data, 0); rewind($data); $dumps[] = $dump; diff --git a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php index 43601fe668..0b032b71e6 100644 --- a/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php +++ b/src/Symfony/Component/VarDumper/Dumper/HtmlDumper.php @@ -54,18 +54,6 @@ class HtmlDumper extends CliDumper $this->dumpId = 'sf-dump-'.mt_rand(); } - /** - * {@inheritdoc} - */ - public function setOutput($output) - { - if ($output !== $prev = parent::setOutput($output)) { - $this->headerIsDumped = false; - } - - return $prev; - } - /** * {@inheritdoc} */ @@ -111,7 +99,7 @@ class HtmlDumper extends CliDumper */ protected function getDumpHeader() { - $this->headerIsDumped = true; + $this->headerIsDumped = null !== $this->outputStream ? $this->outputStream : $this->lineDumper; if (null !== $this->dumpHeader) { return $this->dumpHeader; @@ -433,7 +421,7 @@ EOHTML; if (-1 === $this->lastDepth) { $this->line = sprintf($this->dumpPrefix, $this->dumpId, $this->indentPad).$this->line; } - if (!$this->headerIsDumped) { + if ($this->headerIsDumped !== (null !== $this->outputStream ? $this->outputStream : $this->lineDumper)) { $this->line = $this->getDumpHeader().$this->line; } diff --git a/src/Symfony/Component/VarDumper/Tests/HtmlDumperTest.php b/src/Symfony/Component/VarDumper/Tests/HtmlDumperTest.php index 1171bb8083..30495f7c40 100644 --- a/src/Symfony/Component/VarDumper/Tests/HtmlDumperTest.php +++ b/src/Symfony/Component/VarDumper/Tests/HtmlDumperTest.php @@ -132,8 +132,7 @@ EOTXT $data = $cloner->cloneVar($var); $out = fopen('php://memory', 'r+b'); $dumper->dump($data, $out); - rewind($out); - $out = stream_get_contents($out); + $out = stream_get_contents($out, -1, 0); $this->assertStringMatchesFormat( <<setDumpHeader(''); + $dumper->setDumpBoundaries('', ''); + $cloner = new VarCloner(); + + $dumper->dump($cloner->cloneVar(123), $out); + $dumper->dump($cloner->cloneVar(456), $out); + + $out = stream_get_contents($out, -1, 0); + + $this->assertSame(<<<'EOTXT' +123 + +456 + + +EOTXT + , $out ); } From f45da32488b907ab1d20ba4d9555cd43c3a53ff1 Mon Sep 17 00:00:00 2001 From: Christian Schmidt Date: Sun, 7 Aug 2016 16:57:36 +0200 Subject: [PATCH 9/9] [Routing] Add missing options in docblock --- src/Symfony/Component/Routing/Router.php | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Routing/Router.php b/src/Symfony/Component/Routing/Router.php index d43029e706..a04385ead4 100644 --- a/src/Symfony/Component/Routing/Router.php +++ b/src/Symfony/Component/Routing/Router.php @@ -106,9 +106,19 @@ class Router implements RouterInterface, RequestMatcherInterface * * Available options: * - * * cache_dir: The cache directory (or null to disable caching) - * * debug: Whether to enable debugging or not (false by default) - * * resource_type: Type hint for the main resource (optional) + * * cache_dir: The cache directory (or null to disable caching) + * * debug: Whether to enable debugging or not (false by default) + * * generator_class: The name of a UrlGeneratorInterface implementation + * * generator_base_class: The base class for the dumped generator class + * * generator_cache_class: The class name for the dumped generator class + * * generator_dumper_class: The name of a GeneratorDumperInterface implementation + * * matcher_class: The name of a UrlMatcherInterface implementation + * * matcher_base_class: The base class for the dumped matcher class + * * matcher_dumper_class: The class name for the dumped matcher class + * * matcher_cache_class: The name of a MatcherDumperInterface implementation + * * resource_type: Type hint for the main resource (optional) + * * strict_requirements: Configure strict requirement checking for generators + * implementing ConfigurableRequirementsInterface (default is true) * * @param array $options An array of options *