From ffe3f10780e73fa4358e1001d16531326d6d3447 Mon Sep 17 00:00:00 2001 From: Michel Roca Date: Mon, 25 Nov 2019 17:15:20 +0100 Subject: [PATCH 1/9] [MonologBridge] Fix debug processor datetime type --- .../Monolog/Processor/DebugProcessor.php | 2 +- .../Tests/Processor/DebugProcessorTest.php | 61 +++++++++++++++++++ 2 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Bridge/Monolog/Tests/Processor/DebugProcessorTest.php diff --git a/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php b/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php index 3950268fb2..2d4529f296 100644 --- a/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php +++ b/src/Symfony/Bridge/Monolog/Processor/DebugProcessor.php @@ -22,7 +22,7 @@ class DebugProcessor implements DebugLoggerInterface public function __invoke(array $record) { $this->records[] = [ - 'timestamp' => $record['datetime']->getTimestamp(), + 'timestamp' => $record['datetime'] instanceof \DateTimeInterface ? $record['datetime']->getTimestamp() : strtotime($record['datetime']), 'message' => $record['message'], 'priority' => $record['level'], 'priorityName' => $record['level_name'], diff --git a/src/Symfony/Bridge/Monolog/Tests/Processor/DebugProcessorTest.php b/src/Symfony/Bridge/Monolog/Tests/Processor/DebugProcessorTest.php new file mode 100644 index 0000000000..d9fcccafcb --- /dev/null +++ b/src/Symfony/Bridge/Monolog/Tests/Processor/DebugProcessorTest.php @@ -0,0 +1,61 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Monolog\Tests\Processor; + +use Monolog\Logger; +use PHPUnit\Framework\TestCase; +use Symfony\Bridge\Monolog\Processor\DebugProcessor; + +class DebugProcessorTest extends TestCase +{ + /** + * @dataProvider providerDatetimeFormatTests + */ + public function testDatetimeFormat(array $record, $expectedTimestamp) + { + $processor = new DebugProcessor(); + $processor($record); + + $records = $processor->getLogs(); + self::assertCount(1, $records); + self::assertSame($expectedTimestamp, $records[0]['timestamp']); + } + + /** + * @return array + */ + public function providerDatetimeFormatTests() + { + $record = $this->getRecord(); + + return [ + [array_merge($record, ['datetime' => new \DateTime('2019-01-01T00:01:00+00:00')]), 1546300860], + [array_merge($record, ['datetime' => '2019-01-01T00:01:00+00:00']), 1546300860], + [array_merge($record, ['datetime' => 'foo']), false], + ]; + } + + /** + * @return array + */ + private function getRecord() + { + return [ + 'message' => 'test', + 'context' => [], + 'level' => Logger::DEBUG, + 'level_name' => Logger::getLevelName(Logger::DEBUG), + 'channel' => 'test', + 'datetime' => new \DateTime(), + ]; + } +} From e1145a78b5b783285a27eeb56e221915e9df11ed Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 9 Dec 2019 10:31:37 +0100 Subject: [PATCH 2/9] add tags before processing them --- src/Symfony/Bundle/TwigBundle/TwigBundle.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/TwigBundle/TwigBundle.php b/src/Symfony/Bundle/TwigBundle/TwigBundle.php index bd766c1521..5a353833eb 100644 --- a/src/Symfony/Bundle/TwigBundle/TwigBundle.php +++ b/src/Symfony/Bundle/TwigBundle/TwigBundle.php @@ -32,7 +32,8 @@ class TwigBundle extends Bundle { parent::build($container); - $container->addCompilerPass(new ExtensionPass()); + // ExtensionPass must be run before the FragmentRendererPass as it adds tags that are processed later + $container->addCompilerPass(new ExtensionPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 10); $container->addCompilerPass(new TwigEnvironmentPass()); $container->addCompilerPass(new TwigLoaderPass()); $container->addCompilerPass(new ExceptionListenerPass()); From 03dbcf87948b86899707294d6181b8cf63649ed9 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Mon, 9 Dec 2019 14:42:15 +0100 Subject: [PATCH 3/9] [Validator][ConstraintValidator] Stop passing unnecessary timezone argument to \DateTime --- src/Symfony/Component/Validator/ConstraintValidator.php | 5 +---- .../Constraints/AbstractComparisonValidatorTestCase.php | 5 +---- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/Validator/ConstraintValidator.php b/src/Symfony/Component/Validator/ConstraintValidator.php index 93cca2ea74..8469926561 100644 --- a/src/Symfony/Component/Validator/ConstraintValidator.php +++ b/src/Symfony/Component/Validator/ConstraintValidator.php @@ -93,10 +93,7 @@ abstract class ConstraintValidator implements ConstraintValidatorInterface // neither the native nor the stub IntlDateFormatter support // DateTimeImmutable as of yet if (!$value instanceof \DateTime) { - $value = new \DateTime( - $value->format('Y-m-d H:i:s.u e'), - $value->getTimezone() - ); + $value = new \DateTime($value->format('Y-m-d H:i:s.u e')); } return $formatter->format($value); diff --git a/src/Symfony/Component/Validator/Tests/Constraints/AbstractComparisonValidatorTestCase.php b/src/Symfony/Component/Validator/Tests/Constraints/AbstractComparisonValidatorTestCase.php index b02e57cfa2..6cee07cc64 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/AbstractComparisonValidatorTestCase.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/AbstractComparisonValidatorTestCase.php @@ -53,10 +53,7 @@ abstract class AbstractComparisonValidatorTestCase extends ConstraintValidatorTe foreach ($comparison as $i => $value) { if ($value instanceof \DateTime) { - $comparison[$i] = new \DateTimeImmutable( - $value->format('Y-m-d H:i:s.u e'), - $value->getTimezone() - ); + $comparison[$i] = new \DateTimeImmutable($value->format('Y-m-d H:i:s.u e')); $add = true; } elseif ('DateTime' === $value) { $comparison[$i] = 'DateTimeImmutable'; From 98e18d33df143da487324d9af4435aaf668495fd Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Mon, 9 Dec 2019 21:23:16 +0100 Subject: [PATCH 4/9] forward caught exception --- src/Symfony/Component/PropertyAccess/PropertyAccessor.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 4297d3947f..7aff347134 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -229,7 +229,7 @@ class PropertyAccessor implements PropertyAccessorInterface $value = $zval[self::VALUE]; } } catch (\TypeError $e) { - self::throwInvalidArgumentException($e->getMessage(), $e->getTrace(), 0); + self::throwInvalidArgumentException($e->getMessage(), $e->getTrace(), 0, $e); // It wasn't thrown in this class so rethrow it throw $e; @@ -253,7 +253,7 @@ class PropertyAccessor implements PropertyAccessorInterface return null !== self::$previousErrorHandler && false !== \call_user_func(self::$previousErrorHandler, $type, $message, $file, $line, $context); } - private static function throwInvalidArgumentException($message, $trace, $i) + private static function throwInvalidArgumentException($message, $trace, $i, $previous = null) { // the type mismatch is not caused by invalid arguments (but e.g. by an incompatible return type hint of the writer method) if (0 !== strpos($message, 'Argument ')) { @@ -267,7 +267,7 @@ class PropertyAccessor implements PropertyAccessorInterface $type = substr($message, 2 + $j, strpos($message, ' given', $j) - $j - 2); $message = substr($message, $pos, $j - $pos); - throw new InvalidArgumentException(sprintf('Expected argument of type "%s", "%s" given', $message, 'NULL' === $type ? 'null' : $type)); + throw new InvalidArgumentException(sprintf('Expected argument of type "%s", "%s" given', $message, 'NULL' === $type ? 'null' : $type), 0, $previous); } } From 02ab72ab3073f84a70d2f1cab286c31100beb313 Mon Sep 17 00:00:00 2001 From: Ivan Date: Sun, 8 Dec 2019 11:15:22 +0300 Subject: [PATCH 5/9] [ExpressionLanguage][Node][BinaryNode] Process division by zero --- .../Component/ExpressionLanguage/Node/BinaryNode.php | 8 ++++++++ src/Symfony/Component/ExpressionLanguage/composer.json | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/ExpressionLanguage/Node/BinaryNode.php b/src/Symfony/Component/ExpressionLanguage/Node/BinaryNode.php index 92378102be..bbfe393d0d 100644 --- a/src/Symfony/Component/ExpressionLanguage/Node/BinaryNode.php +++ b/src/Symfony/Component/ExpressionLanguage/Node/BinaryNode.php @@ -147,8 +147,16 @@ class BinaryNode extends Node case '*': return $left * $right; case '/': + if (0 == $right) { + throw new \DivisionByZeroError('Division by zero'); + } + return $left / $right; case '%': + if (0 == $right) { + throw new \DivisionByZeroError('Modulo by zero'); + } + return $left % $right; case 'matches': return preg_match($right, $left); diff --git a/src/Symfony/Component/ExpressionLanguage/composer.json b/src/Symfony/Component/ExpressionLanguage/composer.json index 5f662ffd38..ee44185134 100644 --- a/src/Symfony/Component/ExpressionLanguage/composer.json +++ b/src/Symfony/Component/ExpressionLanguage/composer.json @@ -17,7 +17,8 @@ ], "require": { "php": "^5.5.9|>=7.0.8", - "symfony/cache": "~3.1|~4.0" + "symfony/cache": "~3.1|~4.0", + "symfony/polyfill-php70": "~1.6" }, "autoload": { "psr-4": { "Symfony\\Component\\ExpressionLanguage\\": "" }, From 4d3b73e688b53b91986596eda84a3cdabeeca06b Mon Sep 17 00:00:00 2001 From: Artem Henvald Date: Tue, 3 Dec 2019 14:21:05 +0200 Subject: [PATCH 6/9] [CI] Replace php7.4snapshot with php7.4 in Travis configuration --- .travis.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 99595ca5f8..8574ad92a0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: php -dist: trusty +dist: xenial git: depth: 2 @@ -24,9 +24,10 @@ matrix: include: - php: 5.5 env: php_extra="5.6 7.0 7.1 7.2" + dist: trusty - php: 7.3 env: deps=high - - php: 7.4snapshot + - php: 7.4 env: deps=low fast_finish: true From 9f1ebd7fb9cb71abb667f7a6eefd29d7f6edc7bb Mon Sep 17 00:00:00 2001 From: Arman Hosseini Date: Sat, 30 Nov 2019 00:24:54 +0330 Subject: [PATCH 7/9] [FrameworkBundle] Use UserInterface to @return in getUser method --- .../Bundle/FrameworkBundle/Controller/ControllerTrait.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php index cb339cd15e..6bc3f7ae29 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php +++ b/src/Symfony/Bundle/FrameworkBundle/Controller/ControllerTrait.php @@ -26,6 +26,7 @@ use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\HttpKernel\HttpKernelInterface; use Symfony\Component\Routing\Generator\UrlGeneratorInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException; +use Symfony\Component\Security\Core\User\UserInterface; use Symfony\Component\Security\Csrf\CsrfToken; /** @@ -431,7 +432,7 @@ trait ControllerTrait /** * Get a user from the Security Token Storage. * - * @return object|null + * @return UserInterface|object|null * * @throws \LogicException If SecurityBundle is not available * From 1b1002b42667a525efd5e991ac856d1087172107 Mon Sep 17 00:00:00 2001 From: Matthias Pigulla Date: Mon, 18 Nov 2019 13:24:53 +0000 Subject: [PATCH 8/9] [HttpFoundation] Use `Cache-Control: must-revalidate` only if explicit lifetime has been given --- .../Component/HttpFoundation/ResponseHeaderBag.php | 10 +++++----- .../HttpFoundation/Tests/ResponseHeaderBagTest.php | 4 ++-- .../HttpKernel/HttpCache/ResponseCacheStrategy.php | 2 -- .../HttpKernel/Tests/HttpCache/HttpCacheTest.php | 2 -- 4 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php b/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php index 1dc8dc2c5f..e11b98a10f 100644 --- a/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php +++ b/src/Symfony/Component/HttpFoundation/ResponseHeaderBag.php @@ -309,13 +309,13 @@ class ResponseHeaderBag extends HeaderBag */ protected function computeCacheControlValue() { - if (!$this->cacheControl && !$this->has('ETag') && !$this->has('Last-Modified') && !$this->has('Expires')) { - return 'no-cache, private'; - } - if (!$this->cacheControl) { + if ($this->has('Last-Modified') || $this->has('Expires')) { + return 'private, must-revalidate'; // allows for heuristic expiration (RFC 7234 Section 4.2.2) in the case of "Last-Modified" + } + // conservative by default - return 'private, must-revalidate'; + return 'no-cache, private'; } $header = $this->getCacheControlHeader(); diff --git a/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php b/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php index d85f6e112f..4e3a6c82b5 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/ResponseHeaderBagTest.php @@ -51,9 +51,9 @@ class ResponseHeaderBagTest extends TestCase $this->assertTrue($bag->hasCacheControlDirective('public')); $bag = new ResponseHeaderBag(['ETag' => 'abcde']); - $this->assertEquals('private, must-revalidate', $bag->get('Cache-Control')); + $this->assertEquals('no-cache, private', $bag->get('Cache-Control')); $this->assertTrue($bag->hasCacheControlDirective('private')); - $this->assertTrue($bag->hasCacheControlDirective('must-revalidate')); + $this->assertTrue($bag->hasCacheControlDirective('no-cache')); $this->assertFalse($bag->hasCacheControlDirective('max-age')); $bag = new ResponseHeaderBag(['Expires' => 'Wed, 16 Feb 2011 14:17:43 GMT']); diff --git a/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php b/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php index 3bdf0f5199..aee689e1ce 100644 --- a/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php +++ b/src/Symfony/Component/HttpKernel/HttpCache/ResponseCacheStrategy.php @@ -110,8 +110,6 @@ class ResponseCacheStrategy implements ResponseCacheStrategyInterface $response->headers->set('Age', $this->age); if ($this->isNotCacheableResponseEmbedded) { - $response->setExpires($response->getDate()); - if ($this->flagDirectives['no-store']) { $response->headers->set('Cache-Control', 'no-cache, no-store, must-revalidate'); } else { diff --git a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php index 93d92eb11e..a4e30444a5 100644 --- a/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php +++ b/src/Symfony/Component/HttpKernel/Tests/HttpCache/HttpCacheTest.php @@ -1242,7 +1242,6 @@ class HttpCacheTest extends HttpCacheTestCase $this->request('GET', '/', [], [], true); $this->assertEquals('Hello World! My name is Bobby.', $this->response->getContent()); $this->assertNull($this->response->getTtl()); - $this->assertTrue($this->response->mustRevalidate()); $this->assertTrue($this->response->headers->hasCacheControlDirective('private')); $this->assertTrue($this->response->headers->hasCacheControlDirective('no-cache')); } @@ -1273,7 +1272,6 @@ class HttpCacheTest extends HttpCacheTestCase // This can neither be cached nor revalidated, so it should be private/no cache $this->assertEmpty($this->response->getContent()); $this->assertNull($this->response->getTtl()); - $this->assertTrue($this->response->mustRevalidate()); $this->assertTrue($this->response->headers->hasCacheControlDirective('private')); $this->assertTrue($this->response->headers->hasCacheControlDirective('no-cache')); } From 84241d4e62cac72ce9d7c02d51f4f837ec391fa2 Mon Sep 17 00:00:00 2001 From: natepage Date: Tue, 19 Nov 2019 20:02:51 +1100 Subject: [PATCH 9/9] [Yaml] Implement multiline string as scalar block for tagged values --- src/Symfony/Component/Yaml/Dumper.php | 15 ++++++++- .../Component/Yaml/Tests/DumperTest.php | 33 +++++++++++++++++++ ...nes_as_literal_block_for_tagged_values.yml | 2 ++ 3 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 src/Symfony/Component/Yaml/Tests/Fixtures/multiple_lines_as_literal_block_for_tagged_values.yml diff --git a/src/Symfony/Component/Yaml/Dumper.php b/src/Symfony/Component/Yaml/Dumper.php index a496dcc88e..641dcd7f54 100644 --- a/src/Symfony/Component/Yaml/Dumper.php +++ b/src/Symfony/Component/Yaml/Dumper.php @@ -105,7 +105,7 @@ class Dumper $blockIndentationIndicator = (' ' === substr($value, 0, 1)) ? (string) $this->indentation : ''; $output .= sprintf("%s%s%s |%s\n", $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', '', $blockIndentationIndicator); - foreach (preg_split('/\n|\r\n/', $value) as $row) { + foreach (explode("\n", $value) as $row) { $output .= sprintf("%s%s%s\n", $prefix, str_repeat(' ', $this->indentation), $row); } @@ -115,6 +115,19 @@ class Dumper if ($value instanceof TaggedValue) { $output .= sprintf('%s%s !%s', $prefix, $dumpAsMap ? Inline::dump($key, $flags).':' : '-', $value->getTag()); + if ($inline >= 1 && Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK & $flags && \is_string($value->getValue()) && false !== strpos($value->getValue(), "\n") && false === strpos($value->getValue(), "\r\n")) { + // If the first line starts with a space character, the spec requires a blockIndicationIndicator + // http://www.yaml.org/spec/1.2/spec.html#id2793979 + $blockIndentationIndicator = (' ' === substr($value->getValue(), 0, 1)) ? (string) $this->indentation : ''; + $output .= sprintf(" |%s\n", $blockIndentationIndicator); + + foreach (explode("\n", $value->getValue()) as $row) { + $output .= sprintf("%s%s%s\n", $prefix, str_repeat(' ', $this->indentation), $row); + } + + continue; + } + if ($inline - 1 <= 0 || null === $value->getValue() || is_scalar($value->getValue())) { $output .= ' '.$this->dump($value->getValue(), $inline - 1, 0, $flags)."\n"; } else { diff --git a/src/Symfony/Component/Yaml/Tests/DumperTest.php b/src/Symfony/Component/Yaml/Tests/DumperTest.php index 1a1ef25a5a..231cf9a838 100644 --- a/src/Symfony/Component/Yaml/Tests/DumperTest.php +++ b/src/Symfony/Component/Yaml/Tests/DumperTest.php @@ -553,6 +553,39 @@ YAML; $this->assertSame($expected, $this->dumper->dump($data, 2)); } + public function testDumpingMultiLineStringAsScalarBlockTaggedValue() + { + $data = [ + 'foo' => new TaggedValue('bar', "foo\nline with trailing spaces:\n \nbar\ninteger like line:\n123456789\nempty line:\n\nbaz"), + ]; + $expected = <<assertSame($expected, $this->dumper->dump($data, 2, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK)); + } + + public function testDumpingInlinedMultiLineIfRnBreakLineInTaggedValue() + { + $data = [ + 'data' => [ + 'foo' => new TaggedValue('bar', "foo\r\nline with trailing spaces:\n \nbar\ninteger like line:\n123456789\nempty line:\n\nbaz"), + ], + ]; + + $this->assertSame(file_get_contents(__DIR__.'/Fixtures/multiple_lines_as_literal_block_for_tagged_values.yml'), $this->dumper->dump($data, 2, 0, Yaml::DUMP_MULTI_LINE_LITERAL_BLOCK)); + } + public function testDumpMultiLineStringAsScalarBlock() { $data = [ diff --git a/src/Symfony/Component/Yaml/Tests/Fixtures/multiple_lines_as_literal_block_for_tagged_values.yml b/src/Symfony/Component/Yaml/Tests/Fixtures/multiple_lines_as_literal_block_for_tagged_values.yml new file mode 100644 index 0000000000..f8c9112fd5 --- /dev/null +++ b/src/Symfony/Component/Yaml/Tests/Fixtures/multiple_lines_as_literal_block_for_tagged_values.yml @@ -0,0 +1,2 @@ +data: + foo: !bar "foo\r\nline with trailing spaces:\n \nbar\ninteger like line:\n123456789\nempty line:\n\nbaz"