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'; pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy