From 93eacd9bfdb580d3084b490a367c9d00b2c4d929 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 1 Feb 2023 09:01:28 +0100 Subject: [PATCH 001/115] Update CHANGELOG for 4.4.50 --- CHANGELOG-4.4.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG-4.4.md b/CHANGELOG-4.4.md index 00b3a813dfba2..5a261d439826d 100644 --- a/CHANGELOG-4.4.md +++ b/CHANGELOG-4.4.md @@ -7,6 +7,11 @@ in 4.4 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/v4.4.0...v4.4.1 +* 4.4.50 (2023-02-01) + + * security #cve-2022-24895 [Security/Http] Remove CSRF tokens from storage on successful login (nicolas-grekas) + * security #cve-2022-24894 [HttpKernel] Remove private headers before storing responses with HttpCache (nicolas-grekas) + * 4.4.49 (2022-11-28) * bug #48273 [HttpKernel] Fix message for unresovable arguments of invokable controllers (fancyweb) From d0f26e7850c5e815a949caae4083ac0f83454de6 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Wed, 1 Feb 2023 09:01:31 +0100 Subject: [PATCH 002/115] Update VERSION for 4.4.50 --- src/Symfony/Component/HttpKernel/Kernel.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index be36bc6346550..7064edefbe456 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -76,11 +76,11 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl private static $freshCache = []; - public const VERSION = '4.4.49'; - public const VERSION_ID = 40449; + public const VERSION = '4.4.50'; + public const VERSION_ID = 40450; public const MAJOR_VERSION = 4; public const MINOR_VERSION = 4; - public const RELEASE_VERSION = 49; + public const RELEASE_VERSION = 50; public const EXTRA_VERSION = ''; public const END_OF_MAINTENANCE = '11/2022'; From d4a701096401ff6eaab32cbc5428767205b1c220 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 4 May 2023 10:52:02 +0200 Subject: [PATCH 003/115] [HttpClient] fix missing dep --- src/Symfony/Component/HttpClient/composer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Symfony/Component/HttpClient/composer.json b/src/Symfony/Component/HttpClient/composer.json index 086d34e22ff02..42a95e245fa9c 100644 --- a/src/Symfony/Component/HttpClient/composer.json +++ b/src/Symfony/Component/HttpClient/composer.json @@ -33,6 +33,7 @@ "nyholm/psr7": "^1.0", "php-http/httplug": "^1.0|^2.0", "psr/http-client": "^1.0", + "php-http/message-factory": "^1.0", "symfony/dependency-injection": "^4.3|^5.0", "symfony/http-kernel": "^4.4.13", "symfony/process": "^4.2|^5.0" From b8eb61daf4a9443298178893f858b953d4e5fd2d Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sat, 30 Sep 2023 08:36:22 +0200 Subject: [PATCH 004/115] Bump Symfony version to 5.4.30 --- src/Symfony/Component/HttpKernel/Kernel.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Symfony/Component/HttpKernel/Kernel.php b/src/Symfony/Component/HttpKernel/Kernel.php index 8e40682cea873..e7e3282d49db7 100644 --- a/src/Symfony/Component/HttpKernel/Kernel.php +++ b/src/Symfony/Component/HttpKernel/Kernel.php @@ -78,12 +78,12 @@ abstract class Kernel implements KernelInterface, RebootableInterface, Terminabl */ private static $freshCache = []; - public const VERSION = '5.4.29'; - public const VERSION_ID = 50429; + public const VERSION = '5.4.30-DEV'; + public const VERSION_ID = 50430; public const MAJOR_VERSION = 5; public const MINOR_VERSION = 4; - public const RELEASE_VERSION = 29; - public const EXTRA_VERSION = ''; + public const RELEASE_VERSION = 30; + public const EXTRA_VERSION = 'DEV'; public const END_OF_MAINTENANCE = '11/2024'; public const END_OF_LIFE = '11/2025'; From 5d9d6b79e49178dd9328d29a0959ed1278f350b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Lesueurs?= Date: Fri, 19 Aug 2022 19:39:55 +0200 Subject: [PATCH 005/115] Change incorrect message, when the sender in the global envelope or the from header of asEmailMessage() is not defined. --- src/Symfony/Component/Notifier/Channel/EmailChannel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Notifier/Channel/EmailChannel.php b/src/Symfony/Component/Notifier/Channel/EmailChannel.php index a258783464d6a..c5eec591755c8 100644 --- a/src/Symfony/Component/Notifier/Channel/EmailChannel.php +++ b/src/Symfony/Component/Notifier/Channel/EmailChannel.php @@ -57,7 +57,7 @@ public function notify(Notification $notification, RecipientInterface $recipient if ($email instanceof Email) { if (!$email->getFrom()) { if (null === $this->from) { - throw new LogicException(sprintf('To send the "%s" notification by email, you should either configure a global "from" header, set a sender in the global "envelope" of the mailer configuration or set a "from" header in the "asEmailMessage()" method.', get_debug_type($notification))); + throw new LogicException(sprintf('To send the "%s" notification by email, you must configure the global "from" header. For this you can set a sender in the global "envelope" of the mailer configuration or set a "from" header in the "asEmailMessage()" method.', get_debug_type($notification))); } $email->from($this->from); From 28ba7d98e804cda552188b7c6e053e77176cf122 Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Sun, 1 Oct 2023 09:27:32 +0200 Subject: [PATCH 006/115] [Notifier] Tweak an error message --- src/Symfony/Component/Notifier/Channel/EmailChannel.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Component/Notifier/Channel/EmailChannel.php b/src/Symfony/Component/Notifier/Channel/EmailChannel.php index c5eec591755c8..69caaad1ae480 100644 --- a/src/Symfony/Component/Notifier/Channel/EmailChannel.php +++ b/src/Symfony/Component/Notifier/Channel/EmailChannel.php @@ -57,7 +57,7 @@ public function notify(Notification $notification, RecipientInterface $recipient if ($email instanceof Email) { if (!$email->getFrom()) { if (null === $this->from) { - throw new LogicException(sprintf('To send the "%s" notification by email, you must configure the global "from" header. For this you can set a sender in the global "envelope" of the mailer configuration or set a "from" header in the "asEmailMessage()" method.', get_debug_type($notification))); + throw new LogicException(sprintf('To send the "%s" notification by email, you must configure a "from" header by either setting a sender in the global "envelope" of the mailer configuration or by setting a "from" header in the "asEmailMessage()" method.', get_debug_type($notification))); } $email->from($this->from); From cff99dc3fdc7d863290dfe12c96c6d412ab81d8b Mon Sep 17 00:00:00 2001 From: "g.petraroli" Date: Wed, 4 Oct 2023 14:42:59 +0200 Subject: [PATCH 007/115] [Validator] Add missing italian translations --- .../Resources/translations/validators.it.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf index c7cd43784ee63..d9d9d06611d42 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.it.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Il valore della netmask dovrebbe essere compreso tra {{ min }} e {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Il nome del file è troppo lungo. Dovrebbe avere {{ filename_max_length }} carattere o meno.|Il nome del file è troppo lungo. Dovrebbe avere {{ filename_max_length }} caratteri o meno. + + + The password strength is too low. Please use a stronger password. + La password non è abbastanza sicura. Per favore, utilizza una password più robusta. + + + This value contains characters that are not allowed by the current restriction-level. + Questo valore contiene caratteri che non sono consentiti dal livello di restrizione attuale. + + + Using invisible characters is not allowed. + Utilizzare caratteri invisibili non è consentito. + + + Mixing numbers from different scripts is not allowed. + Non è consentito mescolare numeri provenienti da diversi script. + + + Using hidden overlay characters is not allowed. + Non è consentito utilizzare caratteri sovrapposti nascosti. + From 98c41e07bc95db4cd478d4f408c04dbe8455fb9a Mon Sep 17 00:00:00 2001 From: Robin Chalas Date: Thu, 5 Oct 2023 15:08:48 +0200 Subject: [PATCH 008/115] [Security] Fix resetting traceable listeners --- .../SecurityBundle/Debug/TraceableFirewallListener.php | 9 ++++++++- .../DependencyInjection/SecurityExtension.php | 1 + .../SecurityBundle/Resources/config/security_debug.php | 1 + src/Symfony/Bundle/SecurityBundle/composer.json | 3 ++- .../Debug/TraceableAuthenticatorManagerListener.php | 8 +++++++- src/Symfony/Component/Security/Http/composer.json | 5 +++-- 6 files changed, 22 insertions(+), 5 deletions(-) diff --git a/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php b/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php index e82b47695bad9..9cb032adc8e93 100644 --- a/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php +++ b/src/Symfony/Bundle/SecurityBundle/Debug/TraceableFirewallListener.php @@ -17,13 +17,14 @@ use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\Security\Http\Authenticator\Debug\TraceableAuthenticatorManagerListener; use Symfony\Component\Security\Http\Firewall\FirewallListenerInterface; +use Symfony\Contracts\Service\ResetInterface; /** * Firewall collecting called security listeners and authenticators. * * @author Robin Chalas */ -final class TraceableFirewallListener extends FirewallListener +final class TraceableFirewallListener extends FirewallListener implements ResetInterface { private $wrappedListeners = []; private $authenticatorsInfo = []; @@ -38,6 +39,12 @@ public function getAuthenticatorsInfo(): array return $this->authenticatorsInfo; } + public function reset(): void + { + $this->wrappedListeners = []; + $this->authenticatorsInfo = []; + } + protected function callListeners(RequestEvent $event, iterable $listeners) { $wrappedListeners = []; diff --git a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php index c165024b68d0d..c19cae041bd10 100644 --- a/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php +++ b/src/Symfony/Bundle/SecurityBundle/DependencyInjection/SecurityExtension.php @@ -544,6 +544,7 @@ private function createFirewall(ContainerBuilder $container, string $id, array $ ->register('debug.security.firewall.authenticator.'.$id, TraceableAuthenticatorManagerListener::class) ->setDecoratedService('security.firewall.authenticator.'.$id) ->setArguments([new Reference('debug.security.firewall.authenticator.'.$id.'.inner')]) + ->addTag('kernel.reset', ['method' => 'reset']) ; } diff --git a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_debug.php b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_debug.php index dc668b15e9ded..c98e3a6984672 100644 --- a/src/Symfony/Bundle/SecurityBundle/Resources/config/security_debug.php +++ b/src/Symfony/Bundle/SecurityBundle/Resources/config/security_debug.php @@ -36,6 +36,7 @@ service('security.logout_url_generator'), ]) ->tag('kernel.event_subscriber') + ->tag('kernel.reset', ['method' => 'reset']) ->alias('security.firewall', 'debug.security.firewall') ; }; diff --git a/src/Symfony/Bundle/SecurityBundle/composer.json b/src/Symfony/Bundle/SecurityBundle/composer.json index dc3c62aeee0e6..097031baffb6d 100644 --- a/src/Symfony/Bundle/SecurityBundle/composer.json +++ b/src/Symfony/Bundle/SecurityBundle/composer.json @@ -29,7 +29,8 @@ "symfony/security-core": "^5.4|^6.0", "symfony/security-csrf": "^4.4|^5.0|^6.0", "symfony/security-guard": "^5.3", - "symfony/security-http": "^5.4.20|~6.0.20|~6.1.12|^6.2.6" + "symfony/security-http": "^5.4.30|^6.3.6", + "symfony/service-contracts": "^1.10|^2|^3" }, "require-dev": { "doctrine/annotations": "^1.10.4|^2", diff --git a/src/Symfony/Component/Security/Http/Authenticator/Debug/TraceableAuthenticatorManagerListener.php b/src/Symfony/Component/Security/Http/Authenticator/Debug/TraceableAuthenticatorManagerListener.php index 3286ce265dd81..e67e332286014 100644 --- a/src/Symfony/Component/Security/Http/Authenticator/Debug/TraceableAuthenticatorManagerListener.php +++ b/src/Symfony/Component/Security/Http/Authenticator/Debug/TraceableAuthenticatorManagerListener.php @@ -16,13 +16,14 @@ use Symfony\Component\Security\Http\Firewall\AbstractListener; use Symfony\Component\Security\Http\Firewall\AuthenticatorManagerListener; use Symfony\Component\VarDumper\Caster\ClassStub; +use Symfony\Contracts\Service\ResetInterface; /** * Decorates the AuthenticatorManagerListener to collect information about security authenticators. * * @author Robin Chalas */ -final class TraceableAuthenticatorManagerListener extends AbstractListener +final class TraceableAuthenticatorManagerListener extends AbstractListener implements ResetInterface { private $authenticationManagerListener; private $authenticatorsInfo = []; @@ -78,4 +79,9 @@ public function getAuthenticatorsInfo(): array { return $this->authenticatorsInfo; } + + public function reset(): void + { + $this->authenticatorsInfo = []; + } } diff --git a/src/Symfony/Component/Security/Http/composer.json b/src/Symfony/Component/Security/Http/composer.json index a5378b3ce5812..deb09da87c162 100644 --- a/src/Symfony/Component/Security/Http/composer.json +++ b/src/Symfony/Component/Security/Http/composer.json @@ -18,12 +18,13 @@ "require": { "php": ">=7.2.5", "symfony/deprecation-contracts": "^2.1|^3", - "symfony/security-core": "^5.4.19|~6.0.19|~6.1.11|^6.2.5", "symfony/http-foundation": "^5.3|^6.0", "symfony/http-kernel": "^5.3|^6.0", "symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-php80": "^1.16", - "symfony/property-access": "^4.4|^5.0|^6.0" + "symfony/property-access": "^4.4|^5.0|^6.0", + "symfony/security-core": "^5.4.19|~6.0.19|~6.1.11|^6.2.5", + "symfony/service-contracts": "^1.10|^2|^3" }, "require-dev": { "symfony/cache": "^4.4|^5.0|^6.0", From af18ce4709c66987dc8d85670b1547d945deeee9 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Fri, 6 Oct 2023 21:16:43 +0200 Subject: [PATCH 009/115] Make FormPerformanceTestCase compatible with PHPUnit 10 --- .../Form/Test/FormPerformanceTestCase.php | 10 ++++-- .../Form/Test/Traits/RunTestTrait.php | 36 +++++++++++++++++++ 2 files changed, 43 insertions(+), 3 deletions(-) create mode 100644 src/Symfony/Component/Form/Test/Traits/RunTestTrait.php diff --git a/src/Symfony/Component/Form/Test/FormPerformanceTestCase.php b/src/Symfony/Component/Form/Test/FormPerformanceTestCase.php index 732f9ec3dd02b..8c0284ebf5985 100644 --- a/src/Symfony/Component/Form/Test/FormPerformanceTestCase.php +++ b/src/Symfony/Component/Form/Test/FormPerformanceTestCase.php @@ -11,6 +11,7 @@ namespace Symfony\Component\Form\Test; +use Symfony\Component\Form\Test\Traits\RunTestTrait; use Symfony\Component\Form\Tests\VersionAwareTest; /** @@ -23,6 +24,7 @@ */ abstract class FormPerformanceTestCase extends FormIntegrationTestCase { + use RunTestTrait; use VersionAwareTest; /** @@ -31,17 +33,19 @@ abstract class FormPerformanceTestCase extends FormIntegrationTestCase protected $maxRunningTime = 0; /** - * {@inheritdoc} + * @return mixed */ - protected function runTest() + private function doRunTest() { $s = microtime(true); - parent::runTest(); + $result = parent::runTest(); $time = microtime(true) - $s; if (0 != $this->maxRunningTime && $time > $this->maxRunningTime) { $this->fail(sprintf('expected running time: <= %s but was: %s', $this->maxRunningTime, $time)); } + + return $result; } /** diff --git a/src/Symfony/Component/Form/Test/Traits/RunTestTrait.php b/src/Symfony/Component/Form/Test/Traits/RunTestTrait.php new file mode 100644 index 0000000000000..17204b96703f2 --- /dev/null +++ b/src/Symfony/Component/Form/Test/Traits/RunTestTrait.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Form\Test\Traits; + +use PHPUnit\Framework\TestCase; + +if ((new \ReflectionMethod(TestCase::class, 'runTest'))->hasReturnType()) { + // PHPUnit 10 + /** @internal */ + trait RunTestTrait + { + protected function runTest(): mixed + { + return $this->doRunTest(); + } + } +} else { + // PHPUnit 9 + /** @internal */ + trait RunTestTrait + { + protected function runTest() + { + return $this->doRunTest(); + } + } +} From 7c8b6ed5de8fd672f9e00820ba956306f73c9d7e Mon Sep 17 00:00:00 2001 From: Mykola Zyk Date: Wed, 22 Dec 2021 20:01:14 +0200 Subject: [PATCH 010/115] [RateLimiter] TokenBucket policy fix for adding tokens with a predefined frequency --- .../Component/RateLimiter/Policy/Rate.php | 12 +++++++++ .../RateLimiter/Policy/TokenBucket.php | 7 ++++- .../RateLimiter/Policy/TokenBucketLimiter.php | 2 -- .../Tests/Policy/TokenBucketLimiterTest.php | 26 +++++++++++++++++++ 4 files changed, 44 insertions(+), 3 deletions(-) diff --git a/src/Symfony/Component/RateLimiter/Policy/Rate.php b/src/Symfony/Component/RateLimiter/Policy/Rate.php index 0c91ef78e76c2..3775f53ae8b3c 100644 --- a/src/Symfony/Component/RateLimiter/Policy/Rate.php +++ b/src/Symfony/Component/RateLimiter/Policy/Rate.php @@ -95,6 +95,18 @@ public function calculateNewTokensDuringInterval(float $duration): int return $cycles * $this->refillAmount; } + /** + * Calculates total amount in seconds of refill intervals during $duration (for maintain strict refill frequency). + * + * @param float $duration interval in seconds + */ + public function calculateRefillInterval(float $duration): int + { + $cycleTime = TimeUtil::dateIntervalToSeconds($this->refillTime); + + return floor($duration / $cycleTime) * $cycleTime; + } + public function __toString(): string { return $this->refillTime->format('P%dDT%HH%iM%sS').'-'.$this->refillAmount; diff --git a/src/Symfony/Component/RateLimiter/Policy/TokenBucket.php b/src/Symfony/Component/RateLimiter/Policy/TokenBucket.php index e4eb32a744a71..2d43286e15e23 100644 --- a/src/Symfony/Component/RateLimiter/Policy/TokenBucket.php +++ b/src/Symfony/Component/RateLimiter/Policy/TokenBucket.php @@ -83,8 +83,13 @@ public function setTokens(int $tokens): void public function getAvailableTokens(float $now): int { $elapsed = max(0, $now - $this->timer); + $newTokens = $this->rate->calculateNewTokensDuringInterval($elapsed); - return min($this->burstSize, $this->tokens + $this->rate->calculateNewTokensDuringInterval($elapsed)); + if ($newTokens > 0) { + $this->timer += $this->rate->calculateRefillInterval($elapsed); + } + + return min($this->burstSize, $this->tokens + $newTokens); } public function getExpirationTime(): int diff --git a/src/Symfony/Component/RateLimiter/Policy/TokenBucketLimiter.php b/src/Symfony/Component/RateLimiter/Policy/TokenBucketLimiter.php index 09c4e36cdf861..5724eba2b2abb 100644 --- a/src/Symfony/Component/RateLimiter/Policy/TokenBucketLimiter.php +++ b/src/Symfony/Component/RateLimiter/Policy/TokenBucketLimiter.php @@ -72,7 +72,6 @@ public function reserve(int $tokens = 1, float $maxTime = null): Reservation if ($availableTokens >= $tokens) { // tokens are now available, update bucket $bucket->setTokens($availableTokens - $tokens); - $bucket->setTimer($now); $reservation = new Reservation($now, new RateLimit($bucket->getAvailableTokens($now), \DateTimeImmutable::createFromFormat('U', floor($now)), true, $this->maxBurst)); } else { @@ -89,7 +88,6 @@ public function reserve(int $tokens = 1, float $maxTime = null): Reservation // at $now + $waitDuration all tokens will be reserved for this process, // so no tokens are left for other processes. $bucket->setTokens($availableTokens - $tokens); - $bucket->setTimer($now); $reservation = new Reservation($now + $waitDuration, new RateLimit(0, \DateTimeImmutable::createFromFormat('U', floor($now + $waitDuration)), false, $this->maxBurst)); } diff --git a/src/Symfony/Component/RateLimiter/Tests/Policy/TokenBucketLimiterTest.php b/src/Symfony/Component/RateLimiter/Tests/Policy/TokenBucketLimiterTest.php index 84136ed7f5d7d..3b7b579c0cf77 100644 --- a/src/Symfony/Component/RateLimiter/Tests/Policy/TokenBucketLimiterTest.php +++ b/src/Symfony/Component/RateLimiter/Tests/Policy/TokenBucketLimiterTest.php @@ -128,6 +128,32 @@ public function testBucketResilientToTimeShifting() $this->assertSame(100, $bucket->getAvailableTokens($serverOneClock)); } + public function testBucketRefilledWithStrictFrequency() + { + $limiter = $this->createLimiter(1000, new Rate(\DateInterval::createFromDateString('15 seconds'), 100)); + $rateLimit = $limiter->consume(300); + + $this->assertTrue($rateLimit->isAccepted()); + $this->assertEquals(700, $rateLimit->getRemainingTokens()); + + $expected = 699; + + for ($i = 1; $i <= 20; ++$i) { + $rateLimit = $limiter->consume(); + $this->assertTrue($rateLimit->isAccepted()); + $this->assertEquals($expected, $rateLimit->getRemainingTokens()); + + sleep(4); + --$expected; + + if (\in_array($i, [4, 8, 12], true)) { + $expected += 100; + } elseif (\in_array($i, [15, 19], true)) { + $expected = 999; + } + } + } + private function createLimiter($initialTokens = 10, Rate $rate = null) { return new TokenBucketLimiter('test', $initialTokens, $rate ?? Rate::perSecond(10), $this->storage); From 49f7f5e71911b3d6540f744cf4475f571cf012a6 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Tue, 10 Oct 2023 08:19:19 +0200 Subject: [PATCH 011/115] Add keyword `dev` to leverage composer hint --- src/Symfony/Bridge/PhpUnit/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/composer.json b/src/Symfony/Bridge/PhpUnit/composer.json index 9627d2b40c12c..4cddb15dac3a2 100644 --- a/src/Symfony/Bridge/PhpUnit/composer.json +++ b/src/Symfony/Bridge/PhpUnit/composer.json @@ -2,7 +2,7 @@ "name": "symfony/phpunit-bridge", "type": "symfony-bridge", "description": "Provides utilities for PHPUnit, especially user deprecation notices management", - "keywords": [], + "keywords": ['dev'], "homepage": "https://symfony.com", "license": "MIT", "authors": [ From e86d26abd07187d5ec5b2d780cfd1d872d57fe2a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Tue, 10 Oct 2023 09:31:48 +0200 Subject: [PATCH 012/115] [PhpUnitBridge] Fix typo --- src/Symfony/Bridge/PhpUnit/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/composer.json b/src/Symfony/Bridge/PhpUnit/composer.json index 4cddb15dac3a2..167ed8767b35b 100644 --- a/src/Symfony/Bridge/PhpUnit/composer.json +++ b/src/Symfony/Bridge/PhpUnit/composer.json @@ -2,7 +2,7 @@ "name": "symfony/phpunit-bridge", "type": "symfony-bridge", "description": "Provides utilities for PHPUnit, especially user deprecation notices management", - "keywords": ['dev'], + "keywords": ["dev"], "homepage": "https://symfony.com", "license": "MIT", "authors": [ From 5168f2d8515e1a76c097b0432ffbad4dd5034488 Mon Sep 17 00:00:00 2001 From: adhamiamirhossein Date: Tue, 10 Oct 2023 13:52:57 +0330 Subject: [PATCH 013/115] [Validator] Add missing Persian(fa) translations --- .../Resources/translations/validators.fa.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf index b72bc6e03e93c..50bb61aac420f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fa.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. مقدار ماسک شبکه (NetMask) باید بین {{ min }} و {{ max }} باشد. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + نام فایل طولانی است. نام فایل باید {{ filename_max_length }} کاراکتر یا کمتر باشد.|نام فایل طولانی است. نام فایل باید {{ filename_max_length }} کاراکتر یا کمتر باشد. + + + The password strength is too low. Please use a stronger password. + رمز عبور ضعیف است. لطفا از رمز عبور قوی‌تری استفاده کنید. + + + This value contains characters that are not allowed by the current restriction-level. + این مقدار حاوی کاراکترهایی است که در سطح محدودیت فعلی مجاز نیستند. + + + Using invisible characters is not allowed. + استفاده از کاراکترهای نامرئی مجاز نمی‌باشد. + + + Mixing numbers from different scripts is not allowed. + مخلوط کردن اعداد از اسکریپت های مختلف مجاز نیست. + + + Using hidden overlay characters is not allowed. + استفاده از کاراکترهای همپوشانی پنهان (hidden overlay characters) مجاز نیست. + From f10c2ccd33a0ac17f5a45f930e3a878452eb830f Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Tue, 10 Oct 2023 12:05:35 +0200 Subject: [PATCH 014/115] [FrameworkBundle] Fix calling Kernel::warmUp() when running cache:warmup --- .../Bundle/FrameworkBundle/Command/CacheWarmupCommand.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/Command/CacheWarmupCommand.php b/src/Symfony/Bundle/FrameworkBundle/Command/CacheWarmupCommand.php index ddaf9eb63e06d..48e882e6f68b3 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Command/CacheWarmupCommand.php +++ b/src/Symfony/Bundle/FrameworkBundle/Command/CacheWarmupCommand.php @@ -18,6 +18,7 @@ use Symfony\Component\Console\Style\SymfonyStyle; use Symfony\Component\DependencyInjection\Dumper\Preloader; use Symfony\Component\HttpKernel\CacheWarmer\CacheWarmerAggregate; +use Symfony\Component\HttpKernel\CacheWarmer\WarmableInterface; /** * Warmup the cache. @@ -73,8 +74,13 @@ protected function execute(InputInterface $input, OutputInterface $output): int if (!$input->getOption('no-optional-warmers')) { $this->cacheWarmer->enableOptionalWarmers(); } + $cacheDir = $kernel->getContainer()->getParameter('kernel.cache_dir'); - $preload = $this->cacheWarmer->warmUp($cacheDir = $kernel->getContainer()->getParameter('kernel.cache_dir')); + if ($kernel instanceof WarmableInterface) { + $kernel->warmUp($cacheDir); + } + + $preload = $this->cacheWarmer->warmUp($cacheDir); if ($preload && file_exists($preloadFile = $cacheDir.'/'.$kernel->getContainer()->getParameter('kernel.container_class').'.preload.php')) { Preloader::append($preloadFile, $preload); From b32735b19f17901b3aed9e5ac38a71ffdc31a69c Mon Sep 17 00:00:00 2001 From: Pedro Silva <9375141+pedrox-hs@users.noreply.github.com> Date: Tue, 10 Oct 2023 14:12:05 -0300 Subject: [PATCH 015/115] [Translation][Validator] Add missing translations for pt_BR (104-109) --- .../translations/validators.pt_BR.xlf | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf index e88b81f9eaf8b..7e930a3c6a0bf 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf @@ -402,6 +402,31 @@ The value of the netmask should be between {{ min }} and {{ max }}. O valor da máscara de rede deve estar entre {{ min }} e {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + O nome do arquivo é muito longo. Deve ter {{ filename_max_length }} caractere ou menos.|O nome do arquivo é muito longo. Deve ter {{ filename_max_length }} caracteres ou menos. + + + The password strength is too low. Please use a stronger password. + A força da senha é muito baixa. Por favor, use uma senha mais forte. + + + This value contains characters that are not allowed by the current restriction-level. + Este valor contém caracteres que não são permitidos pelo nível de restrição atual. + + + Using invisible characters is not allowed. + O uso de caracteres invisíveis não é permitido. + + + Mixing numbers from different scripts is not allowed. + Misturar números de scripts diferentes não é permitido. + + + Using hidden overlay characters is not allowed. + O uso de caracteres de sobreposição ocultos não é permitido. + + From 887b1307bfea90fff734e2cbaaef4242099dc8be Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Tue, 10 Oct 2023 21:28:02 +0200 Subject: [PATCH 016/115] [Translation] remove blank line --- .../Validator/Resources/translations/validators.pt_BR.xlf | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf index 7e930a3c6a0bf..2430ad6b58285 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt_BR.xlf @@ -426,7 +426,6 @@ Using hidden overlay characters is not allowed. O uso de caracteres de sobreposição ocultos não é permitido. - From 970f9ae38e99b23182862e95e8303b91c7ba765e Mon Sep 17 00:00:00 2001 From: Natsuki Ikeguchi Date: Wed, 11 Oct 2023 01:50:15 +0900 Subject: [PATCH 017/115] [Translation][Validator] Add missing translations for Japanese (104 - 109) --- .../Resources/translations/validators.ja.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf index 9feed48d04cb0..7e4cac5434a17 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ja.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. ネットマスクの値は、{{ min }}から{{ max }}の間にある必要があります。 + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + ファイル名が長すぎます。ファイル名の長さは{{ filename_max_length }}文字以下でなければなりません。 + + + The password strength is too low. Please use a stronger password. + パスワードの強度が弱すぎます。より強いパスワードを使用してください。 + + + This value contains characters that are not allowed by the current restriction-level. + この値は現在の制限レベルで許可されていない文字を含んでいます。 + + + Using invisible characters is not allowed. + 不可視文字は使用できません。 + + + Mixing numbers from different scripts is not allowed. + 異なる種類の数字を使うことはできません。 + + + Using hidden overlay characters is not allowed. + 隠れたオーバレイ文字は使用できません。 + From d398c8bacf05d0035a3f36699f0001981c23ac45 Mon Sep 17 00:00:00 2001 From: Sergey Panteleev Date: Wed, 11 Oct 2023 10:53:45 +0300 Subject: [PATCH 018/115] [Translation][Validator] Add missing translations for Russian (104 - 109) --- .../Resources/translations/validators.ru.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf index 8705cbb55d0e6..2b66b1eafd954 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ru.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Значение маски подсети должно быть от {{ min }} до {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Имя файла слишком длинное. Оно должно содержать {{ filename_max_length }} символ или меньше.|Имя файла слишком длинное. Оно должно содержать {{ filename_max_length }} символа или меньше.|Имя файла слишком длинное. Оно должно содержать {{ filename_max_length }} символов или меньше. + + + The password strength is too low. Please use a stronger password. + Слишком низкая надёжность пароля. Пожалуйста, используйте более надёжный пароль. + + + This value contains characters that are not allowed by the current restriction-level. + Значение содержит символы, запрещённые на текущем уровне ограничений. + + + Using invisible characters is not allowed. + Использование невидимых символов запрещено. + + + Mixing numbers from different scripts is not allowed. + Смешивание номеров из разных сценариев запрещено. + + + Using hidden overlay characters is not allowed. + Использование невидимых символов наложения запрещено. + From c0648fff946731e2d6ad82baf81b01a48522b608 Mon Sep 17 00:00:00 2001 From: Mathieu Lechat Date: Wed, 11 Oct 2023 10:22:16 +0200 Subject: [PATCH 019/115] [WebProfilerBundle] Fix markup to make link to profiler appear on errored WDT --- .../Resources/views/Profiler/base_js.html.twig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig index af36bc03313de..be979cd6ad231 100644 --- a/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig +++ b/src/Symfony/Bundle/WebProfilerBundle/Resources/views/Profiler/base_js.html.twig @@ -618,7 +618,7 @@ if (typeof Sfjs === 'undefined' || typeof Sfjs.loadToolbar === 'undefined') { sfwdt.innerHTML = '\
\
\ - An error occurred while loading the web debug toolbar. Open the web profiler.\ + An error occurred while loading the web debug toolbar. Open the web profiler.\
\ '; sfwdt.setAttribute('class', 'sf-toolbar sf-error-toolbar'); From ccacdf885bfd2cb4ddd02a4acd5da80ec09b7611 Mon Sep 17 00:00:00 2001 From: Yanick Witschi Date: Wed, 11 Oct 2023 10:40:37 +0200 Subject: [PATCH 020/115] Do not match request twice in HttpUtils --- .../Component/Security/Http/HttpUtils.php | 5 +++++ .../Security/Http/Tests/HttpUtilsTest.php | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Symfony/Component/Security/Http/HttpUtils.php b/src/Symfony/Component/Security/Http/HttpUtils.php index a4e0371321516..ee15ce965e38e 100644 --- a/src/Symfony/Component/Security/Http/HttpUtils.php +++ b/src/Symfony/Component/Security/Http/HttpUtils.php @@ -118,6 +118,11 @@ public function createRequest(Request $request, string $path) public function checkRequestPath(Request $request, string $path) { if ('/' !== $path[0]) { + // Shortcut if request has already been matched before + if ($request->attributes->has('_route')) { + return $path === $request->attributes->get('_route'); + } + try { // matching a request is more powerful than matching a URL path + context, so try that first if ($this->urlMatcher instanceof RequestMatcherInterface) { diff --git a/src/Symfony/Component/Security/Http/Tests/HttpUtilsTest.php b/src/Symfony/Component/Security/Http/Tests/HttpUtilsTest.php index 7686a296d775b..a63c40f5b9758 100644 --- a/src/Symfony/Component/Security/Http/Tests/HttpUtilsTest.php +++ b/src/Symfony/Component/Security/Http/Tests/HttpUtilsTest.php @@ -318,6 +318,22 @@ public function testCheckRequestPathWithUrlMatcherLoadingException() $utils->checkRequestPath($this->getRequest(), 'foobar'); } + public function testCheckRequestPathWithRequestAlreadyMatchedBefore() + { + $urlMatcher = $this->createMock(RequestMatcherInterface::class); + $urlMatcher + ->expects($this->never()) + ->method('matchRequest') + ; + + $request = $this->getRequest(); + $request->attributes->set('_route', 'route_name'); + + $utils = new HttpUtils(null, $urlMatcher); + $this->assertTrue($utils->checkRequestPath($request, 'route_name')); + $this->assertFalse($utils->checkRequestPath($request, 'foobar')); + } + public function testCheckPathWithoutRouteParam() { $urlMatcher = $this->createMock(UrlMatcherInterface::class); From 79d75ffba9975873b898b511fda59b2d40e44fa7 Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Tue, 10 Oct 2023 09:59:31 +0200 Subject: [PATCH 021/115] Run high-deps tests with ORM 3 and DBAL 4 --- .../PropertyInfo/DoctrineExtractor.php | 19 +++-- .../Doctrine/Test/TestRepositoryFactory.php | 35 +++++++-- .../Tests/Fixtures/LegacyQueryMock.php | 36 +++++++++ .../ChoiceList/ORMQueryBuilderLoaderTest.php | 78 +++++++------------ .../Tests/Form/DoctrineOrmTypeGuesserTest.php | 46 +++++++---- .../PropertyInfo/DoctrineExtractorTest.php | 24 ++---- .../Security/User/EntityUserProviderTest.php | 5 +- .../Constraints/UniqueEntityValidatorTest.php | 5 +- .../Tests/Validator/DoctrineLoaderTest.php | 43 ++++++---- .../Doctrine/Validator/DoctrineLoader.php | 4 +- src/Symfony/Bridge/Doctrine/composer.json | 4 +- .../Cache/Tests/Fixtures/DriverWrapper.php | 5 +- src/Symfony/Component/Cache/composer.json | 2 +- .../Tests/Store/DoctrineDbalStoreTest.php | 15 +++- src/Symfony/Component/Lock/composer.json | 2 +- .../Tests/Transport/ConnectionTest.php | 48 ++++++++---- .../DoctrineTransportFactoryTest.php | 12 ++- .../Bridge/Doctrine/Transport/Connection.php | 7 +- .../Messenger/Bridge/Doctrine/composer.json | 2 +- 19 files changed, 247 insertions(+), 145 deletions(-) create mode 100644 src/Symfony/Bridge/Doctrine/Tests/Fixtures/LegacyQueryMock.php diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index db9c151f0268e..ccd53c1ebe7c6 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -14,9 +14,8 @@ use Doctrine\Common\Collections\Collection; use Doctrine\DBAL\Types\Types; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\Mapping\AssociationMapping; use Doctrine\ORM\Mapping\ClassMetadata; -use Doctrine\ORM\Mapping\ClassMetadataInfo; -use Doctrine\ORM\Mapping\Embedded; use Doctrine\ORM\Mapping\MappingException as OrmMappingException; use Doctrine\Persistence\Mapping\MappingException; use Symfony\Component\PropertyInfo\PropertyAccessExtractorInterface; @@ -49,7 +48,7 @@ public function getProperties(string $class, array $context = []) $properties = array_merge($metadata->getFieldNames(), $metadata->getAssociationNames()); - if ($metadata instanceof ClassMetadataInfo && class_exists(Embedded::class) && $metadata->embeddedClasses) { + if ($metadata instanceof ClassMetadata && $metadata->embeddedClasses) { $properties = array_filter($properties, function ($property) { return !str_contains($property, '.'); }); @@ -73,7 +72,7 @@ public function getTypes(string $class, string $property, array $context = []) $class = $metadata->getAssociationTargetClass($property); if ($metadata->isSingleValuedAssociation($property)) { - if ($metadata instanceof ClassMetadataInfo) { + if ($metadata instanceof ClassMetadata) { $associationMapping = $metadata->getAssociationMapping($property); $nullable = $this->isAssociationNullable($associationMapping); @@ -86,11 +85,10 @@ public function getTypes(string $class, string $property, array $context = []) $collectionKeyType = Type::BUILTIN_TYPE_INT; - if ($metadata instanceof ClassMetadataInfo) { + if ($metadata instanceof ClassMetadata) { $associationMapping = $metadata->getAssociationMapping($property); if (isset($associationMapping['indexBy'])) { - /** @var ClassMetadataInfo $subMetadata */ $subMetadata = $this->entityManager->getClassMetadata($associationMapping['targetEntity']); // Check if indexBy value is a property @@ -102,7 +100,6 @@ public function getTypes(string $class, string $property, array $context = []) // Maybe the column name is the association join column? $associationMapping = $subMetadata->getAssociationMapping($fieldName); - /** @var ClassMetadataInfo $subMetadata */ $indexProperty = $subMetadata->getSingleAssociationReferencedJoinColumnName($fieldName); $subMetadata = $this->entityManager->getClassMetadata($associationMapping['targetEntity']); @@ -130,7 +127,7 @@ public function getTypes(string $class, string $property, array $context = []) )]; } - if ($metadata instanceof ClassMetadataInfo && class_exists(Embedded::class) && isset($metadata->embeddedClasses[$property])) { + if ($metadata instanceof ClassMetadata && isset($metadata->embeddedClasses[$property])) { return [new Type(Type::BUILTIN_TYPE_OBJECT, false, $metadata->embeddedClasses[$property]['class'])]; } @@ -141,7 +138,7 @@ public function getTypes(string $class, string $property, array $context = []) return null; } - $nullable = $metadata instanceof ClassMetadataInfo && $metadata->isNullable($property); + $nullable = $metadata instanceof ClassMetadata && $metadata->isNullable($property); $enumType = null; if (null !== $enumClass = $metadata->getFieldMapping($property)['enumType'] ?? null) { $enumType = new Type(Type::BUILTIN_TYPE_OBJECT, $nullable, $enumClass); @@ -233,9 +230,11 @@ private function getMetadata(string $class): ?ClassMetadata /** * Determines whether an association is nullable. * + * @param array|AssociationMapping $associationMapping + * * @see https://github.com/doctrine/doctrine2/blob/v2.5.4/lib/Doctrine/ORM/Tools/EntityGenerator.php#L1221-L1246 */ - private function isAssociationNullable(array $associationMapping): bool + private function isAssociationNullable($associationMapping): bool { if (isset($associationMapping['id']) && $associationMapping['id']) { return false; diff --git a/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php b/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php index 80964663c340c..f08e2154d06e9 100644 --- a/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php +++ b/src/Symfony/Bridge/Doctrine/Test/TestRepositoryFactory.php @@ -12,10 +12,36 @@ namespace Symfony\Bridge\Doctrine\Test; use Doctrine\ORM\EntityManagerInterface; +use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Repository\RepositoryFactory; use Doctrine\Persistence\ObjectRepository; +if ((new \ReflectionMethod(RepositoryFactory::class, 'getRepository'))->hasReturnType()) { + /** @internal */ + trait GetRepositoryTrait + { + public function getRepository(EntityManagerInterface $entityManager, string $entityName): EntityRepository + { + return $this->doGetRepository($entityManager, $entityName); + } + } +} else { + /** @internal */ + trait GetRepositoryTrait + { + /** + * {@inheritdoc} + * + * @return ObjectRepository + */ + public function getRepository(EntityManagerInterface $entityManager, $entityName) + { + return $this->doGetRepository($entityManager, $entityName); + } + } +} + /** * @author Andreas Braun * @@ -23,17 +49,14 @@ */ class TestRepositoryFactory implements RepositoryFactory { + use GetRepositoryTrait; + /** * @var ObjectRepository[] */ private $repositoryList = []; - /** - * {@inheritdoc} - * - * @return ObjectRepository - */ - public function getRepository(EntityManagerInterface $entityManager, $entityName) + private function doGetRepository(EntityManagerInterface $entityManager, string $entityName): ObjectRepository { if (__CLASS__ === static::class) { trigger_deprecation('symfony/doctrine-bridge', '5.3', '"%s" is deprecated and will be removed in 6.0.', __CLASS__); diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/LegacyQueryMock.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/LegacyQueryMock.php new file mode 100644 index 0000000000000..5ec46f606a8d9 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/LegacyQueryMock.php @@ -0,0 +1,36 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Tests\Fixtures; + +use Doctrine\DBAL\Result; +use Doctrine\ORM\AbstractQuery; + +class LegacyQueryMock extends AbstractQuery +{ + public function __construct() + { + } + + /** + * @return array|string + */ + public function getSQL() + { + } + + /** + * @return Result|int + */ + protected function _doExecute() + { + } +} diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/ORMQueryBuilderLoaderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/ORMQueryBuilderLoaderTest.php index b9a9d6558a49d..67f600f5d145e 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/ORMQueryBuilderLoaderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/ChoiceList/ORMQueryBuilderLoaderTest.php @@ -13,14 +13,19 @@ use Doctrine\DBAL\ArrayParameterType; use Doctrine\DBAL\Connection; -use Doctrine\DBAL\Result; use Doctrine\DBAL\Types\GuidType; use Doctrine\DBAL\Types\Type; use Doctrine\ORM\AbstractQuery; -use Doctrine\ORM\Version; +use Doctrine\ORM\Query; +use Doctrine\ORM\QueryBuilder; +use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Doctrine\Form\ChoiceList\ORMQueryBuilderLoader; use Symfony\Bridge\Doctrine\Tests\DoctrineTestHelper; +use Symfony\Bridge\Doctrine\Tests\Fixtures\EmbeddedIdentifierEntity; +use Symfony\Bridge\Doctrine\Tests\Fixtures\LegacyQueryMock; +use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity; +use Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringIdEntity; use Symfony\Bridge\Doctrine\Types\UlidType; use Symfony\Bridge\Doctrine\Types\UuidType; use Symfony\Component\Form\Exception\TransformationFailedException; @@ -37,21 +42,19 @@ protected function tearDown(): void public function testIdentifierTypeIsStringArray() { - $this->checkIdentifierType('Symfony\Bridge\Doctrine\Tests\Fixtures\SingleStringIdEntity', class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY); + $this->checkIdentifierType(SingleStringIdEntity::class, class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY); } public function testIdentifierTypeIsIntegerArray() { - $this->checkIdentifierType('Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity', class_exists(ArrayParameterType::class) ? ArrayParameterType::INTEGER : Connection::PARAM_INT_ARRAY); + $this->checkIdentifierType(SingleIntIdEntity::class, class_exists(ArrayParameterType::class) ? ArrayParameterType::INTEGER : Connection::PARAM_INT_ARRAY); } - protected function checkIdentifierType($classname, $expectedType) + protected function checkIdentifierType(string $classname, $expectedType) { $em = DoctrineTestHelper::createTestEntityManager(); - $query = $this->getMockBuilder(QueryMock::class) - ->onlyMethods(['setParameter', 'getResult', 'getSql', '_doExecute']) - ->getMock(); + $query = $this->getQueryMock(); $query ->method('getResult') @@ -62,7 +65,7 @@ protected function checkIdentifierType($classname, $expectedType) ->with('ORMQueryBuilderLoader_getEntitiesByIds_id', [1, 2], $expectedType) ->willReturn($query); - $qb = $this->getMockBuilder(\Doctrine\ORM\QueryBuilder::class) + $qb = $this->getMockBuilder(QueryBuilder::class) ->setConstructorArgs([$em]) ->onlyMethods(['getQuery']) ->getMock(); @@ -82,9 +85,7 @@ public function testFilterNonIntegerValues() { $em = DoctrineTestHelper::createTestEntityManager(); - $query = $this->getMockBuilder(QueryMock::class) - ->onlyMethods(['setParameter', 'getResult', 'getSql', '_doExecute']) - ->getMock(); + $query = $this->getQueryMock(); $query ->method('getResult') @@ -95,7 +96,7 @@ public function testFilterNonIntegerValues() ->with('ORMQueryBuilderLoader_getEntitiesByIds_id', [1, 2, 3, '9223372036854775808'], class_exists(ArrayParameterType::class) ? ArrayParameterType::INTEGER : Connection::PARAM_INT_ARRAY) ->willReturn($query); - $qb = $this->getMockBuilder(\Doctrine\ORM\QueryBuilder::class) + $qb = $this->getMockBuilder(QueryBuilder::class) ->setConstructorArgs([$em]) ->onlyMethods(['getQuery']) ->getMock(); @@ -118,9 +119,7 @@ public function testFilterEmptyUuids($entityClass) { $em = DoctrineTestHelper::createTestEntityManager(); - $query = $this->getMockBuilder(QueryMock::class) - ->onlyMethods(['setParameter', 'getResult', 'getSql', '_doExecute']) - ->getMock(); + $query = $this->getQueryMock(); $query ->method('getResult') @@ -131,7 +130,7 @@ public function testFilterEmptyUuids($entityClass) ->with('ORMQueryBuilderLoader_getEntitiesByIds_id', ['71c5fd46-3f16-4abb-bad7-90ac1e654a2d', 'b98e8e11-2897-44df-ad24-d2627eb7f499'], class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY) ->willReturn($query); - $qb = $this->getMockBuilder(\Doctrine\ORM\QueryBuilder::class) + $qb = $this->getMockBuilder(QueryBuilder::class) ->setConstructorArgs([$em]) ->onlyMethods(['getQuery']) ->getMock(); @@ -163,9 +162,7 @@ public function testFilterUid($entityClass) $em = DoctrineTestHelper::createTestEntityManager(); - $query = $this->getMockBuilder(QueryMock::class) - ->onlyMethods(['setParameter', 'getResult', 'getSql', '_doExecute']) - ->getMock(); + $query = $this->getQueryMock(); $query ->method('getResult') @@ -176,7 +173,7 @@ public function testFilterUid($entityClass) ->with('ORMQueryBuilderLoader_getEntitiesByIds_id', [Uuid::fromString('71c5fd46-3f16-4abb-bad7-90ac1e654a2d')->toBinary(), Uuid::fromString('b98e8e11-2897-44df-ad24-d2627eb7f499')->toBinary()], class_exists(ArrayParameterType::class) ? ArrayParameterType::STRING : Connection::PARAM_STR_ARRAY) ->willReturn($query); - $qb = $this->getMockBuilder(\Doctrine\ORM\QueryBuilder::class) + $qb = $this->getMockBuilder(QueryBuilder::class) ->setConstructorArgs([$em]) ->onlyMethods(['getQuery']) ->getMock(); @@ -208,7 +205,7 @@ public function testUidThrowProperException($entityClass) $em = DoctrineTestHelper::createTestEntityManager(); - $qb = $this->getMockBuilder(\Doctrine\ORM\QueryBuilder::class) + $qb = $this->getMockBuilder(QueryBuilder::class) ->setConstructorArgs([$em]) ->onlyMethods(['getQuery']) ->getMock(); @@ -229,17 +226,9 @@ public function testUidThrowProperException($entityClass) public function testEmbeddedIdentifierName() { - if (Version::compare('2.5.0') > 0) { - $this->markTestSkipped('Applicable only for Doctrine >= 2.5.0'); - - return; - } - $em = DoctrineTestHelper::createTestEntityManager(); - $query = $this->getMockBuilder(QueryMock::class) - ->onlyMethods(['setParameter', 'getResult', 'getSql', '_doExecute']) - ->getMock(); + $query = $this->getQueryMock(); $query ->method('getResult') @@ -250,7 +239,7 @@ public function testEmbeddedIdentifierName() ->with('ORMQueryBuilderLoader_getEntitiesByIds_id_value', [1, 2, 3], class_exists(ArrayParameterType::class) ? ArrayParameterType::INTEGER : Connection::PARAM_INT_ARRAY) ->willReturn($query); - $qb = $this->getMockBuilder(\Doctrine\ORM\QueryBuilder::class) + $qb = $this->getMockBuilder(QueryBuilder::class) ->setConstructorArgs([$em]) ->onlyMethods(['getQuery']) ->getMock(); @@ -259,13 +248,13 @@ public function testEmbeddedIdentifierName() ->willReturn($query); $qb->select('e') - ->from('Symfony\Bridge\Doctrine\Tests\Fixtures\EmbeddedIdentifierEntity', 'e'); + ->from(EmbeddedIdentifierEntity::class, 'e'); $loader = new ORMQueryBuilderLoader($qb); $loader->getEntitiesByIds('id.value', [1, '', 2, 3, 'foo']); } - public static function provideGuidEntityClasses() + public static function provideGuidEntityClasses(): array { return [ ['Symfony\Bridge\Doctrine\Tests\Fixtures\GuidIdEntity'], @@ -273,32 +262,21 @@ public static function provideGuidEntityClasses() ]; } - public static function provideUidEntityClasses() + public static function provideUidEntityClasses(): array { return [ ['Symfony\Bridge\Doctrine\Tests\Fixtures\UuidIdEntity'], ['Symfony\Bridge\Doctrine\Tests\Fixtures\UlidIdEntity'], ]; } -} - -class QueryMock extends AbstractQuery -{ - public function __construct() - { - } /** - * @return array|string + * @return (LegacyQueryMock&MockObject)|(Query&MockObject) */ - public function getSQL() + private function getQueryMock(): AbstractQuery { - } + $class = ((new \ReflectionClass(Query::class))->isFinal()) ? LegacyQueryMock::class : Query::class; - /** - * @return Result|int - */ - protected function _doExecute() - { + return $this->createMock($class); } } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php b/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php index f211f291f873a..930ee9994879e 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Form/DoctrineOrmTypeGuesserTest.php @@ -13,6 +13,8 @@ use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping\ClassMetadata; +use Doctrine\ORM\Mapping\JoinColumnMapping; +use Doctrine\ORM\Mapping\ManyToOneAssociationMapping; use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ObjectManager; use PHPUnit\Framework\TestCase; @@ -69,33 +71,49 @@ public function testRequiredGuesserSimpleFieldNullable() public function testRequiredGuesserOneToOneNullable() { - $classMetadata = $this->createMock(ClassMetadata::class); - $classMetadata->expects($this->once())->method('isAssociationWithSingleJoinColumn')->with('field')->willReturn(true); + $classMetadata = new ClassMetadata('Acme\Entity\Foo'); - $mapping = ['joinColumns' => [[]]]; - $classMetadata->expects($this->once())->method('getAssociationMapping')->with('field')->willReturn($mapping); + if (class_exists(ManyToOneAssociationMapping::class)) { + $associationMapping = new ManyToOneAssociationMapping('field', 'Acme\Entity\Foo', 'Acme\Entity\Bar'); + $associationMapping->joinColumns[] = new JoinColumnMapping('field', 'field'); + } else { + $associationMapping = ['joinColumns' => [[]]]; + } + $classMetadata->associationMappings['field'] = $associationMapping; $this->assertEquals(new ValueGuess(false, Guess::HIGH_CONFIDENCE), $this->getGuesser($classMetadata)->guessRequired('TestEntity', 'field')); } public function testRequiredGuesserOneToOneExplicitNullable() { - $classMetadata = $this->createMock(ClassMetadata::class); - $classMetadata->expects($this->once())->method('isAssociationWithSingleJoinColumn')->with('field')->willReturn(true); - - $mapping = ['joinColumns' => [['nullable' => true]]]; - $classMetadata->expects($this->once())->method('getAssociationMapping')->with('field')->willReturn($mapping); + $classMetadata = new ClassMetadata('Acme\Entity\Foo'); + + if (class_exists(ManyToOneAssociationMapping::class)) { + $associationMapping = new ManyToOneAssociationMapping('field', 'Acme\Entity\Foo', 'Acme\Entity\Bar'); + $joinColumnMapping = new JoinColumnMapping('field', 'field'); + $joinColumnMapping->nullable = true; + $associationMapping->joinColumns[] = $joinColumnMapping; + } else { + $associationMapping = ['joinColumns' => [['nullable' => true]]]; + } + $classMetadata->associationMappings['field'] = $associationMapping; $this->assertEquals(new ValueGuess(false, Guess::HIGH_CONFIDENCE), $this->getGuesser($classMetadata)->guessRequired('TestEntity', 'field')); } public function testRequiredGuesserOneToOneNotNullable() { - $classMetadata = $this->createMock(ClassMetadata::class); - $classMetadata->expects($this->once())->method('isAssociationWithSingleJoinColumn')->with('field')->willReturn(true); - - $mapping = ['joinColumns' => [['nullable' => false]]]; - $classMetadata->expects($this->once())->method('getAssociationMapping')->with('field')->willReturn($mapping); + $classMetadata = new ClassMetadata('Acme\Entity\Foo'); + + if (class_exists(ManyToOneAssociationMapping::class)) { + $associationMapping = new ManyToOneAssociationMapping('field', 'Acme\Entity\Foo', 'Acme\Entity\Bar'); + $joinColumnMapping = new JoinColumnMapping('field', 'field'); + $joinColumnMapping->nullable = false; + $associationMapping->joinColumns[] = $joinColumnMapping; + } else { + $associationMapping = ['joinColumns' => [['nullable' => false]]]; + } + $classMetadata->associationMappings['field'] = $associationMapping; $this->assertEquals(new ValueGuess(true, Guess::HIGH_CONFIDENCE), $this->getGuesser($classMetadata)->guessRequired('TestEntity', 'field')); } diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php index 40884d2c572c6..e4e67eb663557 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/DoctrineExtractorTest.php @@ -26,9 +26,11 @@ use PHPUnit\Framework\TestCase; use Symfony\Bridge\Doctrine\PropertyInfo\DoctrineExtractor; use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineDummy; +use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineEmbeddable; use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineEnum; use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineGeneratedValue; use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineRelation; +use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineWithEmbedded; use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\EnumInt; use Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\EnumString; use Symfony\Component\PropertyInfo\Type; @@ -38,7 +40,7 @@ */ class DoctrineExtractorTest extends TestCase { - private function createExtractor() + private function createExtractor(): DoctrineExtractor { $config = class_exists(ORMSetup::class) ? ORMSetup::createConfiguration(true) @@ -109,10 +111,6 @@ public function testGetProperties() public function testTestGetPropertiesWithEmbedded() { - if (!class_exists(\Doctrine\ORM\Mapping\Embedded::class)) { - $this->markTestSkipped('@Embedded is not available in Doctrine ORM lower than 2.5.'); - } - $this->assertEquals( [ 'id', @@ -125,25 +123,21 @@ public function testTestGetPropertiesWithEmbedded() /** * @dataProvider typesProvider */ - public function testExtract($property, array $type = null) + public function testExtract(string $property, array $type = null) { $this->assertEquals($type, $this->createExtractor()->getTypes(DoctrineDummy::class, $property, [])); } public function testExtractWithEmbedded() { - if (!class_exists(\Doctrine\ORM\Mapping\Embedded::class)) { - $this->markTestSkipped('@Embedded is not available in Doctrine ORM lower than 2.5.'); - } - $expectedTypes = [new Type( Type::BUILTIN_TYPE_OBJECT, false, - 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineEmbeddable' + DoctrineEmbeddable::class )]; $actualTypes = $this->createExtractor()->getTypes( - 'Symfony\Bridge\Doctrine\Tests\PropertyInfo\Fixtures\DoctrineWithEmbedded', + DoctrineWithEmbedded::class, 'embedded', [] ); @@ -166,9 +160,9 @@ public function testExtractEnum() $this->assertNull($this->createExtractor()->getTypes(DoctrineEnum::class, 'enumCustom', [])); } - public static function typesProvider() + public static function typesProvider(): array { - $provider = [ + return [ ['id', [new Type(Type::BUILTIN_TYPE_INT)]], ['guid', [new Type(Type::BUILTIN_TYPE_STRING)]], ['bigint', [new Type(Type::BUILTIN_TYPE_STRING)]], @@ -251,8 +245,6 @@ public static function typesProvider() )]], ['json', null], ]; - - return $provider; } public function testGetPropertiesCatchException() diff --git a/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php index eb7b00d561173..f3a78dfe9226b 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Security/User/EntityUserProviderTest.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Doctrine\Tests\Security\User; use Doctrine\ORM\EntityManager; +use Doctrine\ORM\EntityRepository; use Doctrine\ORM\Tools\SchemaTool; use Doctrine\Persistence\ManagerRegistry; use Doctrine\Persistence\ObjectManager; @@ -251,12 +252,12 @@ private function createSchema($em) } } -abstract class UserLoaderRepository implements ObjectRepository, UserLoaderInterface +abstract class UserLoaderRepository extends EntityRepository implements UserLoaderInterface { abstract public function loadUserByIdentifier(string $identifier): ?UserInterface; } -abstract class PasswordUpgraderRepository implements ObjectRepository, PasswordUpgraderInterface +abstract class PasswordUpgraderRepository extends EntityRepository implements PasswordUpgraderInterface { abstract public function upgradePassword(PasswordAuthenticatedUserInterface $user, string $newHashedPassword): void; } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php index b04e51eb781e4..66849208fd44b 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/Constraints/UniqueEntityValidatorTest.php @@ -14,6 +14,7 @@ use Doctrine\Common\Collections\ArrayCollection; use Doctrine\DBAL\Types\Type; use Doctrine\ORM\EntityRepository; +use Doctrine\ORM\Mapping\ClassMetadata; use Doctrine\ORM\Mapping\ClassMetadataInfo; use Doctrine\ORM\Tools\SchemaTool; use Doctrine\Persistence\ManagerRegistry; @@ -114,7 +115,9 @@ protected function createEntityManagerMock($repositoryMock) ->willReturn($repositoryMock) ; - $classMetadata = $this->createMock(ClassMetadataInfo::class); + $classMetadata = $this->createMock( + class_exists(ClassMetadataInfo::class) ? ClassMetadataInfo::class : ClassMetadata::class + ); $classMetadata ->expects($this->any()) ->method('hasField') diff --git a/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php b/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php index 731f393c48b1d..9aa8d6ef61230 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Validator/DoctrineLoaderTest.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Doctrine\Tests\Validator; use Doctrine\ORM\Mapping\Column; +use Doctrine\ORM\Mapping\Driver\AnnotationDriver; use PHPUnit\Framework\TestCase; use Symfony\Bridge\Doctrine\Tests\DoctrineTestHelper; use Symfony\Bridge\Doctrine\Tests\Fixtures\BaseUser; @@ -47,9 +48,12 @@ protected function setUp(): void public function testLoadClassMetadata() { - $validator = Validation::createValidatorBuilder() - ->enableAnnotationMapping(true) - ->addDefaultDoctrineAnnotationReader() + $validatorBuilder = Validation::createValidatorBuilder()->enableAnnotationMapping(true); + if (class_exists(AnnotationDriver::class) && method_exists($validatorBuilder, 'addDefaultDoctrineAnnotationReader')) { + $validatorBuilder->addDefaultDoctrineAnnotationReader(); + } + + $validator = $validatorBuilder ->addLoader(new DoctrineLoader(DoctrineTestHelper::createTestEntityManager(), '{^Symfony\\\\Bridge\\\\Doctrine\\\\Tests\\\\Fixtures\\\\DoctrineLoader}')) ->getValidator() ; @@ -157,10 +161,15 @@ public function testExtractEnum() $this->markTestSkipped('The "enumType" requires doctrine/orm 2.11.'); } - $validator = Validation::createValidatorBuilder() + $validatorBuilder = Validation::createValidatorBuilder() ->addMethodMapping('loadValidatorMetadata') - ->enableAnnotationMapping(true) - ->addDefaultDoctrineAnnotationReader() + ->enableAnnotationMapping(true); + + if (class_exists(AnnotationDriver::class) && method_exists($validatorBuilder, 'addDefaultDoctrineAnnotationReader')) { + $validatorBuilder->addDefaultDoctrineAnnotationReader(); + } + + $validator = $validatorBuilder ->addLoader(new DoctrineLoader(DoctrineTestHelper::createTestEntityManager(), '{^Symfony\\\\Bridge\\\\Doctrine\\\\Tests\\\\Fixtures\\\\DoctrineLoader}')) ->getValidator() ; @@ -176,9 +185,13 @@ public function testExtractEnum() public function testFieldMappingsConfiguration() { - $validator = Validation::createValidatorBuilder() - ->enableAnnotationMapping(true) - ->addDefaultDoctrineAnnotationReader() + $validatorBuilder = Validation::createValidatorBuilder()->enableAnnotationMapping(true); + + if (class_exists(AnnotationDriver::class) && method_exists($validatorBuilder, 'addDefaultDoctrineAnnotationReader')) { + $validatorBuilder->addDefaultDoctrineAnnotationReader(); + } + + $validator = $validatorBuilder ->addXmlMappings([__DIR__.'/../Resources/validator/BaseUser.xml']) ->addLoader( new DoctrineLoader( @@ -206,7 +219,7 @@ public function testClassValidator(bool $expected, string $classValidatorRegexp $this->assertSame($expected, $doctrineLoader->loadClassMetadata($classMetadata)); } - public static function regexpProvider() + public static function regexpProvider(): array { return [ [false, null], @@ -218,9 +231,13 @@ public static function regexpProvider() public function testClassNoAutoMapping() { - $validator = Validation::createValidatorBuilder() - ->enableAnnotationMapping(true) - ->addDefaultDoctrineAnnotationReader() + $validatorBuilder = Validation::createValidatorBuilder()->enableAnnotationMapping(true); + + if (class_exists(AnnotationDriver::class) && method_exists($validatorBuilder, 'addDefaultDoctrineAnnotationReader')) { + $validatorBuilder->addDefaultDoctrineAnnotationReader(); + } + + $validator = $validatorBuilder ->addLoader(new DoctrineLoader(DoctrineTestHelper::createTestEntityManager(), '{.*}')) ->getValidator(); diff --git a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php index fe199c2043ff0..9fcb0d3486ada 100644 --- a/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php +++ b/src/Symfony/Bridge/Doctrine/Validator/DoctrineLoader.php @@ -12,7 +12,7 @@ namespace Symfony\Bridge\Doctrine\Validator; use Doctrine\ORM\EntityManagerInterface; -use Doctrine\ORM\Mapping\ClassMetadataInfo; +use Doctrine\ORM\Mapping\ClassMetadata as OrmClassMetadata; use Doctrine\ORM\Mapping\MappingException as OrmMappingException; use Doctrine\Persistence\Mapping\MappingException; use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity; @@ -54,7 +54,7 @@ public function loadClassMetadata(ClassMetadata $metadata): bool return false; } - if (!$doctrineMetadata instanceof ClassMetadataInfo) { + if (!$doctrineMetadata instanceof OrmClassMetadata) { return false; } diff --git a/src/Symfony/Bridge/Doctrine/composer.json b/src/Symfony/Bridge/Doctrine/composer.json index dcb046fbc38e7..61d08a0b213d2 100644 --- a/src/Symfony/Bridge/Doctrine/composer.json +++ b/src/Symfony/Bridge/Doctrine/composer.json @@ -46,8 +46,8 @@ "doctrine/annotations": "^1.10.4|^2", "doctrine/collections": "^1.0|^2.0", "doctrine/data-fixtures": "^1.1", - "doctrine/dbal": "^2.13.1|^3.0", - "doctrine/orm": "^2.7.4", + "doctrine/dbal": "^2.13.1|^3|^4", + "doctrine/orm": "^2.7.4|^3", "psr/log": "^1|^2|^3" }, "conflict": { diff --git a/src/Symfony/Component/Cache/Tests/Fixtures/DriverWrapper.php b/src/Symfony/Component/Cache/Tests/Fixtures/DriverWrapper.php index bb73d8d0cf240..f0d97724a4e3f 100644 --- a/src/Symfony/Component/Cache/Tests/Fixtures/DriverWrapper.php +++ b/src/Symfony/Component/Cache/Tests/Fixtures/DriverWrapper.php @@ -15,6 +15,7 @@ use Doctrine\DBAL\Driver; use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Schema\AbstractSchemaManager; +use Doctrine\DBAL\ServerVersionProvider; class DriverWrapper implements Driver { @@ -31,9 +32,9 @@ public function connect(array $params, $username = null, $password = null, array return $this->driver->connect($params, $username, $password, $driverOptions); } - public function getDatabasePlatform(): AbstractPlatform + public function getDatabasePlatform(ServerVersionProvider $versionProvider = null): AbstractPlatform { - return $this->driver->getDatabasePlatform(); + return $this->driver->getDatabasePlatform($versionProvider); } public function getSchemaManager(Connection $conn, AbstractPlatform $platform): AbstractSchemaManager diff --git a/src/Symfony/Component/Cache/composer.json b/src/Symfony/Component/Cache/composer.json index 91296b0477ba9..e3526bb8158b4 100644 --- a/src/Symfony/Component/Cache/composer.json +++ b/src/Symfony/Component/Cache/composer.json @@ -34,7 +34,7 @@ "require-dev": { "cache/integration-tests": "dev-master", "doctrine/cache": "^1.6|^2.0", - "doctrine/dbal": "^2.13.1|^3.0", + "doctrine/dbal": "^2.13.1|^3|^4", "predis/predis": "^1.1", "psr/simple-cache": "^1.0|^2.0", "symfony/config": "^4.4|^5.0|^6.0", diff --git a/src/Symfony/Component/Lock/Tests/Store/DoctrineDbalStoreTest.php b/src/Symfony/Component/Lock/Tests/Store/DoctrineDbalStoreTest.php index f8abec2522319..9f8c2aac6be3b 100644 --- a/src/Symfony/Component/Lock/Tests/Store/DoctrineDbalStoreTest.php +++ b/src/Symfony/Component/Lock/Tests/Store/DoctrineDbalStoreTest.php @@ -150,13 +150,22 @@ public function testCreatesTableInTransaction(string $platform) $store->save($key); } - public static function providePlatforms() + public static function providePlatforms(): \Generator { yield [\Doctrine\DBAL\Platforms\PostgreSQLPlatform::class]; - yield [\Doctrine\DBAL\Platforms\PostgreSQL94Platform::class]; + + // DBAL < 4 + if (class_exists(\Doctrine\DBAL\Platforms\PostgreSQL94Platform::class)) { + yield [\Doctrine\DBAL\Platforms\PostgreSQL94Platform::class]; + } + yield [\Doctrine\DBAL\Platforms\SqlitePlatform::class]; yield [\Doctrine\DBAL\Platforms\SQLServerPlatform::class]; - yield [\Doctrine\DBAL\Platforms\SQLServer2012Platform::class]; + + // DBAL < 4 + if (class_exists(\Doctrine\DBAL\Platforms\SQLServer2012Platform::class)) { + yield [\Doctrine\DBAL\Platforms\SQLServer2012Platform::class]; + } } public function testTableCreationInTransactionNotSupported() diff --git a/src/Symfony/Component/Lock/composer.json b/src/Symfony/Component/Lock/composer.json index c2b8e3078e756..b7e2d0c0d87ea 100644 --- a/src/Symfony/Component/Lock/composer.json +++ b/src/Symfony/Component/Lock/composer.json @@ -22,7 +22,7 @@ "symfony/polyfill-php80": "^1.16" }, "require-dev": { - "doctrine/dbal": "^2.13|^3.0", + "doctrine/dbal": "^2.13|^3|^4", "predis/predis": "~1.0" }, "conflict": { diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php index 5af44c4845849..d7c9a05c8502e 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/ConnectionTest.php @@ -19,8 +19,10 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Platforms\MariaDBPlatform; use Doctrine\DBAL\Platforms\MySQL57Platform; +use Doctrine\DBAL\Platforms\MySQLPlatform; use Doctrine\DBAL\Platforms\OraclePlatform; use Doctrine\DBAL\Platforms\SQLServer2012Platform; +use Doctrine\DBAL\Platforms\SQLServerPlatform; use Doctrine\DBAL\Query\QueryBuilder; use Doctrine\DBAL\Result; use Doctrine\DBAL\Schema\AbstractSchemaManager; @@ -98,7 +100,7 @@ public function testItThrowsATransportExceptionIfItCannotAcknowledgeMessage() { $this->expectException(TransportException::class); $driverConnection = $this->getDBALConnectionMock(); - $driverConnection->method('delete')->willThrowException(new DBALException()); + $driverConnection->method('delete')->willThrowException($this->createStub(DBALException::class)); $connection = new Connection([], $driverConnection); $connection->ack('dummy_id'); @@ -108,7 +110,7 @@ public function testItThrowsATransportExceptionIfItCannotRejectMessage() { $this->expectException(TransportException::class); $driverConnection = $this->getDBALConnectionMock(); - $driverConnection->method('delete')->willThrowException(new DBALException()); + $driverConnection->method('delete')->willThrowException($this->createStub(DBALException::class)); $connection = new Connection([], $driverConnection); $connection->reject('dummy_id'); @@ -391,7 +393,7 @@ public function testGeneratedSql(AbstractPlatform $platform, string $expectedSql public static function providePlatformSql(): iterable { yield 'MySQL' => [ - new MySQL57Platform(), + class_exists(MySQLPlatform::class) ? new MySQLPlatform() : new MySQL57Platform(), 'SELECT m.* FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?) ORDER BY available_at ASC LIMIT 1 FOR UPDATE', ]; @@ -403,14 +405,23 @@ public static function providePlatformSql(): iterable } yield 'SQL Server' => [ - new SQLServer2012Platform(), + class_exists(SQLServerPlatform::class) && !class_exists(SQLServer2012Platform::class) ? new SQLServerPlatform() : new SQLServer2012Platform(), 'SELECT m.* FROM messenger_messages m WITH (UPDLOCK, ROWLOCK) WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?) ORDER BY available_at ASC OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY ', ]; - yield 'Oracle' => [ - new OraclePlatform(), - 'SELECT w.id AS "id", w.body AS "body", w.headers AS "headers", w.queue_name AS "queue_name", w.created_at AS "created_at", w.available_at AS "available_at", w.delivered_at AS "delivered_at" FROM messenger_messages w WHERE w.id IN (SELECT a.id FROM (SELECT m.id FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?) ORDER BY available_at ASC) a WHERE ROWNUM <= 1) FOR UPDATE', - ]; + if (!class_exists(MySQL57Platform::class)) { + // DBAL >= 4 + yield 'Oracle' => [ + new OraclePlatform(), + 'SELECT w.id AS "id", w.body AS "body", w.headers AS "headers", w.queue_name AS "queue_name", w.created_at AS "created_at", w.available_at AS "available_at", w.delivered_at AS "delivered_at" FROM messenger_messages w WHERE w.id IN (SELECT m.id FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?) ORDER BY available_at ASC FETCH NEXT 1 ROWS ONLY) FOR UPDATE', + ]; + } else { + // DBAL < 4 + yield 'Oracle' => [ + new OraclePlatform(), + 'SELECT w.id AS "id", w.body AS "body", w.headers AS "headers", w.queue_name AS "queue_name", w.created_at AS "created_at", w.available_at AS "available_at", w.delivered_at AS "delivered_at" FROM messenger_messages w WHERE w.id IN (SELECT a.id FROM (SELECT m.id FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?) ORDER BY available_at ASC) a WHERE ROWNUM <= 1) FOR UPDATE', + ]; + } } public function testConfigureSchema() @@ -483,7 +494,7 @@ public function testFindAllSqlGenerated(AbstractPlatform $platform, string $expe public function provideFindAllSqlGeneratedByPlatform(): iterable { yield 'MySQL' => [ - new MySQL57Platform(), + class_exists(MySQLPlatform::class) ? new MySQLPlatform() : new MySQL57Platform(), 'SELECT m.* FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?) LIMIT 50', ]; @@ -495,13 +506,22 @@ public function provideFindAllSqlGeneratedByPlatform(): iterable } yield 'SQL Server' => [ - new SQLServer2012Platform(), + class_exists(SQLServerPlatform::class) && !class_exists(SQLServer2012Platform::class) ? new SQLServerPlatform() : new SQLServer2012Platform(), 'SELECT m.* FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?) ORDER BY (SELECT 0) OFFSET 0 ROWS FETCH NEXT 50 ROWS ONLY', ]; - yield 'Oracle' => [ - new OraclePlatform(), - 'SELECT a.* FROM (SELECT m.id AS "id", m.body AS "body", m.headers AS "headers", m.queue_name AS "queue_name", m.created_at AS "created_at", m.available_at AS "available_at", m.delivered_at AS "delivered_at" FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?)) a WHERE ROWNUM <= 50', - ]; + if (!class_exists(MySQL57Platform::class)) { + // DBAL >= 4 + yield 'Oracle' => [ + new OraclePlatform(), + 'SELECT m.id AS "id", m.body AS "body", m.headers AS "headers", m.queue_name AS "queue_name", m.created_at AS "created_at", m.available_at AS "available_at", m.delivered_at AS "delivered_at" FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?) FETCH NEXT 50 ROWS ONLY', + ]; + } else { + // DBAL < 4 + yield 'Oracle' => [ + new OraclePlatform(), + 'SELECT a.* FROM (SELECT m.id AS "id", m.body AS "body", m.headers AS "headers", m.queue_name AS "queue_name", m.created_at AS "created_at", m.available_at AS "available_at", m.delivered_at AS "delivered_at" FROM messenger_messages m WHERE (m.delivered_at is null OR m.delivered_at < ?) AND (m.available_at <= ?) AND (m.queue_name = ?)) a WHERE ROWNUM <= 50', + ]; + } } } diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineTransportFactoryTest.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineTransportFactoryTest.php index 54dd7ab153adf..6e108baa449be 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineTransportFactoryTest.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Tests/Transport/DoctrineTransportFactoryTest.php @@ -46,7 +46,11 @@ public function testCreateTransport() $schemaConfig = $this->createMock(SchemaConfig::class); $platform = $this->createMock(AbstractPlatform::class); $schemaManager->method('createSchemaConfig')->willReturn($schemaConfig); - $driverConnection->method('getSchemaManager')->willReturn($schemaManager); + $driverConnection->method( + method_exists(\Doctrine\DBAL\Connection::class, 'createSchemaManager') + ? 'createSchemaManager' + : 'getSchemaManager' + )->willReturn($schemaManager); $driverConnection->method('getDatabasePlatform')->willReturn($platform); $registry = $this->createMock(ConnectionRegistry::class); @@ -70,7 +74,11 @@ public function testCreateTransportNotifyWithPostgreSQLPlatform() $schemaConfig = $this->createMock(SchemaConfig::class); $platform = $this->createMock(PostgreSQLPlatform::class); $schemaManager->method('createSchemaConfig')->willReturn($schemaConfig); - $driverConnection->method('getSchemaManager')->willReturn($schemaManager); + $driverConnection->method( + method_exists(\Doctrine\DBAL\Connection::class, 'createSchemaManager') + ? 'createSchemaManager' + : 'getSchemaManager' + )->willReturn($schemaManager); $driverConnection->method('getDatabasePlatform')->willReturn($platform); $registry = $this->createMock(ConnectionRegistry::class); diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php index 6bb601c2eef29..fe1b7a2f4ef91 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/Transport/Connection.php @@ -177,11 +177,8 @@ public function get(): ?array // Append pessimistic write lock to FROM clause if db platform supports it $sql = $query->getSQL(); - if (($fromPart = $query->getQueryPart('from')) && - ($table = $fromPart[0]['table'] ?? null) && - ($alias = $fromPart[0]['alias'] ?? null) - ) { - $fromClause = sprintf('%s %s', $table, $alias); + if (preg_match('/FROM (.+) WHERE/', (string) $sql, $matches)) { + $fromClause = $matches[1]; $sql = str_replace( sprintf('FROM %s WHERE', $fromClause), sprintf('FROM %s WHERE', $this->driverConnection->getDatabasePlatform()->appendLockHint($fromClause, LockMode::PESSIMISTIC_WRITE)), diff --git a/src/Symfony/Component/Messenger/Bridge/Doctrine/composer.json b/src/Symfony/Component/Messenger/Bridge/Doctrine/composer.json index 3a9494a6a24cb..e1490a7f98e2e 100644 --- a/src/Symfony/Component/Messenger/Bridge/Doctrine/composer.json +++ b/src/Symfony/Component/Messenger/Bridge/Doctrine/composer.json @@ -21,7 +21,7 @@ "symfony/service-contracts": "^1.1|^2|^3" }, "require-dev": { - "doctrine/dbal": "^2.13|^3.0", + "doctrine/dbal": "^2.13|^3|^4", "doctrine/persistence": "^1.3|^2|^3", "symfony/property-access": "^4.4|^5.0|^6.0", "symfony/serializer": "^4.4|^5.0|^6.0" From e05c25256eaf65f6996728c28b7f28ae067d7370 Mon Sep 17 00:00:00 2001 From: JoppeDC Date: Wed, 11 Oct 2023 13:43:35 +0200 Subject: [PATCH 022/115] Add missing dutch translations --- .../Resources/translations/validators.nl.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf index 97d1da00e9a50..45cefb3bbd59f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.nl.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. De waarde van de netmask moet zich tussen {{ min }} en {{ max }} bevinden. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + De bestandsnaam is te lang. Het moet {{ filename_max_length }} karakter of minder zijn. + + + The password strength is too low. Please use a stronger password. + De wachtwoordsterkte is te laag. Gebruik alstublieft een sterker wachtwoord. + + + This value contains characters that are not allowed by the current restriction-level. + Deze waarde bevat tekens die niet zijn toegestaan volgens het huidige beperkingsniveau. + + + Using invisible characters is not allowed. + Het gebruik van onzichtbare tekens is niet toegestaan. + + + Mixing numbers from different scripts is not allowed. + Het mengen van cijfers uit verschillende schriften is niet toegestaan. + + + Using hidden overlay characters is not allowed. + Het gebruik van verborgen overlay-tekens is niet toegestaan. + From 1ed99d11f98cb0e3c2a0816622dca226c60ac181 Mon Sep 17 00:00:00 2001 From: Jessica F Martinez Date: Wed, 11 Oct 2023 13:40:17 +0200 Subject: [PATCH 023/115] [Validator] Add missing Spanish (es) translations #51956 --- .../Resources/translations/validators.es.xlf | 38 +++++++++++++++---- 1 file changed, 31 insertions(+), 7 deletions(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf index 897d0a45d74fd..55f21271f1bc9 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.es.xlf @@ -40,7 +40,7 @@ This field is missing. - Este campo está desaparecido. + Este campo falta. This value is not a valid date. @@ -48,7 +48,7 @@ This value is not a valid datetime. - Este valor no es una fecha y hora válidas. + Este valor no es una fecha y hora válida. This value is not a valid email address. @@ -184,11 +184,11 @@ The file was only partially uploaded. - El archivo fue sólo subido parcialmente. + El archivo se cargó solo parcialmente. No file was uploaded. - Ningún archivo fue subido. + No se subió ningún archivo. No temporary folder was configured in php.ini. @@ -200,7 +200,7 @@ A PHP extension caused the upload to fail. - Una extensión de PHP hizo que la subida fallara. + Una extensión de PHP provocó que la carga fallara. This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. @@ -300,7 +300,7 @@ An empty file is not allowed. - No está permitido un archivo vacío. + No se permite un archivo vacío. The host could not be resolved. @@ -360,7 +360,7 @@ This password has been leaked in a data breach, it must not be used. Please use another password. - Esta contraseña no se puede utilizar porque está incluida en un listado de contraseñas públicas obtenido gracias a fallos de seguridad de otros sitios y aplicaciones. Por favor utilice otra contraseña. + Esta contraseña no se puede utilizar porque está incluida en un listado de contraseñas públicas obtenido gracias a fallos de seguridad de otros sitios y aplicaciones. Por favor, utilice otra contraseña. This value should be between {{ min }} and {{ max }}. @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. El valor de la máscara de red debería estar entre {{ min }} y {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + El nombre del archivo es demasido largo. Debe tener {{ filename_max_length }} carácter o menos.|El nombre del archivo es demasido largo. Debe tener {{ filename_max_length }} caracteres o menos. + + + The password strength is too low. Please use a stronger password. + La seguridad de la contraseña es demasiado baja. Por favor, utilice una contraseña más segura. + + + This value contains characters that are not allowed by the current restriction-level. + Este valor contiene caracteres que no están permitidos según el nivel de restricción actual. + + + Using invisible characters is not allowed. + No se permite el uso de caracteres invisibles. + + + Mixing numbers from different scripts is not allowed. + No está permitido mezclar números de diferentes scripts. + + + Using hidden overlay characters is not allowed. + No está permitido el uso de caracteres superpuestos ocultos. + From 42d70af349e92ced6aa26e165a4f077084bf95ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Anamarija=20Papi=C4=87?= Date: Wed, 11 Oct 2023 21:09:11 +0200 Subject: [PATCH 024/115] Add missing Validator translations - Croatian (hr) --- .../Resources/translations/validators.hr.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf index 34384b401551f..0b57fc98ef56b 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.hr.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Vrijednost mrežne maske trebala bi biti između {{ min }} i {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Naziv datoteke je predug. Treba imati {{ filename_max_length }} znak ili manje.|Naziv datoteke je predug. Treba imati {{ filename_max_length }} znaka ili manje.|Naziv datoteke je predug. Treba imati {{ filename_max_length }} znakova ili manje. + + + The password strength is too low. Please use a stronger password. + Jačina lozinke je preniska. Molim koristite jaču lozinku. + + + This value contains characters that are not allowed by the current restriction-level. + Ova vrijednost sadrži znakove koji nisu dopušteni prema trenutnoj razini ograničenja. + + + Using invisible characters is not allowed. + Korištenje nevidljivih znakova nije dopušteno. + + + Mixing numbers from different scripts is not allowed. + Miješanje brojeva iz različitih pisama nije dopušteno. + + + Using hidden overlay characters is not allowed. + Korištenje skrivenih preklapajućih znakova nije dopušteno. + From 7af728985ece80600083c9ed815f0206fd1ad3aa Mon Sep 17 00:00:00 2001 From: BiaDd <49127629+BiaDd@users.noreply.github.com> Date: Wed, 11 Oct 2023 21:25:23 -0400 Subject: [PATCH 025/115] [Validator] Add missing translations for Vietnamese (VI) Update validators.vi.xlf --- .../Resources/translations/validators.vi.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf index 00201792253ab..4de9de6fb8c81 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.vi.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Giá trị của mặt nạ mạng phải nằm trong khoảng từ {{ min }} đến {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Tên tệp quá dài. Phải bằng {{ filename_max_length }} ký tự hoặc ít hơn.|Tên tệp quá dài. Phải bằng {{ filename_max_length }} ký tự hoặc ít hơn. + + + The password strength is too low. Please use a stronger password. + Sức mạnh mật khẩu quá thấp. Vui lòng sử dụng mật khẩu mạnh hơn. + + + This value contains characters that are not allowed by the current restriction-level. + Giá trị này chứa các ký tự không được phép bởi mức độ hạn chế hiện tại. + + + Using invisible characters is not allowed. + Sử dụng ký tự vô hình không được phép. + + + Mixing numbers from different scripts is not allowed. + Không được phép trộn các số từ các tập lệnh khác nhau. + + + Using hidden overlay characters is not allowed. + Sử dụng các ký tự lớp phủ ẩn không được phép. + From 7d4fb1cb06d40323a5b7c005bdff3b5f788a1b3f Mon Sep 17 00:00:00 2001 From: Asis Pattisahusiwa <79239132+asispts@users.noreply.github.com> Date: Thu, 12 Oct 2023 08:37:04 +0700 Subject: [PATCH 026/115] [Validator] Add missing translations for Indonesian (id) --- .../Resources/translations/validators.id.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf index 1687f330bc570..29960b3da34e5 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.id.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Nilai dari netmask harus berada diantara {{ min }} dan {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Nama file terlalu panjang. Harusnya {{ filename_max_length }} karakter atau kurang. + + + The password strength is too low. Please use a stronger password. + Kata sandi terlalu lemah. Harap gunakan kata sandi yang lebih kuat. + + + This value contains characters that are not allowed by the current restriction-level. + Nilai ini mengandung karakter yang tidak diizinkan oleh tingkat pembatasan saat ini. + + + Using invisible characters is not allowed. + Penggunaan karakter tak terlihat tidak diperbolehkan. + + + Mixing numbers from different scripts is not allowed. + Menggabungkan angka-angka dari skrip yang berbeda tidak diperbolehkan. + + + Using hidden overlay characters is not allowed. + Penggunaan karakter overlay yang tersembunyi tidak diperbolehkan. + From 9ec85bb68f8e705a887f4535b62b3d10b65eebdc Mon Sep 17 00:00:00 2001 From: Viktoriia Zolotova Date: Wed, 11 Oct 2023 19:05:47 -0700 Subject: [PATCH 027/115] [Validator] Add missing Ukrainian translations #51960 --- .../Resources/translations/validators.uk.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf index c11f851fb0267..d12b4db8c9459 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.uk.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Значення в мережевій масці має бути між {{ min }} та {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Назва файлу занадто довга. Вона має містити {{ filename_max_length }} символів або менше.|Назва файлу занадто довга. Вона має містити {{ filename_max_length }} символів або менше. + + + The password strength is too low. Please use a stronger password. + Надійність пароля занадто низька. Будь ласка, створіть складніший пароль. + + + This value contains characters that are not allowed by the current restriction-level. + Це значення містить символи, які не дозволяються поточним рівнем обмежень. + + + Using invisible characters is not allowed. + Використання невидимих ​​символів не допускається. + + + Mixing numbers from different scripts is not allowed. + Змішувати числа з різних скриптів не допускається. + + + Using hidden overlay characters is not allowed. + Використання прихованих накладених символів не допускається. + From 315a8a462cb057287c13e69b25596477eb7e4582 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Deruss=C3=A9?= Date: Thu, 12 Oct 2023 10:12:39 +0200 Subject: [PATCH 028/115] Revert "Add keyword `dev` to leverage composer hint" This reverts commit 49f7f5e71911b3d6540f744cf4475f571cf012a6. --- src/Symfony/Bridge/PhpUnit/composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bridge/PhpUnit/composer.json b/src/Symfony/Bridge/PhpUnit/composer.json index 167ed8767b35b..9627d2b40c12c 100644 --- a/src/Symfony/Bridge/PhpUnit/composer.json +++ b/src/Symfony/Bridge/PhpUnit/composer.json @@ -2,7 +2,7 @@ "name": "symfony/phpunit-bridge", "type": "symfony-bridge", "description": "Provides utilities for PHPUnit, especially user deprecation notices management", - "keywords": ["dev"], + "keywords": [], "homepage": "https://symfony.com", "license": "MIT", "authors": [ From 929390669e360a25fe176088d5477d993fdab350 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dariusz=20Rumi=C5=84ski?= Date: Thu, 12 Oct 2023 14:38:41 +0200 Subject: [PATCH 029/115] DX: PHP CS Fixer - drop explicit nullable_type_declaration_for_default_null_value config, as it's part of ruleset anyway --- .php-cs-fixer.dist.php | 1 - 1 file changed, 1 deletion(-) diff --git a/.php-cs-fixer.dist.php b/.php-cs-fixer.dist.php index 311ef1270f734..8333789ec831b 100644 --- a/.php-cs-fixer.dist.php +++ b/.php-cs-fixer.dist.php @@ -30,7 +30,6 @@ '@Symfony:risky' => true, 'protected_to_private' => false, 'native_constant_invocation' => ['strict' => false], - 'nullable_type_declaration_for_default_null_value' => ['use_nullable_type_declaration' => false], 'header_comment' => ['header' => $fileHeaderComment], ]) ->setRiskyAllowed(true) From b7d25e85cf4758e9daf16fd020f43e46db879463 Mon Sep 17 00:00:00 2001 From: Mathieu Lechat Date: Thu, 12 Oct 2023 10:00:56 +0200 Subject: [PATCH 030/115] [FrameworkBundle] Configure `logger` as error logger if the Monolog Bundle is not registered --- .../Compiler/ErrorLoggerCompilerPass.php | 37 +++++++++++++++++++ .../FrameworkBundle/FrameworkBundle.php | 3 ++ .../Resources/config/debug_prod.php | 4 +- .../FrameworkExtensionTestCase.php | 6 +-- 4 files changed, 45 insertions(+), 5 deletions(-) create mode 100644 src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php new file mode 100644 index 0000000000000..9ce67bc10cc65 --- /dev/null +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php @@ -0,0 +1,37 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler; + +use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface; +use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Reference; + +/** + * @internal + */ +class ErrorLoggerCompilerPass implements CompilerPassInterface +{ + public function process(ContainerBuilder $container) + { + if (!$container->hasDefinition('debug.debug_handlers_listener')) { + return; + } + + $definition = $container->getDefinition('debug.debug_handlers_listener'); + if ($container->hasDefinition('monolog.logger.php')) { + $definition->replaceArgument(1, new Reference('monolog.logger.php')); + } + if ($container->hasDefinition('monolog.logger.deprecation')) { + $definition->replaceArgument(6, new Reference('monolog.logger.deprecation')); + } + } +} diff --git a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php index 4ec54eccf555d..2197610896eb5 100644 --- a/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php +++ b/src/Symfony/Bundle/FrameworkBundle/FrameworkBundle.php @@ -17,6 +17,7 @@ use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\AssetsContextPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ContainerBuilderDebugDumpPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\DataCollectorTranslatorPass; +use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ErrorLoggerCompilerPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\LoggingTranslatorPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\ProfilerPass; use Symfony\Bundle\FrameworkBundle\DependencyInjection\Compiler\RemoveUnusedSessionMarshallingHandlerPass; @@ -160,6 +161,8 @@ public function build(ContainerBuilder $container) $container->addCompilerPass(new RegisterReverseContainerPass(false), PassConfig::TYPE_AFTER_REMOVING); $container->addCompilerPass(new RemoveUnusedSessionMarshallingHandlerPass()); $container->addCompilerPass(new SessionPass()); + // must be registered after MonologBundle's LoggerChannelPass + $container->addCompilerPass(new ErrorLoggerCompilerPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, -32); if ($container->getParameter('kernel.debug')) { $container->addCompilerPass(new AddDebugLogProcessorPass(), PassConfig::TYPE_BEFORE_OPTIMIZATION, 2); diff --git a/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug_prod.php b/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug_prod.php index f381b018f0629..f3a16eb25f663 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug_prod.php +++ b/src/Symfony/Bundle/FrameworkBundle/Resources/config/debug_prod.php @@ -21,12 +21,12 @@ ->set('debug.debug_handlers_listener', DebugHandlersListener::class) ->args([ null, // Exception handler - service('monolog.logger.php')->nullOnInvalid(), + service('logger')->nullOnInvalid(), null, // Log levels map for enabled error levels param('debug.error_handler.throw_at'), param('kernel.debug'), param('kernel.debug'), - service('monolog.logger.deprecation')->nullOnInvalid(), + service('logger')->nullOnInvalid(), ]) ->tag('kernel.event_subscriber') ->tag('monolog.logger', ['channel' => 'php']) diff --git a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php index f5429d617b1a7..52a6ad6a4840f 100644 --- a/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php +++ b/src/Symfony/Bundle/FrameworkBundle/Tests/DependencyInjection/FrameworkExtensionTestCase.php @@ -507,7 +507,7 @@ public function testEnabledPhpErrorsConfig() $container = $this->createContainerFromFile('php_errors_enabled'); $definition = $container->getDefinition('debug.debug_handlers_listener'); - $this->assertEquals(new Reference('monolog.logger.php', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1)); + $this->assertEquals(new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1)); $this->assertNull($definition->getArgument(2)); $this->assertSame(-1, $container->getParameter('debug.error_handler.throw_at')); } @@ -527,7 +527,7 @@ public function testPhpErrorsWithLogLevel() $container = $this->createContainerFromFile('php_errors_log_level'); $definition = $container->getDefinition('debug.debug_handlers_listener'); - $this->assertEquals(new Reference('monolog.logger.php', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1)); + $this->assertEquals(new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1)); $this->assertSame(8, $definition->getArgument(2)); } @@ -536,7 +536,7 @@ public function testPhpErrorsWithLogLevels() $container = $this->createContainerFromFile('php_errors_log_levels'); $definition = $container->getDefinition('debug.debug_handlers_listener'); - $this->assertEquals(new Reference('monolog.logger.php', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1)); + $this->assertEquals(new Reference('logger', ContainerInterface::NULL_ON_INVALID_REFERENCE), $definition->getArgument(1)); $this->assertSame([ \E_NOTICE => \Psr\Log\LogLevel::ERROR, \E_WARNING => \Psr\Log\LogLevel::ERROR, From e7d45da727dfb6afb604716104e6e68b11587021 Mon Sep 17 00:00:00 2001 From: Nicolas Grekas Date: Thu, 12 Oct 2023 17:13:29 +0200 Subject: [PATCH 031/115] [FrameworkBundle] Add void return-type to ErrorLoggerCompilerPass --- .../DependencyInjection/Compiler/ErrorLoggerCompilerPass.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php index 9ce67bc10cc65..15ff70aa650e7 100644 --- a/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php +++ b/src/Symfony/Bundle/FrameworkBundle/DependencyInjection/Compiler/ErrorLoggerCompilerPass.php @@ -20,7 +20,7 @@ */ class ErrorLoggerCompilerPass implements CompilerPassInterface { - public function process(ContainerBuilder $container) + public function process(ContainerBuilder $container): void { if (!$container->hasDefinition('debug.debug_handlers_listener')) { return; From 5937e425667079883d15b8e82f21d2092881187b Mon Sep 17 00:00:00 2001 From: Peter Kokot Date: Thu, 12 Oct 2023 21:32:10 +0200 Subject: [PATCH 032/115] [Validator] Update Slovenian translations (sl) --- .../Resources/translations/validators.sl.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf index b956911e5a0dc..462a7752febe5 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.sl.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Vrednost omrežne maske mora biti med {{ min }} in {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Ime datoteke je predolgo. Imeti mora {{ filename_max_length }} znak ali manj.|Ime datoteke je predolgo. Imeti mora {{ filename_max_length }} znaka ali manj.|Ime datoteke je predolgo. Imeti mora {{ filename_max_length }} znake ali manj.|Ime datoteke je predolgo. Imeti mora {{ filename_max_length }} znakov ali manj. + + + The password strength is too low. Please use a stronger password. + Moč gesla je prenizka. Uporabite močnejše geslo. + + + This value contains characters that are not allowed by the current restriction-level. + Ta vrednost vsebuje znake, ki jih trenutna raven omejitve ne dovoljuje. + + + Using invisible characters is not allowed. + Uporaba nevidnih znakov ni dovoljena. + + + Mixing numbers from different scripts is not allowed. + Mešanje številk iz različnih skript ni dovoljeno. + + + Using hidden overlay characters is not allowed. + Uporaba skritih prekrivnih znakov ni dovoljena. + From 50c0fbc79b4e86d1a500b27d4d519f0ec3b33cae Mon Sep 17 00:00:00 2001 From: "Alexander M. Turek" Date: Fri, 13 Oct 2023 10:59:07 +0200 Subject: [PATCH 033/115] Fix DBAL 4 compatibility --- .../Doctrine/Form/DoctrineOrmTypeGuesser.php | 2 +- .../DoctrinePingConnectionMiddleware.php | 16 +- .../Doctrine/Middleware/Debug/Connection.php | 135 ++++---------- .../Middleware/Debug/DBAL3/Connection.php | 174 ++++++++++++++++++ .../Middleware/Debug/DBAL3/Statement.php | 86 +++++++++ .../Doctrine/Middleware/Debug/Driver.php | 16 +- .../Doctrine/Middleware/Debug/Query.php | 16 +- .../Doctrine/Middleware/Debug/Statement.php | 51 ++--- .../PropertyInfo/DoctrineExtractor.php | 10 +- ...octrineDataCollectorWithDebugStackTest.php | 7 + .../Tests/Fixtures/SingleIntIdEntity.php | 5 +- .../Tests/Fixtures/Type/StringWrapperType.php | 8 +- .../Doctrine/Tests/Logger/DbalLoggerTest.php | 8 + .../DoctrinePingConnectionMiddlewareTest.php | 40 ++-- .../Tests/Middleware/Debug/MiddlewareTest.php | 10 +- .../PropertyInfo/Fixtures/DoctrineFooType.php | 8 +- ...rTransportDoctrineSchemaSubscriberTest.php | 8 + .../Doctrine/Tests/Types/UlidTypeTest.php | 23 ++- .../Bridge/Doctrine/Types/AbstractUidType.php | 40 +++- 19 files changed, 466 insertions(+), 197 deletions(-) create mode 100644 src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Connection.php create mode 100644 src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Statement.php diff --git a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php index 231b50640f040..6386318ef97d9 100644 --- a/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php +++ b/src/Symfony/Bridge/Doctrine/Form/DoctrineOrmTypeGuesser.php @@ -52,7 +52,7 @@ public function guessType(string $class, string $property) } switch ($metadata->getTypeOfField($property)) { - case Types::ARRAY: + case 'array': // DBAL < 4 case Types::SIMPLE_ARRAY: return new TypeGuess('Symfony\Component\Form\Extension\Core\Type\CollectionType', [], Guess::MEDIUM_CONFIDENCE); case Types::BOOLEAN: diff --git a/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php b/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php index de925284d09dc..5f8d9496348c8 100644 --- a/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php +++ b/src/Symfony/Bridge/Doctrine/Messenger/DoctrinePingConnectionMiddleware.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Doctrine\Messenger; +use Doctrine\DBAL\Connection; use Doctrine\DBAL\Exception as DBALException; use Doctrine\ORM\EntityManagerInterface; use Symfony\Component\Messenger\Envelope; @@ -33,19 +34,28 @@ protected function handleForManager(EntityManagerInterface $entityManager, Envel return $stack->next()->handle($envelope, $stack); } - private function pingConnection(EntityManagerInterface $entityManager) + private function pingConnection(EntityManagerInterface $entityManager): void { $connection = $entityManager->getConnection(); try { - $connection->executeQuery($connection->getDatabasePlatform()->getDummySelectSQL()); + $this->executeDummySql($connection); } catch (DBALException $e) { $connection->close(); - $connection->connect(); + // Attempt to reestablish the lazy connection by sending another query. + $this->executeDummySql($connection); } if (!$entityManager->isOpen()) { $this->managerRegistry->resetManager($this->entityManagerName); } } + + /** + * @throws DBALException + */ + private function executeDummySql(Connection $connection): void + { + $connection->executeQuery($connection->getDatabasePlatform()->getDummySelectSQL()); + } } diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Connection.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Connection.php index e768407bdd137..a0d642dd7d250 100644 --- a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Connection.php +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Connection.php @@ -14,31 +14,26 @@ use Doctrine\DBAL\Driver\Connection as ConnectionInterface; use Doctrine\DBAL\Driver\Middleware\AbstractConnectionMiddleware; use Doctrine\DBAL\Driver\Result; -use Doctrine\DBAL\Driver\Statement as DriverStatement; use Symfony\Component\Stopwatch\Stopwatch; /** * @author Laurent VOULLEMIER + * @author Alexander M. Turek * * @internal */ final class Connection extends AbstractConnectionMiddleware { - private $nestingLevel = 0; - private $debugDataHolder; - private $stopwatch; - private $connectionName; - - public function __construct(ConnectionInterface $connection, DebugDataHolder $debugDataHolder, ?Stopwatch $stopwatch, string $connectionName) - { + public function __construct( + ConnectionInterface $connection, + private DebugDataHolder $debugDataHolder, + private ?Stopwatch $stopwatch, + private string $connectionName, + ) { parent::__construct($connection); - - $this->debugDataHolder = $debugDataHolder; - $this->stopwatch = $stopwatch; - $this->connectionName = $connectionName; } - public function prepare(string $sql): DriverStatement + public function prepare(string $sql): Statement { return new Statement( parent::prepare($sql), @@ -53,135 +48,79 @@ public function query(string $sql): Result { $this->debugDataHolder->addQuery($this->connectionName, $query = new Query($sql)); - if (null !== $this->stopwatch) { - $this->stopwatch->start('doctrine', 'doctrine'); - } - + $this->stopwatch?->start('doctrine', 'doctrine'); $query->start(); try { - $result = parent::query($sql); + return parent::query($sql); } finally { $query->stop(); - - if (null !== $this->stopwatch) { - $this->stopwatch->stop('doctrine'); - } + $this->stopwatch?->stop('doctrine'); } - - return $result; } public function exec(string $sql): int { $this->debugDataHolder->addQuery($this->connectionName, $query = new Query($sql)); - if (null !== $this->stopwatch) { - $this->stopwatch->start('doctrine', 'doctrine'); - } - + $this->stopwatch?->start('doctrine', 'doctrine'); $query->start(); try { $affectedRows = parent::exec($sql); } finally { $query->stop(); - - if (null !== $this->stopwatch) { - $this->stopwatch->stop('doctrine'); - } + $this->stopwatch?->stop('doctrine'); } return $affectedRows; } - public function beginTransaction(): bool + public function beginTransaction(): void { - $query = null; - if (1 === ++$this->nestingLevel) { - $this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"START TRANSACTION"')); - } - - if (null !== $this->stopwatch) { - $this->stopwatch->start('doctrine', 'doctrine'); - } + $query = new Query('"START TRANSACTION"'); + $this->debugDataHolder->addQuery($this->connectionName, $query); - if (null !== $query) { - $query->start(); - } + $this->stopwatch?->start('doctrine', 'doctrine'); + $query->start(); try { - $ret = parent::beginTransaction(); + parent::beginTransaction(); } finally { - if (null !== $query) { - $query->stop(); - } - - if (null !== $this->stopwatch) { - $this->stopwatch->stop('doctrine'); - } + $query->stop(); + $this->stopwatch?->stop('doctrine'); } - - return $ret; } - public function commit(): bool + public function commit(): void { - $query = null; - if (1 === $this->nestingLevel--) { - $this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"COMMIT"')); - } + $query = new Query('"COMMIT"'); + $this->debugDataHolder->addQuery($this->connectionName, $query); - if (null !== $this->stopwatch) { - $this->stopwatch->start('doctrine', 'doctrine'); - } - - if (null !== $query) { - $query->start(); - } + $this->stopwatch?->start('doctrine', 'doctrine'); + $query->start(); try { - $ret = parent::commit(); + parent::commit(); } finally { - if (null !== $query) { - $query->stop(); - } - - if (null !== $this->stopwatch) { - $this->stopwatch->stop('doctrine'); - } + $query->stop(); + $this->stopwatch?->stop('doctrine'); } - - return $ret; } - public function rollBack(): bool + public function rollBack(): void { - $query = null; - if (1 === $this->nestingLevel--) { - $this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"ROLLBACK"')); - } - - if (null !== $this->stopwatch) { - $this->stopwatch->start('doctrine', 'doctrine'); - } + $query = new Query('"ROLLBACK"'); + $this->debugDataHolder->addQuery($this->connectionName, $query); - if (null !== $query) { - $query->start(); - } + $this->stopwatch?->start('doctrine', 'doctrine'); + $query->start(); try { - $ret = parent::rollBack(); + parent::rollBack(); } finally { - if (null !== $query) { - $query->stop(); - } - - if (null !== $this->stopwatch) { - $this->stopwatch->stop('doctrine'); - } + $query->stop(); + $this->stopwatch?->stop('doctrine'); } - - return $ret; } } diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Connection.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Connection.php new file mode 100644 index 0000000000000..1bcb6c22e0c3d --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Connection.php @@ -0,0 +1,174 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Middleware\Debug\DBAL3; + +use Doctrine\DBAL\Driver\Connection as ConnectionInterface; +use Doctrine\DBAL\Driver\Middleware\AbstractConnectionMiddleware; +use Doctrine\DBAL\Driver\Result; +use Doctrine\DBAL\Driver\Statement as StatementInterface; +use Symfony\Bridge\Doctrine\Middleware\Debug\DebugDataHolder; +use Symfony\Bridge\Doctrine\Middleware\Debug\Query; +use Symfony\Component\Stopwatch\Stopwatch; + +/** + * @author Laurent VOULLEMIER + * + * @internal + */ +final class Connection extends AbstractConnectionMiddleware +{ + /** @var int */ + private $nestingLevel = 0; + private $debugDataHolder; + private $stopwatch; + private $connectionName; + + public function __construct( + ConnectionInterface $connection, + DebugDataHolder $debugDataHolder, + ?Stopwatch $stopwatch, + string $connectionName + ) { + $this->connectionName = $connectionName; + $this->stopwatch = $stopwatch; + $this->debugDataHolder = $debugDataHolder; + + parent::__construct($connection); + } + + public function prepare(string $sql): StatementInterface + { + return new Statement( + parent::prepare($sql), + $this->debugDataHolder, + $this->connectionName, + $sql, + $this->stopwatch, + ); + } + + public function query(string $sql): Result + { + $this->debugDataHolder->addQuery($this->connectionName, $query = new Query($sql)); + + if ($this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + $query->start(); + + try { + return parent::query($sql); + } finally { + $query->stop(); + if ($this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + } + + public function exec(string $sql): int + { + $this->debugDataHolder->addQuery($this->connectionName, $query = new Query($sql)); + + if ($this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + $query->start(); + + try { + return parent::exec($sql); + } finally { + $query->stop(); + if ($this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + } + + public function beginTransaction(): bool + { + $query = null; + if (1 === ++$this->nestingLevel) { + $this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"START TRANSACTION"')); + } + + if ($this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + if ($query) { + $query->start(); + } + + try { + return parent::beginTransaction(); + } finally { + if ($query) { + $query->stop(); + } + if ($this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + } + + public function commit(): bool + { + $query = null; + if (1 === $this->nestingLevel--) { + $this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"COMMIT"')); + } + + if ($this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + if ($query) { + $query->start(); + } + + try { + return parent::commit(); + } finally { + if ($query) { + $query->stop(); + } + if ($this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + } + + public function rollBack(): bool + { + $query = null; + if (1 === $this->nestingLevel--) { + $this->debugDataHolder->addQuery($this->connectionName, $query = new Query('"ROLLBACK"')); + } + + if ($this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + if ($query) { + $query->start(); + } + + try { + return parent::rollBack(); + } finally { + if ($query) { + $query->stop(); + } + if ($this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + } +} diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Statement.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Statement.php new file mode 100644 index 0000000000000..16217c2f46a51 --- /dev/null +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/DBAL3/Statement.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Bridge\Doctrine\Middleware\Debug\DBAL3; + +use Doctrine\DBAL\Driver\Middleware\AbstractStatementMiddleware; +use Doctrine\DBAL\Driver\Result as ResultInterface; +use Doctrine\DBAL\Driver\Statement as StatementInterface; +use Doctrine\DBAL\ParameterType; +use Symfony\Bridge\Doctrine\Middleware\Debug\DebugDataHolder; +use Symfony\Bridge\Doctrine\Middleware\Debug\Query; +use Symfony\Component\Stopwatch\Stopwatch; + +/** + * @author Laurent VOULLEMIER + * + * @internal + */ +final class Statement extends AbstractStatementMiddleware +{ + private $query; + private $debugDataHolder; + private $connectionName; + private $stopwatch; + + public function __construct( + StatementInterface $statement, + DebugDataHolder $debugDataHolder, + string $connectionName, + string $sql, + Stopwatch $stopwatch = null + ) { + $this->stopwatch = $stopwatch; + $this->connectionName = $connectionName; + $this->debugDataHolder = $debugDataHolder; + $this->query = new Query($sql); + + parent::__construct($statement); + } + + public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null): bool + { + $this->query->setParam($param, $variable, $type); + + return parent::bindParam($param, $variable, $type, ...\array_slice(\func_get_args(), 3)); + } + + public function bindValue($param, $value, $type = ParameterType::STRING): bool + { + $this->query->setValue($param, $value, $type); + + return parent::bindValue($param, $value, $type); + } + + public function execute($params = null): ResultInterface + { + if (null !== $params) { + $this->query->setValues($params); + } + + // clone to prevent variables by reference to change + $this->debugDataHolder->addQuery($this->connectionName, $query = clone $this->query); + + if ($this->stopwatch) { + $this->stopwatch->start('doctrine', 'doctrine'); + } + $query->start(); + + try { + return parent::execute($params); + } finally { + $query->stop(); + if ($this->stopwatch) { + $this->stopwatch->stop('doctrine'); + } + } + } +} diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Driver.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Driver.php index 7f7fdd3bf0d8d..090b1643f6ad6 100644 --- a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Driver.php +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Driver.php @@ -12,6 +12,7 @@ namespace Symfony\Bridge\Doctrine\Middleware\Debug; use Doctrine\DBAL\Driver as DriverInterface; +use Doctrine\DBAL\Driver\Connection as ConnectionInterface; use Doctrine\DBAL\Driver\Middleware\AbstractDriverMiddleware; use Symfony\Component\Stopwatch\Stopwatch; @@ -35,10 +36,21 @@ public function __construct(DriverInterface $driver, DebugDataHolder $debugDataH $this->connectionName = $connectionName; } - public function connect(array $params): Connection + public function connect(array $params): ConnectionInterface { + $connection = parent::connect($params); + + if ('void' !== (string) (new \ReflectionMethod(DriverInterface\Connection::class, 'commit'))->getReturnType()) { + return new DBAL3\Connection( + $connection, + $this->debugDataHolder, + $this->stopwatch, + $this->connectionName + ); + } + return new Connection( - parent::connect($params), + $connection, $this->debugDataHolder, $this->stopwatch, $this->connectionName diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Query.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Query.php index eb835caa41b25..6ab402e1b7779 100644 --- a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Query.php +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Query.php @@ -46,10 +46,11 @@ public function stop(): void } /** - * @param string|int $param - * @param mixed $variable + * @param string|int $param + * @param mixed $variable + * @param int|ParameterType $type */ - public function setParam($param, &$variable, int $type): void + public function setParam($param, &$variable, $type): void { // Numeric indexes start at 0 in profiler $idx = \is_int($param) ? $param - 1 : $param; @@ -59,10 +60,11 @@ public function setParam($param, &$variable, int $type): void } /** - * @param string|int $param - * @param mixed $value + * @param string|int $param + * @param mixed $value + * @param int|ParameterType $type */ - public function setValue($param, $value, int $type): void + public function setValue($param, $value, $type): void { // Numeric indexes start at 0 in profiler $idx = \is_int($param) ? $param - 1 : $param; @@ -95,7 +97,7 @@ public function getParams(): array } /** - * @return array + * @return array */ public function getTypes(): array { diff --git a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php index a40cdaa9695ba..3f4ba10fc2138 100644 --- a/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php +++ b/src/Symfony/Bridge/Doctrine/Middleware/Debug/Statement.php @@ -19,65 +19,46 @@ /** * @author Laurent VOULLEMIER + * @author Alexander M. Turek * * @internal */ final class Statement extends AbstractStatementMiddleware { - private $debugDataHolder; - private $connectionName; - private $query; - private $stopwatch; - - public function __construct(StatementInterface $statement, DebugDataHolder $debugDataHolder, string $connectionName, string $sql, Stopwatch $stopwatch = null) - { + private Query $query; + + public function __construct( + StatementInterface $statement, + private DebugDataHolder $debugDataHolder, + private string $connectionName, + string $sql, + private ?Stopwatch $stopwatch = null, + ) { parent::__construct($statement); - $this->debugDataHolder = $debugDataHolder; - $this->connectionName = $connectionName; $this->query = new Query($sql); - $this->stopwatch = $stopwatch; - } - - public function bindParam($param, &$variable, $type = ParameterType::STRING, $length = null): bool - { - $this->query->setParam($param, $variable, $type); - - return parent::bindParam($param, $variable, $type, ...\array_slice(\func_get_args(), 3)); } - public function bindValue($param, $value, $type = ParameterType::STRING): bool + public function bindValue(int|string $param, mixed $value, ParameterType $type): void { $this->query->setValue($param, $value, $type); - return parent::bindValue($param, $value, $type); + parent::bindValue($param, $value, $type); } - public function execute($params = null): ResultInterface + public function execute(): ResultInterface { - if (null !== $params) { - $this->query->setValues($params); - } - // clone to prevent variables by reference to change $this->debugDataHolder->addQuery($this->connectionName, $query = clone $this->query); - if ($this->stopwatch) { - $this->stopwatch->start('doctrine', 'doctrine'); - } - + $this->stopwatch?->start('doctrine', 'doctrine'); $query->start(); try { - $result = parent::execute($params); + return parent::execute(); } finally { $query->stop(); - - if ($this->stopwatch) { - $this->stopwatch->stop('doctrine'); - } + $this->stopwatch?->stop('doctrine'); } - - return $result; } } diff --git a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php index ccd53c1ebe7c6..f33a62cb6257c 100644 --- a/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php +++ b/src/Symfony/Bridge/Doctrine/PropertyInfo/DoctrineExtractor.php @@ -167,8 +167,8 @@ public function getTypes(string $class, string $property, array $context = []) break; case Type::BUILTIN_TYPE_ARRAY: switch ($typeOfField) { - case Types::ARRAY: - case 'json_array': + case 'array': // DBAL < 4 + case 'json_array': // DBAL < 3 // return null if $enumType is set, because we can't determine if collectionKeyType is string or int if ($enumType) { return null; @@ -281,7 +281,7 @@ private function getPhpType(string $doctrineType): ?string case Types::BINARY: return Type::BUILTIN_TYPE_RESOURCE; - case Types::OBJECT: + case 'object': // DBAL < 4 case Types::DATE_MUTABLE: case Types::DATETIME_MUTABLE: case Types::DATETIMETZ_MUTABLE: @@ -294,9 +294,9 @@ private function getPhpType(string $doctrineType): ?string case Types::DATEINTERVAL: return Type::BUILTIN_TYPE_OBJECT; - case Types::ARRAY: + case 'array': // DBAL < 4 case Types::SIMPLE_ARRAY: - case 'json_array': + case 'json_array': // DBAL < 3 return Type::BUILTIN_TYPE_ARRAY; } diff --git a/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorWithDebugStackTest.php b/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorWithDebugStackTest.php index 64bee1203b781..690c5aa6f9b8d 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorWithDebugStackTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/DataCollector/DoctrineDataCollectorWithDebugStackTest.php @@ -32,6 +32,13 @@ class DoctrineDataCollectorWithDebugStackTest extends TestCase { use DoctrineDataCollectorTestTrait; + public static function setUpBeforeClass(): void + { + if (!class_exists(DebugStack::class)) { + self::markTestSkipped('This test requires DBAL < 4.'); + } + } + public function testReset() { $queries = [ diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleIntIdEntity.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleIntIdEntity.php index 94b47da855a37..85c1c0cc20ea6 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleIntIdEntity.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/SingleIntIdEntity.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Doctrine\Tests\Fixtures; +use Doctrine\DBAL\Types\Types; use Doctrine\ORM\Mapping\Column; use Doctrine\ORM\Mapping\Entity; use Doctrine\ORM\Mapping\Id; @@ -27,8 +28,8 @@ class SingleIntIdEntity #[Column(type: 'string', nullable: true)] public $name; - /** @Column(type="array", nullable=true) */ - #[Column(type: 'array', nullable: true)] + /** @Column(type="json", nullable=true) */ + #[Column(type: Types::JSON, nullable: true)] public $phoneNumbers = []; public function __construct($id, $name) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Type/StringWrapperType.php b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Type/StringWrapperType.php index d01148f3b018c..33481663b6152 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Type/StringWrapperType.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Fixtures/Type/StringWrapperType.php @@ -18,20 +18,16 @@ class StringWrapperType extends StringType { /** * {@inheritdoc} - * - * @return mixed */ - public function convertToDatabaseValue($value, AbstractPlatform $platform) + public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string { return $value instanceof StringWrapper ? $value->getString() : null; } /** * {@inheritdoc} - * - * @return mixed */ - public function convertToPHPValue($value, AbstractPlatform $platform) + public function convertToPHPValue($value, AbstractPlatform $platform): StringWrapper { return new StringWrapper($value); } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php b/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php index 2e9ed80e3115a..b43bb93d7dd52 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Logger/DbalLoggerTest.php @@ -11,6 +11,7 @@ namespace Symfony\Bridge\Doctrine\Tests\Logger; +use Doctrine\DBAL\Logging\SQLLogger; use PHPUnit\Framework\TestCase; use Psr\Log\LoggerInterface; use Symfony\Bridge\Doctrine\Logger\DbalLogger; @@ -20,6 +21,13 @@ */ class DbalLoggerTest extends TestCase { + public static function setUpBeforeClass(): void + { + if (!class_exists(SQLLogger::class)) { + self::markTestSkipped('This test requires DBAL < 4.'); + } + } + /** * @dataProvider getLogFixtures */ diff --git a/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php b/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php index 6c7bf67bc08af..a478f72266ffb 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Messenger/DoctrinePingConnectionMiddlewareTest.php @@ -13,8 +13,11 @@ use Doctrine\DBAL\Connection; use Doctrine\DBAL\Exception as DBALException; +use Doctrine\DBAL\Platforms\AbstractPlatform; +use Doctrine\DBAL\Result; use Doctrine\ORM\EntityManagerInterface; use Doctrine\Persistence\ManagerRegistry; +use PHPUnit\Framework\MockObject\MockObject; use Symfony\Bridge\Doctrine\Messenger\DoctrinePingConnectionMiddleware; use Symfony\Component\Messenger\Envelope; use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException; @@ -47,16 +50,24 @@ protected function setUp(): void public function testMiddlewarePingOk() { - $this->connection->expects($this->once()) - ->method('getDatabasePlatform') - ->will($this->throwException(new DBALException())); + $this->connection->method('getDatabasePlatform') + ->willReturn($this->mockPlatform()); + + $this->connection->expects($this->exactly(2)) + ->method('executeQuery') + ->willReturnCallback(function () { + static $counter = 0; + + if (1 === ++$counter) { + throw $this->createMock(DBALException::class); + } + + return $this->createMock(Result::class); + }); $this->connection->expects($this->once()) ->method('close') ; - $this->connection->expects($this->once()) - ->method('connect') - ; $envelope = new Envelope(new \stdClass(), [ new ConsumedByWorkerStamp(), @@ -66,9 +77,8 @@ public function testMiddlewarePingOk() public function testMiddlewarePingResetEntityManager() { - $this->connection->expects($this->once()) - ->method('getDatabasePlatform') - ->will($this->throwException(new DBALException())); + $this->connection->method('getDatabasePlatform') + ->willReturn($this->mockPlatform()); $this->entityManager->expects($this->once()) ->method('isOpen') @@ -112,11 +122,17 @@ public function testMiddlewareNoPingInNonWorkerContext() $this->connection->expects($this->never()) ->method('close') ; - $this->connection->expects($this->never()) - ->method('connect') - ; $envelope = new Envelope(new \stdClass()); $this->middleware->handle($envelope, $this->getStackMock()); } + + /** @return AbstractPlatform&MockObject */ + private function mockPlatform(): AbstractPlatform + { + $platform = $this->createMock(AbstractPlatform::class); + $platform->method('getDummySelectSQL')->willReturn('SELECT 1'); + + return $platform; + } } diff --git a/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php b/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php index 4e546b20890c6..e59428783e4dd 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php @@ -178,13 +178,13 @@ public static function provideEndTransactionMethod(): array { return [ 'commit' => [ - static function (Connection $conn): bool { + static function (Connection $conn): ?bool { return $conn->commit(); }, '"COMMIT"', ], 'rollback' => [ - static function (Connection $conn): bool { + static function (Connection $conn): ?bool { return $conn->rollBack(); }, '"ROLLBACK"', @@ -236,7 +236,7 @@ public static function provideExecuteAndEndTransactionMethods(): array static function (Connection $conn, string $sql) { return $conn->executeStatement($sql); }, - static function (Connection $conn): bool { + static function (Connection $conn): ?bool { return $conn->commit(); }, ], @@ -244,7 +244,7 @@ static function (Connection $conn): bool { static function (Connection $conn, string $sql): Result { return $conn->executeQuery($sql); }, - static function (Connection $conn): bool { + static function (Connection $conn): ?bool { return $conn->rollBack(); }, ], @@ -252,7 +252,7 @@ static function (Connection $conn): bool { static function (Connection $conn, string $sql): Result { return $conn->prepare($sql)->executeQuery(); }, - static function (Connection $conn): bool { + static function (Connection $conn): ?bool { return $conn->commit(); }, ], diff --git a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineFooType.php b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineFooType.php index 7c09108fde562..cc2e8154a7c41 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineFooType.php +++ b/src/Symfony/Bridge/Doctrine/Tests/PropertyInfo/Fixtures/DoctrineFooType.php @@ -43,10 +43,8 @@ public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $pla /** * {@inheritdoc} - * - * @return mixed */ - public function convertToDatabaseValue($value, AbstractPlatform $platform) + public function convertToDatabaseValue($value, AbstractPlatform $platform): ?string { if (null === $value) { return null; @@ -60,10 +58,8 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform) /** * {@inheritdoc} - * - * @return mixed */ - public function convertToPHPValue($value, AbstractPlatform $platform) + public function convertToPHPValue($value, AbstractPlatform $platform): ?Foo { if (null === $value) { return null; diff --git a/src/Symfony/Bridge/Doctrine/Tests/SchemaListener/MessengerTransportDoctrineSchemaSubscriberTest.php b/src/Symfony/Bridge/Doctrine/Tests/SchemaListener/MessengerTransportDoctrineSchemaSubscriberTest.php index ff4ab2c27a19c..f846a4f38225a 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/SchemaListener/MessengerTransportDoctrineSchemaSubscriberTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/SchemaListener/MessengerTransportDoctrineSchemaSubscriberTest.php @@ -49,6 +49,10 @@ public function testPostGenerateSchema() public function testOnSchemaCreateTable() { + if (!class_exists(SchemaCreateTableEventArgs::class)) { + self::markTestSkipped('This test requires DBAL < 4.'); + } + $platform = $this->createMock(AbstractPlatform::class); $table = new Table('queue_table'); $event = new SchemaCreateTableEventArgs($table, [], [], $platform); @@ -80,6 +84,10 @@ public function testOnSchemaCreateTable() public function testOnSchemaCreateTableNoExtraSql() { + if (!class_exists(SchemaCreateTableEventArgs::class)) { + self::markTestSkipped('This test requires DBAL < 4.'); + } + $platform = $this->createMock(AbstractPlatform::class); $table = new Table('queue_table'); $event = new SchemaCreateTableEventArgs($table, [], [], $platform); diff --git a/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php b/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php index c1db2bbe70124..6f78bf3ecce92 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Types/UlidTypeTest.php @@ -15,7 +15,7 @@ use Doctrine\DBAL\Platforms\MariaDBPlatform; use Doctrine\DBAL\Platforms\MySQLPlatform; use Doctrine\DBAL\Platforms\PostgreSQLPlatform; -use Doctrine\DBAL\Platforms\SqlitePlatform; +use Doctrine\DBAL\Platforms\SQLitePlatform; use Doctrine\DBAL\Types\ConversionException; use Doctrine\DBAL\Types\Type; use PHPUnit\Framework\TestCase; @@ -26,6 +26,9 @@ // DBAL 2 compatibility class_exists('Doctrine\DBAL\Platforms\PostgreSqlPlatform'); +// DBAL 3 compatibility +class_exists('Doctrine\DBAL\Platforms\SqlitePlatform'); + final class UlidTypeTest extends TestCase { private const DUMMY_ULID = '01EEDQEK6ZAZE93J8KG5B4MBJC'; @@ -85,25 +88,25 @@ public function testNotSupportedTypeConversionForDatabaseValue() { $this->expectException(ConversionException::class); - $this->type->convertToDatabaseValue(new \stdClass(), new SqlitePlatform()); + $this->type->convertToDatabaseValue(new \stdClass(), new SQLitePlatform()); } public function testNullConversionForDatabaseValue() { - $this->assertNull($this->type->convertToDatabaseValue(null, new SqlitePlatform())); + $this->assertNull($this->type->convertToDatabaseValue(null, new SQLitePlatform())); } public function testUlidInterfaceConvertsToPHPValue() { $ulid = $this->createMock(AbstractUid::class); - $actual = $this->type->convertToPHPValue($ulid, new SqlitePlatform()); + $actual = $this->type->convertToPHPValue($ulid, new SQLitePlatform()); $this->assertSame($ulid, $actual); } public function testUlidConvertsToPHPValue() { - $ulid = $this->type->convertToPHPValue(self::DUMMY_ULID, new SqlitePlatform()); + $ulid = $this->type->convertToPHPValue(self::DUMMY_ULID, new SQLitePlatform()); $this->assertInstanceOf(Ulid::class, $ulid); $this->assertEquals(self::DUMMY_ULID, $ulid->__toString()); @@ -113,19 +116,19 @@ public function testInvalidUlidConversionForPHPValue() { $this->expectException(ConversionException::class); - $this->type->convertToPHPValue('abcdefg', new SqlitePlatform()); + $this->type->convertToPHPValue('abcdefg', new SQLitePlatform()); } public function testNullConversionForPHPValue() { - $this->assertNull($this->type->convertToPHPValue(null, new SqlitePlatform())); + $this->assertNull($this->type->convertToPHPValue(null, new SQLitePlatform())); } public function testReturnValueIfUlidForPHPValue() { $ulid = new Ulid(); - $this->assertSame($ulid, $this->type->convertToPHPValue($ulid, new SqlitePlatform())); + $this->assertSame($ulid, $this->type->convertToPHPValue($ulid, new SQLitePlatform())); } public function testGetName() @@ -144,7 +147,7 @@ public function testGetGuidTypeDeclarationSQL(AbstractPlatform $platform, string public static function provideSqlDeclarations(): \Generator { yield [new PostgreSQLPlatform(), 'UUID']; - yield [new SqlitePlatform(), 'BLOB']; + yield [new SQLitePlatform(), 'BLOB']; yield [new MySQLPlatform(), 'BINARY(16)']; if (class_exists(MariaDBPlatform::class)) { @@ -154,6 +157,6 @@ public static function provideSqlDeclarations(): \Generator public function testRequiresSQLCommentHint() { - $this->assertTrue($this->type->requiresSQLCommentHint(new SqlitePlatform())); + $this->assertTrue($this->type->requiresSQLCommentHint(new SQLitePlatform())); } } diff --git a/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php b/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php index 003093aec8845..fa1a72fa4eb33 100644 --- a/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php +++ b/src/Symfony/Bridge/Doctrine/Types/AbstractUidType.php @@ -13,6 +13,8 @@ use Doctrine\DBAL\Platforms\AbstractPlatform; use Doctrine\DBAL\Types\ConversionException; +use Doctrine\DBAL\Types\Exception\InvalidType; +use Doctrine\DBAL\Types\Exception\ValueNotConvertible; use Doctrine\DBAL\Types\Type; use Symfony\Component\Uid\AbstractUid; @@ -33,7 +35,7 @@ public function getSQLDeclaration(array $column, AbstractPlatform $platform): st } return $platform->getBinaryTypeDeclarationSQL([ - 'length' => '16', + 'length' => 16, 'fixed' => true, ]); } @@ -50,13 +52,13 @@ public function convertToPHPValue($value, AbstractPlatform $platform): ?Abstract } if (!\is_string($value)) { - throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'string', AbstractUid::class]); + $this->throwInvalidType($value); } try { return $this->getUidClass()::fromString($value); } catch (\InvalidArgumentException $e) { - throw ConversionException::conversionFailed($value, $this->getName(), $e); + $this->throwValueNotConvertible($value, $e); } } @@ -78,13 +80,13 @@ public function convertToDatabaseValue($value, AbstractPlatform $platform): ?str } if (!\is_string($value)) { - throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'string', AbstractUid::class]); + $this->throwInvalidType($value); } try { return $this->getUidClass()::fromString($value)->$toString(); } catch (\InvalidArgumentException $e) { - throw ConversionException::conversionFailed($value, $this->getName()); + $this->throwValueNotConvertible($value, $e); } } @@ -105,4 +107,32 @@ private function hasNativeGuidType(AbstractPlatform $platform): bool return $platform->getGuidTypeDeclarationSQL([]) !== $platform->$method(['fixed' => true, 'length' => 36]); } + + /** + * @param mixed $value + * + * @return never + */ + private function throwInvalidType($value): void + { + if (!class_exists(InvalidType::class)) { + throw ConversionException::conversionFailedInvalidType($value, $this->getName(), ['null', 'string', AbstractUid::class]); + } + + throw InvalidType::new($value, $this->getName(), ['null', 'string', AbstractUid::class]); + } + + /** + * @param mixed $value + * + * @return never + */ + private function throwValueNotConvertible($value, \Throwable $previous): void + { + if (!class_exists(ValueNotConvertible::class)) { + throw ConversionException::conversionFailed($value, $this->getName(), $previous); + } + + throw ValueNotConvertible::new($value, $this->getName(), null, $previous); + } } From f601638291a06030bb8a5895638c99ae55b78546 Mon Sep 17 00:00:00 2001 From: Oleksii Bulba Date: Fri, 13 Oct 2023 15:54:26 +0300 Subject: [PATCH 034/115] #51928 Missing translations for Belarusian (be) - Added missing translations for Belarusian (be); --- .../Resources/translations/validators.be.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf index 648955684baa0..d9fcd93b808f9 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.be.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Значэнне сеткавай маскі павінна быць ад {{min}} да {{max}}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Назва файла занадта доўгая. Ён павінен мець {{ filename_max_length }} сімвал або менш.|Назва файла занадта доўгая. Ён павінен мець {{ filename_max_length }} сімвалы або менш.|Назва файла занадта доўгая. Ён павінен мець {{ filename_max_length }} сімвалаў або менш. + + + The password strength is too low. Please use a stronger password. + Надзейнасць пароля занадта нізкая. Выкарыстоўвайце больш надзейны пароль. + + + This value contains characters that are not allowed by the current restriction-level. + Гэта значэнне змяшчае сімвалы, якія не дазволены цяперашнім узроўнем абмежаванняў. + + + Using invisible characters is not allowed. + Выкарыстанне нябачных сімвалаў не дазваляецца. + + + Mixing numbers from different scripts is not allowed. + Змешванне лікаў з розных алфавітаў не дапускаецца. + + + Using hidden overlay characters is not allowed. + Выкарыстанне схаваных накладзеных сімвалаў не дазваляецца. + From 5b0cf25ba98fe07a581618bbc97f1441dbd705e5 Mon Sep 17 00:00:00 2001 From: Javier Ledezma Date: Wed, 11 Oct 2023 21:21:37 -0600 Subject: [PATCH 035/115] [Translation] Prevent creating empty keys when key ends with a period [Translation] create getKeyParts() to keep periods at start or end of the key [Translation] Simplify test cases by removing blank spaces --- .../Tests/Util/ArrayConverterTest.php | 28 ++++++++++++ .../Translation/Util/ArrayConverter.php | 44 ++++++++++++++++++- 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Translation/Tests/Util/ArrayConverterTest.php b/src/Symfony/Component/Translation/Tests/Util/ArrayConverterTest.php index 8936ef1ae6926..446130cc477a5 100644 --- a/src/Symfony/Component/Translation/Tests/Util/ArrayConverterTest.php +++ b/src/Symfony/Component/Translation/Tests/Util/ArrayConverterTest.php @@ -69,6 +69,34 @@ public static function messagesData() ], ], ], + [ + // input + [ + 'foo.' => 'foo.', + '.bar' => '.bar', + 'abc.abc' => 'value', + 'bcd.bcd.' => 'value', + '.cde.cde.' => 'value', + '.def.def' => 'value', + ], + // expected output + [ + 'foo.' => 'foo.', + '.bar' => '.bar', + 'abc' => [ + 'abc' => 'value', + ], + 'bcd' => [ + 'bcd.' => 'value', + ], + '.cde' => [ + 'cde.' => 'value', + ], + '.def' => [ + 'def' => 'value', + ], + ], + ], ]; } } diff --git a/src/Symfony/Component/Translation/Util/ArrayConverter.php b/src/Symfony/Component/Translation/Util/ArrayConverter.php index f69c2e3c6481d..e132e3decfcdd 100644 --- a/src/Symfony/Component/Translation/Util/ArrayConverter.php +++ b/src/Symfony/Component/Translation/Util/ArrayConverter.php @@ -38,7 +38,7 @@ public static function expandToTree(array $messages) $tree = []; foreach ($messages as $id => $value) { - $referenceToElement = &self::getElementByPath($tree, explode('.', $id)); + $referenceToElement = &self::getElementByPath($tree, self::getKeyParts($id)); $referenceToElement = $value; @@ -65,6 +65,7 @@ private static function &getElementByPath(array &$tree, array $parts) $elem = &$elem[implode('.', \array_slice($parts, $i))]; break; } + $parentOfElem = &$elem; $elem = &$elem[$part]; } @@ -96,4 +97,45 @@ private static function cancelExpand(array &$tree, string $prefix, array $node) } } } + + private static function getKeyParts(string $key) + { + $parts = explode('.', $key); + $partsCount = \count($parts); + + $result = []; + $buffer = ''; + + foreach ($parts as $index => $part) { + if (0 === $index && '' === $part) { + $buffer = '.'; + + continue; + } + + if ($index === $partsCount - 1 && '' === $part) { + $buffer .= '.'; + $result[] = $buffer; + + continue; + } + + if (isset($parts[$index + 1]) && '' === $parts[$index + 1]) { + $buffer .= $part; + + continue; + } + + if ($buffer) { + $result[] = $buffer.$part; + $buffer = ''; + + continue; + } + + $result[] = $part; + } + + return $result; + } } From 6b5a36248bf5a7f56427eb6778d83b7a7092e0f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ramon=20Cu=C3=B1at?= Date: Sat, 14 Oct 2023 11:09:35 +0200 Subject: [PATCH 036/115] [Validator] add missing catalan translations Solves #51932 --- .../Resources/translations/validators.ca.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf index 04f3e9abf211e..d6d925ecc5814 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ca.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. El valor de la màscara de xarxa hauria d'estar entre {{ min }} i {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + El nom del fitxer és massa llarg. Ha de tenir {{ filename_max_length }} caràcter o menys.|El nom del fitxer és massa llarg. Ha de tenir {{ filename_max_length }} caràcters o menys. + + + The password strength is too low. Please use a stronger password. + La contrasenya és massa feble. Si us plau, feu servir una contrasenya més segura. + + + This value contains characters that are not allowed by the current restriction-level. + Aquest valor conté caràcters que no estan permisos segons el nivell de restricció actual. + + + Using invisible characters is not allowed. + No es permet l'ús de caràcters invisibles. + + + Mixing numbers from different scripts is not allowed. + No es permet barrejar números de diferents scripts. + + + Using hidden overlay characters is not allowed. + No es permet l'ús de caràcters superposats ocults. + From 2aacd2249c0d7cf6f6c5068d7f71a5426dfb42ea Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Sat, 14 Oct 2023 18:25:31 +0200 Subject: [PATCH 037/115] [Translation] Add missing return type --- src/Symfony/Component/Translation/Util/ArrayConverter.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Translation/Util/ArrayConverter.php b/src/Symfony/Component/Translation/Util/ArrayConverter.php index e132e3decfcdd..cbab0c5909b19 100644 --- a/src/Symfony/Component/Translation/Util/ArrayConverter.php +++ b/src/Symfony/Component/Translation/Util/ArrayConverter.php @@ -98,7 +98,10 @@ private static function cancelExpand(array &$tree, string $prefix, array $node) } } - private static function getKeyParts(string $key) + /** + * @return string[] + */ + private static function getKeyParts(string $key): array { $parts = explode('.', $key); $partsCount = \count($parts); From fa661b53d8b8ed9a6bb0e065b02d1f159b9bc99d Mon Sep 17 00:00:00 2001 From: "Roland Franssen :)" Date: Mon, 16 Oct 2023 15:31:00 +0200 Subject: [PATCH 038/115] [Messenger] Fix DoctrineOpenTransactionLoggerMiddleware --- .../DoctrineOpenTransactionLoggerMiddleware.php | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/Symfony/Bridge/Doctrine/Messenger/DoctrineOpenTransactionLoggerMiddleware.php b/src/Symfony/Bridge/Doctrine/Messenger/DoctrineOpenTransactionLoggerMiddleware.php index 246f0090e58ef..40adcbabae59f 100644 --- a/src/Symfony/Bridge/Doctrine/Messenger/DoctrineOpenTransactionLoggerMiddleware.php +++ b/src/Symfony/Bridge/Doctrine/Messenger/DoctrineOpenTransactionLoggerMiddleware.php @@ -26,6 +26,8 @@ class DoctrineOpenTransactionLoggerMiddleware extends AbstractDoctrineMiddleware { private $logger; + /** @var bool */ + private $isHandling = false; public function __construct(ManagerRegistry $managerRegistry, string $entityManagerName = null, LoggerInterface $logger = null) { @@ -36,6 +38,12 @@ public function __construct(ManagerRegistry $managerRegistry, string $entityMana protected function handleForManager(EntityManagerInterface $entityManager, Envelope $envelope, StackInterface $stack): Envelope { + if ($this->isHandling) { + return $stack->next()->handle($envelope, $stack); + } + + $this->isHandling = true; + try { return $stack->next()->handle($envelope, $stack); } finally { @@ -44,6 +52,7 @@ protected function handleForManager(EntityManagerInterface $entityManager, Envel 'message' => $envelope->getMessage(), ]); } + $this->isHandling = false; } } } From 0f398cebb02e550a8f6e4493c7dde9a11f5d23ad Mon Sep 17 00:00:00 2001 From: HypeMC Date: Sat, 7 Oct 2023 17:47:31 +0200 Subject: [PATCH 039/115] [Serializer] Fix collecting only first missing constructor argument --- .../Normalizer/AbstractNormalizer.php | 31 +++---- .../Php80WithPromotedTypedConstructor.php | 7 +- .../Tests/Fixtures/WithTypedConstructor.php | 35 ++++++++ .../ConstructorArgumentsTestTrait.php | 27 ++++++- .../Serializer/Tests/SerializerTest.php | 80 +++++++++++++++++++ 5 files changed, 161 insertions(+), 19 deletions(-) create mode 100644 src/Symfony/Component/Serializer/Tests/Fixtures/WithTypedConstructor.php diff --git a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php index 4fcae7d99cfcc..5c88e4455e09c 100644 --- a/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php +++ b/src/Symfony/Component/Serializer/Normalizer/AbstractNormalizer.php @@ -348,7 +348,7 @@ protected function instantiateObject(array &$data, string $class, array &$contex } $constructorParameters = $constructor->getParameters(); - + $missingConstructorArguments = []; $params = []; foreach ($constructorParameters as $constructorParameter) { $paramName = $constructorParameter->name; @@ -401,7 +401,8 @@ protected function instantiateObject(array &$data, string $class, array &$contex $params[] = null; } else { if (!isset($context['not_normalizable_value_exceptions'])) { - throw new MissingConstructorArgumentsException(sprintf('Cannot create an instance of "%s" from serialized data because its constructor requires parameter "%s" to be present.', $class, $constructorParameter->name), 0, null, [$constructorParameter->name]); + $missingConstructorArguments[] = $constructorParameter->name; + continue; } $exception = NotNormalizableValueException::createForUnexpectedDataType( @@ -412,24 +413,26 @@ protected function instantiateObject(array &$data, string $class, array &$contex true ); $context['not_normalizable_value_exceptions'][] = $exception; - - return $reflectionClass->newInstanceWithoutConstructor(); } } - if ($constructor->isConstructor()) { - try { - return $reflectionClass->newInstanceArgs($params); - } catch (\TypeError $th) { - if (!isset($context['not_normalizable_value_exceptions'])) { - throw $th; - } + if ($missingConstructorArguments) { + throw new MissingConstructorArgumentsException(sprintf('Cannot create an instance of "%s" from serialized data because its constructor requires the following parameters to be present : "$%s".', $class, implode('", "$', $missingConstructorArguments)), 0, null, $missingConstructorArguments); + } - return $reflectionClass->newInstanceWithoutConstructor(); - } - } else { + if (!$constructor->isConstructor()) { return $constructor->invokeArgs(null, $params); } + + try { + return $reflectionClass->newInstanceArgs($params); + } catch (\TypeError $e) { + if (!isset($context['not_normalizable_value_exceptions'])) { + throw $e; + } + + return $reflectionClass->newInstanceWithoutConstructor(); + } } unset($context['has_constructor']); diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/Php80WithPromotedTypedConstructor.php b/src/Symfony/Component/Serializer/Tests/Fixtures/Php80WithPromotedTypedConstructor.php index be3247450ba79..a7b79aa47dcae 100644 --- a/src/Symfony/Component/Serializer/Tests/Fixtures/Php80WithPromotedTypedConstructor.php +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/Php80WithPromotedTypedConstructor.php @@ -13,7 +13,10 @@ final class Php80WithPromotedTypedConstructor { - public function __construct(public bool $bool) - { + public function __construct( + public bool $bool, + public string $string, + public int $int, + ) { } } diff --git a/src/Symfony/Component/Serializer/Tests/Fixtures/WithTypedConstructor.php b/src/Symfony/Component/Serializer/Tests/Fixtures/WithTypedConstructor.php new file mode 100644 index 0000000000000..734d1c83b24d9 --- /dev/null +++ b/src/Symfony/Component/Serializer/Tests/Fixtures/WithTypedConstructor.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Symfony\Component\Serializer\Tests\Fixtures; + +final class WithTypedConstructor +{ + /** + * @var string + */ + public $string; + /** + * @var bool + */ + public $bool; + /** + * @var int + */ + public $int; + + public function __construct(string $string, bool $bool, int $int) + { + $this->string = $string; + $this->bool = $bool; + $this->int = $int; + } +} diff --git a/src/Symfony/Component/Serializer/Tests/Normalizer/Features/ConstructorArgumentsTestTrait.php b/src/Symfony/Component/Serializer/Tests/Normalizer/Features/ConstructorArgumentsTestTrait.php index 306c571f9c59d..f7e18241c7210 100644 --- a/src/Symfony/Component/Serializer/Tests/Normalizer/Features/ConstructorArgumentsTestTrait.php +++ b/src/Symfony/Component/Serializer/Tests/Normalizer/Features/ConstructorArgumentsTestTrait.php @@ -62,9 +62,30 @@ public function testConstructorWithMissingData() ]; $normalizer = $this->getDenormalizerForConstructArguments(); + try { + $normalizer->denormalize($data, ConstructorArgumentsObject::class); + self::fail(sprintf('Failed asserting that exception of type "%s" is thrown.', MissingConstructorArgumentsException::class)); + } catch (MissingConstructorArgumentsException $e) { + self::assertSame(sprintf('Cannot create an instance of "%s" from serialized data because its constructor requires the following parameters to be present : "$bar", "$baz".', ConstructorArgumentsObject::class), $e->getMessage()); + self::assertSame(['bar', 'baz'], $e->getMissingConstructorArguments()); + } + } + + public function testExceptionsAreCollectedForConstructorWithMissingData() + { + $data = [ + 'foo' => 10, + ]; + + $exceptions = []; + + $normalizer = $this->getDenormalizerForConstructArguments(); + $normalizer->denormalize($data, ConstructorArgumentsObject::class, null, [ + 'not_normalizable_value_exceptions' => &$exceptions, + ]); - $this->expectException(MissingConstructorArgumentsException::class); - $this->expectExceptionMessage('Cannot create an instance of "'.ConstructorArgumentsObject::class.'" from serialized data because its constructor requires parameter "bar" to be present.'); - $normalizer->denormalize($data, ConstructorArgumentsObject::class); + self::assertCount(2, $exceptions); + self::assertSame('Failed to create object because the class misses the "bar" property.', $exceptions[0]->getMessage()); + self::assertSame('Failed to create object because the class misses the "baz" property.', $exceptions[1]->getMessage()); } } diff --git a/src/Symfony/Component/Serializer/Tests/SerializerTest.php b/src/Symfony/Component/Serializer/Tests/SerializerTest.php index 2141c0cf6d334..fdd98d0be5b5a 100644 --- a/src/Symfony/Component/Serializer/Tests/SerializerTest.php +++ b/src/Symfony/Component/Serializer/Tests/SerializerTest.php @@ -67,6 +67,7 @@ use Symfony\Component\Serializer\Tests\Fixtures\Php74Full; use Symfony\Component\Serializer\Tests\Fixtures\Php80WithPromotedTypedConstructor; use Symfony\Component\Serializer\Tests\Fixtures\TraversableDummy; +use Symfony\Component\Serializer\Tests\Fixtures\WithTypedConstructor; use Symfony\Component\Serializer\Tests\Normalizer\TestDenormalizer; use Symfony\Component\Serializer\Tests\Normalizer\TestNormalizer; @@ -1196,6 +1197,85 @@ public function testCollectDenormalizationErrorsWithConstructor(?ClassMetadataFa 'useMessageForUser' => false, 'message' => 'The type of the "bool" attribute for class "Symfony\\Component\\Serializer\\Tests\\Fixtures\\Php80WithPromotedTypedConstructor" must be one of "bool" ("string" given).', ], + [ + 'currentType' => 'array', + 'expectedTypes' => [ + 'unknown', + ], + 'path' => null, + 'useMessageForUser' => true, + 'message' => 'Failed to create object because the class misses the "string" property.', + ], + [ + 'currentType' => 'array', + 'expectedTypes' => [ + 'unknown', + ], + 'path' => null, + 'useMessageForUser' => true, + 'message' => 'Failed to create object because the class misses the "int" property.', + ], + ]; + + $this->assertSame($expected, $exceptionsAsArray); + } + + public function testCollectDenormalizationErrorsWithInvalidConstructorTypes() + { + $json = '{"string": "some string", "bool": "bool", "int": true}'; + + $extractor = new PropertyInfoExtractor([], [new ReflectionExtractor()]); + + $serializer = new Serializer( + [new ObjectNormalizer(null, null, null, $extractor)], + ['json' => new JsonEncoder()] + ); + + try { + $serializer->deserialize($json, WithTypedConstructor::class, 'json', [ + DenormalizerInterface::COLLECT_DENORMALIZATION_ERRORS => true, + ]); + + $this->fail(); + } catch (\Throwable $th) { + $this->assertInstanceOf(PartialDenormalizationException::class, $th); + } + + $this->assertInstanceOf(WithTypedConstructor::class, $object = $th->getData()); + + $this->assertSame('some string', $object->string); + $this->assertTrue($object->bool); + $this->assertSame(1, $object->int); + + $exceptionsAsArray = array_map(function (NotNormalizableValueException $e): array { + return [ + 'currentType' => $e->getCurrentType(), + 'expectedTypes' => $e->getExpectedTypes(), + 'path' => $e->getPath(), + 'useMessageForUser' => $e->canUseMessageForUser(), + 'message' => $e->getMessage(), + ]; + }, $th->getErrors()); + + $expected = [ + [ + 'currentType' => 'string', + 'expectedTypes' => [ + 0 => 'bool', + ], + 'path' => 'bool', + 'useMessageForUser' => false, + 'message' => 'The type of the "bool" attribute for class "Symfony\Component\Serializer\Tests\Fixtures\WithTypedConstructor" must be one of "bool" ("string" given).', + ], + [ + 'currentType' => 'bool', + 'expectedTypes' => [ + 0 => 'int', + ], + 'path' => 'int', + 'useMessageForUser' => false, + 'message' => 'The type of the "int" attribute for class "Symfony\Component\Serializer\Tests\Fixtures\WithTypedConstructor" must be one of "int" ("bool" given).', + ], ]; $this->assertSame($expected, $exceptionsAsArray); From 8ae89938713d54f3fe8a627c0907d693107d5c70 Mon Sep 17 00:00:00 2001 From: Christophe Coevoet Date: Tue, 17 Oct 2023 10:37:39 +0200 Subject: [PATCH 040/115] Handle Sendinblue error responses without a message key --- .../Bridge/Sendinblue/Transport/SendinblueApiTransport.php | 2 +- .../Notifier/Bridge/Sendinblue/SendinblueTransport.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Mailer/Bridge/Sendinblue/Transport/SendinblueApiTransport.php b/src/Symfony/Component/Mailer/Bridge/Sendinblue/Transport/SendinblueApiTransport.php index 0a43deb97f65d..110ad48f1a077 100644 --- a/src/Symfony/Component/Mailer/Bridge/Sendinblue/Transport/SendinblueApiTransport.php +++ b/src/Symfony/Component/Mailer/Bridge/Sendinblue/Transport/SendinblueApiTransport.php @@ -65,7 +65,7 @@ protected function doSendApi(SentMessage $sentMessage, Email $email, Envelope $e } if (201 !== $statusCode) { - throw new HttpTransportException('Unable to send an email: '.$result['message'].sprintf(' (code %d).', $statusCode), $response); + throw new HttpTransportException('Unable to send an email: '.($result['message'] ?? $response->getContent(false)).sprintf(' (code %d).', $statusCode), $response); } $sentMessage->setMessageId($result['messageId']); diff --git a/src/Symfony/Component/Notifier/Bridge/Sendinblue/SendinblueTransport.php b/src/Symfony/Component/Notifier/Bridge/Sendinblue/SendinblueTransport.php index b554cfef9f67b..d8709f7d1e960 100644 --- a/src/Symfony/Component/Notifier/Bridge/Sendinblue/SendinblueTransport.php +++ b/src/Symfony/Component/Notifier/Bridge/Sendinblue/SendinblueTransport.php @@ -75,7 +75,7 @@ protected function doSend(MessageInterface $message): SentMessage if (201 !== $statusCode) { $error = $response->toArray(false); - throw new TransportException('Unable to send the SMS: '.$error['message'], $response); + throw new TransportException('Unable to send the SMS: '.($error['message'] ?? $response->getContent(false)), $response); } $success = $response->toArray(false); From 77ca01ca7a48d8f19bbb405cb76e0884bb032355 Mon Sep 17 00:00:00 2001 From: Oskar Stark Date: Mon, 2 Oct 2023 23:04:54 +0200 Subject: [PATCH 041/115] [HttpFoundation] Do not swallow trailing `=` in cookie value --- .../Component/HttpFoundation/HeaderUtils.php | 63 ++++++++++--------- .../HttpFoundation/Tests/CookieTest.php | 3 + .../HttpFoundation/Tests/HeaderUtilsTest.php | 6 +- 3 files changed, 39 insertions(+), 33 deletions(-) diff --git a/src/Symfony/Component/HttpFoundation/HeaderUtils.php b/src/Symfony/Component/HttpFoundation/HeaderUtils.php index 46b1e6aed60fb..f91c7e1d97d86 100644 --- a/src/Symfony/Component/HttpFoundation/HeaderUtils.php +++ b/src/Symfony/Component/HttpFoundation/HeaderUtils.php @@ -33,17 +33,21 @@ private function __construct() * * Example: * - * HeaderUtils::split("da, en-gb;q=0.8", ",;") + * HeaderUtils::split('da, en-gb;q=0.8', ',;') * // => ['da'], ['en-gb', 'q=0.8']] * * @param string $separators List of characters to split on, ordered by - * precedence, e.g. ",", ";=", or ",;=" + * precedence, e.g. ',', ';=', or ',;=' * * @return array Nested array with as many levels as there are characters in * $separators */ public static function split(string $header, string $separators): array { + if ('' === $separators) { + throw new \InvalidArgumentException('At least one separator must be specified.'); + } + $quotedSeparators = preg_quote($separators, '/'); preg_match_all(' @@ -77,8 +81,8 @@ public static function split(string $header, string $separators): array * * Example: * - * HeaderUtils::combine([["foo", "abc"], ["bar"]]) - * // => ["foo" => "abc", "bar" => true] + * HeaderUtils::combine([['foo', 'abc'], ['bar']]) + * // => ['foo' => 'abc', 'bar' => true] */ public static function combine(array $parts): array { @@ -95,13 +99,13 @@ public static function combine(array $parts): array /** * Joins an associative array into a string for use in an HTTP header. * - * The key and value of each entry are joined with "=", and all entries + * The key and value of each entry are joined with '=', and all entries * are joined with the specified separator and an additional space (for * readability). Values are quoted if necessary. * * Example: * - * HeaderUtils::toString(["foo" => "abc", "bar" => true, "baz" => "a b c"], ",") + * HeaderUtils::toString(['foo' => 'abc', 'bar' => true, 'baz' => 'a b c'], ',') * // => 'foo=abc, bar, baz="a b c"' */ public static function toString(array $assoc, string $separator): string @@ -252,40 +256,37 @@ public static function parseQuery(string $query, bool $ignoreBrackets = false, s private static function groupParts(array $matches, string $separators, bool $first = true): array { $separator = $separators[0]; - $partSeparators = substr($separators, 1); - + $separators = substr($separators, 1); $i = 0; + + if ('' === $separators && !$first) { + $parts = ['']; + + foreach ($matches as $match) { + if (!$i && isset($match['separator'])) { + $i = 1; + $parts[1] = ''; + } else { + $parts[$i] .= self::unquote($match[0]); + } + } + + return $parts; + } + + $parts = []; $partMatches = []; - $previousMatchWasSeparator = false; + foreach ($matches as $match) { - if (!$first && $previousMatchWasSeparator && isset($match['separator']) && $match['separator'] === $separator) { - $previousMatchWasSeparator = true; - $partMatches[$i][] = $match; - } elseif (isset($match['separator']) && $match['separator'] === $separator) { - $previousMatchWasSeparator = true; + if (($match['separator'] ?? null) === $separator) { ++$i; } else { - $previousMatchWasSeparator = false; $partMatches[$i][] = $match; } } - $parts = []; - if ($partSeparators) { - foreach ($partMatches as $matches) { - $parts[] = self::groupParts($matches, $partSeparators, false); - } - } else { - foreach ($partMatches as $matches) { - $parts[] = self::unquote($matches[0][0]); - } - - if (!$first && 2 < \count($parts)) { - $parts = [ - $parts[0], - implode($separator, \array_slice($parts, 1)), - ]; - } + foreach ($partMatches as $matches) { + $parts[] = '' === $separators ? self::unquote($matches[0][0]) : self::groupParts($matches, $separators, false); } return $parts; diff --git a/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php b/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php index ec5a4e28f406a..9cc0d9fb8cb1d 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/CookieTest.php @@ -324,6 +324,9 @@ public function testFromString() $cookie = Cookie::fromString('foo=bar', true); $this->assertEquals(Cookie::create('foo', 'bar', 0, '/', null, false, false, false, null), $cookie); + $cookie = Cookie::fromString('foo=bar=', true); + $this->assertEquals(Cookie::create('foo', 'bar=', 0, '/', null, false, false, false, null), $cookie); + $cookie = Cookie::fromString('foo', true); $this->assertEquals(Cookie::create('foo', null, 0, '/', null, false, false, false, null), $cookie); diff --git a/src/Symfony/Component/HttpFoundation/Tests/HeaderUtilsTest.php b/src/Symfony/Component/HttpFoundation/Tests/HeaderUtilsTest.php index 73d3f150c7a8e..befa4aea035a5 100644 --- a/src/Symfony/Component/HttpFoundation/Tests/HeaderUtilsTest.php +++ b/src/Symfony/Component/HttpFoundation/Tests/HeaderUtilsTest.php @@ -34,7 +34,7 @@ public static function provideHeaderToSplit(): array [['foo', '123, bar'], 'foo=123, bar', '='], [['foo', '123, bar'], ' foo = 123, bar ', '='], [[['foo', '123'], ['bar']], 'foo=123, bar', ',='], - [[[['foo', '123']], [['bar'], ['foo', '456']]], 'foo=123, bar; foo=456', ',;='], + [[[['foo', '123']], [['bar'], ['foo', '456']]], 'foo=123, bar;; foo=456', ',;='], [[[['foo', 'a,b;c=d']]], 'foo="a,b;c=d"', ',;='], [['foo', 'bar'], 'foo,,,, bar', ','], @@ -46,13 +46,15 @@ public static function provideHeaderToSplit(): array [[['foo_cookie', 'foo=1&bar=2&baz=3'], ['expires', 'Tue, 22-Sep-2020 06:27:09 GMT'], ['path', '/']], 'foo_cookie=foo=1&bar=2&baz=3; expires=Tue, 22-Sep-2020 06:27:09 GMT; path=/', ';='], [[['foo_cookie', 'foo=='], ['expires', 'Tue, 22-Sep-2020 06:27:09 GMT'], ['path', '/']], 'foo_cookie=foo==; expires=Tue, 22-Sep-2020 06:27:09 GMT; path=/', ';='], + [[['foo_cookie', 'foo='], ['expires', 'Tue, 22-Sep-2020 06:27:09 GMT'], ['path', '/']], 'foo_cookie=foo=; expires=Tue, 22-Sep-2020 06:27:09 GMT; path=/', ';='], [[['foo_cookie', 'foo=a=b'], ['expires', 'Tue, 22-Sep-2020 06:27:09 GMT'], ['path', '/']], 'foo_cookie=foo="a=b"; expires=Tue, 22-Sep-2020 06:27:09 GMT; path=/', ';='], // These are not a valid header values. We test that they parse anyway, // and that both the valid and invalid parts are returned. [[], '', ','], [[], ',,,', ','], - [['foo', 'bar', 'baz'], 'foo, "bar", "baz', ','], + [[['', 'foo'], ['bar', '']], '=foo,bar=', ',='], + [['foo', 'foobar', 'baz'], 'foo, foo"bar", "baz', ','], [['foo', 'bar, baz'], 'foo, "bar, baz', ','], [['foo', 'bar, baz\\'], 'foo, "bar, baz\\', ','], [['foo', 'bar, baz\\'], 'foo, "bar, baz\\\\', ','], From 4da09bc891d0c11a8724f1c5ffc559525272634a Mon Sep 17 00:00:00 2001 From: Priyadi Iman Nurcahyo Date: Thu, 12 Oct 2023 23:56:38 +0700 Subject: [PATCH 042/115] [Form] Fix merging params & files when "multiple" is enabled If a form field is configured with the "multiple" option, the request handler merges param values with uploaded files. However, it does not merge correctly if "multiple" is enabled. Example: With the example, the file field will incorrectly replace the first hidden field, when they should be merged. This commit fixes the problem. --- .../HttpFoundationRequestHandler.php | 3 +- .../Component/Form/NativeRequestHandler.php | 3 +- .../Tests/AbstractRequestHandlerTestCase.php | 36 +++++++++++++++++++ src/Symfony/Component/Form/Util/FormUtil.php | 25 +++++++++++++ 4 files changed, 65 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php index 05503ff52977f..90723fd8b48a9 100644 --- a/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php +++ b/src/Symfony/Component/Form/Extension/HttpFoundation/HttpFoundationRequestHandler.php @@ -15,6 +15,7 @@ use Symfony\Component\Form\FormError; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\RequestHandlerInterface; +use Symfony\Component\Form\Util\FormUtil; use Symfony\Component\Form\Util\ServerParams; use Symfony\Component\HttpFoundation\File\File; use Symfony\Component\HttpFoundation\File\UploadedFile; @@ -95,7 +96,7 @@ public function handleRequest(FormInterface $form, $request = null) } if (\is_array($params) && \is_array($files)) { - $data = array_replace_recursive($params, $files); + $data = FormUtil::mergeParamsAndFiles($params, $files); } else { $data = $params ?: $files; } diff --git a/src/Symfony/Component/Form/NativeRequestHandler.php b/src/Symfony/Component/Form/NativeRequestHandler.php index 7b39ad3a17c65..1afa6a6ba734f 100644 --- a/src/Symfony/Component/Form/NativeRequestHandler.php +++ b/src/Symfony/Component/Form/NativeRequestHandler.php @@ -12,6 +12,7 @@ namespace Symfony\Component\Form; use Symfony\Component\Form\Exception\UnexpectedTypeException; +use Symfony\Component\Form\Util\FormUtil; use Symfony\Component\Form\Util\ServerParams; /** @@ -106,7 +107,7 @@ public function handleRequest(FormInterface $form, $request = null) } if (\is_array($params) && \is_array($files)) { - $data = array_replace_recursive($params, $files); + $data = FormUtil::mergeParamsAndFiles($params, $files); } else { $data = $params ?: $files; } diff --git a/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTestCase.php b/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTestCase.php index becf3504c3183..c61447a1ddc68 100644 --- a/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTestCase.php +++ b/src/Symfony/Component/Form/Tests/AbstractRequestHandlerTestCase.php @@ -236,6 +236,42 @@ public function testMergeParamsAndFiles($method) $this->assertSame($file, $form->get('field2')->getData()); } + /** + * @dataProvider methodExceptGetProvider + */ + public function testMergeParamsAndFilesMultiple($method) + { + $form = $this->createForm('param1', $method, true); + $form->add($this->createBuilder('field1', false, ['allow_file_upload' => true, 'multiple' => true])->getForm()); + $file1 = $this->getUploadedFile(); + $file2 = $this->getUploadedFile(); + + $this->setRequestData($method, [ + 'param1' => [ + 'field1' => [ + 'foo', + 'bar', + 'baz', + ], + ], + ], [ + 'param1' => [ + 'field1' => [ + $file1, + $file2, + ], + ], + ]); + + $this->requestHandler->handleRequest($form, $this->request); + $data = $form->get('field1')->getData(); + + $this->assertTrue($form->isSubmitted()); + $this->assertIsArray($data); + $this->assertCount(5, $data); + $this->assertSame(['foo', 'bar', 'baz', $file1, $file2], $data); + } + /** * @dataProvider methodExceptGetProvider */ diff --git a/src/Symfony/Component/Form/Util/FormUtil.php b/src/Symfony/Component/Form/Util/FormUtil.php index fed96de4fa9b3..6c7873de70cb6 100644 --- a/src/Symfony/Component/Form/Util/FormUtil.php +++ b/src/Symfony/Component/Form/Util/FormUtil.php @@ -41,4 +41,29 @@ public static function isEmpty($data) // not considered to be empty, ever. return null === $data || '' === $data; } + + /** + * Recursively replaces or appends elements of the first array with elements + * of second array. If the key is an integer, the values will be appended to + * the new array; otherwise, the value from the second array will replace + * the one from the first array. + */ + public static function mergeParamsAndFiles(array $params, array $files): array + { + $result = []; + + foreach ($params as $key => $value) { + if (\is_array($value) && \is_array($files[$key] ?? null)) { + $value = self::mergeParamsAndFiles($value, $files[$key]); + unset($files[$key]); + } + if (\is_int($key)) { + $result[] = $value; + } else { + $result[$key] = $value; + } + } + + return array_merge($result, $files); + } } From 942c80f8c720123e4aec936482747d7e20881f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=A1rbara=20Luz?= Date: Mon, 16 Oct 2023 07:43:06 -0300 Subject: [PATCH 043/115] Adds translations for Portuguese (pt) --- .../Resources/translations/validators.pt.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf index 090add6bd3413..9c3b00e01521f 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.pt.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. O valor da máscara de rede deve estar entre {{ min }} e {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + O nome do arquivo é muito grande. Deveria ter {{ filename_max_length }} caractere ou menos.|O nome do arquivo é muito grande. Deveria ter {{ filename_max_length }} caracteres ou menos. + + + The password strength is too low. Please use a stronger password. + A força da senha é muito baixa. Por favor utilize uma senha mais forte. + + + This value contains characters that are not allowed by the current restriction-level. + Este valor contém caracteres que não são permitidos pelo nível de restrição atual. + + + Using invisible characters is not allowed. + Não é permitido usar caracteres invisíveis. + + + Mixing numbers from different scripts is not allowed. + Não é permitido misturar números de scripts diferentes. + + + Using hidden overlay characters is not allowed. + Não é permitido usar caracteres de sobreposição ocultos. + From af15423674deba32628828e473cbc8b7b4f3d083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?C=C3=A9dric=20Anne?= Date: Tue, 17 Oct 2023 13:54:47 +0200 Subject: [PATCH 044/115] [Cache] Remove temporary cache item file on `rename()` failure --- .../Component/Cache/Traits/FilesystemCommonTrait.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php b/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php index c06cc309a6b3f..16e768990b942 100644 --- a/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php +++ b/src/Symfony/Component/Cache/Traits/FilesystemCommonTrait.php @@ -90,6 +90,7 @@ protected function doUnlink(string $file) private function write(string $file, string $data, int $expiresAt = null) { + $unlink = false; set_error_handler(__CLASS__.'::throwError'); try { if (null === $this->tmp) { @@ -107,14 +108,22 @@ private function write(string $file, string $data, int $expiresAt = null) } fwrite($h, $data); fclose($h); + $unlink = true; if (null !== $expiresAt) { touch($this->tmp, $expiresAt ?: time() + 31556952); // 1 year in seconds } - return rename($this->tmp, $file); + $success = rename($this->tmp, $file); + $unlink = !$success; + + return $success; } finally { restore_error_handler(); + + if ($unlink) { + @unlink($this->tmp); + } } } From 0d1af2070066ea958b61285b1922788b22b40b96 Mon Sep 17 00:00:00 2001 From: Christian Flothmann Date: Tue, 17 Oct 2023 18:08:14 +0200 Subject: [PATCH 045/115] fix tests with Doctrine DBAL 3.8 --- .../Doctrine/Tests/Middleware/Debug/MiddlewareTest.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php b/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php index e59428783e4dd..1d723dedb6064 100644 --- a/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php +++ b/src/Symfony/Bridge/Doctrine/Tests/Middleware/Debug/MiddlewareTest.php @@ -16,6 +16,7 @@ use Doctrine\DBAL\Driver\Middleware as MiddlewareInterface; use Doctrine\DBAL\DriverManager; use Doctrine\DBAL\ParameterType; +use Doctrine\DBAL\Query\QueryBuilder; use Doctrine\DBAL\Result; use Doctrine\DBAL\Schema\DefaultSchemaManagerFactory; use Doctrine\DBAL\Types\Types; @@ -213,11 +214,11 @@ public function testTransaction(callable $endTransactionMethod, string $expected $this->assertCount(9, $debug); $this->assertSame('"START TRANSACTION"', $debug[1]['sql']); $this->assertGreaterThan(0, $debug[1]['executionMS']); - $this->assertSame('SAVEPOINT DOCTRINE2_SAVEPOINT_2', $debug[2]['sql']); + $this->assertSame(method_exists(QueryBuilder::class, 'resetOrderBy') ? 'SAVEPOINT DOCTRINE_2' : 'SAVEPOINT DOCTRINE2_SAVEPOINT_2', $debug[2]['sql']); $this->assertGreaterThan(0, $debug[2]['executionMS']); $this->assertSame('INSERT INTO products(name, price, stock) VALUES ("product1", 12.5, 5)', $debug[3]['sql']); $this->assertGreaterThan(0, $debug[3]['executionMS']); - $this->assertSame(('"ROLLBACK"' === $expectedEndTransactionDebug ? 'ROLLBACK TO' : 'RELEASE').' SAVEPOINT DOCTRINE2_SAVEPOINT_2', $debug[4]['sql']); + $this->assertSame(('"ROLLBACK"' === $expectedEndTransactionDebug ? 'ROLLBACK TO' : 'RELEASE').' '.(method_exists(QueryBuilder::class, 'resetOrderBy') ? 'SAVEPOINT DOCTRINE_2' : 'SAVEPOINT DOCTRINE2_SAVEPOINT_2'), $debug[4]['sql']); $this->assertGreaterThan(0, $debug[4]['executionMS']); $this->assertSame($expectedEndTransactionDebug, $debug[5]['sql']); $this->assertGreaterThan(0, $debug[5]['executionMS']); From 3896d010802ac573998073b0a04386a4671c8c08 Mon Sep 17 00:00:00 2001 From: Minna N <44906587+minna-xD@users.noreply.github.com> Date: Wed, 18 Oct 2023 22:02:45 +0300 Subject: [PATCH 046/115] [Validator] Add missing Finnish translations --- .../Resources/translations/validators.fi.xlf | 116 +++++++++++------- 1 file changed, 70 insertions(+), 46 deletions(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf index 9a6bfe4b6a6f0..0a796a2dbaeb0 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.fi.xlf @@ -24,11 +24,11 @@ You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. - Sinun tulee valita vähintään {{ limit }} vaihtoehtoa. + Sinun tulee valita vähintään yksi vaihtoehto.|Sinun tulee valita vähintään {{ limit }} vaihtoehtoa. You must select at most {{ limit }} choice.|You must select at most {{ limit }} choices. - Sinun tulee valitan enintään {{ limit }} vaihtoehtoa. + Sinun tulee valita enintään yksi vaihtoehto.|Sinun tulee valita enintään {{ limit }} vaihtoehtoa. One or more of the given values is invalid. @@ -36,7 +36,7 @@ This field was not expected. - Tässä kentässä ei odotettu. + Tätä kenttää ei odotettu. This field is missing. @@ -60,7 +60,7 @@ The file is not readable. - Tiedostoa ei voida lukea. + Tiedostoa ei voi lukea. The file is too large ({{ size }} {{ suffix }}). Allowed maximum size is {{ limit }} {{ suffix }}. @@ -76,7 +76,7 @@ This value is too long. It should have {{ limit }} character or less.|This value is too long. It should have {{ limit }} characters or less. - Liian pitkä syöte. Syöte saa olla enintään {{ limit }} merkkiä. + Liian pitkä syöte. Syöte saa olla enintään yhden merkin.|Liian pitkä syöte. Syöte saa olla enintään {{ limit }} merkkiä. This value should be {{ limit }} or more. @@ -84,7 +84,7 @@ This value is too short. It should have {{ limit }} character or more.|This value is too short. It should have {{ limit }} characters or more. - Liian lyhyt syöte. Syötteen tulee olla vähintään {{ limit }} merkkiä. + Liian lyhyt syöte. Syötteen tulee olla vähintään yhden merkin.|Liian lyhyt syöte. Syötteen tulee olla vähintään {{ limit }} merkkiä. This value should not be blank. @@ -92,11 +92,11 @@ This value should not be null. - Syöte ei voi olla null. + Annettu arvo ei voi olla null. This value should be null. - Syötteen tulee olla null. + Annetun arvon tulee olla null. This value is not valid. @@ -128,11 +128,11 @@ This value should be a valid number. - Tämän arvon tulee olla numero. + Arvon tulee olla numero. This file is not a valid image. - Tämä tiedosto ei ole kelvollinen kuva. + Tiedosto ei ole kelvollinen kuva. This is not a valid IP address. @@ -140,47 +140,47 @@ This value is not a valid language. - Tämä arvo ei ole kelvollinen kieli. + Arvo ei ole kelvollinen kieli. This value is not a valid locale. - Tämä arvo ei ole kelvollinen kieli- ja alueasetus (locale). + Arvo ei ole kelvollinen kieli- ja alueasetus (locale). This value is not a valid country. - Tämä arvo ei ole kelvollinen maa. + Arvo ei ole kelvollinen maa. This value is already used. - Tämä arvo on jo käytetty. + Arvo on jo käytetty. The size of the image could not be detected. - Kuvan kokoa ei voitu tunnistaa. + Kuvan kokoa ei tunnistettu. The image width is too big ({{ width }}px). Allowed maximum width is {{ max_width }}px. - Kuva on liian leveä ({{ width }}px). Sallittu maksimileveys on {{ max_width }}px. + Kuva on liian leveä ({{ width }} px). Leveyden tulee olla enintään {{ max_width }} px. The image width is too small ({{ width }}px). Minimum width expected is {{ min_width }}px. - Kuva on liian kapea ({{ width }}px). Leveyden tulisi olla vähintään {{ min_width }}px. + Kuva on liian kapea ({{ width }} px). Leveyden tulee olla vähintään {{ min_width }} px. The image height is too big ({{ height }}px). Allowed maximum height is {{ max_height }}px. - Kuva on liian korkea ({{ width }}px). Sallittu maksimikorkeus on {{ max_width }}px. + Kuva on liian korkea ({{ width }} px). Korkeuden tulee olla enintään {{ max_width }} px. The image height is too small ({{ height }}px). Minimum height expected is {{ min_height }}px. - Kuva on liian matala ({{ height }}px). Korkeuden tulisi olla vähintään {{ min_height }}px. + Kuva on liian matala ({{ height }} px). Korkeuden tulee olla vähintään {{ min_height }} px. This value should be the user's current password. - Tämän arvon tulisi olla käyttäjän tämänhetkinen salasana. + Arvon tulee olla käyttäjän tämänhetkinen salasana. This value should have exactly {{ limit }} character.|This value should have exactly {{ limit }} characters. - Tämän arvon tulisi olla tasan yhden merkin pituinen.|Tämän arvon tulisi olla tasan {{ limit }} merkkiä pitkä. + Arvon tulee olla tasan yhden merkin pituinen.|Arvon tulee olla tasan {{ limit }} merkin pituinen. The file was only partially uploaded. @@ -192,7 +192,7 @@ No temporary folder was configured in php.ini. - Väliaikaishakemistoa ei ole asetettu php.ini -tiedostoon. + Väliaikaishakemistoa ei ole asetettu php.ini-tiedostossa. Cannot write temporary file to disk. @@ -204,15 +204,15 @@ This collection should contain {{ limit }} element or more.|This collection should contain {{ limit }} elements or more. - Tässä ryhmässä tulisi olla yksi tai useampi elementti.|Tässä ryhmässä tulisi olla vähintään {{ limit }} elementtiä. + Tässä ryhmässä tulee olla vähintään yksi elementti.|Tässä ryhmässä tulee olla vähintään {{ limit }} elementtiä. This collection should contain {{ limit }} element or less.|This collection should contain {{ limit }} elements or less. - Tässä ryhmässä tulisi olla enintään yksi elementti.|Tässä ryhmässä tulisi olla enintään {{ limit }} elementtiä. + Tässä ryhmässä tulee olla enintään yksi elementti.|Tässä ryhmässä tulee olla enintään {{ limit }} elementtiä. This collection should contain exactly {{ limit }} element.|This collection should contain exactly {{ limit }} elements. - Tässä ryhmässä tulisi olla tasan yksi elementti.|Tässä ryhmässä tulisi olla enintään {{ limit }} elementtiä. + Tässä ryhmässä tulee olla tasan yksi elementti.|Tässä ryhmässä tulee olla tasan {{ limit }} elementtiä. Invalid card number. @@ -236,7 +236,7 @@ This value is neither a valid ISBN-10 nor a valid ISBN-13. - Arvo ei ole kelvollinen ISBN-10 tai kelvollinen ISBN-13. + Arvo ei ole kelvollinen ISBN-10 eikä ISBN-13. This value is not a valid ISSN. @@ -260,7 +260,7 @@ This value should be identical to {{ compared_value_type }} {{ compared_value }}. - Tämä arvo tulee olla sama kuin {{ compared_value_type }} {{ compared_value }}. + Arvon tulee olla sama kuin {{ compared_value_type }} {{ compared_value }}. This value should be less than {{ compared_value }}. @@ -268,7 +268,7 @@ This value should be less than or equal to {{ compared_value }}. - Arvon tulee olla pienempi tai yhtä suuri {{ compared_value }}. + Arvon tulee olla pienempi tai yhtä suuri kuin {{ compared_value }}. This value should not be equal to {{ compared_value }}. @@ -276,7 +276,7 @@ This value should not be identical to {{ compared_value_type }} {{ compared_value }}. - Tämä arvo ei tule olla sama kuin {{ compared_value_type }} {{ compared_value }}. + Arvon ei tule olla sama kuin {{ compared_value_type }} {{ compared_value }}. The image ratio is too big ({{ ratio }}). Allowed maximum ratio is {{ max_ratio }}. @@ -284,23 +284,23 @@ The image ratio is too small ({{ ratio }}). Minimum ratio expected is {{ min_ratio }}. - Kuvasuhde on liian pieni ({{ ratio }}). Pienin sallittu arvo on {{ min_ratio }}. + Kuvasuhde on liian pieni ({{ ratio }}). Pienin sallittu suhde on {{ min_ratio }}. The image is square ({{ width }}x{{ height }}px). Square images are not allowed. - Kuva on neliä ({{ width }}x{{ height }}px). Neliöt kuvat eivät ole sallittuja. + Kuva on neliö ({{ width }}x{{ height }} px). Neliönmuotoiset kuvat eivät ole sallittuja. The image is landscape oriented ({{ width }}x{{ height }}px). Landscape oriented images are not allowed. - Kuva on vaakasuuntainen ({{ width }}x{{ height }}px). Vaakasuuntaiset kuvat eivät ole sallittuja. + Kuva on vaakasuuntainen ({{ width }}x{{ height }} px). Vaakasuuntaiset kuvat eivät ole sallittuja. The image is portrait oriented ({{ width }}x{{ height }}px). Portrait oriented images are not allowed. - Kuva on pystysuuntainen ({{ width }}x{{ height }}px). Pystysuuntaiset kuvat eivät ole sallittuja. + Kuva on pystysuuntainen ({{ width }}x{{ height }} px). Pystysuuntaiset kuvat eivät ole sallittuja. An empty file is not allowed. - Tyhjä tiedosto ei ole sallittu. + Tiedosto ei saa olla tyhjä. The host could not be resolved. @@ -324,11 +324,11 @@ This value should be a multiple of {{ compared_value }}. - Tämän arvon tulisi olla kerrannainen {{ compared_value }}. + Tämän arvon tulee olla luvun {{ compared_value }} kerrannainen. This Business Identifier Code (BIC) is not associated with IBAN {{ iban }}. - Tämä yritystunnus (BIC) ei ole liitetty IBAN {{ iban }}. + Tätä yritystunnusta (BIC) ei ole liitetty IBAN-tilinumeroon {{ iban }}. This value should be valid JSON. @@ -336,23 +336,23 @@ This collection should contain only unique elements. - Tämän ryhmän tulisi sisältää vain yksilöllisiä arvoja. + Ryhmän tulee sisältää vain yksilöllisiä arvoja. This value should be positive. - Arvon tulisi olla positiivinen. + Arvon tulee olla positiivinen. This value should be either positive or zero. - Arvon tulisi olla joko positiivinen tai nolla. + Arvon tulee olla joko positiivinen tai nolla. This value should be negative. - Arvon tulisi olla negatiivinen. + Arvon tulee olla negatiivinen. This value should be either negative or zero. - Arvon tulisi olla joko negatiivinen tai nolla. + Arvon tulee olla joko negatiivinen tai nolla. This value is not a valid timezone. @@ -360,11 +360,11 @@ This password has been leaked in a data breach, it must not be used. Please use another password. - Tämä salasana on vuotanut tietomurrossa, sitä ei saa käyttää. Käytä toista salasanaa. + Tämä salasana on vuotanut tietomurrossa, eikä sitä saa käyttää. Käytä toista salasanaa. This value should be between {{ min }} and {{ max }}. - Arvon tulisi olla välillä {{ min }} - {{ max }}. + Arvon tulee olla {{ min }} - {{ max }}. This value is not a valid hostname. @@ -372,11 +372,11 @@ The number of elements in this collection should be a multiple of {{ compared_value }}. - Ryhmässä olevien elementtien määrän pitää olla monikerta luvulle {{ compared_value }}. + Ryhmässä olevien elementtien määrän pitää olla luvun {{ compared_value }} kerrannainen. This value should satisfy at least one of the following constraints: - Tämän arvon tulee läpäistä vähintään yksi seuraavista tarkistuksista: + Arvon tulee läpäistä vähintään yksi seuraavista tarkistuksista: Each element of this collection should satisfy its own set of constraints. @@ -400,7 +400,31 @@ The value of the netmask should be between {{ min }} and {{ max }}. - Verkkomaskille annetun arvon tulisi olla {{ min }} ja {{ max }} välillä. + Verkkomaskille annetun arvon tulee olla {{ min }} - {{ max }}. + + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Tiedostonimi on liian pitkä. Nimi saa olla enintään yhden merkin pituinen.|Tiedostonimi on liian pitkä. Nimi saa olla enintään {{ filename_max_length }} merkin pituinen. + + + The password strength is too low. Please use a stronger password. + Salasana on liian heikko. Valitse vahvempi salasana. + + + This value contains characters that are not allowed by the current restriction-level. + Arvo sisältää merkkejä, joita nykyinen rajoitustaso ei salli. + + + Using invisible characters is not allowed. + Näkymättömiä merkkejä ei saa käyttää. + + + Mixing numbers from different scripts is not allowed. + Eri kirjaimistojen numeroita ei saa sekoittaa. + + + Using hidden overlay characters is not allowed. + Piilotettuja tarkemerkkejä ei saa käyttää. From 77cd7036aa7c2039acab053be76937c8dabdf301 Mon Sep 17 00:00:00 2001 From: asrorbekh Date: Thu, 19 Oct 2023 20:08:49 +0500 Subject: [PATCH 047/115] Added missing Uzbek translations. --- .../Resources/translations/validators.uz.xlf | 40 +++++++++++++++---- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf index d1ecaf1b70a29..63a79a084a924 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.uz.xlf @@ -4,11 +4,11 @@ This value should be false. - Qiymat noto'g'ri bo'lishi kerak. + Qiymat false bo'lishi kerak. This value should be true. - Qiymat to'g'ri bo'lishi kerak. + Qiymat true bo'lishi kerak. This value should be of type {{ type }}. @@ -20,7 +20,7 @@ The value you selected is not a valid choice. - Tanlangan qiymat to'g'ri emas. + Tanlangan qiymat yaroqli emas. You must select at least {{ limit }} choice.|You must select at least {{ limit }} choices. @@ -32,7 +32,7 @@ One or more of the given values is invalid. - Belgilangan qiymatlarning bir yoki bir nechtasi noto'g'ri. + Belgilangan qiymatlarning bir yoki bir nechtasi yaroqsiz. This field was not expected. @@ -143,9 +143,9 @@ Noto'g'ri til. - This value is not a valid locale. - Ushbu qiymat mahalliy qiymat emas. - + This value is not a valid locale. + Ushbu qiymat mahalliy qiymat emas. + This value is not a valid country. Mamlakat qiymati noto'g'ri. @@ -390,7 +390,7 @@ This value should be a valid expression. Ushbu qiymat to'g'ri ifoda bo'lishi kerak. - + This value is not a valid CSS color. Bu qiymat haqiqiy CSS rangi emas. @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Tarmoq niqobining qiymati {{ min }} va {{ max }} oralig'ida bo'lishi kerak. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Fayl nomi juda uzun. U {{ filename_max_length }} belgidan iborat boʻlishi kerak.|Fayl nomi juda uzun. U {{ filename_max_length }} ta belgidan iborat boʻlishi kerak. + + + The password strength is too low. Please use a stronger password. + Parol kuchi juda past. Iltimos, kuchliroq paroldan foydalaning. + + + This value contains characters that are not allowed by the current restriction-level. + Bu qiymat joriy cheklov darajasida ruxsat etilmagan belgilarni o'z ichiga oladi. + + + Using invisible characters is not allowed. + Ko'rinmas belgilardan foydalanish taqiqlangan. + + + Mixing numbers from different scripts is not allowed. + Turli skriptlardagi raqamlarni aralashtirish taqiqlangan. + + + Using hidden overlay characters is not allowed. + Yashirin qoplamali belgilardan foydalanish taqiqlangan. + From a58c6124368d4c8d628a1aed0a7d5b08893140ca Mon Sep 17 00:00:00 2001 From: Vitalii Date: Wed, 18 Oct 2023 14:50:47 -0500 Subject: [PATCH 048/115] [Validator] Added missing translations for Romanian language for Validator component --- .../Resources/translations/validators.ro.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf index 7fba2cd1e0e73..f0ca7477c4b95 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ro.xlf @@ -398,6 +398,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. Valoarea netmask-ului trebuie sa fie intre {{ min }} si {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + Denumirea fișierului este prea lungă. Ea trebuie să conțină {{ filename_max_length }} caractere sau mai puține.|Denumirea fișierului este prea lungă. Ea trebuie să conțină {{ filename_max_length }} caractere sau mai puține. + + + The password strength is too low. Please use a stronger password. + Complexitatea parolei este prea mică. Vă rugăm să folosiți o parolă mai puternică. + + + This value contains characters that are not allowed by the current restriction-level. + Această valoare conține caractere care nu sunt premise de nivelul de restricționare curent. + + + Using invisible characters is not allowed. + Folosirea caracterelor invizibile nu este permisă. + + + Mixing numbers from different scripts is not allowed. + Combinarea numerelor din diferite script-uri nu este permisă. + + + Using hidden overlay characters is not allowed. + Folosirea caracterelor invizibile suprapuse nu este permisă. + From 1c24f63f3c1216b33b39f742a8f2e451efe13336 Mon Sep 17 00:00:00 2001 From: Thomas Calvet Date: Thu, 19 Oct 2023 17:42:30 +0200 Subject: [PATCH 049/115] [CI] Add step to verify symfony/deprecation-contracts requirements --- .github/get-modified-packages.php | 6 +++-- .github/workflows/package-tests.yml | 40 +++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 2 deletions(-) diff --git a/.github/get-modified-packages.php b/.github/get-modified-packages.php index a3682af0b9d1a..cd6d97016d255 100644 --- a/.github/get-modified-packages.php +++ b/.github/get-modified-packages.php @@ -66,8 +66,10 @@ function getPackageType(string $packageDir): string $output = []; foreach ($modifiedPackages as $directory => $bool) { - $name = json_decode(file_get_contents($directory.'/composer.json'), true)['name'] ?? 'unknown'; - $output[] = ['name' => $name, 'directory' => $directory, 'new' => $newPackage[$directory] ?? false, 'type' => getPackageType($directory)]; + $composerData = json_decode(file_get_contents($directory.'/composer.json'), true); + $name = $composerData['name'] ?? 'unknown'; + $requiresDeprecationContracts = isset($composerData['require']['symfony/deprecation-contracts']); + $output[] = ['name' => $name, 'directory' => $directory, 'new' => $newPackage[$directory] ?? false, 'type' => getPackageType($directory), 'requires_deprecation_contracts' => $requiresDeprecationContracts]; } echo json_encode($output); diff --git a/.github/workflows/package-tests.yml b/.github/workflows/package-tests.yml index 1840d30f091a6..69f22dab44a9f 100644 --- a/.github/workflows/package-tests.yml +++ b/.github/workflows/package-tests.yml @@ -100,4 +100,44 @@ jobs: fi done + exit $ok + - name: Verify symfony/deprecation-contracts requirements + run: | + set +e + + ok=0 + json='${{ steps.find-packages.outputs.packages }}' + for package in $(echo "${json}" | jq -r '.[] | @base64'); do + _jq() { + echo ${package} | base64 --decode | jq -r ${1} + } + + NAME=$(_jq '.name') + if [[ $NAME = 'symfony/deprecation-contracts' || $NAME = 'symfony/contracts' ]]; then + continue + fi + + echo "::group::$NAME" + DIR=$(_jq '.directory') + localExit=0 + grep -rq 'trigger_deprecation(' --include=*.php --exclude-dir=Tests/ --exclude-dir=Bridge/ $DIR + triggersDeprecation=$? + if [[ $triggersDeprecation -eq 0 && $(_jq '.requires_deprecation_contracts') == false ]]; then + errorMessage="::error::$NAME does not require symfony/deprecation-contracts but triggers at least one deprecation" + localExit=1 + elif [[ $triggersDeprecation -eq 1 && $(_jq '.requires_deprecation_contracts') == true ]]; then + errorMessage="::error::$NAME requires symfony/deprecation-contracts but does not trigger any deprecation" + localExit=1 + elif [[ $triggersDeprecation -ne 0 && $triggersDeprecation -ne 1 ]]; then + echo "::error::grep failed" + exit 2 + fi + + ok=$(( $localExit || $ok )) + echo ::endgroup:: + if [ $localExit -ne 0 ]; then + echo $errorMessage + fi + done + exit $ok From 738385f127dd9a27751deca1d600b7f4647b8c93 Mon Sep 17 00:00:00 2001 From: Nadim AL ABDOU Date: Thu, 19 Oct 2023 20:45:10 +0200 Subject: [PATCH 050/115] [Validator] Add missing arabic translations --- .../Resources/translations/validators.ar.xlf | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf index 6aa0d594843f6..fce6604a533cd 100644 --- a/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf +++ b/src/Symfony/Component/Validator/Resources/translations/validators.ar.xlf @@ -402,6 +402,30 @@ The value of the netmask should be between {{ min }} and {{ max }}. يجب أن تكون قيمة netmask بين {{ min }} و {{ max }}. + + The filename is too long. It should have {{ filename_max_length }} character or less.|The filename is too long. It should have {{ filename_max_length }} characters or less. + اسم الملف طويل جدا. يجب أن يحتوي على {{ filename_max_length }} حرف أو أقل.|اسم الملف طويل جدا. يجب أن يحتوي على {{ filename_max_length }} أحرف أو أقل. + + + The password strength is too low. Please use a stronger password. + قوة كلمة المرور منخفضة للغاية. يرجى استخدام كلمة مرور أقوى. + + + This value contains characters that are not allowed by the current restriction-level. + تحتوي هذه القيمة على أحرف غير مسموح بها بواسطة مستوى التقييد الحالي. + + + Using invisible characters is not allowed. + لا يسمح باستخدام أحرف غير مرئية. + + + Mixing numbers from different scripts is not allowed. + لا يسمح بخلط الأرقام من نصوص مختلفة. + + + Using hidden overlay characters is not allowed. + لا يسمح باستخدام أحرف التراكب المخفية. + From 07f9d2eeb2d9093c3ee00661a6ddf84839eecb8a Mon Sep 17 00:00:00 2001 From: Fabien Potencier Date: Fri, 20 Oct 2023 07:50:21 +0200 Subject: [PATCH 051/115] Replace Tickets by Issues --- .github/PULL_REQUEST_TEMPLATE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index f56136de940d3..ff72a1cc13a5c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -4,7 +4,7 @@ | Bug fix? | yes/no | New feature? | yes/no | Deprecations? | yes/no -| Tickets | Fix #... +| Issues | Fix #... | License | MIT