From d333aae1874f451e22cc492432c3edb335a5ed07 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Thu, 21 May 2020 21:40:39 +0200 Subject: [PATCH 01/31] never directly validate Existence (Required/Optional) constraints --- .../Tests/Validator/RecursiveValidatorTest.php | 16 ++++++++++++++++ .../Validator/RecursiveContextualValidator.php | 5 +++++ 2 files changed, 21 insertions(+) diff --git a/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php b/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php index 31871c3f9a1ed..484236241c7fa 100644 --- a/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php +++ b/src/Symfony/Component/Validator/Tests/Validator/RecursiveValidatorTest.php @@ -19,6 +19,8 @@ use Symfony\Component\Validator\Constraints\Length; use Symfony\Component\Validator\Constraints\NotBlank; use Symfony\Component\Validator\Constraints\NotNull; +use Symfony\Component\Validator\Constraints\Optional; +use Symfony\Component\Validator\Constraints\Required; use Symfony\Component\Validator\ConstraintValidatorFactory; use Symfony\Component\Validator\Context\ExecutionContextFactory; use Symfony\Component\Validator\Mapping\ClassMetadata; @@ -157,4 +159,18 @@ public function testAllConstraintValidateAllGroupsForNestedConstraints() $this->assertInstanceOf(NotBlank::class, $violations->get(0)->getConstraint()); $this->assertInstanceOf(Length::class, $violations->get(1)->getConstraint()); } + + public function testRequiredConstraintIsIgnored() + { + $violations = $this->validator->validate([], new Required()); + + $this->assertCount(0, $violations); + } + + public function testOptionalConstraintIsIgnored() + { + $violations = $this->validator->validate([], new Optional()); + + $this->assertCount(0, $violations); + } } diff --git a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php index a204cd91f6194..24206bfc27d92 100644 --- a/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php +++ b/src/Symfony/Component/Validator/Validator/RecursiveContextualValidator.php @@ -13,6 +13,7 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\Constraints\Composite; +use Symfony\Component\Validator\Constraints\Existence; use Symfony\Component\Validator\Constraints\GroupSequence; use Symfony\Component\Validator\Constraints\Valid; use Symfony\Component\Validator\ConstraintValidatorFactoryInterface; @@ -790,6 +791,10 @@ private function validateInGroup($value, $cacheKey, MetadataInterface $metadata, $context->setGroup($group); foreach ($metadata->findConstraints($group) as $constraint) { + if ($constraint instanceof Existence) { + continue; + } + // Prevent duplicate validation of constraints, in the case // that constraints belong to multiple validated groups if (null !== $cacheKey) { From 9a16c8ef270b4b99a903778b3841cb112341c7e1 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 26 May 2020 09:39:17 +0200 Subject: [PATCH 02/31] bumped Symfony version to 5.1.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 b06cb82389faa..c5313ee24f85d 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 static $freshCache = []; - const VERSION = '5.1.0-RC2'; + const VERSION = '5.1.0-DEV'; const VERSION_ID = 50100; const MAJOR_VERSION = 5; const MINOR_VERSION = 1; const RELEASE_VERSION = 0; - const EXTRA_VERSION = 'RC2'; + const EXTRA_VERSION = 'DEV'; const END_OF_MAINTENANCE = '01/2021'; const END_OF_LIFE = '01/2021'; From f3b8a585139bb3b95473a2c679c6f02b26958bc1 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Mon, 25 May 2020 17:24:52 +0200 Subject: [PATCH 03/31] [DotEnv][WebLink][Templating][ErrorHandler] Updated README with minimal example --- src/Symfony/Component/Dotenv/README.md | 24 +++++++++++++++- src/Symfony/Component/ErrorHandler/README.md | 29 ++++++++++++++++++++ src/Symfony/Component/Templating/README.md | 25 ++++++++++++++++- src/Symfony/Component/WebLink/README.md | 22 ++++++++++++++- 4 files changed, 97 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Dotenv/README.md b/src/Symfony/Component/Dotenv/README.md index 10bfff14ba78d..855b8c02a1df6 100644 --- a/src/Symfony/Component/Dotenv/README.md +++ b/src/Symfony/Component/Dotenv/README.md @@ -4,10 +4,32 @@ Dotenv Component Symfony Dotenv parses `.env` files to make environment variables stored in them accessible via `$_SERVER` or `$_ENV`. +Getting Started +--------------- + +``` +$ composer require symfony/dotenv +``` + +```php +use Symfony\Component\Dotenv\Dotenv; + +$dotenv = new Dotenv(); +$dotenv->load(__DIR__.'/.env'); + +// you can also load several files +$dotenv->load(__DIR__.'/.env', __DIR__.'/.env.dev'); + +// overwrites existing env variables +$dotenv->overload(__DIR__.'/.env'); + +// loads .env, .env.local, and .env.$APP_ENV.local or .env.$APP_ENV +$dotenv->loadEnv(__DIR__.'/.env'); +``` + Resources --------- - * [Documentation](https://symfony.com/doc/current/components/dotenv.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/ErrorHandler/README.md b/src/Symfony/Component/ErrorHandler/README.md index 17e1cfd751d06..d14ccfd7b9c58 100644 --- a/src/Symfony/Component/ErrorHandler/README.md +++ b/src/Symfony/Component/ErrorHandler/README.md @@ -3,6 +3,35 @@ ErrorHandler Component The ErrorHandler component provides tools to manage errors and ease debugging PHP code. +Getting Started +--------------- + +``` +$ composer require symfony/error-handler +``` + +```php +use Symfony\Component\ErrorHandler\Debug; +use Symfony\Component\ErrorHandler\ErrorHandler; +use Symfony\Component\ErrorHandler\DebugClassLoader; + +Debug::enable(); + +// or enable only one feature +//ErrorHandler::register(); +//DebugClassLoader::enable(); + +$data = ErrorHandler::call(static function () use ($filename, $datetimeFormat) { + // if any code executed inside this anonymous function fails, a PHP exception + // will be thrown, even if the code uses the '@' PHP silence operator + $data = json_decode(file_get_contents($filename), true); + $data['read_at'] = date($datetimeFormat); + file_put_contents($filename, json_encode($data)); + + return $data; +}); +``` + Resources --------- diff --git a/src/Symfony/Component/Templating/README.md b/src/Symfony/Component/Templating/README.md index 2b8ecad873964..a4798fdaafdef 100644 --- a/src/Symfony/Component/Templating/README.md +++ b/src/Symfony/Component/Templating/README.md @@ -9,10 +9,33 @@ for changes. It also provides a concrete template engine implementation using PHP with additional tools for escaping and separating templates into blocks and layouts. +Getting Started +--------------- + +``` +$ composer require symfony/templating +``` + +```php +use Symfony\Component\Templating\Loader\FilesystemLoader; +use Symfony\Component\Templating\PhpEngine; +use Symfony\Component\Templating\Helper\SlotsHelper; +use Symfony\Component\Templating\TemplateNameParser; + +$filesystemLoader = new FilesystemLoader(__DIR__.'/views/%name%'); + +$templating = new PhpEngine(new TemplateNameParser(), $filesystemLoader); +$templating->set(new SlotsHelper()); + +echo $templating->render('hello.php', ['firstname' => 'Fabien']); + +// hello.php +Hello, escape($firstname) ?>! +``` + Resources --------- - * [Documentation](https://symfony.com/doc/current/components/templating.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) diff --git a/src/Symfony/Component/WebLink/README.md b/src/Symfony/Component/WebLink/README.md index d246e50754318..7c6abd3969a5c 100644 --- a/src/Symfony/Component/WebLink/README.md +++ b/src/Symfony/Component/WebLink/README.md @@ -8,10 +8,30 @@ This component implements the [HTML5's Links](https://www.w3.org/TR/html5/links. and [Resource Hints](https://www.w3.org/TR/resource-hints/) W3C's specifications. It can also be used with extensions defined in the [HTML5 link type extensions wiki](http://microformats.org/wiki/existing-rel-values#HTML5_link_type_extensions). +Getting Started +--------------- + +``` +$ composer require symfony/web-link +``` + +```php +use Symfony\Component\WebLink\GenericLinkProvider; +use Symfony\Component\WebLink\HttpHeaderSerializer; +use Symfony\Component\WebLink\Link; + +$linkProvider = (new GenericLinkProvider()) + ->withLink(new Link('preload', '/bootstrap.min.css')); + +header('Link: '.(new HttpHeaderSerializer())->serialize($linkProvider->getLinks())); + +echo 'Hello'; +``` + Resources --------- - * [Documentation](https://symfony.com/doc/current/components/web_link.html) + * [Documentation](https://symfony.com/doc/current/web_link.html) * [Contributing](https://symfony.com/doc/current/contributing/index.html) * [Report issues](https://github.com/symfony/symfony/issues) and [send Pull Requests](https://github.com/symfony/symfony/pulls) From a91204a79d146d063898345d87813744592343fe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Loi=CC=88c=20Beurlet?= Date: Tue, 26 May 2020 14:58:50 +0200 Subject: [PATCH 04/31] [WebProfilerBundle] changed label of memory usage in time panel (Mb into MiB) --- .../Bundle/WebProfilerBundle/Resources/views/Collector/time.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.js b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.js index 6e693a9dc57c7..588a9d22ed350 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.js +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Collector/time.js @@ -94,7 +94,7 @@ class TimelineEngine { createLabel(name, duration, memory, period) { const label = this.renderer.createText(name, period.start * this.scale, this.labelY, 'timeline-label'); - const sublabel = this.renderer.createTspan(` ${duration} ms / ${memory} Mb`, 'timeline-sublabel'); + const sublabel = this.renderer.createTspan(` ${duration} ms / ${memory} MiB`, 'timeline-sublabel'); label.appendChild(sublabel); From 50348f2eb70501ec706b6effb9afe073a60c1e6d Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Tue, 26 May 2020 16:53:18 +0200 Subject: [PATCH 05/31] Fixed handling of CSRF logout error --- .../Security/Http/Firewall/ExceptionListener.php | 8 +++++--- .../Http/Tests/Firewall/ExceptionListenerTest.php | 12 ++++++++++++ 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php index 0232917687670..a1dfa27855fa2 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php @@ -102,7 +102,7 @@ public function onKernelException(GetResponseForExceptionEvent $event) } if ($exception instanceof LogoutException) { - $this->handleLogoutException($exception); + $this->handleLogoutException($event, $exception); return; } @@ -172,10 +172,12 @@ private function handleAccessDeniedException(GetResponseForExceptionEvent $event } } - private function handleLogoutException(LogoutException $exception) + private function handleLogoutException(GetResponseForExceptionEvent $event, LogoutException $exception) { + $event->setException(new AccessDeniedHttpException($exception->getMessage(), $exception)); + if (null !== $this->logger) { - $this->logger->info('A LogoutException was thrown.', ['exception' => $exception]); + $this->logger->info('A LogoutException was thrown; wrapping with AccessDeniedHttpException', ['exception' => $exception]); } } diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php index 29899de11f957..74d366311c5ff 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php @@ -21,6 +21,7 @@ use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface; use Symfony\Component\Security\Core\Exception\AccessDeniedException; use Symfony\Component\Security\Core\Exception\AuthenticationException; +use Symfony\Component\Security\Core\Exception\LogoutException; use Symfony\Component\Security\Http\Authorization\AccessDeniedHandlerInterface; use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface; use Symfony\Component\Security\Http\Firewall\ExceptionListener; @@ -160,6 +161,17 @@ public function testAccessDeniedExceptionNotFullFledged(\Exception $exception, \ $this->assertSame(null === $eventException ? $exception : $eventException, $event->getException()->getPrevious()); } + public function testLogoutException() + { + $event = $this->createEvent(new LogoutException('Invalid CSRF.')); + + $listener = $this->createExceptionListener(); + $listener->onKernelException($event); + + $this->assertEquals('Invalid CSRF.', $event->getException()->getMessage()); + $this->assertEquals(403, $event->getException()->getStatusCode()); + } + public function getAccessDeniedExceptionProvider() { return [ From 5db0a8bf4b87c26b511fff1950266ca0f513d305 Mon Sep 17 00:00:00 2001 From: Dmitriy Derepko Date: Wed, 27 May 2020 10:34:32 +0200 Subject: [PATCH 06/31] [Contracts/Deprecation] fix composer.json for PHP 8 --- src/Symfony/Contracts/Deprecation/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Contracts/Deprecation/composer.json b/src/Symfony/Contracts/Deprecation/composer.json index de77c26ae8b0a..c8ace825c325b 100644 --- a/src/Symfony/Contracts/Deprecation/composer.json +++ b/src/Symfony/Contracts/Deprecation/composer.json @@ -15,7 +15,7 @@ } ], "require": { - "php": "^7.1" + "php": ">=7.1" }, "autoload": { "files": [ From 3d18c1c18509f9ed21635f8daecaa9d09f6fb3bf Mon Sep 17 00:00:00 2001 From: Martin Hujer Date: Wed, 27 May 2020 11:59:50 +0200 Subject: [PATCH 07/31] [Validator] add missing Czech translations --- .../Resources/translations/validators.cs.xlf | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf index e637d09aa9faa..ce32f1368de64 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.cs.xlf @@ -334,6 +334,54 @@ This value should be valid JSON. Tato hodnota musí být validní JSON. + + This collection should contain only unique elements. + Tato kolekce musí obsahovat pouze unikátní prvky. + + + This value should be positive. + Tato hodnota musí být kladná. + + + This value should be either positive or zero. + Tato hodnota musí být buď kladná nebo nula. + + + This value should be negative. + Tato hodnota musí být záporná. + + + This value should be either negative or zero. + Tato hodnota musí být buď záporná nebo nula. + + + This value is not a valid timezone. + Tato časová zóna neexistuje. + + + This password has been leaked in a data breach, it must not be used. Please use another password. + Zadané heslo bylo součástí úniku dat, takže ho není možné použít. Použijte prosím jiné heslo. + + + This value should be between {{ min }} and {{ max }}. + Hodnota musí být mezi {{ min }} a {{ max }}. + + + This value is not a valid hostname. + Tato hodnota není platný hostname. + + + The number of elements in this collection should be a multiple of {{ compared_value }}. + Počet prvků v této kolekci musí být násobek {{ compared_value }}. + + + This value should satisfy at least one of the following constraints: + Tato hodnota musí splňovat alespoň jedno z následujících omezení: + + + Each element of this collection should satisfy its own set of constraints. + Každý prvek v této kolekci musí splňovat svá vlastní omezení. + From e3d9b259e004ffeaebbde89704dc4a9dc08a6962 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Wed, 27 May 2020 21:00:01 +0200 Subject: [PATCH 08/31] Fixed security-* package dependencies --- src/Symfony/Bundle/SecurityBundle/composer.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index 3be54e720ac1a..c1603160dd0cd 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -23,9 +23,9 @@ "symfony/event-dispatcher": "^5.1", "symfony/http-kernel": "^5.0", "symfony/polyfill-php80": "^1.15", - "symfony/security-core": "^4.4|^5.0", + "symfony/security-core": "^5.1", "symfony/security-csrf": "^4.4|^5.0", - "symfony/security-guard": "^4.4|^5.0", + "symfony/security-guard": "^5.1", "symfony/security-http": "^5.1" }, "require-dev": { From ed518551e119b594be2b57b2fff414cff61d1eec Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Wed, 27 May 2020 23:40:15 +0200 Subject: [PATCH 09/31] Handle fetch mode deprecation of DBAL 2.11. --- .../RememberMe/DoctrineTokenProvider.php | 2 +- .../RememberMe/DoctrineTokenProviderTest.php | 88 +++++++++++++++++++ .../Cache/Tests/Traits/PdoPruneableTrait.php | 4 +- .../Component/Cache/Traits/PdoTrait.php | 8 +- 4 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 src/Symfony/Bridge/Doctrine/Tests/Security/RememberMe/DoctrineTokenProviderTest.php diff --git a/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php b/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php index ef0612df3128f..4bbc9f3fcdfb4 100644 --- a/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php +++ b/src/Symfony/Bridge/Doctrine/Security/RememberMe/DoctrineTokenProvider.php @@ -63,7 +63,7 @@ public function loadTokenBySeries($series) $paramValues = ['series' => $series]; $paramTypes = ['series' => \PDO::PARAM_STR]; $stmt = $this->conn->executeQuery($sql, $paramValues, $paramTypes); - $row = $stmt->fetch(\PDO::FETCH_ASSOC); + $row = method_exists($stmt, 'fetchAssociative') ? $stmt->fetchAssociative() : $stmt->fetch(\PDO::FETCH_ASSOC); if ($row) { return new PersistentToken($row['class'], $row['username'], $series, $row['value'], new \DateTime($row['last_used'])); diff --git a/src/Symfony/Bridge/Doctrine/Tests/Security/RememberMe/DoctrineTokenProviderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Security/RememberMe/DoctrineTokenProviderTest.php new file mode 100644 index 0000000000000..9c86ecacb29cc --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Security/RememberMe/DoctrineTokenProviderTest.php @@ -0,0 +1,88 @@ += 80000) { + self::markTestSkipped('Doctrine DBAL 2.x is incompatible with PHP 8.'); + } + } + + public function testCreateNewToken() + { + $provider = $this->bootstrapProvider(); + + $token = new PersistentToken('someClass', 'someUser', 'someSeries', 'tokenValue', new \DateTime('2013-01-26T18:23:51')); + $provider->createNewToken($token); + + $this->assertEquals($provider->loadTokenBySeries('someSeries'), $token); + } + + public function testLoadTokenBySeriesThrowsNotFoundException() + { + $provider = $this->bootstrapProvider(); + + $this->expectException(TokenNotFoundException::class); + $provider->loadTokenBySeries('someSeries'); + } + + public function testUpdateToken() + { + $provider = $this->bootstrapProvider(); + + $token = new PersistentToken('someClass', 'someUser', 'someSeries', 'tokenValue', new \DateTime('2013-01-26T18:23:51')); + $provider->createNewToken($token); + $provider->updateToken('someSeries', 'newValue', $lastUsed = new \DateTime('2014-06-26T22:03:46')); + $token = $provider->loadTokenBySeries('someSeries'); + + $this->assertEquals('newValue', $token->getTokenValue()); + $this->assertEquals($token->getLastUsed(), $lastUsed); + } + + public function testDeleteToken() + { + $provider = $this->bootstrapProvider(); + $token = new PersistentToken('someClass', 'someUser', 'someSeries', 'tokenValue', new \DateTime('2013-01-26T18:23:51')); + $provider->createNewToken($token); + $provider->deleteTokenBySeries('someSeries'); + + $this->expectException(TokenNotFoundException::class); + + $provider->loadTokenBySeries('someSeries'); + } + + /** + * @return DoctrineTokenProvider + */ + private function bootstrapProvider() + { + $connection = DriverManager::getConnection([ + 'driver' => 'pdo_sqlite', + 'url' => 'sqlite:///:memory:', + ]); + $connection->executeUpdate(<<< 'SQL' + CREATE TABLE rememberme_token ( + series char(88) UNIQUE PRIMARY KEY NOT NULL, + value char(88) NOT NULL, + lastUsed datetime NOT NULL, + class varchar(100) NOT NULL, + username varchar(200) NOT NULL + ); +SQL + ); + + return new DoctrineTokenProvider($connection); + } +} diff --git a/src/Symfony/Component/Cache/Tests/Traits/PdoPruneableTrait.php b/src/Symfony/Component/Cache/Tests/Traits/PdoPruneableTrait.php index 3b1e1128ba0d7..c5ba9c66d6942 100644 --- a/src/Symfony/Component/Cache/Tests/Traits/PdoPruneableTrait.php +++ b/src/Symfony/Component/Cache/Tests/Traits/PdoPruneableTrait.php @@ -24,11 +24,11 @@ protected function isPruned($cache, $name) $getPdoConn = $o->getMethod('getConnection'); $getPdoConn->setAccessible(true); - /** @var \Doctrine\DBAL\Statement $select */ + /** @var \Doctrine\DBAL\Statement|\PDOStatement $select */ $select = $getPdoConn->invoke($cache)->prepare('SELECT 1 FROM cache_items WHERE item_id LIKE :id'); $select->bindValue(':id', sprintf('%%%s', $name)); $select->execute(); - return 0 === \count($select->fetchAll(\PDO::FETCH_COLUMN)); + return 1 !== (int) (method_exists($select, 'fetchOne') ? $select->fetchOne() : $select->fetch(\PDO::FETCH_COLUMN)); } } diff --git a/src/Symfony/Component/Cache/Traits/PdoTrait.php b/src/Symfony/Component/Cache/Traits/PdoTrait.php index ab9054b38d8c4..6a9f3c46aea45 100644 --- a/src/Symfony/Component/Cache/Traits/PdoTrait.php +++ b/src/Symfony/Component/Cache/Traits/PdoTrait.php @@ -177,7 +177,13 @@ protected function doFetch(array $ids) } $stmt->execute(); - while ($row = $stmt->fetch(\PDO::FETCH_NUM)) { + if (method_exists($stmt, 'iterateNumeric')) { + $stmt = $stmt->iterateNumeric(); + } else { + $stmt->setFetchMode(\PDO::FETCH_NUM); + } + + foreach ($stmt as $row) { if (null === $row[1]) { $expired[] = $row[0]; } else { From 1385213a9adf6bc6723b67c8bbe3a4e02e36de5a Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Thu, 28 May 2020 01:00:48 +0200 Subject: [PATCH 10/31] Handle fetch mode deprecation of DBAL 2.11. --- .../Component/Cache/Traits/PdoTrait.php | 2 +- src/Symfony/Component/Lock/Store/PdoStore.php | 2 +- .../Transport/Doctrine/ConnectionTest.php | 21 +++++++++++++------ .../Doctrine/DoctrineIntegrationTest.php | 7 +++---- .../Transport/Doctrine/Connection.php | 17 ++++++++------- 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/src/Symfony/Component/Cache/Traits/PdoTrait.php b/src/Symfony/Component/Cache/Traits/PdoTrait.php index 943d34e5ebd42..cb5bb0511f251 100644 --- a/src/Symfony/Component/Cache/Traits/PdoTrait.php +++ b/src/Symfony/Component/Cache/Traits/PdoTrait.php @@ -226,7 +226,7 @@ protected function doHave($id) $stmt->bindValue(':time', time(), \PDO::PARAM_INT); $stmt->execute(); - return (bool) $stmt->fetchColumn(); + return (bool) (method_exists($stmt, 'fetchOne') ? $stmt->fetchOne() : $stmt->fetchColumn()); } /** diff --git a/src/Symfony/Component/Lock/Store/PdoStore.php b/src/Symfony/Component/Lock/Store/PdoStore.php index 5e2f01caa408e..7af7f3870fad2 100644 --- a/src/Symfony/Component/Lock/Store/PdoStore.php +++ b/src/Symfony/Component/Lock/Store/PdoStore.php @@ -203,7 +203,7 @@ public function exists(Key $key) $stmt->bindValue(':token', $this->getUniqueToken($key)); $stmt->execute(); - return (bool) $stmt->fetchColumn(); + return (bool) (method_exists($stmt, 'fetchOne') ? $stmt->fetchOne() : $stmt->fetchColumn()); } /** diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php index bd7fff769bcc5..d34e45d2ce518 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/ConnectionTest.php @@ -12,7 +12,8 @@ namespace Symfony\Component\Messenger\Tests\Transport\Doctrine; use Doctrine\DBAL\DBALException; -use Doctrine\DBAL\Driver\Statement; +use Doctrine\DBAL\Driver\ResultStatement; +use Doctrine\DBAL\ForwardCompatibility\Driver\ResultStatement as ForwardCompatibleResultStatement; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Query\QueryBuilder; use Doctrine\DBAL\Schema\AbstractSchemaManager; @@ -142,11 +143,16 @@ private function getQueryBuilderMock() return $queryBuilder; } - private function getStatementMock($expectedResult): Statement + private function getStatementMock($expectedResult): ResultStatement { - $stmt = $this->createMock(Statement::class); + $mockedInterface = interface_exists(ForwardCompatibleResultStatement::class) + ? ForwardCompatibleResultStatement::class + : ResultStatement::class; + + $stmt = $this->createMock($mockedInterface); + $stmt->expects($this->once()) - ->method('fetch') + ->method(method_exists($mockedInterface, 'fetchAssociative') ? 'fetchAssociative' : 'fetch') ->willReturn($expectedResult); return $stmt; @@ -306,9 +312,12 @@ public function testFindAll() 'headers' => json_encode(['type' => DummyMessage::class]), ]; - $stmt = $this->createMock(Statement::class); + $mockedInterface = interface_exists(ForwardCompatibleResultStatement::class) + ? ForwardCompatibleResultStatement::class + : ResultStatement::class; + $stmt = $this->createMock($mockedInterface); $stmt->expects($this->once()) - ->method('fetchAll') + ->method(method_exists($mockedInterface, 'fetchAllAssociative') ? 'fetchAllAssociative' : 'fetchAll') ->willReturn([$message1, $message2]); $driverConnection diff --git a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php index f417283aa5bb8..45ca64b77106a 100644 --- a/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php +++ b/src/Symfony/Component/Messenger/Tests/Transport/Doctrine/DoctrineIntegrationTest.php @@ -64,15 +64,14 @@ public function testSendWithDelay() { $this->connection->send('{"message": "Hi i am delayed"}', ['type' => DummyMessage::class], 600000); - $available_at = $this->driverConnection->createQueryBuilder() + $stmt = $this->driverConnection->createQueryBuilder() ->select('m.available_at') ->from('messenger_messages', 'm') ->where('m.body = :body') ->setParameter(':body', '{"message": "Hi i am delayed"}') - ->execute() - ->fetchColumn(); + ->execute(); - $available_at = new \DateTime($available_at); + $available_at = new \DateTime(method_exists($stmt, 'fetchOne') ? $stmt->fetchOne() : $stmt->fetchColumn()); $now = new \DateTime(); $now->modify('+60 seconds'); diff --git a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php index 6004bf360e3b1..4f5b43c4ac8d9 100644 --- a/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php +++ b/src/Symfony/Component/Messenger/Transport/Doctrine/Connection.php @@ -159,11 +159,12 @@ public function get(): ?array ->setMaxResults(1); // use SELECT ... FOR UPDATE to lock table - $doctrineEnvelope = $this->executeQuery( + $stmt = $this->executeQuery( $query->getSQL().' '.$this->driverConnection->getDatabasePlatform()->getWriteLockSQL(), $query->getParameters(), $query->getParameterTypes() - )->fetch(); + ); + $doctrineEnvelope = method_exists($stmt, 'fetchAssociative') ? $stmt->fetchAssociative() : $stmt->fetch(); if (false === $doctrineEnvelope) { $this->driverConnection->commit(); @@ -249,7 +250,9 @@ public function getMessageCount(): int ->select('COUNT(m.id) as message_count') ->setMaxResults(1); - return $this->executeQuery($queryBuilder->getSQL(), $queryBuilder->getParameters(), $queryBuilder->getParameterTypes())->fetchColumn(); + $stmt = $this->executeQuery($queryBuilder->getSQL(), $queryBuilder->getParameters(), $queryBuilder->getParameterTypes()); + + return method_exists($stmt, 'fetchOne') ? $stmt->fetchOne() : $stmt->fetchColumn(); } public function findAll(int $limit = null): array @@ -259,7 +262,8 @@ public function findAll(int $limit = null): array $queryBuilder->setMaxResults($limit); } - $data = $this->executeQuery($queryBuilder->getSQL(), $queryBuilder->getParameters(), $queryBuilder->getParameterTypes())->fetchAll(); + $stmt = $this->executeQuery($queryBuilder->getSQL(), $queryBuilder->getParameters(), $queryBuilder->getParameterTypes()); + $data = method_exists($stmt, 'fetchAllAssociative') ? $stmt->fetchAllAssociative() : $stmt->fetchAll(); return array_map(function ($doctrineEnvelope) { return $this->decodeEnvelopeHeaders($doctrineEnvelope); @@ -271,9 +275,8 @@ public function find($id): ?array $queryBuilder = $this->createQueryBuilder() ->where('m.id = ?'); - $data = $this->executeQuery($queryBuilder->getSQL(), [ - $id, - ])->fetch(); + $stmt = $this->executeQuery($queryBuilder->getSQL(), [$id]); + $data = method_exists($stmt, 'fetchAssociative') ? $stmt->fetchAssociative() : $stmt->fetch(); return false === $data ? null : $this->decodeEnvelopeHeaders($data); } From afdda5d764cf002cc8069149b5f4b2033d4324c1 Mon Sep 17 00:00:00 2001 From: Martin Hujer Date: Wed, 27 May 2020 12:01:07 +0200 Subject: [PATCH 11/31] [Form] add missing Czech validators translation --- .../Component/Form/Resources/translations/validators.cs.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.cs.xlf b/src/Symfony/Component/Form/Resources/translations/validators.cs.xlf index 776da49481816..44d597db980ec 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.cs.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.cs.xlf @@ -14,6 +14,10 @@ The CSRF token is invalid. Please try to resubmit the form. CSRF token je neplatný. Zkuste prosím znovu odeslat formulář. + + This value is not a valid HTML5 color. + Tato hodnota není platná HTML5 barva. + From aa50c9287c93b0972dafc533e350fff75c5820a3 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 28 May 2020 12:36:45 +0200 Subject: [PATCH 12/31] [ErrorHandler] fix setting $trace to null in FatalError --- src/Symfony/Component/ErrorHandler/Error/FatalError.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/ErrorHandler/Error/FatalError.php b/src/Symfony/Component/ErrorHandler/Error/FatalError.php index 68172d876cb51..98490b5accc41 100644 --- a/src/Symfony/Component/ErrorHandler/Error/FatalError.php +++ b/src/Symfony/Component/ErrorHandler/Error/FatalError.php @@ -72,9 +72,11 @@ public function __construct(string $message, int $code, array $error, int $trace 'line' => $error['line'], 'trace' => $trace, ] as $property => $value) { - $refl = new \ReflectionProperty(\Error::class, $property); - $refl->setAccessible(true); - $refl->setValue($this, $value); + if (null !== $value) { + $refl = new \ReflectionProperty(\Error::class, $property); + $refl->setAccessible(true); + $refl->setValue($this, $value); + } } } From 15d4f7ac041a59272af282a21228621a26311165 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 28 May 2020 14:17:38 +0200 Subject: [PATCH 13/31] [Security/Http] fix merge --- .../Component/Security/Http/Firewall/ExceptionListener.php | 2 +- .../Security/Http/Tests/Firewall/ExceptionListenerTest.php | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php index 09ef9564ed0c3..93fe14c4c556d 100644 --- a/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php +++ b/src/Symfony/Component/Security/Http/Firewall/ExceptionListener.php @@ -183,7 +183,7 @@ private function handleAccessDeniedException(GetResponseForExceptionEvent $event private function handleLogoutException(GetResponseForExceptionEvent $event, LogoutException $exception): void { - $event->setException(new AccessDeniedHttpException($exception->getMessage(), $exception)); + $event->setThrowable(new AccessDeniedHttpException($exception->getMessage(), $exception)); if (null !== $this->logger) { $this->logger->info('A LogoutException was thrown; wrapping with AccessDeniedHttpException', ['exception' => $exception]); diff --git a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php index 53204129fedd4..7328394b486d2 100644 --- a/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php +++ b/src/Symfony/Component/Security/Http/Tests/Firewall/ExceptionListenerTest.php @@ -165,8 +165,8 @@ public function testLogoutException() $listener = $this->createExceptionListener(); $listener->onKernelException($event); - $this->assertEquals('Invalid CSRF.', $event->getException()->getMessage()); - $this->assertEquals(403, $event->getException()->getStatusCode()); + $this->assertEquals('Invalid CSRF.', $event->getThrowable()->getMessage()); + $this->assertEquals(403, $event->getThrowable()->getStatusCode()); } public function getAccessDeniedExceptionProvider() From 6f59d605083b619ee41b07add28c5cfd42357ad2 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 28 May 2020 15:20:36 +0200 Subject: [PATCH 14/31] [TwigBridge] fix fallback html-to-txt body converter --- src/Symfony/Bridge/Twig/Mime/BodyRenderer.php | 2 +- src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php b/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php index e1031b3d569c2..e082d8313b5ec 100644 --- a/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php +++ b/src/Symfony/Bridge/Twig/Mime/BodyRenderer.php @@ -74,6 +74,6 @@ private function convertHtmlToText(string $html): string return $this->converter->convert($html); } - return strip_tags($html); + return strip_tags(preg_replace('{<(head|style)\b.*?}i', '', $html)); } } diff --git a/src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php b/src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php index 6eeade3a737af..175a8e1978066 100644 --- a/src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php +++ b/src/Symfony/Bridge/Twig/Tests/Mime/BodyRendererTest.php @@ -29,11 +29,12 @@ public function testRenderTextOnly(): void public function testRenderHtmlOnly(): void { - $email = $this->prepareEmail(null, 'HTML'); + $html = 'headHTML'; + $email = $this->prepareEmail(null, $html); $body = $email->getBody(); $this->assertInstanceOf(AlternativePart::class, $body); $this->assertEquals('HTML', $body->getParts()[0]->bodyToString()); - $this->assertEquals('HTML', $body->getParts()[1]->bodyToString()); + $this->assertEquals(str_replace('=', '=3D', $html), $body->getParts()[1]->bodyToString()); } public function testRenderHtmlOnlyWithTextSet(): void From 03b4e986301cbe0c23fd6a56f4ee18afef31139f Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Fri, 29 May 2020 02:02:01 +0200 Subject: [PATCH 15/31] [PropertyAccess] Fix TypeError parsing again. --- .../PropertyAccess/PropertyAccessor.php | 10 +++- .../Tests/PropertyAccessorTest.php | 53 +++++++++++++++++++ 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 3bb5d6dcf799e..99aa9a3ebc32a 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -479,9 +479,15 @@ private function readProperty($zval, $property) try { $result[self::VALUE] = $object->{$access[self::ACCESS_NAME]}(); } catch (\TypeError $e) { + list($trace) = $e->getTrace(); + // handle uninitialized properties in PHP >= 7 - if (preg_match((sprintf('/^Return value of %s::%s\(\) must be of (?:the )?type (\w+), null returned$/', preg_quote(\get_class($object)), $access[self::ACCESS_NAME])), $e->getMessage(), $matches)) { - throw new AccessException(sprintf('The method "%s::%s()" returned "null", but expected type "%3$s". Did you forget to initialize a property or to make the return type nullable using "?%3$s"?', \get_class($object), $access[self::ACCESS_NAME], $matches[1]), 0, $e); + if (__FILE__ === $trace['file'] + && $access[self::ACCESS_NAME] === $trace['function'] + && $object instanceof $trace['class'] + && preg_match((sprintf('/Return value (?:of .*::\w+\(\) )?must be of (?:the )?type (\w+), null returned$/')), $e->getMessage(), $matches) + ) { + throw new AccessException(sprintf('The method "%s::%s()" returned "null", but expected type "%3$s". Did you forget to initialize a property or to make the return type nullable using "?%3$s"?', false === strpos(\get_class($object), "@anonymous\0") ? \get_class($object) : (get_parent_class($object) ?: 'class').'@anonymous', $access[self::ACCESS_NAME], $matches[1]), 0, $e); } throw $e; diff --git a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php index d8331e76ad811..e1d87a428c26b 100644 --- a/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php +++ b/src/Symfony/Component/PropertyAccess/Tests/PropertyAccessorTest.php @@ -142,6 +142,59 @@ public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetter() $this->propertyAccessor->getValue(new UninitializedPrivateProperty(), 'uninitialized'); } + /** + * @requires PHP 7 + */ + public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetterOfAnonymousClass() + { + $this->expectException('Symfony\Component\PropertyAccess\Exception\AccessException'); + $this->expectExceptionMessage('The method "class@anonymous::getUninitialized()" returned "null", but expected type "array". Did you forget to initialize a property or to make the return type nullable using "?array"?'); + + $object = eval('return new class() { + private $uninitialized; + + public function getUninitialized(): array + { + return $this->uninitialized; + } + };'); + + $this->propertyAccessor->getValue($object, 'uninitialized'); + } + + /** + * @requires PHP 7 + */ + public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetterOfAnonymousStdClass() + { + $this->expectException('Symfony\Component\PropertyAccess\Exception\AccessException'); + $this->expectExceptionMessage('The method "stdClass@anonymous::getUninitialized()" returned "null", but expected type "array". Did you forget to initialize a property or to make the return type nullable using "?array"?'); + + $object = eval('return new class() extends \stdClass { + private $uninitialized; + + public function getUninitialized(): array + { + return $this->uninitialized; + } + };'); + + $this->propertyAccessor->getValue($object, 'uninitialized'); + } + + /** + * @requires PHP 7 + */ + public function testGetValueThrowsExceptionIfUninitializedPropertyWithGetterOfAnonymousChildClass() + { + $this->expectException('Symfony\Component\PropertyAccess\Exception\AccessException'); + $this->expectExceptionMessage('The method "Symfony\Component\PropertyAccess\Tests\Fixtures\UninitializedPrivateProperty@anonymous::getUninitialized()" returned "null", but expected type "array". Did you forget to initialize a property or to make the return type nullable using "?array"?'); + + $object = eval('return new class() extends \Symfony\Component\PropertyAccess\Tests\Fixtures\UninitializedPrivateProperty {};'); + + $this->propertyAccessor->getValue($object, 'uninitialized'); + } + public function testGetValueThrowsExceptionIfNotArrayAccess() { $this->expectException('Symfony\Component\PropertyAccess\Exception\NoSuchIndexException'); From d9decf9da29dd8214d0fd81f067eba14d767f0c2 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Thu, 28 May 2020 09:31:39 +0200 Subject: [PATCH 16/31] [Messenger] Change the default notify timeout value for PostgreSQL --- .../Bridge/Doctrine/Transport/PostgreSqlConnection.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/PostgreSqlConnection.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/PostgreSqlConnection.php index dfffdac4b7162..225f0b880111f 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/PostgreSqlConnection.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/PostgreSqlConnection.php @@ -24,11 +24,11 @@ final class PostgreSqlConnection extends Connection { /** * * use_notify: Set to false to disable the use of LISTEN/NOTIFY. Default: true - * * check_delayed_interval: The interval to check for delayed messages, in milliseconds. Set to 0 to disable checks. Default: 1000 + * * check_delayed_interval: The interval to check for delayed messages, in milliseconds. Set to 0 to disable checks. Default: 60000 (1 minute) * * get_notify_timeout: The length of time to wait for a response when calling PDO::pgsqlGetNotify, in milliseconds. Default: 0. */ protected const DEFAULT_OPTIONS = parent::DEFAULT_OPTIONS + [ - 'check_delayed_interval' => 1000, + 'check_delayed_interval' => 60000, 'get_notify_timeout' => 0, ]; @@ -75,6 +75,8 @@ public function get(): ?array // delayed messages (microtime(true) * 1000 - $this->queueEmptiedAt < $this->configuration['check_delayed_interval']) ) { + usleep(1000); + return null; } From 3ab76e40ff0962c14a86c34a479d169b8e5a1da3 Mon Sep 17 00:00:00 2001 From: Laurent VOULLEMIER Date: Thu, 28 May 2020 22:44:39 +0200 Subject: [PATCH 17/31] Add meaningful message when Process is not installed (ProcessHelper) --- src/Symfony/Component/Console/Helper/ProcessHelper.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Console/Helper/ProcessHelper.php b/src/Symfony/Component/Console/Helper/ProcessHelper.php index 666f114a23c4a..951bb854ec93f 100644 --- a/src/Symfony/Component/Console/Helper/ProcessHelper.php +++ b/src/Symfony/Component/Console/Helper/ProcessHelper.php @@ -37,6 +37,10 @@ class ProcessHelper extends Helper */ public function run(OutputInterface $output, $cmd, $error = null, callable $callback = null, $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE) { + if (!class_exists(Process::class)) { + throw new \LogicException('The Process helper requires the "Process" component. Install "symfony/process" to use it.'); + } + if ($output instanceof ConsoleOutputInterface) { $output = $output->getErrorOutput(); } From 1614595424692f0d536892c351a82ac1c4b800eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?G=C3=A1bor=20Egyed?= Date: Fri, 29 May 2020 09:40:36 +0200 Subject: [PATCH 18/31] Update Hungarian translations --- .../Component/Form/Resources/translations/validators.hu.xlf | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Symfony/Component/Form/Resources/translations/validators.hu.xlf b/src/Symfony/Component/Form/Resources/translations/validators.hu.xlf index 374cfaaea34ac..b53f16d6ae913 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.hu.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.hu.xlf @@ -14,6 +14,10 @@ The CSRF token is invalid. Please try to resubmit the form. Érvénytelen CSRF token. Kérem, próbálja újra elküldeni az űrlapot. + + This value is not a valid HTML5 color. + Ez az érték nem egy érvényes HTML5 szín. + From b819d94d1413e426237f35e6b6eddbc380dbccf9 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 19 May 2020 08:35:15 +0200 Subject: [PATCH 19/31] validate subforms in all validation groups --- .../Validator/Constraints/FormValidator.php | 31 +++++++++++++----- .../Validator/ValidatorExtension.php | 4 +-- .../Form/Resources/config/validation.xml | 6 ++-- .../Constraints/FormValidatorTest.php | 6 ++-- .../Validator/ValidatorExtensionTest.php | 32 +++++++++++++++++-- 5 files changed, 61 insertions(+), 18 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php index 14158f4c1cf74..6a8923ecbf0a5 100644 --- a/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php +++ b/src/Symfony/Component/Form/Extension/Validator/Constraints/FormValidator.php @@ -63,12 +63,16 @@ public function validate($form, Constraint $formConstraint) /** @var Constraint[] $constraints */ $constraints = $config->getOption('constraints', []); + $hasChildren = $form->count() > 0; + + if ($hasChildren && $form->isRoot()) { + $this->resolvedGroups = new \SplObjectStorage(); + } + if ($groups instanceof GroupSequence) { // Validate the data, the form AND nested fields in sequence $violationsCount = $this->context->getViolations()->count(); $fieldPropertyPath = \is_object($data) ? 'children[%s]' : 'children%s'; - $hasChildren = $form->count() > 0; - $this->resolvedGroups = $hasChildren ? new \SplObjectStorage() : null; foreach ($groups->groups as $group) { if ($validateDataGraph) { @@ -86,7 +90,8 @@ public function validate($form, Constraint $formConstraint) // sequence recursively, thus some fields could fail // in different steps without breaking early enough $this->resolvedGroups[$field] = (array) $group; - $validator->atPath(sprintf($fieldPropertyPath, $field->getPropertyPath()))->validate($field, $formConstraint); + $fieldFormConstraint = new Form(); + $validator->atPath(sprintf($fieldPropertyPath, $field->getPropertyPath()))->validate($field, $fieldFormConstraint); } } @@ -94,12 +99,9 @@ public function validate($form, Constraint $formConstraint) break; } } - - if ($hasChildren) { - // destroy storage at the end of the sequence to avoid memory leaks - $this->resolvedGroups = null; - } } else { + $fieldPropertyPath = \is_object($data) ? 'children[%s]' : 'children%s'; + if ($validateDataGraph) { $validator->atPath('data')->validate($data, null, $groups); } @@ -125,6 +127,19 @@ public function validate($form, Constraint $formConstraint) } } } + + foreach ($form->all() as $field) { + if ($field->isSubmitted()) { + $this->resolvedGroups[$field] = $groups; + $fieldFormConstraint = new Form(); + $validator->atPath(sprintf($fieldPropertyPath, $field->getPropertyPath()))->validate($field, $fieldFormConstraint); + } + } + } + + if ($hasChildren && $form->isRoot()) { + // destroy storage to avoid memory leaks + $this->resolvedGroups = new \SplObjectStorage(); } } elseif (!$form->isSynchronized()) { $childrenSynchronized = true; diff --git a/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php b/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php index a5e38859c0888..ac2d61238feb9 100644 --- a/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php +++ b/src/Symfony/Component/Form/Extension/Validator/ValidatorExtension.php @@ -13,7 +13,7 @@ use Symfony\Component\Form\AbstractExtension; use Symfony\Component\Form\Extension\Validator\Constraints\Form; -use Symfony\Component\Validator\Constraints\Valid; +use Symfony\Component\Validator\Constraints\Traverse; use Symfony\Component\Validator\Mapping\ClassMetadata; use Symfony\Component\Validator\Validator\ValidatorInterface; @@ -37,7 +37,7 @@ public function __construct(ValidatorInterface $validator) /* @var $metadata ClassMetadata */ $metadata->addConstraint(new Form()); - $metadata->addPropertyConstraint('children', new Valid()); + $metadata->addConstraint(new Traverse(false)); $this->validator = $validator; } diff --git a/src/Symfony/Component/Form/Resources/config/validation.xml b/src/Symfony/Component/Form/Resources/config/validation.xml index b2b935442d467..918f101f4266a 100644 --- a/src/Symfony/Component/Form/Resources/config/validation.xml +++ b/src/Symfony/Component/Form/Resources/config/validation.xml @@ -6,8 +6,8 @@ - - - + + + diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php index 5181e4122516e..3d7111f85f3c1 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/Constraints/FormValidatorTest.php @@ -615,7 +615,8 @@ public function testViolationIfExtraData() $this->assertTrue($form->isSubmitted()); $this->assertTrue($form->isSynchronized()); - $this->expectNoValidate(); + + $this->expectValidateValueAt(0, 'children[child]', $form->get('child'), new Form()); $this->validator->validate($form, new Form()); @@ -638,7 +639,8 @@ public function testViolationFormatIfMultipleExtraFields() $this->assertTrue($form->isSubmitted()); $this->assertTrue($form->isSynchronized()); - $this->expectNoValidate(); + + $this->expectValidateValueAt(0, 'children[child]', $form->get('child'), new Form()); $this->validator->validate($form, new Form()); diff --git a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorExtensionTest.php b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorExtensionTest.php index cb9b93abdbf61..9793bd78e69e7 100644 --- a/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorExtensionTest.php +++ b/src/Symfony/Component/Form/Tests/Extension/Validator/ValidatorExtensionTest.php @@ -54,9 +54,8 @@ public function test2Dot5ValidationApi() $this->assertInstanceOf(FormConstraint::class, $metadata->getConstraints()[0]); $this->assertSame(CascadingStrategy::NONE, $metadata->cascadingStrategy); - $this->assertSame(TraversalStrategy::IMPLICIT, $metadata->traversalStrategy); - $this->assertSame(CascadingStrategy::CASCADE, $metadata->getPropertyMetadata('children')[0]->cascadingStrategy); - $this->assertSame(TraversalStrategy::IMPLICIT, $metadata->getPropertyMetadata('children')[0]->traversalStrategy); + $this->assertSame(TraversalStrategy::NONE, $metadata->traversalStrategy); + $this->assertCount(0, $metadata->getPropertyMetadata('children')); } public function testDataConstraintsInvalidateFormEvenIfFieldIsNotSubmitted() @@ -138,6 +137,33 @@ public function testFieldsValidateInSequenceWithNestedGroupsArray() $this->assertInstanceOf(Length::class, $errors[1]->getCause()->getConstraint()); } + public function testConstraintsInDifferentGroupsOnSingleField() + { + $form = $this->createForm(FormType::class, null, [ + 'validation_groups' => new GroupSequence(['group1', 'group2']), + ]) + ->add('foo', TextType::class, [ + 'constraints' => [ + new NotBlank([ + 'groups' => ['group1'], + ]), + new Length([ + 'groups' => ['group2'], + 'max' => 3, + ]), + ], + ]); + $form->submit([ + 'foo' => 'test@example.com', + ]); + + $errors = $form->getErrors(true); + + $this->assertFalse($form->isValid()); + $this->assertCount(1, $errors); + $this->assertInstanceOf(Length::class, $errors[0]->getCause()->getConstraint()); + } + private function createForm($type, $data = null, array $options = []) { $validator = Validation::createValidatorBuilder() From 472883313f32f09a52973479edbbde5532d65141 Mon Sep 17 00:00:00 2001 From: Pierre du Plessis Date: Tue, 19 May 2020 10:49:18 +0200 Subject: [PATCH 20/31] [Validator] Use Mime component to determine mime type for file validator --- .../Validator/Constraints/FileValidator.php | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Validator/Constraints/FileValidator.php b/src/Symfony/Component/Validator/Constraints/FileValidator.php index 52e937944188b..31218c2020fa8 100644 --- a/src/Symfony/Component/Validator/Constraints/FileValidator.php +++ b/src/Symfony/Component/Validator/Constraints/FileValidator.php @@ -13,8 +13,10 @@ use Symfony\Component\HttpFoundation\File\File as FileObject; use Symfony\Component\HttpFoundation\File\UploadedFile; +use Symfony\Component\Mime\MimeTypes; use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; +use Symfony\Component\Validator\Exception\LogicException; use Symfony\Component\Validator\Exception\UnexpectedTypeException; use Symfony\Component\Validator\Exception\UnexpectedValueException; @@ -170,12 +172,17 @@ public function validate($value, Constraint $constraint) } if ($constraint->mimeTypes) { - if (!$value instanceof FileObject) { - $value = new FileObject($value); + if ($value instanceof FileObject) { + $mime = $value->getMimeType(); + } elseif (class_exists(MimeTypes::class)) { + $mime = MimeTypes::getDefault()->guessMimeType($path); + } elseif (!class_exists(FileObject::class)) { + throw new LogicException('You cannot validate the mime-type of files as the Mime component is not installed. Try running "composer require symfony/mime".'); + } else { + $mime = (new FileObject($value))->getMimeType(); } $mimeTypes = (array) $constraint->mimeTypes; - $mime = $value->getMimeType(); foreach ($mimeTypes as $mimeType) { if ($mimeType === $mime) { From 5d93b61278bff6a3919081fbcc7d10c1928896f2 Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Fri, 29 May 2020 16:03:43 +0200 Subject: [PATCH 21/31] [Console] Fix QuestionHelper::disableStty() --- .../Console/Helper/QuestionHelper.php | 6 ++-- .../Tests/Helper/QuestionHelperTest.php | 30 +++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/QuestionHelper.php b/src/Symfony/Component/Console/Helper/QuestionHelper.php index 93e221d36a563..80f6048b80740 100644 --- a/src/Symfony/Component/Console/Helper/QuestionHelper.php +++ b/src/Symfony/Component/Console/Helper/QuestionHelper.php @@ -32,7 +32,7 @@ class QuestionHelper extends Helper { private $inputStream; private static $shell; - private static $stty; + private static $stty = true; /** * Asks a question to the user. @@ -158,7 +158,7 @@ private function doAsk(OutputInterface $output, Question $question) $inputStream = $this->inputStream ?: STDIN; $autocomplete = $question->getAutocompleterValues(); - if (null === $autocomplete || !Terminal::hasSttyAvailable()) { + if (null === $autocomplete || !self::$stty || !Terminal::hasSttyAvailable()) { $ret = false; if ($question->isHidden()) { try { @@ -424,7 +424,7 @@ private function getHiddenResponse(OutputInterface $output, $inputStream) return $value; } - if (Terminal::hasSttyAvailable()) { + if (self::$stty && Terminal::hasSttyAvailable()) { $sttyMode = shell_exec('stty -g'); shell_exec('stty -echo'); diff --git a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php index 4303c020a319c..93b762c26186d 100644 --- a/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php +++ b/src/Symfony/Component/Console/Tests/Helper/QuestionHelperTest.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Console\Tests\Helper; +use Symfony\Component\Console\Exception\InvalidArgumentException; use Symfony\Component\Console\Formatter\OutputFormatter; use Symfony\Component\Console\Helper\FormatterHelper; use Symfony\Component\Console\Helper\HelperSet; @@ -1013,6 +1014,35 @@ public function testTraversableAutocomplete() $this->assertEquals('FooBundle', $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question)); } + public function testDisableSttby() + { + if (!Terminal::hasSttyAvailable()) { + $this->markTestSkipped('`stty` is required to test autocomplete functionality'); + } + + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('invalid'); + + QuestionHelper::disableStty(); + $dialog = new QuestionHelper(); + $dialog->setHelperSet(new HelperSet([new FormatterHelper()])); + + $question = new ChoiceQuestion('Please select a bundle', [1 => 'AcmeDemoBundle', 4 => 'AsseticBundle']); + $question->setMaxAttempts(1); + + // + // Gives `AcmeDemoBundle` with stty + $inputStream = $this->getInputStream("\033[A\033[A\n\033[B\033[B\n"); + + try { + $dialog->ask($this->createStreamableInputInterfaceMock($inputStream), $this->createOutputInterface(), $question); + } finally { + $reflection = new \ReflectionProperty(QuestionHelper::class, 'stty'); + $reflection->setAccessible(true); + $reflection->setValue(null, true); + } + } + public function testTraversableMultiselectAutocomplete() { // From ff7d3f4f01541ec130d8b436cc67547b4e99e181 Mon Sep 17 00:00:00 2001 From: Pedro Casado Date: Fri, 22 May 2020 14:37:09 -0300 Subject: [PATCH 22/31] Fixes sprintf(): Too few arguments in form transformer --- .../Bundle/WebServerBundle/Command/ServerLogCommand.php | 2 +- .../Asset/VersionStrategy/JsonManifestVersionStrategy.php | 2 +- src/Symfony/Component/Filesystem/Filesystem.php | 8 ++++---- src/Symfony/Component/Form/Form.php | 8 ++++---- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Bundle/WebServerBundle/Command/ServerLogCommand.php b/src/Symfony/Bundle/WebServerBundle/Command/ServerLogCommand.php index 75d94321f4f0b..40be5a50a4272 100644 --- a/src/Symfony/Bundle/WebServerBundle/Command/ServerLogCommand.php +++ b/src/Symfony/Bundle/WebServerBundle/Command/ServerLogCommand.php @@ -99,7 +99,7 @@ protected function execute(InputInterface $input, OutputInterface $output) } if (!$socket = stream_socket_server($host, $errno, $errstr)) { - throw new RuntimeException(sprintf('Server start failed on "%s": '.$errstr.' '.$errno, $host)); + throw new RuntimeException(sprintf('Server start failed on "%s": ', $host).$errstr.' '.$errno); } foreach ($this->getLogs($socket) as $clientId => $message) { diff --git a/src/Symfony/Component/Asset/VersionStrategy/JsonManifestVersionStrategy.php b/src/Symfony/Component/Asset/VersionStrategy/JsonManifestVersionStrategy.php index d052317678c80..62f9ff7dbd1e8 100644 --- a/src/Symfony/Component/Asset/VersionStrategy/JsonManifestVersionStrategy.php +++ b/src/Symfony/Component/Asset/VersionStrategy/JsonManifestVersionStrategy.php @@ -59,7 +59,7 @@ private function getManifestPath($path) $this->manifestData = json_decode(file_get_contents($this->manifestPath), true); if (0 < json_last_error()) { - throw new \RuntimeException(sprintf('Error parsing JSON from asset manifest file "%s": '.json_last_error_msg(), $this->manifestPath)); + throw new \RuntimeException(sprintf('Error parsing JSON from asset manifest file "%s": ', $this->manifestPath).json_last_error_msg()); } } diff --git a/src/Symfony/Component/Filesystem/Filesystem.php b/src/Symfony/Component/Filesystem/Filesystem.php index e2812f8e2252b..0b5297ecf0666 100644 --- a/src/Symfony/Component/Filesystem/Filesystem.php +++ b/src/Symfony/Component/Filesystem/Filesystem.php @@ -101,7 +101,7 @@ public function mkdir($dirs, $mode = 0777) if (!is_dir($dir)) { // The directory was not created by a concurrent process. Let's throw an exception with a developer friendly error message if we have one if (self::$lastError) { - throw new IOException(sprintf('Failed to create "%s": '.self::$lastError, $dir), 0, null, $dir); + throw new IOException(sprintf('Failed to create "%s": ', $dir).self::$lastError, 0, null, $dir); } throw new IOException(sprintf('Failed to create "%s".', $dir), 0, null, $dir); } @@ -171,16 +171,16 @@ public function remove($files) if (is_link($file)) { // See https://bugs.php.net/52176 if (!(self::box('unlink', $file) || '\\' !== \DIRECTORY_SEPARATOR || self::box('rmdir', $file)) && file_exists($file)) { - throw new IOException(sprintf('Failed to remove symlink "%s": '.self::$lastError, $file)); + throw new IOException(sprintf('Failed to remove symlink "%s": ', $file).self::$lastError); } } elseif (is_dir($file)) { $this->remove(new \FilesystemIterator($file, \FilesystemIterator::CURRENT_AS_PATHNAME | \FilesystemIterator::SKIP_DOTS)); if (!self::box('rmdir', $file) && file_exists($file)) { - throw new IOException(sprintf('Failed to remove directory "%s": '.self::$lastError, $file)); + throw new IOException(sprintf('Failed to remove directory "%s": ', $file).self::$lastError); } } elseif (!self::box('unlink', $file) && file_exists($file)) { - throw new IOException(sprintf('Failed to remove file "%s": '.self::$lastError, $file)); + throw new IOException(sprintf('Failed to remove file "%s": ', $file).self::$lastError); } } } diff --git a/src/Symfony/Component/Form/Form.php b/src/Symfony/Component/Form/Form.php index 93b62a9acff35..70874a2f909aa 100644 --- a/src/Symfony/Component/Form/Form.php +++ b/src/Symfony/Component/Form/Form.php @@ -1031,7 +1031,7 @@ private function modelToNorm($value) $value = $transformer->transform($value); } } catch (TransformationFailedException $exception) { - throw new TransformationFailedException(sprintf('Unable to transform data for property path "%s": '.$exception->getMessage(), $this->getPropertyPath()), $exception->getCode(), $exception); + throw new TransformationFailedException(sprintf('Unable to transform data for property path "%s": ', $this->getPropertyPath()).$exception->getMessage(), $exception->getCode(), $exception); } return $value; @@ -1055,7 +1055,7 @@ private function normToModel($value) $value = $transformers[$i]->reverseTransform($value); } } catch (TransformationFailedException $exception) { - throw new TransformationFailedException(sprintf('Unable to reverse value for property path "%s": '.$exception->getMessage(), $this->getPropertyPath()), $exception->getCode(), $exception); + throw new TransformationFailedException(sprintf('Unable to reverse value for property path "%s": ', $this->getPropertyPath()).$exception->getMessage(), $exception->getCode(), $exception); } return $value; @@ -1086,7 +1086,7 @@ private function normToView($value) $value = $transformer->transform($value); } } catch (TransformationFailedException $exception) { - throw new TransformationFailedException(sprintf('Unable to transform value for property path "%s": '.$exception->getMessage(), $this->getPropertyPath()), $exception->getCode(), $exception); + throw new TransformationFailedException(sprintf('Unable to transform value for property path "%s": ', $this->getPropertyPath()).$exception->getMessage(), $exception->getCode(), $exception); } return $value; @@ -1112,7 +1112,7 @@ private function viewToNorm($value) $value = $transformers[$i]->reverseTransform($value); } } catch (TransformationFailedException $exception) { - throw new TransformationFailedException(sprintf('Unable to reverse value for property path "%s": '.$exception->getMessage(), $this->getPropertyPath()), $exception->getCode(), $exception); + throw new TransformationFailedException(sprintf('Unable to reverse value for property path "%s": ', $this->getPropertyPath()).$exception->getMessage(), $exception->getCode(), $exception); } return $value; From a337ba55474f45c93d77a640268abe79e1bf2d3a Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 30 May 2020 20:30:09 +0200 Subject: [PATCH 23/31] [HttpClient] fix issues in tests --- .travis.yml | 1 + .../DataCollector/HttpClientDataCollectorTest.php | 12 +++++++----- .../HttpClient/Tests/HttplugClientTest.php | 2 -- .../Component/HttpClient/Tests/Psr18ClientTest.php | 2 -- .../Contracts/HttpClient/Test/TestHttpServer.php | 13 +++++++------ 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5d6c2159a6fb5..fc26dc6491e43 100644 --- a/.travis.yml +++ b/.travis.yml @@ -151,6 +151,7 @@ before_install: INI=~/.phpenv/versions/$PHP/etc/conf.d/travis.ini echo date.timezone = Europe/Paris >> $INI echo memory_limit = -1 >> $INI + echo default_socket_timeout = 10 >> $INI echo session.gc_probability = 0 >> $INI echo opcache.enable_cli = 1 >> $INI echo apc.enable_cli = 1 >> $INI diff --git a/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php b/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php index d173c172501a5..b5787105467d2 100755 --- a/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php +++ b/src/Symfony/Component/HttpClient/Tests/DataCollector/HttpClientDataCollectorTest.php @@ -9,6 +9,8 @@ * file that was distributed with this source code. */ +namespace Symfony\Component\HttpClient\Tests\DataCollector; + use PHPUnit\Framework\TestCase; use Symfony\Component\HttpClient\DataCollector\HttpClientDataCollector; use Symfony\Component\HttpClient\NativeHttpClient; @@ -19,9 +21,13 @@ class HttpClientDataCollectorTest extends TestCase { - public function testItCollectsRequestCount() + public static function setUpBeforeClass(): void { TestHttpServer::start(); + } + + public function testItCollectsRequestCount() + { $httpClient1 = $this->httpClientThatHasTracedRequests([ [ 'method' => 'GET', @@ -50,7 +56,6 @@ public function testItCollectsRequestCount() public function testItCollectsErrorCount() { - TestHttpServer::start(); $httpClient1 = $this->httpClientThatHasTracedRequests([ [ 'method' => 'GET', @@ -80,7 +85,6 @@ public function testItCollectsErrorCount() public function testItCollectsErrorCountByClient() { - TestHttpServer::start(); $httpClient1 = $this->httpClientThatHasTracedRequests([ [ 'method' => 'GET', @@ -113,7 +117,6 @@ public function testItCollectsErrorCountByClient() public function testItCollectsTracesByClient() { - TestHttpServer::start(); $httpClient1 = $this->httpClientThatHasTracedRequests([ [ 'method' => 'GET', @@ -146,7 +149,6 @@ public function testItCollectsTracesByClient() public function testItIsEmptyAfterReset() { - TestHttpServer::start(); $httpClient1 = $this->httpClientThatHasTracedRequests([ [ 'method' => 'GET', diff --git a/src/Symfony/Component/HttpClient/Tests/HttplugClientTest.php b/src/Symfony/Component/HttpClient/Tests/HttplugClientTest.php index 66a8cef6e7c52..6a8cadbbc88a8 100644 --- a/src/Symfony/Component/HttpClient/Tests/HttplugClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/HttplugClientTest.php @@ -22,8 +22,6 @@ class HttplugClientTest extends TestCase { - private static $server; - public static function setUpBeforeClass(): void { TestHttpServer::start(); diff --git a/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php b/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php index 42e627b590e1a..1ef36fc5bd09e 100644 --- a/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php +++ b/src/Symfony/Component/HttpClient/Tests/Psr18ClientTest.php @@ -21,8 +21,6 @@ class Psr18ClientTest extends TestCase { - private static $server; - public static function setUpBeforeClass(): void { TestHttpServer::start(); diff --git a/src/Symfony/Contracts/HttpClient/Test/TestHttpServer.php b/src/Symfony/Contracts/HttpClient/Test/TestHttpServer.php index 0adb1a52a3036..cfc100d80ce6c 100644 --- a/src/Symfony/Contracts/HttpClient/Test/TestHttpServer.php +++ b/src/Symfony/Contracts/HttpClient/Test/TestHttpServer.php @@ -19,12 +19,12 @@ */ class TestHttpServer { - private static $started; + private static $process; public static function start() { - if (self::$started) { - return; + if (self::$process) { + self::$process->stop(); } $finder = new PhpExecutableFinder(); @@ -32,9 +32,10 @@ public static function start() $process->setWorkingDirectory(__DIR__.'/Fixtures/web'); $process->start(); - register_shutdown_function([$process, 'stop']); - sleep('\\' === \DIRECTORY_SEPARATOR ? 10 : 1); + do { + usleep(50000); + } while (!@fopen('http://127.0.0.1:8057/', 'r')); - self::$started = true; + self::$process = $process; } } From d8f282edca9f58bfab51d4300683e40c9423db84 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 30 May 2020 20:58:05 +0200 Subject: [PATCH 24/31] Various cleanups --- src/Symfony/Component/Console/Helper/ProcessHelper.php | 2 +- .../Component/DependencyInjection/EnvVarProcessor.php | 2 +- .../Form/Resources/translations/validators.hu.xlf | 2 +- .../Intl/Data/Bundle/Reader/JsonBundleReader.php | 2 +- .../Component/Ldap/Adapter/ExtLdap/EntryManager.php | 8 ++++---- .../Serializer/Normalizer/DateTimeNormalizer.php | 2 +- .../Component/Translation/Loader/XliffFileLoader.php | 2 +- 7 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/Symfony/Component/Console/Helper/ProcessHelper.php b/src/Symfony/Component/Console/Helper/ProcessHelper.php index 951bb854ec93f..6cafb1facef4b 100644 --- a/src/Symfony/Component/Console/Helper/ProcessHelper.php +++ b/src/Symfony/Component/Console/Helper/ProcessHelper.php @@ -38,7 +38,7 @@ class ProcessHelper extends Helper public function run(OutputInterface $output, $cmd, $error = null, callable $callback = null, $verbosity = OutputInterface::VERBOSITY_VERY_VERBOSE) { if (!class_exists(Process::class)) { - throw new \LogicException('The Process helper requires the "Process" component. Install "symfony/process" to use it.'); + throw new \LogicException('The ProcessHelper cannot be run as the Process component is not installed. Try running "compose require symfony/process".'); } if ($output instanceof ConsoleOutputInterface) { diff --git a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php index 3410103764e52..cc9fa3b39075a 100644 --- a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php +++ b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php @@ -125,7 +125,7 @@ public function getEnv($prefix, $name, \Closure $getEnv) $env = json_decode($env, true); if (JSON_ERROR_NONE !== json_last_error()) { - throw new RuntimeException(sprintf('Invalid JSON in env var "%s": '.json_last_error_msg(), $name)); + throw new RuntimeException(sprintf('Invalid JSON in env var "%s": ', $name)).json_last_error_msg(); } if (!\is_array($env)) { diff --git a/src/Symfony/Component/Form/Resources/translations/validators.hu.xlf b/src/Symfony/Component/Form/Resources/translations/validators.hu.xlf index b53f16d6ae913..bc7f6055e4845 100644 --- a/src/Symfony/Component/Form/Resources/translations/validators.hu.xlf +++ b/src/Symfony/Component/Form/Resources/translations/validators.hu.xlf @@ -17,7 +17,7 @@ This value is not a valid HTML5 color. Ez az érték nem egy érvényes HTML5 szín. - + diff --git a/src/Symfony/Component/Intl/Data/Bundle/Reader/JsonBundleReader.php b/src/Symfony/Component/Intl/Data/Bundle/Reader/JsonBundleReader.php index 555dd377c9341..1d0cfbad0d242 100644 --- a/src/Symfony/Component/Intl/Data/Bundle/Reader/JsonBundleReader.php +++ b/src/Symfony/Component/Intl/Data/Bundle/Reader/JsonBundleReader.php @@ -46,7 +46,7 @@ public function read($path, $locale) $data = json_decode(file_get_contents($fileName), true); if (null === $data) { - throw new RuntimeException(sprintf('The resource bundle "%s" contains invalid JSON: '.json_last_error_msg(), $fileName)); + throw new RuntimeException(sprintf('The resource bundle "%s" contains invalid JSON: ', $fileName).json_last_error_msg()); } return $data; diff --git a/src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php b/src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php index 789672e7b22ef..26f99fc9caff4 100644 --- a/src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php +++ b/src/Symfony/Component/Ldap/Adapter/ExtLdap/EntryManager.php @@ -38,7 +38,7 @@ public function add(Entry $entry) $con = $this->getConnectionResource(); if (!@ldap_add($con, $entry->getDn(), $entry->getAttributes())) { - throw new LdapException(sprintf('Could not add entry "%s": '.ldap_error($con), $entry->getDn())); + throw new LdapException(sprintf('Could not add entry "%s": ', $entry->getDn()).ldap_error($con)); } return $this; @@ -52,7 +52,7 @@ public function update(Entry $entry) $con = $this->getConnectionResource(); if (!@ldap_modify($con, $entry->getDn(), $entry->getAttributes())) { - throw new LdapException(sprintf('Could not update entry "%s": '.ldap_error($con), $entry->getDn())); + throw new LdapException(sprintf('Could not update entry "%s": ', $entry->getDn()).ldap_error($con)); } } @@ -64,7 +64,7 @@ public function remove(Entry $entry) $con = $this->getConnectionResource(); if (!@ldap_delete($con, $entry->getDn())) { - throw new LdapException(sprintf('Could not remove entry "%s": '.ldap_error($con), $entry->getDn())); + throw new LdapException(sprintf('Could not remove entry "%s": ', $entry->getDn()).ldap_error($con)); } } @@ -76,7 +76,7 @@ public function rename(Entry $entry, $newRdn, $removeOldRdn = true) $con = $this->getConnectionResource(); if (!@ldap_rename($con, $entry->getDn(), $newRdn, null, $removeOldRdn)) { - throw new LdapException(sprintf('Could not rename entry "%s" to "%s": '.ldap_error($con), $entry->getDn(), $newRdn)); + throw new LdapException(sprintf('Could not rename entry "%s" to "%s": ', $entry->getDn(), $newRdn).ldap_error($con)); } } diff --git a/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php index 3217bc38beaf8..fef57d120d63c 100644 --- a/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/DateTimeNormalizer.php @@ -101,7 +101,7 @@ public function denormalize($data, $type, $format = null, array $context = []) $dateTimeErrors = \DateTime::class === $type ? \DateTime::getLastErrors() : \DateTimeImmutable::getLastErrors(); - throw new NotNormalizableValueException(sprintf('Parsing datetime string "%s" using format "%s" resulted in %d errors:.'."\n".'%s', $data, $dateTimeFormat, $dateTimeErrors['error_count'], implode("\n", $this->formatDateTimeErrors($dateTimeErrors['errors'])))); + throw new NotNormalizableValueException(sprintf('Parsing datetime string "%s" using format "%s" resulted in %d errors: ', $data, $dateTimeFormat, $dateTimeErrors['error_count'])."\n".implode("\n", $this->formatDateTimeErrors($dateTimeErrors['errors']))); } try { diff --git a/src/Symfony/Component/Translation/Loader/XliffFileLoader.php b/src/Symfony/Component/Translation/Loader/XliffFileLoader.php index 0a6ff16b1756f..14a2668c27682 100644 --- a/src/Symfony/Component/Translation/Loader/XliffFileLoader.php +++ b/src/Symfony/Component/Translation/Loader/XliffFileLoader.php @@ -194,7 +194,7 @@ private function validateSchema($file, \DOMDocument $dom, $schema) if (!@$dom->schemaValidateSource($schema)) { libxml_disable_entity_loader($disableEntities); - throw new InvalidResourceException(sprintf('Invalid resource provided: "%s"; Errors: '.implode("\n", $this->getXmlErrors($internalErrors)), $file)); + throw new InvalidResourceException(sprintf('Invalid resource provided: "%s"; Errors: ', $file).implode("\n", $this->getXmlErrors($internalErrors))); } libxml_disable_entity_loader($disableEntities); From d6966c3147fd145248095034bfa8f395485e11b7 Mon Sep 17 00:00:00 2001 From: Laurent VOULLEMIER Date: Sat, 30 May 2020 21:50:06 +0200 Subject: [PATCH 25/31] Fix abstract method name in PHP doc block --- src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php index 2a715e35d7710..10bddfbc94ea8 100644 --- a/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php +++ b/src/Symfony/Component/Routing/Loader/AnnotationClassLoader.php @@ -22,7 +22,7 @@ /** * AnnotationClassLoader loads routing information from a PHP class and its methods. * - * You need to define an implementation for the getRouteDefaults() method. Most of the + * You need to define an implementation for the configureRoute() method. Most of the * time, this method should define some PHP callable to be called for the route * (a controller in MVC speak). * From fa31260e5eb647c2487def360dbd7dc969dd81f0 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 30 May 2020 23:06:01 +0200 Subject: [PATCH 26/31] [DI] fix typo --- src/Symfony/Component/DependencyInjection/EnvVarProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php index cc9fa3b39075a..6b7ccf2e188b2 100644 --- a/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php +++ b/src/Symfony/Component/DependencyInjection/EnvVarProcessor.php @@ -125,7 +125,7 @@ public function getEnv($prefix, $name, \Closure $getEnv) $env = json_decode($env, true); if (JSON_ERROR_NONE !== json_last_error()) { - throw new RuntimeException(sprintf('Invalid JSON in env var "%s": ', $name)).json_last_error_msg(); + throw new RuntimeException(sprintf('Invalid JSON in env var "%s": ', $name).json_last_error_msg()); } if (!\is_array($env)) { From 308f28678cd1d8fb89dcc97a85f6315e5018a75b Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Sat, 30 May 2020 23:17:32 +0200 Subject: [PATCH 27/31] [PropertyAccess] fix merge --- src/Symfony/Component/PropertyAccess/PropertyAccessor.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php index 7c1f36f7aa4ba..f5e64651bab7e 100644 --- a/src/Symfony/Component/PropertyAccess/PropertyAccessor.php +++ b/src/Symfony/Component/PropertyAccess/PropertyAccessor.php @@ -408,11 +408,11 @@ private function readProperty(array $zval, string $property, bool $ignoreInvalid // handle uninitialized properties in PHP >= 7 if (__FILE__ === $trace['file'] - && $access[self::ACCESS_NAME] === $trace['function'] + && $name === $trace['function'] && $object instanceof $trace['class'] && preg_match((sprintf('/Return value (?:of .*::\w+\(\) )?must be of (?:the )?type (\w+), null returned$/')), $e->getMessage(), $matches) ) { - throw new UninitializedPropertyException(sprintf('The method "%s::%s()" returned "null", but expected type "%3$s". Did you forget to initialize a property or to make the return type nullable using "?%3$s"?', false === strpos(\get_class($object), "@anonymous\0") ? \get_class($object) : (get_parent_class($object) ?: 'class').'@anonymous', $access[self::ACCESS_NAME], $matches[1]), 0, $e); + throw new UninitializedPropertyException(sprintf('The method "%s::%s()" returned "null", but expected type "%3$s". Did you forget to initialize a property or to make the return type nullable using "?%3$s"?', false === strpos(\get_class($object), "@anonymous\0") ? \get_class($object) : (get_parent_class($object) ?: key(class_implements($object)) ?: 'class').'@anonymous', $name, $matches[1]), 0, $e); } throw $e; From f297beb42cf34ca96a2c994db0ca18a15a25ed69 Mon Sep 17 00:00:00 2001 From: Wouter de Jong Date: Sat, 30 May 2020 11:27:30 +0200 Subject: [PATCH 28/31] [Security] Fixed AbstractToken::hasUserChanged() --- .../Authentication/Token/AbstractToken.php | 7 +- .../Token/AbstractTokenTest.php | 67 ++++++++++++++++++- 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php index de0ebac264884..e59997de34913 100644 --- a/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php +++ b/src/Symfony/Component/Security/Core/Authentication/Token/AbstractToken.php @@ -317,10 +317,13 @@ private function hasUserChanged(UserInterface $user): bool return true; } - $currentUserRoles = array_map('strval', (array) $this->user->getRoles()); $userRoles = array_map('strval', (array) $user->getRoles()); - if (\count($userRoles) !== \count($currentUserRoles) || \count($userRoles) !== \count(array_intersect($userRoles, $currentUserRoles))) { + if ($this instanceof SwitchUserToken) { + $userRoles[] = 'ROLE_PREVIOUS_ADMIN'; + } + + if (\count($userRoles) !== \count($this->getRoleNames()) || \count($userRoles) !== \count(array_intersect($userRoles, $this->getRoleNames()))) { return true; } diff --git a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php index 031fe4989884c..b61af1d6bab72 100644 --- a/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php +++ b/src/Symfony/Component/Security/Core/Tests/Authentication/Token/AbstractTokenTest.php @@ -238,13 +238,28 @@ public function getUserChangesAdvancedUser() */ public function testSetUserDoesNotSetAuthenticatedToFalseWhenUserDoesNotChange($user) { - $token = new ConcreteToken(['ROLE_FOO']); + $token = new ConcreteToken(); + $token->setAuthenticated(true); + $this->assertTrue($token->isAuthenticated()); + + $token->setUser($user); + $this->assertTrue($token->isAuthenticated()); + + $token->setUser($user); + $this->assertTrue($token->isAuthenticated()); + } + + public function testIsUserChangedWhenSerializing() + { + $token = new ConcreteToken(['ROLE_ADMIN']); $token->setAuthenticated(true); $this->assertTrue($token->isAuthenticated()); + $user = new SerializableUser('wouter', ['ROLE_ADMIN']); $token->setUser($user); $this->assertTrue($token->isAuthenticated()); + $token = unserialize(serialize($token)); $token->setUser($user); $this->assertTrue($token->isAuthenticated()); } @@ -265,6 +280,56 @@ public function __toString(): string } } +class SerializableUser implements UserInterface, \Serializable +{ + private $roles; + private $name; + + public function __construct($name, array $roles = []) + { + $this->name = $name; + $this->roles = $roles; + } + + public function getUsername() + { + return $this->name; + } + + public function getPassword() + { + return '***'; + } + + public function getRoles() + { + if (empty($this->roles)) { + return ['ROLE_USER']; + } + + return $this->roles; + } + + public function eraseCredentials() + { + } + + public function getSalt() + { + return null; + } + + public function serialize() + { + return serialize($this->name); + } + + public function unserialize($serialized) + { + $this->name = unserialize($serialized); + } +} + class ConcreteToken extends AbstractToken { private $credentials = 'credentials_value'; From 4807dab305ca85d2f0a0fa04c4a08e48ae2ab420 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Sat, 30 May 2020 10:18:13 +0200 Subject: [PATCH 29/31] [Validator] use "allowedVariables" to configure the ExpressionLanguageSyntax constraint --- .../Validator/Constraints/ExpressionLanguageSyntax.php | 3 +-- .../Constraints/ExpressionLanguageSyntaxValidator.php | 5 +++-- ...taxTest.php => ExpressionLanguageSyntaxValidatorTest.php} | 5 +++-- 3 files changed, 7 insertions(+), 6 deletions(-) rename src/Symfony/Component/Validator/Tests/Constraints/{ExpressionLanguageSyntaxTest.php => ExpressionLanguageSyntaxValidatorTest.php} (94%) diff --git a/src/Symfony/Component/Validator/Constraints/ExpressionLanguageSyntax.php b/src/Symfony/Component/Validator/Constraints/ExpressionLanguageSyntax.php index eab003854dc72..50790fba054a4 100644 --- a/src/Symfony/Component/Validator/Constraints/ExpressionLanguageSyntax.php +++ b/src/Symfony/Component/Validator/Constraints/ExpressionLanguageSyntax.php @@ -29,8 +29,7 @@ class ExpressionLanguageSyntax extends Constraint public $message = 'This value should be a valid expression.'; public $service; - public $validateNames = true; - public $names = []; + public $allowedVariables = null; /** * {@inheritdoc} diff --git a/src/Symfony/Component/Validator/Constraints/ExpressionLanguageSyntaxValidator.php b/src/Symfony/Component/Validator/Constraints/ExpressionLanguageSyntaxValidator.php index e7104452e7678..4b67da2c2be9c 100644 --- a/src/Symfony/Component/Validator/Constraints/ExpressionLanguageSyntaxValidator.php +++ b/src/Symfony/Component/Validator/Constraints/ExpressionLanguageSyntaxValidator.php @@ -16,6 +16,7 @@ use Symfony\Component\Validator\Constraint; use Symfony\Component\Validator\ConstraintValidator; use Symfony\Component\Validator\Exception\UnexpectedTypeException; +use Symfony\Component\Validator\Exception\UnexpectedValueException; /** * @author Andrey Sevastianov @@ -39,7 +40,7 @@ public function validate($expression, Constraint $constraint): void } if (!\is_string($expression)) { - throw new UnexpectedTypeException($expression, 'string'); + throw new UnexpectedValueException($expression, 'string'); } if (null === $this->expressionLanguage) { @@ -47,7 +48,7 @@ public function validate($expression, Constraint $constraint): void } try { - $this->expressionLanguage->lint($expression, ($constraint->validateNames ? ($constraint->names ?? []) : null)); + $this->expressionLanguage->lint($expression, $constraint->allowedVariables); } catch (SyntaxError $exception) { $this->context->buildViolation($constraint->message) ->setParameter('{{ syntax_error }}', $this->formatValue($exception->getMessage())) diff --git a/src/Symfony/Component/Validator/Tests/Constraints/ExpressionLanguageSyntaxTest.php b/src/Symfony/Component/Validator/Tests/Constraints/ExpressionLanguageSyntaxValidatorTest.php similarity index 94% rename from src/Symfony/Component/Validator/Tests/Constraints/ExpressionLanguageSyntaxTest.php rename to src/Symfony/Component/Validator/Tests/Constraints/ExpressionLanguageSyntaxValidatorTest.php index dc80288c38544..7db835b333f52 100644 --- a/src/Symfony/Component/Validator/Tests/Constraints/ExpressionLanguageSyntaxTest.php +++ b/src/Symfony/Component/Validator/Tests/Constraints/ExpressionLanguageSyntaxValidatorTest.php @@ -18,7 +18,7 @@ use Symfony\Component\Validator\Constraints\ExpressionLanguageSyntaxValidator; use Symfony\Component\Validator\Test\ConstraintValidatorTestCase; -class ExpressionLanguageSyntaxTest extends ConstraintValidatorTestCase +class ExpressionLanguageSyntaxValidatorTest extends ConstraintValidatorTestCase { /** * @var \PHPUnit\Framework\MockObject\MockObject|ExpressionLanguage @@ -45,6 +45,7 @@ public function testExpressionValid(): void $this->validator->validate($this->value, new ExpressionLanguageSyntax([ 'message' => 'myMessage', + 'allowedVariables' => [], ])); $this->assertNoViolation(); @@ -58,7 +59,6 @@ public function testExpressionWithoutNames(): void $this->validator->validate($this->value, new ExpressionLanguageSyntax([ 'message' => 'myMessage', - 'validateNames' => false, ])); $this->assertNoViolation(); @@ -73,6 +73,7 @@ public function testExpressionIsNotValid(): void $this->validator->validate($this->value, new ExpressionLanguageSyntax([ 'message' => 'myMessage', + 'allowedVariables' => [], ])); $this->buildViolation('myMessage') From 69f45dc3a2e127e60dd2454401df3a7df873cc2e Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 31 May 2020 08:14:11 +0200 Subject: [PATCH 30/31] updated CHANGELOG for 5.1.0 --- CHANGELOG-5.1.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/CHANGELOG-5.1.md b/CHANGELOG-5.1.md index 5f1269de038e9..7d1409a1ec728 100644 --- a/CHANGELOG-5.1.md +++ b/CHANGELOG-5.1.md @@ -7,6 +7,23 @@ in 5.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/v5.1.0...v5.1.1 +* 5.1.0 (2020-05-31) + + * bug #37009 [Validator] use "allowedVariables" to configure the ExpressionLanguageSyntax constraint (xabbuh) + * bug #37008 [Security] Fixed AbstractToken::hasUserChanged() (wouterj) + * bug #36894 [Validator] never directly validate Existence (Required/Optional) constraints (xabbuh) + * bug #37007 [Console] Fix QuestionHelper::disableStty() (chalasr) + * bug #36865 [Form] validate subforms in all validation groups (xabbuh) + * bug #36907 Fixes sprintf(): Too few arguments in form transformer (pedrocasado) + * bug #36868 [Validator] Use Mime component to determine mime type for file validator (pierredup) + * bug #37000 Add meaningful message when using ProcessHelper and Process is not installed (l-vo) + * bug #36990 [Messenger] Change the default notify timeout value for PostgreSQL (fabpot) + * bug #36995 [TwigBridge] fix fallback html-to-txt body converter (nicolas-grekas) + * bug #36993 [ErrorHandler] fix setting $trace to null in FatalError (nicolas-grekas) + * bug #36987 Handle fetch mode deprecation of DBAL 2.11. (derrabus) + * bug #36984 [SecurityBundle] Fixed version constraint on security-core and security-guard (wouterj) + * bug #36974 [Security] Fixed handling of CSRF logout error (wouterj) + * 5.1.0-RC2 (2020-05-26) * bug #36966 Fix extra SQL support in Doctrine migrations (fabpot) From 70780fc68bee71a01b4c38ec4c2ff73feaa0788c Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 31 May 2020 08:14:18 +0200 Subject: [PATCH 31/31] updated VERSION for 5.1.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 c5313ee24f85d..0df231dca9334 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 static $freshCache = []; - const VERSION = '5.1.0-DEV'; + const VERSION = '5.1.0'; const VERSION_ID = 50100; const MAJOR_VERSION = 5; const MINOR_VERSION = 1; const RELEASE_VERSION = 0; - const EXTRA_VERSION = 'DEV'; + const EXTRA_VERSION = ''; const END_OF_MAINTENANCE = '01/2021'; const END_OF_LIFE = '01/2021';