Merge branch '2.8' into 3.1
* 2.8: [Routing] Add missing options in docblock [VarDumper] Fix dumping continuations [HttpFoundation] fixed Request::getContent() reusage bug [Form] Skip CSRF validation on form when POST max size is exceeded Enhance the phpDoc return types so IDEs can handle the configuration tree. fixes Remove 3.0 from branch suggestions for fixes in PR template [Process] Strengthen Windows pipe files opening (again...) Fix #19531 [Form] DateType fails parsing when midnight is not a valid time
This commit is contained in:
commit
d7f8ca72e8
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
2
.github/PULL_REQUEST_TEMPLATE.md
vendored
@ -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
|
||||
|
@ -12,6 +12,7 @@
|
||||
<argument>%form.type_extension.csrf.field_name%</argument>
|
||||
<argument type="service" id="translator.default" />
|
||||
<argument>%validator.translation_domain%</argument>
|
||||
<argument type="service" id="form.server_params" />
|
||||
</service>
|
||||
</services>
|
||||
</container>
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -116,20 +116,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));
|
||||
}
|
||||
|
||||
@ -139,15 +148,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;
|
||||
|
||||
@ -162,4 +173,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);
|
||||
}
|
||||
}
|
||||
|
@ -15,6 +15,7 @@ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
|
||||
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;
|
||||
@ -65,6 +66,11 @@ class CsrfValidationListener implements EventSubscriberInterface
|
||||
*/
|
||||
private $translationDomain;
|
||||
|
||||
/**
|
||||
* @var ServerParams
|
||||
*/
|
||||
private $serverParams;
|
||||
|
||||
public static function getSubscribedEvents()
|
||||
{
|
||||
return array(
|
||||
@ -72,7 +78,7 @@ class CsrfValidationListener implements EventSubscriberInterface
|
||||
);
|
||||
}
|
||||
|
||||
public function __construct($fieldName, CsrfTokenManagerInterface $tokenManager, $tokenId, $errorMessage, TranslatorInterface $translator = null, $translationDomain = null)
|
||||
public function __construct($fieldName, CsrfTokenManagerInterface $tokenManager, $tokenId, $errorMessage, TranslatorInterface $translator = null, $translationDomain = null, ServerParams $serverParams = null)
|
||||
{
|
||||
$this->fieldName = $fieldName;
|
||||
$this->tokenManager = $tokenManager;
|
||||
@ -80,13 +86,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]))) {
|
||||
|
@ -16,6 +16,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\OptionsResolver;
|
||||
use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
|
||||
use Symfony\Component\Translation\TranslatorInterface;
|
||||
@ -50,13 +51,19 @@ class FormTypeCsrfExtension extends AbstractTypeExtension
|
||||
*/
|
||||
private $translationDomain;
|
||||
|
||||
public function __construct(CsrfTokenManagerInterface $defaultTokenManager, $defaultEnabled = true, $defaultFieldName = '_token', TranslatorInterface $translator = null, $translationDomain = null)
|
||||
/**
|
||||
* @var ServerParams
|
||||
*/
|
||||
private $serverParams;
|
||||
|
||||
public function __construct(CsrfTokenManagerInterface $defaultTokenManager, $defaultEnabled = true, $defaultFieldName = '_token', TranslatorInterface $translator = null, $translationDomain = null, ServerParams $serverParams = null)
|
||||
{
|
||||
$this->defaultTokenManager = $defaultTokenManager;
|
||||
$this->defaultEnabled = $defaultEnabled;
|
||||
$this->defaultFieldName = $defaultFieldName;
|
||||
$this->translator = $translator;
|
||||
$this->translationDomain = $translationDomain;
|
||||
$this->serverParams = $serverParams;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,7 +85,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
|
||||
))
|
||||
;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -227,6 +227,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();
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -1525,7 +1525,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');
|
||||
}
|
||||
|
||||
|
@ -1059,8 +1059,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)
|
||||
@ -1077,12 +1085,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),
|
||||
);
|
||||
|
@ -201,9 +201,7 @@ class DumpDataCollector extends DataCollector implements DataDumperInterface
|
||||
|
||||
foreach ($this->data as $dump) {
|
||||
$dumper->dump($dump['data']->withMaxDepth($maxDepthLimit)->withMaxItemsPerDepth($maxItemsPerDepth));
|
||||
|
||||
rewind($data);
|
||||
$dump['data'] = stream_get_contents($data);
|
||||
$dump['data'] = stream_get_contents($data, -1, 0);
|
||||
ftruncate($data, 0);
|
||||
rewind($data);
|
||||
$dumps[] = $dump;
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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
|
||||
*
|
||||
|
@ -4,7 +4,7 @@
|
||||
<body>
|
||||
<trans-unit id="1">
|
||||
<source>This value should be false.</source>
|
||||
<target>Deze waarde mag niet waar zijn.</target>
|
||||
<target>Deze waarde moet onwaar zijn.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="2">
|
||||
<source>This value should be true.</source>
|
||||
@ -36,7 +36,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="9">
|
||||
<source>This field was not expected.</source>
|
||||
<target>Dit veld was niet verwacht.</target>
|
||||
<target>Dit veld werd niet verwacht.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="10">
|
||||
<source>This field is missing.</source>
|
||||
@ -56,7 +56,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="14">
|
||||
<source>The file could not be found.</source>
|
||||
<target>Het bestand is niet gevonden.</target>
|
||||
<target>Het bestand kon niet gevonden worden.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="15">
|
||||
<source>The file is not readable.</source>
|
||||
@ -100,7 +100,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="25">
|
||||
<source>This value is not valid.</source>
|
||||
<target>Deze waarde is ongeldig.</target>
|
||||
<target>Deze waarde is niet geldig.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="26">
|
||||
<source>This value is not a valid time.</source>
|
||||
@ -124,7 +124,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="34">
|
||||
<source>The file could not be uploaded.</source>
|
||||
<target>Het bestand kon niet geüpload worden.</target>
|
||||
<target>Het bestand kon niet worden geüpload.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="35">
|
||||
<source>This value should be a valid number.</source>
|
||||
@ -140,15 +140,15 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="38">
|
||||
<source>This value is not a valid language.</source>
|
||||
<target>Deze waarde representeert geen geldige taal.</target>
|
||||
<target>Deze waarde is geen geldige taal.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="39">
|
||||
<source>This value is not a valid locale.</source>
|
||||
<target>Deze waarde representeert geen geldige lokalisering.</target>
|
||||
<target>Deze waarde is geen geldige locale.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="40">
|
||||
<source>This value is not a valid country.</source>
|
||||
<target>Deze waarde representeert geen geldig land.</target>
|
||||
<target>Deze waarde is geen geldig land.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="41">
|
||||
<source>This value is already used.</source>
|
||||
@ -184,7 +184,7 @@
|
||||
</trans-unit>
|
||||
<trans-unit id="49">
|
||||
<source>The file was only partially uploaded.</source>
|
||||
<target>Het bestand is niet geheel geüpload.</target>
|
||||
<target>Het bestand is slechts gedeeltelijk geüpload.</target>
|
||||
</trans-unit>
|
||||
<trans-unit id="50">
|
||||
<source>No file was uploaded.</source>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -122,8 +122,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(
|
||||
<<<EOTXT
|
||||
@ -132,7 +131,32 @@ EOTXT
|
||||
|
||||
EOTXT
|
||||
,
|
||||
$out
|
||||
);
|
||||
}
|
||||
|
||||
public function testAppend()
|
||||
{
|
||||
$out = fopen('php://memory', 'r+b');
|
||||
|
||||
$dumper = new HtmlDumper();
|
||||
$dumper->setDumpHeader('<foo></foo>');
|
||||
$dumper->setDumpBoundaries('<bar>', '</bar>');
|
||||
$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'
|
||||
<foo></foo><bar><span class=sf-dump-num>123</span>
|
||||
</bar>
|
||||
<bar><span class=sf-dump-num>456</span>
|
||||
</bar>
|
||||
|
||||
EOTXT
|
||||
,
|
||||
$out
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user